From f5675fd06442dbf9d11dfdd78a5d99657de8b12f Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 7 May 2026 17:23:55 +0100 Subject: [PATCH 1/6] Add test for leak Signed-off-by: Ben Taylor --- tests/suites/test_suite_ssl.data | 4 ++ tests/suites/test_suite_ssl.function | 91 ++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 881d502ed5..f21fb55bcc 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3549,3 +3549,7 @@ send_invalid_sig_alg:MBEDTLS_SSL_SIG_ECDSA:MBEDTLS_SSL_HASH_SHA512:0 Negative Test: Server using sig_alg not offered by the client - ECDSA with SHA512 depends_on:MBEDTLS_CAN_HANDLE_ECDSA_TEST_KEY:MBEDTLS_CAN_HANDLE_ECDSA_CLIENT_TEST_KEY:PSA_WANT_ALG_SHA_512 send_invalid_sig_alg:MBEDTLS_SSL_SIG_ECDSA:MBEDTLS_SSL_HASH_SHA512:MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER + +TLS 1.2 NewSessionTicket: failing ticket callback leaves lifetime unset +depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:PSA_HAVE_ALG_SOME_RSA_SIGN:PSA_WANT_ECC_SECP_R1_384:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY:MBEDTLS_CAN_HANDLE_RSA_TEST_KEY +write_new_session_ticket_mem diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 39457c9047..a93904a2b6 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -25,6 +25,36 @@ #define TEST_EARLY_DATA_NO_INITIAL_ALPN 6 #define TEST_EARLY_DATA_NO_LATER_ALPN 7 +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_SSL_SESSION_TICKETS) && \ + defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_SRV_C) && \ + defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED) && \ + defined(PSA_HAVE_ALG_SOME_RSA_SIGN) && \ + defined(PSA_WANT_ECC_SECP_R1_384) && \ + defined(PSA_WANT_ALG_SHA_256) && \ + defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) && \ + defined(MBEDTLS_CAN_HANDLE_RSA_TEST_KEY) +static int failing_ticket_write_unset_lifetime( + void *p_ticket, const mbedtls_ssl_session *session, + unsigned char *start, const unsigned char *end, + size_t *tlen, uint32_t *lifetime) +{ + ((void) p_ticket); + ((void) session); + ((void) start); + ((void) end); + ((void) tlen); + ((void) lifetime); + + return MBEDTLS_ERR_SSL_INTERNAL_ERROR; +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 && MBEDTLS_SSL_SESSION_TICKETS && + MBEDTLS_SSL_CLI_C && MBEDTLS_SSL_SRV_C && + MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED && + PSA_HAVE_ALG_SOME_RSA_SIGN && PSA_WANT_ECC_SECP_R1_384 && + PSA_WANT_ALG_SHA_256 && PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY && + MBEDTLS_CAN_HANDLE_RSA_TEST_KEY */ + #if (!defined(MBEDTLS_SSL_PROTO_TLS1_2)) && \ defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C) && \ defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_DEBUG_C) && \ @@ -6350,3 +6380,64 @@ exit: PSA_DONE(); } /* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:PSA_HAVE_ALG_SOME_RSA_SIGN:PSA_WANT_ECC_SECP_R1_384:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY:MBEDTLS_CAN_HANDLE_RSA_TEST_KEY */ +void write_new_session_ticket_mem() +{ + enum { BUFFSIZE = 1024 }; + mbedtls_test_ssl_endpoint server_ep, client_ep; + mbedtls_test_handshake_test_options options; + int ret = -1; + + memset(&server_ep, 0, sizeof(server_ep)); + memset(&client_ep, 0, sizeof(client_ep)); + mbedtls_test_init_handshake_options(&options); + + options.pk_alg = MBEDTLS_PK_RSA; + options.client_min_version = MBEDTLS_SSL_VERSION_TLS1_2; + options.client_max_version = MBEDTLS_SSL_VERSION_TLS1_2; + options.server_min_version = MBEDTLS_SSL_VERSION_TLS1_2; + options.server_max_version = MBEDTLS_SSL_VERSION_TLS1_2; + + MD_OR_USE_PSA_INIT(); + + ret = mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER, + &options); + TEST_EQUAL(ret, 0); + + mbedtls_ssl_conf_session_tickets_cb(&server_ep.conf, + failing_ticket_write_unset_lifetime, + mbedtls_test_ticket_parse, + NULL); + + ret = mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT, + &options); + TEST_EQUAL(ret, 0); + + ret = mbedtls_test_mock_socket_connect(&(server_ep.socket), + &(client_ep.socket), + BUFFSIZE); + TEST_EQUAL(ret, 0); + + ret = mbedtls_test_move_handshake_to_state(&(server_ep.ssl), + &(client_ep.ssl), + MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC); + TEST_EQUAL(ret, 0); + + ret = mbedtls_ssl_handshake_step(&(server_ep.ssl)); + TEST_EQUAL(ret, 0); + +#if defined(MBEDTLS_TEST_HAVE_MSAN) + { + volatile unsigned char lifetime_byte = server_ep.ssl.out_msg[4]; + TEST_ASSERT(lifetime_byte != 0xff); + } +#endif + +exit: + mbedtls_test_ssl_endpoint_free(&client_ep); + mbedtls_test_ssl_endpoint_free(&server_ep); + mbedtls_test_free_handshake_options(&options); + MD_OR_USE_PSA_DONE(); +} +/* END_CASE */ From a5c2e02198433b4808c500bd8f5e77bd07d82bf1 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 7 May 2026 17:24:50 +0100 Subject: [PATCH 2/6] Add fix for leak Signed-off-by: Ben Taylor --- library/ssl_tls12_server.c | 1 + 1 file changed, 1 insertion(+) diff --git a/library/ssl_tls12_server.c b/library/ssl_tls12_server.c index 884c8fd4a4..a1fa442b7a 100644 --- a/library/ssl_tls12_server.c +++ b/library/ssl_tls12_server.c @@ -3396,6 +3396,7 @@ static int ssl_write_new_session_ticket(mbedtls_ssl_context *ssl) &tlen, &lifetime)) != 0) { MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_ticket_write", ret); tlen = 0; + lifetime = 0; } MBEDTLS_PUT_UINT32_BE(lifetime, ssl->out_msg, 4); From 38185e2308d201d7dfd05aa0032636440bdd1bfa Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 1 Jun 2026 14:56:20 +0100 Subject: [PATCH 3/6] Improve robustness of tlen and lifetime variables Signed-off-by: Ben Taylor --- library/ssl_tls12_server.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/ssl_tls12_server.c b/library/ssl_tls12_server.c index a1fa442b7a..328e25aafc 100644 --- a/library/ssl_tls12_server.c +++ b/library/ssl_tls12_server.c @@ -3367,8 +3367,8 @@ MBEDTLS_CHECK_RETURN_CRITICAL static int ssl_write_new_session_ticket(mbedtls_ssl_context *ssl) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - size_t tlen; - uint32_t lifetime; + size_t tlen = 0; + uint32_t lifetime = 0; MBEDTLS_SSL_DEBUG_MSG(2, ("=> write new session ticket")); @@ -3395,8 +3395,6 @@ static int ssl_write_new_session_ticket(mbedtls_ssl_context *ssl) ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN, &tlen, &lifetime)) != 0) { MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_ticket_write", ret); - tlen = 0; - lifetime = 0; } MBEDTLS_PUT_UINT32_BE(lifetime, ssl->out_msg, 4); From 33c55a90e323620dbe67f0074668af8484c74960 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 8 Jun 2026 15:32:26 +0100 Subject: [PATCH 4/6] Improve test of non-initilisation of lifetime Signed-off-by: Ben Taylor --- tests/suites/test_suite_ssl.function | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index a93904a2b6..34c4d89e00 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -6427,12 +6427,13 @@ void write_new_session_ticket_mem() ret = mbedtls_ssl_handshake_step(&(server_ep.ssl)); TEST_EQUAL(ret, 0); -#if defined(MBEDTLS_TEST_HAVE_MSAN) - { - volatile unsigned char lifetime_byte = server_ep.ssl.out_msg[4]; - TEST_ASSERT(lifetime_byte != 0xff); - } -#endif + /* Force a read of the lifetime value from the outgoing message. + * This is a non-regression test for a bug where the lifetime was set from + * uninitialized memory. + * The read here causes MSan and Valgrind to complain if the bug isn't fixed. + */ + volatile unsigned char lifetime = MBEDTLS_GET_UINT32_BE(server_ep.ssl.out_msg + 4); + (void) lifetime; exit: mbedtls_test_ssl_endpoint_free(&client_ep); From 0c62b498bdc54cf56ed4b4198d766e76edf9153a Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 8 Jun 2026 15:46:00 +0100 Subject: [PATCH 5/6] Add ChangeLog Signed-off-by: Ben Taylor --- ChangeLog.d/fix-info-leak-in-ssl.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 ChangeLog.d/fix-info-leak-in-ssl.txt diff --git a/ChangeLog.d/fix-info-leak-in-ssl.txt b/ChangeLog.d/fix-info-leak-in-ssl.txt new file mode 100644 index 0000000000..2a0309fc40 --- /dev/null +++ b/ChangeLog.d/fix-info-leak-in-ssl.txt @@ -0,0 +1,6 @@ +Security + * Fix a potential information disclosure in TLS 1.2 servers using session + tickets. If the session ticket write callback failed without setting the + lifetime output parameter, Mbed TLS could send 4 bytes of uninitialized + stack memory to the peer in the NewSessionTicket message. Fixes #1570. + Reported by James Love. CVE-2026-50586. From 273c9b38b78da06244bd685dd7073e599f10eb9e Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Wed, 10 Jun 2026 08:38:36 +0100 Subject: [PATCH 6/6] Correct syntax of MBEDTLS_GET_UINT32_BE in write_new_session_ticket_mem Signed-off-by: Ben Taylor --- tests/suites/test_suite_ssl.function | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 34c4d89e00..d6a7ea8e27 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -6432,7 +6432,7 @@ void write_new_session_ticket_mem() * uninitialized memory. * The read here causes MSan and Valgrind to complain if the bug isn't fixed. */ - volatile unsigned char lifetime = MBEDTLS_GET_UINT32_BE(server_ep.ssl.out_msg + 4); + volatile uint32_t lifetime = MBEDTLS_GET_UINT32_BE(server_ep.ssl.out_msg, 4); (void) lifetime; exit: