From: Stefan Eissing Date: Thu, 26 Oct 2023 09:27:42 +0000 (+0200) Subject: vtls: cleanup SSL config management X-Git-Tag: curl-8_5_0~167 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bf0e278a3c54bc7fee7360da17c489f5d9a02a72;p=thirdparty%2Fcurl.git vtls: cleanup SSL config management - remove `Curl_ssl_get_config()`, no longer needed Closes #12204 --- diff --git a/lib/setopt.c b/lib/setopt.c index 15a00f9e5b..5178feaea6 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -1921,10 +1921,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) TRUE : FALSE; /* Update the current connection ssl_config. */ - if(data->conn) { - data->conn->ssl_config.verifypeer = - data->set.ssl.primary.verifypeer; - } + Curl_ssl_conn_config_update(data, FALSE); break; #ifndef CURL_DISABLE_DOH case CURLOPT_DOH_SSL_VERIFYPEER: @@ -1944,10 +1941,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) (0 != va_arg(param, long))?TRUE:FALSE; /* Update the current connection proxy_ssl_config. */ - if(data->conn) { - data->conn->proxy_ssl_config.verifypeer = - data->set.proxy_ssl.primary.verifypeer; - } + Curl_ssl_conn_config_update(data, TRUE); break; #endif case CURLOPT_SSL_VERIFYHOST: @@ -1962,10 +1956,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) data->set.ssl.primary.verifyhost = (bool)((arg & 3) ? TRUE : FALSE); /* Update the current connection ssl_config. */ - if(data->conn) { - data->conn->ssl_config.verifyhost = - data->set.ssl.primary.verifyhost; - } + Curl_ssl_conn_config_update(data, FALSE); break; #ifndef CURL_DISABLE_DOH case CURLOPT_DOH_SSL_VERIFYHOST: @@ -1987,12 +1978,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) /* Treat both 1 and 2 as TRUE */ data->set.proxy_ssl.primary.verifyhost = (bool)((arg & 3)?TRUE:FALSE); - /* Update the current connection proxy_ssl_config. */ - if(data->conn) { - data->conn->proxy_ssl_config.verifyhost = - data->set.proxy_ssl.primary.verifyhost; - } + Curl_ssl_conn_config_update(data, TRUE); break; #endif case CURLOPT_SSL_VERIFYSTATUS: @@ -2008,10 +1995,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) TRUE : FALSE; /* Update the current connection ssl_config. */ - if(data->conn) { - data->conn->ssl_config.verifystatus = - data->set.ssl.primary.verifystatus; - } + Curl_ssl_conn_config_update(data, FALSE); break; #ifndef CURL_DISABLE_DOH case CURLOPT_DOH_SSL_VERIFYSTATUS: diff --git a/lib/url.c b/lib/url.c index 92feb97a4c..c0e726a7eb 100644 --- a/lib/url.c +++ b/lib/url.c @@ -526,26 +526,16 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) Curl_mime_initpart(&set->mimepost); - /* - * libcurl 7.10 introduced SSL verification *by default*! This needs to be - * switched off unless wanted. - */ + Curl_ssl_easy_config_init(data); #ifndef CURL_DISABLE_DOH set->doh_verifyhost = TRUE; set->doh_verifypeer = TRUE; #endif - set->ssl.primary.verifypeer = TRUE; - set->ssl.primary.verifyhost = TRUE; #ifdef USE_SSH /* defaults to any auth type */ set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; set->new_directory_perms = 0755; /* Default permissions */ #endif - set->ssl.primary.sessionid = TRUE; /* session ID caching enabled by - default */ -#ifndef CURL_DISABLE_PROXY - set->proxy_ssl = set->ssl; -#endif set->new_file_perms = 0644; /* Default permissions */ set->allowed_protocols = (curl_prot_t) CURLPROTO_ALL; @@ -707,7 +697,6 @@ static void conn_free(struct Curl_easy *data, struct connectdata *conn) Curl_safefree(conn->socks_proxy.passwd); Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */ Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */ - Curl_free_primary_ssl_config(&conn->proxy_ssl_config); #endif Curl_safefree(conn->user); Curl_safefree(conn->passwd); @@ -722,7 +711,7 @@ static void conn_free(struct Curl_easy *data, struct connectdata *conn) Curl_safefree(conn->hostname_resolve); Curl_safefree(conn->secondaryhostname); Curl_safefree(conn->localdev); - Curl_free_primary_ssl_config(&conn->ssl_config); + Curl_ssl_conn_config_cleanup(conn); #ifdef USE_UNIX_SOCKETS Curl_safefree(conn->unix_domain_socket); @@ -1220,12 +1209,10 @@ ConnectionExists(struct Curl_easy *data, continue; else if(needle->handler->flags&PROTOPT_SSL) { /* use double layer ssl */ - if(!Curl_ssl_config_matches(&needle->proxy_ssl_config, - &check->proxy_ssl_config)) + if(!Curl_ssl_conn_config_match(data, needle, check, TRUE)) continue; } - else if(!Curl_ssl_config_matches(&needle->ssl_config, - &check->ssl_config)) + else if(!Curl_ssl_conn_config_match(data, needle, check, FALSE)) continue; } } @@ -1343,8 +1330,7 @@ ConnectionExists(struct Curl_easy *data, if(needle->handler->flags & PROTOPT_SSL) { /* This is a SSL connection so verify that we're using the same SSL options as well */ - if(!Curl_ssl_config_matches(&needle->ssl_config, - &check->ssl_config)) { + if(!Curl_ssl_conn_config_match(data, needle, check, FALSE)) { DEBUGF(infof(data, "Connection #%" CURL_FORMAT_CURL_OFF_T " has different SSL parameters, can't reuse", @@ -1550,17 +1536,6 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) #ifndef CURL_DISABLE_FTP conn->bits.ftp_use_epsv = data->set.ftp_use_epsv; conn->bits.ftp_use_eprt = data->set.ftp_use_eprt; -#endif - conn->ssl_config.verifystatus = data->set.ssl.primary.verifystatus; - conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer; - conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost; - conn->ssl_config.ssl_options = data->set.ssl.primary.ssl_options; -#ifndef CURL_DISABLE_PROXY - conn->proxy_ssl_config.verifystatus = - data->set.proxy_ssl.primary.verifystatus; - conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer; - conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost; - conn->proxy_ssl_config.ssl_options = data->set.proxy_ssl.primary.ssl_options; #endif conn->ip_version = data->set.ipver; conn->connect_only = data->set.connect_only; @@ -3587,85 +3562,10 @@ static CURLcode create_conn(struct Curl_easy *data, conn->send[SECONDARYSOCKET] = Curl_conn_send; conn->bits.tcp_fastopen = data->set.tcp_fastopen; - /* Get a cloned copy of the SSL config situation stored in the - connection struct. But to get this going nicely, we must first make - sure that the strings in the master copy are pointing to the correct - strings in the session handle strings array! - - Keep in mind that the pointers in the master copy are pointing to strings - that will be freed as part of the Curl_easy struct, but all cloned - copies will be separately allocated. - */ - data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH]; - data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE]; - data->set.ssl.primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT]; - data->set.ssl.primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT]; - data->set.ssl.primary.cipher_list = - data->set.str[STRING_SSL_CIPHER_LIST]; - data->set.ssl.primary.cipher_list13 = - data->set.str[STRING_SSL_CIPHER13_LIST]; - 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 - data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; - data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY]; - data->set.proxy_ssl.primary.cipher_list = - data->set.str[STRING_SSL_CIPHER_LIST_PROXY]; - data->set.proxy_ssl.primary.cipher_list13 = - data->set.str[STRING_SSL_CIPHER13_LIST_PROXY]; - 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.primary.issuercert = - data->set.str[STRING_SSL_ISSUERCERT_PROXY]; - data->set.proxy_ssl.primary.issuercert_blob = - data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY]; - data->set.proxy_ssl.primary.CRLfile = - data->set.str[STRING_SSL_CRLFILE_PROXY]; - data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY]; - data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY]; - data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY]; - data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY]; - data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY]; - data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY]; -#endif - data->set.ssl.primary.CRLfile = data->set.str[STRING_SSL_CRLFILE]; - data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE]; - data->set.ssl.key = data->set.str[STRING_KEY]; - data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE]; - data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD]; - data->set.ssl.primary.clientcert = data->set.str[STRING_CERT]; -#ifdef USE_TLS_SRP - data->set.ssl.primary.username = data->set.str[STRING_TLSAUTH_USERNAME]; - data->set.ssl.primary.password = data->set.str[STRING_TLSAUTH_PASSWORD]; -#ifndef CURL_DISABLE_PROXY - data->set.proxy_ssl.primary.username = - data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; - data->set.proxy_ssl.primary.password = - data->set.str[STRING_TLSAUTH_PASSWORD_PROXY]; -#endif -#endif - data->set.ssl.key_blob = data->set.blobs[BLOB_KEY]; - - if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary, - &conn->ssl_config)) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - -#ifndef CURL_DISABLE_PROXY - if(!Curl_clone_primary_ssl_config(&data->set.proxy_ssl.primary, - &conn->proxy_ssl_config)) { - result = CURLE_OUT_OF_MEMORY; + /* Init the SSL configuration for the connection from settings in data */ + result = Curl_ssl_conn_config_init(data, conn); + if(result) goto out; - } -#endif prune_dead_connections(data); diff --git a/lib/vquic/curl_msh3.c b/lib/vquic/curl_msh3.c index 9c94a8ec17..1a5692305a 100644 --- a/lib/vquic/curl_msh3.c +++ b/lib/vquic/curl_msh3.c @@ -38,6 +38,7 @@ #include "http1.h" #include "curl_msh3.h" #include "socketpair.h" +#include "vtls/vtls.h" #include "vquic/vquic.h" /* The last 3 #include files should be in this order */ @@ -796,14 +797,20 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_msh3_ctx *ctx = cf->ctx; - bool verify = !!cf->conn->ssl_config.verifypeer; + struct ssl_primary_config *conn_config; MSH3_ADDR addr = {0}; CURLcode result; + bool verify; + + conn_config = Curl_ssl_cf_get_primary_config(cf); + if(!conn_config) + return CURLE_FAILED_INIT; + verify = !!conn_config->verifypeer; memcpy(&addr, &ctx->addr.sa_addr, ctx->addr.addrlen); MSH3_SET_PORT(&addr, (uint16_t)cf->conn->remote_port); - if(verify && (cf->conn->ssl_config.CAfile || cf->conn->ssl_config.CApath)) { + if(verify && (conn_config->CAfile || conn_config->CApath)) { /* TODO: need a way to provide trust anchors to MSH3 */ #ifdef DEBUGBUILD /* we need this for our test cases to run */ diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index a967f90b28..121d85fcfd 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -440,14 +440,19 @@ static CURLcode quic_ssl_ctx(SSL_CTX **pssl_ctx, struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_ngtcp2_ctx *ctx = cf->ctx; - struct connectdata *conn = cf->conn; + struct ssl_primary_config *conn_config; CURLcode result = CURLE_FAILED_INIT; - SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method()); + SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method()); if(!ssl_ctx) { result = CURLE_OUT_OF_MEMORY; goto out; } + conn_config = Curl_ssl_cf_get_primary_config(cf); + if(!conn_config) { + result = CURLE_FAILED_INIT; + goto out; + } #if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) if(ngtcp2_crypto_boringssl_configure_client_context(ssl_ctx) != 0) { @@ -464,8 +469,8 @@ static CURLcode quic_ssl_ctx(SSL_CTX **pssl_ctx, SSL_CTX_set_default_verify_paths(ssl_ctx); { - const char *curves = conn->ssl_config.curves ? - conn->ssl_config.curves : QUIC_GROUPS; + const char *curves = conn_config->curves ? + conn_config->curves : QUIC_GROUPS; if(!SSL_CTX_set1_curves_list(ssl_ctx, curves)) { failf(data, "failed setting curves list for QUIC: '%s'", curves); return CURLE_SSL_CIPHER; @@ -474,8 +479,8 @@ static CURLcode quic_ssl_ctx(SSL_CTX **pssl_ctx, #ifndef OPENSSL_IS_BORINGSSL { - const char *ciphers13 = conn->ssl_config.cipher_list13 ? - conn->ssl_config.cipher_list13 : QUIC_CIPHERS; + const char *ciphers13 = conn_config->cipher_list13 ? + conn_config->cipher_list13 : QUIC_CIPHERS; if(SSL_CTX_set_ciphersuites(ssl_ctx, ciphers13) != 1) { failf(data, "failed setting QUIC cipher suite: %s", ciphers13); return CURLE_SSL_CIPHER; @@ -494,7 +499,7 @@ static CURLcode quic_ssl_ctx(SSL_CTX **pssl_ctx, * fail to connect if the verification fails, or if it should continue * anyway. In the latter case the result of the verification is checked with * SSL_get_verify_result() below. */ - SSL_CTX_set_verify(ssl_ctx, conn->ssl_config.verifypeer ? + SSL_CTX_set_verify(ssl_ctx, conn_config->verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); /* give application a chance to interfere with SSL set up. */ @@ -533,7 +538,7 @@ static CURLcode quic_set_client_cert(struct Curl_cfilter *cf, SSL_CTX *ssl_ctx = ctx->sslctx; const struct ssl_config_data *ssl_config; - ssl_config = Curl_ssl_get_config(data, FIRSTSOCKET); + ssl_config = Curl_ssl_cf_get_config(cf, data); DEBUGASSERT(ssl_config); if(ssl_config->primary.clientcert || ssl_config->primary.cert_blob @@ -591,6 +596,7 @@ static CURLcode quic_init_ssl(struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_ngtcp2_ctx *ctx = cf->ctx; + struct ssl_primary_config *conn_config; CURLcode result; gnutls_datum_t alpn[2]; /* this will need some attention when HTTPS proxy over QUIC get fixed */ @@ -598,12 +604,16 @@ static CURLcode quic_init_ssl(struct Curl_cfilter *cf, long * const pverifyresult = &data->set.ssl.certverifyresult; int rc; + conn_config = Curl_ssl_cf_get_primary_config(cf); + if(!conn_config) + return CURLE_FAILED_INIT; + DEBUGASSERT(ctx->gtls == NULL); ctx->gtls = calloc(1, sizeof(*(ctx->gtls))); if(!ctx->gtls) return CURLE_OUT_OF_MEMORY; - result = gtls_client_init(data, &cf->conn->ssl_config, &data->set.ssl, + result = gtls_client_init(data, conn_config, &data->set.ssl, hostname, ctx->gtls, pverifyresult); if(result) return result; @@ -644,10 +654,17 @@ static CURLcode quic_init_ssl(struct Curl_cfilter *cf, static CURLcode quic_ssl_ctx(WOLFSSL_CTX **pssl_ctx, struct Curl_cfilter *cf, struct Curl_easy *data) { - struct connectdata *conn = cf->conn; CURLcode result = CURLE_FAILED_INIT; - WOLFSSL_CTX *ssl_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()); + struct ssl_primary_config *conn_config; + WOLFSSL_CTX *ssl_ctx = NULL; + conn_config = Curl_ssl_cf_get_primary_config(cf); + if(!conn_config) { + result = CURLE_FAILED_INIT; + goto out; + } + + ssl_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()); if(!ssl_ctx) { result = CURLE_OUT_OF_MEMORY; goto out; @@ -655,13 +672,14 @@ static CURLcode quic_ssl_ctx(WOLFSSL_CTX **pssl_ctx, if(ngtcp2_crypto_wolfssl_configure_client_context(ssl_ctx) != 0) { failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed"); + result = CURLE_FAILED_INIT; goto out; } wolfSSL_CTX_set_default_verify_paths(ssl_ctx); - if(wolfSSL_CTX_set_cipher_list(ssl_ctx, conn->ssl_config.cipher_list13 ? - conn->ssl_config.cipher_list13 : + if(wolfSSL_CTX_set_cipher_list(ssl_ctx, conn_config->cipher_list13 ? + conn_config->cipher_list13 : QUIC_CIPHERS) != 1) { char error_buffer[256]; ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer)); @@ -669,8 +687,8 @@ static CURLcode quic_ssl_ctx(WOLFSSL_CTX **pssl_ctx, goto out; } - if(wolfSSL_CTX_set1_groups_list(ssl_ctx, conn->ssl_config.curves ? - conn->ssl_config.curves : + if(wolfSSL_CTX_set1_groups_list(ssl_ctx, conn_config->curves ? + conn_config->curves : (char *)QUIC_GROUPS) != 1) { failf(data, "wolfSSL failed to set curves"); goto out; @@ -687,9 +705,9 @@ static CURLcode quic_ssl_ctx(WOLFSSL_CTX **pssl_ctx, #endif } - if(conn->ssl_config.verifypeer) { - const char * const ssl_cafile = conn->ssl_config.CAfile; - const char * const ssl_capath = conn->ssl_config.CApath; + if(conn_config->verifypeer) { + const char * const ssl_cafile = conn_config->CAfile; + const char * const ssl_capath = conn_config->CApath; wolfSSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); if(ssl_cafile || ssl_capath) { @@ -1912,11 +1930,16 @@ static CURLcode qng_verify_peer(struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_ngtcp2_ctx *ctx = cf->ctx; + struct ssl_primary_config *conn_config; CURLcode result = CURLE_OK; const char *hostname, *disp_hostname; int port; char *snihost; + conn_config = Curl_ssl_cf_get_primary_config(cf); + if(!conn_config) + return CURLE_FAILED_INIT; + Curl_conn_get_host(data, cf->sockindex, &hostname, &disp_hostname, &port); snihost = Curl_ssl_snihost(data, hostname, NULL); if(!snihost) @@ -1926,7 +1949,7 @@ static CURLcode qng_verify_peer(struct Curl_cfilter *cf, cf->conn->httpversion = 30; cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX; - if(cf->conn->ssl_config.verifyhost) { + if(conn_config->verifyhost) { #ifdef USE_OPENSSL X509 *server_cert; server_cert = SSL_get_peer_certificate(ctx->ssl); @@ -1939,7 +1962,7 @@ static CURLcode qng_verify_peer(struct Curl_cfilter *cf, return result; #elif defined(USE_GNUTLS) result = Curl_gtls_verifyserver(data, ctx->gtls->session, - &cf->conn->ssl_config, &data->set.ssl, + conn_config, &data->set.ssl, hostname, disp_hostname, data->set.str[STRING_SSL_PINNEDPUBLICKEY]); if(result) diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index f8fa370c80..814414944c 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -139,11 +139,16 @@ static CURLcode quic_x509_store_setup(struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_quiche_ctx *ctx = cf->ctx; + struct ssl_primary_config *conn_config; + + conn_config = Curl_ssl_cf_get_primary_config(cf); + if(!conn_config) + return CURLE_FAILED_INIT; if(!ctx->x509_store_setup) { - if(cf->conn->ssl_config.verifypeer) { - const char * const ssl_cafile = cf->conn->ssl_config.CAfile; - const char * const ssl_capath = cf->conn->ssl_config.CApath; + if(conn_config->verifypeer) { + const char * const ssl_cafile = conn_config->CAfile; + const char * const ssl_capath = conn_config->CApath; if(ssl_cafile || ssl_capath) { SSL_CTX_set_verify(ctx->sslctx, SSL_VERIFY_PEER, NULL); /* tell OpenSSL where to find CA certificates that are used to verify @@ -176,9 +181,12 @@ static CURLcode quic_x509_store_setup(struct Curl_cfilter *cf, static CURLcode quic_ssl_setup(struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_quiche_ctx *ctx = cf->ctx; + struct ssl_primary_config *conn_config; unsigned char checkip[16]; - struct connectdata *conn = data->conn; - const char *curves = conn->ssl_config.curves; + + conn_config = Curl_ssl_cf_get_primary_config(cf); + if(!conn_config) + return CURLE_FAILED_INIT; DEBUGASSERT(!ctx->sslctx); ctx->sslctx = SSL_CTX_new(TLS_method()); @@ -197,8 +205,10 @@ static CURLcode quic_ssl_setup(struct Curl_cfilter *cf, struct Curl_easy *data) SSL_CTX_set_keylog_callback(ctx->sslctx, keylog_callback); } - if(curves && !SSL_CTX_set1_curves_list(ctx->sslctx, curves)) { - failf(data, "failed setting curves list for QUIC: '%s'", curves); + if(conn_config->curves && + !SSL_CTX_set1_curves_list(ctx->sslctx, conn_config->curves)) { + failf(data, "failed setting curves list for QUIC: '%s'", + conn_config->curves); return CURLE_SSL_CIPHER; } @@ -1239,13 +1249,18 @@ static CURLcode cf_verify_peer(struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_quiche_ctx *ctx = cf->ctx; + struct ssl_primary_config *conn_config; CURLcode result = CURLE_OK; + conn_config = Curl_ssl_cf_get_primary_config(cf); + if(!conn_config) + return CURLE_FAILED_INIT; + cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ cf->conn->httpversion = 30; cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX; - if(cf->conn->ssl_config.verifyhost) { + if(conn_config->verifyhost) { X509 *server_cert; server_cert = SSL_get_peer_certificate(ctx->ssl); if(!server_cert) { diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 5086aa2842..c2565ef1f1 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -4628,22 +4628,9 @@ static ssize_t ossl_send(struct Curl_cfilter *cf, case SSL_ERROR_SSL: { /* A failure in the SSL library occurred, usually a protocol error. The OpenSSL error queue contains more information on the error. */ - struct Curl_cfilter *cf_ssl_next = Curl_ssl_cf_get_ssl(cf->next); - struct ssl_connect_data *connssl_next = cf_ssl_next? - cf_ssl_next->ctx : NULL; sslerror = ERR_get_error(); - if(ERR_GET_LIB(sslerror) == ERR_LIB_SSL && - ERR_GET_REASON(sslerror) == SSL_R_BIO_NOT_SET && - connssl->state == ssl_connection_complete && - (connssl_next && connssl_next->state == ssl_connection_complete) - ) { - char ver[120]; - (void)ossl_version(ver, sizeof(ver)); - failf(data, "Error: %s does not support double SSL tunneling.", ver); - } - else - failf(data, "SSL_write() error: %s", - ossl_strerror(sslerror, error_buffer, sizeof(error_buffer))); + failf(data, "SSL_write() error: %s", + ossl_strerror(sslerror, error_buffer, sizeof(error_buffer))); *curlcode = CURLE_SEND_ERROR; rc = -1; goto out; diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index eea71f2b41..1dca74a226 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -158,40 +158,67 @@ static const struct alpn_spec *alpn_get_spec(int httpwant, bool use_alpn) #endif /* USE_SSL */ -bool -Curl_ssl_config_matches(struct ssl_primary_config *data, - struct ssl_primary_config *needle) -{ - if((data->version == needle->version) && - (data->version_max == needle->version_max) && - (data->ssl_options == needle->ssl_options) && - (data->verifypeer == needle->verifypeer) && - (data->verifyhost == needle->verifyhost) && - (data->verifystatus == needle->verifystatus) && - blobcmp(data->cert_blob, needle->cert_blob) && - blobcmp(data->ca_info_blob, needle->ca_info_blob) && - blobcmp(data->issuercert_blob, needle->issuercert_blob) && - Curl_safecmp(data->CApath, needle->CApath) && - Curl_safecmp(data->CAfile, needle->CAfile) && - Curl_safecmp(data->issuercert, needle->issuercert) && - Curl_safecmp(data->clientcert, needle->clientcert) && +void Curl_ssl_easy_config_init(struct Curl_easy *data) +{ + /* + * libcurl 7.10 introduced SSL verification *by default*! This needs to be + * switched off unless wanted. + */ + data->set.ssl.primary.verifypeer = TRUE; + data->set.ssl.primary.verifyhost = TRUE; + data->set.ssl.primary.sessionid = TRUE; /* session ID caching by default */ +#ifndef CURL_DISABLE_PROXY + data->set.proxy_ssl = data->set.ssl; +#endif +} + +static bool +match_ssl_primary_config(struct Curl_easy *data, + struct ssl_primary_config *c1, + struct ssl_primary_config *c2) +{ + (void)data; + if((c1->version == c2->version) && + (c1->version_max == c2->version_max) && + (c1->ssl_options == c2->ssl_options) && + (c1->verifypeer == c2->verifypeer) && + (c1->verifyhost == c2->verifyhost) && + (c1->verifystatus == c2->verifystatus) && + blobcmp(c1->cert_blob, c2->cert_blob) && + blobcmp(c1->ca_info_blob, c2->ca_info_blob) && + blobcmp(c1->issuercert_blob, c2->issuercert_blob) && + Curl_safecmp(c1->CApath, c2->CApath) && + Curl_safecmp(c1->CAfile, c2->CAfile) && + Curl_safecmp(c1->issuercert, c2->issuercert) && + Curl_safecmp(c1->clientcert, c2->clientcert) && #ifdef USE_TLS_SRP - !Curl_timestrcmp(data->username, needle->username) && - !Curl_timestrcmp(data->password, needle->password) && + !Curl_timestrcmp(c1->username, c2->username) && + !Curl_timestrcmp(c1->password, c2->password) && #endif - strcasecompare(data->cipher_list, needle->cipher_list) && - strcasecompare(data->cipher_list13, needle->cipher_list13) && - strcasecompare(data->curves, needle->curves) && - strcasecompare(data->CRLfile, needle->CRLfile) && - strcasecompare(data->pinned_key, needle->pinned_key)) + strcasecompare(c1->cipher_list, c2->cipher_list) && + strcasecompare(c1->cipher_list13, c2->cipher_list13) && + strcasecompare(c1->curves, c2->curves) && + strcasecompare(c1->CRLfile, c2->CRLfile) && + strcasecompare(c1->pinned_key, c2->pinned_key)) return TRUE; return FALSE; } -bool -Curl_clone_primary_ssl_config(struct ssl_primary_config *source, - struct ssl_primary_config *dest) +bool Curl_ssl_conn_config_match(struct Curl_easy *data, + struct connectdata *conn, + struct connectdata *candidate, + bool proxy) +{ + if(proxy) + return match_ssl_primary_config(data, &conn->proxy_ssl_config, + &candidate->proxy_ssl_config); + return match_ssl_primary_config(data, &conn->ssl_config, + &candidate->ssl_config); +} + +static bool clone_ssl_primary_config(struct ssl_primary_config *source, + struct ssl_primary_config *dest) { dest->version = source->version; dest->version_max = source->version_max; @@ -221,7 +248,7 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source, return TRUE; } -void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc) +static void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc) { Curl_safefree(sslc->CApath); Curl_safefree(sslc->CAfile); @@ -241,6 +268,117 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc) #endif } +static CURLcode Curl_ssl_init_ssl_config(struct Curl_easy *data, + struct ssl_primary_config *config) +{ + data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH]; + data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE]; + data->set.ssl.primary.CRLfile = data->set.str[STRING_SSL_CRLFILE]; + data->set.ssl.primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT]; + data->set.ssl.primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT]; + data->set.ssl.primary.cipher_list = + data->set.str[STRING_SSL_CIPHER_LIST]; + data->set.ssl.primary.cipher_list13 = + data->set.str[STRING_SSL_CIPHER13_LIST]; + 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]; +#ifdef USE_TLS_SRP + data->set.ssl.primary.username = data->set.str[STRING_TLSAUTH_USERNAME]; + data->set.ssl.primary.password = data->set.str[STRING_TLSAUTH_PASSWORD]; +#endif + data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE]; + data->set.ssl.key = data->set.str[STRING_KEY]; + data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE]; + data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD]; + data->set.ssl.primary.clientcert = data->set.str[STRING_CERT]; + data->set.ssl.key_blob = data->set.blobs[BLOB_KEY]; + + if(!clone_ssl_primary_config(&data->set.ssl.primary, config)) + return CURLE_OUT_OF_MEMORY; + return CURLE_OK; +} + +#ifndef CURL_DISABLE_PROXY +static CURLcode +Curl_ssl_init_proxy_ssl_config(struct Curl_easy *data, + struct ssl_primary_config *config) +{ + data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; + data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY]; + data->set.proxy_ssl.primary.cipher_list = + data->set.str[STRING_SSL_CIPHER_LIST_PROXY]; + data->set.proxy_ssl.primary.cipher_list13 = + data->set.str[STRING_SSL_CIPHER13_LIST_PROXY]; + 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.primary.issuercert = + data->set.str[STRING_SSL_ISSUERCERT_PROXY]; + data->set.proxy_ssl.primary.issuercert_blob = + data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY]; + data->set.proxy_ssl.primary.CRLfile = + data->set.str[STRING_SSL_CRLFILE_PROXY]; + data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY]; + data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY]; + data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY]; + data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY]; + data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY]; + data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY]; +#ifdef USE_TLS_SRP + data->set.proxy_ssl.primary.username = + data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; + data->set.proxy_ssl.primary.password = + data->set.str[STRING_TLSAUTH_PASSWORD_PROXY]; +#endif + + if(!clone_ssl_primary_config(&data->set.proxy_ssl.primary, config)) + return CURLE_OUT_OF_MEMORY; + return CURLE_OK; +} +#endif /* !CURL_DISABLE_PROXY */ + +CURLcode Curl_ssl_conn_config_init(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result; + /* Get a cloned copy of the SSL config situation for use in + * the connection. `data` might have a shorter lifetime than `conn`*/ + result = Curl_ssl_init_ssl_config(data, &conn->ssl_config); + if(result) + goto out; +#ifndef CURL_DISABLE_PROXY + result = Curl_ssl_init_proxy_ssl_config(data, &conn->proxy_ssl_config); +#endif +out: + return result; +} + +void Curl_ssl_conn_config_cleanup(struct connectdata *conn) +{ + Curl_free_primary_ssl_config(&conn->ssl_config); +#ifndef CURL_DISABLE_PROXY + Curl_free_primary_ssl_config(&conn->proxy_ssl_config); +#endif +} + +void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy) +{ + /* May be called on an easy that has no connection yet */ + if(data->conn) { + struct ssl_primary_config *src, *dest; + src = for_proxy? &data->set.proxy_ssl.primary : &data->set.ssl.primary; + dest = for_proxy? &data->conn->proxy_ssl_config : &data->conn->ssl_config; + dest->verifyhost = src->verifyhost; + dest->verifypeer = src->verifypeer; + dest->verifystatus = src->verifystatus; + } +} + #ifdef USE_SSL static int multissl_setup(const struct Curl_ssl *backend); #endif @@ -441,7 +579,7 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf, cf->conn->conn_to_port == check->conn_to_port)) && (connssl->port == check->remote_port) && strcasecompare(cf->conn->handler->scheme, check->scheme) && - Curl_ssl_config_matches(conn_config, &check->ssl_config)) { + match_ssl_primary_config(data, conn_config, &check->ssl_config)) { /* yes, we have a session ID! */ (*general_age)++; /* increase general age */ check->age = *general_age; /* set this as used in this age */ @@ -590,7 +728,7 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf, store->remote_port = connssl->port; store->scheme = cf->conn->handler->scheme; - if(!Curl_clone_primary_ssl_config(conn_config, &store->ssl_config)) { + if(!clone_ssl_primary_config(conn_config, &store->ssl_config)) { Curl_free_primary_ssl_config(&store->ssl_config); store->sessionid = NULL; /* let caller free sessionid */ free(clone_host); @@ -1831,6 +1969,16 @@ bool Curl_ssl_supports(struct Curl_easy *data, int option) return (Curl_ssl->supports & option)? TRUE : FALSE; } +static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf) +{ + for(; cf; cf = cf->next) { + if(cf->cft == &Curl_cft_ssl || cf->cft == &Curl_cft_ssl_proxy) + return cf; + } + return NULL; +} + + void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex, CURLINFO info, int n) { @@ -1838,8 +1986,8 @@ void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex, (void)n; if(data->conn) { struct Curl_cfilter *cf; - /* get first filter in chain, if any is present */ - cf = Curl_ssl_cf_get_ssl(data->conn->cfilter[sockindex]); + /* get first SSL filter in chain, if any is present */ + cf = get_ssl_filter(data->conn->cfilter[sockindex]); if(cf) { struct cf_call_data save; CF_DATA_SAVE(save, cf, data); @@ -1869,23 +2017,6 @@ CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data, return result; } -static struct Curl_cfilter *get_ssl_cf_engaged(struct connectdata *conn, - int sockindex) -{ - struct Curl_cfilter *cf, *lowest_ssl_cf = NULL; - - for(cf = conn->cfilter[sockindex]; cf; cf = cf->next) { - if(cf->cft == &Curl_cft_ssl || cf->cft == &Curl_cft_ssl_proxy) { - lowest_ssl_cf = cf; - if(cf->connected || (cf->next && cf->next->connected)) { - /* connected or about to start */ - return cf; - } - } - } - return lowest_ssl_cf; -} - bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf) { return (cf->cft == &Curl_cft_ssl_proxy); @@ -1902,17 +2033,6 @@ Curl_ssl_cf_get_config(struct Curl_cfilter *cf, struct Curl_easy *data) #endif } -struct ssl_config_data * -Curl_ssl_get_config(struct Curl_easy *data, int sockindex) -{ - struct Curl_cfilter *cf; - - (void)data; - DEBUGASSERT(data->conn); - cf = get_ssl_cf_engaged(data->conn, sockindex); - return cf? Curl_ssl_cf_get_config(cf, data) : &data->set.ssl; -} - struct ssl_primary_config * Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf) { @@ -1924,15 +2044,6 @@ Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf) #endif } -struct Curl_cfilter *Curl_ssl_cf_get_ssl(struct Curl_cfilter *cf) -{ - for(; cf; cf = cf->next) { - if(cf->cft == &Curl_cft_ssl || cf->cft == &Curl_cft_ssl_proxy) - return cf; - } - return NULL; -} - CURLcode Curl_alpn_to_proto_buf(struct alpn_proto_buf *buf, const struct alpn_spec *spec) { diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h index 8ad1cf6def..5cedf4730c 100644 --- a/lib/vtls/vtls.h +++ b/lib/vtls/vtls.h @@ -66,14 +66,41 @@ CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, #endif char *Curl_ssl_snihost(struct Curl_easy *data, const char *host, size_t *olen); -bool Curl_ssl_config_matches(struct ssl_primary_config *data, - struct ssl_primary_config *needle); -bool Curl_clone_primary_ssl_config(struct ssl_primary_config *source, - struct ssl_primary_config *dest); -void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc); curl_sslbackend Curl_ssl_backend(void); +/** + * Init ssl config for a new easy handle. + */ +void Curl_ssl_easy_config_init(struct Curl_easy *data); + +/** + * Init SSL configs (main + proxy) for a new connection from the easy handle. + */ +CURLcode Curl_ssl_conn_config_init(struct Curl_easy *data, + struct connectdata *conn); + +/** + * Free allocated resources in SSL configs (main + proxy) for + * the given connection. + */ +void Curl_ssl_conn_config_cleanup(struct connectdata *conn); + +/** + * Return TRUE iff SSL configuration from `conn` is functionally the + * same as the one on `candidate`. + * @param proxy match the proxy SSL config or the main one + */ +bool Curl_ssl_conn_config_match(struct Curl_easy *data, + struct connectdata *conn, + struct connectdata *candidate, + bool proxy); + +/* Update certain connection SSL config flags after they have + * been changed on the easy handle. Will work for `verifypeer`, + * `verifyhost` and `verifystatus`. */ +void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy); + #ifdef USE_SSL int Curl_ssl_init(void); void Curl_ssl_cleanup(void); @@ -159,18 +186,6 @@ CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at, struct Curl_easy *data); #endif /* !CURL_DISABLE_PROXY */ -/** - * Get the SSL configuration that is used on the connection. - * This returns NULL if no SSL is configured. - * Otherwise it returns the config of the first (highest) one that is - * either connected, in handshake or about to start - * (e.g. all filters below it are connected). If SSL filters are present, - * but neither can start operating, return the config of the lowest one - * that will first come into effect when connecting. - */ -struct ssl_config_data *Curl_ssl_get_config(struct Curl_easy *data, - int sockindex); - /** * True iff the underlying SSL implementation supports the option. * Option is one of the defined SSLSUPP_* values. @@ -188,6 +203,18 @@ bool Curl_ssl_supports(struct Curl_easy *data, int ssl_option); void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex, CURLINFO info, int n); +/** + * Get the ssl_config_data in `data` that is relevant for cfilter `cf`. + */ +struct ssl_config_data *Curl_ssl_cf_get_config(struct Curl_cfilter *cf, + struct Curl_easy *data); + +/** + * Get the primary config relevant for the filter from its connection. + */ +struct ssl_primary_config * + Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf); + extern struct Curl_cftype Curl_cft_ssl; extern struct Curl_cftype Curl_cft_ssl_proxy; @@ -209,8 +236,9 @@ extern struct Curl_cftype Curl_cft_ssl_proxy; #define Curl_ssl_get_internals(a,b,c,d) NULL #define Curl_ssl_supports(a,b) FALSE #define Curl_ssl_cfilter_add(a,b,c) CURLE_NOT_BUILT_IN -#define Curl_ssl_get_config(a,b) NULL #define Curl_ssl_cfilter_remove(a,b) CURLE_OK +#define Curl_ssl_cf_get_config(a,b) NULL +#define Curl_ssl_cf_get_primary_config(a) NULL #endif #endif /* HEADER_CURL_VTLS_H */ diff --git a/lib/vtls/vtls_int.h b/lib/vtls/vtls_int.h index 3581087e90..2e65e6303c 100644 --- a/lib/vtls/vtls_int.h +++ b/lib/vtls/vtls_int.h @@ -169,23 +169,6 @@ bool Curl_none_false_start(void); void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data, struct easy_pollset *ps); -/** - * Get the ssl_config_data in `data` that is relevant for cfilter `cf`. - */ -struct ssl_config_data *Curl_ssl_cf_get_config(struct Curl_cfilter *cf, - struct Curl_easy *data); - -/** - * Get the primary config relevant for the filter from its connection. - */ -struct ssl_primary_config * - Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf); - -/** - * Get the first SSL filter in the chain starting with `cf`, or NULL. - */ -struct Curl_cfilter *Curl_ssl_cf_get_ssl(struct Curl_cfilter *cf); - /** * Get the SSL filter below the given one or NULL if there is none. */