From: Stefan Eissing Date: Thu, 3 Jul 2025 10:06:41 +0000 (+0200) Subject: quic: implement CURLINFO_TLS_SSL_PTR X-Git-Tag: rc-8_15_0-3~31 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2db8ae480fdcae7f005bf847fbbf837821c8184c;p=thirdparty%2Fcurl.git quic: implement CURLINFO_TLS_SSL_PTR Replace the old Curl_ssl_get_internals() with a new connection filter query to retrieve the information. Implement that filter query for TCP and QUIC TLS filter types. Add tests in client tls_session_reuse to use the info option and check that pointers are returned. Reported-by: Larry Campbell Fixes #17801 Closes #17809 --- diff --git a/lib/cfilters.c b/lib/cfilters.c index 2c11ce56e2..4c0f48606f 100644 --- a/lib/cfilters.c +++ b/lib/cfilters.c @@ -580,6 +580,19 @@ bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex) return conn ? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE; } +bool Curl_conn_get_ssl_info(struct Curl_easy *data, + struct connectdata *conn, int sockindex, + struct curl_tlssessioninfo *info) +{ + if(Curl_conn_is_ssl(conn, sockindex)) { + struct Curl_cfilter *cf = conn->cfilter[sockindex]; + CURLcode result = cf ? cf->cft->query(cf, data, CF_QUERY_SSL_INFO, + NULL, (void *)info) : CURLE_UNKNOWN_OPTION; + return !result; + } + return FALSE; +} + bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex) { struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL; diff --git a/lib/cfilters.h b/lib/cfilters.h index 3c49e15005..1487ff615f 100644 --- a/lib/cfilters.h +++ b/lib/cfilters.h @@ -32,6 +32,7 @@ struct Curl_easy; struct Curl_dns_entry; struct connectdata; struct ip_quadruple; +struct curl_tlssessioninfo; /* Callback to destroy resources held by this filter instance. * Implementations MUST NOT chain calls to cf->next. @@ -151,6 +152,12 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf, * - CF_QUERY_IP_INFO: res1 says if connection used IPv6, res2 is the * ip quadruple * - CF_QUERY_HOST_PORT: the remote hostname and port a filter talks to + * - CF_QUERY_SSL_INFO: fill out the passed curl_tlssessioninfo with the + * internal from the SSL secured connection when + * available. + * - CF_QUERY_SSL_CTX_INFO: same as CF_QUERY_SSL_INFO, but give the SSL_CTX + * when available, or the same internal pointer + * when the TLS stack does not differentiate. */ /* query res1 res2 */ #define CF_QUERY_MAX_CONCURRENT 1 /* number - */ @@ -166,6 +173,8 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf, * to NULL when not connected. */ #define CF_QUERY_REMOTE_ADDR 10 /* - `Curl_sockaddr_ex *` */ #define CF_QUERY_HOST_PORT 11 /* port const char * */ +#define CF_QUERY_SSL_INFO 12 /* - struct curl_tlssessioninfo * */ +#define CF_QUERY_SSL_CTX_INFO 13 /* - struct curl_tlssessioninfo * */ /** * Query the cfilter for properties. Filters ignorant of a query will @@ -380,6 +389,15 @@ bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex); */ bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex); +/* + * Fill `info` with information about the TLS instance securing + * the connection when available, otherwise e.g. when + * Curl_conn_is_ssl() is FALSE, return FALSE. + */ +bool Curl_conn_get_ssl_info(struct Curl_easy *data, + struct connectdata *conn, int sockindex, + struct curl_tlssessioninfo *info); + /** * Connection provides multiplexing of easy handles at `socketindex`. */ diff --git a/lib/getinfo.c b/lib/getinfo.c index 388646bf75..7ff78d2d6d 100644 --- a/lib/getinfo.c +++ b/lib/getinfo.c @@ -28,6 +28,7 @@ #include "urldata.h" #include "getinfo.h" +#include "cfilters.h" #include "vtls/vtls.h" #include "connect.h" /* Curl_getconnectinfo() */ #include "progress.h" @@ -579,19 +580,14 @@ static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info, struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **) param_slistp; struct curl_tlssessioninfo *tsi = &data->tsi; -#ifdef USE_SSL - struct connectdata *conn = data->conn; -#endif + /* we are exposing a pointer to internal memory with unknown + * lifetime here. */ *tsip = tsi; - tsi->backend = Curl_ssl_backend(); - tsi->internals = NULL; - -#ifdef USE_SSL - if(conn && tsi->backend != CURLSSLBACKEND_NONE) { - tsi->internals = Curl_ssl_get_internals(data, FIRSTSOCKET, info, 0); + if(!Curl_conn_get_ssl_info(data, data->conn, FIRSTSOCKET, tsi)) { + tsi->backend = Curl_ssl_backend(); + tsi->internals = NULL; } -#endif } break; default: diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 50dd873767..5d40fd5ccf 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -2655,6 +2655,14 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf, case CF_QUERY_HTTP_VERSION: *pres1 = 30; return CURLE_OK; + case CF_QUERY_SSL_INFO: + case CF_QUERY_SSL_CTX_INFO: { + struct curl_tlssessioninfo *info = pres2; + if(Curl_vquic_tls_get_ssl_info(&ctx->tls, + (query == CF_QUERY_SSL_INFO), info)) + return CURLE_OK; + break; + } default: break; } diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index 8f01ad15e6..d435d7f512 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -2351,6 +2351,14 @@ static CURLcode cf_osslq_query(struct Curl_cfilter *cf, case CF_QUERY_HTTP_VERSION: *pres1 = 30; return CURLE_OK; + case CF_QUERY_SSL_INFO: + case CF_QUERY_SSL_CTX_INFO: { + struct curl_tlssessioninfo *info = pres2; + if(Curl_vquic_tls_get_ssl_info(&ctx->tls, + (query == CF_QUERY_SSL_INFO), info)) + return CURLE_OK; + break; + } default: break; } diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index b52bf9a35a..6d79842fba 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -1553,6 +1553,14 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf, case CF_QUERY_HTTP_VERSION: *pres1 = 30; return CURLE_OK; + case CF_QUERY_SSL_INFO: + case CF_QUERY_SSL_CTX_INFO: { + struct curl_tlssessioninfo *info = pres2; + if(Curl_vquic_tls_get_ssl_info(&ctx->tls, + (query == CF_QUERY_SSL_INFO), info)) + return CURLE_OK; + break; + } default: break; } @@ -1658,20 +1666,4 @@ out: return result; } -bool Curl_conn_is_quiche(const struct Curl_easy *data, - const struct connectdata *conn, - int sockindex) -{ - struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL; - - (void)data; - for(; cf; cf = cf->next) { - if(cf->cft == &Curl_cft_http3) - return TRUE; - if(cf->cft->flags & CF_TYPE_IP_CONNECT) - return FALSE; - } - return FALSE; -} - #endif diff --git a/lib/vquic/curl_quiche.h b/lib/vquic/curl_quiche.h index 9832687bdc..b2c767216f 100644 --- a/lib/vquic/curl_quiche.h +++ b/lib/vquic/curl_quiche.h @@ -41,10 +41,6 @@ CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf, struct connectdata *conn, const struct Curl_addrinfo *ai); -bool Curl_conn_is_quiche(const struct Curl_easy *data, - const struct connectdata *conn, - int sockindex); - #endif #endif /* HEADER_CURL_VQUIC_CURL_QUICHE_H */ diff --git a/lib/vquic/vquic-tls.c b/lib/vquic/vquic-tls.c index 2a5be138fc..e6160b3902 100644 --- a/lib/vquic/vquic-tls.c +++ b/lib/vquic/vquic-tls.c @@ -197,4 +197,28 @@ CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx, } +bool Curl_vquic_tls_get_ssl_info(struct curl_tls_ctx *ctx, + bool give_ssl_ctx, + struct curl_tlssessioninfo *info) +{ +#ifdef USE_OPENSSL + info->backend = CURLSSLBACKEND_OPENSSL; + info->internals = give_ssl_ctx ? + (void *)ctx->ossl.ssl_ctx : (void *)ctx->ossl.ssl; + return TRUE; +#elif defined(USE_GNUTLS) + (void)give_ssl_ctx; /* gnutls always returns its session */ + info->backend = CURLSSLBACKEND_OPENSSL; + info->internals = ctx->gtls.session; + return TRUE; +#elif defined(USE_WOLFSSL) + info->backend = CURLSSLBACKEND_WOLFSSL; + info->internals = give_ssl_ctx ? + (void *)ctx->wssl.ssl_ctx : (void *)ctx->wssl.ssl; + return TRUE; +#else + return FALSE; +#endif +} + #endif /* !USE_HTTP3 && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */ diff --git a/lib/vquic/vquic-tls.h b/lib/vquic/vquic-tls.h index bf29eecc91..49b923a4e4 100644 --- a/lib/vquic/vquic-tls.h +++ b/lib/vquic/vquic-tls.h @@ -37,6 +37,7 @@ struct ssl_peer; struct Curl_ssl_session; +struct curl_tlssessioninfo; struct curl_tls_ctx { #ifdef USE_OPENSSL @@ -106,6 +107,10 @@ CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx, struct Curl_easy *data, struct ssl_peer *peer); +bool Curl_vquic_tls_get_ssl_info(struct curl_tls_ctx *ctx, + bool give_ssl_ctx, + struct curl_tlssessioninfo *info); + #endif /* !USE_HTTP3 && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */ #endif /* HEADER_CURL_VQUIC_TLS_H */ diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index f729ebf739..65ba9df0c4 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -1558,6 +1558,18 @@ static CURLcode ssl_cf_query(struct Curl_cfilter *cf, *when = connssl->handshake_done; return CURLE_OK; } + case CF_QUERY_SSL_INFO: + case CF_QUERY_SSL_CTX_INFO: { + struct curl_tlssessioninfo *info = pres2; + struct cf_call_data save; + CF_DATA_SAVE(save, cf, data); + info->backend = Curl_ssl_backend(); + info->internals = connssl->ssl_impl->get_internals( + cf->ctx, (query == CF_QUERY_SSL_INFO) ? + CURLINFO_TLS_SSL_PTR : CURLINFO_TLS_SESSION); + CF_DATA_RESTORE(cf, save); + return CURLE_OK; + } default: break; } @@ -1727,40 +1739,6 @@ bool Curl_ssl_supports(struct Curl_easy *data, unsigned int ssl_option) return (Curl_ssl->supports & ssl_option); } -static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf) -{ - for(; cf; cf = cf->next) { - if(cf->cft == &Curl_cft_ssl) - return cf; -#ifndef CURL_DISABLE_PROXY - if(cf->cft == &Curl_cft_ssl_proxy) - return cf; -#endif - } - return NULL; -} - - -void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex, - CURLINFO info, int n) -{ - void *result = NULL; - (void)n; - if(data->conn) { - struct Curl_cfilter *cf; - /* get first SSL filter in chain, if any is present */ - cf = get_ssl_filter(data->conn->cfilter[sockindex]); - if(cf) { - struct ssl_connect_data *connssl = cf->ctx; - struct cf_call_data save; - CF_DATA_SAVE(save, cf, data); - result = connssl->ssl_impl->get_internals(cf->ctx, info); - CF_DATA_RESTORE(cf, save); - } - } - return result; -} - static CURLcode vtls_shutdown_blocking(struct Curl_cfilter *cf, struct Curl_easy *data, bool send_shutdown, bool *done) diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h index d37a22a78c..a6cf4e0e74 100644 --- a/lib/vtls/vtls.h +++ b/lib/vtls/vtls.h @@ -233,16 +233,6 @@ CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at, */ bool Curl_ssl_supports(struct Curl_easy *data, unsigned int ssl_option); -/** - * Get the internal ssl instance (like OpenSSL's SSL*) from the filter - * chain at `sockindex` of type specified by `info`. - * For `n` == 0, the first active (top down) instance is returned. - * 1 gives the second active, etc. - * NULL is returned when no active SSL filter is present. - */ -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`. */ @@ -272,7 +262,6 @@ extern struct Curl_cftype Curl_cft_ssl_proxy; #define Curl_ssl_free_certinfo(x) Curl_nop_stmt #define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN) #define Curl_ssl_cert_status_request() FALSE -#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_cfilter_remove(a,b,c) CURLE_OK diff --git a/src/tool_operate.c b/src/tool_operate.c index bd25e99c40..e37ce97be5 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -1494,6 +1494,8 @@ static CURLcode add_parallel_transfers(struct GlobalConfig *global, (void)curl_easy_setopt(per->curl, CURLOPT_PIPEWAIT, global->parallel_connect ? 0L : 1L); (void)curl_easy_setopt(per->curl, CURLOPT_PRIVATE, per); + /* curl does not use signals, switching this on saves some system calls */ + (void)curl_easy_setopt(per->curl, CURLOPT_NOSIGNAL, 1L); (void)curl_easy_setopt(per->curl, CURLOPT_XFERINFOFUNCTION, xferinfo_cb); (void)curl_easy_setopt(per->curl, CURLOPT_XFERINFODATA, per); (void)curl_easy_setopt(per->curl, CURLOPT_NOPROGRESS, 0L); diff --git a/tests/client/tls_session_reuse.c b/tests/client/tls_session_reuse.c index 12bac86747..4e69383f60 100644 --- a/tests/client/tls_session_reuse.c +++ b/tests/client/tls_session_reuse.c @@ -23,16 +23,40 @@ ***************************************************************************/ #include "first.h" +static int tse_found_tls_session = FALSE; + static size_t write_tse_cb(char *ptr, size_t size, size_t nmemb, void *opaque) { + CURL *easy = opaque; (void)ptr; - (void)opaque; + if(!tse_found_tls_session) { + struct curl_tlssessioninfo *tlssession; + CURLcode rc; + + rc = curl_easy_getinfo(easy, CURLINFO_TLS_SSL_PTR, &tlssession); + if(rc) { + curl_mfprintf(stderr, "curl_easy_getinfo(CURLINFO_TLS_SSL_PTR) " + "failed: %s\n", curl_easy_strerror(rc)); + return rc; + } + if(tlssession->backend == CURLSSLBACKEND_NONE) { + curl_mfprintf(stderr, "curl_easy_getinfo(CURLINFO_TLS_SSL_PTR) " + "gave no backend\n"); + return CURLE_FAILED_INIT; + } + if(!tlssession->internals) { + curl_mfprintf(stderr, "curl_easy_getinfo(CURLINFO_TLS_SSL_PTR) " + "missing\n"); + return CURLE_FAILED_INIT; + } + tse_found_tls_session = TRUE; + } return size * nmemb; } -static int add_transfer(CURLM *multi, CURLSH *share, - struct curl_slist *resolve, - const char *url, long http_version) +static CURL *tse_add_transfer(CURLM *multi, CURLSH *share, + struct curl_slist *resolve, + const char *url, long http_version) { CURL *easy; CURLMcode mc; @@ -40,7 +64,7 @@ static int add_transfer(CURLM *multi, CURLSH *share, easy = curl_easy_init(); if(!easy) { curl_mfprintf(stderr, "curl_easy_init failed\n"); - return 1; + return NULL; } curl_easy_setopt(easy, CURLOPT_VERBOSE, 1L); curl_easy_setopt(easy, CURLOPT_DEBUGFUNCTION, debug_cb); @@ -51,7 +75,7 @@ static int add_transfer(CURLM *multi, CURLSH *share, curl_easy_setopt(easy, CURLOPT_FAILONERROR, 1L); curl_easy_setopt(easy, CURLOPT_HTTP_VERSION, http_version); curl_easy_setopt(easy, CURLOPT_WRITEFUNCTION, write_tse_cb); - curl_easy_setopt(easy, CURLOPT_WRITEDATA, NULL); + curl_easy_setopt(easy, CURLOPT_WRITEDATA, easy); curl_easy_setopt(easy, CURLOPT_HTTPGET, 1L); curl_easy_setopt(easy, CURLOPT_SSL_VERIFYPEER, 0L); if(resolve) @@ -63,9 +87,9 @@ static int add_transfer(CURLM *multi, CURLSH *share, curl_mfprintf(stderr, "curl_multi_add_handle: %s\n", curl_multi_strerror(mc)); curl_easy_cleanup(easy); - return 1; + return NULL; } - return 0; + return easy; } static int test_tls_session_reuse(int argc, char *argv[]) @@ -132,7 +156,7 @@ static int test_tls_session_reuse(int argc, char *argv[]) curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); - if(add_transfer(multi, share, resolve, url, http_version)) + if(!tse_add_transfer(multi, share, resolve, url, http_version)) goto cleanup; ++ongoing; add_more = 6; @@ -159,7 +183,7 @@ static int test_tls_session_reuse(int argc, char *argv[]) } else { while(add_more) { - if(add_transfer(multi, share, resolve, url, http_version)) + if(!tse_add_transfer(multi, share, resolve, url, http_version)) goto cleanup; ++ongoing; --add_more; @@ -203,6 +227,12 @@ static int test_tls_session_reuse(int argc, char *argv[]) } while(ongoing || add_more); + if(!tse_found_tls_session) { + curl_mfprintf(stderr, "CURLINFO_TLS_SSL_PTR not found during run\n"); + exitcode = CURLE_FAILED_INIT; + goto cleanup; + } + curl_mfprintf(stderr, "exiting\n"); exitcode = 0;