tls: use shared init code for TCP+QUIC

Closes #13172
This commit is contained in:
Stefan Eissing 2024-03-22 13:07:25 +01:00 коммит произвёл Daniel Stenberg
Родитель 49573bc187
Коммит 3210101088
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 5CC908FDB71E12C2
27 изменённых файлов: 732 добавлений и 776 удалений

Просмотреть файл

@ -1068,7 +1068,7 @@ static void cf_h1_proxy_close(struct Curl_cfilter *cf,
struct Curl_cftype Curl_cft_h1_proxy = {
"H1-PROXY",
CF_TYPE_IP_CONNECT,
CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
0,
cf_h1_proxy_destroy,
cf_h1_proxy_connect,

Просмотреть файл

@ -1532,7 +1532,7 @@ static bool cf_h2_proxy_is_alive(struct Curl_cfilter *cf,
struct Curl_cftype Curl_cft_h2_proxy = {
"H2-PROXY",
CF_TYPE_IP_CONNECT,
CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
CURL_LOG_LVL_NONE,
cf_h2_proxy_destroy,
cf_h2_proxy_connect,

Просмотреть файл

@ -189,7 +189,7 @@ static void cf_haproxy_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_cftype Curl_cft_haproxy = {
"HAPROXY",
0,
CF_TYPE_PROXY,
0,
cf_haproxy_destroy,
cf_haproxy_connect,

Просмотреть файл

@ -178,10 +178,12 @@ typedef CURLcode Curl_cft_query(struct Curl_cfilter *cf,
* connection, etc.
* CF_TYPE_SSL: provide SSL/TLS
* CF_TYPE_MULTIPLEX: provides multiplexing of easy handles
* CF_TYPE_PROXY provides proxying
*/
#define CF_TYPE_IP_CONNECT (1 << 0)
#define CF_TYPE_SSL (1 << 1)
#define CF_TYPE_MULTIPLEX (1 << 2)
#define CF_TYPE_PROXY (1 << 3)
/* A connection filter type, e.g. specific implementation. */
struct Curl_cftype {

Просмотреть файл

@ -293,7 +293,7 @@ static void http_proxy_cf_close(struct Curl_cfilter *cf,
struct Curl_cftype Curl_cft_http_proxy = {
"HTTP-PROXY",
CF_TYPE_IP_CONNECT,
CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
0,
http_proxy_cf_destroy,
http_proxy_cf_connect,

Просмотреть файл

@ -1244,7 +1244,7 @@ static void socks_cf_get_host(struct Curl_cfilter *cf,
struct Curl_cftype Curl_cft_socks_proxy = {
"SOCKS-PROXYY",
CF_TYPE_IP_CONNECT,
CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
0,
socks_proxy_cf_destroy,
socks_proxy_cf_connect,

Просмотреть файл

@ -279,6 +279,8 @@ struct ssl_peer {
char *dispname; /* display version of hostname */
char *sni; /* SNI version of hostname or NULL if not usable */
ssl_peer_type type; /* type of the peer information */
int port; /* port we are talking to */
int transport; /* TCP or QUIC */
};
struct ssl_primary_config {
@ -344,6 +346,7 @@ struct Curl_ssl_session {
long age; /* just a number, the higher the more recent */
int remote_port; /* remote port */
int conn_to_port; /* remote port for the connection (may be -1) */
int transport; /* TCP or QUIC */
struct ssl_primary_config ssl_config; /* setup for this session */
};

Просмотреть файл

@ -113,7 +113,7 @@ void Curl_ngtcp2_ver(char *p, size_t len)
struct cf_ngtcp2_ctx {
struct cf_quic_ctx q;
struct ssl_peer peer;
struct quic_tls_ctx tls;
struct curl_tls_ctx tls;
ngtcp2_path connected_path;
ngtcp2_conn *qconn;
ngtcp2_cid dcid;
@ -1909,25 +1909,60 @@ static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
(void)save;
}
static CURLcode tls_ctx_setup(struct quic_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data)
#ifdef USE_OPENSSL
/* The "new session" callback must return zero if the session can be removed
* or non-zero if the session has been put into the session cache.
*/
static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
{
struct Curl_cfilter *cf;
struct cf_ngtcp2_ctx *ctx;
struct Curl_easy *data;
ngtcp2_crypto_conn_ref *cref;
cref = (ngtcp2_crypto_conn_ref *)SSL_get_app_data(ssl);
cf = cref? cref->user_data : NULL;
ctx = cf? cf->ctx : NULL;
data = cf? CF_DATA_CURRENT(cf) : NULL;
if(cf && data && ctx) {
CURLcode result = Curl_ossl_add_session(cf, data, &ctx->peer,
ssl_sessionid);
return result? 0 : 1;
}
return 0;
}
#endif /* USE_OPENSSL */
static CURLcode tls_ctx_setup(struct Curl_cfilter *cf,
struct Curl_easy *data,
void *user_data)
{
struct curl_tls_ctx *ctx = user_data;
(void)cf;
#ifdef USE_OPENSSL
#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
if(ngtcp2_crypto_boringssl_configure_client_context(ctx->ssl_ctx) != 0) {
if(ngtcp2_crypto_boringssl_configure_client_context(ctx->ossl.ssl_ctx)
!= 0) {
failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed");
return CURLE_FAILED_INIT;
}
#else
if(ngtcp2_crypto_quictls_configure_client_context(ctx->ssl_ctx) != 0) {
if(ngtcp2_crypto_quictls_configure_client_context(ctx->ossl.ssl_ctx) != 0) {
failf(data, "ngtcp2_crypto_quictls_configure_client_context failed");
return CURLE_FAILED_INIT;
}
#endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */
/* Enable the session cache because it's a prerequisite for the
* "new session" callback. Use the "external storage" mode to prevent
* OpenSSL from creating an internal session cache.
*/
SSL_CTX_set_session_cache_mode(ctx->ossl.ssl_ctx,
SSL_SESS_CACHE_CLIENT |
SSL_SESS_CACHE_NO_INTERNAL);
SSL_CTX_sess_set_new_cb(ctx->ossl.ssl_ctx, ossl_new_session_cb);
#elif defined(USE_GNUTLS)
if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls->session) != 0) {
if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls.session) != 0) {
failf(data, "ngtcp2_crypto_gnutls_configure_client_session failed");
return CURLE_FAILED_INIT;
}
@ -1960,17 +1995,21 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
H3_STREAM_POOL_SPARES);
result = Curl_ssl_peer_init(&ctx->peer, cf);
result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC);
if(result)
return result;
#define H3_ALPN "\x2h3\x5h3-29"
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
H3_ALPN, sizeof(H3_ALPN) - 1,
tls_ctx_setup, &ctx->conn_ref);
tls_ctx_setup, &ctx->tls, &ctx->conn_ref);
if(result)
return result;
#ifdef USE_OPENSSL
SSL_set_quic_use_legacy_codepoint(ctx->tls.ossl.ssl, 0);
#endif
ctx->dcid.datalen = NGTCP2_MAX_CIDLEN;
result = Curl_rand(data, ctx->dcid.data, NGTCP2_MAX_CIDLEN);
if(result)
@ -2012,8 +2051,10 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
if(rc)
return CURLE_QUIC_CONNECT_ERROR;
#ifdef USE_GNUTLS
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls->session);
#ifdef USE_OPENSSL
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ossl.ssl);
#elif defined(USE_GNUTLS)
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls.session);
#else
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ssl);
#endif

Просмотреть файл

@ -281,7 +281,7 @@ static void cf_osslq_h3conn_cleanup(struct cf_osslq_h3conn *h3)
struct cf_osslq_ctx {
struct cf_quic_ctx q;
struct ssl_peer peer;
struct quic_tls_ctx tls;
struct curl_tls_ctx tls;
struct cf_call_data call_data;
struct cf_osslq_h3conn h3;
struct curltime started_at; /* time the current attempt started */
@ -318,7 +318,7 @@ static void cf_osslq_close(struct Curl_cfilter *cf, struct Curl_easy *data)
struct cf_call_data save;
CF_DATA_SAVE(save, cf, data);
if(ctx && ctx->tls.ssl) {
if(ctx && ctx->tls.ossl.ssl) {
/* TODO: send connection close */
CURL_TRC_CF(data, cf, "cf_osslq_close()");
cf_osslq_ctx_clear(ctx);
@ -403,7 +403,7 @@ static CURLcode cf_osslq_ssl_err(struct Curl_cfilter *cf,
(reason == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED))) {
result = CURLE_PEER_FAILED_VERIFICATION;
lerr = SSL_get_verify_result(ctx->tls.ssl);
lerr = SSL_get_verify_result(ctx->tls.ossl.ssl);
if(lerr != X509_V_OK) {
ssl_config->certverifyresult = lerr;
msnprintf(ebuf, sizeof(ebuf),
@ -1047,14 +1047,14 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf,
Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
H3_STREAM_POOL_SPARES);
result = Curl_ssl_peer_init(&ctx->peer, cf);
result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC);
if(result)
goto out;
#define H3_ALPN "\x2h3"
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
H3_ALPN, sizeof(H3_ALPN) - 1,
NULL, NULL);
NULL, NULL, NULL);
if(result)
goto out;
@ -1098,12 +1098,12 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf,
goto out;
}
if(!SSL_set1_initial_peer_addr(ctx->tls.ssl, baddr)) {
if(!SSL_set1_initial_peer_addr(ctx->tls.ossl.ssl, baddr)) {
failf(data, "failed to set the initial peer address");
result = CURLE_FAILED_INIT;
goto out;
}
if(!SSL_set_blocking_mode(ctx->tls.ssl, 0)) {
if(!SSL_set_blocking_mode(ctx->tls.ossl.ssl, 0)) {
failf(data, "failed to turn off blocking mode");
result = CURLE_FAILED_INIT;
goto out;
@ -1111,7 +1111,8 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf,
#ifdef SSL_VALUE_QUIC_IDLE_TIMEOUT
/* Added in OpenSSL v3.3.x */
if(!SSL_set_feature_request_uint(ctx->tls.ssl, SSL_VALUE_QUIC_IDLE_TIMEOUT,
if(!SSL_set_feature_request_uint(ctx->tls.ossl.ssl,
SSL_VALUE_QUIC_IDLE_TIMEOUT,
CURL_QUIC_MAX_IDLE_MS)) {
CURL_TRC_CF(data, cf, "error setting idle timeout, ");
result = CURLE_FAILED_INIT;
@ -1119,13 +1120,13 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf,
}
#endif
SSL_set_bio(ctx->tls.ssl, bio, bio);
SSL_set_bio(ctx->tls.ossl.ssl, bio, bio);
bio = NULL;
SSL_set_connect_state(ctx->tls.ssl);
SSL_set_incoming_stream_policy(ctx->tls.ssl,
SSL_set_connect_state(ctx->tls.ossl.ssl);
SSL_set_incoming_stream_policy(ctx->tls.ossl.ssl,
SSL_INCOMING_STREAM_POLICY_ACCEPT, 0);
/* setup the H3 things on top of the QUIC connection */
result = cf_osslq_h3conn_init(ctx, ctx->tls.ssl, cf);
result = cf_osslq_h3conn_init(ctx, ctx->tls.ossl.ssl, cf);
out:
if(bio)
@ -1288,22 +1289,23 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
struct cf_osslq_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
if(!ctx->tls.ssl)
if(!ctx->tls.ossl.ssl)
goto out;
ERR_clear_error();
/* 1. Check for new incoming streams */
while(1) {
SSL *snew = SSL_accept_stream(ctx->tls.ssl, SSL_ACCEPT_STREAM_NO_BLOCK);
SSL *snew = SSL_accept_stream(ctx->tls.ossl.ssl,
SSL_ACCEPT_STREAM_NO_BLOCK);
if(!snew)
break;
(void)cf_osslq_h3conn_add_stream(&ctx->h3, snew, cf, data);
}
if(!SSL_handle_events(ctx->tls.ssl)) {
int detail = SSL_get_error(ctx->tls.ssl, 0);
if(!SSL_handle_events(ctx->tls.ossl.ssl)) {
int detail = SSL_get_error(ctx->tls.ossl.ssl, 0);
result = cf_osslq_ssl_err(cf, data, detail, CURLE_RECV_ERROR);
}
@ -1370,7 +1372,7 @@ static CURLcode h3_send_streams(struct Curl_cfilter *cf,
struct cf_osslq_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
if(!ctx->tls.ssl || !ctx->h3.conn)
if(!ctx->tls.ossl.ssl || !ctx->h3.conn)
goto out;
for(;;) {
@ -1493,7 +1495,7 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
struct cf_osslq_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
if(!ctx->tls.ssl)
if(!ctx->tls.ossl.ssl)
goto out;
ERR_clear_error();
@ -1501,8 +1503,8 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
if(result)
goto out;
if(!SSL_handle_events(ctx->tls.ssl)) {
int detail = SSL_get_error(ctx->tls.ssl, 0);
if(!SSL_handle_events(ctx->tls.ossl.ssl)) {
int detail = SSL_get_error(ctx->tls.ossl.ssl, 0);
result = cf_osslq_ssl_err(cf, data, detail, CURLE_SEND_ERROR);
}
@ -1522,8 +1524,8 @@ static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
timediff_t timeoutms;
int is_infinite = TRUE;
if(ctx->tls.ssl &&
SSL_get_event_timeout(ctx->tls.ssl, &tv, &is_infinite) &&
if(ctx->tls.ossl.ssl &&
SSL_get_event_timeout(ctx->tls.ossl.ssl, &tv, &is_infinite) &&
!is_infinite) {
timeoutms = curlx_tvtoms(&tv);
/* QUIC want to be called again latest at the returned timeout */
@ -1534,7 +1536,7 @@ static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
result = cf_progress_egress(cf, data);
if(result)
goto out;
if(SSL_get_event_timeout(ctx->tls.ssl, &tv, &is_infinite)) {
if(SSL_get_event_timeout(ctx->tls.ossl.ssl, &tv, &is_infinite)) {
timeoutms = curlx_tvtoms(&tv);
}
}
@ -1579,7 +1581,7 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
goto out;
}
if(!ctx->tls.ssl) {
if(!ctx->tls.ossl.ssl) {
ctx->started_at = now;
result = cf_osslq_ctx_start(cf, data);
if(result)
@ -1595,7 +1597,7 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
}
ERR_clear_error();
err = SSL_do_handshake(ctx->tls.ssl);
err = SSL_do_handshake(ctx->tls.ossl.ssl);
if(err == 1) {
/* connected */
@ -1613,7 +1615,7 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
}
}
else {
int detail = SSL_get_error(ctx->tls.ssl, err);
int detail = SSL_get_error(ctx->tls.ossl.ssl, err);
switch(detail) {
case SSL_ERROR_WANT_READ:
ctx->q.last_io = now;
@ -1644,7 +1646,8 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
}
out:
if(result == CURLE_RECV_ERROR && ctx->tls.ssl && ctx->protocol_shutdown) {
if(result == CURLE_RECV_ERROR && ctx->tls.ossl.ssl &&
ctx->protocol_shutdown) {
/* When a QUIC server instance is shutting down, it may send us a
* CONNECTION_CLOSE right away. Our connection then enters the DRAINING
* state. The CONNECT may work in the near future again. Indicate
@ -1732,7 +1735,7 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
}
DEBUGASSERT(stream->s.id == -1);
*err = cf_osslq_stream_open(&stream->s, ctx->tls.ssl, 0,
*err = cf_osslq_stream_open(&stream->s, ctx->tls.ossl.ssl, 0,
&ctx->stream_bufcp, data);
if(*err) {
failf(data, "can't get bidi streams");
@ -1810,7 +1813,7 @@ static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
CF_DATA_SAVE(save, cf, data);
DEBUGASSERT(cf->connected);
DEBUGASSERT(ctx->tls.ssl);
DEBUGASSERT(ctx->tls.ossl.ssl);
DEBUGASSERT(ctx->h3.conn);
*err = CURLE_OK;
@ -1952,7 +1955,7 @@ static ssize_t cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
CF_DATA_SAVE(save, cf, data);
DEBUGASSERT(cf->connected);
DEBUGASSERT(ctx);
DEBUGASSERT(ctx->tls.ssl);
DEBUGASSERT(ctx->tls.ossl.ssl);
DEBUGASSERT(ctx->h3.conn);
*err = CURLE_OK;
@ -2088,7 +2091,7 @@ static bool cf_osslq_conn_is_alive(struct Curl_cfilter *cf,
CF_DATA_SAVE(save, cf, data);
*input_pending = FALSE;
if(!ctx->tls.ssl)
if(!ctx->tls.ossl.ssl)
goto out;
#ifdef SSL_VALUE_QUIC_IDLE_TIMEOUT
@ -2096,7 +2099,8 @@ static bool cf_osslq_conn_is_alive(struct Curl_cfilter *cf,
{
timediff_t idletime;
uint64_t idle_ms = ctx->max_idle_ms;
if(!SSL_get_value_uint(ctx->tls.ssl, SSL_VALUE_CLASS_FEATURE_NEGOTIATED,
if(!SSL_get_value_uint(ctx->tls.ossl.ssl,
SSL_VALUE_CLASS_FEATURE_NEGOTIATED,
SSL_VALUE_QUIC_IDLE_TIMEOUT, &idle_ms)) {
CURL_TRC_CF(data, cf, "error getting negotiated idle timeout, "
"assume connection is dead.");
@ -2136,15 +2140,15 @@ static void cf_osslq_adjust_pollset(struct Curl_cfilter *cf,
{
struct cf_osslq_ctx *ctx = cf->ctx;
if(!ctx->tls.ssl) {
if(!ctx->tls.ossl.ssl) {
/* NOP */
}
else if(!cf->connected) {
/* during handshake, transfer has not started yet. we always
* add our socket for polling if SSL wants to send/recv */
Curl_pollset_set(data, ps, ctx->q.sockfd,
SSL_net_read_desired(ctx->tls.ssl),
SSL_net_write_desired(ctx->tls.ssl));
SSL_net_read_desired(ctx->tls.ossl.ssl),
SSL_net_write_desired(ctx->tls.ossl.ssl));
}
else {
/* once connected, we only modify the socket if it is present.
@ -2153,8 +2157,8 @@ static void cf_osslq_adjust_pollset(struct Curl_cfilter *cf,
Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
if(want_recv || want_send) {
Curl_pollset_set(data, ps, ctx->q.sockfd,
SSL_net_read_desired(ctx->tls.ssl),
SSL_net_write_desired(ctx->tls.ssl));
SSL_net_read_desired(ctx->tls.ossl.ssl),
SSL_net_write_desired(ctx->tls.ossl.ssl));
}
}
}
@ -2170,7 +2174,7 @@ static CURLcode cf_osslq_query(struct Curl_cfilter *cf,
#ifdef SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL
/* Added in OpenSSL v3.3.x */
uint64_t v;
if(!SSL_get_value_uint(ctx->tls.ssl, SSL_VALUE_CLASS_GENERIC,
if(!SSL_get_value_uint(ctx->tls.ossl.ssl, SSL_VALUE_CLASS_GENERIC,
SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL, &v)) {
CURL_TRC_CF(data, cf, "error getting available local bidi streams");
return CURLE_HTTP3;

Просмотреть файл

@ -88,7 +88,7 @@ void Curl_quiche_ver(char *p, size_t len)
struct cf_quiche_ctx {
struct cf_quic_ctx q;
struct ssl_peer peer;
struct quic_tls_ctx tls;
struct curl_tls_ctx tls;
quiche_conn *qconn;
quiche_config *cfg;
quiche_h3_conn *h3c;
@ -123,8 +123,8 @@ static void cf_quiche_ctx_clear(struct cf_quiche_ctx *ctx)
quiche_conn_free(ctx->qconn);
if(ctx->cfg)
quiche_config_free(ctx->cfg);
/* quiche just freed ctx->tls.ssl */
ctx->tls.ssl = NULL;
/* quiche just freed it */
ctx->tls.ossl.ssl = NULL;
Curl_vquic_tls_cleanup(&ctx->tls);
Curl_ssl_peer_cleanup(&ctx->peer);
vquic_ctx_free(&ctx->q);
@ -565,7 +565,7 @@ static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
return CURLE_OK;
}
else if(QUICHE_ERR_TLS_FAIL == nread) {
long verify_ok = SSL_get_verify_result(ctx->tls.ssl);
long verify_ok = SSL_get_verify_result(ctx->tls.ossl.ssl);
if(verify_ok != X509_V_OK) {
failf(r->data, "SSL certificate problem: %s",
X509_verify_cert_error_string(verify_ok));
@ -1202,7 +1202,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
if(result)
return result;
result = Curl_ssl_peer_init(&ctx->peer, cf);
result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC);
if(result)
return result;
@ -1237,7 +1237,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
QUICHE_H3_APPLICATION_PROTOCOL,
sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1,
NULL, cf);
NULL, NULL, cf);
if(result)
return result;
@ -1257,7 +1257,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
(struct sockaddr *)&ctx->q.local_addr,
ctx->q.local_addrlen,
&sockaddr->sa_addr, sockaddr->addrlen,
ctx->cfg, ctx->tls.ssl, false);
ctx->cfg, ctx->tls.ossl.ssl, false);
if(!ctx->qconn) {
failf(data, "can't create quiche connection");
return CURLE_OUT_OF_MEMORY;

Просмотреть файл

@ -61,277 +61,12 @@
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif
#ifdef USE_OPENSSL
#define QUIC_CIPHERS \
"TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \
"POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
#define QUIC_GROUPS "P-256:X25519:P-384:P-521"
#elif defined(USE_GNUTLS)
#define QUIC_PRIORITY \
"NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \
"+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
"+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \
"%DISABLE_TLS13_COMPAT_MODE"
#elif defined(USE_WOLFSSL)
#if defined(USE_WOLFSSL)
#define QUIC_CIPHERS \
"TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \
"POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
#define QUIC_GROUPS "P-256:P-384:P-521"
#endif
#ifdef USE_OPENSSL
static void keylog_callback(const SSL *ssl, const char *line)
{
(void)ssl;
Curl_tls_keylog_write_line(line);
}
static CURLcode curl_ossl_init_ctx(struct quic_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
Curl_vquic_tls_ctx_setup *ctx_setup)
{
struct ssl_primary_config *conn_config;
CURLcode result = CURLE_FAILED_INIT;
DEBUGASSERT(!ctx->ssl_ctx);
#ifdef USE_OPENSSL_QUIC
ctx->ssl_ctx = SSL_CTX_new(OSSL_QUIC_client_method());
#else
ctx->ssl_ctx = SSL_CTX_new(TLS_method());
#endif
if(!ctx->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(ctx_setup) {
result = ctx_setup(ctx, cf, data);
if(result)
goto out;
}
SSL_CTX_set_default_verify_paths(ctx->ssl_ctx);
{
const char *curves = conn_config->curves ?
conn_config->curves : QUIC_GROUPS;
if(!SSL_CTX_set1_curves_list(ctx->ssl_ctx, curves)) {
failf(data, "failed setting curves list for QUIC: '%s'", curves);
return CURLE_SSL_CIPHER;
}
}
#ifndef OPENSSL_IS_BORINGSSL
{
const char *ciphers13 = conn_config->cipher_list13 ?
conn_config->cipher_list13 : QUIC_CIPHERS;
if(SSL_CTX_set_ciphersuites(ctx->ssl_ctx, ciphers13) != 1) {
failf(data, "failed setting QUIC cipher suite: %s", ciphers13);
return CURLE_SSL_CIPHER;
}
infof(data, "QUIC cipher selection: %s", ciphers13);
}
#endif
/* Open the file if a TLS or QUIC backend has not done this before. */
Curl_tls_keylog_open();
if(Curl_tls_keylog_enabled()) {
SSL_CTX_set_keylog_callback(ctx->ssl_ctx, keylog_callback);
}
/* OpenSSL always tries to verify the peer, this only says whether it should
* 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(ctx->ssl_ctx, conn_config->verifypeer ?
SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
/* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
/* When a user callback is installed to modify the SSL_CTX,
* we need to do the full initialization before calling it.
* See: #11800 */
if(!ctx->x509_store_setup) {
result = Curl_ssl_setup_x509_store(cf, data, ctx->ssl_ctx);
if(result)
goto out;
ctx->x509_store_setup = TRUE;
}
Curl_set_in_callback(data, true);
result = (*data->set.ssl.fsslctx)(data, ctx->ssl_ctx,
data->set.ssl.fsslctxp);
Curl_set_in_callback(data, false);
if(result) {
failf(data, "error signaled by ssl ctx callback");
goto out;
}
}
result = CURLE_OK;
out:
if(result && ctx->ssl_ctx) {
SSL_CTX_free(ctx->ssl_ctx);
ctx->ssl_ctx = NULL;
}
return result;
}
static CURLcode curl_ossl_set_client_cert(struct quic_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data)
{
SSL_CTX *ssl_ctx = ctx->ssl_ctx;
const struct ssl_config_data *ssl_config;
ssl_config = Curl_ssl_cf_get_config(cf, data);
DEBUGASSERT(ssl_config);
if(ssl_config->primary.clientcert ||
ssl_config->primary.cert_blob ||
ssl_config->cert_type) {
return Curl_ossl_set_client_cert(
data, ssl_ctx, ssl_config->primary.clientcert,
ssl_config->primary.cert_blob, ssl_config->cert_type,
ssl_config->key, ssl_config->key_blob,
ssl_config->key_type, ssl_config->key_passwd);
}
return CURLE_OK;
}
/** SSL callbacks ***/
static CURLcode curl_ossl_init_ssl(struct quic_tls_ctx *ctx,
struct Curl_easy *data,
struct ssl_peer *peer,
const char *alpn, size_t alpn_len,
void *user_data)
{
DEBUGASSERT(!ctx->ssl);
ctx->ssl = SSL_new(ctx->ssl_ctx);
SSL_set_app_data(ctx->ssl, user_data);
SSL_set_connect_state(ctx->ssl);
#ifndef USE_OPENSSL_QUIC
SSL_set_quic_use_legacy_codepoint(ctx->ssl, 0);
#endif
if(alpn)
SSL_set_alpn_protos(ctx->ssl, (const uint8_t *)alpn, (int)alpn_len);
if(peer->sni) {
if(!SSL_set_tlsext_host_name(ctx->ssl, peer->sni)) {
failf(data, "Failed set SNI");
SSL_free(ctx->ssl);
ctx->ssl = NULL;
return CURLE_QUIC_CONNECT_ERROR;
}
}
return CURLE_OK;
}
#elif defined(USE_GNUTLS)
static int keylog_callback(gnutls_session_t session, const char *label,
const gnutls_datum_t *secret)
{
gnutls_datum_t crandom;
gnutls_datum_t srandom;
gnutls_session_get_random(session, &crandom, &srandom);
if(crandom.size != 32) {
return -1;
}
Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size);
return 0;
}
static CURLcode curl_gtls_init_ctx(struct quic_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
const char *alpn, size_t alpn_len,
Curl_vquic_tls_ctx_setup *ctx_setup,
void *user_data)
{
struct ssl_primary_config *conn_config;
CURLcode result;
gnutls_datum_t alpns[5];
/* this will need some attention when HTTPS proxy over QUIC get fixed */
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, conn_config, &data->set.ssl,
peer, ctx->gtls, pverifyresult);
if(result)
return result;
gnutls_session_set_ptr(ctx->gtls->session, user_data);
if(ctx_setup) {
result = ctx_setup(ctx, cf, data);
if(result)
return result;
}
rc = gnutls_priority_set_direct(ctx->gtls->session, QUIC_PRIORITY, NULL);
if(rc < 0) {
CURL_TRC_CF(data, cf, "gnutls_priority_set_direct failed: %s\n",
gnutls_strerror(rc));
return CURLE_QUIC_CONNECT_ERROR;
}
/* Open the file if a TLS or QUIC backend has not done this before. */
Curl_tls_keylog_open();
if(Curl_tls_keylog_enabled()) {
gnutls_session_set_keylog_function(ctx->gtls->session, keylog_callback);
}
/* convert the ALPN string from our arguments to a list of strings
* that gnutls wants and will convert internally back to this very
* string for sending to the server. nice. */
if(alpn) {
size_t i, alen = alpn_len;
unsigned char *s = (unsigned char *)alpn;
unsigned char slen;
for(i = 0; (i < ARRAYSIZE(alpns)) && alen; ++i) {
slen = s[0];
if(slen >= alen)
return CURLE_FAILED_INIT;
alpns[i].data = s + 1;
alpns[i].size = slen;
s += slen + 1;
alen -= (size_t)slen + 1;
}
if(alen) /* not all alpn chars used, wrong format or too many */
return CURLE_FAILED_INIT;
if(i) {
gnutls_alpn_set_protocols(ctx->gtls->session,
alpns, (unsigned int)i,
GNUTLS_ALPN_MANDATORY);
}
}
return CURLE_OK;
}
#elif defined(USE_WOLFSSL)
#if defined(HAVE_SECRET_CALLBACK)
static void keylog_callback(const WOLFSSL *ssl, const char *line)
@ -341,10 +76,11 @@ static void keylog_callback(const WOLFSSL *ssl, const char *line)
}
#endif
static CURLcode curl_wssl_init_ctx(struct quic_tls_ctx *ctx,
static CURLcode curl_wssl_init_ctx(struct curl_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
Curl_vquic_tls_ctx_setup *ctx_setup)
Curl_vquic_tls_ctx_setup *cb_setup,
void *cb_user_data)
{
struct ssl_primary_config *conn_config;
CURLcode result = CURLE_FAILED_INIT;
@ -361,8 +97,8 @@ static CURLcode curl_wssl_init_ctx(struct quic_tls_ctx *ctx,
goto out;
}
if(ctx_setup) {
result = ctx_setup(ctx, cf, data);
if(cb_setup) {
result = cb_setup(cf, data, cb_user_data);
if(result)
goto out;
}
@ -458,7 +194,7 @@ out:
/** SSL callbacks ***/
static CURLcode curl_wssl_init_ssl(struct quic_tls_ctx *ctx,
static CURLcode curl_wssl_init_ssl(struct curl_tls_ctx *ctx,
struct Curl_easy *data,
struct ssl_peer *peer,
const char *alpn, size_t alpn_len,
@ -486,57 +222,50 @@ static CURLcode curl_wssl_init_ssl(struct quic_tls_ctx *ctx,
}
#endif /* defined(USE_WOLFSSL) */
CURLcode Curl_vquic_tls_init(struct quic_tls_ctx *ctx,
CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
const char *alpn, size_t alpn_len,
Curl_vquic_tls_ctx_setup *ctx_setup,
void *user_data)
Curl_vquic_tls_ctx_setup *cb_setup,
void *cb_user_data, void *ssl_user_data)
{
CURLcode result;
#ifdef USE_OPENSSL
result = curl_ossl_init_ctx(ctx, cf, data, ctx_setup);
if(result)
return result;
result = curl_ossl_set_client_cert(ctx, cf, data);
if(result)
return result;
return curl_ossl_init_ssl(ctx, data, peer, alpn, alpn_len, user_data);
(void)result;
return Curl_ossl_ctx_init(&ctx->ossl, cf, data, peer, TRNSPRT_QUIC,
(const unsigned char *)alpn, alpn_len,
cb_setup, cb_user_data, NULL, ssl_user_data);
#elif defined(USE_GNUTLS)
(void)result;
return curl_gtls_init_ctx(ctx, cf, data, peer, alpn, alpn_len,
ctx_setup, user_data);
return Curl_gtls_ctx_init(&ctx->gtls, cf, data, peer,
(const unsigned char *)alpn, alpn_len,
cb_setup, cb_user_data, ssl_user_data);
#elif defined(USE_WOLFSSL)
result = curl_wssl_init_ctx(ctx, cf, data, ctx_setup);
result = curl_wssl_init_ctx(ctx, cf, data, cb_setup, cb_user_data);
if(result)
return result;
return curl_wssl_init_ssl(ctx, data, peer, alpn, alpn_len, user_data);
return curl_wssl_init_ssl(ctx, data, peer, alpn, alpn_len, ssl_user_data);
#else
#error "no TLS lib in used, should not happen"
return CURLE_FAILED_INIT;
#endif
}
void Curl_vquic_tls_cleanup(struct quic_tls_ctx *ctx)
void Curl_vquic_tls_cleanup(struct curl_tls_ctx *ctx)
{
#ifdef USE_OPENSSL
if(ctx->ssl)
SSL_free(ctx->ssl);
if(ctx->ssl_ctx)
SSL_CTX_free(ctx->ssl_ctx);
if(ctx->ossl.ssl)
SSL_free(ctx->ossl.ssl);
if(ctx->ossl.ssl_ctx)
SSL_CTX_free(ctx->ossl.ssl_ctx);
#elif defined(USE_GNUTLS)
if(ctx->gtls) {
if(ctx->gtls->cred)
gnutls_certificate_free_credentials(ctx->gtls->cred);
if(ctx->gtls->session)
gnutls_deinit(ctx->gtls->session);
free(ctx->gtls);
}
if(ctx->gtls.cred)
gnutls_certificate_free_credentials(ctx->gtls.cred);
if(ctx->gtls.session)
gnutls_deinit(ctx->gtls.session);
#elif defined(USE_WOLFSSL)
if(ctx->ssl)
wolfSSL_free(ctx->ssl);
@ -546,16 +275,16 @@ void Curl_vquic_tls_cleanup(struct quic_tls_ctx *ctx)
memset(ctx, 0, sizeof(*ctx));
}
CURLcode Curl_vquic_tls_before_recv(struct quic_tls_ctx *ctx,
CURLcode Curl_vquic_tls_before_recv(struct curl_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data)
{
#ifdef USE_OPENSSL
if(!ctx->x509_store_setup) {
CURLcode result = Curl_ssl_setup_x509_store(cf, data, ctx->ssl_ctx);
if(!ctx->ossl.x509_store_setup) {
CURLcode result = Curl_ssl_setup_x509_store(cf, data, ctx->ossl.ssl_ctx);
if(result)
return result;
ctx->x509_store_setup = TRUE;
ctx->ossl.x509_store_setup = TRUE;
}
#else
(void)ctx; (void)cf; (void)data;
@ -563,7 +292,7 @@ CURLcode Curl_vquic_tls_before_recv(struct quic_tls_ctx *ctx,
return CURLE_OK;
}
CURLcode Curl_vquic_tls_verify_peer(struct quic_tls_ctx *ctx,
CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer)
@ -575,36 +304,24 @@ CURLcode Curl_vquic_tls_verify_peer(struct quic_tls_ctx *ctx,
if(!conn_config)
return CURLE_FAILED_INIT;
if(conn_config->verifyhost) {
#ifdef USE_OPENSSL
X509 *server_cert;
server_cert = SSL_get1_peer_certificate(ctx->ssl);
if(!server_cert) {
return CURLE_PEER_FAILED_VERIFICATION;
}
result = Curl_ossl_verifyhost(data, cf->conn, peer, server_cert);
X509_free(server_cert);
if(result)
return result;
(void)conn_config;
result = Curl_oss_check_peer_cert(cf, data, &ctx->ossl, peer);
#elif defined(USE_GNUTLS)
result = Curl_gtls_verifyserver(data, ctx->gtls->session,
if(conn_config->verifyhost) {
result = Curl_gtls_verifyserver(data, ctx->gtls.session,
conn_config, &data->set.ssl, peer,
data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
if(result)
return result;
}
#elif defined(USE_WOLFSSL)
(void)data;
if(conn_config->verifyhost) {
if(!peer->sni ||
wolfSSL_check_domain_name(ctx->ssl, peer->sni) == SSL_FAILURE)
return CURLE_PEER_FAILED_VERIFICATION;
#endif
infof(data, "Verified certificate just fine");
}
else
infof(data, "Skipped certificate verification");
#ifdef USE_OPENSSL
if(data->set.ssl.certinfo)
/* asked to gather certificate info */
(void)Curl_ossl_certchain(data, ctx->ssl);
#endif
return result;
}

Просмотреть файл

@ -26,21 +26,20 @@
#include "curl_setup.h"
#include "bufq.h"
#include "vtls/openssl.h"
#if defined(ENABLE_QUIC) && \
(defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_WOLFSSL))
struct quic_tls_ctx {
struct curl_tls_ctx {
#ifdef USE_OPENSSL
SSL_CTX *ssl_ctx;
SSL *ssl;
struct ossl_ctx ossl;
#elif defined(USE_GNUTLS)
struct gtls_instance *gtls;
struct gtls_ctx gtls;
#elif defined(USE_WOLFSSL)
WOLFSSL_CTX *ssl_ctx;
WOLFSSL *ssl;
#endif
BIT(x509_store_setup); /* if x509 store has been set up */
};
/**
@ -50,9 +49,9 @@ struct quic_tls_ctx {
* - openssl/wolfssl: SSL_CTX* has just been created
* - gnutls: gtls_client_init() has run
*/
typedef CURLcode Curl_vquic_tls_ctx_setup(struct quic_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data);
typedef CURLcode Curl_vquic_tls_ctx_setup(struct Curl_cfilter *cf,
struct Curl_easy *data,
void *cb_user_data);
/**
* Initialize the QUIC TLS instances based of the SSL configurations
@ -64,23 +63,25 @@ typedef CURLcode Curl_vquic_tls_ctx_setup(struct quic_tls_ctx *ctx,
* @param alpn the ALPN string in protocol format ((len+bytes+)+),
* may be NULL
* @param alpn_len the overall number of bytes in `alpn`
* @param ctx_setup optional callback for very early TLS config
* @param user_data optional pointer to set in TLS application context
* @param cb_setup optional callback for very early TLS config
± @param cb_user_data user_data param for callback
* @param ssl_user_data optional pointer to set in TLS application context
*/
CURLcode Curl_vquic_tls_init(struct quic_tls_ctx *ctx,
CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
const char *alpn, size_t alpn_len,
Curl_vquic_tls_ctx_setup *ctx_setup,
void *user_data);
Curl_vquic_tls_ctx_setup *cb_setup,
void *cb_user_data,
void *ssl_user_data);
/**
* Cleanup all data that has been initialized.
*/
void Curl_vquic_tls_cleanup(struct quic_tls_ctx *ctx);
void Curl_vquic_tls_cleanup(struct curl_tls_ctx *ctx);
CURLcode Curl_vquic_tls_before_recv(struct quic_tls_ctx *ctx,
CURLcode Curl_vquic_tls_before_recv(struct curl_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data);
@ -88,7 +89,7 @@ CURLcode Curl_vquic_tls_before_recv(struct quic_tls_ctx *ctx,
* After the QUIC basic handshake has been, verify that the peer
* (and its certificate) fulfill our requirements.
*/
CURLcode Curl_vquic_tls_verify_peer(struct quic_tls_ctx *ctx,
CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer);

Просмотреть файл

@ -686,7 +686,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "connect_step1, check session cache");
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, &session, NULL)) {
if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &session, NULL)) {
br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
session_set = 1;
infof(data, "BearSSL: reusing session ID");
@ -905,10 +905,11 @@ static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
return CURLE_OUT_OF_MEMORY;
br_ssl_engine_get_session_parameters(&backend->ctx.eng, session);
Curl_ssl_sessionid_lock(data);
incache = !(Curl_ssl_getsessionid(cf, data, &oldsession, NULL));
incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
&oldsession, NULL));
if(incache)
Curl_ssl_delsessionid(data, oldsession);
ret = Curl_ssl_addsessionid(cf, data, session, 0, &added);
ret = Curl_ssl_addsessionid(cf, data, &connssl->peer, session, 0, &added);
Curl_ssl_sessionid_unlock(data);
if(!added)
free(session);

Просмотреть файл

@ -43,6 +43,7 @@
#include "urldata.h"
#include "sendf.h"
#include "inet_pton.h"
#include "keylog.h"
#include "gtls.h"
#include "vtls.h"
#include "vtls_int.h"
@ -59,6 +60,16 @@
/* The last #include file should be: */
#include "memdebug.h"
#ifndef ARRAYSIZE
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif
#define QUIC_PRIORITY \
"NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \
"+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
"+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \
"%DISABLE_TLS13_COMPAT_MODE"
/* Enable GnuTLS debugging by defining GTLSDEBUG */
/*#define GTLSDEBUG */
@ -77,7 +88,7 @@ static bool gtls_inited = FALSE;
# include <gnutls/ocsp.h>
struct gtls_ssl_backend_data {
struct gtls_instance gtls;
struct gtls_ctx gtls;
};
static ssize_t gtls_push(void *s, const void *buf, size_t blen)
@ -330,6 +341,7 @@ static gnutls_x509_crt_fmt_t do_file_type(const char *type)
static CURLcode
set_ssl_version_min_max(struct Curl_easy *data,
struct ssl_peer *peer,
struct ssl_primary_config *conn_config,
const char **prioritylist,
const char *tls13support)
@ -337,6 +349,16 @@ set_ssl_version_min_max(struct Curl_easy *data,
long ssl_version = conn_config->version;
long ssl_version_max = conn_config->version_max;
if(peer->transport == TRNSPRT_QUIC) {
if((ssl_version != CURL_SSLVERSION_DEFAULT) &&
(ssl_version < CURL_SSLVERSION_TLSv1_3)) {
failf(data, "QUIC needs at least TLS version 1.3");
return CURLE_SSL_CONNECT_ERROR;
}
*prioritylist = QUIC_PRIORITY;
return CURLE_OK;
}
if((ssl_version == CURL_SSLVERSION_DEFAULT) ||
(ssl_version == CURL_SSLVERSION_TLSv1))
ssl_version = CURL_SSLVERSION_TLSv1_0;
@ -401,12 +423,12 @@ set_ssl_version_min_max(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
CURLcode gtls_client_init(struct Curl_easy *data,
struct ssl_primary_config *config,
struct ssl_config_data *ssl_config,
struct ssl_peer *peer,
struct gtls_instance *gtls,
long *pverifyresult)
static CURLcode gtls_client_init(struct Curl_easy *data,
struct ssl_primary_config *config,
struct ssl_config_data *ssl_config,
struct ssl_peer *peer,
struct gtls_ctx *gtls,
long *pverifyresult)
{
unsigned int init_flags;
int rc;
@ -578,7 +600,8 @@ CURLcode gtls_client_init(struct Curl_easy *data,
}
/* At this point we know we have a supported TLS version, so set it */
result = set_ssl_version_min_max(data, config, &prioritylist, tls13support);
result = set_ssl_version_min_max(data, peer,
config, &prioritylist, tls13support);
if(result)
return result;
@ -677,46 +700,81 @@ CURLcode gtls_client_init(struct Curl_easy *data,
return CURLE_OK;
}
static CURLcode
gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
static int keylog_callback(gnutls_session_t session, const char *label,
const gnutls_datum_t *secret)
{
gnutls_datum_t crandom;
gnutls_datum_t srandom;
gnutls_session_get_random(session, &crandom, &srandom);
if(crandom.size != 32) {
return -1;
}
Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size);
return 0;
}
CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
const unsigned char *alpn, size_t alpn_len,
Curl_gtls_ctx_setup_cb *cb_setup,
void *cb_user_data,
void *ssl_user_data)
{
struct ssl_connect_data *connssl = cf->ctx;
struct gtls_ssl_backend_data *backend =
(struct gtls_ssl_backend_data *)connssl->backend;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
long * const pverifyresult = &ssl_config->certverifyresult;
CURLcode result;
DEBUGASSERT(backend);
DEBUGASSERT(gctx);
if(connssl->state == ssl_connection_complete)
/* to make us tolerant against being called more than once for the
same connection */
return CURLE_OK;
result = gtls_client_init(data, conn_config, ssl_config,
&connssl->peer,
&backend->gtls, pverifyresult);
result = gtls_client_init(data, conn_config, ssl_config, peer,
gctx, pverifyresult);
if(result)
return result;
if(connssl->alpn) {
struct alpn_proto_buf proto;
gnutls_datum_t alpn[ALPN_ENTRIES_MAX];
size_t i;
gnutls_session_set_ptr(gctx->session, ssl_user_data);
for(i = 0; i < connssl->alpn->count; ++i) {
alpn[i].data = (unsigned char *)connssl->alpn->entries[i];
alpn[i].size = (unsigned)strlen(connssl->alpn->entries[i]);
if(cb_setup) {
result = cb_setup(cf, data, cb_user_data);
if(result)
return result;
}
/* Open the file if a TLS or QUIC backend has not done this before. */
Curl_tls_keylog_open();
if(Curl_tls_keylog_enabled()) {
gnutls_session_set_keylog_function(gctx->session, keylog_callback);
}
/* convert the ALPN string from our arguments to a list of strings
* that gnutls wants and will convert internally back to this very
* string for sending to the server. nice. */
if(alpn) {
gnutls_datum_t alpns[5];
size_t i, alen = alpn_len;
unsigned char *s = (unsigned char *)alpn;
unsigned char slen;
for(i = 0; (i < ARRAYSIZE(alpns)) && alen; ++i) {
slen = s[0];
if(slen >= alen)
return CURLE_FAILED_INIT;
alpns[i].data = s + 1;
alpns[i].size = slen;
s += slen + 1;
alen -= (size_t)slen + 1;
}
if(gnutls_alpn_set_protocols(backend->gtls.session, alpn,
(unsigned)connssl->alpn->count, 0)) {
if(alen) /* not all alpn chars used, wrong format or too many */
return CURLE_FAILED_INIT;
if(i && gnutls_alpn_set_protocols(gctx->session,
alpns, (unsigned int)i,
GNUTLS_ALPN_MANDATORY)) {
failf(data, "failed setting ALPN");
return CURLE_SSL_CONNECT_ERROR;
}
Curl_alpn_to_proto_str(&proto, connssl->alpn);
infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
}
/* This might be a reconnect, so we check for a session ID in the cache
@ -726,16 +784,49 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
size_t ssl_idsize;
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, &ssl_idsize)) {
if(!Curl_ssl_getsessionid(cf, data, peer, &ssl_sessionid, &ssl_idsize)) {
/* we got a session id, use it! */
gnutls_session_set_data(backend->gtls.session,
ssl_sessionid, ssl_idsize);
gnutls_session_set_data(gctx->session, ssl_sessionid, ssl_idsize);
/* Informational message */
infof(data, "SSL reusing session ID");
}
Curl_ssl_sessionid_unlock(data);
}
return CURLE_OK;
}
static CURLcode
gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
struct gtls_ssl_backend_data *backend =
(struct gtls_ssl_backend_data *)connssl->backend;
struct alpn_proto_buf proto;
CURLcode result;
DEBUGASSERT(backend);
DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
if(connssl->state == ssl_connection_complete)
/* to make us tolerant against being called more than once for the
same connection */
return CURLE_OK;
memset(&proto, 0, sizeof(proto));
if(connssl->alpn) {
result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
if(result) {
failf(data, "Error determining ALPN");
return CURLE_SSL_CONNECT_ERROR;
}
}
result = Curl_gtls_ctx_init(&backend->gtls, cf, data, &connssl->peer,
proto.data, proto.len, NULL, NULL, cf);
if(result)
return result;
/* register callback functions and handle to send and receive data. */
gnutls_transport_set_ptr(backend->gtls.session, cf);
@ -1291,7 +1382,8 @@ static CURLcode gtls_verifyserver(struct Curl_cfilter *cf,
gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
Curl_ssl_sessionid_lock(data);
incache = !(Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL));
incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
&ssl_sessionid, NULL));
if(incache) {
/* there was one before in the cache, so instead of risking that the
previous one was rejected, we just kill that and store the new */
@ -1299,8 +1391,9 @@ static CURLcode gtls_verifyserver(struct Curl_cfilter *cf,
}
/* store this session id */
result = Curl_ssl_addsessionid(cf, data, connect_sessionid,
connect_idsize, &added);
result = Curl_ssl_addsessionid(cf, data, &connssl->peer,
connect_sessionid, connect_idsize,
&added);
Curl_ssl_sessionid_unlock(data);
if(!added)
free(connect_sessionid);

Просмотреть файл

@ -45,7 +45,7 @@ struct ssl_primary_config;
struct ssl_config_data;
struct ssl_peer;
struct gtls_instance {
struct gtls_ctx {
gnutls_session_t session;
gnutls_certificate_credentials_t cred;
#ifdef USE_GNUTLS_SRP
@ -53,13 +53,18 @@ struct gtls_instance {
#endif
};
CURLcode
gtls_client_init(struct Curl_easy *data,
struct ssl_primary_config *config,
struct ssl_config_data *ssl_config,
struct ssl_peer *peer,
struct gtls_instance *gtls,
long *pverifyresult);
typedef CURLcode Curl_gtls_ctx_setup_cb(struct Curl_cfilter *cf,
struct Curl_easy *data,
void *user_data);
CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
const unsigned char *alpn, size_t alpn_len,
Curl_gtls_ctx_setup_cb *cb_setup,
void *cb_user_data,
void *ssl_user_data);
CURLcode
Curl_gtls_verifyserver(struct Curl_easy *data,

Просмотреть файл

@ -24,6 +24,7 @@
#include "curl_setup.h"
#if defined(USE_OPENSSL) || \
defined(USE_GNUTLS) || \
defined(USE_WOLFSSL) || \
(defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || \
defined(USE_QUICHE)

Просмотреть файл

@ -589,7 +589,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
#endif
infof(data, "mbedTLS: Connecting to %s:%d", hostname, connssl->port);
infof(data, "mbedTLS: Connecting to %s:%d", hostname, connssl->peer.port);
mbedtls_ssl_config_init(&backend->config);
ret = mbedtls_ssl_config_defaults(&backend->config,
@ -667,7 +667,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
void *old_session = NULL;
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, &old_session, NULL)) {
if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &old_session, NULL)) {
ret = mbedtls_ssl_set_session(&backend->ssl, old_session);
if(ret) {
Curl_ssl_sessionid_unlock(data);
@ -955,11 +955,12 @@ mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
/* If there's already a matching session in the cache, delete it */
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL))
if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
&old_ssl_sessionid, NULL))
Curl_ssl_delsessionid(data, old_ssl_sessionid);
retcode = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid,
0, &added);
retcode = Curl_ssl_addsessionid(cf, data, &connssl->peer,
our_ssl_sessionid, 0, &added);
Curl_ssl_sessionid_unlock(data);
if(!added) {
mbedtls_ssl_session_free(our_ssl_sessionid);

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -36,6 +36,39 @@
#include "urldata.h"
/* Struct to hold a Curl OpenSSL instance */
struct ossl_ctx {
/* these ones requires specific SSL-types */
SSL_CTX* ssl_ctx;
SSL* ssl;
X509* server_cert;
BIO_METHOD *bio_method;
CURLcode io_result; /* result of last BIO cfilter operation */
#ifndef HAVE_KEYLOG_CALLBACK
/* Set to true once a valid keylog entry has been created to avoid dupes. */
BIT(keylog_done);
#endif
BIT(x509_store_setup); /* x509 store has been set up */
BIT(reused_session); /* session-ID was reused for this */
};
typedef CURLcode Curl_ossl_ctx_setup_cb(struct Curl_cfilter *cf,
struct Curl_easy *data,
void *user_data);
typedef int Curl_ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid);
CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
int transport, /* TCP or QUIC */
const unsigned char *alpn, size_t alpn_len,
Curl_ossl_ctx_setup_cb *cb_setup,
void *cb_user_data,
Curl_ossl_new_session_cb *cb_new_session,
void *ssl_user_data);
#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
#define SSL_get1_peer_certificate SSL_get_peer_certificate
#endif
@ -66,5 +99,23 @@ CURLcode Curl_ossl_ctx_configure(struct Curl_cfilter *cf,
struct Curl_easy *data,
SSL_CTX *ssl_ctx);
/*
* Add a new session to the cache.
*/
CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
struct Curl_easy *data,
const struct ssl_peer *peer,
SSL_SESSION *ssl_sessionid);
/*
* Get the server cert, verify it and show it, etc., only call failf() if
* ssl config verifypeer or -host is set. Otherwise all this is for
* informational purposes only!
*/
CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ossl_ctx *octx,
struct ssl_peer *peer);
#endif /* USE_OPENSSL */
#endif /* HEADER_CURL_SSLUSE_H */

Просмотреть файл

@ -1071,7 +1071,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGASSERT(backend);
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %d (step 1/3)",
connssl->peer.hostname, connssl->port));
connssl->peer.hostname, connssl->peer.port));
if(curlx_verify_windows_version(5, 1, 0, PLATFORM_WINNT,
VERSION_LESS_THAN_EQUAL)) {
@ -1129,7 +1129,8 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
/* check for an existing reusable credential handle */
if(ssl_config->primary.sessionid) {
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL)) {
if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
(void **)&old_cred, NULL)) {
backend->cred = old_cred;
DEBUGF(infof(data, "schannel: reusing existing credential handle"));
@ -1335,7 +1336,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %d (step 2/3)",
connssl->peer.hostname, connssl->port));
connssl->peer.hostname, connssl->peer.port));
if(!backend->cred || !backend->ctxt)
return CURLE_SSL_CONNECT_ERROR;
@ -1693,7 +1694,7 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %d (step 3/3)",
connssl->peer.hostname, connssl->port));
connssl->peer.hostname, connssl->peer.port));
if(!backend->cred)
return CURLE_SSL_CONNECT_ERROR;
@ -1755,7 +1756,8 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
struct Curl_schannel_cred *old_cred = NULL;
Curl_ssl_sessionid_lock(data);
incache = !(Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL));
incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
(void **)&old_cred, NULL));
if(incache) {
if(old_cred != backend->cred) {
DEBUGF(infof(data,
@ -1766,7 +1768,7 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
if(!incache) {
result = Curl_ssl_addsessionid(cf, data, backend->cred,
result = Curl_ssl_addsessionid(cf, data, &connssl->peer, backend->cred,
sizeof(struct Curl_schannel_cred),
&added);
if(result) {
@ -2493,7 +2495,7 @@ static int schannel_shutdown(struct Curl_cfilter *cf,
if(backend->ctxt) {
infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
connssl->peer.hostname, connssl->port);
connssl->peer.hostname, connssl->peer.port);
}
if(backend->cred && backend->ctxt) {

Просмотреть файл

@ -2047,8 +2047,8 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
size_t ssl_sessionid_len;
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, (void **)&ssl_sessionid,
&ssl_sessionid_len)) {
if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
(void **)&ssl_sessionid, &ssl_sessionid_len)) {
/* we got a session id, use it! */
err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
Curl_ssl_sessionid_unlock(data);
@ -2067,7 +2067,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
aprintf("%s:%d:%d:%s:%d",
ssl_cafile ? ssl_cafile : "(blob memory)",
verifypeer, conn_config->verifyhost, connssl->peer.hostname,
connssl->port);
connssl->peer.port);
ssl_sessionid_len = strlen(ssl_sessionid);
err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
@ -2077,7 +2077,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
}
result = Curl_ssl_addsessionid(cf, data, ssl_sessionid,
result = Curl_ssl_addsessionid(cf, data, &connssl->peer, ssl_sessionid,
ssl_sessionid_len, NULL);
Curl_ssl_sessionid_unlock(data);
if(result) {

Просмотреть файл

@ -534,10 +534,10 @@ void Curl_ssl_sessionid_unlock(struct Curl_easy *data)
*/
bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
struct Curl_easy *data,
const struct ssl_peer *peer,
void **ssl_sessionid,
size_t *idsize) /* set 0 if unknown */
{
struct ssl_connect_data *connssl = cf->ctx;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
struct Curl_ssl_session *check;
@ -567,14 +567,15 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
if(!check->sessionid)
/* not session ID means blank entry */
continue;
if(strcasecompare(connssl->peer.hostname, check->name) &&
if(strcasecompare(peer->hostname, check->name) &&
((!cf->conn->bits.conn_to_host && !check->conn_to_host) ||
(cf->conn->bits.conn_to_host && check->conn_to_host &&
strcasecompare(cf->conn->conn_to_host.name, check->conn_to_host))) &&
((!cf->conn->bits.conn_to_port && check->conn_to_port == -1) ||
(cf->conn->bits.conn_to_port && check->conn_to_port != -1 &&
cf->conn->conn_to_port == check->conn_to_port)) &&
(connssl->port == check->remote_port) &&
(peer->port == check->remote_port) &&
(peer->transport == check->transport) &&
strcasecompare(cf->conn->handler->scheme, check->scheme) &&
match_ssl_primary_config(data, conn_config, &check->ssl_config)) {
/* yes, we have a session ID! */
@ -591,8 +592,7 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
DEBUGF(infof(data, "%s Session ID in cache for %s %s://%s:%d",
no_match? "Didn't find": "Found",
Curl_ssl_cf_is_proxy(cf) ? "proxy" : "host",
cf->conn->handler->scheme, connssl->peer.hostname,
connssl->port));
cf->conn->handler->scheme, peer->hostname, peer->port));
return no_match;
}
@ -642,11 +642,11 @@ void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid)
*/
CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
struct Curl_easy *data,
const struct ssl_peer *peer,
void *ssl_sessionid,
size_t idsize,
bool *added)
{
struct ssl_connect_data *connssl = cf->ctx;
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
size_t i;
@ -668,7 +668,7 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
(void)ssl_config;
DEBUGASSERT(ssl_config->primary.sessionid);
clone_host = strdup(connssl->peer.hostname);
clone_host = strdup(peer->hostname);
if(!clone_host)
return CURLE_OUT_OF_MEMORY; /* bail out */
@ -723,8 +723,9 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
store->conn_to_port = conn_to_port; /* connect to port number */
/* port number */
store->remote_port = connssl->port;
store->remote_port = peer->port;
store->scheme = cf->conn->handler->scheme;
store->transport = peer->transport;
if(!clone_ssl_primary_config(conn_config, &store->ssl_config)) {
Curl_free_primary_ssl_config(&store->ssl_config);
@ -1549,9 +1550,9 @@ static ssl_peer_type get_peer_type(const char *hostname)
return CURL_SSL_PEER_DNS;
}
CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf)
CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf,
int transport)
{
struct ssl_connect_data *connssl = cf->ctx;
const char *ehostname, *edispname;
int eport;
@ -1614,7 +1615,8 @@ CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf)
}
}
connssl->port = eport;
peer->port = eport;
peer->transport = transport;
return CURLE_OK;
}
@ -1667,7 +1669,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
goto out;
*done = FALSE;
result = Curl_ssl_peer_init(&connssl->peer, cf);
result = Curl_ssl_peer_init(&connssl->peer, cf, TRNSPRT_TCP);
if(result)
goto out;
@ -1857,7 +1859,7 @@ struct Curl_cftype Curl_cft_ssl = {
struct Curl_cftype Curl_cft_ssl_proxy = {
"SSL-PROXY",
CF_TYPE_SSL,
CF_TYPE_SSL|CF_TYPE_PROXY,
CURL_LOG_LVL_NONE,
ssl_cf_destroy,
ssl_cf_connect,
@ -2033,12 +2035,7 @@ CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf)
{
#ifndef CURL_DISABLE_PROXY
return (cf->cft == &Curl_cft_ssl_proxy);
#else
(void)cf;
return FALSE;
#endif
return (cf->cft->flags & CF_TYPE_SSL) && (cf->cft->flags & CF_TYPE_PROXY);
}
struct ssl_config_data *

Просмотреть файл

@ -107,7 +107,8 @@ void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy);
/**
* Init SSL peer information for filter. Can be called repeatedly.
*/
CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf);
CURLcode Curl_ssl_peer_init(struct ssl_peer *peer,
struct Curl_cfilter *cf, int transport);
/**
* Free all allocated data and reset peer information.
*/

