[PATCH v2 0/3] Add virt-pki-query-dn binary

v2: - do not use err*() functions - fix missing include dir in meson.build Patches 2 and 3 are reviewed. Martin Kletzander (3): tools: Add virt-pki-query-dn binary Add suggestions for virt-pki-query-dn usage news: Mention the addition of virt-pki-query-dn binary NEWS.rst | 6 ++ docs/remote.html.in | 4 + libvirt.spec.in | 1 + po/POTFILES.in | 1 + src/remote/libvirtd.conf.in | 5 ++ src/rpc/virnettlscontext.c | 2 +- tests/virconfdata/libvirtd.conf | 4 + tests/virconfdata/libvirtd.out | 4 + tools/meson.build | 27 ++++++ tools/virt-pki-query-dn.c | 140 ++++++++++++++++++++++++++++++++ 10 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 tools/virt-pki-query-dn.c -- 2.33.1

With this program we do not have to depend on the output of `certtool -i`, which changed the order of the fields at some point and the newest version is incompatible with what libvirt expects in tls_allowed_dn_list configuration option. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- libvirt.spec.in | 1 + po/POTFILES.in | 1 + tools/meson.build | 27 ++++++++ tools/virt-pki-query-dn.c | 140 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+) create mode 100644 tools/virt-pki-query-dn.c diff --git a/libvirt.spec.in b/libvirt.spec.in index 4ecb28114ce8..5f1773ef93f2 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -1983,6 +1983,7 @@ exit 0 %{_mandir}/man1/virt-pki-validate.1* %{_bindir}/virsh %{_bindir}/virt-xml-validate +%{_bindir}/virt-pki-query-dn %{_bindir}/virt-pki-validate %{_datadir}/bash-completion/completions/virsh diff --git a/po/POTFILES.in b/po/POTFILES.in index 8a726f624e38..bf0a3b352979 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -376,6 +376,7 @@ @SRCDIR@tools/virt-host-validate-qemu.c @SRCDIR@tools/virt-host-validate.c @SRCDIR@tools/virt-login-shell-helper.c +@SRCDIR@tools/virt-pki-query-dn.c @SRCDIR@tools/vsh-table.c @SRCDIR@tools/vsh.c @SRCDIR@tools/vsh.h diff --git a/tools/meson.build b/tools/meson.build index bf0eab8b6bf2..3fba313e5f49 100644 --- a/tools/meson.build +++ b/tools/meson.build @@ -257,6 +257,33 @@ configure_file( install_mode: 'rwxrwxr-x', ) +executable( + 'virt-pki-query-dn', + [ + 'virt-pki-query-dn.c', + ], + dependencies: [ + glib_dep, + gnutls_dep, + ], + include_directories: [ + libvirt_inc, + src_inc_dir, + top_inc_dir, + util_inc_dir, + ], + link_args: ( + libvirt_relro + + libvirt_no_indirect + + libvirt_no_undefined + ), + link_with: [ + libvirt_lib + ], + install: true, + install_dir: bindir, +) + if conf.has('WITH_SANLOCK') configure_file( input: 'virt-sanlock-cleanup.in', diff --git a/tools/virt-pki-query-dn.c b/tools/virt-pki-query-dn.c new file mode 100644 index 000000000000..ee3783c1b279 --- /dev/null +++ b/tools/virt-pki-query-dn.c @@ -0,0 +1,140 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include <config.h> +#include "internal.h" + +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> + +#include "virgettext.h" + + +static void +glib_auto_cleanup_gnutls_x509_crt_t(gnutls_x509_crt_t *pointer) +{ + gnutls_x509_crt_deinit(*pointer); +} + + +static void +print_usage(const char *progname, + FILE *out) +{ + fprintf(out, + _("Usage:\n" + " %s FILE\n" + " %s { -v | -h }\n" + "\n" + "Extract Distinguished Name from a PEM certificate.\n" + "The output is meant to be used in the tls_allowed_dn_list\n" + "configuration option in the libvirtd.conf file.\n" + "\n" + " FILE certificate file to extract the DN from\n" + "\n" + "options:\n" + " -h | --help display this help and exit\n" + " -v | --version output version information and exit\n"), + progname, progname); +} + + +int +main(int argc, + char **argv) +{ + const char *progname = NULL; + const char *filename = NULL; + size_t dnamesize = 256; + size_t bufsize = 0; + g_autofree char *dname = g_new0(char, dnamesize); + g_autofree char *buf = NULL; + g_auto(gnutls_x509_crt_t) crt = {0}; + gnutls_datum_t crt_data = {0}; + g_autoptr(GError) error = NULL; + int arg = 0; + int rv = 0; + + struct option opt[] = { + {"help", no_argument, NULL, 'h'}, + {"version", optional_argument, NULL, 'v'}, + {NULL, 0, NULL, 0} + }; + + if (virGettextInitialize() < 0) + return EXIT_FAILURE; + + if (!(progname = strrchr(argv[0], '/'))) + progname = argv[0]; + else + progname++; + + while ((arg = getopt_long(argc, argv, "hv", opt, NULL)) != -1) { + switch (arg) { + case 'v': + printf("%s\n", PACKAGE_VERSION); + return EXIT_SUCCESS; + case 'h': + print_usage(progname, stdout); + return EXIT_SUCCESS; + default: + print_usage(progname, stderr); + return EXIT_FAILURE; + } + } + + if (optind != argc - 1) { + print_usage(progname, stderr); + return EXIT_FAILURE; + } + + filename = argv[optind]; + + g_file_get_contents(filename, &buf, &bufsize, &error); + if (error) { + g_printerr("%s: %s\n", progname, error->message); + return EXIT_FAILURE; + } + + if (bufsize > UINT_MAX) { + g_printerr(_("%s: File '%s' is too large\n"), progname, filename); + return EXIT_FAILURE; + } + + crt_data.data = (unsigned char *)buf; + crt_data.size = bufsize; + + rv = gnutls_x509_crt_init(&crt); + if (rv < 0) { + g_printerr(_("Unable to initialize certificate: %s\n"), + gnutls_strerror(rv)); + return EXIT_FAILURE; + } + + rv = gnutls_x509_crt_import(crt, &crt_data, GNUTLS_X509_FMT_PEM); + if (rv < 0) { + g_printerr(_("Unable to load certificate, make sure it is in PEM format: %s\n"), + gnutls_strerror(rv)); + return EXIT_FAILURE; + } + + rv = gnutls_x509_crt_get_dn(crt, dname, &dnamesize); + if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER) { + dname = g_realloc(dname, dnamesize); + rv = gnutls_x509_crt_get_dn(crt, dname, &dnamesize); + } + if (rv != 0) { + g_printerr(_("Failed to get distinguished name: %s\n"), + gnutls_strerror(rv)); + return EXIT_FAILURE; + } + + printf("%s\n", dname); + + return EXIT_SUCCESS; +} -- 2.33.1

On Thu, Nov 11, 2021 at 09:36:55PM +0100, Martin Kletzander wrote:
With this program we do not have to depend on the output of `certtool -i`, which changed the order of the fields at some point and the newest version is incompatible with what libvirt expects in tls_allowed_dn_list configuration option.
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- libvirt.spec.in | 1 + po/POTFILES.in | 1 + tools/meson.build | 27 ++++++++ tools/virt-pki-query-dn.c | 140 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+) create mode 100644 tools/virt-pki-query-dn.c
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

