mbedTLS: fix handling of TLSv1.3 sessions
For TLSv1.3, if supported, observer special return code to retrieve newly arrived session from mbedTLS. Adjust test expectations now that TLSv1.3 session resumption works in mbedTLS >= 3.6.0. Based on #14135 by @ad-chaos Closes #15245
This commit is contained in:
parent
513904c264
commit
3455d360ce
@ -118,6 +118,10 @@ struct mbed_ssl_backend_data {
|
||||
#define TLS13_SUPPORT
|
||||
#endif
|
||||
|
||||
#if defined(TLS13_SUPPORT) && defined(MBEDTLS_SSL_SESSION_TICKETS)
|
||||
#define HAS_SESSION_TICKETS
|
||||
#endif
|
||||
|
||||
#if defined(THREADING_SUPPORT)
|
||||
static mbedtls_entropy_context ts_entropy;
|
||||
|
||||
@ -291,7 +295,8 @@ mbed_set_ssl_version_min_max(struct Curl_easy *data,
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
failf(data, "mbedTLS: unsupported minimum TLS version value");
|
||||
failf(data, "mbedTLS: unsupported minimum TLS version value: %x",
|
||||
conn_config->version);
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
@ -807,6 +812,12 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
#ifdef MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_ENABLED
|
||||
/* New in mbedTLS 3.6.1, need to enable, default is now disabled */
|
||||
mbedtls_ssl_conf_tls13_enable_signal_new_session_tickets(&backend->config,
|
||||
MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_ENABLED);
|
||||
#endif
|
||||
|
||||
/* Always let mbedTLS verify certificates, if verifypeer or verifyhost are
|
||||
* disabled we clear the corresponding error flags in the verify callback
|
||||
* function. That is also where we log verification errors. */
|
||||
@ -1113,17 +1124,15 @@ static void mbedtls_session_free(void *sessionid, size_t idsize)
|
||||
}
|
||||
|
||||
static CURLcode
|
||||
mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
mbed_new_session(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
CURLcode retcode = CURLE_OK;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct mbed_ssl_backend_data *backend =
|
||||
(struct mbed_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
if(ssl_config->primary.cache_session) {
|
||||
int ret;
|
||||
mbedtls_ssl_session *our_ssl_sessionid;
|
||||
@ -1145,17 +1154,12 @@ mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
|
||||
/* If there is already a matching session in the cache, delete it */
|
||||
Curl_ssl_sessionid_lock(data);
|
||||
retcode = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL,
|
||||
our_ssl_sessionid, 0,
|
||||
mbedtls_session_free);
|
||||
result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL,
|
||||
our_ssl_sessionid, 0,
|
||||
mbedtls_session_free);
|
||||
Curl_ssl_sessionid_unlock(data);
|
||||
if(retcode)
|
||||
return retcode;
|
||||
}
|
||||
|
||||
connssl->connecting_state = ssl_connect_done;
|
||||
|
||||
return CURLE_OK;
|
||||
return result;
|
||||
}
|
||||
|
||||
static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
@ -1314,7 +1318,6 @@ static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
struct mbed_ssl_backend_data *backend =
|
||||
(struct mbed_ssl_backend_data *)connssl->backend;
|
||||
int ret = -1;
|
||||
ssize_t len = -1;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(backend);
|
||||
@ -1324,24 +1327,31 @@ static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
if(ret <= 0) {
|
||||
CURL_TRC_CF(data, cf, "mbedtls_ssl_read(len=%zu) -> -0x%04X",
|
||||
buffersize, -ret);
|
||||
if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
|
||||
return 0;
|
||||
*curlcode = ((ret == MBEDTLS_ERR_SSL_WANT_READ)
|
||||
#ifdef TLS13_SUPPORT
|
||||
|| (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
|
||||
switch(ret) {
|
||||
#ifdef HAS_SESSION_TICKETS
|
||||
case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET:
|
||||
mbed_new_session(cf, data);
|
||||
FALLTHROUGH();
|
||||
#endif
|
||||
) ? CURLE_AGAIN : CURLE_RECV_ERROR;
|
||||
if(*curlcode != CURLE_AGAIN) {
|
||||
case MBEDTLS_ERR_SSL_WANT_READ:
|
||||
*curlcode = CURLE_AGAIN;
|
||||
ret = -1;
|
||||
break;
|
||||
case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
|
||||
*curlcode = CURLE_OK;
|
||||
ret = 0;
|
||||
break;
|
||||
default: {
|
||||
char errorbuf[128];
|
||||
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
|
||||
failf(data, "ssl_read returned: (-0x%04X) %s", -ret, errorbuf);
|
||||
*curlcode = CURLE_RECV_ERROR;
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = ret;
|
||||
|
||||
return len;
|
||||
return (ssize_t)ret;
|
||||
}
|
||||
|
||||
static size_t mbedtls_version(char *buffer, size_t size)
|
||||
@ -1486,9 +1496,22 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
} /* repeat step2 until all transactions are done. */
|
||||
|
||||
if(ssl_connect_3 == connssl->connecting_state) {
|
||||
retcode = mbed_connect_step3(cf, data);
|
||||
if(retcode)
|
||||
return retcode;
|
||||
/* For tls1.3 we get notified about new sessions */
|
||||
#if MBEDTLS_VERSION_NUMBER >= 0x03020000
|
||||
struct ssl_connect_data *ctx = cf->ctx;
|
||||
struct mbed_ssl_backend_data *backend =
|
||||
(struct mbed_ssl_backend_data *)ctx->backend;
|
||||
|
||||
if(mbedtls_ssl_get_version_number(&backend->ssl) <=
|
||||
MBEDTLS_SSL_VERSION_TLS1_2) {
|
||||
#else
|
||||
{ /* no TLSv1.3 supported here */
|
||||
#endif
|
||||
retcode = mbed_new_session(cf, data);
|
||||
if(retcode)
|
||||
return retcode;
|
||||
}
|
||||
connssl->connecting_state = ssl_connect_done;
|
||||
}
|
||||
|
||||
if(ssl_connect_done == connssl->connecting_state) {
|
||||
|
||||
@ -71,10 +71,13 @@ class TestSSLUse:
|
||||
exp_resumed = 'Initial' # Rustls does not support sessions, TODO
|
||||
if env.curl_uses_lib('bearssl') and tls_max == '1.3':
|
||||
pytest.skip('BearSSL does not support TLSv1.3')
|
||||
if env.curl_uses_lib('mbedtls') and tls_max == '1.3':
|
||||
if env.curl_uses_lib('mbedtls') and tls_max == '1.3' and \
|
||||
not env.curl_lib_version_at_least('mbedtls', '3.6.0'):
|
||||
pytest.skip('mbedtls TLSv1.3 session resume not working in 3.6.0')
|
||||
|
||||
curl = CurlClient(env=env)
|
||||
run_env = os.environ.copy()
|
||||
run_env['CURL_DEBUG'] = 'ssl'
|
||||
curl = CurlClient(env=env, run_env=run_env)
|
||||
# tell the server to close the connection after each request
|
||||
urln = f'https://{env.authority_for(env.domain1, proto)}/curltest/sslinfo?'\
|
||||
f'id=[0-{count-1}]&close'
|
||||
@ -91,9 +94,9 @@ class TestSSLUse:
|
||||
djson = json.load(f)
|
||||
assert djson['HTTPS'] == 'on', f'{i}: {djson}'
|
||||
if i == 0:
|
||||
assert djson['SSL_SESSION_RESUMED'] == 'Initial', f'{i}: {djson}'
|
||||
assert djson['SSL_SESSION_RESUMED'] == 'Initial', f'{i}: {djson}\n{r.dump_logs()}'
|
||||
else:
|
||||
assert djson['SSL_SESSION_RESUMED'] == exp_resumed, f'{i}: {djson}'
|
||||
assert djson['SSL_SESSION_RESUMED'] == exp_resumed, f'{i}: {djson}\n{r.dump_logs()}'
|
||||
|
||||
# use host name with trailing dot, verify handshake
|
||||
@pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
|
||||
@ -220,6 +223,9 @@ class TestSSLUse:
|
||||
if tls_proto == 'TLSv1.3':
|
||||
pytest.skip('BearSSL does not support TLSv1.3')
|
||||
tls_proto = 'TLSv1.2'
|
||||
elif env.curl_uses_lib('mbedtls') and not env.curl_lib_version_at_least('mbedtls', '3.6.0'):
|
||||
if tls_proto == 'TLSv1.3':
|
||||
pytest.skip('mbedTLS < 3.6.0 does not support TLSv1.3')
|
||||
elif env.curl_uses_lib('sectransp'): # not in CI, so untested
|
||||
if tls_proto == 'TLSv1.3':
|
||||
pytest.skip('Secure Transport does not support TLSv1.3')
|
||||
|
||||
Loading…
Reference in New Issue
Block a user