Currently only a single set of certificates can be loaded for a
server / client. Certificates are created using a particular
key algorithm and in some scenarios it can be useful to support
multiple algorithms in parallel. This requires the ability to
load multiple sets of certificates.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
crypto/tlscredsx509.c | 164 ++++++++++++++++++++++++++++--------------
1 file changed, 112 insertions(+), 52 deletions(-)
diff --git a/crypto/tlscredsx509.c b/crypto/tlscredsx509.c
index 3cb0a6c31f..d7d1f594c0 100644
--- a/crypto/tlscredsx509.c
+++ b/crypto/tlscredsx509.c
@@ -39,6 +39,14 @@ struct QCryptoTLSCredsX509 {
char *passwordid;
};
+typedef struct QCryptoTLSCredsX509IdentFiles QCryptoTLSCredsX509IdentFiles;
+struct QCryptoTLSCredsX509IdentFiles {
+ char *certpath;
+ char *keypath;
+ gnutls_x509_crt_t *certs;
+ unsigned int ncerts;
+ gnutls_x509_privkey_t key;
+};
typedef struct QCryptoTLSCredsX509Files QCryptoTLSCredsX509Files;
struct QCryptoTLSCredsX509Files {
@@ -46,11 +54,8 @@ struct QCryptoTLSCredsX509Files {
gnutls_x509_crt_t *cacerts;
unsigned int ncacerts;
- char *certpath;
- char *keypath;
- gnutls_x509_crt_t *certs;
- unsigned int ncerts;
- gnutls_x509_privkey_t key;
+ QCryptoTLSCredsX509IdentFiles **identities;
+ size_t nidentities;
};
static QCryptoTLSCredsX509Files *
@@ -61,14 +66,9 @@ qcrypto_tls_creds_x509_files_new(void)
static void
-qcrypto_tls_creds_x509_files_free(QCryptoTLSCredsX509Files *files)
+qcrypto_tls_creds_x509_ident_files_free(QCryptoTLSCredsX509IdentFiles *files)
{
size_t i;
- for (i = 0; i < files->ncacerts; i++) {
- gnutls_x509_crt_deinit(files->cacerts[i]);
- }
- g_free(files->cacerts);
- g_free(files->cacertpath);
for (i = 0; i < files->ncerts; i++) {
gnutls_x509_crt_deinit(files->certs[i]);
}
@@ -79,6 +79,26 @@ qcrypto_tls_creds_x509_files_free(QCryptoTLSCredsX509Files *files)
g_free(files);
}
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSCredsX509IdentFiles,
+ qcrypto_tls_creds_x509_ident_files_free);
+
+
+static void
+qcrypto_tls_creds_x509_files_free(QCryptoTLSCredsX509Files *files)
+{
+ size_t i;
+ for (i = 0; i < files->ncacerts; i++) {
+ gnutls_x509_crt_deinit(files->cacerts[i]);
+ }
+ g_free(files->cacerts);
+ g_free(files->cacertpath);
+ for (i = 0; i < files->nidentities; i++) {
+ qcrypto_tls_creds_x509_ident_files_free(files->identities[i]);
+ }
+ g_free(files->identities);
+ g_free(files);
+}
+
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSCredsX509Files,
qcrypto_tls_creds_x509_files_free);
@@ -573,33 +593,32 @@ qcrypto_tls_creds_load_privkey(QCryptoTLSCredsX509 *creds,
static int
-qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
- QCryptoTLSCredsX509Files *files,
- bool isServer,
- Error **errp)
+qcrypto_tls_creds_x509_sanity_check_identity(QCryptoTLSCredsX509 *creds,
+ QCryptoTLSCredsX509Files *files,
+ QCryptoTLSCredsX509IdentFiles *ifiles,
+ bool isServer,
+ Error **errp)
{
size_t i;
- for (i = 0; i < files->ncerts; i++) {
+ for (i = 0; i < ifiles->ncerts; i++) {
if (qcrypto_tls_creds_check_cert(creds,
- files->certs[i], files->certpath,
+ ifiles->certs[i], ifiles->certpath,
isServer, i != 0, errp) < 0) {
return -1;
}
}
- if (files->ncerts &&
+ if (ifiles->ncerts &&
qcrypto_tls_creds_check_authority_chain(creds, files,
- files->certs, files->ncerts,
+ ifiles->certs, ifiles->ncerts,
isServer, errp) < 0) {
return -1;
}
- if (files->ncerts &&
- qcrypto_tls_creds_check_cert_pair(files,
- files->certs, files->ncerts,
- files->certpath, isServer,
- errp) < 0) {
+ if (ifiles->ncerts &&
+ qcrypto_tls_creds_check_cert_pair(files, ifiles->certs, ifiles->ncerts,
+ ifiles->certpath, isServer, errp) < 0) {
return -1;
}
@@ -607,6 +626,26 @@ qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
}
+static int
+qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
+ QCryptoTLSCredsX509Files *files,
+ bool isServer,
+ Error **errp)
+{
+ size_t i;
+ for (i = 0; i < files->nidentities; i++) {
+ if (qcrypto_tls_creds_x509_sanity_check_identity(creds,
+ files,
+ files->identities[i],
+ isServer,
+ errp) < 0) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
static int
qcrypto_tls_creds_x509_load_ca(QCryptoTLSCredsX509 *creds,
QCryptoTLSCredsBox *box,
@@ -642,48 +681,38 @@ qcrypto_tls_creds_x509_load_ca(QCryptoTLSCredsX509 *creds,
}
-static int
+static QCryptoTLSCredsX509IdentFiles *
qcrypto_tls_creds_x509_load_identity(QCryptoTLSCredsX509 *creds,
QCryptoTLSCredsBox *box,
- QCryptoTLSCredsX509Files *files,
- bool isServer,
+ const char *certbase,
+ const char *keybase,
+ bool isOptional,
Error **errp)
{
+ g_autoptr(QCryptoTLSCredsX509IdentFiles) files =
+ g_new0(QCryptoTLSCredsX509IdentFiles, 1);
int ret;
- if (isServer) {
- if (qcrypto_tls_creds_get_path(&creds->parent_obj,
- QCRYPTO_TLS_CREDS_X509_SERVER_CERT,
- true, &files->certpath, errp) < 0 ||
- qcrypto_tls_creds_get_path(&creds->parent_obj,
- QCRYPTO_TLS_CREDS_X509_SERVER_KEY,
- true, &files->keypath, errp) < 0) {
- return -1;
- }
- } else {
- if (qcrypto_tls_creds_get_path(&creds->parent_obj,
- QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
- false, &files->certpath, errp) < 0 ||
- qcrypto_tls_creds_get_path(&creds->parent_obj,
- QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
- false, &files->keypath, errp) < 0) {
- return -1;
- }
+ if (qcrypto_tls_creds_get_path(&creds->parent_obj, certbase,
+ !isOptional, &files->certpath, errp) < 0 ||
+ qcrypto_tls_creds_get_path(&creds->parent_obj, keybase,
+ !isOptional, &files->keypath, errp) < 0) {
+ return NULL;
}
if (!files->certpath &&
!files->keypath) {
- return 0;
+ return NULL;
}
if (files->certpath && !files->keypath) {
error_setg(errp, "Cert '%s' without corresponding key",
files->certpath);
- return -1;
+ return NULL;
}
if (!files->certpath && files->keypath) {
error_setg(errp, "Key '%s' without corresponding cert",
files->keypath);
- return -1;
+ return NULL;
}
if (qcrypto_tls_creds_load_cert_list(creds,
@@ -691,14 +720,14 @@ qcrypto_tls_creds_x509_load_identity(QCryptoTLSCredsX509 *creds,
&files->certs,
&files->ncerts,
errp) < 0) {
- return -1;
+ return NULL;
}
if (qcrypto_tls_creds_load_privkey(creds,
files->keypath,
&files->key,
errp) < 0) {
- return -1;
+ return NULL;
}
ret = gnutls_certificate_set_x509_key(box->data.cert,
@@ -708,8 +737,39 @@ qcrypto_tls_creds_x509_load_identity(QCryptoTLSCredsX509 *creds,
if (ret < 0) {
error_setg(errp, "Cannot set certificate '%s' & key '%s': %s",
files->certpath, files->keypath, gnutls_strerror(ret));
+ return NULL;
+ }
+ return g_steal_pointer(&files);
+}
+
+
+static int
+qcrypto_tls_creds_x509_load_identities(QCryptoTLSCredsX509 *creds,
+ QCryptoTLSCredsBox *box,
+ QCryptoTLSCredsX509Files *files,
+ bool isServer,
+ Error **errp)
+{
+ QCryptoTLSCredsX509IdentFiles *ifiles;
+
+ ifiles = qcrypto_tls_creds_x509_load_identity(
+ creds, box,
+ isServer ?
+ QCRYPTO_TLS_CREDS_X509_SERVER_CERT :
+ QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
+ isServer ?
+ QCRYPTO_TLS_CREDS_X509_SERVER_KEY :
+ QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
+ !isServer, errp);
+ if (!ifiles) {
return -1;
}
+
+ files->identities = g_renew(QCryptoTLSCredsX509IdentFiles *,
+ files->identities,
+ files->nidentities + 1);
+ files->identities[files->nidentities++] = ifiles;
+
return 0;
}
@@ -752,8 +812,8 @@ qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
return -1;
}
- if (qcrypto_tls_creds_x509_load_identity(creds, box, files,
- isServer, errp) < 0) {
+ if (qcrypto_tls_creds_x509_load_identities(creds, box, files,
+ isServer, errp) < 0) {
return -1;
}
--
2.51.1
Hi
On Thu, Oct 30, 2025 at 6:50 PM Daniel P. Berrangé <berrange@redhat.com>
wrote:
> Currently only a single set of certificates can be loaded for a
> server / client. Certificates are created using a particular
> key algorithm and in some scenarios it can be useful to support
> multiple algorithms in parallel. This requires the ability to
> load multiple sets of certificates.
>
> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> crypto/tlscredsx509.c | 164 ++++++++++++++++++++++++++++--------------
> 1 file changed, 112 insertions(+), 52 deletions(-)
>
> diff --git a/crypto/tlscredsx509.c b/crypto/tlscredsx509.c
> index 3cb0a6c31f..d7d1f594c0 100644
> --- a/crypto/tlscredsx509.c
> +++ b/crypto/tlscredsx509.c
> @@ -39,6 +39,14 @@ struct QCryptoTLSCredsX509 {
> char *passwordid;
> };
>
> +typedef struct QCryptoTLSCredsX509IdentFiles
> QCryptoTLSCredsX509IdentFiles;
> +struct QCryptoTLSCredsX509IdentFiles {
> + char *certpath;
> + char *keypath;
> + gnutls_x509_crt_t *certs;
> + unsigned int ncerts;
> + gnutls_x509_privkey_t key;
> +};
>
> typedef struct QCryptoTLSCredsX509Files QCryptoTLSCredsX509Files;
> struct QCryptoTLSCredsX509Files {
> @@ -46,11 +54,8 @@ struct QCryptoTLSCredsX509Files {
> gnutls_x509_crt_t *cacerts;
> unsigned int ncacerts;
>
> - char *certpath;
> - char *keypath;
> - gnutls_x509_crt_t *certs;
> - unsigned int ncerts;
> - gnutls_x509_privkey_t key;
> + QCryptoTLSCredsX509IdentFiles **identities;
> + size_t nidentities;
> };
>
> static QCryptoTLSCredsX509Files *
> @@ -61,14 +66,9 @@ qcrypto_tls_creds_x509_files_new(void)
>
>
> static void
> -qcrypto_tls_creds_x509_files_free(QCryptoTLSCredsX509Files *files)
> +qcrypto_tls_creds_x509_ident_files_free(QCryptoTLSCredsX509IdentFiles
> *files)
> {
> size_t i;
> - for (i = 0; i < files->ncacerts; i++) {
> - gnutls_x509_crt_deinit(files->cacerts[i]);
> - }
> - g_free(files->cacerts);
> - g_free(files->cacertpath);
> for (i = 0; i < files->ncerts; i++) {
> gnutls_x509_crt_deinit(files->certs[i]);
> }
> @@ -79,6 +79,26 @@
> qcrypto_tls_creds_x509_files_free(QCryptoTLSCredsX509Files *files)
> g_free(files);
> }
>
> +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSCredsX509IdentFiles,
> + qcrypto_tls_creds_x509_ident_files_free);
> +
> +
> +static void
> +qcrypto_tls_creds_x509_files_free(QCryptoTLSCredsX509Files *files)
> +{
> + size_t i;
> + for (i = 0; i < files->ncacerts; i++) {
> + gnutls_x509_crt_deinit(files->cacerts[i]);
> + }
> + g_free(files->cacerts);
> + g_free(files->cacertpath);
> + for (i = 0; i < files->nidentities; i++) {
> + qcrypto_tls_creds_x509_ident_files_free(files->identities[i]);
> + }
> + g_free(files->identities);
> + g_free(files);
> +}
> +
> G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSCredsX509Files,
> qcrypto_tls_creds_x509_files_free);
>
> @@ -573,33 +593,32 @@ qcrypto_tls_creds_load_privkey(QCryptoTLSCredsX509
> *creds,
>
>
> static int
> -qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
> - QCryptoTLSCredsX509Files *files,
> - bool isServer,
> - Error **errp)
> +qcrypto_tls_creds_x509_sanity_check_identity(QCryptoTLSCredsX509 *creds,
> + QCryptoTLSCredsX509Files
> *files,
> +
> QCryptoTLSCredsX509IdentFiles *ifiles,
> + bool isServer,
> + Error **errp)
> {
> size_t i;
>
> - for (i = 0; i < files->ncerts; i++) {
> + for (i = 0; i < ifiles->ncerts; i++) {
> if (qcrypto_tls_creds_check_cert(creds,
> - files->certs[i], files->certpath,
> + ifiles->certs[i],
> ifiles->certpath,
> isServer, i != 0, errp) < 0) {
> return -1;
> }
> }
>
> - if (files->ncerts &&
> + if (ifiles->ncerts &&
> qcrypto_tls_creds_check_authority_chain(creds, files,
> - files->certs,
> files->ncerts,
> + ifiles->certs,
> ifiles->ncerts,
> isServer, errp) < 0) {
> return -1;
> }
>
> - if (files->ncerts &&
> - qcrypto_tls_creds_check_cert_pair(files,
> - files->certs, files->ncerts,
> - files->certpath, isServer,
> - errp) < 0) {
> + if (ifiles->ncerts &&
> + qcrypto_tls_creds_check_cert_pair(files, ifiles->certs,
> ifiles->ncerts,
> + ifiles->certpath, isServer,
> errp) < 0) {
> return -1;
> }
>
> @@ -607,6 +626,26 @@
> qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
> }
>
>
> +static int
> +qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
> + QCryptoTLSCredsX509Files *files,
> + bool isServer,
> + Error **errp)
> +{
> + size_t i;
> + for (i = 0; i < files->nidentities; i++) {
> + if (qcrypto_tls_creds_x509_sanity_check_identity(creds,
> + files,
> +
> files->identities[i],
> + isServer,
> + errp) < 0) {
> + return -1;
> + }
> + }
> + return 0;
> +}
> +
> +
> static int
> qcrypto_tls_creds_x509_load_ca(QCryptoTLSCredsX509 *creds,
> QCryptoTLSCredsBox *box,
> @@ -642,48 +681,38 @@ qcrypto_tls_creds_x509_load_ca(QCryptoTLSCredsX509
> *creds,
> }
>
>
> -static int
> +static QCryptoTLSCredsX509IdentFiles *
> qcrypto_tls_creds_x509_load_identity(QCryptoTLSCredsX509 *creds,
> QCryptoTLSCredsBox *box,
> - QCryptoTLSCredsX509Files *files,
> - bool isServer,
> + const char *certbase,
> + const char *keybase,
> + bool isOptional,
> Error **errp)
> {
> + g_autoptr(QCryptoTLSCredsX509IdentFiles) files =
> + g_new0(QCryptoTLSCredsX509IdentFiles, 1);
> int ret;
>
> - if (isServer) {
> - if (qcrypto_tls_creds_get_path(&creds->parent_obj,
> - QCRYPTO_TLS_CREDS_X509_SERVER_CERT,
> - true, &files->certpath, errp) < 0
> ||
> - qcrypto_tls_creds_get_path(&creds->parent_obj,
> - QCRYPTO_TLS_CREDS_X509_SERVER_KEY,
> - true, &files->keypath, errp) < 0) {
> - return -1;
> - }
> - } else {
> - if (qcrypto_tls_creds_get_path(&creds->parent_obj,
> - QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
> - false, &files->certpath, errp) < 0
> ||
> - qcrypto_tls_creds_get_path(&creds->parent_obj,
> - QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
> - false, &files->keypath, errp) < 0)
> {
> - return -1;
> - }
> + if (qcrypto_tls_creds_get_path(&creds->parent_obj, certbase,
> + !isOptional, &files->certpath, errp) <
> 0 ||
> + qcrypto_tls_creds_get_path(&creds->parent_obj, keybase,
> + !isOptional, &files->keypath, errp) <
> 0) {
> + return NULL;
> }
>
> if (!files->certpath &&
> !files->keypath) {
> - return 0;
> + return NULL;
> }
> if (files->certpath && !files->keypath) {
> error_setg(errp, "Cert '%s' without corresponding key",
> files->certpath);
> - return -1;
> + return NULL;
> }
> if (!files->certpath && files->keypath) {
> error_setg(errp, "Key '%s' without corresponding cert",
> files->keypath);
> - return -1;
> + return NULL;
> }
>
> if (qcrypto_tls_creds_load_cert_list(creds,
> @@ -691,14 +720,14 @@
> qcrypto_tls_creds_x509_load_identity(QCryptoTLSCredsX509 *creds,
> &files->certs,
> &files->ncerts,
> errp) < 0) {
> - return -1;
> + return NULL;
> }
>
> if (qcrypto_tls_creds_load_privkey(creds,
> files->keypath,
> &files->key,
> errp) < 0) {
> - return -1;
> + return NULL;
> }
>
> ret = gnutls_certificate_set_x509_key(box->data.cert,
> @@ -708,8 +737,39 @@
> qcrypto_tls_creds_x509_load_identity(QCryptoTLSCredsX509 *creds,
> if (ret < 0) {
> error_setg(errp, "Cannot set certificate '%s' & key '%s': %s",
> files->certpath, files->keypath, gnutls_strerror(ret));
> + return NULL;
> + }
> + return g_steal_pointer(&files);
> +}
> +
> +
> +static int
> +qcrypto_tls_creds_x509_load_identities(QCryptoTLSCredsX509 *creds,
> + QCryptoTLSCredsBox *box,
> + QCryptoTLSCredsX509Files *files,
> + bool isServer,
> + Error **errp)
> +{
> + QCryptoTLSCredsX509IdentFiles *ifiles;
> +
> + ifiles = qcrypto_tls_creds_x509_load_identity(
> + creds, box,
> + isServer ?
> + QCRYPTO_TLS_CREDS_X509_SERVER_CERT :
> + QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
> + isServer ?
> + QCRYPTO_TLS_CREDS_X509_SERVER_KEY :
> + QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
> + !isServer, errp);
> + if (!ifiles) {
> return -1;
> }
> +
> + files->identities = g_renew(QCryptoTLSCredsX509IdentFiles *,
> + files->identities,
> + files->nidentities + 1);
> + files->identities[files->nidentities++] = ifiles;
> +
> return 0;
> }
>
> @@ -752,8 +812,8 @@ qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
> return -1;
> }
>
> - if (qcrypto_tls_creds_x509_load_identity(creds, box, files,
> - isServer, errp) < 0) {
> + if (qcrypto_tls_creds_x509_load_identities(creds, box, files,
> + isServer, errp) < 0) {
> return -1;
> }
>
> --
> 2.51.1
>
>
© 2016 - 2025 Red Hat, Inc.