Просмотреть файл

@ -73,9 +73,7 @@ struct ssl_connect_data {
void *backend; /* vtls backend specific props */
struct cf_call_data call_data; /* data handle used in current call */
struct curltime handshake_done; /* time when handshake finished */
int port; /* remote port at origin */
BIT(use_alpn); /* if ALPN shall be used in handshake */
BIT(reused_session); /* session-ID was reused for this */
BIT(peer_closed); /* peer has closed connection */
};
@ -181,6 +179,7 @@ bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf);
*/
bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
struct Curl_easy *data,
const struct ssl_peer *peer,
void **ssl_sessionid,
size_t *idsize); /* set 0 if unknown */
/* add a new session ID
@ -190,6 +189,7 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
*/
CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
struct Curl_easy *data,
const struct ssl_peer *peer,
void *ssl_sessionid,
size_t idsize,
bool *added);

Просмотреть файл

@ -409,11 +409,11 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
#if defined(WOLFSSL_ALLOW_TLSV10) && !defined(NO_OLD_TLS)
req_method = TLSv1_client_method();
use_sni(TRUE);
break;
#else
failf(data, "wolfSSL does not support TLS 1.0");
return CURLE_NOT_BUILT_IN;
#endif
break;
case CURL_SSLVERSION_TLSv1_1:
#ifndef NO_OLD_TLS
req_method = TLSv1_1_client_method();
@ -481,6 +481,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_SSL_CONNECT_ERROR;
}
#endif
FALLTHROUGH();
default:
break;
}
@ -711,7 +712,8 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
void *ssl_sessionid = NULL;
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)) {
if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
&ssl_sessionid, NULL)) {
/* we got a session id, use it! */
if(!SSL_set_session(backend->handle, ssl_sessionid)) {
Curl_ssl_delsessionid(data, ssl_sessionid);
@ -968,7 +970,8 @@ wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
if(our_ssl_sessionid) {
Curl_ssl_sessionid_lock(data);
incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL));
incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
&old_ssl_sessionid, NULL));
if(incache) {
if(old_ssl_sessionid != our_ssl_sessionid) {
infof(data, "old SSL session ID is stale, removing");
@ -978,7 +981,8 @@ wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
}
if(!incache) {
result = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid, 0, NULL);
result = Curl_ssl_addsessionid(cf, data, &connssl->peer,
our_ssl_sessionid, 0, NULL);
if(result) {
Curl_ssl_sessionid_unlock(data);
wolfSSL_SESSION_free(our_ssl_sessionid);

Просмотреть файл

@ -142,7 +142,8 @@ static size_t write_cb(char *ptr, size_t size, size_t nmemb, void *opaque)
}
static void add_transfer(CURLM *multi, CURLSH *share,
struct curl_slist *resolve, const char *url)
struct curl_slist *resolve,
const char *url, int http_version)
{
CURL *easy;
CURLMcode mc;
@ -159,7 +160,7 @@ static void add_transfer(CURLM *multi, CURLSH *share,
curl_easy_setopt(easy, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(easy, CURLOPT_AUTOREFERER, 1L);
curl_easy_setopt(easy, CURLOPT_FAILONERROR, 1L);
curl_easy_setopt(easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_easy_setopt(easy, CURLOPT_HTTP_VERSION, http_version);
curl_easy_setopt(easy, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(easy, CURLOPT_WRITEDATA, NULL);
curl_easy_setopt(easy, CURLOPT_HTTPGET, 1L);
@ -190,13 +191,19 @@ int main(int argc, char *argv[])
int msgs_in_queue;
int add_more, waits, ongoing = 0;
char *host, *port;
int http_version = CURL_HTTP_VERSION_1_1;
if(argc != 2) {
fprintf(stderr, "%s URL\n", argv[0]);
if(argc != 3) {
fprintf(stderr, "%s proto URL\n", argv[0]);
exit(2);
}
url = argv[1];
if(!strcmp("h2", argv[1]))
http_version = CURL_HTTP_VERSION_2;
else if(!strcmp("h3", argv[1]))
http_version = CURL_HTTP_VERSION_3ONLY;
url = argv[2];
cu = curl_url();
if(!cu) {
fprintf(stderr, "out of memory\n");
@ -234,7 +241,7 @@ int main(int argc, char *argv[])
curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);
add_transfer(multi, share, &resolve, url);
add_transfer(multi, share, &resolve, url, http_version);
++ongoing;
add_more = 6;
waits = 3;
@ -260,7 +267,7 @@ int main(int argc, char *argv[])
}
else {
while(add_more) {
add_transfer(multi, share, &resolve, url);
add_transfer(multi, share, &resolve, url, http_version);
++ongoing;
--add_more;
}

Просмотреть файл

@ -434,13 +434,14 @@ class TestDownload:
assert r.exit_code == 0, f'{client.dump_logs()}'
# Special client that tests TLS session reuse in parallel transfers
def test_02_26_session_shared_reuse(self, env: Env, httpd, repeat):
curl = CurlClient(env=env)
url = f'https://{env.domain1}:{env.https_port}/data-100k'
# TODO: just uses a single connection for h2/h3. Not sure how to prevent that
@pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
def test_02_26_session_shared_reuse(self, env: Env, proto, httpd, nghttpx, repeat):
url = f'https://{env.authority_for(env.domain1, proto)}/data-100k'
client = LocalClient(name='tls-session-reuse', env=env)
if not client.exists():
pytest.skip(f'example client not built: {client.name}')
r = client.run(args=[url])
r = client.run(args=[proto, url])
r.check_exit_code(0)
# test on paused transfers, based on issue #11982