Harden TLS 1.3 serialized session loading

Signed-off-by: Nadav0077 <18245584+Nadav0077@users.noreply.github.com>
This commit is contained in:
Nadav0077 2026-04-25 15:19:30 +03:00
parent ae8579f2a2
commit 3ab4fce1a0
No known key found for this signature in database
4 changed files with 102 additions and 5 deletions

View File

@ -0,0 +1,3 @@
Bugfix
* Reject malformed TLS 1.3 serialized sessions instead of accepting
unterminated strings or extra trailing data.

View File

@ -3573,6 +3573,7 @@ static int ssl_tls13_session_load(mbedtls_ssl_session *session,
{
const unsigned char *p = buf;
const unsigned char *end = buf + len;
int ret;
if (end - p < 6) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
@ -3634,7 +3635,12 @@ static int ssl_tls13_session_load(mbedtls_ssl_session *session,
}
if (alpn_len > 0) {
int ret = mbedtls_ssl_session_set_ticket_alpn(session, (char *) p);
if (p[alpn_len - 1] != '\0' ||
memchr(p, '\0', alpn_len - 1) != NULL) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}
ret = mbedtls_ssl_session_set_ticket_alpn(session, (char *) p);
if (ret != 0) {
return ret;
}
@ -3659,11 +3665,15 @@ static int ssl_tls13_session_load(mbedtls_ssl_session *session,
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}
if (hostname_len > 0) {
session->hostname = mbedtls_calloc(1, hostname_len);
if (session->hostname == NULL) {
return MBEDTLS_ERR_SSL_ALLOC_FAILED;
if (p[hostname_len - 1] != '\0' ||
memchr(p, '\0', hostname_len - 1) != NULL) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}
ret = mbedtls_ssl_session_set_hostname(session, (const char *) p);
if (ret != 0) {
return ret;
}
memcpy(session->hostname, p, hostname_len);
p += hostname_len;
}
#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */
@ -3701,6 +3711,10 @@ static int ssl_tls13_session_load(mbedtls_ssl_session *session,
}
#endif /* MBEDTLS_SSL_CLI_C */
if (p != end) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}
return 0;
}

View File

@ -3028,6 +3028,18 @@ TLS 1.3: SRV: Session serialization, load buffer size
depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_SRV_C
ssl_serialize_session_load_buf_size:0:"":MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_3
TLS 1.3: Session serialization rejects trailing data
depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C
ssl_tls13_session_load_rejects_bad_serialized_data:MBEDTLS_SSL_IS_CLIENT:0
TLS 1.3: Session serialization rejects hostname without terminator
depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SERVER_NAME_INDICATION
ssl_tls13_session_load_rejects_bad_serialized_data:MBEDTLS_SSL_IS_CLIENT:1
TLS 1.3: Session serialization rejects ALPN without terminator
depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_SRV_C:MBEDTLS_SSL_EARLY_DATA:MBEDTLS_SSL_ALPN
ssl_tls13_session_load_rejects_bad_serialized_data:MBEDTLS_SSL_IS_SERVER:2
Test configuration of EC groups through mbedtls_ssl_conf_groups()
conf_group:

View File

@ -2733,6 +2733,74 @@ exit:
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_SESSION_TICKETS */
void ssl_tls13_session_load_rejects_bad_serialized_data(int endpoint_type,
int mutation)
{
mbedtls_ssl_session session, restored;
unsigned char *buf = NULL;
size_t len, bad_len, i;
unsigned char *field = NULL;
const unsigned char hostname[] = "hostname example";
const unsigned char alpn[] = "ALPNExample";
const unsigned char *string_to_corrupt = NULL;
size_t string_len = 0;
mbedtls_ssl_session_init(&session);
mbedtls_ssl_session_init(&restored);
USE_PSA_INIT();
TEST_EQUAL(mbedtls_test_ssl_tls13_populate_session(
&session, 42, endpoint_type), 0);
TEST_EQUAL(mbedtls_ssl_session_save(&session, NULL, 0, &len),
MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL);
TEST_CALLOC(buf, len + 1);
TEST_EQUAL(mbedtls_ssl_session_save(&session, buf, len, &len), 0);
bad_len = len;
switch (mutation) {
case 0:
bad_len = len + 1;
buf[len] = 0;
break;
case 1:
string_to_corrupt = hostname;
string_len = sizeof(hostname);
break;
case 2:
string_to_corrupt = alpn;
string_len = sizeof(alpn);
break;
default:
TEST_ASSERT(0);
}
if (string_to_corrupt != NULL) {
for (i = 0; i + string_len <= len; i++) {
if (memcmp(buf + i, string_to_corrupt, string_len) == 0) {
field = buf + i;
break;
}
}
TEST_ASSERT(field != NULL);
field[string_len - 1] = 'X';
}
TEST_EQUAL(mbedtls_ssl_session_load(&restored, buf, bad_len),
MBEDTLS_ERR_SSL_BAD_INPUT_DATA);
exit:
mbedtls_ssl_session_free(&session);
mbedtls_ssl_session_free(&restored);
mbedtls_free(buf);
USE_PSA_DONE();
}
/* END_CASE */
/* BEGIN_CASE */
void ssl_session_serialize_version_check(int corrupt_major,
int corrupt_minor,