mirror of
https://github.com/curl/curl.git
synced 2026-04-11 12:01:42 +08:00
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
This commit is contained in:
parent
81693c77be
commit
2db8ae480f
@ -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;
|
||||
|
||||
@ -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`.
|
||||
*/
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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) */
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user