From 1f5506b62d6dcc919c3157e1169146e8534d62f1 Mon Sep 17 00:00:00 2001 From: Gilles Vollant Date: Mon, 13 Jul 2020 03:17:56 +0200 Subject: [PATCH] Add support CAfile in memory with CURLOPT_CAINFO_BLOB and CURLOPT_PROXY_CAINFO_BLOB Let applications provide the CA bundle to libcurl as a PEM formatted in-memory buffer. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rebased branch bundled_cacert from moparisthebest and then modified Validation : 397e11bfa6175c525d9365e63162888a77008213 [397e11b] Parents : 4506607b44 Auteur : moparisthebest Date : vendredi 3 avril 2020 00:32:42 Auteur : moparisthebest Date de validation : samedi 4 avril 2020 00:31:23 Add CURLOPT_CAINFO_PEM no message --- docs/libcurl/curl_easy_setopt.3 | 4 + docs/libcurl/opts/CURLOPT_CAINFO.3 | 2 +- docs/libcurl/opts/CURLOPT_CAINFO_BLOB.3 | 67 +++++++++++++++++ docs/libcurl/opts/CURLOPT_PROXY_CAINFO.3 | 3 +- docs/libcurl/opts/CURLOPT_PROXY_CAINFO_BLOB.3 | 74 +++++++++++++++++++ docs/libcurl/opts/Makefile.inc | 2 + docs/libcurl/symbols-in-versions | 2 + include/curl/curl.h | 8 ++ lib/doh.c | 4 + lib/easyoptions.c | 4 +- lib/setopt.c | 16 ++++ lib/url.c | 3 + lib/urldata.h | 3 + lib/vtls/openssl.c | 70 +++++++++++++++++- lib/vtls/vtls.c | 3 + packages/OS400/curl.inc.in | 4 + 16 files changed, 264 insertions(+), 5 deletions(-) create mode 100644 docs/libcurl/opts/CURLOPT_CAINFO_BLOB.3 create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_CAINFO_BLOB.3 diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index 3fc9a1d0342898..2de993cfa870f6 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -584,8 +584,12 @@ Verify the DOH (DNS-over-HTTPS) SSL certificate's status. See \fICURLOPT_DOH_SSL_VERIFYSTATUS(3)\fP .IP CURLOPT_CAINFO CA cert bundle. See \fICURLOPT_CAINFO(3)\fP +.IP CURLOPT_CAINFO_BLOB +CA cert bundle memory buffer. See \fICURLOPT_CAINFO_BLOB(3)\fP .IP CURLOPT_PROXY_CAINFO Proxy CA cert bundle. See \fICURLOPT_PROXY_CAINFO(3)\fP +.IP CURLOPT_PROXY_CAINFO_BLOB +Proxy CA cert bundle memory buffer. See \fICURLOPT_PROXY_CAINFO_BLOB(3)\fP .IP CURLOPT_ISSUERCERT Issuer certificate. See \fICURLOPT_ISSUERCERT(3)\fP .IP CURLOPT_ISSUERCERT_BLOB diff --git a/docs/libcurl/opts/CURLOPT_CAINFO.3 b/docs/libcurl/opts/CURLOPT_CAINFO.3 index e7eb8b01d4927f..fe7c8187f84e41 100644 --- a/docs/libcurl/opts/CURLOPT_CAINFO.3 +++ b/docs/libcurl/opts/CURLOPT_CAINFO.3 @@ -79,5 +79,5 @@ option is ignored. Schannel support added in libcurl 7.60. Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or CURLE_OUT_OF_MEMORY if there was insufficient heap space. .SH "SEE ALSO" -.BR CURLOPT_CAPATH "(3), " +.BR CURLOPT_CAINFO_BLOB "(3), " CURLOPT_CAPATH "(3), " .BR CURLOPT_SSL_VERIFYPEER "(3), " CURLOPT_SSL_VERIFYHOST "(3), " diff --git a/docs/libcurl/opts/CURLOPT_CAINFO_BLOB.3 b/docs/libcurl/opts/CURLOPT_CAINFO_BLOB.3 new file mode 100644 index 00000000000000..1fd00414ae4d29 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CAINFO_BLOB.3 @@ -0,0 +1,67 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2021, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_CAINFO_BLOB 3 "31 March 2021" "libcurl 7.76.0" "curl_easy_setopt options" +.SH NAME +CURLOPT_CAINFO_BLOB \- Certificate Authority (CA) bundle in PEM format +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CAINFO_BLOB, struct curl_blob *stblob); +.SH DESCRIPTION +Pass a pointer to a curl_blob structure, which contains information (pointer +and size) about a memory block with binary data of PEM encoded content holding +one or more certificates to verify the HTTPS server with. + +If \fICURLOPT_SSL_VERIFYPEER(3)\fP is zero and you avoid verifying the +server's certificate, \fICURLOPT_CAINFO_BLOB(3)\fP is not needed. + +This option overrides \fICURLOPT_CAINFO(3)\fP. +.SH DEFAULT +NULL +.SH PROTOCOLS +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. +.SH EXAMPLE +.nf +char *strpem; /* strpem must point to a PEM string */ +CURL *curl = curl_easy_init(); +if(curl) { + struct curl_blob blob; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + blob.data = strpem; + blob.len = strlen(strpem); + blob.flags = CURL_BLOB_COPY; + curl_easy_setopt(curl, CURLOPT_CAINFO_BLOB, &blob); + ret = curl_easy_perform(curl); + curl_easy_cleanup(curl); +} +.fi +.SH AVAILABILITY +Added in 7.76.0 + +This option is supported by the OpenSSL backends. +.SH RETURN VALUE +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. +.SH "SEE ALSO" +.BR CURLOPT_CAINFO "(3), " CURLOPT_CAPATH "(3), " +.BR CURLOPT_SSL_VERIFYPEER "(3), " CURLOPT_SSL_VERIFYHOST "(3), " diff --git a/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.3 b/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.3 index 17a870bb388b32..b0434d2b969734 100644 --- a/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.3 +++ b/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.3 @@ -77,7 +77,8 @@ https://curl.se/docs/ssl-compared.html Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or CURLE_OUT_OF_MEMORY if there was insufficient heap space. .SH "SEE ALSO" -.BR CURLOPT_PROXY_CAPATH "(3), " +.BR CURLOPT_PROXY_CAINFO_BLOB "(3), " CURLOPT_PROXY_CAPATH "(3), " .BR CURLOPT_PROXY_SSL_VERIFYPEER "(3), " CURLOPT_PROXY_SSL_VERIFYHOST "(3), " +.BR CURLOPT_CAINFO "(3), " CURLOPT_CAINFO_BLOB "(3), " .BR CURLOPT_CAPATH "(3), " .BR CURLOPT_SSL_VERIFYPEER "(3), " CURLOPT_SSL_VERIFYHOST "(3), " diff --git a/docs/libcurl/opts/CURLOPT_PROXY_CAINFO_BLOB.3 b/docs/libcurl/opts/CURLOPT_PROXY_CAINFO_BLOB.3 new file mode 100644 index 00000000000000..c0bb442e5fdacf --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_CAINFO_BLOB.3 @@ -0,0 +1,74 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2021, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PROXY_CAINFO_BLOB 3 "31 March 2021" "libcurl 7.76.0" "curl_easy_setopt options" +.SH NAME +CURLOPT_PROXY_CAINFO_BLOB \- proxy Certificate Authority (CA) bundle in PEM format +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_CAINFO_BLOB, struct curl_blob *stblob); +.SH DESCRIPTION +This option is for connecting to an HTTPS proxy, not an HTTPS server. + +Pass a pointer to a curl_blob structure, which contains information (pointer +and size) about a memory block with binary data of PEM encoded content holding +one or more certificates to verify the HTTPS proxy with. + +If \fICURLOPT_PROXY_SSL_VERIFYPEER(3)\fP is zero and you avoid verifying the +server's certificate, \fICURLOPT_PROXY_CAINFO_BLOB(3)\fP is not needed. + +This option overrides \fICURLOPT_PROXY_CAINFO(3)\fP. +.SH DEFAULT +NULL +.SH PROTOCOLS +Used with HTTPS proxy +.SH EXAMPLE +.nf +char *strpem; /* strpem must point to a PEM string */ +CURL *curl = curl_easy_init(); +if(curl) { + struct curl_blob blob; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* using an HTTPS proxy */ + curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost:443"); + blob.data = strpem; + blob.len = strlen(strpem); + blob.flags = CURL_BLOB_COPY; + curl_easy_setopt(curl, CURLOPT_PROXY_CAINFO_BLOB, &blob); + ret = curl_easy_perform(curl); + curl_easy_cleanup(curl); +} +.fi +.SH AVAILABILITY +Added in 7.76.0 + +This option is supported by the OpenSSL backends. +.SH RETURN VALUE +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. +.SH "SEE ALSO" +.BR CURLOPT_PROXY_CAINFO "(3), " CURLOPT_PROXY_CAPATH "(3), " +.BR CURLOPT_PROXY_SSL_VERIFYPEER "(3), " CURLOPT_PROXY_SSL_VERIFYHOST "(3), " +.BR CURLOPT_CAINFO "(3), " CURLOPT_CAINFO_BLOB "(3), " +.BR CURLOPT_CAPATH "(3), " +.BR CURLOPT_SSL_VERIFYPEER "(3), " CURLOPT_SSL_VERIFYHOST "(3), " diff --git a/docs/libcurl/opts/Makefile.inc b/docs/libcurl/opts/Makefile.inc index 69e2418620c0c3..1181331b980710 100644 --- a/docs/libcurl/opts/Makefile.inc +++ b/docs/libcurl/opts/Makefile.inc @@ -115,6 +115,7 @@ man_MANS = \ CURLOPT_AUTOREFERER.3 \ CURLOPT_BUFFERSIZE.3 \ CURLOPT_CAINFO.3 \ + CURLOPT_CAINFO_BLOB.3 \ CURLOPT_CAPATH.3 \ CURLOPT_CERTINFO.3 \ CURLOPT_CHUNK_BGN_FUNCTION.3 \ @@ -267,6 +268,7 @@ man_MANS = \ CURLOPT_PROXYUSERNAME.3 \ CURLOPT_PROXYUSERPWD.3 \ CURLOPT_PROXY_CAINFO.3 \ + CURLOPT_PROXY_CAINFO_BLOB.3 \ CURLOPT_PROXY_CAPATH.3 \ CURLOPT_PROXY_CRLFILE.3 \ CURLOPT_PROXY_KEYPASSWD.3 \ diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index 5ff3a350332bed..00f95eebc43a94 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -373,6 +373,7 @@ CURLOPT_APPEND 7.17.0 CURLOPT_AUTOREFERER 7.1 CURLOPT_BUFFERSIZE 7.10 CURLOPT_CAINFO 7.4.2 +CURLOPT_CAINFO_BLOB 7.76.0 CURLOPT_CAPATH 7.9.8 CURLOPT_CERTINFO 7.19.1 CURLOPT_CHUNK_BGN_FUNCTION 7.21.0 @@ -542,6 +543,7 @@ CURLOPT_PROXYTYPE 7.10 CURLOPT_PROXYUSERNAME 7.19.1 CURLOPT_PROXYUSERPWD 7.1 CURLOPT_PROXY_CAINFO 7.52.0 +CURLOPT_PROXY_CAINFO_BLOB 7.76.0 CURLOPT_PROXY_CAPATH 7.52.0 CURLOPT_PROXY_CRLFILE 7.52.0 CURLOPT_PROXY_ISSUERCERT 7.71.0 diff --git a/include/curl/curl.h b/include/curl/curl.h index bed8068b0b6faa..ed158a6b55216d 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -2088,6 +2088,14 @@ typedef enum { /* Same as CURLOPT_SSL_VERIFYSTATUS but for DOH (DNS-over-HTTPS) servers. */ CURLOPT(CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 308), + /* The CA certificates as "blob" used to validate the peer certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CURLOPT(CURLOPT_CAINFO_BLOB, CURLOPTTYPE_BLOB, 309), + + /* The CA certificates as "blob" used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CURLOPT(CURLOPT_PROXY_CAINFO_BLOB, CURLOPTTYPE_BLOB, 310), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff --git a/lib/doh.c b/lib/doh.c index 15cdc35a46949f..593589077396a0 100644 --- a/lib/doh.c +++ b/lib/doh.c @@ -313,6 +313,10 @@ static CURLcode dohprobe(struct Curl_easy *data, ERROR_CHECK_SETOPT(CURLOPT_CAINFO, data->set.str[STRING_SSL_CAFILE]); } + if(data->set.blobs[BLOB_CAINFO]) { + ERROR_CHECK_SETOPT(CURLOPT_CAINFO_BLOB, + data->set.blobs[BLOB_CAINFO]); + } if(data->set.str[STRING_SSL_CAPATH]) { ERROR_CHECK_SETOPT(CURLOPT_CAPATH, data->set.str[STRING_SSL_CAPATH]); diff --git a/lib/easyoptions.c b/lib/easyoptions.c index db8337b044ab1d..4e65e3525bf585 100644 --- a/lib/easyoptions.c +++ b/lib/easyoptions.c @@ -38,6 +38,7 @@ struct curl_easyoption Curl_easyopts[] = { {"AWS_SIGV4", CURLOPT_AWS_SIGV4, CURLOT_STRING, 0}, {"BUFFERSIZE", CURLOPT_BUFFERSIZE, CURLOT_LONG, 0}, {"CAINFO", CURLOPT_CAINFO, CURLOT_STRING, 0}, + {"CAINFO_BLOB", CURLOPT_CAINFO_BLOB, CURLOT_BLOB, 0}, {"CAPATH", CURLOPT_CAPATH, CURLOT_STRING, 0}, {"CERTINFO", CURLOPT_CERTINFO, CURLOT_LONG, 0}, {"CHUNK_BGN_FUNCTION", CURLOPT_CHUNK_BGN_FUNCTION, CURLOT_FUNCTION, 0}, @@ -205,6 +206,7 @@ struct curl_easyoption Curl_easyopts[] = { {"PROXYUSERNAME", CURLOPT_PROXYUSERNAME, CURLOT_STRING, 0}, {"PROXYUSERPWD", CURLOPT_PROXYUSERPWD, CURLOT_STRING, 0}, {"PROXY_CAINFO", CURLOPT_PROXY_CAINFO, CURLOT_STRING, 0}, + {"PROXY_CAINFO_BLOB", CURLOPT_PROXY_CAINFO_BLOB, CURLOT_BLOB, 0}, {"PROXY_CAPATH", CURLOPT_PROXY_CAPATH, CURLOT_STRING, 0}, {"PROXY_CRLFILE", CURLOPT_PROXY_CRLFILE, CURLOT_STRING, 0}, {"PROXY_ISSUERCERT", CURLOPT_PROXY_ISSUERCERT, CURLOT_STRING, 0}, @@ -352,6 +354,6 @@ struct curl_easyoption Curl_easyopts[] = { */ int Curl_easyopts_check(void) { - return ((CURLOPT_LASTENTRY%10000) != (308 + 1)); + return ((CURLOPT_LASTENTRY%10000) != (310 + 1)); } #endif diff --git a/lib/setopt.c b/lib/setopt.c index a1666a4e03c037..10075019b5be62 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -2019,6 +2019,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE], va_arg(param, char *)); break; + case CURLOPT_CAINFO_BLOB: + /* + * Blob that holds CA info for SSL connection. + * Specify entire PEM of the CA certificate + */ + result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO], + va_arg(param, struct curl_blob *)); + break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_CAINFO: /* @@ -2028,6 +2036,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY], va_arg(param, char *)); break; + case CURLOPT_PROXY_CAINFO_BLOB: + /* + * Blob that holds CA info for SSL connection proxy. + * Specify entire PEM of the CA certificate + */ + result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO_PROXY], + va_arg(param, struct curl_blob *)); + break; #endif case CURLOPT_CAPATH: /* diff --git a/lib/url.c b/lib/url.c index 69dc081add45b5..49cdd642d4c4a7 100644 --- a/lib/url.c +++ b/lib/url.c @@ -3731,6 +3731,7 @@ static CURLcode create_conn(struct Curl_easy *data, data->set.ssl.primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT]; + data->set.ssl.primary.ca_info_blob = data->set.blobs[BLOB_CAINFO]; data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES]; #ifndef CURL_DISABLE_PROXY @@ -3746,6 +3747,8 @@ static CURLcode create_conn(struct Curl_easy *data, data->set.proxy_ssl.primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]; data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY]; + data->set.proxy_ssl.primary.ca_info_blob = + data->set.blobs[BLOB_CAINFO_PROXY]; data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY]; data->set.proxy_ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY]; data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY]; diff --git a/lib/urldata.h b/lib/urldata.h index fb37905a7bb32a..a0e9685f178791 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -253,6 +253,7 @@ struct ssl_primary_config { char *cipher_list13; /* list of TLS 1.3 cipher suites to use */ char *pinned_key; struct curl_blob *cert_blob; + struct curl_blob *ca_info_blob; char *curves; /* list of curves to use */ BIT(verifypeer); /* set TRUE if this is desired */ BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */ @@ -1615,6 +1616,8 @@ enum dupblob { BLOB_KEY_PROXY, BLOB_SSL_ISSUERCERT, BLOB_SSL_ISSUERCERT_PROXY, + BLOB_CAINFO, + BLOB_CAINFO_PROXY, BLOB_LAST }; diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 9989ca460cf461..e3b0a087709a62 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -2476,6 +2476,55 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid) return res; } +static CURLcode load_cacert_from_memory(SSL_CTX *ctx, + const struct curl_blob *ca_info_blob) +{ + /* these need freed at the end */ + BIO *cbio = NULL; + STACK_OF(X509_INFO) *inf = NULL; + + /* everything else is just a reference */ + int i, count = 0; + X509_STORE *cts = NULL; + X509_INFO *itmp = NULL; + + if(ca_info_blob->len > (size_t)INT_MAX) + return CURLE_SSL_CACERT_BADFILE; + + cts = SSL_CTX_get_cert_store(ctx); + if(!cts) + return CURLE_OUT_OF_MEMORY; + + cbio = BIO_new_mem_buf(ca_info_blob->data, (int)ca_info_blob->len); + if(!cbio) + return CURLE_OUT_OF_MEMORY; + + inf = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL); + if(!inf) { + BIO_free(cbio); + return CURLE_SSL_CACERT_BADFILE; + } + + /* add each entry from PEM file to x509_store */ + for(i = 0; i < (int)sk_X509_INFO_num(inf); ++i) { + itmp = sk_X509_INFO_value(inf, i); + if(itmp->x509) { + X509_STORE_add_cert(cts, itmp->x509); + ++count; + } + if(itmp->crl) { + X509_STORE_add_crl(cts, itmp->crl); + ++count; + } + } + + sk_X509_INFO_pop_free(inf, X509_INFO_free); + BIO_free(cbio); + + /* if we didn't end up importing anything, treat that as an error */ + return (count > 0 ? CURLE_OK : CURLE_SSL_CACERT_BADFILE); +} + static CURLcode ossl_connect_step1(struct Curl_easy *data, struct connectdata *conn, int sockindex) { @@ -2503,8 +2552,11 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, #endif char * const ssl_cert = SSL_SET_OPTION(primary.clientcert); const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob); + const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob); const char * const ssl_cert_type = SSL_SET_OPTION(cert_type); - const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); + const char * const ssl_cafile = + /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ + (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile)); const char * const ssl_capath = SSL_CONN_CONFIG(CApath); const bool verifypeer = SSL_CONN_CONFIG(verifypeer); const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); @@ -2997,6 +3049,19 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, } #endif + if(ca_info_blob) { + result = load_cacert_from_memory(backend->ctx, ca_info_blob); + if(result) { + if(result == CURLE_OUT_OF_MEMORY || + (verifypeer && !imported_native_ca)) { + failf(data, "error importing CA certificate blob"); + return result; + } + /* Only warning if no certificate verification is required. */ + infof(data, "error importing CA certificate blob, continuing anyway\n"); + } + } + #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */ { @@ -3053,7 +3118,8 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, #endif #ifdef CURL_CA_FALLBACK - if(verifypeer && !ssl_cafile && !ssl_capath && !imported_native_ca) { + if(verifypeer && + !ca_info_blob && !ssl_cafile && !ssl_capath && !imported_native_ca) { /* verifying the peer without any CA certificates won't work so use openssl's built in default as fallback */ SSL_CTX_set_default_verify_paths(backend->ctx); diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 6a0069237fdb24..888ce7ad20eca5 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -135,6 +135,7 @@ Curl_ssl_config_matches(struct ssl_primary_config *data, (data->verifyhost == needle->verifyhost) && (data->verifystatus == needle->verifystatus) && blobcmp(data->cert_blob, needle->cert_blob) && + blobcmp(data->ca_info_blob, needle->ca_info_blob) && Curl_safe_strcasecompare(data->CApath, needle->CApath) && Curl_safe_strcasecompare(data->CAfile, needle->CAfile) && Curl_safe_strcasecompare(data->clientcert, needle->clientcert) && @@ -161,6 +162,7 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source, dest->sessionid = source->sessionid; CLONE_BLOB(cert_blob); + CLONE_BLOB(ca_info_blob); CLONE_STRING(CApath); CLONE_STRING(CAfile); CLONE_STRING(clientcert); @@ -185,6 +187,7 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc) Curl_safefree(sslc->cipher_list13); Curl_safefree(sslc->pinned_key); Curl_safefree(sslc->cert_blob); + Curl_safefree(sslc->ca_info_blob); Curl_safefree(sslc->curves); } diff --git a/packages/OS400/curl.inc.in b/packages/OS400/curl.inc.in index c77e2066f3e651..bd0b3ed1509555 100644 --- a/packages/OS400/curl.inc.in +++ b/packages/OS400/curl.inc.in @@ -1464,6 +1464,10 @@ d c 00307 d CURLOPT_DOH_SSL_VERIFYSTATUS... d c 00308 + d CURLOPT_CAINFO_BLOB... + d c 40309 + d CURLOPT_PROXY_CAINFO_BLOB... + d c 40310 * /if not defined(CURL_NO_OLDIES) d CURLOPT_FILE c 10001