From: Daniel P. Berrangé <berrange@redhat.com>
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é <berrange@redhat.com>
---
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
© 2016 - 2025 Red Hat, Inc.