From 31e2cc3d020ccb106a8d7311bc019602f96076ec Mon Sep 17 00:00:00 2001 From: Alexandre Besnard Date: Tue, 24 Mar 2026 14:22:55 +0100 Subject: [PATCH] openssl: extend store provider code to load certificate chains Openssl store provider mechanics allow loading several items with a single name. This change leverages the API to allow loading certificates chains with store providers: a single name (for instance, a .pem file) can contain a chain of certificates, which will be loaded in the SSL context. --- lib/vtls/openssl.c | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index fc71a630d7..3491e44f65 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -1268,8 +1268,8 @@ static int providerload(struct Curl_easy *data, const char *cert_file) { #ifdef OPENSSL_HAS_PROVIDERS - OSSL_STORE_INFO *info = NULL; X509 *cert = NULL; + STACK_OF(X509) *cert_chain = NULL; OSSL_STORE_CTX *store = NULL; int rc; char error_buffer[256]; @@ -1300,14 +1300,31 @@ static int providerload(struct Curl_easy *data, sizeof(error_buffer))); } - info = OSSL_STORE_load(store); - if(info) { - int ossl_type = OSSL_STORE_INFO_get_type(info); + while(!OSSL_STORE_eof(store)) { + OSSL_STORE_INFO *info = OSSL_STORE_load(store); + /* Not really an error, keep looping */ + if(!info) { + continue; + } + + if(OSSL_STORE_INFO_get_type(info) == OSSL_STORE_INFO_CERT) { + /* Only load the first cert hit: when using a cert chain, + first one should be the right one.*/ + if(!cert) { + cert = OSSL_STORE_INFO_get1_CERT(info); + } + + /* Load all certs found in the chain. */ + if(!cert_chain) { + cert_chain = sk_X509_new_null(); + } + X509_add_cert(cert_chain, OSSL_STORE_INFO_get1_CERT(info), + X509_ADD_FLAG_DEFAULT); + } - if(ossl_type == OSSL_STORE_INFO_CERT) - cert = OSSL_STORE_INFO_get1_CERT(info); OSSL_STORE_INFO_free(info); } + OSSL_STORE_close(store); if(!cert) { failf(data, "No cert found in the openssl store: %s", @@ -1323,6 +1340,17 @@ static int providerload(struct Curl_easy *data, failf(data, "unable to set client certificate [%s]", ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer))); + sk_X509_pop_free(cert_chain, X509_free); + return 0; + } + + rc = (int) SSL_CTX_set1_chain(ctx, cert_chain); + sk_X509_pop_free(cert_chain, X509_free); + + if(rc != 1) { + failf(data, "unable to set client certificate chain [%s]", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); return 0; } return 1;