From 383fb1472e6d1a6d44e79c6f43341444d6fb434e Mon Sep 17 00:00:00 2001 From: Remi Tricot-Le Breton Date: Mon, 22 Feb 2021 18:26:14 +0100 Subject: [PATCH] MEDIUM: ssl: Add a way to load a ca-file content from memory The updated CA content coming from the CLI during a ca-file update will directly be in memory and not on disk so the way CAs are loaded in a cafile_entry for now (via X509_STORE_load_locations calls) cannot be used. This patch adds a way to fill a cafile_entry directly from memory and to load the contained certificate and CRL sections into an SSL store. CRL sections are managed as well as certificates in order to mimic the way CA files are processed when specified in an option. Indeed, when parsing a CA file given through a ca-file or ca-verify-file option, we iterate over the different sections in ssl_set_cert_crl_file and load them regardless of their type. This ensures that a file that was properly parsed when given as an option will also be accepted by the CLI. --- include/haproxy/ssl_ckch.h | 1 + src/ssl_ckch.c | 49 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/include/haproxy/ssl_ckch.h b/include/haproxy/ssl_ckch.h index 40f133b1d..dd68662b5 100644 --- a/include/haproxy/ssl_ckch.h +++ b/include/haproxy/ssl_ckch.h @@ -61,6 +61,7 @@ struct cafile_entry *ssl_store_get_cafile_entry(char *path, int oldest_entry); X509_STORE* ssl_store_get0_locations_file(char *path); struct cafile_entry *ssl_store_create_cafile_entry(char *path, X509_STORE *store); void ssl_store_delete_cafile_entry(struct cafile_entry *ca_e); +int ssl_store_load_ca_from_buf(struct cafile_entry *ca_e, char *cert_buf); int ssl_store_load_locations_file(char *path, int create_if_none); #endif /* USE_OPENSSL */ diff --git a/src/ssl_ckch.c b/src/ssl_ckch.c index 84333591b..10123b4fa 100644 --- a/src/ssl_ckch.c +++ b/src/ssl_ckch.c @@ -1015,6 +1015,55 @@ void ssl_store_delete_cafile_entry(struct cafile_entry *ca_e) free(ca_e); } +/* + * Build a cafile_entry out of a buffer instead of out of a file. + * This function is used when the "commit ssl ca-file" cli command is used. + * It can parse CERTIFICATE sections as well as CRL ones. + * Returns 0 in case of success, 1 otherwise. + */ +int ssl_store_load_ca_from_buf(struct cafile_entry *ca_e, char *cert_buf) +{ + int retval = 0; + + if (!ca_e) + return 1; + + if (!ca_e->ca_store) { + ca_e->ca_store = X509_STORE_new(); + if (ca_e->ca_store) { + BIO *bio = BIO_new_mem_buf(cert_buf, strlen(cert_buf)); + if (bio) { + X509_INFO *info; + int i; + STACK_OF(X509_INFO) *infos = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL); + if (!infos) + { + BIO_free(bio); + return 1; + } + + for (i = 0; i < sk_X509_INFO_num(infos) && !retval; i++) { + info = sk_X509_INFO_value(infos, i); + /* X509_STORE_add_cert and X509_STORE_add_crl return 1 on success */ + if (info->x509) { + retval = !X509_STORE_add_cert(ca_e->ca_store, info->x509); + } + if (!retval && info->crl) { + retval = !X509_STORE_add_crl(ca_e->ca_store, info->crl); + } + } + retval = retval || (i != sk_X509_INFO_num(infos)); + + /* Cleanup */ + sk_X509_INFO_pop_free(infos, X509_INFO_free); + BIO_free(bio); + } + } + } + + return retval; +} + int ssl_store_load_locations_file(char *path, int create_if_none) { X509_STORE *store = ssl_store_get0_locations_file(path);