Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tls session storage #13386

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/urldata.h
Expand Up @@ -345,13 +345,16 @@ struct ssl_general_config {
int ca_cache_timeout; /* Certificate store cache timeout (seconds) */
};

typedef void Curl_ssl_sessionid_dtor(void *sessionid, size_t idsize);

/* information stored about one single SSL session */
struct Curl_ssl_session {
char *name; /* host name for which this ID was used */
char *conn_to_host; /* host name for the connection (may be NULL) */
const char *scheme; /* protocol scheme used */
void *sessionid; /* as returned from the SSL layer */
size_t idsize; /* if known, otherwise 0 */
Curl_ssl_sessionid_dtor *sessionid_free; /* free `sessionid` callback */
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) */
Expand Down
5 changes: 2 additions & 3 deletions lib/vquic/curl_ngtcp2.c
Expand Up @@ -1992,9 +1992,8 @@ static int quic_ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
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;
Curl_ossl_add_session(cf, data, &ctx->peer, ssl_sessionid);
return 1;
}
return 0;
}
Expand Down
26 changes: 12 additions & 14 deletions lib/vtls/bearssl.c
Expand Up @@ -830,7 +830,7 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "ssl_recv(len=%zu) -> %zd, %d", len, ret, result);
if(ret == 0) {
failf(data, "SSL: EOF without close notify");
return CURLE_READ_ERROR;
return CURLE_RECV_ERROR;
}
if(ret <= 0) {
return result;
Expand Down Expand Up @@ -873,6 +873,12 @@ static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf,
return ret;
}

static void bearssl_session_free(void *sessionid, size_t idsize)
{
(void)idsize;
free(sessionid);
}

static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
Expand All @@ -896,7 +902,6 @@ static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,

if(ssl_config->primary.sessionid) {
bool incache;
bool added = FALSE;
void *oldsession;
br_ssl_session_parameters *session;

Expand All @@ -909,13 +914,12 @@ static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
&oldsession, NULL));
if(incache)
Curl_ssl_delsessionid(data, oldsession);
ret = Curl_ssl_addsessionid(cf, data, &connssl->peer, session, 0, &added);

ret = Curl_ssl_addsessionid(cf, data, &connssl->peer, session, 0,
bearssl_session_free);
Curl_ssl_sessionid_unlock(data);
if(!added)
free(session);
if(ret) {
return CURLE_OUT_OF_MEMORY;
}
if(ret)
return ret;
}

connssl->connecting_state = ssl_connect_done;
Expand Down Expand Up @@ -1174,11 +1178,6 @@ static void bearssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}

static void bearssl_session_free(void *ptr)
{
free(ptr);
}

static CURLcode bearssl_sha256sum(const unsigned char *input,
size_t inputlen,
unsigned char *sha256sum,
Expand Down Expand Up @@ -1211,7 +1210,6 @@ const struct Curl_ssl Curl_ssl_bearssl = {
bearssl_get_internals, /* get_internals */
bearssl_close, /* close_one */
Curl_none_close_all, /* close_all */
bearssl_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
Expand Down
147 changes: 95 additions & 52 deletions lib/vtls/gtls.c
Expand Up @@ -532,6 +532,88 @@ CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf,
return CURLE_OK;
}

static void gtls_sessionid_free(void *sessionid, size_t idsize)
{
(void)idsize;
free(sessionid);
}

static CURLcode gtls_update_session_id(struct Curl_cfilter *cf,
struct Curl_easy *data,
gnutls_session_t session)
{
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
struct ssl_connect_data *connssl = cf->ctx;
CURLcode result = CURLE_OK;

if(ssl_config->primary.sessionid) {
/* we always unconditionally get the session id here, as even if we
already got it from the cache and asked to use it in the connection, it
might've been rejected and then a new one is in use now and we need to
detect that. */
void *connect_sessionid;
size_t connect_idsize = 0;

/* get the session ID data size */
gnutls_session_get_data(session, NULL, &connect_idsize);
connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
if(!connect_sessionid) {
return CURLE_OUT_OF_MEMORY;
}
else {
bool incache;
void *ssl_sessionid;

/* extract session ID to the allocated buffer */
gnutls_session_get_data(session, connect_sessionid, &connect_idsize);

DEBUGF(infof(data, "get session id (len=%zu) and store in cache",
connect_idsize));
Curl_ssl_sessionid_lock(data);
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 */
Curl_ssl_delsessionid(data, ssl_sessionid);
}

/* store this session id, takes ownership */
result = Curl_ssl_addsessionid(cf, data, &connssl->peer,
connect_sessionid, connect_idsize,
gtls_sessionid_free);
Curl_ssl_sessionid_unlock(data);
}
}
return result;
}

static int gtls_handshake_cb(gnutls_session_t session, unsigned int htype,
unsigned when, unsigned int incoming,
const gnutls_datum_t *msg)
{
struct Curl_cfilter *cf = gnutls_session_get_ptr(session);

(void)msg;
(void)incoming;
if(when) { /* after message has been processed */
struct Curl_easy *data = CF_DATA_CURRENT(cf);
if(data) {
DEBUGF(infof(data, "handshake: %s message type %d",
incoming? "incoming" : "outgoing", htype));
switch(htype) {
case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: {
gtls_update_session_id(cf, data, session);
break;
}
default:
break;
}
}
}
return 0;
}

