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
|
#define TLS13_SUPPORT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(TLS13_SUPPORT) && defined(MBEDTLS_SSL_SESSION_TICKETS)
|
||||||
|
#define HAS_SESSION_TICKETS
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(THREADING_SUPPORT)
|
#if defined(THREADING_SUPPORT)
|
||||||
static mbedtls_entropy_context ts_entropy;
|
static mbedtls_entropy_context ts_entropy;
|
||||||
|
|
||||||
@ -291,7 +295,8 @@ mbed_set_ssl_version_min_max(struct Curl_easy *data,
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
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;
|
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;
|
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
|
/* Always let mbedTLS verify certificates, if verifypeer or verifyhost are
|
||||||
* disabled we clear the corresponding error flags in the verify callback
|
* disabled we clear the corresponding error flags in the verify callback
|
||||||
* function. That is also where we log verification errors. */
|
* 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
|
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 ssl_connect_data *connssl = cf->ctx;
|
||||||
struct mbed_ssl_backend_data *backend =
|
struct mbed_ssl_backend_data *backend =
|
||||||
(struct mbed_ssl_backend_data *)connssl->backend;
|
(struct mbed_ssl_backend_data *)connssl->backend;
|
||||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
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);
|
DEBUGASSERT(backend);
|
||||||
|
|
||||||
if(ssl_config->primary.cache_session) {
|
if(ssl_config->primary.cache_session) {
|
||||||
int ret;
|
int ret;
|
||||||
mbedtls_ssl_session *our_ssl_sessionid;
|
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 */
|
/* If there is already a matching session in the cache, delete it */
|
||||||
Curl_ssl_sessionid_lock(data);
|
Curl_ssl_sessionid_lock(data);
|
||||||
retcode = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL,
|
result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL,
|
||||||
our_ssl_sessionid, 0,
|
our_ssl_sessionid, 0,
|
||||||
mbedtls_session_free);
|
mbedtls_session_free);
|
||||||
Curl_ssl_sessionid_unlock(data);
|
Curl_ssl_sessionid_unlock(data);
|
||||||
if(retcode)
|
|
||||||
return retcode;
|
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
connssl->connecting_state = ssl_connect_done;
|
|
||||||
|
|
||||||
return CURLE_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
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 *backend =
|
||||||
(struct mbed_ssl_backend_data *)connssl->backend;
|
(struct mbed_ssl_backend_data *)connssl->backend;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
ssize_t len = -1;
|
|
||||||
|
|
||||||
(void)data;
|
(void)data;
|
||||||
DEBUGASSERT(backend);
|
DEBUGASSERT(backend);
|
||||||
@ -1324,24 +1327,31 @@ static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||||||
if(ret <= 0) {
|
if(ret <= 0) {
|
||||||
CURL_TRC_CF(data, cf, "mbedtls_ssl_read(len=%zu) -> -0x%04X",
|
CURL_TRC_CF(data, cf, "mbedtls_ssl_read(len=%zu) -> -0x%04X",
|
||||||
buffersize, -ret);
|
buffersize, -ret);
|
||||||
if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
|
switch(ret) {
|
||||||
return 0;
|
#ifdef HAS_SESSION_TICKETS
|
||||||
*curlcode = ((ret == MBEDTLS_ERR_SSL_WANT_READ)
|
case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET:
|
||||||
#ifdef TLS13_SUPPORT
|
mbed_new_session(cf, data);
|
||||||
|| (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
|
FALLTHROUGH();
|
||||||
#endif
|
#endif
|
||||||
) ? CURLE_AGAIN : CURLE_RECV_ERROR;
|
case MBEDTLS_ERR_SSL_WANT_READ:
|
||||||
if(*curlcode != CURLE_AGAIN) {
|
*curlcode = CURLE_AGAIN;
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
|
||||||
|
*curlcode = CURLE_OK;
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
char errorbuf[128];
|
char errorbuf[128];
|
||||||
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
|
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
|
||||||
failf(data, "ssl_read returned: (-0x%04X) %s", -ret, errorbuf);
|
failf(data, "ssl_read returned: (-0x%04X) %s", -ret, errorbuf);
|
||||||
|
*curlcode = CURLE_RECV_ERROR;
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
return (ssize_t)ret;
|
||||||
len = ret;
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t mbedtls_version(char *buffer, size_t size)
|
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. */
|
} /* repeat step2 until all transactions are done. */
|
||||||
|
|
||||||
if(ssl_connect_3 == connssl->connecting_state) {
|
if(ssl_connect_3 == connssl->connecting_state) {
|
||||||
retcode = mbed_connect_step3(cf, data);
|
/* For tls1.3 we get notified about new sessions */
|
||||||
if(retcode)
|
#if MBEDTLS_VERSION_NUMBER >= 0x03020000
|
||||||
return retcode;
|
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) {
|
if(ssl_connect_done == connssl->connecting_state) {
|
||||||
|
|||||||
@ -71,10 +71,13 @@ class TestSSLUse:
|
|||||||
exp_resumed = 'Initial' # Rustls does not support sessions, TODO
|
exp_resumed = 'Initial' # Rustls does not support sessions, TODO
|
||||||
if env.curl_uses_lib('bearssl') and tls_max == '1.3':
|
if env.curl_uses_lib('bearssl') and tls_max == '1.3':
|
||||||
pytest.skip('BearSSL does not support TLSv1.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')
|
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
|
# tell the server to close the connection after each request
|
||||||
urln = f'https://{env.authority_for(env.domain1, proto)}/curltest/sslinfo?'\
|
urln = f'https://{env.authority_for(env.domain1, proto)}/curltest/sslinfo?'\
|
||||||
f'id=[0-{count-1}]&close'
|
f'id=[0-{count-1}]&close'
|
||||||
@ -91,9 +94,9 @@ class TestSSLUse:
|
|||||||
djson = json.load(f)
|
djson = json.load(f)
|
||||||
assert djson['HTTPS'] == 'on', f'{i}: {djson}'
|
assert djson['HTTPS'] == 'on', f'{i}: {djson}'
|
||||||
if i == 0:
|
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:
|
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
|
# use host name with trailing dot, verify handshake
|
||||||
@pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
|
@pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
|
||||||
@ -220,6 +223,9 @@ class TestSSLUse:
|
|||||||
if tls_proto == 'TLSv1.3':
|
if tls_proto == 'TLSv1.3':
|
||||||
pytest.skip('BearSSL does not support TLSv1.3')
|
pytest.skip('BearSSL does not support TLSv1.3')
|
||||||
tls_proto = 'TLSv1.2'
|
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
|
elif env.curl_uses_lib('sectransp'): # not in CI, so untested
|
||||||
if tls_proto == 'TLSv1.3':
|
if tls_proto == 'TLSv1.3':
|
||||||
pytest.skip('Secure Transport does not support TLSv1.3')
|
pytest.skip('Secure Transport does not support TLSv1.3')
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user