Merge pull request #1659 from bjwtaylor/info-leak-in-ssl_write_new_session_ticket-3.6

3.6 backport for Info leak in ssl write new session ticket
This commit is contained in:
Gilles Peskine 2026-06-24 09:42:19 +02:00 committed by GitHub
commit 338572c1d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 105 additions and 3 deletions

View File

@ -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.

View File

@ -4132,8 +4132,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"));
@ -4160,7 +4160,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;
}
MBEDTLS_PUT_UINT32_BE(lifetime, ssl->out_msg, 4);

View File

@ -3563,3 +3563,7 @@ send_invalid_sig_alg:MBEDTLS_SSL_SIG_ECDSA:MBEDTLS_SSL_HASH_SHA512:MBEDTLS_ERR_S
Default verify_result before doing a handshake
verify_result_without_handshake
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:MBEDTLS_PKCS1_V15:MBEDTLS_RSA_C:MBEDTLS_ECP_HAVE_SECP384R1:MBEDTLS_MD_CAN_SHA256:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_CAN_HANDLE_RSA_TEST_KEY
write_new_session_ticket_mem

View File

@ -22,6 +22,37 @@
#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(MBEDTLS_PKCS1_V15) && \
defined(MBEDTLS_RSA_C) && \
defined(MBEDTLS_ECP_HAVE_SECP384R1) && \
defined(MBEDTLS_MD_CAN_SHA256) && \
defined(MBEDTLS_PK_HAVE_ECC_KEYS) && \
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 &&
MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C &&
MBEDTLS_ECP_HAVE_SECP384R1 && MBEDTLS_MD_CAN_SHA256 &&
MBEDTLS_PK_HAVE_ECC_KEYS && 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) && \
@ -6523,3 +6554,65 @@ 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:MBEDTLS_PKCS1_V15:MBEDTLS_RSA_C:MBEDTLS_ECP_HAVE_SECP384R1:MBEDTLS_MD_CAN_SHA256:MBEDTLS_PK_HAVE_ECC_KEYS: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, NULL, NULL, NULL);
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, NULL, NULL, NULL);
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);
/* 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 uint32_t lifetime = MBEDTLS_GET_UINT32_BE(server_ep.ssl.out_msg, 4);
(void) lifetime;
exit:
mbedtls_test_ssl_endpoint_free(&client_ep, NULL);
mbedtls_test_ssl_endpoint_free(&server_ep, NULL);
mbedtls_test_free_handshake_options(&options);
MD_OR_USE_PSA_DONE();
}
/* END_CASE */