To make it easier for users to figure out how the DN should be formatted. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- docs/remote.html.in | 4 ++++ src/remote/libvirtd.conf.in | 5 +++++ src/rpc/virnettlscontext.c | 2 +- tests/virconfdata/libvirtd.conf | 4 ++++ tests/virconfdata/libvirtd.out | 4 ++++ 5 files changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/remote.html.in b/docs/remote.html.in index 66f56a3a64fc..efdb2b32535d 100644 --- a/docs/remote.html.in +++ b/docs/remote.html.in @@ -259,6 +259,10 @@ Blank lines and comments beginning with <code>#</code> are ignored. Note also that GnuTLS returns DNs without spaces after commas between the fields (and this is what we check against), but the <code>openssl x509</code> tool shows spaces. + </p> + To make it easy to see the order of the fields in the DN a helper executable + <code>virt-pki-query-dn</code> is provided for this particular use case. + <p> </p> </td> </tr> diff --git a/src/remote/libvirtd.conf.in b/src/remote/libvirtd.conf.in index b18c5885a1a7..2cd20aaa7f52 100644 --- a/src/remote/libvirtd.conf.in +++ b/src/remote/libvirtd.conf.in @@ -292,6 +292,11 @@ # # Any * matches any number of consecutive spaces, like a simplified glob(7). # +# The format of the DN for a particular certificate can be queried +# using: +# +# virt-pki-query-dn clientcert.pem +# # NB If this is an empty list, no client can connect, so comment out # entirely rather than using empty list to disable these checks # diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c index 3babf3ee4dc3..1a3dd92676f7 100644 --- a/src/rpc/virnettlscontext.c +++ b/src/rpc/virnettlscontext.c @@ -371,7 +371,7 @@ virNetTLSContextCheckCertDNACL(const char *dname, virReportError(VIR_ERR_SYSTEM_ERROR, "%s", _("Client's Distinguished Name is not on the list " "of allowed clients (tls_allowed_dn_list). Use " - "'certtool -i --infile clientcert.pem' to view the " + "'virt-pki-query-dn clientcert.pem' to view the " "Distinguished Name field in the client certificate, " "or run this daemon with --verbose option.")); return 0; diff --git a/tests/virconfdata/libvirtd.conf b/tests/virconfdata/libvirtd.conf index f4c35e9e430f..c5a225e42f6f 100644 --- a/tests/virconfdata/libvirtd.conf +++ b/tests/virconfdata/libvirtd.conf @@ -185,6 +185,10 @@ tls_no_verify_certificate = 1 # # Any * matches any number of consecutive spaces, like a simplified glob(7). # +# The format of the DN for a particular certificate can be queried +# using: +# +# virt-pki-query-dn clientcert.pem # # NB If this is an empty list, no client can connect, so comment out # entirely rather than using empty list to disable these checks diff --git a/tests/virconfdata/libvirtd.out b/tests/virconfdata/libvirtd.out index a407c5f189e9..754bf56ee4dd 100644 --- a/tests/virconfdata/libvirtd.out +++ b/tests/virconfdata/libvirtd.out @@ -149,6 +149,10 @@ tls_no_verify_certificate = 1 # # Any * matches any number of consecutive spaces, like a simplified glob(7). # +# The format of the DN for a particular certificate can be queried +# using: +# +# virt-pki-query-dn clientcert.pem # # NB If this is an empty list, no client can connect, so comment out # entirely rather than using empty list to disable these checks -- 2.33.1

Signed-off-by: Martin Kletzander <mkletzan@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- NEWS.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index 983153a63123..a71b84c36390 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -17,6 +17,12 @@ v7.10.0 (unreleased) * **New features** + * Added virt-pki-query-dn binary + + This binary helps users figure out the format of Distinguished Name + from a certificate file the way that libvirt expects it in + tls_allowed_dn_list option of libvirtd.conf configuration file + * **Improvements** * qemu: Report guest interface information in ``virDomainGetGuestInfo`` -- 2.33.1
participants (2)
-
Daniel P. Berrangé
-
Martin Kletzander