static CURLcode gtls_client_init(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
Expand Down Expand Up @@ -828,10 +910,13 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, peer, &ssl_sessionid, &ssl_idsize)) {
/* we got a session id, use it! */
gnutls_session_set_data(gctx->session, ssl_sessionid, ssl_idsize);
int rc;

/* Informational message */
infof(data, "SSL reusing session ID");
rc = gnutls_session_set_data(gctx->session, ssl_sessionid, ssl_idsize);
if(rc < 0)
infof(data, "SSL failed to set session ID");
else
infof(data, "SSL reusing session ID (size=%zu)", ssl_idsize);
}
Curl_ssl_sessionid_unlock(data);
}
Expand Down Expand Up @@ -869,6 +954,9 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
if(result)
return result;

gnutls_handshake_set_hook_function(backend->gtls.session,
GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST,
gtls_handshake_cb);

/* register callback functions and handle to send and receive data. */
gnutls_transport_set_ptr(backend->gtls.session, cf);
Expand Down Expand Up @@ -1403,49 +1491,10 @@ static CURLcode gtls_verifyserver(struct Curl_cfilter *cf,
Curl_alpn_set_negotiated(cf, data, NULL, 0);
}

if(ssl_config->primary.sessionid) {
/* we always unconditionally get the session id here, as even if we
already got it from the cache and asked to use it in the connection, it
might've been rejected and then a new one is in use now and we need to
detect that. */
void *connect_sessionid;
size_t connect_idsize = 0;

/* get the session ID data size */
gnutls_session_get_data(session, NULL, &connect_idsize);
connect_sessionid = malloc(connect_idsize); /* get a buffer for it */

if(connect_sessionid) {
bool incache;
bool added = FALSE;
void *ssl_sessionid;

/* extract session ID to the allocated buffer */
gnutls_session_get_data(session, connect_sessionid, &connect_idsize);

Curl_ssl_sessionid_lock(data);
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 */
Curl_ssl_delsessionid(data, ssl_sessionid);
}

/* store this session id */
result = Curl_ssl_addsessionid(cf, data, &connssl->peer,
connect_sessionid, connect_idsize,
&added);
Curl_ssl_sessionid_unlock(data);
if(!added)
free(connect_sessionid);
if(result) {
result = CURLE_OUT_OF_MEMORY;
}
}
else
result = CURLE_OUT_OF_MEMORY;
}
/* Only on TLSv1.2 or lower do we have the session id now. For
* TLSv1.3 we get it via a SESSION_TICKET message that arrives later. */
if(gnutls_protocol_get_version(session) < GNUTLS_TLS1_3)
result = gtls_update_session_id(cf, data, session);

out:
return result;
Expand Down Expand Up @@ -1734,11 +1783,6 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf,
return ret;
}

static void gtls_session_free(void *ptr)
{
free(ptr);
}

static size_t gtls_version(char *buffer, size_t size)
{
return msnprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
Expand Down Expand Up @@ -1805,7 +1849,6 @@ const struct Curl_ssl Curl_ssl_gnutls = {
gtls_get_internals, /* get_internals */
gtls_close, /* close_one */
Curl_none_close_all, /* close_all */
gtls_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
Expand Down
26 changes: 10 additions & 16 deletions lib/vtls/mbedtls.c
Expand Up @@ -1033,6 +1033,13 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_OK;
}

static void mbedtls_session_free(void *sessionid, size_t idsize)
{
(void)idsize;
mbedtls_ssl_session_free(sessionid);
free(sessionid);
}

static CURLcode
mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
{
Expand All @@ -1049,7 +1056,6 @@ mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
int ret;
mbedtls_ssl_session *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
bool added = FALSE;

our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
if(!our_ssl_sessionid)
Expand All @@ -1073,16 +1079,11 @@ mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
Curl_ssl_delsessionid(data, old_ssl_sessionid);

retcode = Curl_ssl_addsessionid(cf, data, &connssl->peer,
our_ssl_sessionid, 0, &added);
our_ssl_sessionid, 0,
mbedtls_session_free);
Curl_ssl_sessionid_unlock(data);
if(!added) {
mbedtls_ssl_session_free(our_ssl_sessionid);
free(our_ssl_sessionid);
}
if(retcode) {
failf(data, "failed to store ssl session");
if(retcode)
return retcode;
}
}

connssl->connecting_state = ssl_connect_done;
Expand Down Expand Up @@ -1176,12 +1177,6 @@ static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
return len;
}

static void mbedtls_session_free(void *ptr)
{
mbedtls_ssl_session_free(ptr);
free(ptr);
}

static size_t mbedtls_version(char *buffer, size_t size)
{
#ifdef MBEDTLS_VERSION_C
Expand Down Expand Up @@ -1460,7 +1455,6 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
mbedtls_get_internals, /* get_internals */
mbedtls_close, /* close_one */
mbedtls_close_all, /* close_all */
mbedtls_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
Expand Down