VIR_LOG_INIT("rpc.nettlsconfig");
+
+#define VIR_NET_TLS_CONFIG_MAX_INDEXED 4
+
char *virNetTLSConfigUserPKIBaseDir(void)
{
g_autofree char *userdir = virGetUserDirectory();
VIR_DEBUG("TLS cert %s", *cert);
}
+static void virNetTLSConfigIdentityIndexed(bool isServer,
+ const char *certdir,
+ const char *keydir,
+ size_t idx,
+ char **cert,
+ char **key)
+{
+ if (!*key)
+ *key = g_strdup_printf("%s/%skey%zu.pem", keydir,
+ (isServer ? "server" : "client"), idx);
+ if (!*cert)
+ *cert = g_strdup_printf("%s/%scert%zu.pem", certdir,
+ (isServer ? "server" : "client"), idx);
+
+ VIR_DEBUG("TLS key %s", *key);
+ VIR_DEBUG("TLS cert %s", *cert);
+}
+
void virNetTLSConfigCustomTrust(const char *pkipath,
char **cacert,
char **cacrl)
bool allowMissingIdentity,
char **cacert,
char **cacrl,
- char **cert,
- char **key)
+ char ***certs,
+ char ***keys)
{
virNetTLSConfigTrust(cacertdir,
cacrldir,
if (virNetTLSConfigEnsureTrust(cacert, cacrl, allowMissingCA) < 0)
return -1;
- virNetTLSConfigIdentity(isServer,
- certdir,
- keydir,
- cert,
- key);
+ if (!*certs && !*keys) {
+ g_auto(GStrv) certlist =
+ g_new0(char *, VIR_NET_TLS_CONFIG_MAX_INDEXED + 2);
+ g_auto(GStrv) keylist =
+ g_new0(char *, VIR_NET_TLS_CONFIG_MAX_INDEXED + 2);
+ size_t i;
+
+ /*
+ * When searching for indexed certs/keys, the first
+ * missing index terminates the search, so we don't
+ * get gaps in the returned array. All indexed files
+ * are optional, as if they're all missing, we'll
+ * still honour the traditional file names
+ */
+ for (i = 0; i < VIR_NET_TLS_CONFIG_MAX_INDEXED; i++) {
+ virNetTLSConfigIdentityIndexed(isServer,
+ certdir,
+ keydir,
+ i,
+ &(certlist[i + 1]),
+ &(keylist[i + 1]));
+
+ if (virNetTLSConfigEnsureIdentity(&(certlist[i + 1]),
+ &(keylist[i + 1]), true) < 0)
+ return -1;
- if (virNetTLSConfigEnsureIdentity(cert, key, allowMissingIdentity) < 0)
- return -1;
+ if (certlist[i + 1] == NULL) {
+ break;
+ }
+ }
+
+ /*
+ * If we find index 0, then allow the traditional
+ * default files to be optional
+ */
+ if (certlist[1] != NULL)
+ allowMissingIdentity = true;
+
+ virNetTLSConfigIdentity(isServer,
+ certdir,
+ keydir,
+ &(certlist[0]),
+ &(keylist[0]));
+
+ if (virNetTLSConfigEnsureIdentity(&(certlist[0]),
+ &(keylist[0]), allowMissingIdentity) < 0)
+ return -1;
+
+ if (certlist[0] == NULL) {
+ memmove(certlist, certlist + 1,
+ VIR_NET_TLS_CONFIG_MAX_INDEXED * sizeof(char *));
+ memmove(keylist, keylist + 1,
+ VIR_NET_TLS_CONFIG_MAX_INDEXED * sizeof(char *));
+ certlist[VIR_NET_TLS_CONFIG_MAX_INDEXED] = NULL;
+ keylist[VIR_NET_TLS_CONFIG_MAX_INDEXED] = NULL;
+ }
+
+ if (certlist[0] != NULL) {
+ *certs = g_steal_pointer(&certlist);
+ *keys = g_steal_pointer(&keylist);
+ }
+ }
return 0;
}
bool isServer,
char **cacert,
char **cacrl,
- char **cert,
- char **key)
+ char ***certs,
+ char ***keys)
{
VIR_DEBUG("Locating creds in custom dir %s", pkipath);
false,
!isServer,
cacert, cacrl,
- cert, key);
+ certs, keys);
}
int virNetTLSConfigUserCreds(bool isServer,
char **cacert,
char **cacrl,
- char **cert,
- char **key)
+ char ***certs,
+ char ***keys)
{
g_autofree char *pkipath = virNetTLSConfigUserPKIBaseDir();
true,
true,
cacert, cacrl,
- cert, key);
+ certs, keys);
}
int virNetTLSConfigSystemCreds(bool isServer,
char **cacert,
char **cacrl,
- char **cert,
- char **key)
+ char ***certs,
+ char ***keys)
{
VIR_DEBUG("Locating creds in system dir %s", LIBVIRT_PKI_DIR);
false,
!isServer,
cacert, cacrl,
- cert, key);
+ certs, keys);
}
bool isServer,
char **cacert,
char **cacrl,
- char **cert,
- char **key)
+ char ***certs,
+ char ***keys)
{
*cacert = NULL;
*cacrl = NULL;
- *key = NULL;
- *cert = NULL;
+ *keys = NULL;
+ *certs = NULL;
VIR_DEBUG("pkipath=%s isServer=%d tryUserPkiPath=%d",
pkipath, isServer, tryUserPkiPath);
if (pkipath) {
if (virNetTLSConfigCustomCreds(pkipath, isServer,
cacert, cacrl,
- cert, key) < 0)
+ certs, keys) < 0)
return -1;
} else {
if (tryUserPkiPath &&
virNetTLSConfigUserCreds(isServer,
cacert, cacrl,
- cert, key) < 0)
+ certs, keys) < 0)
return -1;
if (virNetTLSConfigSystemCreds(isServer,
cacert, cacrl,
- cert, key) < 0)
+ certs, keys) < 0)
return -1;
}
+
+ /*
+ * Ensure the cert list is always non-NULL, even
+ * if it is an empty list, so that callers don't
+ * need to have repeated checks for a NULL array.
+ */
+ if (*certs == NULL)
+ *certs = g_new0(char *, 1);
+ if (*keys == NULL)
+ *keys = g_new0(char *, 1);
+
return 0;
}
{
g_autofree char *cacert = NULL;
g_autofree char *cacrl = NULL;
- g_autofree char *key = NULL;
- g_autofree char *cert = NULL;
- const char *certs[] = { cert, NULL };
- const char *keys[] = { key, NULL };
+ g_auto(GStrv) keys = NULL;
+ g_auto(GStrv) certs = NULL;
if (virNetTLSContextLocateCredentials(pkipath, tryUserPkiPath, isServer,
- &cacert, &cacrl, &cert, &key) < 0)
+ &cacert, &cacrl, &certs, &keys) < 0)
return NULL;
- return virNetTLSContextNew(cacert, cacrl, certs, keys,
+ return virNetTLSContextNew(cacert, cacrl,
+ (const char *const *)certs,
+ (const char *const *)keys,
x509dnACL, priority, sanityCheckCert,
requireValidCert, isServer);
}
int err;
g_autofree char *cacert = NULL;
g_autofree char *cacrl = NULL;
- g_autofree char *cert = NULL;
- g_autofree char *key = NULL;
- const char *certs[] = { cert, NULL };
- const char *keys[] = { key, NULL };
+ g_auto(GStrv) certs = NULL;
+ g_auto(GStrv) keys = NULL;
x509credBak = g_steal_pointer(&ctxt->x509cred);
if (virNetTLSContextLocateCredentials(NULL, tryUserPkiPath, true,
- &cacert, &cacrl, &cert, &key))
+ &cacert, &cacrl, &certs, &keys))
goto error;
err = gnutls_certificate_allocate_credentials(&ctxt->x509cred);
goto error;
}
- if (virNetTLSCertSanityCheck(true, cacert, certs))
+ if (virNetTLSCertSanityCheck(true, cacert,
+ (const char *const *)certs))
goto error;
if (virNetTLSContextLoadCredentials(ctxt, cacert, cacrl,
- certs, keys))
+ (const char *const *)certs,
+ (const char *const *)keys))
goto error;
gnutls_certificate_free_credentials(x509credBak);