From: Daniel P. Berrangé <[email protected]> The 'cert_file' and 'key_file' parameters in libvirtd.conf only permit a single cert/key. To support hybrid deployments for PQC, we need to be able to request multiple certs/keys. This involves new 'cert_files' and 'key_files' config parameters that accept a list of filenames. The new parameters are mutually exclusive with the old parameters.
Signed-off-by: Daniel P. Berrangé <[email protected]> --- src/remote/libvirtd.aug.in | 2 ++ src/remote/libvirtd.conf.in | 16 ++++++++++++ src/remote/remote_daemon.c | 26 +++++++++---------- src/remote/remote_daemon_config.c | 43 +++++++++++++++++++++++++++---- src/remote/remote_daemon_config.h | 4 +-- src/remote/test_libvirtd.aug.in | 8 ++++++ 6 files changed, 79 insertions(+), 20 deletions(-) diff --git a/src/remote/libvirtd.aug.in b/src/remote/libvirtd.aug.in index d744548f41..1f3bb5d0e2 100644 --- a/src/remote/libvirtd.aug.in +++ b/src/remote/libvirtd.aug.in @@ -47,6 +47,8 @@ module @DAEMON_NAME_UC@ = let certificate_entry = str_entry "key_file" | str_entry "cert_file" + | str_array_entry "key_files" + | str_array_entry "cert_files" | str_entry "ca_file" | str_entry "crl_file" diff --git a/src/remote/libvirtd.conf.in b/src/remote/libvirtd.conf.in index 32a680317a..e4460e61ef 100644 --- a/src/remote/libvirtd.conf.in +++ b/src/remote/libvirtd.conf.in @@ -244,12 +244,28 @@ # Override the default server key file path # +# This parameter is mutually exclusive with 'key_files' +# #key_file = "@sysconfdir@/pki/libvirt/private/serverkey.pem" +# Override the default server key file path(s) +# +# This parameter is mutually exclusive with 'key_file' +# +#key_files = ["@sysconfdir@/pki/libvirt/private/serverkey-0.pem", "@sysconfdir@/pki/libvirt/private/serverkey-1.pem"] + # Override the default server certificate file path # +# This parameter is mutually exclusive with 'cert_files' +# #cert_file = "@sysconfdir@/pki/libvirt/servercert.pem" +# Override the default server certificate file path(s) +# +# This parameter is mutually exclusive with 'cert_file' +# +#cert_files = ["@sysconfdir@/pki/libvirt/servercert-0.pem", "@sysconfdir@/pki/libvirt/servercert-1.pem"] + # Override the default CA certificate path # #ca_file = "@sysconfdir@/pki/CA/cacert.pem" diff --git a/src/remote/remote_daemon.c b/src/remote/remote_daemon.c index e7c8f587c4..ee3d10bc23 100644 --- a/src/remote/remote_daemon.c +++ b/src/remote/remote_daemon.c @@ -325,31 +325,31 @@ daemonSetupNetworking(virNetServer *srv, virNetTLSContext *ctxt = NULL; if (config->ca_file || - config->cert_file || - config->key_file) { - const char *certs[] = { config->cert_file, NULL }; - const char *keys[] = { config->key_file, NULL }; - + config->cert_files || + config->key_files) { + g_autofree char *certs = g_strjoinv(", ", config->cert_files); + g_autofree char *keys = g_strjoinv(", ", config->key_files); if (!config->ca_file) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("No CA certificate path set to match server key/cert")); + _("No CA certificate path set to match server key(s)/cert(s)")); return -1; } - if (!config->cert_file) { + if (!config->cert_files) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("No server certificate path set to match server key")); + _("No server certificate path(s) set to match server key(s)")); return -1; } - if (!config->key_file) { + if (!config->key_files) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("No server key path set to match server cert")); + _("No server key path(s) set to match server cert(s)")); return -1; } - VIR_DEBUG("Using CA='%s' cert='%s' key='%s'", - config->ca_file, config->cert_file, config->key_file); + VIR_DEBUG("Using CA='%s' certs='%s' keys='%s'", + config->ca_file, certs, keys); if (!(ctxt = virNetTLSContextNewServer(config->ca_file, config->crl_file, - certs, keys, + (const char *const*)config->cert_files, + (const char *const*)config->key_files, (const char *const*)config->tls_allowed_dn_list, config->tls_priority, config->tls_no_sanity_certificate ? false : true, diff --git a/src/remote/remote_daemon_config.c b/src/remote/remote_daemon_config.c index c1e75444e1..bb6078967f 100644 --- a/src/remote/remote_daemon_config.c +++ b/src/remote/remote_daemon_config.c @@ -192,9 +192,9 @@ daemonConfigFree(struct daemonConfig *data) g_free(data->tls_priority); - g_free(data->key_file); + g_strfreev(data->key_files); g_free(data->ca_file); - g_free(data->cert_file); + g_strfreev(data->cert_files); g_free(data->crl_file); #endif /* ! WITH_IP */ @@ -212,8 +212,12 @@ daemonConfigLoadOptions(struct daemonConfig *data, virConf *conf) { int rc G_GNUC_UNUSED; - #ifdef WITH_IP + g_autofree char *cert_file = NULL; + g_autofree char *key_file = NULL; + size_t ncerts; + size_t nkeys; + if (virConfGetValueBool(conf, "listen_tcp", &data->listen_tcp) < 0) return -1; if (virConfGetValueBool(conf, "listen_tls", &data->listen_tls) < 0) @@ -269,10 +273,39 @@ daemonConfigLoadOptions(struct daemonConfig *data, if (virConfGetValueBool(conf, "tls_no_verify_certificate", &data->tls_no_verify_certificate) < 0) return -1; - if (virConfGetValueString(conf, "key_file", &data->key_file) < 0) + if (virConfGetValueString(conf, "key_file", &key_file) < 0) + return -1; + if (virConfGetValueString(conf, "cert_file", &cert_file) < 0) + return -1; + if (virConfGetValueStringList(conf, "key_files", false, &data->key_files) < 0) + return -1; + if (virConfGetValueStringList(conf, "cert_files", false, &data->cert_files) < 0) + return -1; + if ((cert_file && data->cert_files) || + (key_file && data->key_files)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("cert_file/key_file are mutually exclusive with cert_files/key_files")); return -1; - if (virConfGetValueString(conf, "cert_file", &data->cert_file) < 0) + } + if (cert_file) { + data->cert_files = g_new0(char *, 2); + data->cert_files[0] = g_steal_pointer(&cert_file); + data->cert_files[1] = NULL; + } + if (key_file) { + data->key_files = g_new0(char *, 2); + data->key_files[0] = g_steal_pointer(&key_file); + data->key_files[1] = NULL; + } + ncerts = data->cert_files ? g_strv_length(data->cert_files) : 0; + nkeys = data->key_files ? g_strv_length(data->key_files) : 0; + if (ncerts != nkeys) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Number of certificates (%1$zu) must match number of keys (%2$zu)"), + ncerts, nkeys); return -1; + } + if (virConfGetValueString(conf, "ca_file", &data->ca_file) < 0) return -1; if (virConfGetValueString(conf, "crl_file", &data->crl_file) < 0) diff --git a/src/remote/remote_daemon_config.h b/src/remote/remote_daemon_config.h index 9f9e54e838..e699889191 100644 --- a/src/remote/remote_daemon_config.h +++ b/src/remote/remote_daemon_config.h @@ -58,8 +58,8 @@ struct daemonConfig { char *tls_priority; unsigned int tcp_min_ssf; - char *key_file; - char *cert_file; + char **key_files; + char **cert_files; char *ca_file; char *crl_file; #endif /* ! WITH_IP */ diff --git a/src/remote/test_libvirtd.aug.in b/src/remote/test_libvirtd.aug.in index c27680e130..a37b0daa55 100644 --- a/src/remote/test_libvirtd.aug.in +++ b/src/remote/test_libvirtd.aug.in @@ -26,7 +26,15 @@ module Test_@DAEMON_NAME@ = } @CUT_ENABLE_IP@ { "key_file" = "@sysconfdir@/pki/libvirt/private/serverkey.pem" } + { "key_files" + { "1" = "@sysconfdir@/pki/libvirt/private/serverkey-0.pem" } + { "2" = "@sysconfdir@/pki/libvirt/private/serverkey-1.pem" } + } { "cert_file" = "@sysconfdir@/pki/libvirt/servercert.pem" } + { "cert_files" + { "1" = "@sysconfdir@/pki/libvirt/servercert-0.pem" } + { "2" = "@sysconfdir@/pki/libvirt/servercert-1.pem" } + } { "ca_file" = "@sysconfdir@/pki/CA/cacert.pem" } { "crl_file" = "@sysconfdir@/pki/CA/crl.pem" } { "tls_no_sanity_certificate" = "1" } -- 2.51.1
