crypto: expand logic to cope with multiple certificate identities
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. Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
parent
8031b5fb1a
commit
c497a51481
1 changed files with 122 additions and 61 deletions
|
|
@ -40,12 +40,8 @@ struct QCryptoTLSCredsX509 {
|
||||||
#include <gnutls/x509.h>
|
#include <gnutls/x509.h>
|
||||||
|
|
||||||
|
|
||||||
typedef struct QCryptoTLSCredsX509Files QCryptoTLSCredsX509Files;
|
typedef struct QCryptoTLSCredsX509IdentFiles QCryptoTLSCredsX509IdentFiles;
|
||||||
struct QCryptoTLSCredsX509Files {
|
struct QCryptoTLSCredsX509IdentFiles {
|
||||||
char *cacertpath;
|
|
||||||
gnutls_x509_crt_t *cacerts;
|
|
||||||
unsigned int ncacerts;
|
|
||||||
|
|
||||||
char *certpath;
|
char *certpath;
|
||||||
char *keypath;
|
char *keypath;
|
||||||
gnutls_x509_crt_t *certs;
|
gnutls_x509_crt_t *certs;
|
||||||
|
|
@ -53,6 +49,16 @@ struct QCryptoTLSCredsX509Files {
|
||||||
gnutls_x509_privkey_t key;
|
gnutls_x509_privkey_t key;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct QCryptoTLSCredsX509Files QCryptoTLSCredsX509Files;
|
||||||
|
struct QCryptoTLSCredsX509Files {
|
||||||
|
char *cacertpath;
|
||||||
|
gnutls_x509_crt_t *cacerts;
|
||||||
|
unsigned int ncacerts;
|
||||||
|
|
||||||
|
QCryptoTLSCredsX509IdentFiles **identities;
|
||||||
|
size_t nidentities;
|
||||||
|
};
|
||||||
|
|
||||||
static QCryptoTLSCredsX509Files *
|
static QCryptoTLSCredsX509Files *
|
||||||
qcrypto_tls_creds_x509_files_new(void)
|
qcrypto_tls_creds_x509_files_new(void)
|
||||||
{
|
{
|
||||||
|
|
@ -60,6 +66,24 @@ qcrypto_tls_creds_x509_files_new(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
qcrypto_tls_creds_x509_ident_files_free(QCryptoTLSCredsX509IdentFiles *files)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < files->ncerts; i++) {
|
||||||
|
gnutls_x509_crt_deinit(files->certs[i]);
|
||||||
|
}
|
||||||
|
gnutls_x509_privkey_deinit(files->key);
|
||||||
|
g_free(files->certs);
|
||||||
|
g_free(files->certpath);
|
||||||
|
g_free(files->keypath);
|
||||||
|
g_free(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSCredsX509IdentFiles,
|
||||||
|
qcrypto_tls_creds_x509_ident_files_free);
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
qcrypto_tls_creds_x509_files_free(QCryptoTLSCredsX509Files *files)
|
qcrypto_tls_creds_x509_files_free(QCryptoTLSCredsX509Files *files)
|
||||||
{
|
{
|
||||||
|
|
@ -69,13 +93,10 @@ qcrypto_tls_creds_x509_files_free(QCryptoTLSCredsX509Files *files)
|
||||||
}
|
}
|
||||||
g_free(files->cacerts);
|
g_free(files->cacerts);
|
||||||
g_free(files->cacertpath);
|
g_free(files->cacertpath);
|
||||||
for (i = 0; i < files->ncerts; i++) {
|
for (i = 0; i < files->nidentities; i++) {
|
||||||
gnutls_x509_crt_deinit(files->certs[i]);
|
qcrypto_tls_creds_x509_ident_files_free(files->identities[i]);
|
||||||
}
|
}
|
||||||
gnutls_x509_privkey_deinit(files->key);
|
g_free(files->identities);
|
||||||
g_free(files->certs);
|
|
||||||
g_free(files->certpath);
|
|
||||||
g_free(files->keypath);
|
|
||||||
g_free(files);
|
g_free(files);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -572,6 +593,40 @@ qcrypto_tls_creds_load_privkey(QCryptoTLSCredsX509 *creds,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
qcrypto_tls_creds_x509_sanity_check_identity(QCryptoTLSCredsX509 *creds,
|
||||||
|
QCryptoTLSCredsX509Files *files,
|
||||||
|
QCryptoTLSCredsX509IdentFiles *ifiles,
|
||||||
|
bool isServer,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < ifiles->ncerts; i++) {
|
||||||
|
if (qcrypto_tls_creds_check_cert(creds,
|
||||||
|
ifiles->certs[i], ifiles->certpath,
|
||||||
|
isServer, i != 0, errp) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ifiles->ncerts &&
|
||||||
|
qcrypto_tls_creds_check_authority_chain(creds, files,
|
||||||
|
ifiles->certs, ifiles->ncerts,
|
||||||
|
isServer, errp) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ifiles->ncerts &&
|
||||||
|
qcrypto_tls_creds_check_cert_pair(files, ifiles->certs, ifiles->ncerts,
|
||||||
|
ifiles->certpath, isServer, errp) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
|
qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
|
||||||
QCryptoTLSCredsX509Files *files,
|
QCryptoTLSCredsX509Files *files,
|
||||||
|
|
@ -579,30 +634,15 @@ qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
for (i = 0; i < files->nidentities; i++) {
|
||||||
for (i = 0; i < files->ncerts; i++) {
|
if (qcrypto_tls_creds_x509_sanity_check_identity(creds,
|
||||||
if (qcrypto_tls_creds_check_cert(creds,
|
files,
|
||||||
files->certs[i], files->certpath,
|
files->identities[i],
|
||||||
isServer, i != 0, errp) < 0) {
|
isServer,
|
||||||
|
errp) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (files->ncerts &&
|
|
||||||
qcrypto_tls_creds_check_authority_chain(creds, files,
|
|
||||||
files->certs, files->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) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -642,48 +682,38 @@ qcrypto_tls_creds_x509_load_ca(QCryptoTLSCredsX509 *creds,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static QCryptoTLSCredsX509IdentFiles *
|
||||||
qcrypto_tls_creds_x509_load_identity(QCryptoTLSCredsX509 *creds,
|
qcrypto_tls_creds_x509_load_identity(QCryptoTLSCredsX509 *creds,
|
||||||
QCryptoTLSCredsBox *box,
|
QCryptoTLSCredsBox *box,
|
||||||
QCryptoTLSCredsX509Files *files,
|
const char *certbase,
|
||||||
bool isServer,
|
const char *keybase,
|
||||||
|
bool isOptional,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
|
g_autoptr(QCryptoTLSCredsX509IdentFiles) files =
|
||||||
|
g_new0(QCryptoTLSCredsX509IdentFiles, 1);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (isServer) {
|
if (qcrypto_tls_creds_get_path(&creds->parent_obj, certbase,
|
||||||
if (qcrypto_tls_creds_get_path(&creds->parent_obj,
|
!isOptional, &files->certpath, errp) < 0 ||
|
||||||
QCRYPTO_TLS_CREDS_X509_SERVER_CERT,
|
qcrypto_tls_creds_get_path(&creds->parent_obj, keybase,
|
||||||
true, &files->certpath, errp) < 0 ||
|
!isOptional, &files->keypath, errp) < 0) {
|
||||||
qcrypto_tls_creds_get_path(&creds->parent_obj,
|
return NULL;
|
||||||
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 (!files->certpath &&
|
if (!files->certpath &&
|
||||||
!files->keypath) {
|
!files->keypath) {
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (files->certpath && !files->keypath) {
|
if (files->certpath && !files->keypath) {
|
||||||
error_setg(errp, "Cert '%s' without corresponding key",
|
error_setg(errp, "Cert '%s' without corresponding key",
|
||||||
files->certpath);
|
files->certpath);
|
||||||
return -1;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!files->certpath && files->keypath) {
|
if (!files->certpath && files->keypath) {
|
||||||
error_setg(errp, "Key '%s' without corresponding cert",
|
error_setg(errp, "Key '%s' without corresponding cert",
|
||||||
files->keypath);
|
files->keypath);
|
||||||
return -1;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qcrypto_tls_creds_load_cert_list(creds,
|
if (qcrypto_tls_creds_load_cert_list(creds,
|
||||||
|
|
@ -691,14 +721,14 @@ qcrypto_tls_creds_x509_load_identity(QCryptoTLSCredsX509 *creds,
|
||||||
&files->certs,
|
&files->certs,
|
||||||
&files->ncerts,
|
&files->ncerts,
|
||||||
errp) < 0) {
|
errp) < 0) {
|
||||||
return -1;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qcrypto_tls_creds_load_privkey(creds,
|
if (qcrypto_tls_creds_load_privkey(creds,
|
||||||
files->keypath,
|
files->keypath,
|
||||||
&files->key,
|
&files->key,
|
||||||
errp) < 0) {
|
errp) < 0) {
|
||||||
return -1;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = gnutls_certificate_set_x509_key(box->data.cert,
|
ret = gnutls_certificate_set_x509_key(box->data.cert,
|
||||||
|
|
@ -708,8 +738,39 @@ qcrypto_tls_creds_x509_load_identity(QCryptoTLSCredsX509 *creds,
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp, "Cannot set certificate '%s' & key '%s': %s",
|
error_setg(errp, "Cannot set certificate '%s' & key '%s': %s",
|
||||||
files->certpath, files->keypath, gnutls_strerror(ret));
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
files->identities = g_renew(QCryptoTLSCredsX509IdentFiles *,
|
||||||
|
files->identities,
|
||||||
|
files->nidentities + 1);
|
||||||
|
files->identities[files->nidentities++] = ifiles;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -752,8 +813,8 @@ qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qcrypto_tls_creds_x509_load_identity(creds, box, files,
|
if (qcrypto_tls_creds_x509_load_identities(creds, box, files,
|
||||||
isServer, errp) < 0) {
|
isServer, errp) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue