mirror of
https://github.com/curl/curl.git
synced 2026-08-24 21:13:40 +03:00
quic: use the session cache with wolfSSL as well
Use session cache for QUIC when built with quictls or wolfSSL. Add test_017_10 for verifying QUIC TLS session reuse when built with quictls, gnutls or wolfssl. Closes #15358
This commit is contained in:
parent
b34b757c2e
commit
8cb2d5f48a
7 changed files with 189 additions and 54 deletions
|
|
@ -41,6 +41,7 @@
|
|||
#include "vtls/gtls.h"
|
||||
#elif defined(USE_WOLFSSL)
|
||||
#include <ngtcp2/ngtcp2_crypto_wolfssl.h>
|
||||
#include "vtls/wolfssl.h"
|
||||
#endif
|
||||
|
||||
#include "urldata.h"
|
||||
|
|
@ -2160,11 +2161,11 @@ static int quic_gtls_handshake_cb(gnutls_session_t session, unsigned int htype,
|
|||
{
|
||||
ngtcp2_crypto_conn_ref *conn_ref = gnutls_session_get_ptr(session);
|
||||
struct Curl_cfilter *cf = conn_ref ? conn_ref->user_data : NULL;
|
||||
struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
||||
struct cf_ngtcp2_ctx *ctx = cf ? cf->ctx : NULL;
|
||||
|
||||
(void)msg;
|
||||
(void)incoming;
|
||||
if(when) { /* after message has been processed */
|
||||
if(when && cf && ctx) { /* after message has been processed */
|
||||
struct Curl_easy *data = CF_DATA_CURRENT(cf);
|
||||
DEBUGASSERT(data);
|
||||
if(data) {
|
||||
|
|
@ -2184,12 +2185,32 @@ static int quic_gtls_handshake_cb(gnutls_session_t session, unsigned int htype,
|
|||
}
|
||||
#endif /* USE_GNUTLS */
|
||||
|
||||
#ifdef USE_WOLFSSL
|
||||
static int wssl_quic_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session)
|
||||
{
|
||||
ngtcp2_crypto_conn_ref *conn_ref = wolfSSL_get_app_data(ssl);
|
||||
struct Curl_cfilter *cf = conn_ref ? conn_ref->user_data : NULL;
|
||||
|
||||
DEBUGASSERT(cf != NULL);
|
||||
if(cf && session) {
|
||||
struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
||||
struct Curl_easy *data = CF_DATA_CURRENT(cf);
|
||||
DEBUGASSERT(data);
|
||||
if(data && ctx) {
|
||||
(void)wssl_cache_session(cf, data, &ctx->peer, session);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* USE_WOLFSSL */
|
||||
|
||||
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;
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
|
||||
if(ngtcp2_crypto_boringssl_configure_client_context(ctx->ossl.ssl_ctx)
|
||||
|
|
@ -2203,29 +2224,37 @@ static CURLcode tls_ctx_setup(struct Curl_cfilter *cf,
|
|||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
#endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */
|
||||
/* Enable the session cache because it is 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, quic_ossl_new_session_cb);
|
||||
if(ssl_config->primary.cache_session) {
|
||||
/* Enable the session cache because it is 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, quic_ossl_new_session_cb);
|
||||
}
|
||||
|
||||
#elif defined(USE_GNUTLS)
|
||||
if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls.session) != 0) {
|
||||
failf(data, "ngtcp2_crypto_gnutls_configure_client_session failed");
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
gnutls_handshake_set_hook_function(ctx->gtls.session,
|
||||
GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST,
|
||||
quic_gtls_handshake_cb);
|
||||
if(ssl_config->primary.cache_session) {
|
||||
gnutls_handshake_set_hook_function(ctx->gtls.session,
|
||||
GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST,
|
||||
quic_gtls_handshake_cb);
|
||||
}
|
||||
|
||||
#elif defined(USE_WOLFSSL)
|
||||
if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->wssl.ctx) != 0) {
|
||||
failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
if(ssl_config->primary.cache_session) {
|
||||
/* Register to get notified when a new session is received */
|
||||
wolfSSL_CTX_sess_set_new_cb(ctx->wssl.ctx, wssl_quic_new_session_cb);
|
||||
}
|
||||
#endif
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
|
@ -2305,8 +2334,10 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
|
|||
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
|
||||
#elif defined(USE_WOLFSSL)
|
||||
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.wssl.handle);
|
||||
#else
|
||||
#error "ngtcp2 TLS backend not defined"
|
||||
#endif
|
||||
|
||||
ngtcp2_ccerr_default(&ctx->last_error);
|
||||
|
|
|
|||
|
|
@ -195,12 +195,14 @@ out:
|
|||
/** SSL callbacks ***/
|
||||
|
||||
static CURLcode Curl_wssl_init_ssl(struct curl_tls_ctx *ctx,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct ssl_peer *peer,
|
||||
const char *alpn, size_t alpn_len,
|
||||
void *user_data)
|
||||
{
|
||||
(void)data;
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
|
||||
DEBUGASSERT(!ctx->wssl.handle);
|
||||
DEBUGASSERT(ctx->wssl.ctx);
|
||||
ctx->wssl.handle = wolfSSL_new(ctx->wssl.ctx);
|
||||
|
|
@ -218,6 +220,10 @@ static CURLcode Curl_wssl_init_ssl(struct curl_tls_ctx *ctx,
|
|||
peer->sni, (unsigned short)strlen(peer->sni));
|
||||
}
|
||||
|
||||
if(ssl_config->primary.cache_session) {
|
||||
(void)wssl_setup_session(cf, data, &ctx->wssl, peer);
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
#endif /* defined(USE_WOLFSSL) */
|
||||
|
|
@ -247,7 +253,8 @@ CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
|
|||
if(result)
|
||||
return result;
|
||||
|
||||
return Curl_wssl_init_ssl(ctx, data, peer, alpn, alpn_len, ssl_user_data);
|
||||
return Curl_wssl_init_ssl(ctx, cf, data, peer, alpn, alpn_len,
|
||||
ssl_user_data);
|
||||
#else
|
||||
#error "no TLS lib in used, should not happen"
|
||||
return CURLE_FAILED_INIT;
|
||||
|
|
|
|||
|
|
@ -3974,7 +3974,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
|
|||
#endif
|
||||
|
||||
octx->reused_session = FALSE;
|
||||
if(ssl_config->primary.cache_session && transport == TRNSPRT_TCP) {
|
||||
if(ssl_config->primary.cache_session) {
|
||||
Curl_ssl_sessionid_lock(data);
|
||||
if(!Curl_ssl_getsessionid(cf, data, peer, (void **)&der_sessionid,
|
||||
&der_sessionid_size, NULL)) {
|
||||
|
|
|
|||
|
|
@ -370,13 +370,60 @@ static void wolfssl_bio_cf_free_methods(void)
|
|||
|
||||
#endif /* !USE_BIO_CHAIN */
|
||||
|
||||
static void wolfssl_session_free(void *sessionid, size_t idsize)
|
||||
static void wolfssl_session_free(void *sdata, size_t slen)
|
||||
{
|
||||
(void)idsize;
|
||||
wolfSSL_SESSION_free(sessionid);
|
||||
(void)slen;
|
||||
free(sdata);
|
||||
}
|
||||
|
||||
static int wolfssl_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session)
|
||||
CURLcode wssl_cache_session(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct ssl_peer *peer,
|
||||
WOLFSSL_SESSION *session)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
unsigned char *sdata = NULL;
|
||||
unsigned int slen;
|
||||
|
||||
if(!session)
|
||||
goto out;
|
||||
|
||||
slen = wolfSSL_i2d_SSL_SESSION(session, NULL);
|
||||
if(slen <= 0) {
|
||||
CURL_TRC_CF(data, cf, "fail to assess session length: %u", slen);
|
||||
result = CURLE_FAILED_INIT;
|
||||
goto out;
|
||||
}
|
||||
sdata = calloc(1, slen);
|
||||
if(!sdata) {
|
||||
failf(data, "unable to allocate session buffer of %u bytes", slen);
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
slen = wolfSSL_i2d_SSL_SESSION(session, &sdata);
|
||||
if(slen <= 0) {
|
||||
CURL_TRC_CF(data, cf, "fail to serialize session: %u", slen);
|
||||
result = CURLE_FAILED_INIT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
Curl_ssl_sessionid_lock(data);
|
||||
result = Curl_ssl_set_sessionid(cf, data, peer, NULL,
|
||||
sdata, slen, wolfssl_session_free);
|
||||
Curl_ssl_sessionid_unlock(data);
|
||||
if(result)
|
||||
failf(data, "failed to add new ssl session to cache (%d)", result);
|
||||
else {
|
||||
CURL_TRC_CF(data, cf, "added new session to cache");
|
||||
sdata = NULL;
|
||||
}
|
||||
|
||||
out:
|
||||
free(sdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wssl_vtls_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session)
|
||||
{
|
||||
struct Curl_cfilter *cf;
|
||||
|
||||
|
|
@ -388,18 +435,44 @@ static int wolfssl_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session)
|
|||
DEBUGASSERT(connssl);
|
||||
DEBUGASSERT(data);
|
||||
if(connssl && data) {
|
||||
CURLcode result;
|
||||
Curl_ssl_sessionid_lock(data);
|
||||
result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL,
|
||||
session, 0, wolfssl_session_free);
|
||||
Curl_ssl_sessionid_unlock(data);
|
||||
if(result)
|
||||
failf(data, "failed to add new ssl session to cache (%d)", result);
|
||||
else
|
||||
CURL_TRC_CF(data, cf, "added new session to cache");
|
||||
(void)wssl_cache_session(cf, data, &connssl->peer, session);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
CURLcode wssl_setup_session(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct wolfssl_ctx *wss,
|
||||
struct ssl_peer *peer)
|
||||
{
|
||||
void *psdata;
|
||||
const unsigned char *sdata = NULL;
|
||||
size_t slen = 0;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
Curl_ssl_sessionid_lock(data);
|
||||
if(!Curl_ssl_getsessionid(cf, data, peer, &psdata, &slen, NULL)) {
|
||||
WOLFSSL_SESSION *session;
|
||||
sdata = psdata;
|
||||
session = wolfSSL_d2i_SSL_SESSION(NULL, &sdata, (long)slen);
|
||||
if(session) {
|
||||
int ret = wolfSSL_set_session(wss->handle, session);
|
||||
if(ret != WOLFSSL_SUCCESS) {
|
||||
Curl_ssl_delsessionid(data, psdata);
|
||||
infof(data, "previous session not accepted (%d), "
|
||||
"removing from cache", ret);
|
||||
}
|
||||
else
|
||||
infof(data, "SSL reusing session ID");
|
||||
wolfSSL_SESSION_free(session);
|
||||
}
|
||||
else {
|
||||
failf(data, "could not decode previous session");
|
||||
}
|
||||
}
|
||||
Curl_ssl_sessionid_unlock(data);
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode populate_x509_store(struct Curl_cfilter *cf,
|
||||
|
|
@ -1087,24 +1160,11 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
|
||||
/* Check if there is a cached ID we can/should use here! */
|
||||
if(ssl_config->primary.cache_session) {
|
||||
void *ssl_sessionid = NULL;
|
||||
|
||||
/* Set session from cache if there is one */
|
||||
(void)wssl_setup_session(cf, data, backend, &connssl->peer);
|
||||
/* Register to get notified when a new session is received */
|
||||
wolfSSL_set_app_data(backend->handle, cf);
|
||||
wolfSSL_CTX_sess_set_new_cb(backend->ctx, wolfssl_new_session_cb);
|
||||
|
||||
Curl_ssl_sessionid_lock(data);
|
||||
if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
|
||||
&ssl_sessionid, NULL, NULL)) {
|
||||
/* we got a session id, use it! */
|
||||
if(!SSL_set_session(backend->handle, ssl_sessionid)) {
|
||||
Curl_ssl_delsessionid(data, ssl_sessionid);
|
||||
infof(data, "cannot use session ID, going on without");
|
||||
}
|
||||
else
|
||||
infof(data, "SSL reusing session ID");
|
||||
}
|
||||
Curl_ssl_sessionid_unlock(data);
|
||||
wolfSSL_CTX_sess_set_new_cb(backend->ctx, wssl_vtls_new_session_cb);
|
||||
}
|
||||
|
||||
#ifdef USE_ECH
|
||||
|
|
|
|||
|
|
@ -48,5 +48,16 @@ CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
|
|||
struct Curl_easy *data,
|
||||
struct wolfssl_ctx *wssl);
|
||||
|
||||
CURLcode wssl_setup_session(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct wolfssl_ctx *wss,
|
||||
struct ssl_peer *peer);
|
||||
|
||||
CURLcode wssl_cache_session(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct ssl_peer *peer,
|
||||
WOLFSSL_SESSION *session);
|
||||
|
||||
|
||||
#endif /* USE_WOLFSSL */
|
||||
#endif /* HEADER_CURL_WOLFSSL_H */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue