From 465d6e9669a24ff7fe1a018fafe0e9f44aa4a48b Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sat, 11 Apr 2026 17:10:14 +0200 Subject: [PATCH 001/173] Fix ssl_tls13_prepare_new_session_ticket returning 1 on an RNG failure Signed-off-by: Gilles Peskine --- .../ssl_tls13_prepare_new_session_ticket-psa_get_random.txt | 5 +++++ library/ssl_tls13_server.c | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 ChangeLog.d/ssl_tls13_prepare_new_session_ticket-psa_get_random.txt diff --git a/ChangeLog.d/ssl_tls13_prepare_new_session_ticket-psa_get_random.txt b/ChangeLog.d/ssl_tls13_prepare_new_session_ticket-psa_get_random.txt new file mode 100644 index 0000000000..0fc8b0aa85 --- /dev/null +++ b/ChangeLog.d/ssl_tls13_prepare_new_session_ticket-psa_get_random.txt @@ -0,0 +1,5 @@ +Security + * Fix a bug where mbedtls_ssl_read() and mbedtls_ssl_write() could return + 1 instead of an error code if the random generator fails if a server + calls these functions before the end of a TLS 1.3 handshake. + Reported by Mohammad Seet (mhdsait101). CVE-2026-40294 diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index dc7c776830..37fdf79ee3 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -3183,8 +3183,9 @@ static int ssl_tls13_prepare_new_session_ticket(mbedtls_ssl_context *ssl, #endif /* Generate ticket_age_add */ - if ((ret = psa_generate_random((unsigned char *) &session->ticket_age_add, - sizeof(session->ticket_age_add)) != 0)) { + ret = psa_generate_random((unsigned char *) &session->ticket_age_add, + sizeof(session->ticket_age_add)); + if (ret != 0) { MBEDTLS_SSL_DEBUG_RET(1, "generate_ticket_age_add", ret); return ret; } From cec2cef6b5ce9ae3cb2bbcd43f3ac8c06f1f9508 Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Tue, 21 Apr 2026 16:46:31 +0100 Subject: [PATCH 002/173] tls13_client: fix HRR selected_group validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reject HRR selected_group unless it matches the client’s original supported_groups and is locally supported, so unadvertised groups are not accepted in the second ClientHello. Signed-off-by: Minos Galanakis --- library/ssl_tls13_client.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index 9b7ca82f91..96d4d08ee0 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -404,14 +404,18 @@ static int ssl_tls13_parse_hrr_key_share_ext(mbedtls_ssl_context *ssl, * then the client MUST abort the handshake with an "illegal_parameter" alert. */ for (; *group_list != 0; group_list++) { + if (*group_list != selected_group) { + continue; + } #if defined(PSA_WANT_ALG_ECDH) if (mbedtls_ssl_tls13_named_group_is_ecdhe(*group_list)) { - if ((mbedtls_ssl_get_psa_curve_info_from_tls_id( - *group_list, NULL, NULL) == PSA_ERROR_NOT_SUPPORTED) || - *group_list != selected_group) { - found = 1; - break; + if (mbedtls_ssl_get_psa_curve_info_from_tls_id( + *group_list, NULL, NULL) == PSA_ERROR_NOT_SUPPORTED) { + continue; } + /* Found only if psa_curve is supported and group_list == selected_group */ + found = 1; + break; } #endif /* PSA_WANT_ALG_ECDH */ #if defined(PSA_WANT_ALG_FFDH) From bac133ffcb782f15851a7b76e238c8f11f59f23d Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Thu, 23 Apr 2026 13:53:40 +0100 Subject: [PATCH 003/173] test_suite_ssl: Introduced hrr_reject_unadvertised_group Signed-off-by: Minos Galanakis --- tests/suites/test_suite_ssl.data | 3 ++ tests/suites/test_suite_ssl.function | 77 ++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 881d502ed5..6239b5a66e 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3347,6 +3347,9 @@ cookie_parsing:"16fefd0000000000000000002F010000de000000000000011efefd7b72727272 TLS 1.3 srv Certificate msg - wrong vector lengths tls13_server_certificate_msg_invalid_vector_len +TLS 1.3 cli rejects HRR selected_group not in original supported_groups +hrr_reject_unadvertised_group + EC-JPAKE set password depends_on:MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED ssl_ecjpake_set_password:0 diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 39457c9047..b640220aac 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -3995,6 +3995,83 @@ exit: } /* END_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:PSA_WANT_ALG_ECDH:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ECC_SECP_R1_384 */ +void hrr_reject_unadvertised_group(void) +{ + int ret = -1; + + mbedtls_test_ssl_endpoint client_ep, server_ep; + mbedtls_test_handshake_test_options client_options, server_options; + + uint16_t offered_group_before_hrr_parse = 0; + uint16_t offered_group_after_hrr_parse = 0; + + /* Group order is intentional: client offers secp256r1 first, while server only + * accepts secp384r1. This prevents immediate group agreement and forces HRR. */ + uint16_t client_group_list[] = { + MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1, + MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1, + MBEDTLS_SSL_IANA_TLS_GROUP_NONE + }; + uint16_t server_group_list[] = { MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1, + MBEDTLS_SSL_IANA_TLS_GROUP_NONE }; + + memset(&client_ep, 0, sizeof(client_ep)); + memset(&server_ep, 0, sizeof(server_ep)); + + mbedtls_test_init_handshake_options(&client_options); + mbedtls_test_init_handshake_options(&server_options); + MD_OR_USE_PSA_INIT(); + + client_options.pk_alg = MBEDTLS_PK_ECDSA; + client_options.client_min_version = MBEDTLS_SSL_VERSION_TLS1_3; + client_options.client_max_version = MBEDTLS_SSL_VERSION_TLS1_3; + client_options.group_list = client_group_list; + + server_options.pk_alg = MBEDTLS_PK_ECDSA; + server_options.server_min_version = MBEDTLS_SSL_VERSION_TLS1_3; + server_options.server_max_version = MBEDTLS_SSL_VERSION_TLS1_3; + server_options.group_list = server_group_list; + + TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT, + &client_options), 0); + + TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER, + &server_options), 0); + + TEST_EQUAL(mbedtls_test_mock_socket_connect(&(client_ep.socket), + &(server_ep.socket), 4096), 0); + + ret = mbedtls_test_move_handshake_to_state( + &(server_ep.ssl), &(client_ep.ssl), + MBEDTLS_SSL_HELLO_RETRY_REQUEST); + TEST_EQUAL(ret, 0); + + server_ep.ssl.handshake->hrr_selected_group = MBEDTLS_SSL_IANA_TLS_GROUP_X25519; + TEST_EQUAL(mbedtls_ssl_handshake_step(&(server_ep.ssl)), 0); + + /* Push the HRR with unadvertised group into the wire*/ + TEST_EQUAL(mbedtls_ssl_flush_output(&(server_ep.ssl)), 0); + + offered_group_before_hrr_parse = client_ep.ssl.handshake->offered_group_id; + + /* Client should reject malformed selected_group with illegal_parameter. */ + TEST_EQUAL(mbedtls_ssl_handshake_step(&(client_ep.ssl)), MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER); + + /* The server send a non advertised group during HRR. Client shouldnt accept it as offered_group_id */ + offered_group_after_hrr_parse = client_ep.ssl.handshake->offered_group_id; + TEST_EQUAL(offered_group_after_hrr_parse, offered_group_before_hrr_parse); + + +exit: + mbedtls_test_ssl_endpoint_free(&client_ep); + mbedtls_test_ssl_endpoint_free(&server_ep); + mbedtls_test_free_handshake_options(&client_options); + mbedtls_test_free_handshake_options(&server_options); + MD_OR_USE_PSA_DONE(); +} +/* END_CASE */ + /* BEGIN_CASE depends_on:MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ void ssl_ecjpake_set_password(int use_opaque_arg) { From 2c164902ea239738dc9b943c002351266972b860 Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Mon, 27 Apr 2026 12:25:32 +0100 Subject: [PATCH 004/173] Adjusted dependecies for hrr_reject_unadvertised_group Signed-off-by: Minos Galanakis --- 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 b640220aac..1153be4a73 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -3995,7 +3995,7 @@ exit: } /* END_CASE */ -/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:PSA_WANT_ALG_ECDH:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ECC_SECP_R1_384 */ +/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:PSA_WANT_ALG_SHA_256:PSA_WANT_ALG_ECDH:PSA_WANT_ALG_ECDSA_ANY:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ECC_SECP_R1_384 */ void hrr_reject_unadvertised_group(void) { int ret = -1; From 45ca9e1e061bd7df824137ee72045f7a49124da5 Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Tue, 12 May 2026 14:59:18 +0100 Subject: [PATCH 005/173] Added ChangeLog Signed-off-by: Minos Galanakis --- ChangeLog.d/tls13-hrr-selected-group.txt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 ChangeLog.d/tls13-hrr-selected-group.txt diff --git a/ChangeLog.d/tls13-hrr-selected-group.txt b/ChangeLog.d/tls13-hrr-selected-group.txt new file mode 100644 index 0000000000..20d7a18fbd --- /dev/null +++ b/ChangeLog.d/tls13-hrr-selected-group.txt @@ -0,0 +1,5 @@ +Security + * Fix TLS 1.3 clients to reject a HelloRetryRequest whose selected group was + not advertised in the original ClientHello. Reported by + Din Asotić / Xiangdong Li, Beijing University of Posts and + Telecommunications (BUPT) From be84be5d9a76af58937ef100218fe3fce91f2bc1 Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Wed, 13 May 2026 11:33:40 +0100 Subject: [PATCH 006/173] test_suite_ssl: doc fixes Signed-off-by: Minos Galanakis --- 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 1153be4a73..8615e6972c 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4058,7 +4058,7 @@ void hrr_reject_unadvertised_group(void) /* Client should reject malformed selected_group with illegal_parameter. */ TEST_EQUAL(mbedtls_ssl_handshake_step(&(client_ep.ssl)), MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER); - /* The server send a non advertised group during HRR. Client shouldnt accept it as offered_group_id */ + /* The server sends a non-advertised group during HRR. Client shouldn't accept it as offered_group_id */ offered_group_after_hrr_parse = client_ep.ssl.handshake->offered_group_id; TEST_EQUAL(offered_group_after_hrr_parse, offered_group_before_hrr_parse); From f8adf7498873b7f01ca1e4019ffc1027156d0188 Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Tue, 19 May 2026 17:31:47 +0100 Subject: [PATCH 007/173] sll_client: align TLS 1.3 supported_groups filtering with PSA curve support Signed-off-by: Minos Galanakis --- library/ssl_client.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/library/ssl_client.c b/library/ssl_client.c index 6fe6dd8fe6..7f0bb7d937 100644 --- a/library/ssl_client.c +++ b/library/ssl_client.c @@ -208,6 +208,9 @@ static int ssl_write_alpn_ext(mbedtls_ssl_context *ssl, * generalization of the TLS 1.2 supported elliptic curves extension. They both * share the same extension identifier. * + * If the TLS 1.3 logic for selecting proposed groups changes, the TLS 1.3 + * group filtering in this function must be kept in sync. + * */ #define SSL_WRITE_SUPPORTED_GROUPS_EXT_TLS1_2_FLAG 1 #define SSL_WRITE_SUPPORTED_GROUPS_EXT_TLS1_3_FLAG 2 @@ -251,8 +254,8 @@ static int ssl_write_supported_groups_ext(mbedtls_ssl_context *ssl, if (flags & SSL_WRITE_SUPPORTED_GROUPS_EXT_TLS1_3_FLAG) { #if defined(PSA_WANT_ALG_ECDH) if (mbedtls_ssl_tls13_named_group_is_ecdhe(*group_list) && - (mbedtls_ssl_get_ecp_group_id_from_tls_id(*group_list) != - MBEDTLS_ECP_DP_NONE)) { + mbedtls_ssl_get_psa_curve_info_from_tls_id( + *group_list, NULL, NULL) == PSA_SUCCESS) { propose_group = 1; } #endif From d3931632fa331f18e3d3800391d56469a6d7febb Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Tue, 19 May 2026 17:36:12 +0100 Subject: [PATCH 008/173] test_suite_ssl: Renamed hrr_reject_selecting_unoffered_group Signed-off-by: Minos Galanakis --- tests/suites/test_suite_ssl.data | 4 ++-- tests/suites/test_suite_ssl.function | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 6239b5a66e..0c30c8987b 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3347,8 +3347,8 @@ cookie_parsing:"16fefd0000000000000000002F010000de000000000000011efefd7b72727272 TLS 1.3 srv Certificate msg - wrong vector lengths tls13_server_certificate_msg_invalid_vector_len -TLS 1.3 cli rejects HRR selected_group not in original supported_groups -hrr_reject_unadvertised_group +TLS 1.3 cli rejects HRR selecting an un-offered group +reject_hrr_selecting_unoffered_group EC-JPAKE set password depends_on:MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 8615e6972c..5097840748 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -3996,7 +3996,7 @@ exit: /* END_CASE */ /* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:PSA_WANT_ALG_SHA_256:PSA_WANT_ALG_ECDH:PSA_WANT_ALG_ECDSA_ANY:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ECC_SECP_R1_384 */ -void hrr_reject_unadvertised_group(void) +void reject_hrr_selecting_unoffered_group(void) { int ret = -1; From c4461967af0cc7331831a2f50b095766cb7b1e6e Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Tue, 19 May 2026 22:12:05 +0100 Subject: [PATCH 009/173] test_suite_ssl: Restructured reject_hrr_selecting_unoffered_group Signed-off-by: Minos Galanakis --- tests/suites/test_suite_ssl.function | 75 ++++++++++++++++++---------- 1 file changed, 49 insertions(+), 26 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 5097840748..fe4d30f8fb 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4002,9 +4002,7 @@ void reject_hrr_selecting_unoffered_group(void) mbedtls_test_ssl_endpoint client_ep, server_ep; mbedtls_test_handshake_test_options client_options, server_options; - - uint16_t offered_group_before_hrr_parse = 0; - uint16_t offered_group_after_hrr_parse = 0; + mbedtls_test_ssl_log_pattern cli_pattern = { .pattern = "Invalid key share in HRR" }; /* Group order is intentional: client offers secp256r1 first, while server only * accepts secp384r1. This prevents immediate group agreement and forces HRR. */ @@ -4027,47 +4025,72 @@ void reject_hrr_selecting_unoffered_group(void) client_options.client_min_version = MBEDTLS_SSL_VERSION_TLS1_3; client_options.client_max_version = MBEDTLS_SSL_VERSION_TLS1_3; client_options.group_list = client_group_list; + client_options.cli_log_obj = &cli_pattern; + client_options.cli_log_fun = mbedtls_test_ssl_log_analyzer; + mbedtls_debug_set_threshold(1); server_options.pk_alg = MBEDTLS_PK_ECDSA; server_options.server_min_version = MBEDTLS_SSL_VERSION_TLS1_3; server_options.server_max_version = MBEDTLS_SSL_VERSION_TLS1_3; server_options.group_list = server_group_list; - TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT, - &client_options), 0); + for (int round = 0; round < 2; round++) { + int select_unoffered_group = (round != 0); + TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&client_ep, + MBEDTLS_SSL_IS_CLIENT, + &client_options), 0); - TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER, - &server_options), 0); + TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&server_ep, + MBEDTLS_SSL_IS_SERVER, + &server_options), 0); - TEST_EQUAL(mbedtls_test_mock_socket_connect(&(client_ep.socket), - &(server_ep.socket), 4096), 0); + TEST_EQUAL(mbedtls_test_mock_socket_connect(&(client_ep.socket), + &(server_ep.socket), 4096), 0); - ret = mbedtls_test_move_handshake_to_state( - &(server_ep.ssl), &(client_ep.ssl), - MBEDTLS_SSL_HELLO_RETRY_REQUEST); - TEST_EQUAL(ret, 0); + ret = mbedtls_test_move_handshake_to_state( + &(server_ep.ssl), &(client_ep.ssl), + MBEDTLS_SSL_HELLO_RETRY_REQUEST); + TEST_EQUAL(ret, 0); + TEST_EQUAL(client_ep.ssl.handshake->offered_group_id, + MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1); - server_ep.ssl.handshake->hrr_selected_group = MBEDTLS_SSL_IANA_TLS_GROUP_X25519; - TEST_EQUAL(mbedtls_ssl_handshake_step(&(server_ep.ssl)), 0); + if (!select_unoffered_group) { + TEST_EQUAL(server_ep.ssl.handshake->hrr_selected_group, + MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1); + } else { + server_ep.ssl.handshake->hrr_selected_group = MBEDTLS_SSL_IANA_TLS_GROUP_X25519; + } - /* Push the HRR with unadvertised group into the wire*/ - TEST_EQUAL(mbedtls_ssl_flush_output(&(server_ep.ssl)), 0); - - offered_group_before_hrr_parse = client_ep.ssl.handshake->offered_group_id; - - /* Client should reject malformed selected_group with illegal_parameter. */ - TEST_EQUAL(mbedtls_ssl_handshake_step(&(client_ep.ssl)), MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER); - - /* The server sends a non-advertised group during HRR. Client shouldn't accept it as offered_group_id */ - offered_group_after_hrr_parse = client_ep.ssl.handshake->offered_group_id; - TEST_EQUAL(offered_group_after_hrr_parse, offered_group_before_hrr_parse); + /* Write and send the HRR */ + TEST_EQUAL(mbedtls_ssl_handshake_step(&(server_ep.ssl)), 0); + TEST_EQUAL(mbedtls_ssl_flush_output(&(server_ep.ssl)), 0); + if (!select_unoffered_group) { + /* Valid HRR, the client accepts the group MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1 + * and goes ahead with the handshake. + */ + TEST_EQUAL(mbedtls_ssl_handshake_step(&(client_ep.ssl)), 0); + TEST_ASSERT(client_ep.ssl.state != MBEDTLS_SSL_SERVER_HELLO); + TEST_EQUAL(cli_pattern.counter, 0); + } else { + /* Invalid HRR selecting MBEDTLS_SSL_IANA_TLS_GROUP_X25519 group. + * The client rejects it and aborts the handshake. + */ + TEST_EQUAL(mbedtls_ssl_handshake_step(&(client_ep.ssl)), + MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); + TEST_EQUAL(cli_pattern.counter, 1); + } + mbedtls_test_ssl_endpoint_free(&client_ep); + mbedtls_test_ssl_endpoint_free(&server_ep); + } exit: mbedtls_test_ssl_endpoint_free(&client_ep); mbedtls_test_ssl_endpoint_free(&server_ep); mbedtls_test_free_handshake_options(&client_options); mbedtls_test_free_handshake_options(&server_options); + mbedtls_debug_set_threshold(0); MD_OR_USE_PSA_DONE(); } /* END_CASE */ From 2e2087d246b8f78d804bf682587c364a0b2ec77e Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Wed, 20 May 2026 12:25:42 +0100 Subject: [PATCH 010/173] test_suite_ssl: Added MBEDTLS_DEBUG_C guards to logs Signed-off-by: Minos Galanakis --- tests/suites/test_suite_ssl.function | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index fe4d30f8fb..39317cf3f9 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4002,7 +4002,9 @@ void reject_hrr_selecting_unoffered_group(void) mbedtls_test_ssl_endpoint client_ep, server_ep; mbedtls_test_handshake_test_options client_options, server_options; +#if defined(MBEDTLS_DEBUG_C) mbedtls_test_ssl_log_pattern cli_pattern = { .pattern = "Invalid key share in HRR" }; +#endif /* MBEDTLS_DEBUG_C */ /* Group order is intentional: client offers secp256r1 first, while server only * accepts secp384r1. This prevents immediate group agreement and forces HRR. */ @@ -4025,9 +4027,11 @@ void reject_hrr_selecting_unoffered_group(void) client_options.client_min_version = MBEDTLS_SSL_VERSION_TLS1_3; client_options.client_max_version = MBEDTLS_SSL_VERSION_TLS1_3; client_options.group_list = client_group_list; +#if defined(MBEDTLS_DEBUG_C) client_options.cli_log_obj = &cli_pattern; client_options.cli_log_fun = mbedtls_test_ssl_log_analyzer; mbedtls_debug_set_threshold(1); +#endif /* MBEDTLS_DEBUG_C */ server_options.pk_alg = MBEDTLS_PK_ECDSA; server_options.server_min_version = MBEDTLS_SSL_VERSION_TLS1_3; @@ -4071,7 +4075,9 @@ void reject_hrr_selecting_unoffered_group(void) */ TEST_EQUAL(mbedtls_ssl_handshake_step(&(client_ep.ssl)), 0); TEST_ASSERT(client_ep.ssl.state != MBEDTLS_SSL_SERVER_HELLO); +#if defined(MBEDTLS_DEBUG_C) TEST_EQUAL(cli_pattern.counter, 0); +#endif /* MBEDTLS_DEBUG_C */ } else { /* Invalid HRR selecting MBEDTLS_SSL_IANA_TLS_GROUP_X25519 group. * The client rejects it and aborts the handshake. @@ -4079,7 +4085,9 @@ void reject_hrr_selecting_unoffered_group(void) TEST_EQUAL(mbedtls_ssl_handshake_step(&(client_ep.ssl)), MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER); TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); +#if defined(MBEDTLS_DEBUG_C) TEST_EQUAL(cli_pattern.counter, 1); +#endif /* MBEDTLS_DEBUG_C */ } mbedtls_test_ssl_endpoint_free(&client_ep); mbedtls_test_ssl_endpoint_free(&server_ep); @@ -4090,7 +4098,9 @@ exit: mbedtls_test_ssl_endpoint_free(&server_ep); mbedtls_test_free_handshake_options(&client_options); mbedtls_test_free_handshake_options(&server_options); +#if defined(MBEDTLS_DEBUG_C) mbedtls_debug_set_threshold(0); +#endif /* MBEDTLS_DEBUG_C */ MD_OR_USE_PSA_DONE(); } /* END_CASE */ From e16f0e0b014be310f423de5e52109cd0712db6f7 Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Tue, 26 May 2026 10:17:11 +0100 Subject: [PATCH 011/173] ssl_write_supported_groups_ext: Updated documentation Signed-off-by: Minos Galanakis --- library/ssl_client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/ssl_client.c b/library/ssl_client.c index 7f0bb7d937..354fe9b72b 100644 --- a/library/ssl_client.c +++ b/library/ssl_client.c @@ -209,7 +209,8 @@ static int ssl_write_alpn_ext(mbedtls_ssl_context *ssl, * share the same extension identifier. * * If the TLS 1.3 logic for selecting proposed groups changes, the TLS 1.3 - * group filtering in this function must be kept in sync. + * group filtering in the function `ssl_tls13_parse_hrr_key_share_ext()` must + * be updated accordingly. * */ #define SSL_WRITE_SUPPORTED_GROUPS_EXT_TLS1_2_FLAG 1 From 1af2443a38e4ad27fd21a8f86e1cbf9af5036909 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 8 May 2026 12:22:12 +0200 Subject: [PATCH 012/173] Update framework with test certificate with basicConstraints overflow Signed-off-by: Gilles Peskine --- framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework b/framework index e92a819966..e0f6275eff 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit e92a81996656d82941a9afce843453c57e1d51f5 +Subproject commit e0f6275eff2e45e295fdd6b6877de4cbdaddae83 From 9007fc4b9be08da1d494f8fa4a5a09180291956b Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 6 May 2026 22:29:22 +0200 Subject: [PATCH 013/173] Fix lax basicConstraints parsing When parsing the basicConstraints extension, reject junk after the SEQUENCE inside the extension (which is probably benign), and reject a SEQUENCE that extends beyond the extension (could be very dangerous). Add a non-regression test where a certificate that is technically malformed, but accepted as a leaf certificate by OpenSSL and other X.509 implementations, to be accepted as a CA certificate by Mbed TLS. Signed-off-by: Gilles Peskine --- ChangeLog.d/x509-crt-parse-basicConstraints.txt | 7 +++++++ library/x509_crt.c | 7 +++++++ tests/suites/test_suite_x509parse.data | 8 ++++++++ 3 files changed, 22 insertions(+) create mode 100644 ChangeLog.d/x509-crt-parse-basicConstraints.txt diff --git a/ChangeLog.d/x509-crt-parse-basicConstraints.txt b/ChangeLog.d/x509-crt-parse-basicConstraints.txt new file mode 100644 index 0000000000..c5b25f114b --- /dev/null +++ b/ChangeLog.d/x509-crt-parse-basicConstraints.txt @@ -0,0 +1,7 @@ +Security + * Fix a bug in the X.509 certificate parser that caused some inputs + with a malformed basicConstraints extension to be accepted. This + could have dangerous results, in particular causing some certificates + to be parsed as CA certificates when other X.509 implementations would + parse them as end-entity certificates. Reported by Mohammad Seet + (mhdsait101). CVE-2026-TODO diff --git a/library/x509_crt.c b/library/x509_crt.c index 3232760ea2..637ce7f336 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -515,6 +515,13 @@ static int x509_get_basic_constraints(unsigned char **p, return 0; } + if ((size_t) (end - *p) != len) { + /* Reject junk after the SEQUENCE inside the extension (which is + * probably benign), and reject a SEQUENCE that extends beyond + * the extension (could be very dangerous). */ + return MBEDTLS_ERR_X509_INVALID_EXTENSIONS; + } + if ((ret = mbedtls_asn1_get_bool(p, end, ca_istrue)) != 0) { if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { ret = mbedtls_asn1_get_int(p, end, ca_istrue); diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index 5e91df9107..4f479fb30d 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -2052,6 +2052,14 @@ X509 CRT ASN1 (TBSCertificate v3, inv CertificatePolicies, policy qualifier leng depends_on:PSA_HAVE_ALG_SOME_RSA_VERIFY:PSA_WANT_ALG_SHA_256 x509parse_crt:"3081b030819aa0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092a864886f70d01010105000319003016021100ffffffffffffffffffffffffffffffff020103a100a200a314301230100603551d200409300730050601003001300d06092a864886f70d01010b0500030200ff":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_OUT_OF_DATA) +X509 CRT ASN1: basicConstraints overflow would make CA=1 (bad signature) +depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 +mbedtls_x509_crt_parse_file:"../framework/data_files/parse_input/server5.basic-constraints-sequence-overflow.badsign.crt":MBEDTLS_ERR_X509_INVALID_EXTENSIONS:0 + +X509 CRT ASN1: basicConstraints overflow would make CA=1 (good self signature) +depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 +mbedtls_x509_crt_parse_file:"../framework/data_files/parse_input/server5.basic-constraints-sequence-overflow.selfsigned.crt":MBEDTLS_ERR_X509_INVALID_EXTENSIONS:0 + X509 CRT ASN1 (TBS, inv extBasicConstraint, no pathlen length) depends_on:PSA_HAVE_ALG_SOME_RSA_VERIFY:PSA_WANT_ALG_SHA_256 x509parse_crt:"3081b030819aa0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D01010105000319003016021100ffffffffffffffffffffffffffffffff020103a100a200a314301230100603551d130101010406300402010102300d06092a864886f70d01010b0500030200ff":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_OUT_OF_DATA) From 271bf181933a210ecf8a297ffed3830e55dbd389 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Fri, 15 May 2026 11:44:18 +0200 Subject: [PATCH 014/173] ssl: improve documentation of mbedtls_ssl_conf_sig_algs() Clarify that the 'sig_algs' set through this function are only enforced during the key exchange and that 'mbedtls_ssl_conf_cert_profile()' should instead be used to enforce the same algorithms when verifying certificates. Signed-off-by: Valerio Setti --- include/mbedtls/ssl.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 3a69df5466..2a6d98ab1c 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -3411,7 +3411,7 @@ int mbedtls_ssl_conf_cid(mbedtls_ssl_config *conf, size_t len, * * \note The restrictions are enforced for all certificates in the * chain. However, signatures in the handshake are not covered - * by this setting but by \b mbedtls_ssl_conf_sig_algs(). + * by this setting but by \c mbedtls_ssl_conf_sig_algs(). * * \param conf SSL configuration * \param profile Profile to use @@ -3899,7 +3899,12 @@ void mbedtls_ssl_conf_groups(mbedtls_ssl_config *conf, #if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED) /** - * \brief Configure allowed signature algorithms for use in TLS + * \brief Configure allowed signature algorithms for use in TLS key + * exchange. + * + * \note This only covers signature algorithms used in the key + * exchange. To also enforce restrictions in certificate verification + * refer to \c mbedtls_ssl_conf_cert_profile(). * * \param conf The SSL configuration to use. * \param sig_algs List of allowed IANA values for TLS 1.3 signature algorithms, From f0ed933ca840ddde8df7b1adc21581eb9fd2e614 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Mon, 18 May 2026 11:08:23 +0200 Subject: [PATCH 015/173] changelog: add note about issue 1569 resolution Signed-off-by: Valerio Setti --- ChangeLog.d/security-issue1569.txt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 ChangeLog.d/security-issue1569.txt diff --git a/ChangeLog.d/security-issue1569.txt b/ChangeLog.d/security-issue1569.txt new file mode 100644 index 0000000000..320947ec90 --- /dev/null +++ b/ChangeLog.d/security-issue1569.txt @@ -0,0 +1,4 @@ +Security + * Improved documentation of mbedtls_ssl_conf_sig_algs() to emphasize that + this function only set signature algorithms that are enforced during + TLS key exchange and not only on certificate verification. From bd57fb5e8afe003ed24a2ae9e8ca487ecdc4c3f4 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Tue, 19 May 2026 12:37:30 +0200 Subject: [PATCH 016/173] changelog: fix typos Signed-off-by: Valerio Setti --- ChangeLog.d/security-issue1569.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog.d/security-issue1569.txt b/ChangeLog.d/security-issue1569.txt index 320947ec90..c7d3ca0782 100644 --- a/ChangeLog.d/security-issue1569.txt +++ b/ChangeLog.d/security-issue1569.txt @@ -1,4 +1,4 @@ Security * Improved documentation of mbedtls_ssl_conf_sig_algs() to emphasize that - this function only set signature algorithms that are enforced during - TLS key exchange and not only on certificate verification. + this function only sets signature algorithms that are enforced during + TLS key exchange and not on certificate verification. From b05434c1b1df14cb3b2ce52dd1200c3ba9f9b198 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 28 May 2026 16:32:09 +0200 Subject: [PATCH 017/173] Improve changelog wording Signed-off-by: Gilles Peskine --- .../ssl_tls13_prepare_new_session_ticket-psa_get_random.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog.d/ssl_tls13_prepare_new_session_ticket-psa_get_random.txt b/ChangeLog.d/ssl_tls13_prepare_new_session_ticket-psa_get_random.txt index 0fc8b0aa85..b020546b12 100644 --- a/ChangeLog.d/ssl_tls13_prepare_new_session_ticket-psa_get_random.txt +++ b/ChangeLog.d/ssl_tls13_prepare_new_session_ticket-psa_get_random.txt @@ -1,5 +1,5 @@ Security * Fix a bug where mbedtls_ssl_read() and mbedtls_ssl_write() could return - 1 instead of an error code if the random generator fails if a server - calls these functions before the end of a TLS 1.3 handshake. + 1 instead of an error code if the random generator failed when a server + called these functions before the end of a TLS 1.3 handshake. Reported by Mohammad Seet (mhdsait101). CVE-2026-40294 From 1ac3989db6cd0416f562764e3bfacca62ce4875c Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 11 May 2026 15:22:09 +0100 Subject: [PATCH 018/173] Add fix for OOB key exchange error Signed-off-by: Ben Taylor --- library/ssl_tls12_client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/ssl_tls12_client.c b/library/ssl_tls12_client.c index a0170d51f6..d32fea18c1 100644 --- a/library/ssl_tls12_client.c +++ b/library/ssl_tls12_client.c @@ -1885,6 +1885,8 @@ start_processing: * However since we only support secp256r1 for now, we check only * that TLS ID here */ + MBEDTLS_SSL_CHK_BUF_READ_PTR(p, end, 3); + uint16_t read_tls_id = MBEDTLS_GET_UINT16_BE(p, 1); uint16_t exp_tls_id = mbedtls_ssl_get_tls_id_from_ecp_group_id( MBEDTLS_ECP_DP_SECP256R1); From 0cc307762a975a8cb0047df36703935bf084bd37 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Tue, 12 May 2026 14:41:06 +0100 Subject: [PATCH 019/173] Add ChangeLog Signed-off-by: Ben Taylor --- ChangeLog.d/oob-key-exchange-restricted.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 ChangeLog.d/oob-key-exchange-restricted.txt diff --git a/ChangeLog.d/oob-key-exchange-restricted.txt b/ChangeLog.d/oob-key-exchange-restricted.txt new file mode 100644 index 0000000000..a0e698c077 --- /dev/null +++ b/ChangeLog.d/oob-key-exchange-restricted.txt @@ -0,0 +1,3 @@ +Security + * Fix an out-of-bounds read in TLS 1.2 ECJPAKE ServerKeyExchange parsing. + Reported-by Biniam Demissie From 44b833324b6a8ba3354b94cdb55fab1eb7be3f14 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 7 May 2026 20:29:11 +0200 Subject: [PATCH 020/173] Tighten CSR extensionRequest bounds Don't allow parts of a compound (SEQUENCE or SET) to go beyond the containing compound. The inline CSR regression test is derived from the existing "X509 CSR ASN.1 (OK)" DER test vector. In the extensionRequest attribute, the original well-formed fragment is: a029 3027 06092a864886f70d01090e 311a 3018 ... where 31 1a is the SET containing the Extensions sequence and 30 18 is the contained Extensions sequence. The malformed test changes only the SET length byte, from 1a to 19: a029 3027 06092a864886f70d01090e 3119 3018 ... The attribute SEQUENCE length and the inner Extensions sequence length are left unchanged. This makes the SET one byte too short for its containing attribute, so the parser must reject it with MBEDTLS_ERR_ASN1_LENGTH_MISMATCH instead of parsing the trailing byte as data outside the SET. There is no known security impact, just some risk reduction. Signed-off-by: Gilles Peskine --- .../x509-csr-extension-request-bounds.txt | 3 +++ library/x509_csr.c | 18 +++++++++++++++--- tests/suites/test_suite_x509parse.data | 12 ++++++++---- 3 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 ChangeLog.d/x509-csr-extension-request-bounds.txt diff --git a/ChangeLog.d/x509-csr-extension-request-bounds.txt b/ChangeLog.d/x509-csr-extension-request-bounds.txt new file mode 100644 index 0000000000..dfc706703c --- /dev/null +++ b/ChangeLog.d/x509-csr-extension-request-bounds.txt @@ -0,0 +1,3 @@ +Bugfix + * Reject malformed X.509 CSRs where the extensionRequest attribute + wrappers do not exactly contain the requested extensions. diff --git a/library/x509_csr.c b/library/x509_csr.c index 3e8e407b26..45b7b8f9ac 100644 --- a/library/x509_csr.c +++ b/library/x509_csr.c @@ -227,18 +227,30 @@ static int x509_csr_parse_attributes(mbedtls_x509_csr *csr, /* Check that this is an extension-request attribute */ if (MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS9_CSR_EXT_REQ, &attr_oid) == 0) { - if ((ret = mbedtls_asn1_get_tag(p, end, &len, + if ((ret = mbedtls_asn1_get_tag(p, end_attr_data, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET)) != 0) { return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); } - if ((ret = mbedtls_asn1_get_tag(p, end, &len, + const unsigned char *end_set = *p + len; + if (end_set != end_attr_data) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); + } + + if ((ret = mbedtls_asn1_get_tag(p, end_set, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); } - if ((ret = x509_csr_parse_extensions(csr, p, *p + len, cb, p_ctx)) != 0) { + const unsigned char *end_exts = *p + len; + if (end_exts != end_set) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); + } + + if ((ret = x509_csr_parse_extensions(csr, p, end_exts, cb, p_ctx)) != 0) { return ret; } diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index 4f479fb30d..bb91cd1788 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -2955,6 +2955,10 @@ X509 CSR ASN.1 (OK) depends_on:PSA_HAVE_ALG_SOME_ECDSA:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_1:!MBEDTLS_X509_REMOVE_INFO mbedtls_x509_csr_parse:"308201183081bf0201003034310b3009060355040613024e4c3111300f060355040a1308506f6c617253534c31123010060355040313096c6f63616c686f73743059301306072a8648ce3d020106082a8648ce3d0301070342000437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edffa029302706092a864886f70d01090e311a301830090603551d1304023000300b0603551d0f0404030205e0300906072a8648ce3d04010349003046022100b49fd8c8f77abfa871908dfbe684a08a793d0f490a43d86fcf2086e4f24bb0c2022100f829d5ccd3742369299e6294394717c4b723a0f68b44e831b6e6c3bcabf97243":"CSR version \: 1\nsubject name \: C=NL, O=PolarSSL, CN=localhost\nsigned using \: ECDSA with SHA1\nEC key size \: 256 bits\n\nkey usage \: Digital Signature, Non Repudiation, Key Encipherment\n":0 +X509 CSR ASN.1 (extensionRequest SET length too short) +depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1 +mbedtls_x509_csr_parse:"308201183081bf0201003034310b3009060355040613024e4c3111300f060355040a1308506f6c617253534c31123010060355040313096c6f63616c686f73743059301306072a8648ce3d020106082a8648ce3d0301070342000437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edffa029302706092a864886f70d01090e3119301830090603551d1304023000300b0603551d0f0404030205e0300906072a8648ce3d04010349003046022100b49fd8c8f77abfa871908dfbe684a08a793d0f490a43d86fcf2086e4f24bb0c2022100f829d5ccd3742369299e6294394717c4b723a0f68b44e831b6e6c3bcabf97243":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS+MBEDTLS_ERR_ASN1_LENGTH_MISMATCH + X509 CSR ASN.1 (Unsupported critical extension, critical=true) depends_on:PSA_HAVE_ALG_SOME_ECDSA:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256:!MBEDTLS_X509_REMOVE_INFO mbedtls_x509_csr_parse:"308201233081cb02010030413119301706035504030c1053656c66207369676e65642074657374310b300906035504061302444531173015060355040a0c0e41757468437274444220546573743059301306072a8648ce3d020106082a8648ce3d03010703420004c11ebb9951848a436ca2c8a73382f24bbb6c28a92e401d4889b0c361f377b92a8b0497ff2f5a5f6057ae85f704ab1850bef075914f68ed3aeb15a1ff1ebc0dc6a028302606092a864886f70d01090e311930173015060b2b0601040183890c8622020101ff0403010101300a06082a8648ce3d040302034700304402200c4108fd098525993d3fd5b113f0a1ead8750852baf55a2f8e670a22cabc0ba1022034db93a0fcb993912adcf2ea8cb4b66389af30e264d43c0daea03255e45d2ccc":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) @@ -3090,17 +3094,17 @@ X509 CSR ASN.1 (attributes: invalid len (len > data)) depends_on:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_SOME_RSA_VERIFY mbedtls_x509_csr_parse_file:"../framework/data_files/parse_input/test_csr_v3_all_malformed_attributes_len1.csr.der":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_OUT_OF_DATA) -X509 CSR ASN.1 (attributes: invalid len (len < data)) +X509 CSR ASN.1 (attributes: extensionRequest SET extends past attribute) depends_on:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_SOME_RSA_VERIFY -mbedtls_x509_csr_parse_file:"../framework/data_files/parse_input/test_csr_v3_all_malformed_attributes_len2.csr.der":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_LENGTH_MISMATCH) +mbedtls_x509_csr_parse_file:"../framework/data_files/parse_input/test_csr_v3_all_malformed_attributes_len2.csr.der":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_OUT_OF_DATA) X509 CSR ASN.1 (attributes: extension request invalid len (len > data)) depends_on:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_SOME_RSA_VERIFY mbedtls_x509_csr_parse_file:"../framework/data_files/parse_input/test_csr_v3_all_malformed_attributes_extension_request_sequence_len1.csr.der":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_OUT_OF_DATA) -X509 CSR ASN.1 (attributes: extension request invalid len (len < data)) +X509 CSR ASN.1 (attributes: extensionRequest sequence shorter than SET) depends_on:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_SOME_RSA_VERIFY -mbedtls_x509_csr_parse_file:"../framework/data_files/parse_input/test_csr_v3_all_malformed_attributes_extension_request_sequence_len2.csr.der":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_OUT_OF_DATA) +mbedtls_x509_csr_parse_file:"../framework/data_files/parse_input/test_csr_v3_all_malformed_attributes_extension_request_sequence_len2.csr.der":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_LENGTH_MISMATCH) X509 CSR ASN.1 (extensions: invalid sequence tag) depends_on:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_SOME_RSA_VERIFY From ef81e7106114e2b78eb3822c9c2fc39e3a1ca6bf Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 7 May 2026 20:59:00 +0200 Subject: [PATCH 021/173] Remove unreachable CSR extensionRequest check It is now unreachable because: - end_set == end_attr_data is enforced at library/x509_csr.c:236. - end_exts == end_set is enforced at library/x509_csr.c:248. - x509_csr_parse_extensions() only returns success if *p == end_exts, enforced at library/x509_csr.c:188. So after a successful x509_csr_parse_extensions() call, *p == end_exts == end_set == end_attr_data. The condition at line 257 cannot be true. Signed-off-by: Gilles Peskine --- library/x509_csr.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/library/x509_csr.c b/library/x509_csr.c index 45b7b8f9ac..28a4560c43 100644 --- a/library/x509_csr.c +++ b/library/x509_csr.c @@ -253,11 +253,8 @@ static int x509_csr_parse_attributes(mbedtls_x509_csr *csr, if ((ret = x509_csr_parse_extensions(csr, p, end_exts, cb, p_ctx)) != 0) { return ret; } - - if (*p != end_attr_data) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, - MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); - } + /* x509_csr_parse_extensions() guarantees *p == end_exts + * on success */ } *p = end_attr_data; From f6afd20e719b6b3a8dcbf28dea3a0f736e9f02a9 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 12 May 2026 17:14:02 +0200 Subject: [PATCH 022/173] basicConstraints pathLenConstraint tests: use standard cA type In test cases for pathLenConstraint parsing in a basicConstraints extension of an X.509 certificate, use the standard type for the leading cA field, namely BOOLEAN. The test data was encoding that field as INTEGER, which was accepted as a deviation from the standard since XySSL 0.9. Signed-off-by: Gilles Peskine --- tests/suites/test_suite_x509parse.data | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index bb91cd1788..ff4ecaedc1 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -2062,7 +2062,7 @@ mbedtls_x509_crt_parse_file:"../framework/data_files/parse_input/server5.basic-c X509 CRT ASN1 (TBS, inv extBasicConstraint, no pathlen length) depends_on:PSA_HAVE_ALG_SOME_RSA_VERIFY:PSA_WANT_ALG_SHA_256 -x509parse_crt:"3081b030819aa0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D01010105000319003016021100ffffffffffffffffffffffffffffffff020103a100a200a314301230100603551d130101010406300402010102300d06092a864886f70d01010b0500030200ff":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_OUT_OF_DATA) +x509parse_crt:"3081b030819aa0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D01010105000319003016021100ffffffffffffffffffffffffffffffff020103a100a200a314301230100603551d13010101040630040101ff02300d06092a864886f70d01010b0500030200ff":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_OUT_OF_DATA) X509 CRT ASN1 (inv extBasicConstraint, pathlen is INT_MAX) depends_on:PSA_HAVE_ALG_SOME_RSA_VERIFY:PSA_WANT_ALG_SHA_256:PSA_WANT_ALG_SHA_1 @@ -2074,19 +2074,19 @@ mbedtls_x509_crt_parse_file:"../framework/data_files/parse_input/server1_pathlen X509 CRT ASN1 (TBS, inv extBasicConstraint, pathlen inv length encoding) depends_on:PSA_HAVE_ALG_SOME_RSA_VERIFY:PSA_WANT_ALG_SHA_256 -x509parse_crt:"3081b130819ba0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D01010105000319003016021100ffffffffffffffffffffffffffffffff020103a100a200a315301330110603551d13010101040730050201010285300d06092a864886f70d01010b0500030200ff":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_INVALID_LENGTH) +x509parse_crt:"3081b130819ba0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D01010105000319003016021100ffffffffffffffffffffffffffffffff020103a100a200a315301330110603551d13010101040730050101ff0285300d06092a864886f70d01010b0500030200ff":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_INVALID_LENGTH) X509 CRT ASN1 (TBS, inv extBasicConstraint, pathlen length out of bounds) depends_on:PSA_HAVE_ALG_SOME_RSA_VERIFY:PSA_WANT_ALG_SHA_256 -x509parse_crt:"3081b130819ba0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D01010105000319003016021100ffffffffffffffffffffffffffffffff020103a100a200a315301330110603551d13010101040730050201010201300d06092a864886f70d01010b0500030200ff":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_OUT_OF_DATA) +x509parse_crt:"3081b130819ba0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D01010105000319003016021100ffffffffffffffffffffffffffffffff020103a100a200a315301330110603551d13010101040730050101ff0201300d06092a864886f70d01010b0500030200ff":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_OUT_OF_DATA) X509 CRT ASN1 (TBS, inv extBasicConstraint, pathlen empty) depends_on:PSA_HAVE_ALG_SOME_RSA_VERIFY:PSA_WANT_ALG_SHA_256 -x509parse_crt:"3081b130819ba0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D01010105000319003016021100ffffffffffffffffffffffffffffffff020103a100a200a315301330110603551d13010101040730050201010200300d06092a864886f70d01010b0500030200ff":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_INVALID_LENGTH) +x509parse_crt:"3081b130819ba0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D01010105000319003016021100ffffffffffffffffffffffffffffffff020103a100a200a315301330110603551d13010101040730050101ff0200300d06092a864886f70d01010b0500030200ff":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_INVALID_LENGTH) X509 CRT ASN1 (TBS, inv extBasicConstraint, pathlen length mismatch) depends_on:PSA_HAVE_ALG_SOME_RSA_VERIFY:PSA_WANT_ALG_SHA_256 -x509parse_crt:"3081b430819ea0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D01010105000319003016021100ffffffffffffffffffffffffffffffff020103a100a200a318301630140603551d13010101040a30080201010201010500300d06092a864886f70d01010b0500030200ff":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_LENGTH_MISMATCH) +x509parse_crt:"3081b430819ea0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D01010105000319003016021100ffffffffffffffffffffffffffffffff020103a100a200a318301630140603551d13010101040a30080101ff0201010500300d06092a864886f70d01010b0500030200ff":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_LENGTH_MISMATCH) X509 CRT ASN1 (TBS, inv v3Ext, ExtKeyUsage bad second tag) depends_on:PSA_HAVE_ALG_SOME_RSA_VERIFY:PSA_WANT_ALG_SHA_256 From 4ac13cc65f6f8a0f7eaada4b27a2d835648a07da Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 12 May 2026 17:06:18 +0200 Subject: [PATCH 023/173] Stop accepting basicConstraints with only pathLenConstraint In an X.509 certificate, a basicConstraints extension where the cA field (BOOLEAN) is omitted but the pathLenConstraint field (INTEGER )is present is syntactically valid, but RFC 5280 states that CAs MUST NOT emit such a certificate. Historically, since XySSL 0.9 in 2008, if a basicConstraints extension started with an INTEGER field, we interpreted that field as a cA value. This was a deliberate change: > Fixed x509_get_ext() to accept some rare certificates (like > www.openssl.org:443) which have an INTEGER instead of a BOOLEAN for > Extension::BasicConstraints::cA. However, 18 years later, this does not seem to be relevant, and the details seem to have been lost. Furthermore, major implementations follow RFC 5280 and interpret `SEQUENCE { INTEGER n }` with cA being set to its default value (FALSE) and pathLenConstraint set to `n`. This means that such a certificate with n != 0 would be interpreted as a CA certificate in Mbed TLS but as a leaf certificate elsewhere, which is dangerous. Since CAs are not supposed to emit such certificates, stop accepting them altogether. Signed-off-by: Gilles Peskine --- library/x509_crt.c | 26 +++++++++++++++----------- tests/suites/test_suite_x509parse.data | 8 ++++++++ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 637ce7f336..093d733c1c 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -512,6 +512,7 @@ static int x509_get_basic_constraints(unsigned char **p, } if (*p == end) { + /* Empty basicConstraints: valid, not a CA. */ return 0; } @@ -523,18 +524,21 @@ static int x509_get_basic_constraints(unsigned char **p, } if ((ret = mbedtls_asn1_get_bool(p, end, ca_istrue)) != 0) { - if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { - ret = mbedtls_asn1_get_int(p, end, ca_istrue); - } - - if (ret != 0) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); - } - - if (*ca_istrue != 0) { - *ca_istrue = 1; - } + /* If the SEQUENCE starts with an INTEGER and not a BOOLEAN, + * according to RFC 5280, it's syntactically valid, but it's + * something that a CA MUST NOT produce. So we reject it. + * + * Note: historically, from XySSL 0.9 to Mbed TLS 3.6.6/4.1.0, + * `SEQUENCE { INTEGER n }` was interpreted as cA=FALSE if n == 0 + * and cA=TRUE if n != 0. This was dangerous since + * `SEQUENCE { INTEGER n }` should be parsed as cA=FALSE + * according to RFC 5280, so we stopped doing it. + */ + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); } + /* `SEQUENCE { BOOLEAN FALSE }` is not DER since default-value fields + * must be omitted in DER. But it seems harmless, and Mbed TLS has + * always accepted it, so we continue to accept it. */ if (*p == end) { return 0; diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index ff4ecaedc1..a2e3e9c67e 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -2060,6 +2060,14 @@ X509 CRT ASN1: basicConstraints overflow would make CA=1 (good self signature) depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 mbedtls_x509_crt_parse_file:"../framework/data_files/parse_input/server5.basic-constraints-sequence-overflow.selfsigned.crt":MBEDTLS_ERR_X509_INVALID_EXTENSIONS:0 +X509 CRT ASN1: basicConstraints: no cA but pathLenConstraint (bad signature) +depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 +mbedtls_x509_crt_parse_file:"../framework/data_files/parse_input/server5.basic-constraints-integer-first.badsign.crt":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG):0 + +X509 CRT ASN1: basicConstraints: no cA but pathLenConstraint (good self signature) +depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 +mbedtls_x509_crt_parse_file:"../framework/data_files/parse_input/server5.basic-constraints-integer-first.selfsigned.crt":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG):0 + X509 CRT ASN1 (TBS, inv extBasicConstraint, no pathlen length) depends_on:PSA_HAVE_ALG_SOME_RSA_VERIFY:PSA_WANT_ALG_SHA_256 x509parse_crt:"3081b030819aa0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D01010105000319003016021100ffffffffffffffffffffffffffffffff020103a100a200a314301230100603551d13010101040630040101ff02300d06092a864886f70d01010b0500030200ff":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_OUT_OF_DATA) From 0c8913d90646b313428a95d9b60bbd8b981124c5 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 12 May 2026 17:21:48 +0200 Subject: [PATCH 024/173] basicConstraints with leading INTEGER field: document the behavior change Announce the security fix together with the overflow fix, since the two bugs are pretty much indistinguishable from a black-box perspective, despite being due to independent problems in the code. Signed-off-by: Gilles Peskine --- ChangeLog.d/x509-crt-parse-basicConstraints.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ChangeLog.d/x509-crt-parse-basicConstraints.txt b/ChangeLog.d/x509-crt-parse-basicConstraints.txt index c5b25f114b..4fd450e18e 100644 --- a/ChangeLog.d/x509-crt-parse-basicConstraints.txt +++ b/ChangeLog.d/x509-crt-parse-basicConstraints.txt @@ -1,7 +1,15 @@ Security - * Fix a bug in the X.509 certificate parser that caused some inputs + * Fix two bugs in the X.509 certificate parser that caused some inputs with a malformed basicConstraints extension to be accepted. This could have dangerous results, in particular causing some certificates to be parsed as CA certificates when other X.509 implementations would parse them as end-entity certificates. Reported by Mohammad Seet (mhdsait101). CVE-2026-TODO + +Changes + * X.509 certificates with a basicConstraints extension starting with an + INTEGER field are no longer accepted. According to RFC 5280, such + certificates are syntactically valid and the first field is the + pathLenConstraint value, but certificate authorities must not emit such + certificates. Mbed TLS interpreted it as a cA value, which was nonstandard + and dangerous. From 4e5d35087190835ed53f26fd8bb6d5ad105d5676 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 27 May 2026 12:29:51 +0200 Subject: [PATCH 025/173] Switch to MBEDTLS_ERROR_ADD for combining X509 and ASN1 error codes Since Mbed TLS 4.0, this is just the low-level error code. But keep the combination for uniformity with the rest of the file, and to reduce the differences with the 3.6 branch. Signed-off-by: Gilles Peskine --- tests/suites/test_suite_x509parse.data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index a2e3e9c67e..d0314753bf 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -2965,7 +2965,7 @@ mbedtls_x509_csr_parse:"308201183081bf0201003034310b3009060355040613024e4c311130 X509 CSR ASN.1 (extensionRequest SET length too short) depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1 -mbedtls_x509_csr_parse:"308201183081bf0201003034310b3009060355040613024e4c3111300f060355040a1308506f6c617253534c31123010060355040313096c6f63616c686f73743059301306072a8648ce3d020106082a8648ce3d0301070342000437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edffa029302706092a864886f70d01090e3119301830090603551d1304023000300b0603551d0f0404030205e0300906072a8648ce3d04010349003046022100b49fd8c8f77abfa871908dfbe684a08a793d0f490a43d86fcf2086e4f24bb0c2022100f829d5ccd3742369299e6294394717c4b723a0f68b44e831b6e6c3bcabf97243":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS+MBEDTLS_ERR_ASN1_LENGTH_MISMATCH +mbedtls_x509_csr_parse:"308201183081bf0201003034310b3009060355040613024e4c3111300f060355040a1308506f6c617253534c31123010060355040313096c6f63616c686f73743059301306072a8648ce3d020106082a8648ce3d0301070342000437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edffa029302706092a864886f70d01090e3119301830090603551d1304023000300b0603551d0f0404030205e0300906072a8648ce3d04010349003046022100b49fd8c8f77abfa871908dfbe684a08a793d0f490a43d86fcf2086e4f24bb0c2022100f829d5ccd3742369299e6294394717c4b723a0f68b44e831b6e6c3bcabf97243":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_LENGTH_MISMATCH) X509 CSR ASN.1 (Unsupported critical extension, critical=true) depends_on:PSA_HAVE_ALG_SOME_ECDSA:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256:!MBEDTLS_X509_REMOVE_INFO From 5427ccf7237396a112a5ba408e2696d7c744743e Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 27 May 2026 15:44:01 +0200 Subject: [PATCH 026/173] Update dependencies in forward port from 3.6 Signed-off-by: Gilles Peskine --- tests/suites/test_suite_x509parse.data | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index d0314753bf..63f4c0daa9 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -2053,19 +2053,19 @@ depends_on:PSA_HAVE_ALG_SOME_RSA_VERIFY:PSA_WANT_ALG_SHA_256 x509parse_crt:"3081b030819aa0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092a864886f70d01010105000319003016021100ffffffffffffffffffffffffffffffff020103a100a200a314301230100603551d200409300730050601003001300d06092a864886f70d01010b0500030200ff":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_OUT_OF_DATA) X509 CRT ASN1: basicConstraints overflow would make CA=1 (bad signature) -depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 +depends_on:PSA_HAVE_ALG_ECDSA_VERIFY:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256 mbedtls_x509_crt_parse_file:"../framework/data_files/parse_input/server5.basic-constraints-sequence-overflow.badsign.crt":MBEDTLS_ERR_X509_INVALID_EXTENSIONS:0 X509 CRT ASN1: basicConstraints overflow would make CA=1 (good self signature) -depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 +depends_on:PSA_HAVE_ALG_ECDSA_VERIFY:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256 mbedtls_x509_crt_parse_file:"../framework/data_files/parse_input/server5.basic-constraints-sequence-overflow.selfsigned.crt":MBEDTLS_ERR_X509_INVALID_EXTENSIONS:0 X509 CRT ASN1: basicConstraints: no cA but pathLenConstraint (bad signature) -depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 +depends_on:PSA_HAVE_ALG_ECDSA_VERIFY:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256 mbedtls_x509_crt_parse_file:"../framework/data_files/parse_input/server5.basic-constraints-integer-first.badsign.crt":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG):0 X509 CRT ASN1: basicConstraints: no cA but pathLenConstraint (good self signature) -depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 +depends_on:PSA_HAVE_ALG_ECDSA_VERIFY:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256 mbedtls_x509_crt_parse_file:"../framework/data_files/parse_input/server5.basic-constraints-integer-first.selfsigned.crt":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG):0 X509 CRT ASN1 (TBS, inv extBasicConstraint, no pathlen length) @@ -2964,7 +2964,7 @@ depends_on:PSA_HAVE_ALG_SOME_ECDSA:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_1:! mbedtls_x509_csr_parse:"308201183081bf0201003034310b3009060355040613024e4c3111300f060355040a1308506f6c617253534c31123010060355040313096c6f63616c686f73743059301306072a8648ce3d020106082a8648ce3d0301070342000437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edffa029302706092a864886f70d01090e311a301830090603551d1304023000300b0603551d0f0404030205e0300906072a8648ce3d04010349003046022100b49fd8c8f77abfa871908dfbe684a08a793d0f490a43d86fcf2086e4f24bb0c2022100f829d5ccd3742369299e6294394717c4b723a0f68b44e831b6e6c3bcabf97243":"CSR version \: 1\nsubject name \: C=NL, O=PolarSSL, CN=localhost\nsigned using \: ECDSA with SHA1\nEC key size \: 256 bits\n\nkey usage \: Digital Signature, Non Repudiation, Key Encipherment\n":0 X509 CSR ASN.1 (extensionRequest SET length too short) -depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1 +depends_on:PSA_HAVE_ALG_ECDSA_VERIFY:PSA_WANT_ECC_SECP_R1_256 mbedtls_x509_csr_parse:"308201183081bf0201003034310b3009060355040613024e4c3111300f060355040a1308506f6c617253534c31123010060355040313096c6f63616c686f73743059301306072a8648ce3d020106082a8648ce3d0301070342000437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edffa029302706092a864886f70d01090e3119301830090603551d1304023000300b0603551d0f0404030205e0300906072a8648ce3d04010349003046022100b49fd8c8f77abfa871908dfbe684a08a793d0f490a43d86fcf2086e4f24bb0c2022100f829d5ccd3742369299e6294394717c4b723a0f68b44e831b6e6c3bcabf97243":"":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_LENGTH_MISMATCH) X509 CSR ASN.1 (Unsupported critical extension, critical=true) From 3345a593856c76c04947e83b819b1fdaeb1a12f3 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 3 Jun 2026 18:23:42 +0200 Subject: [PATCH 027/173] Add attribution for the second bug Signed-off-by: Gilles Peskine --- ChangeLog.d/x509-crt-parse-basicConstraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.d/x509-crt-parse-basicConstraints.txt b/ChangeLog.d/x509-crt-parse-basicConstraints.txt index 4fd450e18e..30ee25a785 100644 --- a/ChangeLog.d/x509-crt-parse-basicConstraints.txt +++ b/ChangeLog.d/x509-crt-parse-basicConstraints.txt @@ -4,7 +4,7 @@ Security could have dangerous results, in particular causing some certificates to be parsed as CA certificates when other X.509 implementations would parse them as end-entity certificates. Reported by Mohammad Seet - (mhdsait101). CVE-2026-TODO + (mhdsait101) and Pablo Ruiz García. CVE-2026-TODO Changes * X.509 certificates with a basicConstraints extension starting with an From 6181a54b5781768614577de84abf7e24a660e6ed Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 3 Jun 2026 18:24:04 +0200 Subject: [PATCH 028/173] Add CVE-ID Signed-off-by: Gilles Peskine --- ChangeLog.d/x509-crt-parse-basicConstraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.d/x509-crt-parse-basicConstraints.txt b/ChangeLog.d/x509-crt-parse-basicConstraints.txt index 30ee25a785..a67f992ab5 100644 --- a/ChangeLog.d/x509-crt-parse-basicConstraints.txt +++ b/ChangeLog.d/x509-crt-parse-basicConstraints.txt @@ -4,7 +4,7 @@ Security could have dangerous results, in particular causing some certificates to be parsed as CA certificates when other X.509 implementations would parse them as end-entity certificates. Reported by Mohammad Seet - (mhdsait101) and Pablo Ruiz García. CVE-2026-TODO + (mhdsait101) and Pablo Ruiz García. CVE-2026-49300 Changes * X.509 certificates with a basicConstraints extension starting with an From f63ca6e0af1d37ae048e00e692f21d302d0acd25 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Fri, 1 May 2026 10:23:02 +0100 Subject: [PATCH 029/173] Added fix for Integer overflow using a large ECDHE Identity Signed-off-by: Ben Taylor (cherry picked from commit baf449db7e31f031ed5def0fecf417122f72d3ee) --- library/ssl_tls12_client.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/library/ssl_tls12_client.c b/library/ssl_tls12_client.c index a0170d51f6..9f86491fd6 100644 --- a/library/ssl_tls12_client.c +++ b/library/ssl_tls12_client.c @@ -2424,11 +2424,16 @@ static int ssl_write_client_key_exchange(mbedtls_ssl_context *ssl) /* uint16 to store content length */ const size_t content_len_size = 2; + const size_t ecpoint_len_size = 1; + const size_t ecpoint_max_len = + PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(handshake->xxdh_psa_type, + handshake->xxdh_psa_bits); header_len = 4; - if (header_len + content_len_size + ssl->conf->psk_identity_len - > MBEDTLS_SSL_OUT_CONTENT_LEN) { + if (ecpoint_max_len > MBEDTLS_SSL_OUT_CONTENT_LEN - ecpoint_len_size || + header_len + content_len_size + ssl->conf->psk_identity_len + > MBEDTLS_SSL_OUT_CONTENT_LEN - ecpoint_len_size - ecpoint_max_len) { MBEDTLS_SSL_DEBUG_MSG(1, ("psk identity too long or SSL buffer too short")); return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL; From 4afd1c1685f0a83eedce4c1b4ebf8836f349a1c9 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Wed, 3 Jun 2026 09:44:12 +0100 Subject: [PATCH 030/173] Add in tests for ECDHE-PSK integer overflow Signed-off-by: Ben Taylor (cherry picked from commit c567299ee6bade9547a97d3ad1dcd5f3bd98ea6f) --- tests/ssl-opt.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 47ff800ed1..0499b9b89c 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -8382,6 +8382,37 @@ run_test "extKeyUsage cli-auth 1.3: codeSign -> fail (hard)" \ -s "Processing of the Certificate handshake message failed" # MBEDTLS_X509_BADCERT_EXT_KEY_USAGE -> MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT +# Miscellaneous PSK-related tests + +psk_identity_max_minus_10=a$(printf "%$((MAX_OUT_LEN - 11))s" z | tr ' ' .) + +run_test "Large PSK identity (MBEDTLS_SSL_OUT_CONTENT_LEN - 7)" \ + "$P_SRV debug_level=3 \ + psk_identity=${psk_identity_max_minus_10}987 psk=73776f726466697368" \ + "$P_CLI force_ciphersuite=TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA256 debug_level=3 \ + psk_identity=${psk_identity_max_minus_10}987 psk=73776f726466697368" \ + 1 \ + -s "! mbedtls_ssl_handshake returned" \ + -c "! mbedtls_ssl_handshake returned" + +run_test "Large PSK identity (MBEDTLS_SSL_OUT_CONTENT_LEN - 6)" \ + "$P_SRV debug_level=3 \ + psk_identity=${psk_identity_max_minus_10}9876 psk=73776f726466697368" \ + "$P_CLI force_ciphersuite=TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA256 debug_level=3 \ + psk_identity=${psk_identity_max_minus_10}9876 psk=73776f726466697368" \ + 1 \ + -s "! mbedtls_ssl_handshake returned" \ + -c "! mbedtls_ssl_handshake returned" + +run_test "Large PSK identity (MBEDTLS_SSL_OUT_CONTENT_LEN - 5)" \ + "$P_SRV debug_level=3 \ + psk_identity=${psk_identity_max_minus_10}98765 psk=73776f726466697368" \ + "$P_CLI force_ciphersuite=TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA256 debug_level=3 \ + psk_identity=${psk_identity_max_minus_10}98765 psk=73776f726466697368" \ + 1 \ + -s "! mbedtls_ssl_handshake returned" \ + -c "! mbedtls_ssl_handshake returned" + # Tests for PSK callback run_test "PSK callback: psk, no callback" \ From 93b10471aa534cf8b7b2b3601e85f26c5f1daaa2 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Fri, 1 May 2026 10:26:49 +0100 Subject: [PATCH 031/173] Add ChangeLog Signed-off-by: Ben Taylor (cherry picked from commit e71e49e634ba49b2b630f268bc8f0dd392751ec3) --- ChangeLog.d/ecdh-psk-integer-overflow.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 ChangeLog.d/ecdh-psk-integer-overflow.txt diff --git a/ChangeLog.d/ecdh-psk-integer-overflow.txt b/ChangeLog.d/ecdh-psk-integer-overflow.txt new file mode 100644 index 0000000000..0c84914a45 --- /dev/null +++ b/ChangeLog.d/ecdh-psk-integer-overflow.txt @@ -0,0 +1,2 @@ +Bugfix + * Add fix for ecdh-psk integer overflow with large identity. From 2705873c5a112a89c5fa6b481c057fa1875b9001 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Wed, 3 Jun 2026 08:26:17 +0100 Subject: [PATCH 032/173] Improve ChangeLog Signed-off-by: Ben Taylor (cherry picked from commit c058818451833a748da112e3b8129fd299480ceb) --- ChangeLog.d/ecdh-psk-integer-overflow.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog.d/ecdh-psk-integer-overflow.txt b/ChangeLog.d/ecdh-psk-integer-overflow.txt index 0c84914a45..c1b7f6affa 100644 --- a/ChangeLog.d/ecdh-psk-integer-overflow.txt +++ b/ChangeLog.d/ecdh-psk-integer-overflow.txt @@ -1,2 +1,2 @@ -Bugfix - * Add fix for ecdh-psk integer overflow with large identity. +Security + * Fix a remote buffer overflow in (D)TLS with ECDHE-PSK cipher suites when CBC is disabled. From afdbd67f21e99d9dd863923977374af71a65e1ba Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Wed, 3 Jun 2026 10:38:21 +0100 Subject: [PATCH 033/173] Correct style of ChangeLog Signed-off-by: Ben Taylor (cherry picked from commit 0501e447cc19ed06b69daea5e17585e1294030cd) --- ChangeLog.d/ecdh-psk-integer-overflow.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog.d/ecdh-psk-integer-overflow.txt b/ChangeLog.d/ecdh-psk-integer-overflow.txt index c1b7f6affa..7d4b452275 100644 --- a/ChangeLog.d/ecdh-psk-integer-overflow.txt +++ b/ChangeLog.d/ecdh-psk-integer-overflow.txt @@ -1,2 +1,3 @@ Security - * Fix a remote buffer overflow in (D)TLS with ECDHE-PSK cipher suites when CBC is disabled. + * Fix a remote buffer overflow in (D)TLS with ECDHE-PSK cipher suites when + CBC is disabled. From 1e061ee95a99155ca9e01e26ec83b31abfe1b2dd Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 4 Jun 2026 14:20:18 +0100 Subject: [PATCH 034/173] Add reported by and CVE placeholder Signed-off-by: Ben Taylor (cherry picked from commit ab2a7d5a3472f39190344f754e6cee5039fcba50) --- ChangeLog.d/ecdh-psk-integer-overflow.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.d/ecdh-psk-integer-overflow.txt b/ChangeLog.d/ecdh-psk-integer-overflow.txt index 7d4b452275..8693dde60e 100644 --- a/ChangeLog.d/ecdh-psk-integer-overflow.txt +++ b/ChangeLog.d/ecdh-psk-integer-overflow.txt @@ -1,3 +1,3 @@ Security * Fix a remote buffer overflow in (D)TLS with ECDHE-PSK cipher suites when - CBC is disabled. + CBC is disabled. Reported by Karnakar Reddy. CVE-ID-TODO From 75cfc5c0b9cbd6b820fd45642d9c37aaf6beb7a5 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 7 May 2026 17:23:55 +0100 Subject: [PATCH 035/173] 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 56e314728bd5c3fcb41a646972c2159403d733ac Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 7 May 2026 17:24:50 +0100 Subject: [PATCH 036/173] 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 dd5a8501c0e58acfff9ec551cb1b15b69a24591f Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 1 Jun 2026 14:56:20 +0100 Subject: [PATCH 037/173] 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 5fa28bb6cd948ec0a96ed5fc68c62a59c2ec3229 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 8 Jun 2026 15:32:26 +0100 Subject: [PATCH 038/173] 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 e9332e8ebe2cea7908a0508a281b47fed485e8cc Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 8 Jun 2026 15:46:00 +0100 Subject: [PATCH 039/173] 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 f2a1306c867f6c3be7d7e04af39772afbd46b57a Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Wed, 10 Jun 2026 08:38:36 +0100 Subject: [PATCH 040/173] 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: From cf37056714e34d3909895a9cc182ce6cfa1a70b2 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Fri, 5 Jun 2026 10:22:49 +0100 Subject: [PATCH 041/173] Add improvements to ChangeLog Signed-off-by: Ben Taylor From 4cb3470f913baf5e5b6cb21554823f1ce5ae702a Mon Sep 17 00:00:00 2001 From: Ben Taylor <32939606+bjwtaylor@users.noreply.github.com> Date: Mon, 8 Jun 2026 15:13:02 +0100 Subject: [PATCH 042/173] Improve the wording of the ChangeLog Co-authored-by: Ronald Cron Signed-off-by: Ben Taylor <32939606+bjwtaylor@users.noreply.github.com> --- ChangeLog.d/oob-key-exchange-restricted.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.d/oob-key-exchange-restricted.txt b/ChangeLog.d/oob-key-exchange-restricted.txt index a0e698c077..a4bfe738b2 100644 --- a/ChangeLog.d/oob-key-exchange-restricted.txt +++ b/ChangeLog.d/oob-key-exchange-restricted.txt @@ -1,3 +1,3 @@ Security - * Fix an out-of-bounds read in TLS 1.2 ECJPAKE ServerKeyExchange parsing. + * Fix an out-of-bounds read when parsing TLS 1.2 ECJPAKE ServerKeyExchange messages. Reported-by Biniam Demissie From ff8de9cec9bed96b4e2cab24831a731f28892425 Mon Sep 17 00:00:00 2001 From: Ben Taylor <32939606+bjwtaylor@users.noreply.github.com> Date: Mon, 8 Jun 2026 15:13:37 +0100 Subject: [PATCH 043/173] Add CVE to ChangeLog Co-authored-by: Ronald Cron Signed-off-by: Ben Taylor <32939606+bjwtaylor@users.noreply.github.com> --- ChangeLog.d/oob-key-exchange-restricted.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog.d/oob-key-exchange-restricted.txt b/ChangeLog.d/oob-key-exchange-restricted.txt index a4bfe738b2..62e613648b 100644 --- a/ChangeLog.d/oob-key-exchange-restricted.txt +++ b/ChangeLog.d/oob-key-exchange-restricted.txt @@ -1,3 +1,4 @@ Security * Fix an out-of-bounds read when parsing TLS 1.2 ECJPAKE ServerKeyExchange messages. - Reported-by Biniam Demissie + Reported-by Biniam Demissie. + CVE-2026-50588 From f5cb455b5c5665aa121878f5848ad97ee36dbc09 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Wed, 10 Jun 2026 08:21:05 +0100 Subject: [PATCH 044/173] Correct ChangeLog style Signed-off-by: Ben Taylor --- ChangeLog.d/oob-key-exchange-restricted.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog.d/oob-key-exchange-restricted.txt b/ChangeLog.d/oob-key-exchange-restricted.txt index 62e613648b..6a250644b9 100644 --- a/ChangeLog.d/oob-key-exchange-restricted.txt +++ b/ChangeLog.d/oob-key-exchange-restricted.txt @@ -1,4 +1,4 @@ Security - * Fix an out-of-bounds read when parsing TLS 1.2 ECJPAKE ServerKeyExchange messages. - Reported-by Biniam Demissie. + * Fix an out-of-bounds read when parsing TLS 1.2 ECJPAKE ServerKeyExchange + messages. Reported-by Biniam Demissie. CVE-2026-50588 From 1a5e328377af66a1795ebf9440e79592bffa2a71 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Wed, 10 Jun 2026 14:15:48 +0100 Subject: [PATCH 045/173] Fix style issue Signed-off-by: Ben Taylor --- ChangeLog.d/oob-key-exchange-restricted.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.d/oob-key-exchange-restricted.txt b/ChangeLog.d/oob-key-exchange-restricted.txt index 6a250644b9..2e48ce0fec 100644 --- a/ChangeLog.d/oob-key-exchange-restricted.txt +++ b/ChangeLog.d/oob-key-exchange-restricted.txt @@ -1,4 +1,4 @@ Security - * Fix an out-of-bounds read when parsing TLS 1.2 ECJPAKE ServerKeyExchange + * Fix an out-of-bounds read when parsing TLS 1.2 ECJPAKE ServerKeyExchange messages. Reported-by Biniam Demissie. CVE-2026-50588 From a98b95074ad1d2a73e91278a380a424f3f4df4c6 Mon Sep 17 00:00:00 2001 From: Ben Taylor <32939606+bjwtaylor@users.noreply.github.com> Date: Mon, 15 Jun 2026 09:20:59 +0100 Subject: [PATCH 046/173] Update ChangeLog to include CVE number Co-authored-by: Gilles Peskine Signed-off-by: Ben Taylor <32939606+bjwtaylor@users.noreply.github.com> --- ChangeLog.d/ecdh-psk-integer-overflow.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.d/ecdh-psk-integer-overflow.txt b/ChangeLog.d/ecdh-psk-integer-overflow.txt index 8693dde60e..3ed448ee16 100644 --- a/ChangeLog.d/ecdh-psk-integer-overflow.txt +++ b/ChangeLog.d/ecdh-psk-integer-overflow.txt @@ -1,3 +1,3 @@ Security * Fix a remote buffer overflow in (D)TLS with ECDHE-PSK cipher suites when - CBC is disabled. Reported by Karnakar Reddy. CVE-ID-TODO + CBC is disabled. Reported by Karnakar Reddy. CVE-ID-50580 From 91d7da23a811ca9739763f623dc694d441b7e763 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Tue, 21 Apr 2026 09:26:07 +0200 Subject: [PATCH 047/173] Remove unnecessary dependency Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.function | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 39317cf3f9..8d8da35c09 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -2870,7 +2870,7 @@ exit: } /* END_CASE */ -/* BEGIN_CASE depends_on:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:PSA_HAVE_ALG_SOME_RSA_SIGN:PSA_WANT_ECC_SECP_R1_384:!MBEDTLS_SSL_PROTO_TLS1_3:PSA_WANT_ALG_SHA_256 */ +/* BEGIN_CASE depends_on:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:PSA_HAVE_ALG_SOME_RSA_SIGN:PSA_WANT_ECC_SECP_R1_384:PSA_WANT_ALG_SHA_256 */ void mbedtls_endpoint_sanity(int endpoint_type) { enum { BUFFSIZE = 1024 }; @@ -3106,7 +3106,7 @@ void app_data_tls(int mfl, int cli_msg_len, int srv_msg_len, } /* END_CASE */ -/* BEGIN_CASE depends_on:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:!MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_PROTO_TLS1_2:PSA_HAVE_ALG_SOME_RSA_SIGN:PSA_WANT_ECC_SECP_R1_384:MBEDTLS_SSL_PROTO_DTLS:PSA_WANT_ALG_SHA_256:MBEDTLS_CAN_HANDLE_RSA_TEST_KEY */ +/* BEGIN_CASE depends_on:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:MBEDTLS_SSL_PROTO_TLS1_2:PSA_HAVE_ALG_SOME_RSA_SIGN:PSA_WANT_ECC_SECP_R1_384:MBEDTLS_SSL_PROTO_DTLS:PSA_WANT_ALG_SHA_256:MBEDTLS_CAN_HANDLE_RSA_TEST_KEY */ void app_data_dtls(int mfl, int cli_msg_len, int srv_msg_len, int expected_cli_fragments, int expected_srv_fragments) @@ -3135,7 +3135,7 @@ exit: } /* END_CASE */ -/* BEGIN_CASE depends_on:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:!MBEDTLS_SSL_PROTO_TLS1_3:PSA_HAVE_ALG_SOME_RSA_SIGN:PSA_WANT_KEY_TYPE_AES:PSA_WANT_ECC_SECP_R1_384:MBEDTLS_DEBUG_C:MBEDTLS_SSL_MAX_FRAGMENT_LENGTH:PSA_WANT_ALG_CBC_NO_PADDING:PSA_WANT_ALG_SHA_384:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED */ +/* BEGIN_CASE depends_on:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:PSA_HAVE_ALG_SOME_RSA_SIGN:PSA_WANT_KEY_TYPE_AES:PSA_WANT_ECC_SECP_R1_384:MBEDTLS_DEBUG_C:MBEDTLS_SSL_MAX_FRAGMENT_LENGTH:PSA_WANT_ALG_CBC_NO_PADDING:PSA_WANT_ALG_SHA_384:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED */ void handshake_fragmentation(int mfl, int expected_srv_hs_fragmentation, int expected_cli_hs_fragmentation) @@ -3332,7 +3332,7 @@ exit: } /* END_CASE */ -/* BEGIN_CASE depends_on:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:!MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_PROTO_TLS1_2:PSA_HAVE_ALG_SOME_RSA_SIGN:PSA_WANT_ECC_SECP_R1_384:MBEDTLS_SSL_PROTO_DTLS:MBEDTLS_SSL_RENEGOTIATION:PSA_WANT_ALG_SHA_256:MBEDTLS_CAN_HANDLE_RSA_TEST_KEY */ +/* BEGIN_CASE depends_on:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:MBEDTLS_SSL_PROTO_TLS1_2:PSA_HAVE_ALG_SOME_RSA_SIGN:PSA_WANT_ECC_SECP_R1_384:MBEDTLS_SSL_PROTO_DTLS:MBEDTLS_SSL_RENEGOTIATION:PSA_WANT_ALG_SHA_256:MBEDTLS_CAN_HANDLE_RSA_TEST_KEY */ void renegotiation(int legacy_renegotiation) { mbedtls_test_handshake_test_options options; From 9fe8059464f42b3b0eb20f2161b0d8f09d366956 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 5 Jun 2026 15:40:03 +0200 Subject: [PATCH 048/173] Add a missing dependency Needed by a test certificate. Signed-off-by: Gilles Peskine --- 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 8d8da35c09..97a70f997a 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -3135,7 +3135,7 @@ exit: } /* END_CASE */ -/* BEGIN_CASE depends_on:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:PSA_HAVE_ALG_SOME_RSA_SIGN:PSA_WANT_KEY_TYPE_AES:PSA_WANT_ECC_SECP_R1_384:MBEDTLS_DEBUG_C:MBEDTLS_SSL_MAX_FRAGMENT_LENGTH:PSA_WANT_ALG_CBC_NO_PADDING:PSA_WANT_ALG_SHA_384:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED */ +/* BEGIN_CASE depends_on:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:PSA_HAVE_ALG_SOME_RSA_SIGN:PSA_WANT_KEY_TYPE_AES:PSA_WANT_ECC_SECP_R1_384:MBEDTLS_DEBUG_C:MBEDTLS_SSL_MAX_FRAGMENT_LENGTH:PSA_WANT_ALG_CBC_NO_PADDING:PSA_WANT_ALG_SHA_256:PSA_WANT_ALG_SHA_384:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED */ void handshake_fragmentation(int mfl, int expected_srv_hs_fragmentation, int expected_cli_hs_fragmentation) From 025422b2e96f02e07ec4c2bf6846cea3eef26d44 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 3 Jun 2026 15:43:18 +0200 Subject: [PATCH 049/173] Add some hooks in mbedtls_test_ssl_perform_handshake() Let test code customize the kitchen sink function `mbedtls_test_ssl_perform_handshake()` at a few points. Signed-off-by: Gilles Peskine --- tests/include/test/ssl_helpers.h | 32 ++++++++++++++++++++++++++++ tests/src/test_helpers/ssl_helpers.c | 17 +++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/tests/include/test/ssl_helpers.h b/tests/include/test/ssl_helpers.h index a653c9643e..467a27f342 100644 --- a/tests/include/test/ssl_helpers.h +++ b/tests/include/test/ssl_helpers.h @@ -117,6 +117,9 @@ enum { #define MBEDTLS_TEST_MAX_ALPN_LIST_SIZE 10 #endif +/* Forward declaration. Defined below. */ +struct mbedtls_test_ssl_endpoint; + typedef struct mbedtls_test_ssl_log_pattern { const char *pattern; size_t counter; @@ -147,6 +150,35 @@ typedef struct mbedtls_test_handshake_test_options { int expected_srv_fragments; int renegotiate; int legacy_renegotiation; + /** Hook that mbedtls_test_ssl_perform_handshake() runs just before + * the initial handshake. */ + void (*pre_handshake_fun)(struct mbedtls_test_ssl_endpoint *client, + struct mbedtls_test_ssl_endpoint *server, + void *param); + /** Value passed to ::pre_handshake_fun. */ + void *pre_handshake_param; + /** Hook that mbedtls_test_ssl_perform_handshake() runs after + * the initial handshake succeeds. */ + void (*post_handshake_fun)(struct mbedtls_test_ssl_endpoint *client, + struct mbedtls_test_ssl_endpoint *server, + void *param); + /** Value passed to ::post_handshake_fun. */ + void *post_handshake_param; + /** Hook that mbedtls_test_ssl_perform_handshake() runs after + * exchanging some data, before testing additional features such as + * serialization and renegotiation. */ + void (*post_data_fun)(struct mbedtls_test_ssl_endpoint *client, + struct mbedtls_test_ssl_endpoint *server, + void *param); + /** Value passed to ::post_data_fun. */ + void *post_data_param; + /** Hook that mbedtls_test_ssl_perform_handshake() runs after a successful + * connection, just before closing down. */ + void (*pre_shutdown_fun)(struct mbedtls_test_ssl_endpoint *client, + struct mbedtls_test_ssl_endpoint *server, + void *param); + /** Value passed to ::pre_shutdown_fun. */ + void *pre_shutdown_param; void *srv_log_obj; void *cli_log_obj; void (*srv_log_fun)(void *, int, const char *, int, const char *); diff --git a/tests/src/test_helpers/ssl_helpers.c b/tests/src/test_helpers/ssl_helpers.c index db29413de6..08cfe252af 100644 --- a/tests/src/test_helpers/ssl_helpers.c +++ b/tests/src/test_helpers/ssl_helpers.c @@ -2282,6 +2282,10 @@ int mbedtls_test_ssl_perform_connection( expected_handshake_result = MBEDTLS_ERR_SSL_BAD_PROTOCOL_VERSION; } + if (options->pre_handshake_fun != NULL) { + options->pre_handshake_fun(client, server, options->pre_handshake_param); + } + TEST_EQUAL(mbedtls_test_move_handshake_to_state(&(client->ssl), &(server->ssl), MBEDTLS_SSL_HANDSHAKE_OVER), @@ -2313,6 +2317,10 @@ int mbedtls_test_ssl_perform_connection( options->expected_ciphersuite); } + if (options->post_handshake_fun != NULL) { + options->post_handshake_fun(client, server, options->post_handshake_param); + } + #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) if (options->resize_buffers != 0) { /* A server, when using DTLS, might delay a buffer resize to happen @@ -2339,6 +2347,11 @@ int mbedtls_test_ssl_perform_connection( options->expected_srv_fragments), 0); } + + if (options->post_data_fun != NULL) { + options->post_data_fun(client, server, options->post_data_param); + } + #if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION) if (options->serialize == 1) { TEST_ASSERT(test_serialization(options, client, server)); @@ -2396,6 +2409,10 @@ void mbedtls_test_ssl_perform_handshake( TEST_ASSERT(mbedtls_ssl_conf_get_user_data_p(&server->conf) == server); TEST_ASSERT(mbedtls_ssl_get_user_data_p(&server->ssl) == server); + if (options->pre_shutdown_fun != NULL) { + options->pre_shutdown_fun(client, server, options->pre_shutdown_param); + } + exit: mbedtls_test_ssl_endpoint_free(client); mbedtls_test_ssl_endpoint_free(server); From 84f66de73f06aca1964afc193dac15cf00c30d91 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 3 Jun 2026 15:44:08 +0200 Subject: [PATCH 050/173] Test DTLS renegotiation when badmac_seen_or_in_hsfraglen != 0 Non-regression test for a bug introduced with TLS handshake defragmentation support in Mbed TLS 3.6.3, whereby the confusion between the `badmac_seen` meaning and the `in_hsfraglen` meaning of `ssl->badmac_seen_or_in_hsfraglen` causes renegotiation to be processed incorrectly after receiving a message with a bad MAC. The bug doesn't affect Mbed TLS 4.0.0 and above, but it's still good to have more testing. Signed-off-by: Gilles Peskine --- tests/suites/test_suite_ssl.data | 12 +++++++++--- tests/suites/test_suite_ssl.function | 28 +++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 0c30c8987b..da975a5b0d 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -548,13 +548,19 @@ Sending app data via DTLS, without MFL and with fragmentation app_data_dtls:MBEDTLS_SSL_MAX_FRAG_LEN_NONE:16385:100000:0:0 DTLS renegotiation: no legacy renegotiation -renegotiation:MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION +renegotiation:MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION:-1 DTLS renegotiation: legacy renegotiation -renegotiation:MBEDTLS_SSL_LEGACY_ALLOW_RENEGOTIATION +renegotiation:MBEDTLS_SSL_LEGACY_ALLOW_RENEGOTIATION:-1 DTLS renegotiation: legacy break handshake -renegotiation:MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE +renegotiation:MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE:-1 + +DTLS renegotiation: after bad MAC on client +renegotiation:MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION:MBEDTLS_SSL_IS_CLIENT + +DTLS renegotiation: after bad MAC on server +renegotiation:MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION:MBEDTLS_SSL_IS_SERVER DTLS serialization with MFL=512 resize_buffers_serialize_mfl:MBEDTLS_SSL_MAX_FRAG_LEN_512 diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 97a70f997a..f5492ff53c 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -109,6 +109,30 @@ static void resize_buffers(int mfl, int renegotiation, int legacy_renegotiation, #define TEST_GCM_OR_CHACHAPOLY_ENABLED #endif +#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(PSA_HAVE_ALG_SOME_RSA_SIGN) && \ + defined(PSA_WANT_ECC_SECP_R1_384) && \ + defined(MBEDTLS_SSL_PROTO_DTLS) && \ + defined(MBEDTLS_SSL_RENEGOTIATION) && \ + defined(PSA_WANT_ALG_SHA_256) && \ + defined(MBEDTLS_CAN_HANDLE_RSA_TEST_KEY) +static void simulate_badmac_seen_on(mbedtls_test_ssl_endpoint *client, + mbedtls_test_ssl_endpoint *server, + void *param) +{ + int on = *(int *) param; + switch (on) { + case MBEDTLS_SSL_IS_CLIENT: + client->ssl.badmac_seen = 1; + break; + case MBEDTLS_SSL_IS_SERVER: + server->ssl.badmac_seen = 1; + break; + } +} +#endif + typedef enum { RECOMBINE_NOMINAL, /* param: ignored */ RECOMBINE_SPLIT_FIRST, /* param: offset of split (<=0 means from end) */ @@ -3333,7 +3357,7 @@ exit: /* END_CASE */ /* BEGIN_CASE depends_on:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:MBEDTLS_SSL_PROTO_TLS1_2:PSA_HAVE_ALG_SOME_RSA_SIGN:PSA_WANT_ECC_SECP_R1_384:MBEDTLS_SSL_PROTO_DTLS:MBEDTLS_SSL_RENEGOTIATION:PSA_WANT_ALG_SHA_256:MBEDTLS_CAN_HANDLE_RSA_TEST_KEY */ -void renegotiation(int legacy_renegotiation) +void renegotiation(int legacy_renegotiation, int badmac_seen_on) { mbedtls_test_handshake_test_options options; mbedtls_test_init_handshake_options(&options); @@ -3342,6 +3366,8 @@ void renegotiation(int legacy_renegotiation) options.legacy_renegotiation = legacy_renegotiation; options.dtls = 1; options.expected_negotiated_version = MBEDTLS_SSL_VERSION_TLS1_2; + options.post_data_fun = &simulate_badmac_seen_on; + options.post_data_param = &badmac_seen_on; mbedtls_test_ssl_perform_handshake(&options); From 1509cc4509b27a53e7c9e07fc0c41164833a6064 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 28 May 2026 10:54:32 +0200 Subject: [PATCH 051/173] Add udp_proxy options to delay an encrypted handshake message This can be used to simulate data messages received in the wrong epoch, or to cause a handshake message to be buffered. Signed-off-by: Gilles Peskine --- programs/test/udp_proxy.c | 50 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/programs/test/udp_proxy.c b/programs/test/udp_proxy.c index eab15feb38..7712a5f908 100644 --- a/programs/test/udp_proxy.c +++ b/programs/test/udp_proxy.c @@ -103,6 +103,12 @@ int main(void) " May be used multiple times, even for the same\n" \ " message, in which case the respective message\n" \ " gets delayed multiple times.\n" \ + " delay_encrypted_hs_cli=%%d default: 0 (don't delay)\n" \ + " delay the Nth encrypted handshake message from\n" \ + " client to server.\n" \ + " delay_encrypted_hs_srv=%%d default: 0 (don't delay)\n" \ + " delay the Nth encrypted handshake message from\n" \ + " server to client.\n" \ " delay_srv=%%s Handshake message from server that should be\n" \ " delayed. Possible values are 'HelloRequest',\n" \ " 'ServerHello', 'ServerHelloDone', 'Certificate'\n" \ @@ -148,6 +154,8 @@ static struct options { char *delay_srv[MAX_DELAYED_HS]; /* handshake types of messages from * server that should be delayed. */ uint8_t delay_srv_cnt; /* Number of entries in delay_srv. */ + int delay_encrypted_hs_cli; /* Delay Nth encrypted HS from client. */ + int delay_encrypted_hs_srv; /* Delay Nth encrypted HS from server. */ int drop; /* drop 1 packet in N (none if 0) */ int mtu; /* drop packets larger than this */ int bad_ad; /* inject corrupted ApplicationData record */ @@ -219,6 +227,16 @@ static void get_options(int argc, char *argv[]) if (opt.delay_ccs < 0 || opt.delay_ccs > 1) { exit_usage(p, q); } + } else if (strcmp(p, "delay_encrypted_hs_cli") == 0) { + opt.delay_encrypted_hs_cli = atoi(q); + if (opt.delay_encrypted_hs_cli < 0) { + exit_usage(p, q); + } + } else if (strcmp(p, "delay_encrypted_hs_srv") == 0) { + opt.delay_encrypted_hs_srv = atoi(q); + if (opt.delay_encrypted_hs_srv < 0) { + exit_usage(p, q); + } } else if (strcmp(p, "delay_cli") == 0 || strcmp(p, "delay_srv") == 0) { uint8_t *delay_cnt; @@ -664,6 +682,31 @@ static int send_delayed(void) static unsigned char held[2048] = { 0 }; #define HOLD_MAX 2 +static unsigned encrypted_hs_cli_seen; +static unsigned encrypted_hs_srv_seen; + +static int delay_encrypted_hs(const packet *p) +{ + unsigned *seen; + int delay_at; + + if (strcmp(p->type, "Encrypted handshake") != 0) { + return 0; + } + + if (strcmp(p->way, "S <- C") == 0) { + seen = &encrypted_hs_cli_seen; + delay_at = opt.delay_encrypted_hs_cli; + } else { + seen = &encrypted_hs_srv_seen; + delay_at = opt.delay_encrypted_hs_srv; + } + + ++*seen; + + return delay_at > 0 && *seen == (unsigned) delay_at; +} + static int handle_message(const char *way, mbedtls_net_context *dst, mbedtls_net_context *src) @@ -717,6 +760,11 @@ static int handle_message(const char *way, } } + if (delay_encrypted_hs(&cur)) { + delay_packet(&cur); + return 0; + } + /* do we want to drop, delay, or forward it? */ if ((opt.mtu != 0 && cur.len > (unsigned) opt.mtu) || @@ -851,6 +899,8 @@ accept: */ clear_pending(); memset(held, 0, sizeof(held)); + encrypted_hs_cli_seen = 0; + encrypted_hs_srv_seen = 0; nb_fds = client_fd.fd; if (nb_fds < server_fd.fd) { From 1d354f2ae078d7394215d2b07b12a9354a3e1155 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 28 May 2026 11:04:52 +0200 Subject: [PATCH 052/173] Add one-shot bad AD options to udp_proxy Signed-off-by: Gilles Peskine --- programs/test/udp_proxy.c | 51 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/programs/test/udp_proxy.c b/programs/test/udp_proxy.c index 7712a5f908..04c2e3a7e7 100644 --- a/programs/test/udp_proxy.c +++ b/programs/test/udp_proxy.c @@ -122,6 +122,12 @@ int main(void) " mtu=%%d default: 0 (unlimited)\n" \ " drop packets larger than N bytes\n" \ " bad_ad=0/1 default: 0 (don't add bad ApplicationData)\n" \ + " bad_ad_cli_once=%%d default: 0 (don't add bad ApplicationData)\n" \ + " add bad ApplicationData before the Nth\n" \ + " ApplicationData from client to server.\n" \ + " bad_ad_srv_once=%%d default: 0 (don't add bad ApplicationData)\n" \ + " add bad ApplicationData before the Nth\n" \ + " ApplicationData from server to client.\n" \ " bad_cid=%%d default: 0 (don't corrupt Connection IDs)\n" \ " duplicate 1:N packets containing a CID,\n" \ " modifying CID in first instance of the packet.\n" \ @@ -159,6 +165,8 @@ static struct options { int drop; /* drop 1 packet in N (none if 0) */ int mtu; /* drop packets larger than this */ int bad_ad; /* inject corrupted ApplicationData record */ + int bad_ad_cli_once; /* Inject corrupted Nth AD from client. */ + int bad_ad_srv_once; /* Inject corrupted Nth AD from server. */ unsigned bad_cid; /* inject corrupted CID record */ int protect_hvr; /* never drop or delay HelloVerifyRequest */ int protect_len; /* never drop/delay packet of the given size*/ @@ -289,6 +297,16 @@ static void get_options(int argc, char *argv[]) if (opt.bad_ad < 0 || opt.bad_ad > 1) { exit_usage(p, q); } + } else if (strcmp(p, "bad_ad_cli_once") == 0) { + opt.bad_ad_cli_once = atoi(q); + if (opt.bad_ad_cli_once < 0) { + exit_usage(p, q); + } + } else if (strcmp(p, "bad_ad_srv_once") == 0) { + opt.bad_ad_srv_once = atoi(q); + if (opt.bad_ad_srv_once < 0) { + exit_usage(p, q); + } } #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) else if (strcmp(p, "bad_cid") == 0) { @@ -546,6 +564,35 @@ typedef enum { static inject_clihlo_state_t inject_clihlo_state; static packet initial_clihlo; +static unsigned bad_ad_cli_seen; +static unsigned bad_ad_srv_seen; + +static int bad_ad_once(const packet *p) +{ + unsigned *seen; + int bad_ad_at; + + if (strcmp(p->type, "ApplicationData") != 0) { + return 0; + } + + if (strcmp(p->way, "S <- C") == 0) { + seen = &bad_ad_cli_seen; + bad_ad_at = opt.bad_ad_cli_once; + } else { + seen = &bad_ad_srv_seen; + bad_ad_at = opt.bad_ad_srv_once; + } + + if (bad_ad_at <= 0) { + return 0; + } + + ++*seen; + + return *seen == (unsigned) bad_ad_at; +} + static int send_packet(const packet *p, const char *why) { int ret; @@ -577,7 +624,7 @@ static int send_packet(const packet *p, const char *why) } /* insert corrupted ApplicationData record? */ - if (opt.bad_ad && + if ((bad_ad_once(p) || opt.bad_ad) && strcmp(p->type, "ApplicationData") == 0) { unsigned char buf[MAX_MSG_SIZE]; memcpy(buf, p->buf, p->len); @@ -901,6 +948,8 @@ accept: memset(held, 0, sizeof(held)); encrypted_hs_cli_seen = 0; encrypted_hs_srv_seen = 0; + bad_ad_cli_seen = 0; + bad_ad_srv_seen = 0; nb_fds = client_fd.fd; if (nb_fds < server_fd.fd) { From f99b4be7cd6870a7924f99acd5994b178782c24a Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 28 May 2026 14:03:49 +0200 Subject: [PATCH 053/173] Add badmac_limit option to ssl_client2 Signed-off-by: Gilles Peskine --- programs/ssl/ssl_client2.c | 15 ++++++++++++++- programs/ssl/ssl_server2.c | 7 ++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index fc00473cfc..26ea63db9b 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -86,6 +86,7 @@ int main(void) #define DFL_HS_TO_MIN 0 #define DFL_HS_TO_MAX 0 #define DFL_DTLS_MTU -1 +#define DFL_BADMAC_LIMIT -1 #define DFL_DGRAM_PACKING 1 #define DFL_FALLBACK -1 #define DFL_EXTENDED_MS -1 @@ -269,7 +270,8 @@ int main(void) " mtu=%%d default: (library default: unlimited)\n" \ " dgram_packing=%%d default: 1 (allowed)\n" \ " allow or forbid packing of multiple\n" \ - " records within a single datgram.\n" + " records within a single datagram.\n" \ + " badmac_limit=%%d default: (library default: disabled)\n" #else #define USAGE_DTLS "" #endif @@ -518,6 +520,7 @@ struct options { int dtls_mtu; /* UDP Maximum transport unit for DTLS */ int fallback; /* is this a fallback connection? */ int dgram_packing; /* allow/forbid datagram packing */ + int badmac_limit; /* Limit of records with bad MAC */ int extended_ms; /* negotiate extended master secret? */ int etm; /* negotiate encrypt then mac? */ int context_crt_cb; /* use context-specific CRT verify callback */ @@ -959,6 +962,7 @@ int main(int argc, char *argv[]) opt.extended_ms = DFL_EXTENDED_MS; opt.etm = DFL_ETM; opt.dgram_packing = DFL_DGRAM_PACKING; + opt.badmac_limit = DFL_BADMAC_LIMIT; opt.serialize = DFL_SERIALIZE; opt.context_file = DFL_CONTEXT_FILE; opt.eap_tls = DFL_EAP_TLS; @@ -1372,6 +1376,11 @@ usage: opt.dgram_packing != 1) { goto usage; } + } else if (strcmp(p, "badmac_limit") == 0) { + opt.badmac_limit = atoi(q); + if (opt.badmac_limit < 0) { + goto usage; + } } else if (strcmp(p, "recsplit") == 0) { opt.recsplit = atoi(q); if (opt.recsplit < 0 || opt.recsplit > 1) { @@ -1835,6 +1844,10 @@ usage: if (opt.dgram_packing != DFL_DGRAM_PACKING) { mbedtls_ssl_set_datagram_packing(&ssl, opt.dgram_packing); } + + if (opt.badmac_limit != DFL_BADMAC_LIMIT) { + mbedtls_ssl_conf_dtls_badmac_limit(&conf, opt.badmac_limit); + } #endif /* MBEDTLS_SSL_PROTO_DTLS */ #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 79cbad877d..541c6a6b43 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -367,9 +367,6 @@ int main(void) #define USAGE_ANTI_REPLAY "" #endif -#define USAGE_BADMAC_LIMIT \ - " badmac_limit=%%d default: (library default: disabled)\n" - #if defined(MBEDTLS_SSL_PROTO_DTLS) #define USAGE_DTLS \ " dtls=%%d default: 0 (TLS)\n" \ @@ -378,7 +375,8 @@ int main(void) " mtu=%%d default: (library default: unlimited)\n" \ " dgram_packing=%%d default: 1 (allowed)\n" \ " allow or forbid packing of multiple\n" \ - " records within a single datgram.\n" + " records within a single datagram.\n" \ + " badmac_limit=%%d default: (library default: disabled)\n" #else #define USAGE_DTLS "" #endif @@ -524,7 +522,6 @@ int main(void) USAGE_SRTP \ USAGE_COOKIES \ USAGE_ANTI_REPLAY \ - USAGE_BADMAC_LIMIT \ "\n" #define USAGE2 \ " auth_mode=%%s default: (library default: none)\n" \ From b7718ad291a5c6038cf635a616cc33e7bfc3560b Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 28 May 2026 19:59:10 +0200 Subject: [PATCH 054/173] Check "refusing renegotiation" log in more renegotiation tests Signed-off-by: Gilles Peskine --- tests/ssl-opt.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 6fa14924b3..9f037148c7 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -5269,6 +5269,7 @@ run_test "Renegotiation: client-initiated, server-rejected" \ -c "=> renegotiate" \ -S "=> renegotiate" \ -S "write hello request" \ + -s "refusing renegotiation" \ -c "SSL - Unexpected message at ServerHello in renegotiation" \ -c "failed" @@ -5285,6 +5286,7 @@ run_test "Renegotiation: server-initiated, client-rejected, default" \ -C "=> renegotiate" \ -S "=> renegotiate" \ -s "write hello request" \ + -c "refusing renegotiation" \ -S "SSL - An unexpected message was received from our peer" \ -S "failed" @@ -5302,6 +5304,7 @@ run_test "Renegotiation: server-initiated, client-rejected, not enforced" \ -C "=> renegotiate" \ -S "=> renegotiate" \ -s "write hello request" \ + -c "refusing renegotiation" \ -S "SSL - An unexpected message was received from our peer" \ -S "failed" @@ -5320,6 +5323,7 @@ run_test "Renegotiation: server-initiated, client-rejected, delay 2" \ -C "=> renegotiate" \ -S "=> renegotiate" \ -s "write hello request" \ + -c "refusing renegotiation" \ -S "SSL - An unexpected message was received from our peer" \ -S "failed" @@ -5337,6 +5341,7 @@ run_test "Renegotiation: server-initiated, client-rejected, delay 0" \ -C "=> renegotiate" \ -S "=> renegotiate" \ -s "write hello request" \ + -c "refusing renegotiation" \ -s "SSL - An unexpected message was received from our peer" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION @@ -5353,6 +5358,7 @@ run_test "Renegotiation: server-initiated, client-accepted, delay 0" \ -c "=> renegotiate" \ -s "=> renegotiate" \ -s "write hello request" \ + -C "refusing renegotiation" \ -S "SSL - An unexpected message was received from our peer" \ -S "failed" From a21f97139fde54199e943733244c043021631db9 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 28 May 2026 20:00:29 +0200 Subject: [PATCH 055/173] Add tests for renegotiation with badmac_seen=1 on the client After a message with a bad MAC (invalid application data record), try to renegotiate: * Test cases where renegotiation (nominal or delayed) is rejected. Nothing bad happens. * A test where renegotiation is misparsed and rejected. The subsequent parsing fails. * A test where the renegotiation request is delayed. This causes a heap buffer overflow in `ssl_buffer_message()`. Signed-off-by: Gilles Peskine --- tests/ssl-opt.sh | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 9f037148c7..4d4b4541e3 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -11775,6 +11775,86 @@ run_test "DTLS proxy: inject invalid AD record, badmac_limit 2, exchanges 2"\ -s "too many records with bad MAC" \ -s "Verification of the message MAC failed" +requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +run_test "DTLS proxy: client: get invalid AD record then reject renego" \ + -p "$P_PXY bad_ad_srv_once=1" \ + "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 \ + renegotiate=1 renegotiation=1 exchanges=4 \ + badmac_limit=99 debug_level=3" \ + "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ + exchanges=4 badmac_limit=99 debug_level=3" \ + 0 \ + -s "write hello request" \ + -c "refusing renegotiation" \ + -S "=> renegotiate" \ + -C "=> renegotiate" \ + -s "Extra-header:" \ + -c "HTTP/1.0 200 OK" \ + -c "discarding invalid record (mac)" \ + -C "too many records with bad MAC" \ + -C "Verification of the message MAC failed" \ + -C "Consume: waiting for more handshake fragments" + +requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +run_test "DTLS proxy: client: get invalid AD record then accept renego" \ + -p "$P_PXY bad_ad_srv_once=1" \ + "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 \ + renegotiate=1 renegotiation=1 exchanges=4 \ + badmac_limit=99 debug_level=3" \ + "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ + renegotiation=1 exchanges=4 badmac_limit=99 debug_level=3" \ + 0 \ + -s "=> renegotiate" \ + -c "=> renegotiate" \ + -s "Extra-header:" \ + -c "HTTP/1.0 200 OK" \ + -c "discarding invalid record (mac)" \ + -C "too many records with bad MAC" \ + -C "Verification of the message MAC failed" \ + -C "Consume: waiting for more handshake fragments" + +requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +run_test "DTLS proxy: client: get invalid AD record then reject early renego" \ + -p "$P_PXY bad_ad_srv_once=1 delay_encrypted_hs_srv=3" \ + "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 \ + renegotiate=1 renegotiation=1 exchanges=4 \ + debug_level=3" \ + "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ + exchanges=4 badmac_limit=99 debug_level=3" \ + 0 \ + -S "=> renegotiate" \ + -C "=> renegotiate" \ + -s "write hello request" \ + -c "refusing renegotiation" \ + -C "=> ssl_buffer_message" \ + -C "initialize reassembly, total length = 0" \ + -s "Extra-header:" \ + -c "HTTP/1.0 200 OK" \ + -c "discarding invalid record (mac)" \ + -C "too many records with bad MAC" \ + -C "Verification of the message MAC failed" \ + -C "Consume: waiting for more handshake fragments" + +requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +run_test "DTLS proxy: client: get invalid AD record then accept early renego" \ + -p "$P_PXY bad_ad_srv_once=1 delay_encrypted_hs_srv=3" \ + "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 \ + renegotiate=1 renegotiation=1 exchanges=4 \ + debug_level=3" \ + "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ + renegotiation=1 exchanges=4 badmac_limit=99 debug_level=3" \ + 0 \ + -s "=> renegotiate" \ + -c "=> renegotiate" \ + -c "=> ssl_buffer_message" \ + -C "initialize reassembly, total length = 0" \ + -s "Extra-header:" \ + -c "HTTP/1.0 200 OK" \ + -c "discarding invalid record (mac)" \ + -C "too many records with bad MAC" \ + -C "Verification of the message MAC failed" \ + -C "Consume: waiting for more handshake fragments" + requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2 run_test "DTLS proxy: delay ChangeCipherSpec" \ -p "$P_PXY delay_ccs=1" \ From 4bb28f657354882e7900960ff98037e8fbf71d92 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 28 May 2026 20:52:38 +0200 Subject: [PATCH 056/173] Add renegotiate=2 option to ssl_client2 In `ssl_client2`, the existing option `renegotiate=1` causes the client to initiate renegotiation immediately after the initial handshake. Add a variant `renegotiate=2` that initiates renegotiation after one data exchange. Signed-off-by: Gilles Peskine --- programs/ssl/ssl_client2.c | 43 ++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 26ea63db9b..be1d2a8e2e 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -296,7 +296,7 @@ int main(void) #if defined(MBEDTLS_SSL_RENEGOTIATION) #define USAGE_RENEGO \ " renegotiation=%%d default: 0 (disabled)\n" \ - " renegotiate=%%d default: 0 (disabled)\n" \ + " renegotiate=%%d default: 0 (disabled), 1 immediately, 2 after first exchange\n" \ " renego_delay=%%d default: -2 (library default)\n" #else #define USAGE_RENEGO "" @@ -493,7 +493,7 @@ struct options { #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */ int renegotiation; /* enable / disable renegotiation */ int allow_legacy; /* allow legacy renegotiation */ - int renegotiate; /* attempt renegotiation? */ + int renegotiate; /* attempt renegotiation? 1: before data, 2: after first exchange */ int renego_delay; /* delay before enforcing renegotiation */ int exchanges; /* number of data exchanges */ int min_version; /* minimum protocol version accepted */ @@ -1168,7 +1168,7 @@ usage: opt.renego_delay = (atoi(q)); } else if (strcmp(p, "renegotiate") == 0) { opt.renegotiate = atoi(q); - if (opt.renegotiate < 0 || opt.renegotiate > 1) { + if (opt.renegotiate < 0 || opt.renegotiate > 2) { goto usage; } } else if (strcmp(p, "exchanges") == 0) { @@ -2455,7 +2455,7 @@ usage: #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ #if defined(MBEDTLS_SSL_RENEGOTIATION) - if (opt.renegotiate) { + if (opt.renegotiate == 1) { /* * Perform renegotiation (this must be done when the server is waiting * for input from our side). @@ -2830,6 +2830,41 @@ send_request: goto send_request; } +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if (opt.renegotiate == 2) { + opt.renegotiate = 0; + + /* Perform renegotiation after the first data exchange. */ + mbedtls_printf(" . Performing renegotiation..."); + fflush(stdout); + while ((ret = mbedtls_ssl_renegotiate(&ssl)) != 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && + ret != MBEDTLS_ERR_SSL_WANT_WRITE && + ret != MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) { + mbedtls_printf(" failed\n ! mbedtls_ssl_renegotiate returned %d\n\n", + ret); + goto exit; + } + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) { + continue; + } +#endif + + /* For event-driven IO, wait for socket to become available */ + if (opt.event == 1 /* level triggered IO */) { +#if defined(MBEDTLS_TIMING_C) + idle(&server_fd, &timer, ret); +#else + idle(&server_fd, ret); +#endif + } + } + mbedtls_printf(" ok\n"); + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + /* * 7c. Simulate serialize/deserialize and go back to data exchange */ From cde26bd4ce6f11a3e5c76635a95cf6e0fdb3e8a3 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 28 May 2026 20:52:38 +0200 Subject: [PATCH 057/173] Add tests for renegotiation with badmac_seen=1 on the server Signed-off-by: Gilles Peskine --- tests/ssl-opt.sh | 92 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 4d4b4541e3..41280a7ab2 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -11795,6 +11795,25 @@ run_test "DTLS proxy: client: get invalid AD record then reject renego" \ -C "Verification of the message MAC failed" \ -C "Consume: waiting for more handshake fragments" +requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +run_test "DTLS proxy: server: get invalid AD record then reject renego (cli)" \ + -p "$P_PXY bad_ad_cli_once=1" \ + "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 \ + renegotiation=0 exchanges=4 \ + badmac_limit=99 debug_level=3" \ + "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ + renegotiation=1 renegotiate=2 exchanges=4 badmac_limit=99 debug_level=3" \ + 1 \ + -s "discarding invalid record (mac)" \ + -c "=> renegotiate" \ + -S "=> renegotiate" \ + -s "refusing renegotiation" \ + -s "Extra-header:" \ + -c "HTTP/1.0 200 OK" \ + -S "too many records with bad MAC" \ + -S "Verification of the message MAC failed" \ + -S "Consume: waiting for more handshake fragments" + requires_config_enabled MBEDTLS_SSL_RENEGOTIATION run_test "DTLS proxy: client: get invalid AD record then accept renego" \ -p "$P_PXY bad_ad_srv_once=1" \ @@ -11813,6 +11832,42 @@ run_test "DTLS proxy: client: get invalid AD record then accept renego" \ -C "Verification of the message MAC failed" \ -C "Consume: waiting for more handshake fragments" +requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +run_test "DTLS proxy: server: get invalid AD record then accept renego (srv)" \ + -p "$P_PXY bad_ad_cli_once=1" \ + "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 \ + renegotiate=1 renegotiation=1 exchanges=4 \ + badmac_limit=99 debug_level=3" \ + "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ + renegotiation=1 exchanges=4 badmac_limit=99 debug_level=3" \ + 0 \ + -s "discarding invalid record (mac)" \ + -s "=> renegotiate" \ + -c "=> renegotiate" \ + -s "Extra-header:" \ + -c "HTTP/1.0 200 OK" \ + -S "too many records with bad MAC" \ + -S "Verification of the message MAC failed" \ + -S "Consume: waiting for more handshake fragments" + +requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +run_test "DTLS proxy: server: get invalid AD record then accept renego (cli)" \ + -p "$P_PXY bad_ad_cli_once=1" \ + "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 \ + renegotiation=1 exchanges=4 \ + badmac_limit=99 debug_level=3" \ + "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ + renegotiation=1 renegotiate=2 exchanges=4 badmac_limit=99 debug_level=3" \ + 0 \ + -s "discarding invalid record (mac)" \ + -c "=> renegotiate" \ + -s "=> renegotiate" \ + -s "Extra-header:" \ + -c "HTTP/1.0 200 OK" \ + -S "too many records with bad MAC" \ + -S "Verification of the message MAC failed" \ + -S "Consume: waiting for more handshake fragments" + requires_config_enabled MBEDTLS_SSL_RENEGOTIATION run_test "DTLS proxy: client: get invalid AD record then reject early renego" \ -p "$P_PXY bad_ad_srv_once=1 delay_encrypted_hs_srv=3" \ @@ -11855,6 +11910,43 @@ run_test "DTLS proxy: client: get invalid AD record then accept early renego" -C "Verification of the message MAC failed" \ -C "Consume: waiting for more handshake fragments" +requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +run_test "DTLS proxy: server: get invalid AD record then reject early renego (cli)" \ + -p "$P_PXY bad_ad_cli_once=1 delay_encrypted_hs_cli=2" \ + "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 \ + renegotiation=0 exchanges=4 \ + badmac_limit=99 debug_level=3" \ + "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ + renegotiation=1 renegotiate=2 exchanges=4 badmac_limit=99 debug_level=3" \ + 1 \ + -s "discarding invalid record (mac)" \ + -c "=> renegotiate" \ + -S "=> renegotiate" \ + -s "refusing renegotiation" \ + -s "Extra-header:" \ + -c "HTTP/1.0 200 OK" \ + -S "too many records with bad MAC" \ + -S "Verification of the message MAC failed" \ + -S "Consume: waiting for more handshake fragments" + +requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +run_test "DTLS proxy: server: get invalid AD record then accept early renego (cli)" \ + -p "$P_PXY bad_ad_cli_once=1 delay_encrypted_hs_cli=2" \ + "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 \ + renegotiation=1 exchanges=4 \ + badmac_limit=99 debug_level=3" \ + "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ + renegotiation=1 renegotiate=2 exchanges=4 badmac_limit=99 debug_level=3" \ + 0 \ + -s "discarding invalid record (mac)" \ + -c "=> renegotiate" \ + -s "=> renegotiate" \ + -s "Extra-header:" \ + -c "HTTP/1.0 200 OK" \ + -S "too many records with bad MAC" \ + -S "Verification of the message MAC failed" \ + -S "Consume: waiting for more handshake fragments" + requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2 run_test "DTLS proxy: delay ChangeCipherSpec" \ -p "$P_PXY delay_ccs=1" \ From 3d5e440b4153a86006442172acc6e14de2db268c Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 15 Jun 2026 13:08:43 +0200 Subject: [PATCH 058/173] Add DTLS handshake test with badmac_seen=1 Add a test entry point for a handshake with a specially crafted context. This can be used for defense in depths for scenarios that we think can't happen, but might actually happen due to a bug, or due to a new feature that is insufficiently tested. This can also be a proxy for testing aspects of renegotiation or session resumption in circumstances that are hard to arrange. In this commit, use it to test a DTLS handshake with `ssl->badmac_seen` :(actually `ssl->badmac_seen_or_in_hsfraglen` in the 3.6 branch) set to a nonzero value. This can't happen, as far as I know (`badmac_seen` can only be nonzero during renegotiation, not during a nominal handshake or in session resumption). But it could happen, for example, if `mbedtls_ssl_session_reset()` failed to reset `badmac_seen`, as was the case in Mbed TLS 4.0.0 to 4.1.0. Signed-off-by: Gilles Peskine --- tests/suites/test_suite_ssl.data | 8 ++++ tests/suites/test_suite_ssl.function | 67 ++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index da975a5b0d..09da227dac 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -471,6 +471,14 @@ Handshake, select ECDHE-ECDSA-WITH-AES-256-CCM, opaque, bad usage depends_on:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_AES:PSA_WANT_ALG_CCM:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ECC_SECP_R1_384:MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH handshake_ciphersuite_select:"TLS-ECDHE-ECDSA-WITH-AES-256-CCM":MBEDTLS_PK_ECDSA:"":PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_ALG_NONE:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE:0 +Handshake: DTLS 1.2, badmac_seen on client +depends_on:MBEDTLS_SSL_PROTO_DTLS:MBEDTLS_SSL_PROTO_TLS1_2 +handshake_with_forced_context:1:MBEDTLS_SSL_VERSION_TLS1_2:PRE_HANDSHAKE_BADMAC_SEEN:0 + +Handshake: DTLS 1.2, badmac_seen on server +depends_on:MBEDTLS_SSL_PROTO_DTLS:MBEDTLS_SSL_PROTO_TLS1_2 +handshake_with_forced_context:1:MBEDTLS_SSL_VERSION_TLS1_2:0:PRE_HANDSHAKE_BADMAC_SEEN + Sending app data via TLS, MFL=512 without fragmentation depends_on:MBEDTLS_SSL_MAX_FRAGMENT_LENGTH app_data_tls:MBEDTLS_SSL_MAX_FRAG_LEN_512:400:512:1:1 diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index f5492ff53c..b4bdf37553 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -66,6 +66,39 @@ exit: } #endif +typedef enum { + PRE_HANDSHAKE_BADMAC_SEEN = 1u << 0, +} pre_handshake_tweaks_t; + +#if 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) +typedef struct { + uint32_t client; + uint32_t server; +} pre_handshake_tweak_spec_t; + +static void pre_handshake_tweak_context(mbedtls_ssl_context *ssl, + int tweaks) +{ + if (tweaks & PRE_HANDSHAKE_BADMAC_SEEN) { + ssl->badmac_seen = 1; + } +} + +static void pre_handshake_tweak_contexts(mbedtls_test_ssl_endpoint *client, + mbedtls_test_ssl_endpoint *server, + void *param) +{ + const pre_handshake_tweak_spec_t *tweaks = param; + pre_handshake_tweak_context(&client->ssl, tweaks->client); + pre_handshake_tweak_context(&server->ssl, tweaks->server); +} +#endif + #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) && \ defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) && \ defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ @@ -3089,6 +3122,40 @@ exit: } /* END_CASE */ +/* BEGIN_CASE depends_on: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 */ +/* Test a handshake in forced conditions. + * + * This can be used for defense in depths for scenarios that we think + * can't happen, but might actually happen due to a bug, or due to + * a new feature that is insufficiently tested. + * + * This can also be a proxy for testing aspects of renegotiation or + * session resumption in circumstances that are hard to arrange. + */ +void handshake_with_forced_context(int dtls, int version, + int client_tweaks, int server_tweaks) +{ + pre_handshake_tweak_spec_t tweaks = { client_tweaks, server_tweaks }; + + mbedtls_test_handshake_test_options options; + mbedtls_test_init_handshake_options(&options); + options.dtls = dtls; + options.client_min_version = version; + options.client_max_version = version; + options.expected_negotiated_version = version; + options.pre_handshake_fun = &pre_handshake_tweak_contexts; + options.pre_handshake_param = &tweaks; + + mbedtls_test_ssl_perform_handshake(&options); + + /* The goto below is used to avoid an "unused label" warning.*/ + goto exit; + +exit: + mbedtls_test_free_handshake_options(&options); +} +/* END_CASE */ + /* BEGIN_CASE depends_on:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:PSA_HAVE_ALG_SOME_RSA_SIGN:PSA_WANT_ECC_SECP_R1_384:PSA_WANT_ALG_SHA_256 */ void app_data(int mfl, int cli_msg_len, int srv_msg_len, int expected_cli_fragments, From cbc94fbdf4b877a7d2f7f7045ec2fd1c25d6c717 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 15 Jun 2026 13:37:54 +0200 Subject: [PATCH 059/173] Don't pass badmac_limit when it would have no effect Only set `badmac_limit` on the side that actually receives a message with a bad MAC/tag (injected by the proxy). Signed-off-by: Gilles Peskine --- tests/ssl-opt.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 41280a7ab2..5b966d5a38 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -11780,7 +11780,7 @@ run_test "DTLS proxy: client: get invalid AD record then reject renego" \ -p "$P_PXY bad_ad_srv_once=1" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 \ renegotiate=1 renegotiation=1 exchanges=4 \ - badmac_limit=99 debug_level=3" \ + debug_level=3" \ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ exchanges=4 badmac_limit=99 debug_level=3" \ 0 \ @@ -11802,7 +11802,7 @@ run_test "DTLS proxy: server: get invalid AD record then reject renego (cli)" renegotiation=0 exchanges=4 \ badmac_limit=99 debug_level=3" \ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ - renegotiation=1 renegotiate=2 exchanges=4 badmac_limit=99 debug_level=3" \ + renegotiation=1 renegotiate=2 exchanges=4 debug_level=3" \ 1 \ -s "discarding invalid record (mac)" \ -c "=> renegotiate" \ @@ -11819,7 +11819,7 @@ run_test "DTLS proxy: client: get invalid AD record then accept renego" \ -p "$P_PXY bad_ad_srv_once=1" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 \ renegotiate=1 renegotiation=1 exchanges=4 \ - badmac_limit=99 debug_level=3" \ + debug_level=3" \ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ renegotiation=1 exchanges=4 badmac_limit=99 debug_level=3" \ 0 \ @@ -11839,7 +11839,7 @@ run_test "DTLS proxy: server: get invalid AD record then accept renego (srv)" renegotiate=1 renegotiation=1 exchanges=4 \ badmac_limit=99 debug_level=3" \ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ - renegotiation=1 exchanges=4 badmac_limit=99 debug_level=3" \ + renegotiation=1 exchanges=4 debug_level=3" \ 0 \ -s "discarding invalid record (mac)" \ -s "=> renegotiate" \ @@ -11857,7 +11857,7 @@ run_test "DTLS proxy: server: get invalid AD record then accept renego (cli)" renegotiation=1 exchanges=4 \ badmac_limit=99 debug_level=3" \ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ - renegotiation=1 renegotiate=2 exchanges=4 badmac_limit=99 debug_level=3" \ + renegotiation=1 renegotiate=2 exchanges=4 debug_level=3" \ 0 \ -s "discarding invalid record (mac)" \ -c "=> renegotiate" \ @@ -11917,7 +11917,7 @@ run_test "DTLS proxy: server: get invalid AD record then reject early renego renegotiation=0 exchanges=4 \ badmac_limit=99 debug_level=3" \ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ - renegotiation=1 renegotiate=2 exchanges=4 badmac_limit=99 debug_level=3" \ + renegotiation=1 renegotiate=2 exchanges=4 debug_level=3" \ 1 \ -s "discarding invalid record (mac)" \ -c "=> renegotiate" \ @@ -11936,7 +11936,7 @@ run_test "DTLS proxy: server: get invalid AD record then accept early renego renegotiation=1 exchanges=4 \ badmac_limit=99 debug_level=3" \ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ - renegotiation=1 renegotiate=2 exchanges=4 badmac_limit=99 debug_level=3" \ + renegotiation=1 renegotiate=2 exchanges=4 debug_level=3" \ 0 \ -s "discarding invalid record (mac)" \ -c "=> renegotiate" \ From 046e5a43ade2021c924178fc8733fd8a80093011 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 15 Jun 2026 13:58:49 +0200 Subject: [PATCH 060/173] Explain the "get invalid AD record .*renego" tests better Signed-off-by: Gilles Peskine --- programs/ssl/ssl_client2.c | 5 ++++- tests/ssl-opt.sh | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index be1d2a8e2e..9dc99c3e0b 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -2832,9 +2832,12 @@ send_request: #if defined(MBEDTLS_SSL_RENEGOTIATION) if (opt.renegotiate == 2) { + /* Perform renegotiation after the first data exchange. + * This is a one-time thing, we won't renegotiate even if there are + * more data exchanges that cause a `goto send_request` later. + */ opt.renegotiate = 0; - /* Perform renegotiation after the first data exchange. */ mbedtls_printf(" . Performing renegotiation..."); fflush(stdout); while ((ret = mbedtls_ssl_renegotiate(&ssl)) != 0) { diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 5b966d5a38..d66c2026ae 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -11775,6 +11775,14 @@ run_test "DTLS proxy: inject invalid AD record, badmac_limit 2, exchanges 2"\ -s "too many records with bad MAC" \ -s "Verification of the message MAC failed" +# The next few tests exercise renegotiation in DTLS when `ssl->badmac_seen != 0`. +# +# This seems unrelated, but was the location of a bug in Mbed TLS 3.6.3 to +# 3.6.6 (CVE-2026-50713) due to `ssl->badmac_seen` being unified with +# `ssl->in_hsfraglen` (to preserve the ABI when adding support for handshake +# defragmentation in TLS in 3.6.3), with some mistakes in using the unified +# field that were fixed in 3.6.7. + requires_config_enabled MBEDTLS_SSL_RENEGOTIATION run_test "DTLS proxy: client: get invalid AD record then reject renego" \ -p "$P_PXY bad_ad_srv_once=1" \ @@ -11868,6 +11876,15 @@ run_test "DTLS proxy: server: get invalid AD record then accept renego (cli)" -S "Verification of the message MAC failed" \ -S "Consume: waiting for more handshake fragments" +# The next few tests have "early renego". A DTLS handshake message is delayed +# past another handshake message. From the perspective of the recipient, +# this means that a DTLS handshake arrives early (its epoch number is still +# in the future) and needs to be queued. +# +# In Mbed TLS 3.6.3 through 3.6.6, due to the fields `ssl->badmac_seen` +# and `ssl->in_hsfraglen` being unified, the early message was parsed +# incorrectly, leading to heap corruption. + requires_config_enabled MBEDTLS_SSL_RENEGOTIATION run_test "DTLS proxy: client: get invalid AD record then reject early renego" \ -p "$P_PXY bad_ad_srv_once=1 delay_encrypted_hs_srv=3" \ @@ -11890,6 +11907,13 @@ run_test "DTLS proxy: client: get invalid AD record then reject early renego" -C "Verification of the message MAC failed" \ -C "Consume: waiting for more handshake fragments" +# Delay the third encrypted handshake message from the server: +# 1. Finished message of the initial handshake. +# 2. HelloRequest to request renegotiation. +# 3. ServerHello of renegotiation, delayed. +# 4. Subsequent handshake message, which the client receives and enqueues. +# +# In Mbed TLS 3.6.3 though 3.6.6, the processing of (4) caused heap corruption. requires_config_enabled MBEDTLS_SSL_RENEGOTIATION run_test "DTLS proxy: client: get invalid AD record then accept early renego" \ -p "$P_PXY bad_ad_srv_once=1 delay_encrypted_hs_srv=3" \ From dc258c9b9b59f0ee24800efda9dd2bcac7ad115b Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 15 Jun 2026 18:22:11 +0200 Subject: [PATCH 061/173] Remove some test cases that are not really meaningful Remove the "srv" variant of "DTLS proxy: server: get invalid AD record then accept renego", where the server initiates the renegotiation process by sending a HelloRequest. The HelloRequest message is not relevant to this test. The first message of the actual renegotiation is the ClientHello message from the client, and the interesting part of the test happens when the client receives the server's response. Remove "DTLS proxy: server: get invalid AD record then accept early renego (cli)" and the corresponding "reject" control. This test case doesn't really do what it is advertised to do, and in particular does not lead to a call to `ssl_consume_current_message()` in the server. What happens is that the client sends a ClientHello message to start the renegotiation, then it blocks until the server has replied. So there is nothing to delay that ClientHello after:(unlike what happens in the corresponding client-side test, where the first flight of the renegotiation protocol contains multiple messages, so we can delay the first of these messages after the second one). What happens in practice is that the client times out, then resends its ClientHello, and the proxy sends the delayed ClientHello immediately after the resent one, which does not cause any interesting behavior in the server. Signed-off-by: Gilles Peskine --- tests/ssl-opt.sh | 59 ++---------------------------------------------- 1 file changed, 2 insertions(+), 57 deletions(-) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index d66c2026ae..8ad596a6ea 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -11804,7 +11804,7 @@ run_test "DTLS proxy: client: get invalid AD record then reject renego" \ -C "Consume: waiting for more handshake fragments" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION -run_test "DTLS proxy: server: get invalid AD record then reject renego (cli)" \ +run_test "DTLS proxy: server: get invalid AD record then reject renego" \ -p "$P_PXY bad_ad_cli_once=1" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 \ renegotiation=0 exchanges=4 \ @@ -11841,25 +11841,7 @@ run_test "DTLS proxy: client: get invalid AD record then accept renego" \ -C "Consume: waiting for more handshake fragments" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION -run_test "DTLS proxy: server: get invalid AD record then accept renego (srv)" \ - -p "$P_PXY bad_ad_cli_once=1" \ - "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 \ - renegotiate=1 renegotiation=1 exchanges=4 \ - badmac_limit=99 debug_level=3" \ - "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ - renegotiation=1 exchanges=4 debug_level=3" \ - 0 \ - -s "discarding invalid record (mac)" \ - -s "=> renegotiate" \ - -c "=> renegotiate" \ - -s "Extra-header:" \ - -c "HTTP/1.0 200 OK" \ - -S "too many records with bad MAC" \ - -S "Verification of the message MAC failed" \ - -S "Consume: waiting for more handshake fragments" - -requires_config_enabled MBEDTLS_SSL_RENEGOTIATION -run_test "DTLS proxy: server: get invalid AD record then accept renego (cli)" \ +run_test "DTLS proxy: server: get invalid AD record then accept renego" \ -p "$P_PXY bad_ad_cli_once=1" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 \ renegotiation=1 exchanges=4 \ @@ -11934,43 +11916,6 @@ run_test "DTLS proxy: client: get invalid AD record then accept early renego" -C "Verification of the message MAC failed" \ -C "Consume: waiting for more handshake fragments" -requires_config_enabled MBEDTLS_SSL_RENEGOTIATION -run_test "DTLS proxy: server: get invalid AD record then reject early renego (cli)" \ - -p "$P_PXY bad_ad_cli_once=1 delay_encrypted_hs_cli=2" \ - "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 \ - renegotiation=0 exchanges=4 \ - badmac_limit=99 debug_level=3" \ - "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ - renegotiation=1 renegotiate=2 exchanges=4 debug_level=3" \ - 1 \ - -s "discarding invalid record (mac)" \ - -c "=> renegotiate" \ - -S "=> renegotiate" \ - -s "refusing renegotiation" \ - -s "Extra-header:" \ - -c "HTTP/1.0 200 OK" \ - -S "too many records with bad MAC" \ - -S "Verification of the message MAC failed" \ - -S "Consume: waiting for more handshake fragments" - -requires_config_enabled MBEDTLS_SSL_RENEGOTIATION -run_test "DTLS proxy: server: get invalid AD record then accept early renego (cli)" \ - -p "$P_PXY bad_ad_cli_once=1 delay_encrypted_hs_cli=2" \ - "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 \ - renegotiation=1 exchanges=4 \ - badmac_limit=99 debug_level=3" \ - "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 \ - renegotiation=1 renegotiate=2 exchanges=4 debug_level=3" \ - 0 \ - -s "discarding invalid record (mac)" \ - -c "=> renegotiate" \ - -s "=> renegotiate" \ - -s "Extra-header:" \ - -c "HTTP/1.0 200 OK" \ - -S "too many records with bad MAC" \ - -S "Verification of the message MAC failed" \ - -S "Consume: waiting for more handshake fragments" - requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2 run_test "DTLS proxy: delay ChangeCipherSpec" \ -p "$P_PXY delay_ccs=1" \ From 49b13b34b332d997943f7a09dc846a0fa14a5a30 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 16 Jun 2026 19:34:32 +0200 Subject: [PATCH 062/173] Credit independent report Signed-off-by: Gilles Peskine --- ChangeLog.d/x509-crt-parse-basicConstraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.d/x509-crt-parse-basicConstraints.txt b/ChangeLog.d/x509-crt-parse-basicConstraints.txt index a67f992ab5..251dc8f0fd 100644 --- a/ChangeLog.d/x509-crt-parse-basicConstraints.txt +++ b/ChangeLog.d/x509-crt-parse-basicConstraints.txt @@ -4,7 +4,7 @@ Security could have dangerous results, in particular causing some certificates to be parsed as CA certificates when other X.509 implementations would parse them as end-entity certificates. Reported by Mohammad Seet - (mhdsait101) and Pablo Ruiz García. CVE-2026-49300 + (mhdsait101), Pablo Ruiz García and NVIDIA Project Vanessa. CVE-2026-49300 Changes * X.509 certificates with a basicConstraints extension starting with an From b1a4b07509cbadbaa963ae896d4d44ddba550f74 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 30 Apr 2026 13:09:10 +0100 Subject: [PATCH 063/173] Add fix for stale pointer after mbedtls_pkcs7_free Signed-off-by: Ben Taylor --- library/pkcs7.c | 2 +- tests/suites/test_suite_pkcs7.data | 4 ++ tests/suites/test_suite_pkcs7.function | 59 ++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/library/pkcs7.c b/library/pkcs7.c index 2cc7812bf0..e345d4b980 100644 --- a/library/pkcs7.c +++ b/library/pkcs7.c @@ -766,7 +766,7 @@ void mbedtls_pkcs7_free(mbedtls_pkcs7 *pkcs7) mbedtls_free(signer_prev); } - pkcs7->raw.p = NULL; + mbedtls_platform_zeroize(pkcs7, sizeof(*pkcs7)); } #endif diff --git a/tests/suites/test_suite_pkcs7.data b/tests/suites/test_suite_pkcs7.data index 3e3f7f1d7d..7e220fc2e6 100644 --- a/tests/suites/test_suite_pkcs7.data +++ b/tests/suites/test_suite_pkcs7.data @@ -14,6 +14,10 @@ PKCS7 Signed Data Parse with zero signers depends_on:PSA_WANT_ALG_SHA_256 pkcs7_parse:"../framework/data_files/pkcs7_data_no_signers.der":MBEDTLS_PKCS7_SIGNED_DATA +PKCS7 Signed Data Parse reused object after multiple signers +depends_on:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY +pkcs7_parse_reuse:"../framework/data_files/pkcs7_data_multiple_signed.der":"../framework/data_files/pkcs7_data_no_signers.der":MBEDTLS_PKCS7_SIGNED_DATA + PKCS7 Signed Data Parse Fail with multiple certs #4 depends_on:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY pkcs7_parse:"../framework/data_files/pkcs7_data_multiple_certs_signed.der":MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE diff --git a/tests/suites/test_suite_pkcs7.function b/tests/suites/test_suite_pkcs7.function index 9eccabab22..4e60a99bc7 100644 --- a/tests/suites/test_suite_pkcs7.function +++ b/tests/suites/test_suite_pkcs7.function @@ -25,8 +25,33 @@ static int pkcs7_parse_buffer(unsigned char *pkcs7_buf, int buflen) mbedtls_pkcs7_init(&pkcs7); res = mbedtls_pkcs7_parse_der(&pkcs7, pkcs7_buf, buflen); mbedtls_pkcs7_free(&pkcs7); + return res; } + +# ifdef MBEDTLS_FS_IO +static int pkcs7_parse_buffers_reuse(unsigned char *first_buf, int first_len, + unsigned char *second_buf, int second_len) +{ + int res; + mbedtls_pkcs7 pkcs7; + + mbedtls_pkcs7_init(&pkcs7); + + res = mbedtls_pkcs7_parse_der(&pkcs7, first_buf, first_len); + if (res != MBEDTLS_PKCS7_SIGNED_DATA) { + goto exit; + } + + mbedtls_pkcs7_free(&pkcs7); + + res = mbedtls_pkcs7_parse_der(&pkcs7, second_buf, second_len); + +exit: + mbedtls_pkcs7_free(&pkcs7); + return res; +} +#endif /* END_SUITE_HELPERS */ /* BEGIN_CASE */ @@ -71,6 +96,40 @@ exit: } /* END_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_FS_IO */ +void pkcs7_parse_reuse(char *first_pkcs7_file, char *second_pkcs7_file, + int res_expect) +{ + unsigned char *first_pkcs7_buf = NULL; + unsigned char *second_pkcs7_buf = NULL; + size_t first_buflen; + size_t second_buflen; + int res; + + /* PKCS7 uses X509 which itself relies on PK under the hood and the latter + * can use PSA to store keys and perform operations so psa_crypto_init() + * must be called before. */ + USE_PSA_INIT(); + + res = mbedtls_pk_load_file(first_pkcs7_file, &first_pkcs7_buf, + &first_buflen); + TEST_EQUAL(res, 0); + + res = mbedtls_pk_load_file(second_pkcs7_file, &second_pkcs7_buf, + &second_buflen); + TEST_EQUAL(res, 0); + + res = pkcs7_parse_buffers_reuse(first_pkcs7_buf, first_buflen, + second_pkcs7_buf, second_buflen); + TEST_EQUAL(res, res_expect); + +exit: + mbedtls_free(first_pkcs7_buf); + mbedtls_free(second_pkcs7_buf); + USE_PSA_DONE(); +} +/* END_CASE */ + /* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C:PSA_HAVE_ALG_SOME_RSA_VERIFY */ void pkcs7_verify(char *pkcs7_file, char *crt_files, From 434d7114a84970010dcfcd5c5bd9faa4bc2237ed Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 30 Apr 2026 13:14:27 +0100 Subject: [PATCH 064/173] Add ChangeLog Signed-off-by: Ben Taylor --- ChangeLog.d/pkcs-free-stale-pointers.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 ChangeLog.d/pkcs-free-stale-pointers.txt diff --git a/ChangeLog.d/pkcs-free-stale-pointers.txt b/ChangeLog.d/pkcs-free-stale-pointers.txt new file mode 100644 index 0000000000..04ba823217 --- /dev/null +++ b/ChangeLog.d/pkcs-free-stale-pointers.txt @@ -0,0 +1,2 @@ +Bugfix + * Add fix for stale pointer after mbedtls_pkcs7_free. From 55536a07c96cc6b87c0fbef84b36b44598f779b2 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Tue, 2 Jun 2026 15:32:54 +0100 Subject: [PATCH 065/173] Remove redundant function from pkcs7_parse_reuse Signed-off-by: Ben Taylor --- tests/suites/test_suite_pkcs7.function | 49 +++++++++----------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/tests/suites/test_suite_pkcs7.function b/tests/suites/test_suite_pkcs7.function index 4e60a99bc7..cdf221524e 100644 --- a/tests/suites/test_suite_pkcs7.function +++ b/tests/suites/test_suite_pkcs7.function @@ -29,29 +29,6 @@ static int pkcs7_parse_buffer(unsigned char *pkcs7_buf, int buflen) return res; } -# ifdef MBEDTLS_FS_IO -static int pkcs7_parse_buffers_reuse(unsigned char *first_buf, int first_len, - unsigned char *second_buf, int second_len) -{ - int res; - mbedtls_pkcs7 pkcs7; - - mbedtls_pkcs7_init(&pkcs7); - - res = mbedtls_pkcs7_parse_der(&pkcs7, first_buf, first_len); - if (res != MBEDTLS_PKCS7_SIGNED_DATA) { - goto exit; - } - - mbedtls_pkcs7_free(&pkcs7); - - res = mbedtls_pkcs7_parse_der(&pkcs7, second_buf, second_len); - -exit: - mbedtls_pkcs7_free(&pkcs7); - return res; -} -#endif /* END_SUITE_HELPERS */ /* BEGIN_CASE */ @@ -102,30 +79,36 @@ void pkcs7_parse_reuse(char *first_pkcs7_file, char *second_pkcs7_file, { unsigned char *first_pkcs7_buf = NULL; unsigned char *second_pkcs7_buf = NULL; + mbedtls_pkcs7 pkcs7; size_t first_buflen; size_t second_buflen; - int res; /* PKCS7 uses X509 which itself relies on PK under the hood and the latter * can use PSA to store keys and perform operations so psa_crypto_init() * must be called before. */ USE_PSA_INIT(); - res = mbedtls_pk_load_file(first_pkcs7_file, &first_pkcs7_buf, - &first_buflen); - TEST_EQUAL(res, 0); + mbedtls_pkcs7_init(&pkcs7); - res = mbedtls_pk_load_file(second_pkcs7_file, &second_pkcs7_buf, - &second_buflen); - TEST_EQUAL(res, 0); + TEST_EQUAL(mbedtls_pk_load_file(first_pkcs7_file, &first_pkcs7_buf, + &first_buflen), 0); - res = pkcs7_parse_buffers_reuse(first_pkcs7_buf, first_buflen, - second_pkcs7_buf, second_buflen); - TEST_EQUAL(res, res_expect); + TEST_EQUAL(mbedtls_pk_load_file(second_pkcs7_file, &second_pkcs7_buf, + &second_buflen), 0); + + TEST_EQUAL(mbedtls_pkcs7_parse_der(&pkcs7, first_pkcs7_buf, + first_buflen), + MBEDTLS_PKCS7_SIGNED_DATA); + + mbedtls_pkcs7_free(&pkcs7); + TEST_EQUAL(mbedtls_pkcs7_parse_der(&pkcs7, second_pkcs7_buf, + second_buflen), + res_expect); exit: mbedtls_free(first_pkcs7_buf); mbedtls_free(second_pkcs7_buf); + mbedtls_pkcs7_free(&pkcs7); USE_PSA_DONE(); } /* END_CASE */ From fbaf177f2d94da8fe2fbbbbd40c3128edaadeb82 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Tue, 2 Jun 2026 15:34:40 +0100 Subject: [PATCH 066/173] Fix style issues Signed-off-by: Ben Taylor --- tests/suites/test_suite_pkcs7.function | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/suites/test_suite_pkcs7.function b/tests/suites/test_suite_pkcs7.function index cdf221524e..3fccbaceaf 100644 --- a/tests/suites/test_suite_pkcs7.function +++ b/tests/suites/test_suite_pkcs7.function @@ -91,18 +91,18 @@ void pkcs7_parse_reuse(char *first_pkcs7_file, char *second_pkcs7_file, mbedtls_pkcs7_init(&pkcs7); TEST_EQUAL(mbedtls_pk_load_file(first_pkcs7_file, &first_pkcs7_buf, - &first_buflen), 0); + &first_buflen), 0); TEST_EQUAL(mbedtls_pk_load_file(second_pkcs7_file, &second_pkcs7_buf, - &second_buflen), 0); + &second_buflen), 0); TEST_EQUAL(mbedtls_pkcs7_parse_der(&pkcs7, first_pkcs7_buf, - first_buflen), + first_buflen), MBEDTLS_PKCS7_SIGNED_DATA); mbedtls_pkcs7_free(&pkcs7); TEST_EQUAL(mbedtls_pkcs7_parse_der(&pkcs7, second_pkcs7_buf, - second_buflen), + second_buflen), res_expect); exit: From 54284cc451fc6d07950817988a7002eaacbb5312 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Tue, 2 Jun 2026 15:35:08 +0100 Subject: [PATCH 067/173] Update ChangeLog Signed-off-by: Ben Taylor --- ChangeLog.d/pkcs-free-stale-pointers.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ChangeLog.d/pkcs-free-stale-pointers.txt b/ChangeLog.d/pkcs-free-stale-pointers.txt index 04ba823217..e283557b15 100644 --- a/ChangeLog.d/pkcs-free-stale-pointers.txt +++ b/ChangeLog.d/pkcs-free-stale-pointers.txt @@ -1,2 +1,4 @@ -Bugfix - * Add fix for stale pointer after mbedtls_pkcs7_free. +Security + * Fix a use-after-free/double-free risk in mbedtls_pkcs7_free() when reusing an mbedtls_pkcs7 context + across parse -> free -> parse -> free cycles. The function now clears the signer list after freeing it, + ensuring stale signed_data.signers.next pointers cannot be walked by a later free operation. From 15a63673738cb47812d41209d06dde8583eeae11 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Tue, 2 Jun 2026 15:38:02 +0100 Subject: [PATCH 068/173] Update ChangeLog Signed-off-by: Ben Taylor --- ChangeLog.d/pkcs-free-stale-pointers.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.d/pkcs-free-stale-pointers.txt b/ChangeLog.d/pkcs-free-stale-pointers.txt index e283557b15..72c673fac6 100644 --- a/ChangeLog.d/pkcs-free-stale-pointers.txt +++ b/ChangeLog.d/pkcs-free-stale-pointers.txt @@ -1,4 +1,4 @@ Security * Fix a use-after-free/double-free risk in mbedtls_pkcs7_free() when reusing an mbedtls_pkcs7 context - across parse -> free -> parse -> free cycles. The function now clears the signer list after freeing it, + across parse -> free -> parse -> free cycles. The function now resets the context after freeing it, ensuring stale signed_data.signers.next pointers cannot be walked by a later free operation. From 7448a04683ddb47e8042c8d584f4182ab31971d9 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Tue, 2 Jun 2026 15:47:08 +0100 Subject: [PATCH 069/173] Add further testing Signed-off-by: Ben Taylor --- tests/suites/test_suite_pkcs7.data | 8 ++++++ tests/suites/test_suite_pkcs7.function | 35 ++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/tests/suites/test_suite_pkcs7.data b/tests/suites/test_suite_pkcs7.data index 7e220fc2e6..88dc5f27ef 100644 --- a/tests/suites/test_suite_pkcs7.data +++ b/tests/suites/test_suite_pkcs7.data @@ -18,6 +18,14 @@ PKCS7 Signed Data Parse reused object after multiple signers depends_on:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY pkcs7_parse_reuse:"../framework/data_files/pkcs7_data_multiple_signed.der":"../framework/data_files/pkcs7_data_no_signers.der":MBEDTLS_PKCS7_SIGNED_DATA +PKCS7 Signed Data Parse reused object from multiple signers to one signer +depends_on:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY +pkcs7_parse_reuse:"../framework/data_files/pkcs7_data_multiple_signed.der":"../framework/data_files/pkcs7_data_cert_signed_sha256.der":MBEDTLS_PKCS7_SIGNED_DATA + +PKCS7 Signed Data Parse free resets context after multiple signers +depends_on:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY +pkcs7_parse_free_resets_context:"../framework/data_files/pkcs7_data_multiple_signed.der":MBEDTLS_PKCS7_SIGNED_DATA + PKCS7 Signed Data Parse Fail with multiple certs #4 depends_on:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY pkcs7_parse:"../framework/data_files/pkcs7_data_multiple_certs_signed.der":MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE diff --git a/tests/suites/test_suite_pkcs7.function b/tests/suites/test_suite_pkcs7.function index 3fccbaceaf..f6068879f8 100644 --- a/tests/suites/test_suite_pkcs7.function +++ b/tests/suites/test_suite_pkcs7.function @@ -83,13 +83,13 @@ void pkcs7_parse_reuse(char *first_pkcs7_file, char *second_pkcs7_file, size_t first_buflen; size_t second_buflen; + mbedtls_pkcs7_init(&pkcs7); + /* PKCS7 uses X509 which itself relies on PK under the hood and the latter * can use PSA to store keys and perform operations so psa_crypto_init() * must be called before. */ USE_PSA_INIT(); - mbedtls_pkcs7_init(&pkcs7); - TEST_EQUAL(mbedtls_pk_load_file(first_pkcs7_file, &first_pkcs7_buf, &first_buflen), 0); @@ -113,6 +113,37 @@ exit: } /* END_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_FS_IO */ +void pkcs7_parse_free_resets_context(char *pkcs7_file, int res_expect) +{ + unsigned char *pkcs7_buf = NULL; + mbedtls_pkcs7 pkcs7; + size_t buflen; + + mbedtls_pkcs7_init(&pkcs7); + + /* PKCS7 uses X509 which itself relies on PK under the hood and the latter + * can use PSA to store keys and perform operations so psa_crypto_init() + * must be called before. */ + USE_PSA_INIT(); + + TEST_EQUAL(mbedtls_pk_load_file(pkcs7_file, &pkcs7_buf, &buflen), 0); + + TEST_EQUAL(mbedtls_pkcs7_parse_der(&pkcs7, pkcs7_buf, buflen), + res_expect); + + mbedtls_pkcs7_free(&pkcs7); + + TEST_ASSERT(pkcs7.raw.p == NULL); + TEST_ASSERT(pkcs7.signed_data.signers.next == NULL); + +exit: + mbedtls_pkcs7_free(&pkcs7); + mbedtls_free(pkcs7_buf); + USE_PSA_DONE(); +} +/* END_CASE */ + /* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C:PSA_HAVE_ALG_SOME_RSA_VERIFY */ void pkcs7_verify(char *pkcs7_file, char *crt_files, From c4c4ef07c1cd93c5d6f93aee9834ba6c2ca5c0d7 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Wed, 3 Jun 2026 08:03:06 +0100 Subject: [PATCH 070/173] Correct changelog style Signed-off-by: Ben Taylor --- ChangeLog.d/pkcs-free-stale-pointers.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ChangeLog.d/pkcs-free-stale-pointers.txt b/ChangeLog.d/pkcs-free-stale-pointers.txt index 72c673fac6..68811c056c 100644 --- a/ChangeLog.d/pkcs-free-stale-pointers.txt +++ b/ChangeLog.d/pkcs-free-stale-pointers.txt @@ -1,4 +1,6 @@ Security - * Fix a use-after-free/double-free risk in mbedtls_pkcs7_free() when reusing an mbedtls_pkcs7 context - across parse -> free -> parse -> free cycles. The function now resets the context after freeing it, - ensuring stale signed_data.signers.next pointers cannot be walked by a later free operation. + * Fix a use-after-free/double-free risk in mbedtls_pkcs7_free() when reusing + an mbedtls_pkcs7 context across parse -> free -> parse -> free cycles. The + function now resets the context after freeing it, ensuring stale + signed_data.signers.next pointers cannot be walked by a later free + operation. From a74bbc78e6758e1b52ca81a82bbe9f6c2ec489f2 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Wed, 3 Jun 2026 10:24:27 +0100 Subject: [PATCH 071/173] Remove whitespace in ChangeLog Signed-off-by: Ben Taylor --- ChangeLog.d/pkcs-free-stale-pointers.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.d/pkcs-free-stale-pointers.txt b/ChangeLog.d/pkcs-free-stale-pointers.txt index 68811c056c..b56a62cc57 100644 --- a/ChangeLog.d/pkcs-free-stale-pointers.txt +++ b/ChangeLog.d/pkcs-free-stale-pointers.txt @@ -1,6 +1,6 @@ Security * Fix a use-after-free/double-free risk in mbedtls_pkcs7_free() when reusing an mbedtls_pkcs7 context across parse -> free -> parse -> free cycles. The - function now resets the context after freeing it, ensuring stale + function now resets the context after freeing it, ensuring stale signed_data.signers.next pointers cannot be walked by a later free operation. From 5dabb6453391ac958c52c732c2fe6272369a73b7 Mon Sep 17 00:00:00 2001 From: Ben Taylor <32939606+bjwtaylor@users.noreply.github.com> Date: Mon, 8 Jun 2026 15:49:42 +0100 Subject: [PATCH 072/173] Add CVE ID to ChangeLog Co-authored-by: Gilles Peskine Signed-off-by: Ben Taylor <32939606+bjwtaylor@users.noreply.github.com> --- ChangeLog.d/pkcs-free-stale-pointers.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.d/pkcs-free-stale-pointers.txt b/ChangeLog.d/pkcs-free-stale-pointers.txt index b56a62cc57..2c29fed5ef 100644 --- a/ChangeLog.d/pkcs-free-stale-pointers.txt +++ b/ChangeLog.d/pkcs-free-stale-pointers.txt @@ -3,4 +3,4 @@ Security an mbedtls_pkcs7 context across parse -> free -> parse -> free cycles. The function now resets the context after freeing it, ensuring stale signed_data.signers.next pointers cannot be walked by a later free - operation. + operation. CVE-2026-50579 From 37e0f109acfb4ea175c6353a7333da3a7d45fe6e Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Wed, 10 Jun 2026 10:17:48 +0100 Subject: [PATCH 073/173] Remove pkcs7_parse_free_resets_context as it duplicates pkcs7_parse_reuse Signed-off-by: Ben Taylor --- tests/suites/test_suite_pkcs7.data | 4 ---- tests/suites/test_suite_pkcs7.function | 31 -------------------------- 2 files changed, 35 deletions(-) diff --git a/tests/suites/test_suite_pkcs7.data b/tests/suites/test_suite_pkcs7.data index 88dc5f27ef..57f71841e2 100644 --- a/tests/suites/test_suite_pkcs7.data +++ b/tests/suites/test_suite_pkcs7.data @@ -22,10 +22,6 @@ PKCS7 Signed Data Parse reused object from multiple signers to one signer depends_on:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY pkcs7_parse_reuse:"../framework/data_files/pkcs7_data_multiple_signed.der":"../framework/data_files/pkcs7_data_cert_signed_sha256.der":MBEDTLS_PKCS7_SIGNED_DATA -PKCS7 Signed Data Parse free resets context after multiple signers -depends_on:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY -pkcs7_parse_free_resets_context:"../framework/data_files/pkcs7_data_multiple_signed.der":MBEDTLS_PKCS7_SIGNED_DATA - PKCS7 Signed Data Parse Fail with multiple certs #4 depends_on:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY pkcs7_parse:"../framework/data_files/pkcs7_data_multiple_certs_signed.der":MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE diff --git a/tests/suites/test_suite_pkcs7.function b/tests/suites/test_suite_pkcs7.function index f6068879f8..09968f5ddf 100644 --- a/tests/suites/test_suite_pkcs7.function +++ b/tests/suites/test_suite_pkcs7.function @@ -113,37 +113,6 @@ exit: } /* END_CASE */ -/* BEGIN_CASE depends_on:MBEDTLS_FS_IO */ -void pkcs7_parse_free_resets_context(char *pkcs7_file, int res_expect) -{ - unsigned char *pkcs7_buf = NULL; - mbedtls_pkcs7 pkcs7; - size_t buflen; - - mbedtls_pkcs7_init(&pkcs7); - - /* PKCS7 uses X509 which itself relies on PK under the hood and the latter - * can use PSA to store keys and perform operations so psa_crypto_init() - * must be called before. */ - USE_PSA_INIT(); - - TEST_EQUAL(mbedtls_pk_load_file(pkcs7_file, &pkcs7_buf, &buflen), 0); - - TEST_EQUAL(mbedtls_pkcs7_parse_der(&pkcs7, pkcs7_buf, buflen), - res_expect); - - mbedtls_pkcs7_free(&pkcs7); - - TEST_ASSERT(pkcs7.raw.p == NULL); - TEST_ASSERT(pkcs7.signed_data.signers.next == NULL); - -exit: - mbedtls_pkcs7_free(&pkcs7); - mbedtls_free(pkcs7_buf); - USE_PSA_DONE(); -} -/* END_CASE */ - /* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C:PSA_HAVE_ALG_SOME_RSA_VERIFY */ void pkcs7_verify(char *pkcs7_file, char *crt_files, From c20cd06cb41453ed29609c3cd9aacf24e54a7083 Mon Sep 17 00:00:00 2001 From: Ben Taylor <32939606+bjwtaylor@users.noreply.github.com> Date: Mon, 15 Jun 2026 11:52:52 +0100 Subject: [PATCH 074/173] Add in the two additional checks that were dropped. Co-authored-by: Ronald Cron Signed-off-by: Ben Taylor <32939606+bjwtaylor@users.noreply.github.com> --- tests/suites/test_suite_pkcs7.function | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/suites/test_suite_pkcs7.function b/tests/suites/test_suite_pkcs7.function index 09968f5ddf..3bd7595b96 100644 --- a/tests/suites/test_suite_pkcs7.function +++ b/tests/suites/test_suite_pkcs7.function @@ -101,6 +101,8 @@ void pkcs7_parse_reuse(char *first_pkcs7_file, char *second_pkcs7_file, MBEDTLS_PKCS7_SIGNED_DATA); mbedtls_pkcs7_free(&pkcs7); + TEST_ASSERT(pkcs7.raw.p == NULL); + TEST_ASSERT(pkcs7.signed_data.signers.next == NULL); TEST_EQUAL(mbedtls_pkcs7_parse_der(&pkcs7, second_pkcs7_buf, second_buflen), res_expect); From 833a926a92b13241131480cb5758143d94cc0fcb Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Fri, 29 May 2026 18:01:16 +0200 Subject: [PATCH 075/173] x509_crt: remove old invalid comment ssl_preset_default_hashes was removed in f0cda410a4bca0f45f66bdbf0714cd0eb2ea4718 but the comment in 'x509_crt.c' wasn't updated. Signed-off-by: Valerio Setti --- library/x509_crt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 093d733c1c..3938242298 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -87,8 +87,7 @@ typedef struct { * concerns. */ const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default = { - /* Hashes from SHA-256 and above. Note that this selection - * should be aligned with ssl_preset_default_hashes in ssl_tls.c. */ + /* Hashes from SHA-256 and above. */ MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512), From 227bb646b1e04a466ef65e3bb7a5d96e21d5fa0b Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Fri, 29 May 2026 18:02:59 +0200 Subject: [PATCH 076/173] x509_crt: add SHA3 algs to mbedtls_x509_crt_profile_default Signed-off-by: Valerio Setti --- library/x509_crt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 3938242298..e4fedb194a 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -90,7 +90,10 @@ const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default = /* Hashes from SHA-256 and above. */ MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) | - MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512), + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA3_256) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA3_384) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA3_512), 0xFFFFFFF, /* Any PK alg */ #if defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) /* Curves at or above 128-bit security level. Note that this selection From 9bcea79cb541870abcb54ff0bd88e907d0d69ccb Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Fri, 29 May 2026 18:17:52 +0200 Subject: [PATCH 077/173] x509: make profile checking functions internally available Following functions - x509_profile_check_md_alg - x509_profile_check_pk_alg are made non-static and moved to x509_internal.h so that other library files can used them. Signed-off-by: Valerio Setti --- library/x509_crt.c | 26 +++++++++----------------- library/x509_internal.h | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index e4fedb194a..a6fcd1b4e6 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -167,12 +167,8 @@ const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_none = (uint32_t) -1, }; -/* - * Check md_alg against profile - * Return 0 if md_alg is acceptable for this profile, -1 otherwise - */ -static int x509_profile_check_md_alg(const mbedtls_x509_crt_profile *profile, - mbedtls_md_type_t md_alg) +int mbedtls_x509_profile_check_md_alg(const mbedtls_x509_crt_profile *profile, + mbedtls_md_type_t md_alg) { if (md_alg == MBEDTLS_MD_NONE) { return -1; @@ -185,12 +181,8 @@ static int x509_profile_check_md_alg(const mbedtls_x509_crt_profile *profile, return -1; } -/* - * Check pk_alg against profile - * Return 0 if pk_alg is acceptable for this profile, -1 otherwise - */ -static int x509_profile_check_pk_alg(const mbedtls_x509_crt_profile *profile, - mbedtls_pk_sigalg_t pk_alg) +int mbedtls_x509_profile_check_pk_alg(const mbedtls_x509_crt_profile *profile, + mbedtls_pk_sigalg_t pk_alg) { if (pk_alg == MBEDTLS_PK_SIGALG_NONE) { return -1; @@ -2050,11 +2042,11 @@ static int x509_crt_verifycrl(mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, /* * Check if CRL is correctly signed by the trusted CA */ - if (x509_profile_check_md_alg(profile, crl_list->sig_md) != 0) { + if (mbedtls_x509_profile_check_md_alg(profile, crl_list->sig_md) != 0) { flags |= MBEDTLS_X509_BADCRL_BAD_MD; } - if (x509_profile_check_pk_alg(profile, crl_list->sig_pk) != 0) { + if (mbedtls_x509_profile_check_pk_alg(profile, crl_list->sig_pk) != 0) { flags |= MBEDTLS_X509_BADCRL_BAD_PK; } @@ -2563,11 +2555,11 @@ static int x509_crt_verify_chain( } /* Check signature algorithm: MD & PK algs */ - if (x509_profile_check_md_alg(profile, child->sig_md) != 0) { + if (mbedtls_x509_profile_check_md_alg(profile, child->sig_md) != 0) { *flags |= MBEDTLS_X509_BADCERT_BAD_MD; } - if (x509_profile_check_pk_alg(profile, child->sig_pk) != 0) { + if (mbedtls_x509_profile_check_pk_alg(profile, child->sig_pk) != 0) { *flags |= MBEDTLS_X509_BADCERT_BAD_PK; } @@ -3075,7 +3067,7 @@ static int x509_crt_verify_restartable_ca_cb(mbedtls_x509_crt *crt, /* Check the type and size of the key */ pk_type = mbedtls_pk_get_type(&crt->pk); - if (x509_profile_check_pk_alg(profile, (mbedtls_pk_sigalg_t) pk_type) != 0) { + if (mbedtls_x509_profile_check_pk_alg(profile, (mbedtls_pk_sigalg_t) pk_type) != 0) { ee_flags |= MBEDTLS_X509_BADCERT_BAD_PK; } diff --git a/library/x509_internal.h b/library/x509_internal.h index fcb996b19d..f68b6593bd 100644 --- a/library/x509_internal.h +++ b/library/x509_internal.h @@ -15,6 +15,7 @@ #include "mbedtls/private_access.h" #include "mbedtls/x509.h" +#include "mbedtls/x509_crt.h" #include "mbedtls/asn1.h" #include "pk_internal.h" // for a lot of things, including in SSL @@ -79,4 +80,18 @@ int mbedtls_x509_info_key_usage(char **buf, size_t *size, int mbedtls_x509_write_set_san_common(mbedtls_asn1_named_data **extensions, const mbedtls_x509_san_list *san_list); +/* + * Check md_alg against profile + * Return 0 if md_alg is acceptable for this profile, -1 otherwise + */ +int mbedtls_x509_profile_check_md_alg(const mbedtls_x509_crt_profile *profile, + mbedtls_md_type_t md_alg); + +/* + * Check pk_alg against profile + * Return 0 if pk_alg is acceptable for this profile, -1 otherwise + */ +int mbedtls_x509_profile_check_pk_alg(const mbedtls_x509_crt_profile *profile, + mbedtls_pk_sigalg_t pk_alg); + #endif /* MBEDTLS_X509_INTERNAL_H */ From b4d729fb02c111e1eaae29c43f0d1d18158f45f5 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Fri, 29 May 2026 18:22:51 +0200 Subject: [PATCH 078/173] pkcs7: fail verification if MD alg or sig_alg are not secure Add a check on mbedtls_pkcs7_data_or_hash_verify() so that the verification fails if the MD alg specified in PKCS7 structure or the signature algorithm specified in the X.509 certificate are not in the list of secure algorithms (i.e. mbedtls_x509_crt_profile_default). Signed-off-by: Valerio Setti --- library/pkcs7.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/pkcs7.c b/library/pkcs7.c index 2cc7812bf0..1e952998cc 100644 --- a/library/pkcs7.c +++ b/library/pkcs7.c @@ -665,6 +665,14 @@ static int mbedtls_pkcs7_data_or_hash_verify(mbedtls_pkcs7 *pkcs7, return ret; } + /* Ensure the MD alg from the PKCS#7 context and signature algorithm from + * the certificate belong to the list of secure algorithms + * (i.e. mbedtls_x509_crt_profile_default). */ + if (mbedtls_x509_profile_check_md_alg(&mbedtls_x509_crt_profile_default, md_alg) || + mbedtls_x509_profile_check_pk_alg(&mbedtls_x509_crt_profile_default, cert->sig_pk)) { + return MBEDTLS_ERR_PKCS7_VERIFY_FAIL; + } + md_info = mbedtls_md_info_from_type(md_alg); if (md_info == NULL) { return MBEDTLS_ERR_PKCS7_VERIFY_FAIL; From de9ee5d6eeac60bc2a13fd72bc661b5881e0c168 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Wed, 10 Jun 2026 12:03:27 +0200 Subject: [PATCH 079/173] tests: pkcs7: adjust return code in SHA-1 based PKCS7 test Signed-off-by: Valerio Setti --- tests/suites/test_suite_pkcs7.data | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/suites/test_suite_pkcs7.data b/tests/suites/test_suite_pkcs7.data index 3e3f7f1d7d..25659c2f29 100644 --- a/tests/suites/test_suite_pkcs7.data +++ b/tests/suites/test_suite_pkcs7.data @@ -86,9 +86,9 @@ PKCS7 Signed Data Verification Pass SHA256 #9.1 depends_on:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_sha256.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":MBEDTLS_MD_SHA256:0 -PKCS7 Signed Data Verification Pass SHA1 #10 +PKCS7 Signed Data Verification Fail SHA1 #10 depends_on:PSA_WANT_ALG_SHA_1:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY -pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_sha1.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:0 +pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_sha1.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:PSA_ERROR_INVALID_SIGNATURE PKCS7 Signed Data Verification Pass SHA512 #11 depends_on:PSA_WANT_ALG_SHA_512:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY From 2ae1ec8fdcd447352902f560735763b03f717625 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Wed, 10 Jun 2026 16:44:36 +0200 Subject: [PATCH 080/173] changelog: add note for PKCS7 rejecting weak hash algorithms Signed-off-by: Valerio Setti --- ChangeLog.d/pkcs7-reject-weak-hashes.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 ChangeLog.d/pkcs7-reject-weak-hashes.txt diff --git a/ChangeLog.d/pkcs7-reject-weak-hashes.txt b/ChangeLog.d/pkcs7-reject-weak-hashes.txt new file mode 100644 index 0000000000..61cc03affe --- /dev/null +++ b/ChangeLog.d/pkcs7-reject-weak-hashes.txt @@ -0,0 +1,3 @@ +Security + * PKCS7 now rejects weak hash algorithms (RIPEMD160, MD5, SHA-1) on signature + verification. From 9253f375c259deeaa9994e41454c1dceaae2a174 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Thu, 11 Jun 2026 17:15:14 +0200 Subject: [PATCH 081/173] tests: pkcs7: add negative tests using MD5 and RIPEMD160 Signed-off-by: Valerio Setti --- tests/suites/test_suite_pkcs7.data | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/suites/test_suite_pkcs7.data b/tests/suites/test_suite_pkcs7.data index 25659c2f29..301d95ed44 100644 --- a/tests/suites/test_suite_pkcs7.data +++ b/tests/suites/test_suite_pkcs7.data @@ -94,6 +94,14 @@ PKCS7 Signed Data Verification Pass SHA512 #11 depends_on:PSA_WANT_ALG_SHA_512:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_sha512.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:0 +PKCS7 Signed Data Verification Fail MD5 #12 +depends_on:PSA_WANT_ALG_SHA_1:PSA_WANT_ALG_MD5:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY +pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_md5.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:PSA_ERROR_INVALID_SIGNATURE + +PKCS7 Signed Data Verification Fail RIPEMD160 #13 +depends_on:PSA_WANT_ALG_SHA_1:PSA_WANT_ALG_RIPEMD160:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY +pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_ripemd160.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:PSA_ERROR_INVALID_SIGNATURE + PKCS7 Signed Data Verification Fail because of different certificate #12 depends_on:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_sha256.der":"../framework/data_files/pkcs7-rsa-sha256-2.der":"../framework/data_files/pkcs7_data.bin":0:MBEDTLS_ERR_RSA_VERIFY_FAILED From f27a1572e3393dbbe0d499ed57e529a7ceaf3688 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Mon, 15 Jun 2026 10:14:24 +0200 Subject: [PATCH 082/173] pkcs7: split MD/PK check in mbedtls_pkcs7_data_or_hash_verify Follow the default Mbed TLS coding style and ease debugging (i.e. placing of breakpoints). Signed-off-by: Valerio Setti --- library/pkcs7.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/pkcs7.c b/library/pkcs7.c index 1e952998cc..885ead6cb1 100644 --- a/library/pkcs7.c +++ b/library/pkcs7.c @@ -668,8 +668,12 @@ static int mbedtls_pkcs7_data_or_hash_verify(mbedtls_pkcs7 *pkcs7, /* Ensure the MD alg from the PKCS#7 context and signature algorithm from * the certificate belong to the list of secure algorithms * (i.e. mbedtls_x509_crt_profile_default). */ - if (mbedtls_x509_profile_check_md_alg(&mbedtls_x509_crt_profile_default, md_alg) || - mbedtls_x509_profile_check_pk_alg(&mbedtls_x509_crt_profile_default, cert->sig_pk)) { + ret = mbedtls_x509_profile_check_md_alg(&mbedtls_x509_crt_profile_default, md_alg); + if (ret != 0) { + return MBEDTLS_ERR_PKCS7_VERIFY_FAIL; + } + ret = mbedtls_x509_profile_check_pk_alg(&mbedtls_x509_crt_profile_default, cert->sig_pk); + if (ret != 0) { return MBEDTLS_ERR_PKCS7_VERIFY_FAIL; } From 7cc706ca5aaf3934d1ab79019fede78309a858dd Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Mon, 15 Jun 2026 10:24:39 +0200 Subject: [PATCH 083/173] pkcs7: replace MBEDTLS_ERR_PKCS7_VERIFY_FAIL with MBEDTLS_ERR_PKCS7_VERIFY_FAIL This also updates test data. Signed-off-by: Valerio Setti --- library/pkcs7.c | 4 ++-- tests/suites/test_suite_pkcs7.data | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/pkcs7.c b/library/pkcs7.c index 885ead6cb1..365f7eac64 100644 --- a/library/pkcs7.c +++ b/library/pkcs7.c @@ -670,11 +670,11 @@ static int mbedtls_pkcs7_data_or_hash_verify(mbedtls_pkcs7 *pkcs7, * (i.e. mbedtls_x509_crt_profile_default). */ ret = mbedtls_x509_profile_check_md_alg(&mbedtls_x509_crt_profile_default, md_alg); if (ret != 0) { - return MBEDTLS_ERR_PKCS7_VERIFY_FAIL; + return MBEDTLS_ERR_PKCS7_INVALID_ALG; } ret = mbedtls_x509_profile_check_pk_alg(&mbedtls_x509_crt_profile_default, cert->sig_pk); if (ret != 0) { - return MBEDTLS_ERR_PKCS7_VERIFY_FAIL; + return MBEDTLS_ERR_PKCS7_INVALID_ALG; } md_info = mbedtls_md_info_from_type(md_alg); diff --git a/tests/suites/test_suite_pkcs7.data b/tests/suites/test_suite_pkcs7.data index 301d95ed44..0cd899fc27 100644 --- a/tests/suites/test_suite_pkcs7.data +++ b/tests/suites/test_suite_pkcs7.data @@ -88,7 +88,7 @@ pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_sha256.der":"../fra PKCS7 Signed Data Verification Fail SHA1 #10 depends_on:PSA_WANT_ALG_SHA_1:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY -pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_sha1.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:PSA_ERROR_INVALID_SIGNATURE +pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_sha1.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:MBEDTLS_ERR_PKCS7_INVALID_ALG PKCS7 Signed Data Verification Pass SHA512 #11 depends_on:PSA_WANT_ALG_SHA_512:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY @@ -96,11 +96,11 @@ pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_sha512.der":"../fra PKCS7 Signed Data Verification Fail MD5 #12 depends_on:PSA_WANT_ALG_SHA_1:PSA_WANT_ALG_MD5:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY -pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_md5.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:PSA_ERROR_INVALID_SIGNATURE +pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_md5.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:MBEDTLS_ERR_PKCS7_INVALID_ALG PKCS7 Signed Data Verification Fail RIPEMD160 #13 depends_on:PSA_WANT_ALG_SHA_1:PSA_WANT_ALG_RIPEMD160:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY -pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_ripemd160.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:PSA_ERROR_INVALID_SIGNATURE +pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_ripemd160.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:MBEDTLS_ERR_PKCS7_INVALID_ALG PKCS7 Signed Data Verification Fail because of different certificate #12 depends_on:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY From 154e70b4444f105199cc2bb0649b77ef722b678f Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Mon, 15 Jun 2026 10:26:11 +0200 Subject: [PATCH 084/173] test_suite_pkcs7: adjust numbering of tests Some newly added tests had duplicate numbers with what was already there. This commit fixes the duplication problem. Signed-off-by: Valerio Setti --- tests/suites/test_suite_pkcs7.data | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/suites/test_suite_pkcs7.data b/tests/suites/test_suite_pkcs7.data index 0cd899fc27..46d4078fc0 100644 --- a/tests/suites/test_suite_pkcs7.data +++ b/tests/suites/test_suite_pkcs7.data @@ -90,18 +90,18 @@ PKCS7 Signed Data Verification Fail SHA1 #10 depends_on:PSA_WANT_ALG_SHA_1:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_sha1.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:MBEDTLS_ERR_PKCS7_INVALID_ALG -PKCS7 Signed Data Verification Pass SHA512 #11 -depends_on:PSA_WANT_ALG_SHA_512:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY -pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_sha512.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:0 - -PKCS7 Signed Data Verification Fail MD5 #12 +PKCS7 Signed Data Verification Fail MD5 #10.1 depends_on:PSA_WANT_ALG_SHA_1:PSA_WANT_ALG_MD5:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_md5.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:MBEDTLS_ERR_PKCS7_INVALID_ALG -PKCS7 Signed Data Verification Fail RIPEMD160 #13 +PKCS7 Signed Data Verification Fail RIPEMD160 #10.2 depends_on:PSA_WANT_ALG_SHA_1:PSA_WANT_ALG_RIPEMD160:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_ripemd160.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:MBEDTLS_ERR_PKCS7_INVALID_ALG +PKCS7 Signed Data Verification Pass SHA512 #11 +depends_on:PSA_WANT_ALG_SHA_512:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY +pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_sha512.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:0 + PKCS7 Signed Data Verification Fail because of different certificate #12 depends_on:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_sha256.der":"../framework/data_files/pkcs7-rsa-sha256-2.der":"../framework/data_files/pkcs7_data.bin":0:MBEDTLS_ERR_RSA_VERIFY_FAILED From eb8c3f4b4dc10b7bfd894d592414fb129f450a81 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Mon, 15 Jun 2026 10:34:22 +0200 Subject: [PATCH 085/173] changelog: update documentation for PKCS7 changes Signed-off-by: Valerio Setti --- ChangeLog.d/pkcs7-reject-weak-hashes.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ChangeLog.d/pkcs7-reject-weak-hashes.txt b/ChangeLog.d/pkcs7-reject-weak-hashes.txt index 61cc03affe..a62cca9b96 100644 --- a/ChangeLog.d/pkcs7-reject-weak-hashes.txt +++ b/ChangeLog.d/pkcs7-reject-weak-hashes.txt @@ -1,3 +1,7 @@ Security - * PKCS7 now rejects weak hash algorithms (RIPEMD160, MD5, SHA-1) on signature - verification. + * PKCS7 now rejects weak hash algorithms (RIPEMD160, MD5, SHA-1, SHA-224, + SHA3-224) on signature verification. + +Features + * SHA3-256, SHA3-384 and SHA3-512 are now accepted in the default X.509 + certificate profile. From d0e97ad6d8fd3a4df022427c0f6f1e4f721f049b Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Mon, 15 Jun 2026 10:49:56 +0200 Subject: [PATCH 086/173] pkcs7: update documentation adding a note about rejecting weak hash algs Signed-off-by: Valerio Setti --- include/mbedtls/pkcs7.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/mbedtls/pkcs7.h b/include/mbedtls/pkcs7.h index 957ca53d71..aa9764e19a 100644 --- a/include/mbedtls/pkcs7.h +++ b/include/mbedtls/pkcs7.h @@ -31,6 +31,10 @@ * assumed these fields are empty. * - The RFC allows for the signed Data type to contain contentInfo. This * implementation assumes the type is DATA and the content is empty. + * - The RFC doesn't put any constrain on the hash algorithm to be used, but + * this implementation rejects weak hash algorithms (i.e. RIPEMD160, MD5, + * SHA-1, SHA-224, SHA3-224). In general accepted hash and PK algorithms are + * the ones belonging to `mbedtls_x509_crt_profile_default`. */ #ifndef MBEDTLS_PKCS7_H @@ -190,6 +194,9 @@ int mbedtls_pkcs7_parse_der(mbedtls_pkcs7 *pkcs7, const unsigned char *buf, * \note This function internally calculates the hash on the supplied * plain data for signature verification. * + * \note For limitation on the supported hash algorithms, please refer + * to the note at the top of this document. + * * \return 0 if the signature verifies, or a negative error code on failure. */ int mbedtls_pkcs7_signed_data_verify(mbedtls_pkcs7 *pkcs7, @@ -219,6 +226,9 @@ int mbedtls_pkcs7_signed_data_verify(mbedtls_pkcs7 *pkcs7, * \note This function is different from mbedtls_pkcs7_signed_data_verify() * in that it is directly passed the hash of the data. * + * \note For limitation on the supported hash algorithms, please refer + * to the note at the top of this document. + * * \return 0 if the signature verifies, or a negative error code on failure. */ int mbedtls_pkcs7_signed_hash_verify(mbedtls_pkcs7 *pkcs7, From 269312540c1a0ea6e9026ac1e3e87a4409266714 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Tue, 16 Jun 2026 11:43:41 +0200 Subject: [PATCH 087/173] tests: pkcs7: adjust test dependencies Newly added tests for RIPEMD160 and MD5 still require SHA-256 for the certificate being used. SHA-1 is instead useless in this case. Signed-off-by: Valerio Setti --- tests/suites/test_suite_pkcs7.data | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/suites/test_suite_pkcs7.data b/tests/suites/test_suite_pkcs7.data index 46d4078fc0..86dc4ed844 100644 --- a/tests/suites/test_suite_pkcs7.data +++ b/tests/suites/test_suite_pkcs7.data @@ -91,11 +91,11 @@ depends_on:PSA_WANT_ALG_SHA_1:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VER pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_sha1.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:MBEDTLS_ERR_PKCS7_INVALID_ALG PKCS7 Signed Data Verification Fail MD5 #10.1 -depends_on:PSA_WANT_ALG_SHA_1:PSA_WANT_ALG_MD5:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY +depends_on:PSA_WANT_ALG_MD5:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_md5.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:MBEDTLS_ERR_PKCS7_INVALID_ALG PKCS7 Signed Data Verification Fail RIPEMD160 #10.2 -depends_on:PSA_WANT_ALG_SHA_1:PSA_WANT_ALG_RIPEMD160:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY +depends_on:PSA_WANT_ALG_RIPEMD160:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_ripemd160.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:MBEDTLS_ERR_PKCS7_INVALID_ALG PKCS7 Signed Data Verification Pass SHA512 #11 From 4b193e5f8049241dfb90eb34a1bf5048c7bfa6c7 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Thu, 11 Jun 2026 17:13:08 +0200 Subject: [PATCH 088/173] framework: update reference Signed-off-by: Valerio Setti --- framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework b/framework index e0f6275eff..d6dec17adf 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit e0f6275eff2e45e295fdd6b6877de4cbdaddae83 +Subproject commit d6dec17adfb5bf283c6a7a5bb6c451ecdc0b8201 From 0b556f5a2deb146690a93907264ce81f381a4a6a Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Wed, 10 Jun 2026 15:59:50 +0200 Subject: [PATCH 089/173] pkcs7: add MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES build symbol It allows weak hash algorithms to be used in PKCS7. It's only added in the LTS branch for backward compatibility, but it's disabled by default because that's the safest choice. This commit also updates test data in order to test the new build symbol. Signed-off-by: Valerio Setti --- ChangeLog.d/pkcs7-reject-weak-hashes.txt | 4 +++- include/mbedtls/mbedtls_config.h | 9 +++++++++ library/pkcs7.c | 2 ++ tests/suites/test_suite_pkcs7.data | 18 +++++++++++++++--- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/ChangeLog.d/pkcs7-reject-weak-hashes.txt b/ChangeLog.d/pkcs7-reject-weak-hashes.txt index a62cca9b96..659b0a65c5 100644 --- a/ChangeLog.d/pkcs7-reject-weak-hashes.txt +++ b/ChangeLog.d/pkcs7-reject-weak-hashes.txt @@ -1,6 +1,8 @@ Security * PKCS7 now rejects weak hash algorithms (RIPEMD160, MD5, SHA-1, SHA-224, - SHA3-224) on signature verification. + SHA3-224) on signature verification. Build symbol + MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES allows to keep using weak hash + algorithms in PKCS7 for backward compatibility purposes. Features * SHA3-256, SHA3-384 and SHA3-512 are now accepted in the default X.509 diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h index a38b61c147..038a483de3 100644 --- a/include/mbedtls/mbedtls_config.h +++ b/include/mbedtls/mbedtls_config.h @@ -1036,6 +1036,15 @@ */ #define MBEDTLS_PKCS7_C +/** + * \def MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES + * + * Allow weak signature algorithms (RIPEMD160, MD5, SHA-1) in PKCS#7. + * + * Requires: MBEDTLS_PKCS7_C + */ +// #define MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES + /** * \def MBEDTLS_X509_CREATE_C * diff --git a/library/pkcs7.c b/library/pkcs7.c index 365f7eac64..339f342008 100644 --- a/library/pkcs7.c +++ b/library/pkcs7.c @@ -665,6 +665,7 @@ static int mbedtls_pkcs7_data_or_hash_verify(mbedtls_pkcs7 *pkcs7, return ret; } +#if !defined(MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES) /* Ensure the MD alg from the PKCS#7 context and signature algorithm from * the certificate belong to the list of secure algorithms * (i.e. mbedtls_x509_crt_profile_default). */ @@ -676,6 +677,7 @@ static int mbedtls_pkcs7_data_or_hash_verify(mbedtls_pkcs7 *pkcs7, if (ret != 0) { return MBEDTLS_ERR_PKCS7_INVALID_ALG; } +#endif /* MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES */ md_info = mbedtls_md_info_from_type(md_alg); if (md_info == NULL) { diff --git a/tests/suites/test_suite_pkcs7.data b/tests/suites/test_suite_pkcs7.data index 86dc4ed844..bb94fc216d 100644 --- a/tests/suites/test_suite_pkcs7.data +++ b/tests/suites/test_suite_pkcs7.data @@ -87,17 +87,29 @@ depends_on:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_sha256.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":MBEDTLS_MD_SHA256:0 PKCS7 Signed Data Verification Fail SHA1 #10 -depends_on:PSA_WANT_ALG_SHA_1:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY +depends_on:PSA_WANT_ALG_SHA_1:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY:!MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_sha1.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:MBEDTLS_ERR_PKCS7_INVALID_ALG +PKCS7 Signed Data Verification Pass SHA1 #10 +depends_on:PSA_WANT_ALG_SHA_1:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY:MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES +pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_sha1.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:0 + PKCS7 Signed Data Verification Fail MD5 #10.1 -depends_on:PSA_WANT_ALG_MD5:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY +depends_on:PSA_WANT_ALG_MD5:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY:!MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_md5.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:MBEDTLS_ERR_PKCS7_INVALID_ALG +PKCS7 Signed Data Verification Pass MD5 #10.1 +depends_on:PSA_WANT_ALG_MD5:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY:MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES +pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_md5.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:0 + PKCS7 Signed Data Verification Fail RIPEMD160 #10.2 -depends_on:PSA_WANT_ALG_RIPEMD160:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY +depends_on:PSA_WANT_ALG_RIPEMD160:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY:!MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_ripemd160.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:MBEDTLS_ERR_PKCS7_INVALID_ALG +PKCS7 Signed Data Verification Pass RIPEMD160 #10.2 +depends_on:PSA_WANT_ALG_RIPEMD160:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY:MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES +pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_ripemd160.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:0 + PKCS7 Signed Data Verification Pass SHA512 #11 depends_on:PSA_WANT_ALG_SHA_512:PSA_WANT_ALG_SHA_256:PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY pkcs7_verify:"../framework/data_files/pkcs7_data_cert_signed_sha512.der":"../framework/data_files/pkcs7-rsa-sha256-1.der":"../framework/data_files/pkcs7_data.bin":0:0 From 4008c7f811a6ce2c4090aeceef531dc9463c34eb Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Thu, 18 Jun 2026 10:19:07 +0200 Subject: [PATCH 090/173] pkcs7: mention MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES in pkcs7.h documentation Signed-off-by: Valerio Setti --- include/mbedtls/pkcs7.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/mbedtls/pkcs7.h b/include/mbedtls/pkcs7.h index aa9764e19a..ab569da2e6 100644 --- a/include/mbedtls/pkcs7.h +++ b/include/mbedtls/pkcs7.h @@ -32,9 +32,11 @@ * - The RFC allows for the signed Data type to contain contentInfo. This * implementation assumes the type is DATA and the content is empty. * - The RFC doesn't put any constrain on the hash algorithm to be used, but - * this implementation rejects weak hash algorithms (i.e. RIPEMD160, MD5, - * SHA-1, SHA-224, SHA3-224). In general accepted hash and PK algorithms are - * the ones belonging to `mbedtls_x509_crt_profile_default`. + * this implementation by default rejects weak hash algorithms (i.e. RIPEMD160, + * MD5, SHA-1, SHA-224, SHA3-224). In general accepted hash and PK algorithms + * are the ones belonging to `mbedtls_x509_crt_profile_default`. + * MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES can be enabled to remove the limitation + * on weak hash algorithms. */ #ifndef MBEDTLS_PKCS7_H From dfa6a1441eeb5b0b1314dcdb1c2c16ef49e03b4f Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Thu, 18 Jun 2026 17:48:24 +0200 Subject: [PATCH 091/173] pkcs7: improve documentation and changelog for MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES Signed-off-by: Valerio Setti --- ChangeLog.d/pkcs7-reject-weak-hashes.txt | 2 +- include/mbedtls/pkcs7.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ChangeLog.d/pkcs7-reject-weak-hashes.txt b/ChangeLog.d/pkcs7-reject-weak-hashes.txt index 659b0a65c5..ce3f295db1 100644 --- a/ChangeLog.d/pkcs7-reject-weak-hashes.txt +++ b/ChangeLog.d/pkcs7-reject-weak-hashes.txt @@ -1,6 +1,6 @@ Security * PKCS7 now rejects weak hash algorithms (RIPEMD160, MD5, SHA-1, SHA-224, - SHA3-224) on signature verification. Build symbol + SHA3-224) on signature verification. The new configuration option MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES allows to keep using weak hash algorithms in PKCS7 for backward compatibility purposes. diff --git a/include/mbedtls/pkcs7.h b/include/mbedtls/pkcs7.h index ab569da2e6..644969b876 100644 --- a/include/mbedtls/pkcs7.h +++ b/include/mbedtls/pkcs7.h @@ -34,9 +34,9 @@ * - The RFC doesn't put any constrain on the hash algorithm to be used, but * this implementation by default rejects weak hash algorithms (i.e. RIPEMD160, * MD5, SHA-1, SHA-224, SHA3-224). In general accepted hash and PK algorithms - * are the ones belonging to `mbedtls_x509_crt_profile_default`. - * MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES can be enabled to remove the limitation - * on weak hash algorithms. + * are the ones belonging to ::mbedtls_x509_crt_profile_default. + * #MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES can be enabled to accept all + * supported hash algorithms. */ #ifndef MBEDTLS_PKCS7_H From ba5c9383abe89399836b11921fab1c2a07a8d571 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Thu, 18 Jun 2026 17:49:29 +0200 Subject: [PATCH 092/173] config-options-current: add new symbol MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES Signed-off-by: Valerio Setti --- scripts/data_files/config-options-current.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/data_files/config-options-current.txt b/scripts/data_files/config-options-current.txt index 81b233804c..bd18a1cc76 100644 --- a/scripts/data_files/config-options-current.txt +++ b/scripts/data_files/config-options-current.txt @@ -9,6 +9,7 @@ MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_NET_C +MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES MBEDTLS_PKCS7_C MBEDTLS_PSK_MAX_LEN MBEDTLS_SSL_ALL_ALERT_MESSAGES From 5b67d61d0281a4456986d18dbe49a0fa3d06431e Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Thu, 18 Jun 2026 17:55:38 +0200 Subject: [PATCH 093/173] pkcs7: do not mention PK algorithms in the documentation Signed-off-by: Valerio Setti --- include/mbedtls/pkcs7.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mbedtls/pkcs7.h b/include/mbedtls/pkcs7.h index 644969b876..f2da99021c 100644 --- a/include/mbedtls/pkcs7.h +++ b/include/mbedtls/pkcs7.h @@ -33,7 +33,7 @@ * implementation assumes the type is DATA and the content is empty. * - The RFC doesn't put any constrain on the hash algorithm to be used, but * this implementation by default rejects weak hash algorithms (i.e. RIPEMD160, - * MD5, SHA-1, SHA-224, SHA3-224). In general accepted hash and PK algorithms + * MD5, SHA-1, SHA-224, SHA3-224). In general accepted hash algorithms * are the ones belonging to ::mbedtls_x509_crt_profile_default. * #MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES can be enabled to accept all * supported hash algorithms. From 5998104fd60d3da3344dbf8992647e75158437d6 Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Mon, 22 Jun 2026 22:29:15 +0100 Subject: [PATCH 094/173] Added CVE Signed-off-by: Minos Galanakis --- ChangeLog.d/tls13-hrr-selected-group.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.d/tls13-hrr-selected-group.txt b/ChangeLog.d/tls13-hrr-selected-group.txt index 20d7a18fbd..c318b393fc 100644 --- a/ChangeLog.d/tls13-hrr-selected-group.txt +++ b/ChangeLog.d/tls13-hrr-selected-group.txt @@ -2,4 +2,4 @@ Security * Fix TLS 1.3 clients to reject a HelloRetryRequest whose selected group was not advertised in the original ClientHello. Reported by Din Asotić / Xiangdong Li, Beijing University of Posts and - Telecommunications (BUPT) + Telecommunications (BUPT). CVE-2026-25832 From a6d2af8cdb8a46990715365df13e9fd1ef105d6c Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Mon, 22 Jun 2026 22:32:25 +0100 Subject: [PATCH 095/173] Added attribution Signed-off-by: Minos Galanakis --- ChangeLog.d/tls13-hrr-selected-group.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ChangeLog.d/tls13-hrr-selected-group.txt b/ChangeLog.d/tls13-hrr-selected-group.txt index c318b393fc..4c338480f6 100644 --- a/ChangeLog.d/tls13-hrr-selected-group.txt +++ b/ChangeLog.d/tls13-hrr-selected-group.txt @@ -1,5 +1,7 @@ Security * Fix TLS 1.3 clients to reject a HelloRetryRequest whose selected group was - not advertised in the original ClientHello. Reported by + not advertised in the original ClientHello. Reported independently by Din Asotić / Xiangdong Li, Beijing University of Posts and - Telecommunications (BUPT). CVE-2026-25832 + Telecommunications (BUPT), and NVIDIA Project Vanessa. + CVE-2026-25832. + From 4e26c248ec9541b95d3e3e0178960f53d8bb40b8 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 14 May 2026 11:27:05 +0100 Subject: [PATCH 096/173] ssl: propagate transcript-hash computation failures Signed-off-by: Ben Taylor --- library/ssl_tls.c | 1 + library/ssl_tls13_server.c | 1 + 2 files changed, 2 insertions(+) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index e8a44f834c..7ddaa12202 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -6297,6 +6297,7 @@ static int ssl_compute_master(mbedtls_ssl_handshake_params *handshake, ret = handshake->calc_verify(ssl, session_hash, &seed_len); if (ret != 0) { MBEDTLS_SSL_DEBUG_RET(1, "calc_verify", ret); + return ret; } MBEDTLS_SSL_DEBUG_BUF(3, "session hash for extended master secret", diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index 37fdf79ee3..38f2fe9370 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -3077,6 +3077,7 @@ static int ssl_tls13_process_client_finished(mbedtls_ssl_context *ssl) if (ret != 0) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_compute_resumption_master_secret", ret); + return ret; } mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_HANDSHAKE_WRAPUP); From 591a5f24c22cd6ffd2d66472b29d66a9f95d47bb Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 14 May 2026 11:27:15 +0100 Subject: [PATCH 097/173] tests: ssl: add regression tests for EMS/RMS error propagation Signed-off-by: Ben Taylor --- tests/suites/test_suite_ssl.data | 6 + tests/suites/test_suite_ssl.function | 185 +++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 9bf4c1f0bf..ef6ac36909 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3378,6 +3378,12 @@ elliptic_curve_get_properties TLS 1.3 resume session with ticket tls13_resume_session_with_ticket +TLS 1.3 server propagates RMS computation error +tls13_server_propagates_rms_error + +TLS 1.2 server propagates EMS computation error +tls12_server_propagates_ems_error + TLS 1.3 read early data, early data accepted tls13_read_early_data:TEST_EARLY_DATA_ACCEPTED diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index cc73f49aaf..09cd48a525 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -55,6 +55,163 @@ static int failing_ticket_write_unset_lifetime( PSA_WANT_ALG_SHA_256 && PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY && MBEDTLS_CAN_HANDLE_RSA_TEST_KEY */ +#if defined(MBEDTLS_SSL_CLI_C) && \ + defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_DEBUG_C) && \ + defined(PSA_HAVE_ALG_SOME_RSA_SIGN) && \ + ((defined(MBEDTLS_SSL_PROTO_TLS1_3) && \ + defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED) && \ + defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED) && \ + defined(MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE) && \ + defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED) && \ + defined(PSA_WANT_ALG_SHA_256) && \ + defined(PSA_WANT_ECC_SECP_R1_256) && \ + defined(PSA_WANT_ECC_SECP_R1_384) && \ + defined(PSA_HAVE_ALG_ECDSA_VERIFY) && \ + defined(MBEDTLS_SSL_SESSION_TICKETS)) || \ + (defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) && \ + defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED) && \ + defined(PSA_WANT_ALG_SHA_256) && \ + defined(PSA_WANT_ECC_SECP_R1_384) && \ + defined(PSA_HAVE_ALG_ECDSA_VERIFY))) +typedef struct { + mbedtls_ssl_context *ssl; + const char *trigger; + int triggered; +} tls_abort_transcript_context; + +static void tls_abort_transcript(void *ctx, int level, + const char *file, int line, + const char *str) +{ + tls_abort_transcript_context *abort_ctx = ctx; + + (void) level; + (void) file; + (void) line; + + if (abort_ctx->triggered || abort_ctx->ssl == NULL || + abort_ctx->ssl->handshake == NULL || + abort_ctx->trigger == NULL || + strstr(str, abort_ctx->trigger) == NULL) { + return; + } + + abort_ctx->triggered = 1; + psa_hash_abort(&abort_ctx->ssl->handshake->fin_sha256_psa); +#if defined(PSA_WANT_ALG_SHA_384) + psa_hash_abort(&abort_ctx->ssl->handshake->fin_sha384_psa); +#endif +} + +static void tls_server_error(mbedtls_ssl_protocol_version tls_version, + const char *trigger, + int server_state, + int client_state) +{ + int ret = -1; + int max_steps = 100; + mbedtls_test_ssl_endpoint client_ep, server_ep; + mbedtls_test_handshake_test_options client_options; + mbedtls_test_handshake_test_options server_options; + tls_abort_transcript_context abort_ctx; + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3) + unsigned char psk[] = "abcdefghijklmnop"; + data_t psk_data = { psk, sizeof(psk) - 1 }; +#endif + + memset(&client_ep, 0, sizeof(client_ep)); + memset(&server_ep, 0, sizeof(server_ep)); + memset(&abort_ctx, 0, sizeof(abort_ctx)); + mbedtls_test_init_handshake_options(&client_options); + mbedtls_test_init_handshake_options(&server_options); + + PSA_INIT(); + + client_options.client_min_version = tls_version; + client_options.client_max_version = tls_version; + server_options.server_min_version = tls_version; + server_options.server_max_version = tls_version; + + abort_ctx.trigger = trigger; + server_options.srv_log_obj = &abort_ctx; + server_options.srv_log_fun = tls_abort_transcript; + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3) + if (tls_version == MBEDTLS_SSL_VERSION_TLS1_3) { + client_options.psk_str = &psk_data; + } +#endif + + mbedtls_debug_set_threshold(4); + + TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT, + &client_options), 0); + TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER, + &server_options), 0); + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS) + if (tls_version == MBEDTLS_SSL_VERSION_TLS1_3) { + TEST_EQUAL(mbedtls_ssl_conf_psk(&server_ep.conf, psk, sizeof(psk) - 1, + (const unsigned char *) "foo", + strlen("foo")), 0); + mbedtls_ssl_conf_tls13_key_exchange_modes( + &client_ep.conf, MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK); + mbedtls_ssl_conf_tls13_key_exchange_modes( + &server_ep.conf, MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK); + mbedtls_ssl_conf_session_tickets_cb(&server_ep.conf, + mbedtls_test_ticket_write, + mbedtls_test_ticket_parse, + NULL); + } +#endif + + TEST_EQUAL(mbedtls_test_mock_socket_connect(&(client_ep.socket), + &(server_ep.socket), 1024), 0); + + abort_ctx.ssl = &server_ep.ssl; + + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + &(server_ep.ssl), &(client_ep.ssl), + server_state), 0); + + TEST_EQUAL(mbedtls_ssl_flush_output(&(server_ep.ssl)), 0); + + TEST_EQUAL(server_ep.ssl.state, server_state); + + TEST_EQUAL(abort_ctx.triggered, 0); + + while (client_ep.ssl.state != client_state && + --max_steps >= 0) { + ret = mbedtls_ssl_handshake_step(&(client_ep.ssl)); + TEST_ASSERT(ret == 0 || ret == MBEDTLS_ERR_SSL_WANT_READ || + ret == MBEDTLS_ERR_SSL_WANT_WRITE); + } + + TEST_ASSERT(max_steps >= 0); + + TEST_EQUAL(client_ep.ssl.state, client_state); + TEST_EQUAL(server_ep.ssl.state, server_state); + + TEST_EQUAL(abort_ctx.triggered, 0); + + ret = mbedtls_ssl_handshake_step(&(server_ep.ssl)); + TEST_ASSERT(abort_ctx.triggered); + TEST_ASSERT(ret != 0); + + TEST_EQUAL(server_ep.ssl.state, server_state); + +exit: + mbedtls_test_ssl_endpoint_free(&client_ep); + mbedtls_test_ssl_endpoint_free(&server_ep); + mbedtls_test_free_handshake_options(&client_options); + mbedtls_test_free_handshake_options(&server_options); + mbedtls_debug_set_threshold(0); + PSA_DONE(); +} +#endif + #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) && \ @@ -4358,6 +4515,34 @@ exit: } /* END_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_DEBUG_C:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED:PSA_WANT_ALG_SHA_256:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ECC_SECP_R1_384:PSA_HAVE_ALG_ECDSA_VERIFY:PSA_HAVE_ALG_SOME_RSA_SIGN:MBEDTLS_SSL_SESSION_TICKETS */ +void tls13_server_propagates_rms_error() +{ + tls_server_error(MBEDTLS_SSL_VERSION_TLS1_3, + "<= parse finished message", + MBEDTLS_SSL_CLIENT_FINISHED, + MBEDTLS_SSL_FLUSH_BUFFERS); + goto exit; + +exit: + ; +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_DEBUG_C:MBEDTLS_SSL_EXTENDED_MASTER_SECRET:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:PSA_WANT_ALG_SHA_256:PSA_WANT_ECC_SECP_R1_384:PSA_HAVE_ALG_ECDSA_VERIFY:PSA_HAVE_ALG_SOME_RSA_SIGN:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED */ +void tls12_server_propagates_ems_error() +{ + tls_server_error(MBEDTLS_SSL_VERSION_TLS1_2, + "=> derive keys", + MBEDTLS_SSL_CLIENT_KEY_EXCHANGE, + MBEDTLS_SSL_CERTIFICATE_VERIFY); + goto exit; + +exit: + ; +} +/* END_CASE */ + /* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED:PSA_WANT_ALG_SHA_256:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ECC_SECP_R1_384:PSA_HAVE_ALG_ECDSA_VERIFY:MBEDTLS_SSL_SESSION_TICKETS */ void tls13_resume_session_with_ticket() { From 762b68fe267083ff50f9c27a9bf058cc91533e1b Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Fri, 15 May 2026 18:42:45 +0200 Subject: [PATCH 098/173] Improve dependencies and error handling Signed-off-by: Ben Taylor --- tests/suites/test_suite_ssl.data | 6 +- tests/suites/test_suite_ssl.function | 215 +++++++++------------------ 2 files changed, 72 insertions(+), 149 deletions(-) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index ef6ac36909..c93ff542e9 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3379,10 +3379,12 @@ TLS 1.3 resume session with ticket tls13_resume_session_with_ticket TLS 1.3 server propagates RMS computation error -tls13_server_propagates_rms_error +depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT +tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_3:"<= parse finished message":MBEDTLS_SSL_CLIENT_FINISHED:MBEDTLS_SSL_FLUSH_BUFFERS TLS 1.2 server propagates EMS computation error -tls12_server_propagates_ems_error +depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_2:"=> derive keys":MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:MBEDTLS_SSL_CERTIFICATE_VERIFY TLS 1.3 read early data, early data accepted tls13_read_early_data:TEST_EARLY_DATA_ACCEPTED diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 09cd48a525..a68a6fcf3f 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -55,25 +55,11 @@ static int failing_ticket_write_unset_lifetime( PSA_WANT_ALG_SHA_256 && PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY && MBEDTLS_CAN_HANDLE_RSA_TEST_KEY */ -#if defined(MBEDTLS_SSL_CLI_C) && \ - defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_DEBUG_C) && \ - defined(PSA_HAVE_ALG_SOME_RSA_SIGN) && \ - ((defined(MBEDTLS_SSL_PROTO_TLS1_3) && \ +#if defined(MBEDTLS_SSL_TLS_C) && defined(MBEDTLS_DEBUG_C) && \ + defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_SRV_C) && \ defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED) && \ - defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED) && \ - defined(MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE) && \ - defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED) && \ - defined(PSA_WANT_ALG_SHA_256) && \ - defined(PSA_WANT_ECC_SECP_R1_256) && \ - defined(PSA_WANT_ECC_SECP_R1_384) && \ - defined(PSA_HAVE_ALG_ECDSA_VERIFY) && \ - defined(MBEDTLS_SSL_SESSION_TICKETS)) || \ - (defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ - defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) && \ - defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED) && \ - defined(PSA_WANT_ALG_SHA_256) && \ - defined(PSA_WANT_ECC_SECP_R1_384) && \ - defined(PSA_HAVE_ALG_ECDSA_VERIFY))) + defined(MBEDTLS_TEST_HAS_DEFAULT_EC_GROUP) && \ + defined(PSA_WANT_ALG_SHA_256) typedef struct { mbedtls_ssl_context *ssl; const char *trigger; @@ -103,113 +89,6 @@ static void tls_abort_transcript(void *ctx, int level, psa_hash_abort(&abort_ctx->ssl->handshake->fin_sha384_psa); #endif } - -static void tls_server_error(mbedtls_ssl_protocol_version tls_version, - const char *trigger, - int server_state, - int client_state) -{ - int ret = -1; - int max_steps = 100; - mbedtls_test_ssl_endpoint client_ep, server_ep; - mbedtls_test_handshake_test_options client_options; - mbedtls_test_handshake_test_options server_options; - tls_abort_transcript_context abort_ctx; - -#if defined(MBEDTLS_SSL_PROTO_TLS1_3) - unsigned char psk[] = "abcdefghijklmnop"; - data_t psk_data = { psk, sizeof(psk) - 1 }; -#endif - - memset(&client_ep, 0, sizeof(client_ep)); - memset(&server_ep, 0, sizeof(server_ep)); - memset(&abort_ctx, 0, sizeof(abort_ctx)); - mbedtls_test_init_handshake_options(&client_options); - mbedtls_test_init_handshake_options(&server_options); - - PSA_INIT(); - - client_options.client_min_version = tls_version; - client_options.client_max_version = tls_version; - server_options.server_min_version = tls_version; - server_options.server_max_version = tls_version; - - abort_ctx.trigger = trigger; - server_options.srv_log_obj = &abort_ctx; - server_options.srv_log_fun = tls_abort_transcript; - -#if defined(MBEDTLS_SSL_PROTO_TLS1_3) - if (tls_version == MBEDTLS_SSL_VERSION_TLS1_3) { - client_options.psk_str = &psk_data; - } -#endif - - mbedtls_debug_set_threshold(4); - - TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT, - &client_options), 0); - TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER, - &server_options), 0); - -#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS) - if (tls_version == MBEDTLS_SSL_VERSION_TLS1_3) { - TEST_EQUAL(mbedtls_ssl_conf_psk(&server_ep.conf, psk, sizeof(psk) - 1, - (const unsigned char *) "foo", - strlen("foo")), 0); - mbedtls_ssl_conf_tls13_key_exchange_modes( - &client_ep.conf, MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK); - mbedtls_ssl_conf_tls13_key_exchange_modes( - &server_ep.conf, MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK); - mbedtls_ssl_conf_session_tickets_cb(&server_ep.conf, - mbedtls_test_ticket_write, - mbedtls_test_ticket_parse, - NULL); - } -#endif - - TEST_EQUAL(mbedtls_test_mock_socket_connect(&(client_ep.socket), - &(server_ep.socket), 1024), 0); - - abort_ctx.ssl = &server_ep.ssl; - - TEST_EQUAL(mbedtls_test_move_handshake_to_state( - &(server_ep.ssl), &(client_ep.ssl), - server_state), 0); - - TEST_EQUAL(mbedtls_ssl_flush_output(&(server_ep.ssl)), 0); - - TEST_EQUAL(server_ep.ssl.state, server_state); - - TEST_EQUAL(abort_ctx.triggered, 0); - - while (client_ep.ssl.state != client_state && - --max_steps >= 0) { - ret = mbedtls_ssl_handshake_step(&(client_ep.ssl)); - TEST_ASSERT(ret == 0 || ret == MBEDTLS_ERR_SSL_WANT_READ || - ret == MBEDTLS_ERR_SSL_WANT_WRITE); - } - - TEST_ASSERT(max_steps >= 0); - - TEST_EQUAL(client_ep.ssl.state, client_state); - TEST_EQUAL(server_ep.ssl.state, server_state); - - TEST_EQUAL(abort_ctx.triggered, 0); - - ret = mbedtls_ssl_handshake_step(&(server_ep.ssl)); - TEST_ASSERT(abort_ctx.triggered); - TEST_ASSERT(ret != 0); - - TEST_EQUAL(server_ep.ssl.state, server_state); - -exit: - mbedtls_test_ssl_endpoint_free(&client_ep); - mbedtls_test_ssl_endpoint_free(&server_ep); - mbedtls_test_free_handshake_options(&client_options); - mbedtls_test_free_handshake_options(&server_options); - mbedtls_debug_set_threshold(0); - PSA_DONE(); -} #endif #if (!defined(MBEDTLS_SSL_PROTO_TLS1_2)) && \ @@ -4515,31 +4394,73 @@ exit: } /* END_CASE */ -/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_DEBUG_C:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED:PSA_WANT_ALG_SHA_256:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ECC_SECP_R1_384:PSA_HAVE_ALG_ECDSA_VERIFY:PSA_HAVE_ALG_SOME_RSA_SIGN:MBEDTLS_SSL_SESSION_TICKETS */ -void tls13_server_propagates_rms_error() +/* BEGIN_CASE depends_on:MBEDTLS_SSL_TLS_C:MBEDTLS_DEBUG_C:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:MBEDTLS_TEST_HAS_DEFAULT_EC_GROUP:PSA_WANT_ALG_SHA_256 */ +void tls_transcript_error_propagation(int endpoint, + int tls_version, + const char *trigger, + int server_state, + int client_state) { - tls_server_error(MBEDTLS_SSL_VERSION_TLS1_3, - "<= parse finished message", - MBEDTLS_SSL_CLIENT_FINISHED, - MBEDTLS_SSL_FLUSH_BUFFERS); - goto exit; + int ret = -1; + mbedtls_test_ssl_endpoint client_ep, server_ep; + mbedtls_test_handshake_test_options client_options; + mbedtls_test_handshake_test_options server_options; + tls_abort_transcript_context abort_ctx; + + mbedtls_test_init_handshake_options(&client_options); + mbedtls_test_init_handshake_options(&server_options); + memset(&abort_ctx, 0, sizeof(abort_ctx)); + + PSA_INIT(); + + client_options.client_min_version = tls_version; + client_options.client_max_version = tls_version; + server_options.server_min_version = tls_version; + server_options.server_max_version = tls_version; + + abort_ctx.trigger = trigger; + + if (endpoint == MBEDTLS_SSL_IS_CLIENT) { + client_options.cli_log_obj = &abort_ctx; + client_options.cli_log_fun = tls_abort_transcript; + } else { + server_options.srv_log_obj = &abort_ctx; + server_options.srv_log_fun = tls_abort_transcript; + } + + mbedtls_debug_set_threshold(4); + + TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT, + &client_options), 0); + TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER, + &server_options), 0); + + TEST_EQUAL(mbedtls_test_mock_socket_connect(&(client_ep.socket), + &(server_ep.socket), 1024), 0); + + abort_ctx.ssl = &server_ep.ssl; + + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + &(server_ep.ssl), &(client_ep.ssl), + server_state), 0); + + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + &(client_ep.ssl), &(server_ep.ssl), + client_state), 0); + + TEST_EQUAL(abort_ctx.triggered, 0); + + ret = mbedtls_ssl_handshake_step(&(server_ep.ssl)); + TEST_ASSERT(abort_ctx.triggered); + TEST_ASSERT(ret != 0); exit: - ; -} -/* END_CASE */ - -/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_DEBUG_C:MBEDTLS_SSL_EXTENDED_MASTER_SECRET:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:PSA_WANT_ALG_SHA_256:PSA_WANT_ECC_SECP_R1_384:PSA_HAVE_ALG_ECDSA_VERIFY:PSA_HAVE_ALG_SOME_RSA_SIGN:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED */ -void tls12_server_propagates_ems_error() -{ - tls_server_error(MBEDTLS_SSL_VERSION_TLS1_2, - "=> derive keys", - MBEDTLS_SSL_CLIENT_KEY_EXCHANGE, - MBEDTLS_SSL_CERTIFICATE_VERIFY); - goto exit; - -exit: - ; + mbedtls_test_ssl_endpoint_free(&client_ep); + mbedtls_test_ssl_endpoint_free(&server_ep); + mbedtls_test_free_handshake_options(&client_options); + mbedtls_test_free_handshake_options(&server_options); + mbedtls_debug_set_threshold(0); + PSA_DONE(); } /* END_CASE */ From d066076211c2911ded6e301696726927a5d3c496 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Wed, 27 May 2026 07:56:31 +0100 Subject: [PATCH 099/173] Add ChangeLog Signed-off-by: Ben Taylor --- ChangeLog.d/1583-1584-ssl-transcript-errors.txt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 ChangeLog.d/1583-1584-ssl-transcript-errors.txt diff --git a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt new file mode 100644 index 0000000000..921b40b11d --- /dev/null +++ b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt @@ -0,0 +1,5 @@ +Bugfix + * Fix a bug where errors during transcript-hash computation for TLS 1.2 + extended master secret and TLS 1.3 resumption master secret could be + ignored instead of causing the handshake to fail. Fixes #1583 and #1584. + From 29bdcc319ac0f07462d087698e1ae97e12c2ad90 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 28 May 2026 15:07:08 +0100 Subject: [PATCH 100/173] Update ChangeLog Signed-off-by: Ben Taylor --- ChangeLog.d/1583-1584-ssl-transcript-errors.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt index 921b40b11d..062a788788 100644 --- a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt +++ b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt @@ -1,5 +1,5 @@ -Bugfix +Security * Fix a bug where errors during transcript-hash computation for TLS 1.2 extended master secret and TLS 1.3 resumption master secret could be - ignored instead of causing the handshake to fail. Fixes #1583 and #1584. + ignored instead of causing the handshake to fail. From d6019b932d1813cbebe9a033da0754cf0906e94b Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 28 May 2026 15:18:19 +0100 Subject: [PATCH 101/173] Add security impact Signed-off-by: Ben Taylor --- ChangeLog.d/1583-1584-ssl-transcript-errors.txt | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt index 062a788788..4b5db144c3 100644 --- a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt +++ b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt @@ -1,5 +1,12 @@ Security - * Fix a bug where errors during transcript-hash computation for TLS 1.2 - extended master secret and TLS 1.3 resumption master secret could be - ignored instead of causing the handshake to fail. - + * Fix a bug where transcript-hash computation errors during TLS 1.2 + extended master secret calculation could be ignored instead of causing the + handshake to fail. This could allow a handshake to continue with a master + secret that was not correctly bound to the handshake transcript, + undermining the security guarantees of the extended master secret + extension. + * Fix a bug where TLS 1.3 servers could ignore errors when computing the + resumption master secret instead of causing the handshake to fail. This + could allow a server to issue resumption tickets derived from an invalid + resumption secret, weakening authentication of future resumptions made + with those tickets. From d6e60125442bffb0bf7773e8e21cfed219e425d8 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Fri, 29 May 2026 14:48:44 +0100 Subject: [PATCH 102/173] Improve layout of the code for debugging with breakpoints Signed-off-by: Ben Taylor --- tests/suites/test_suite_ssl.function | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index a68a6fcf3f..569cb159d1 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -76,10 +76,19 @@ static void tls_abort_transcript(void *ctx, int level, (void) file; (void) line; - if (abort_ctx->triggered || abort_ctx->ssl == NULL || - abort_ctx->ssl->handshake == NULL || - abort_ctx->trigger == NULL || - strstr(str, abort_ctx->trigger) == NULL) { + if (abort_ctx->triggered){ + return; + } + if (abort_ctx->ssl == NULL) { + return; + } + if (abort_ctx->ssl->handshake == NULL) { + return; + } + if (abort_ctx->trigger == NULL) { + return; + } + if (strstr(str, abort_ctx->trigger) == NULL) { return; } From cdad2f42b79cb7494dea5a6220635bc4cd8b0722 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Fri, 29 May 2026 15:09:34 +0100 Subject: [PATCH 103/173] Add additional guard for sha256 in tests Signed-off-by: Ben Taylor --- tests/suites/test_suite_ssl.function | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 569cb159d1..2728ddc704 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -93,7 +93,9 @@ static void tls_abort_transcript(void *ctx, int level, } abort_ctx->triggered = 1; +#if defined(PSA_WANT_ALG_SHA_256) psa_hash_abort(&abort_ctx->ssl->handshake->fin_sha256_psa); +#endif #if defined(PSA_WANT_ALG_SHA_384) psa_hash_abort(&abort_ctx->ssl->handshake->fin_sha384_psa); #endif From 0a0c86dca446d286974bb699f5eb7e5aa68bacf2 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Fri, 29 May 2026 15:12:28 +0100 Subject: [PATCH 104/173] refactor initialisation in tls_transcript_error_propagation, so that the variables are initialised straight after they are declared Signed-off-by: Ben Taylor --- tests/suites/test_suite_ssl.function | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 2728ddc704..5655be29d9 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4415,11 +4415,10 @@ void tls_transcript_error_propagation(int endpoint, int ret = -1; mbedtls_test_ssl_endpoint client_ep, server_ep; mbedtls_test_handshake_test_options client_options; - mbedtls_test_handshake_test_options server_options; - tls_abort_transcript_context abort_ctx; - mbedtls_test_init_handshake_options(&client_options); + mbedtls_test_handshake_test_options server_options; mbedtls_test_init_handshake_options(&server_options); + tls_abort_transcript_context abort_ctx; memset(&abort_ctx, 0, sizeof(abort_ctx)); PSA_INIT(); From a58163a3391b50ef38143433a076a922423be714 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 1 Jun 2026 07:43:48 +0100 Subject: [PATCH 105/173] Fixed code style 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 5655be29d9..8a99e93940 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -76,7 +76,7 @@ static void tls_abort_transcript(void *ctx, int level, (void) file; (void) line; - if (abort_ctx->triggered){ + if (abort_ctx->triggered) { return; } if (abort_ctx->ssl == NULL) { From 4570537978907f62faa503732a6a8df310ba48ff Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 1 Jun 2026 07:59:06 +0100 Subject: [PATCH 106/173] Fix issues with hanging seed length Signed-off-by: Ben Taylor --- library/ssl_tls.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 7ddaa12202..86bed60fd8 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -6293,12 +6293,16 @@ static int ssl_compute_master(mbedtls_ssl_handshake_params *handshake, #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) if (handshake->extended_ms == MBEDTLS_SSL_EXTENDED_MS_ENABLED) { lbl = "extended master secret"; - seed = session_hash; ret = handshake->calc_verify(ssl, session_hash, &seed_len); if (ret != 0) { MBEDTLS_SSL_DEBUG_RET(1, "calc_verify", ret); return ret; } + if (seed_len > sizeof(session_hash)) { + MBEDTLS_SSL_DEBUG_MSG(1, ("bad session hash length")); + return MBEDTLS_ERR_SSL_INTERNAL_ERROR; + } + seed = session_hash; MBEDTLS_SSL_DEBUG_BUF(3, "session hash for extended master secret", session_hash, seed_len); From 6b60598c88cb34a9965cee9966d297a295c5f840 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 1 Jun 2026 08:03:58 +0100 Subject: [PATCH 107/173] Add further documentation to tls_abort_transcript_context Signed-off-by: Ben Taylor --- tests/suites/test_suite_ssl.function | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 8a99e93940..c377bcaace 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -61,6 +61,9 @@ static int failing_ticket_write_unset_lifetime( defined(MBEDTLS_TEST_HAS_DEFAULT_EC_GROUP) && \ defined(PSA_WANT_ALG_SHA_256) typedef struct { + /* Context for tls_abort_transcript(). The debug callback watches for + * trigger in the SSL debug trace, then aborts this connection's transcript + * hash operation exactly once so the test can check error propagation. */ mbedtls_ssl_context *ssl; const char *trigger; int triggered; From 64b837bef9273484e013cde4fd8738341afc4f93 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 1 Jun 2026 08:12:23 +0100 Subject: [PATCH 108/173] Add unsupported trigger check Signed-off-by: Ben Taylor --- tests/suites/test_suite_ssl.function | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index c377bcaace..416af2141e 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -88,9 +88,6 @@ static void tls_abort_transcript(void *ctx, int level, if (abort_ctx->ssl->handshake == NULL) { return; } - if (abort_ctx->trigger == NULL) { - return; - } if (strstr(str, abort_ctx->trigger) == NULL) { return; } @@ -4432,6 +4429,7 @@ void tls_transcript_error_propagation(int endpoint, server_options.server_max_version = tls_version; abort_ctx.trigger = trigger; + TEST_ASSERT(abort_ctx.trigger != NULL); if (endpoint == MBEDTLS_SSL_IS_CLIENT) { client_options.cli_log_obj = &abort_ctx; From d93c7b6289f325635a89cf7172d933bad9250de9 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 1 Jun 2026 08:26:50 +0100 Subject: [PATCH 109/173] Add client tests for RMS computation error Signed-off-by: Ben Taylor --- tests/suites/test_suite_ssl.data | 8 +++++++ tests/suites/test_suite_ssl.function | 32 ++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index c93ff542e9..3dba0df18b 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3382,10 +3382,18 @@ TLS 1.3 server propagates RMS computation error depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_3:"<= parse finished message":MBEDTLS_SSL_CLIENT_FINISHED:MBEDTLS_SSL_FLUSH_BUFFERS +TLS 1.3 client propagates RMS computation error +depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT +tls_transcript_error_propagation:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_3:"<= write finished message":MBEDTLS_SSL_CLIENT_FINISHED:MBEDTLS_SSL_CLIENT_FINISHED + TLS 1.2 server propagates EMS computation error depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_2:"=> derive keys":MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:MBEDTLS_SSL_CERTIFICATE_VERIFY +TLS 1.2 client propagates EMS computation error +depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +tls_transcript_error_propagation:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_2:"=> derive keys":MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:MBEDTLS_SSL_CERTIFICATE_VERIFY + TLS 1.3 read early data, early data accepted tls13_read_early_data:TEST_EARLY_DATA_ACCEPTED diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 416af2141e..fbbce164a2 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4446,22 +4446,36 @@ void tls_transcript_error_propagation(int endpoint, TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER, &server_options), 0); + /* Keep enough socket capacity for setup traffic so the final step below + * exercises the target state instead of only flushing previous messages. */ TEST_EQUAL(mbedtls_test_mock_socket_connect(&(client_ep.socket), - &(server_ep.socket), 1024), 0); + &(server_ep.socket), 4096), 0); - abort_ctx.ssl = &server_ep.ssl; + if (endpoint == MBEDTLS_SSL_IS_CLIENT) { + /* Moving the client to its target state drives the server as needed. + * Moving the server afterwards can advance the client past that state. */ + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + &(client_ep.ssl), &(server_ep.ssl), + client_state), 0); - TEST_EQUAL(mbedtls_test_move_handshake_to_state( - &(server_ep.ssl), &(client_ep.ssl), - server_state), 0); + abort_ctx.ssl = &client_ep.ssl; + } else { + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + &(server_ep.ssl), &(client_ep.ssl), + server_state), 0); - TEST_EQUAL(mbedtls_test_move_handshake_to_state( - &(client_ep.ssl), &(server_ep.ssl), - client_state), 0); + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + &(client_ep.ssl), &(server_ep.ssl), + client_state), 0); + abort_ctx.ssl = &server_ep.ssl; + } + TEST_EQUAL(mbedtls_ssl_flush_output(abort_ctx.ssl), 0); + TEST_EQUAL(abort_ctx.ssl->state, + endpoint == MBEDTLS_SSL_IS_CLIENT ? client_state : server_state); TEST_EQUAL(abort_ctx.triggered, 0); - ret = mbedtls_ssl_handshake_step(&(server_ep.ssl)); + ret = mbedtls_ssl_handshake_step(abort_ctx.ssl); TEST_ASSERT(abort_ctx.triggered); TEST_ASSERT(ret != 0); From 86140ccd4a7498b09f1a39a6c0b8cd44c95b7625 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 1 Jun 2026 09:03:29 +0100 Subject: [PATCH 110/173] Add additional fix for return with error Signed-off-by: Ben Taylor --- library/ssl_tls13_client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index 96d4d08ee0..ecdf507eab 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -2804,6 +2804,7 @@ static int ssl_tls13_parse_new_session_ticket_exts(mbedtls_ssl_context *ssl, MBEDTLS_SSL_DEBUG_RET( 1, "ssl_tls13_parse_new_session_ticket_early_data_ext", ret); + return ret; } break; #endif /* MBEDTLS_SSL_EARLY_DATA */ From bc111eed2782d54f04c4347cf417d0197317b7f5 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 1 Jun 2026 09:19:29 +0100 Subject: [PATCH 111/173] Add fix for missing return from ssl_write_ecjpake_kkpp_ext Signed-off-by: Ben Taylor --- library/ssl_tls12_server.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/library/ssl_tls12_server.c b/library/ssl_tls12_server.c index 328e25aafc..5333d18c58 100644 --- a/library/ssl_tls12_server.c +++ b/library/ssl_tls12_server.c @@ -1746,7 +1746,7 @@ static void ssl_write_supported_point_formats_ext(mbedtls_ssl_context *ssl, MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) -static void ssl_write_ecjpake_kkpp_ext(mbedtls_ssl_context *ssl, +static int ssl_write_ecjpake_kkpp_ext(mbedtls_ssl_context *ssl, unsigned char *buf, size_t *olen) { @@ -1760,14 +1760,14 @@ static void ssl_write_ecjpake_kkpp_ext(mbedtls_ssl_context *ssl, /* Skip costly computation if not needed */ if (ssl->handshake->ciphersuite_info->key_exchange != MBEDTLS_KEY_EXCHANGE_ECJPAKE) { - return; + return 0; } MBEDTLS_SSL_DEBUG_MSG(3, ("server hello, ecjpake kkpp extension")); if (end - p < 4) { MBEDTLS_SSL_DEBUG_MSG(1, ("buffer too small")); - return; + return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL; } MBEDTLS_PUT_UINT16_BE(MBEDTLS_TLS_EXT_ECJPAKE_KKPP, p, 0); @@ -1780,13 +1780,14 @@ static void ssl_write_ecjpake_kkpp_ext(mbedtls_ssl_context *ssl, psa_destroy_key(ssl->handshake->psa_pake_password); psa_pake_abort(&ssl->handshake->psa_pake_ctx); MBEDTLS_SSL_DEBUG_RET(1, "psa_pake_output", ret); - return; + return ret; } MBEDTLS_PUT_UINT16_BE(kkpp_len, p, 0); p += 2; *olen = kkpp_len + 4; + return 0; } #endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ @@ -2169,7 +2170,10 @@ static int ssl_write_server_hello(mbedtls_ssl_context *ssl) #endif #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) - ssl_write_ecjpake_kkpp_ext(ssl, p + 2 + ext_len, &olen); + if ((ret = ssl_write_ecjpake_kkpp_ext(ssl, p + 2 + ext_len, &olen)) != 0) { + MBEDTLS_SSL_DEBUG_RET(1, "ssl_write_ecjpake_kkpp_ext", ret); + return ret; + } ext_len += olen; #endif From 5aa6ab3408a9c3440c344c82d1055a1eccfd78da Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 1 Jun 2026 14:48:09 +0100 Subject: [PATCH 112/173] Fix code style issues Signed-off-by: Ben Taylor --- library/ssl_tls12_server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/ssl_tls12_server.c b/library/ssl_tls12_server.c index 5333d18c58..7ff2833121 100644 --- a/library/ssl_tls12_server.c +++ b/library/ssl_tls12_server.c @@ -1747,8 +1747,8 @@ static void ssl_write_supported_point_formats_ext(mbedtls_ssl_context *ssl, #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) static int ssl_write_ecjpake_kkpp_ext(mbedtls_ssl_context *ssl, - unsigned char *buf, - size_t *olen) + unsigned char *buf, + size_t *olen) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; unsigned char *p = buf; From 8c27b60597a6bbf5b893fe4a250cdcdd61f3d49b Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 4 Jun 2026 10:29:43 +0100 Subject: [PATCH 113/173] Add Reported by to ChangeLog Signed-off-by: Ben Taylor --- ChangeLog.d/1583-1584-ssl-transcript-errors.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt index 4b5db144c3..75d6969501 100644 --- a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt +++ b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt @@ -10,3 +10,4 @@ Security could allow a server to issue resumption tickets derived from an invalid resumption secret, weakening authentication of future resumptions made with those tickets. + * Reported by jjfz123 / https://github.com/jjfz123 / https://www.linkedin.com/in/jjfdzcastro1/ From f9a3d649ffd3809e2935cc5fa68e20f50de57df2 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 4 Jun 2026 10:32:03 +0100 Subject: [PATCH 114/173] Tidy up ChangeLog Signed-off-by: Ben Taylor --- ChangeLog.d/1583-1584-ssl-transcript-errors.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt index 75d6969501..6d20d958b2 100644 --- a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt +++ b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt @@ -4,10 +4,10 @@ Security handshake to fail. This could allow a handshake to continue with a master secret that was not correctly bound to the handshake transcript, undermining the security guarantees of the extended master secret - extension. + extension. Reported by jjfz123 / https://github.com/jjfz123 / + https://www.linkedin.com/in/jjfdzcastro1/ * Fix a bug where TLS 1.3 servers could ignore errors when computing the resumption master secret instead of causing the handshake to fail. This could allow a server to issue resumption tickets derived from an invalid resumption secret, weakening authentication of future resumptions made with those tickets. - * Reported by jjfz123 / https://github.com/jjfz123 / https://www.linkedin.com/in/jjfdzcastro1/ From 0e3e1182201984d93d46087a90e580c702953871 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 4 Jun 2026 10:33:07 +0100 Subject: [PATCH 115/173] Remove check for NULL pointer Signed-off-by: Ben Taylor --- tests/suites/test_suite_ssl.function | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index fbbce164a2..d0a7f25980 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4429,7 +4429,6 @@ void tls_transcript_error_propagation(int endpoint, server_options.server_max_version = tls_version; abort_ctx.trigger = trigger; - TEST_ASSERT(abort_ctx.trigger != NULL); if (endpoint == MBEDTLS_SSL_IS_CLIENT) { client_options.cli_log_obj = &abort_ctx; From b0f812d68d41d1dfc98fa9a5df5e3c566225211a Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 4 Jun 2026 12:12:00 +0100 Subject: [PATCH 116/173] Fix reporters in ChangeLog Signed-off-by: Ben Taylor --- ChangeLog.d/1583-1584-ssl-transcript-errors.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt index 6d20d958b2..c8b6aa696c 100644 --- a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt +++ b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt @@ -4,10 +4,10 @@ Security handshake to fail. This could allow a handshake to continue with a master secret that was not correctly bound to the handshake transcript, undermining the security guarantees of the extended master secret - extension. Reported by jjfz123 / https://github.com/jjfz123 / - https://www.linkedin.com/in/jjfdzcastro1/ + extension. Report by Mathew Gretton-Dann * Fix a bug where TLS 1.3 servers could ignore errors when computing the resumption master secret instead of causing the handshake to fail. This could allow a server to issue resumption tickets derived from an invalid resumption secret, weakening authentication of future resumptions made - with those tickets. + with those tickets. Reported by jjfz123 / https://github.com/jjfz123 / + https://www.linkedin.com/in/jjfdzcastro1/ From 6ed6d0e491d638a58861cf5436537d2c1a22ec33 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Fri, 5 Jun 2026 07:54:38 +0100 Subject: [PATCH 117/173] Update ChangeLog Signed-off-by: Ben Taylor --- ChangeLog.d/1583-1584-ssl-transcript-errors.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt index c8b6aa696c..e21c52cfde 100644 --- a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt +++ b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt @@ -4,10 +4,9 @@ Security handshake to fail. This could allow a handshake to continue with a master secret that was not correctly bound to the handshake transcript, undermining the security guarantees of the extended master secret - extension. Report by Mathew Gretton-Dann + extension. Report by Mathew Gretton-Dann. * Fix a bug where TLS 1.3 servers could ignore errors when computing the resumption master secret instead of causing the handshake to fail. This could allow a server to issue resumption tickets derived from an invalid resumption secret, weakening authentication of future resumptions made - with those tickets. Reported by jjfz123 / https://github.com/jjfz123 / - https://www.linkedin.com/in/jjfdzcastro1/ + with those tickets. Reported by jjfz123. From 76aa4682ce96fe81fc2cae14843624bf17f61858 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Fri, 5 Jun 2026 08:33:11 +0100 Subject: [PATCH 118/173] Improve testing Signed-off-by: Ben Taylor --- tests/suites/test_suite_ssl.data | 22 ++-- tests/suites/test_suite_ssl.function | 150 +++++++++++++-------------- 2 files changed, 86 insertions(+), 86 deletions(-) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 3dba0df18b..24e9ae9033 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3378,21 +3378,21 @@ elliptic_curve_get_properties TLS 1.3 resume session with ticket tls13_resume_session_with_ticket -TLS 1.3 server propagates RMS computation error +TLS 1.3 server propagates RMS computation error depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_3:"<= parse finished message":MBEDTLS_SSL_CLIENT_FINISHED:MBEDTLS_SSL_FLUSH_BUFFERS - -TLS 1.3 client propagates RMS computation error + +TLS 1.3 client propagates RMS computation error depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT -tls_transcript_error_propagation:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_3:"<= write finished message":MBEDTLS_SSL_CLIENT_FINISHED:MBEDTLS_SSL_CLIENT_FINISHED - -TLS 1.2 server propagates EMS computation error -depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +tls_transcript_error_propagation:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_3:"<= write finished message":MBEDTLS_SSL_CLIENT_FINISHED:-1 + +TLS 1.2 server propagates EMS computation error +depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_2:"=> derive keys":MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:MBEDTLS_SSL_CERTIFICATE_VERIFY - -TLS 1.2 client propagates EMS computation error -depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED -tls_transcript_error_propagation:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_2:"=> derive keys":MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:MBEDTLS_SSL_CERTIFICATE_VERIFY + +TLS 1.2 client propagates EMS computation error +depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +tls_transcript_error_propagation:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_2:"=> derive keys":MBEDTLS_SSL_CERTIFICATE_VERIFY:-1 TLS 1.3 read early data, early data accepted tls13_read_early_data:TEST_EARLY_DATA_ACCEPTED diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index d0a7f25980..09b8ac8230 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4406,85 +4406,85 @@ exit: /* END_CASE */ /* BEGIN_CASE depends_on:MBEDTLS_SSL_TLS_C:MBEDTLS_DEBUG_C:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:MBEDTLS_TEST_HAS_DEFAULT_EC_GROUP:PSA_WANT_ALG_SHA_256 */ -void tls_transcript_error_propagation(int endpoint, - int tls_version, - const char *trigger, - int server_state, - int client_state) -{ - int ret = -1; - mbedtls_test_ssl_endpoint client_ep, server_ep; - mbedtls_test_handshake_test_options client_options; - mbedtls_test_init_handshake_options(&client_options); - mbedtls_test_handshake_test_options server_options; - mbedtls_test_init_handshake_options(&server_options); - tls_abort_transcript_context abort_ctx; - memset(&abort_ctx, 0, sizeof(abort_ctx)); - - PSA_INIT(); - - client_options.client_min_version = tls_version; - client_options.client_max_version = tls_version; - server_options.server_min_version = tls_version; - server_options.server_max_version = tls_version; - - abort_ctx.trigger = trigger; - - if (endpoint == MBEDTLS_SSL_IS_CLIENT) { - client_options.cli_log_obj = &abort_ctx; - client_options.cli_log_fun = tls_abort_transcript; - } else { - server_options.srv_log_obj = &abort_ctx; - server_options.srv_log_fun = tls_abort_transcript; - } - - mbedtls_debug_set_threshold(4); - +void tls_transcript_error_propagation(int endpoint, + int tls_version, + const char *trigger, + int target_state, + int peer_target_state) +{ + int ret = -1; + mbedtls_test_ssl_endpoint client_ep, server_ep; + mbedtls_test_handshake_test_options client_options; + mbedtls_test_init_handshake_options(&client_options); + mbedtls_test_handshake_test_options server_options; + mbedtls_test_init_handshake_options(&server_options); + tls_abort_transcript_context abort_ctx; + memset(&abort_ctx, 0, sizeof(abort_ctx)); + mbedtls_ssl_context *peer_ssl_context = NULL; + + PSA_INIT(); + + client_options.client_min_version = tls_version; + client_options.client_max_version = tls_version; + server_options.server_min_version = tls_version; + server_options.server_max_version = tls_version; + + abort_ctx.trigger = trigger; + TEST_ASSERT(abort_ctx.trigger != NULL); + + if (endpoint == MBEDTLS_SSL_IS_CLIENT) { + client_options.cli_log_obj = &abort_ctx; + client_options.cli_log_fun = tls_abort_transcript; + abort_ctx.ssl = &client_ep.ssl; + peer_ssl_context = &server_ep.ssl; + } else { + server_options.srv_log_obj = &abort_ctx; + server_options.srv_log_fun = tls_abort_transcript; + abort_ctx.ssl = &server_ep.ssl; + peer_ssl_context = &client_ep.ssl; + } + + mbedtls_debug_set_threshold(4); + TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT, - &client_options), 0); + &client_options), 0); TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER, &server_options), 0); - - /* Keep enough socket capacity for setup traffic so the final step below + + /* Keep enough socket capacity for setup traffic so the final step below * exercises the target state instead of only flushing previous messages. */ - TEST_EQUAL(mbedtls_test_mock_socket_connect(&(client_ep.socket), - &(server_ep.socket), 4096), 0); - - if (endpoint == MBEDTLS_SSL_IS_CLIENT) { - /* Moving the client to its target state drives the server as needed. - * Moving the server afterwards can advance the client past that state. */ - TEST_EQUAL(mbedtls_test_move_handshake_to_state( - &(client_ep.ssl), &(server_ep.ssl), - client_state), 0); - - abort_ctx.ssl = &client_ep.ssl; - } else { - TEST_EQUAL(mbedtls_test_move_handshake_to_state( - &(server_ep.ssl), &(client_ep.ssl), - server_state), 0); - - TEST_EQUAL(mbedtls_test_move_handshake_to_state( - &(client_ep.ssl), &(server_ep.ssl), - client_state), 0); - abort_ctx.ssl = &server_ep.ssl; - } - - TEST_EQUAL(mbedtls_ssl_flush_output(abort_ctx.ssl), 0); - TEST_EQUAL(abort_ctx.ssl->state, - endpoint == MBEDTLS_SSL_IS_CLIENT ? client_state : server_state); - TEST_EQUAL(abort_ctx.triggered, 0); - - ret = mbedtls_ssl_handshake_step(abort_ctx.ssl); - TEST_ASSERT(abort_ctx.triggered); - TEST_ASSERT(ret != 0); - -exit: - mbedtls_test_ssl_endpoint_free(&client_ep); - mbedtls_test_ssl_endpoint_free(&server_ep); - mbedtls_test_free_handshake_options(&client_options); - mbedtls_test_free_handshake_options(&server_options); - mbedtls_debug_set_threshold(0); - PSA_DONE(); + TEST_EQUAL(mbedtls_test_mock_socket_connect(&(client_ep.socket), + &(server_ep.socket), 4096), 0); + + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + abort_ctx.ssl, peer_ssl_context, + target_state), 0); + /* + * Advance the peer further through the handshake so that it emits the + * messages needed by the endpoint under test to proceed through its next + * step. + */ + if (peer_target_state != -1) { + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + peer_ssl_context, abort_ctx.ssl, + peer_target_state), 0); + } + + TEST_EQUAL(mbedtls_ssl_flush_output(abort_ctx.ssl), 0); + TEST_EQUAL(abort_ctx.ssl->state, target_state); + TEST_EQUAL(abort_ctx.triggered, 0); + + ret = mbedtls_ssl_handshake_step(abort_ctx.ssl); + TEST_ASSERT(abort_ctx.triggered); + TEST_ASSERT(ret != 0); + +exit: + mbedtls_test_ssl_endpoint_free(&client_ep); + mbedtls_test_ssl_endpoint_free(&server_ep); + mbedtls_test_free_handshake_options(&client_options); + mbedtls_test_free_handshake_options(&server_options); + mbedtls_debug_set_threshold(0); + PSA_DONE(); } /* END_CASE */ From 2e2bbed8f0ccc16195d0d2d98e10a3e2831c79b2 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Fri, 5 Jun 2026 08:39:39 +0100 Subject: [PATCH 119/173] Update error handling of return from ssl_write_ecjpake_kkpp_ext Signed-off-by: Ben Taylor --- library/ssl_tls12_server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/ssl_tls12_server.c b/library/ssl_tls12_server.c index 7ff2833121..03ef8fd5f9 100644 --- a/library/ssl_tls12_server.c +++ b/library/ssl_tls12_server.c @@ -2170,11 +2170,11 @@ static int ssl_write_server_hello(mbedtls_ssl_context *ssl) #endif #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) - if ((ret = ssl_write_ecjpake_kkpp_ext(ssl, p + 2 + ext_len, &olen)) != 0) { + ret = ssl_write_ecjpake_kkpp_ext(ssl, p + 2 + ext_len, &olen); + if (ret != 0) { MBEDTLS_SSL_DEBUG_RET(1, "ssl_write_ecjpake_kkpp_ext", ret); return ret; } - ext_len += olen; #endif #if defined(MBEDTLS_SSL_ALPN) From 470aeeed9d1ad1fb19af5a7b1b6afa40bb1d9f4c Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Fri, 5 Jun 2026 08:42:19 +0100 Subject: [PATCH 120/173] Improve ChangeLog Signed-off-by: Ben Taylor --- ChangeLog.d/1583-1584-ssl-transcript-errors.txt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt index e21c52cfde..3a18c76df9 100644 --- a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt +++ b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt @@ -5,8 +5,12 @@ Security secret that was not correctly bound to the handshake transcript, undermining the security guarantees of the extended master secret extension. Report by Mathew Gretton-Dann. - * Fix a bug where TLS 1.3 servers could ignore errors when computing the - resumption master secret instead of causing the handshake to fail. This - could allow a server to issue resumption tickets derived from an invalid - resumption secret, weakening authentication of future resumptions made - with those tickets. Reported by jjfz123. + * Fix a TLS 1.3 server-side error-handling bug affecting session ticket + generation. Under rare conditions, such as memory allocation failures + while computing the resumption master secret, the server could issue + invalid session tickets instead of failing the handshake. Clients + presented with such tickets would fail session resumption and fall back to + a full handshake. In deployments relying on session resumption, repeated + occurrences could increase the frequency of full handshakes and amplify + resource consumption during periods of resource exhaustion or other + transient failures. Reported by jjfz123. From 9709c1a6e5a1be8edc54cd0c1509e8708bbc8fda Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Fri, 5 Jun 2026 09:21:09 +0100 Subject: [PATCH 121/173] fix code style Signed-off-by: Ben Taylor --- tests/suites/test_suite_ssl.function | 150 +++++++++++++-------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 09b8ac8230..40041210ed 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4406,85 +4406,85 @@ exit: /* END_CASE */ /* BEGIN_CASE depends_on:MBEDTLS_SSL_TLS_C:MBEDTLS_DEBUG_C:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:MBEDTLS_TEST_HAS_DEFAULT_EC_GROUP:PSA_WANT_ALG_SHA_256 */ -void tls_transcript_error_propagation(int endpoint, - int tls_version, - const char *trigger, - int target_state, - int peer_target_state) -{ - int ret = -1; - mbedtls_test_ssl_endpoint client_ep, server_ep; - mbedtls_test_handshake_test_options client_options; - mbedtls_test_init_handshake_options(&client_options); - mbedtls_test_handshake_test_options server_options; - mbedtls_test_init_handshake_options(&server_options); - tls_abort_transcript_context abort_ctx; - memset(&abort_ctx, 0, sizeof(abort_ctx)); - mbedtls_ssl_context *peer_ssl_context = NULL; - - PSA_INIT(); - - client_options.client_min_version = tls_version; - client_options.client_max_version = tls_version; - server_options.server_min_version = tls_version; - server_options.server_max_version = tls_version; - - abort_ctx.trigger = trigger; - TEST_ASSERT(abort_ctx.trigger != NULL); - - if (endpoint == MBEDTLS_SSL_IS_CLIENT) { - client_options.cli_log_obj = &abort_ctx; - client_options.cli_log_fun = tls_abort_transcript; - abort_ctx.ssl = &client_ep.ssl; - peer_ssl_context = &server_ep.ssl; - } else { - server_options.srv_log_obj = &abort_ctx; - server_options.srv_log_fun = tls_abort_transcript; - abort_ctx.ssl = &server_ep.ssl; - peer_ssl_context = &client_ep.ssl; - } - - mbedtls_debug_set_threshold(4); - +void tls_transcript_error_propagation(int endpoint, + int tls_version, + const char *trigger, + int target_state, + int peer_target_state) +{ + int ret = -1; + mbedtls_test_ssl_endpoint client_ep, server_ep; + mbedtls_test_handshake_test_options client_options; + mbedtls_test_init_handshake_options(&client_options); + mbedtls_test_handshake_test_options server_options; + mbedtls_test_init_handshake_options(&server_options); + tls_abort_transcript_context abort_ctx; + memset(&abort_ctx, 0, sizeof(abort_ctx)); + mbedtls_ssl_context *peer_ssl_context = NULL; + + PSA_INIT(); + + client_options.client_min_version = tls_version; + client_options.client_max_version = tls_version; + server_options.server_min_version = tls_version; + server_options.server_max_version = tls_version; + + abort_ctx.trigger = trigger; + TEST_ASSERT(abort_ctx.trigger != NULL); + + if (endpoint == MBEDTLS_SSL_IS_CLIENT) { + client_options.cli_log_obj = &abort_ctx; + client_options.cli_log_fun = tls_abort_transcript; + abort_ctx.ssl = &client_ep.ssl; + peer_ssl_context = &server_ep.ssl; + } else { + server_options.srv_log_obj = &abort_ctx; + server_options.srv_log_fun = tls_abort_transcript; + abort_ctx.ssl = &server_ep.ssl; + peer_ssl_context = &client_ep.ssl; + } + + mbedtls_debug_set_threshold(4); + TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT, - &client_options), 0); + &client_options), 0); TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER, &server_options), 0); - - /* Keep enough socket capacity for setup traffic so the final step below + + /* Keep enough socket capacity for setup traffic so the final step below * exercises the target state instead of only flushing previous messages. */ - TEST_EQUAL(mbedtls_test_mock_socket_connect(&(client_ep.socket), - &(server_ep.socket), 4096), 0); - - TEST_EQUAL(mbedtls_test_move_handshake_to_state( - abort_ctx.ssl, peer_ssl_context, - target_state), 0); - /* - * Advance the peer further through the handshake so that it emits the - * messages needed by the endpoint under test to proceed through its next - * step. - */ - if (peer_target_state != -1) { - TEST_EQUAL(mbedtls_test_move_handshake_to_state( - peer_ssl_context, abort_ctx.ssl, - peer_target_state), 0); - } - - TEST_EQUAL(mbedtls_ssl_flush_output(abort_ctx.ssl), 0); - TEST_EQUAL(abort_ctx.ssl->state, target_state); - TEST_EQUAL(abort_ctx.triggered, 0); - - ret = mbedtls_ssl_handshake_step(abort_ctx.ssl); - TEST_ASSERT(abort_ctx.triggered); - TEST_ASSERT(ret != 0); - -exit: - mbedtls_test_ssl_endpoint_free(&client_ep); - mbedtls_test_ssl_endpoint_free(&server_ep); - mbedtls_test_free_handshake_options(&client_options); - mbedtls_test_free_handshake_options(&server_options); - mbedtls_debug_set_threshold(0); - PSA_DONE(); + TEST_EQUAL(mbedtls_test_mock_socket_connect(&(client_ep.socket), + &(server_ep.socket), 4096), 0); + + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + abort_ctx.ssl, peer_ssl_context, + target_state), 0); + /* + * Advance the peer further through the handshake so that it emits the + * messages needed by the endpoint under test to proceed through its next + * step. + */ + if (peer_target_state != -1) { + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + peer_ssl_context, abort_ctx.ssl, + peer_target_state), 0); + } + + TEST_EQUAL(mbedtls_ssl_flush_output(abort_ctx.ssl), 0); + TEST_EQUAL(abort_ctx.ssl->state, target_state); + TEST_EQUAL(abort_ctx.triggered, 0); + + ret = mbedtls_ssl_handshake_step(abort_ctx.ssl); + TEST_ASSERT(abort_ctx.triggered); + TEST_ASSERT(ret != 0); + +exit: + mbedtls_test_ssl_endpoint_free(&client_ep); + mbedtls_test_ssl_endpoint_free(&server_ep); + mbedtls_test_free_handshake_options(&client_options); + mbedtls_test_free_handshake_options(&server_options); + mbedtls_debug_set_threshold(0); + PSA_DONE(); } /* END_CASE */ From 62d3b1ecc00f45c1a48991cc39c9b54f9938732f Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 8 Jun 2026 13:26:35 +0100 Subject: [PATCH 122/173] Update dependencies for skipped test Signed-off-by: Ben Taylor --- tests/suites/test_suite_ssl.data | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 24e9ae9033..f5fc712b3f 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3379,11 +3379,11 @@ TLS 1.3 resume session with ticket tls13_resume_session_with_ticket TLS 1.3 server propagates RMS computation error -depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT +depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_SIGN tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_3:"<= parse finished message":MBEDTLS_SSL_CLIENT_FINISHED:MBEDTLS_SSL_FLUSH_BUFFERS TLS 1.3 client propagates RMS computation error -depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT +depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_SIGN tls_transcript_error_propagation:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_3:"<= write finished message":MBEDTLS_SSL_CLIENT_FINISHED:-1 TLS 1.2 server propagates EMS computation error From 3e6608a5b60821f94a71304175e4d7097809a1d5 Mon Sep 17 00:00:00 2001 From: Ben Taylor <32939606+bjwtaylor@users.noreply.github.com> Date: Mon, 8 Jun 2026 13:28:07 +0100 Subject: [PATCH 123/173] Update ChangeLog to add CVE Co-authored-by: Gilles Peskine Signed-off-by: Ben Taylor <32939606+bjwtaylor@users.noreply.github.com> --- ChangeLog.d/1583-1584-ssl-transcript-errors.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt index 3a18c76df9..ef092386a9 100644 --- a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt +++ b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt @@ -4,7 +4,7 @@ Security handshake to fail. This could allow a handshake to continue with a master secret that was not correctly bound to the handshake transcript, undermining the security guarantees of the extended master secret - extension. Report by Mathew Gretton-Dann. + extension. Report by Mathew Gretton-Dann. CVE-2026-50581 * Fix a TLS 1.3 server-side error-handling bug affecting session ticket generation. Under rare conditions, such as memory allocation failures while computing the resumption master secret, the server could issue From 52a1b950671170c354701972345da4f8a9cb405a Mon Sep 17 00:00:00 2001 From: Ben Taylor <32939606+bjwtaylor@users.noreply.github.com> Date: Mon, 8 Jun 2026 13:28:42 +0100 Subject: [PATCH 124/173] Update ChangeLog with CVE number Co-authored-by: Ronald Cron Signed-off-by: Ben Taylor <32939606+bjwtaylor@users.noreply.github.com> --- ChangeLog.d/1583-1584-ssl-transcript-errors.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt index ef092386a9..f259bd711e 100644 --- a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt +++ b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt @@ -14,3 +14,4 @@ Security occurrences could increase the frequency of full handshakes and amplify resource consumption during periods of resource exhaustion or other transient failures. Reported by jjfz123. + CVE-2026-50640 From c742ab0a975eed962c109427e0d7e31cf59c0bb0 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 8 Jun 2026 14:19:23 +0100 Subject: [PATCH 125/173] remove trailing whitespace Signed-off-by: Ben Taylor --- tests/suites/test_suite_ssl.data | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index f5fc712b3f..1bdfa68def 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3378,20 +3378,20 @@ elliptic_curve_get_properties TLS 1.3 resume session with ticket tls13_resume_session_with_ticket -TLS 1.3 server propagates RMS computation error +TLS 1.3 server propagates RMS computation error depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_SIGN tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_3:"<= parse finished message":MBEDTLS_SSL_CLIENT_FINISHED:MBEDTLS_SSL_FLUSH_BUFFERS - -TLS 1.3 client propagates RMS computation error + +TLS 1.3 client propagates RMS computation error depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_SIGN tls_transcript_error_propagation:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_3:"<= write finished message":MBEDTLS_SSL_CLIENT_FINISHED:-1 - -TLS 1.2 server propagates EMS computation error -depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + +TLS 1.2 server propagates EMS computation error +depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_2:"=> derive keys":MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:MBEDTLS_SSL_CERTIFICATE_VERIFY - -TLS 1.2 client propagates EMS computation error -depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + +TLS 1.2 client propagates EMS computation error +depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED tls_transcript_error_propagation:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_2:"=> derive keys":MBEDTLS_SSL_CERTIFICATE_VERIFY:-1 TLS 1.3 read early data, early data accepted From 809820934c571c9a3d9557cdd402d385f6556f10 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Wed, 10 Jun 2026 08:11:37 +0100 Subject: [PATCH 126/173] restore missing ext_len set 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 03ef8fd5f9..2a825e07b1 100644 --- a/library/ssl_tls12_server.c +++ b/library/ssl_tls12_server.c @@ -2175,6 +2175,7 @@ static int ssl_write_server_hello(mbedtls_ssl_context *ssl) MBEDTLS_SSL_DEBUG_RET(1, "ssl_write_ecjpake_kkpp_ext", ret); return ret; } + ext_len += olen; #endif #if defined(MBEDTLS_SSL_ALPN) From f234fc5a3c9e910cb00762932261d93f9074bac6 Mon Sep 17 00:00:00 2001 From: Ben Taylor <32939606+bjwtaylor@users.noreply.github.com> Date: Thu, 11 Jun 2026 09:43:59 +0100 Subject: [PATCH 127/173] Update regression test Co-authored-by: Ronald Cron Signed-off-by: Ben Taylor <32939606+bjwtaylor@users.noreply.github.com> --- tests/suites/test_suite_ssl.function | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 40041210ed..3d9dc85aed 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4468,6 +4468,7 @@ void tls_transcript_error_propagation(int endpoint, TEST_EQUAL(mbedtls_test_move_handshake_to_state( peer_ssl_context, abort_ctx.ssl, peer_target_state), 0); + TEST_EQUAL(mbedtls_ssl_flush_output(peer_ssl_context), 0); } TEST_EQUAL(mbedtls_ssl_flush_output(abort_ctx.ssl), 0); From 356e535ff50c7c6e756c9da3b741920f1a1fd9b4 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 11 Jun 2026 10:30:44 +0100 Subject: [PATCH 128/173] Improve tls_transcript_error_propagation testing to check for error codes Signed-off-by: Ben Taylor --- tests/suites/test_suite_ssl.data | 8 ++++---- tests/suites/test_suite_ssl.function | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 1bdfa68def..79206899f2 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3380,19 +3380,19 @@ tls13_resume_session_with_ticket TLS 1.3 server propagates RMS computation error depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_SIGN -tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_3:"<= parse finished message":MBEDTLS_SSL_CLIENT_FINISHED:MBEDTLS_SSL_FLUSH_BUFFERS +tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_3:"<= parse finished message":MBEDTLS_SSL_CLIENT_FINISHED:MBEDTLS_SSL_FLUSH_BUFFERS:MBEDTLS_ERR_SSL_WANT_READ TLS 1.3 client propagates RMS computation error depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_SIGN -tls_transcript_error_propagation:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_3:"<= write finished message":MBEDTLS_SSL_CLIENT_FINISHED:-1 +tls_transcript_error_propagation:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_3:"<= write finished message":MBEDTLS_SSL_CLIENT_FINISHED:-1:MBEDTLS_ERR_SSL_INTERNAL_ERROR TLS 1.2 server propagates EMS computation error depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED -tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_2:"=> derive keys":MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:MBEDTLS_SSL_CERTIFICATE_VERIFY +tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_2:"=> derive keys":MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:MBEDTLS_SSL_CERTIFICATE_VERIFY:PSA_ERROR_GENERIC_ERROR TLS 1.2 client propagates EMS computation error depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED -tls_transcript_error_propagation:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_2:"=> derive keys":MBEDTLS_SSL_CERTIFICATE_VERIFY:-1 +tls_transcript_error_propagation:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_2:"=> derive keys":MBEDTLS_SSL_CERTIFICATE_VERIFY:-1:PSA_ERROR_GENERIC_ERROR TLS 1.3 read early data, early data accepted tls13_read_early_data:TEST_EARLY_DATA_ACCEPTED diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 3d9dc85aed..aba395a8ce 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4410,7 +4410,8 @@ void tls_transcript_error_propagation(int endpoint, int tls_version, const char *trigger, int target_state, - int peer_target_state) + int peer_target_state, + int expected_ret) { int ret = -1; mbedtls_test_ssl_endpoint client_ep, server_ep; @@ -4478,6 +4479,7 @@ void tls_transcript_error_propagation(int endpoint, ret = mbedtls_ssl_handshake_step(abort_ctx.ssl); TEST_ASSERT(abort_ctx.triggered); TEST_ASSERT(ret != 0); + TEST_EQUAL(ret, expected_ret); exit: mbedtls_test_ssl_endpoint_free(&client_ep); From 14cec6ffc1aa145211ba941cb740456b76ef8383 Mon Sep 17 00:00:00 2001 From: Ben Taylor <32939606+bjwtaylor@users.noreply.github.com> Date: Thu, 11 Jun 2026 10:37:00 +0100 Subject: [PATCH 129/173] Fix error codes for tls_transcript_error_propagation Co-authored-by: Ronald Cron Signed-off-by: Ben Taylor <32939606+bjwtaylor@users.noreply.github.com> --- tests/suites/test_suite_ssl.data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 79206899f2..fe279334a0 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3380,7 +3380,7 @@ tls13_resume_session_with_ticket TLS 1.3 server propagates RMS computation error depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_SIGN -tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_3:"<= parse finished message":MBEDTLS_SSL_CLIENT_FINISHED:MBEDTLS_SSL_FLUSH_BUFFERS:MBEDTLS_ERR_SSL_WANT_READ +tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_3:"<= parse finished message":MBEDTLS_SSL_CLIENT_FINISHED:MBEDTLS_SSL_FLUSH_BUFFERS:MBEDTLS_ERR_SSL_INTERNAL_ERROR TLS 1.3 client propagates RMS computation error depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_SIGN From 7cbd8582ee9942ffce5dc907dc36addcdc2185eb Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 11 Jun 2026 11:12:10 +0100 Subject: [PATCH 130/173] Correct error handling in mbedtls_ssl_reset_checksum Signed-off-by: Ben Taylor --- library/ssl_tls.c | 25 ++++++++++++------------- tests/suites/test_suite_ssl.data | 4 ++-- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 86bed60fd8..a1117ed123 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -29,7 +29,6 @@ #include #include "mbedtls/psa_util.h" -#include "md_psa.h" // for mbedtls_md_error_from_psa() #include "psa/crypto.h" #if defined(MBEDTLS_X509_CRT_PARSE_C) @@ -846,21 +845,21 @@ int mbedtls_ssl_reset_checksum(mbedtls_ssl_context *ssl) #if defined(PSA_WANT_ALG_SHA_256) status = psa_hash_abort(&ssl->handshake->fin_sha256_psa); if (status != PSA_SUCCESS) { - return mbedtls_md_error_from_psa(status); + return PSA_TO_MBEDTLS_ERR(status); } status = psa_hash_setup(&ssl->handshake->fin_sha256_psa, PSA_ALG_SHA_256); if (status != PSA_SUCCESS) { - return mbedtls_md_error_from_psa(status); + return PSA_TO_MBEDTLS_ERR(status); } #endif #if defined(PSA_WANT_ALG_SHA_384) status = psa_hash_abort(&ssl->handshake->fin_sha384_psa); if (status != PSA_SUCCESS) { - return mbedtls_md_error_from_psa(status); + return PSA_TO_MBEDTLS_ERR(status); } status = psa_hash_setup(&ssl->handshake->fin_sha384_psa, PSA_ALG_SHA_384); if (status != PSA_SUCCESS) { - return mbedtls_md_error_from_psa(status); + return PSA_TO_MBEDTLS_ERR(status); } #endif return 0; @@ -880,13 +879,13 @@ static int ssl_update_checksum_start(mbedtls_ssl_context *ssl, #if defined(PSA_WANT_ALG_SHA_256) status = psa_hash_update(&ssl->handshake->fin_sha256_psa, buf, len); if (status != PSA_SUCCESS) { - return mbedtls_md_error_from_psa(status); + return PSA_TO_MBEDTLS_ERR(status); } #endif #if defined(PSA_WANT_ALG_SHA_384) status = psa_hash_update(&ssl->handshake->fin_sha384_psa, buf, len); if (status != PSA_SUCCESS) { - return mbedtls_md_error_from_psa(status); + return PSA_TO_MBEDTLS_ERR(status); } #endif return 0; @@ -896,8 +895,8 @@ static int ssl_update_checksum_start(mbedtls_ssl_context *ssl, static int ssl_update_checksum_sha256(mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len) { - return mbedtls_md_error_from_psa(psa_hash_update( - &ssl->handshake->fin_sha256_psa, buf, len)); + return PSA_TO_MBEDTLS_ERR(psa_hash_update( + &ssl->handshake->fin_sha256_psa, buf, len)); } #endif @@ -905,8 +904,8 @@ static int ssl_update_checksum_sha256(mbedtls_ssl_context *ssl, static int ssl_update_checksum_sha384(mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len) { - return mbedtls_md_error_from_psa(psa_hash_update( - &ssl->handshake->fin_sha384_psa, buf, len)); + return PSA_TO_MBEDTLS_ERR(psa_hash_update( + &ssl->handshake->fin_sha384_psa, buf, len)); } #endif @@ -6569,7 +6568,7 @@ static int ssl_calc_verify_tls_psa(const mbedtls_ssl_context *ssl, exit: psa_hash_abort(&cloned_op); - return mbedtls_md_error_from_psa(status); + return PSA_TO_MBEDTLS_ERR(status); } #if defined(PSA_WANT_ALG_SHA_256) @@ -7262,7 +7261,7 @@ static int ssl_calc_finished_tls_generic(mbedtls_ssl_context *ssl, void *ctx, exit: psa_hash_abort(&cloned_op); - return mbedtls_md_error_from_psa(status); + return PSA_TO_MBEDTLS_ERR(status); } #if defined(PSA_WANT_ALG_SHA_256) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index fe279334a0..dbe0dfe44c 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3388,11 +3388,11 @@ tls_transcript_error_propagation:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_ TLS 1.2 server propagates EMS computation error depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED -tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_2:"=> derive keys":MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:MBEDTLS_SSL_CERTIFICATE_VERIFY:PSA_ERROR_GENERIC_ERROR +tls_transcript_error_propagation:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_2:"=> derive keys":MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:MBEDTLS_SSL_CERTIFICATE_VERIFY:MBEDTLS_ERR_SSL_INTERNAL_ERROR TLS 1.2 client propagates EMS computation error depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED -tls_transcript_error_propagation:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_2:"=> derive keys":MBEDTLS_SSL_CERTIFICATE_VERIFY:-1:PSA_ERROR_GENERIC_ERROR +tls_transcript_error_propagation:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_2:"=> derive keys":MBEDTLS_SSL_CERTIFICATE_VERIFY:-1:MBEDTLS_ERR_SSL_INTERNAL_ERROR TLS 1.3 read early data, early data accepted tls13_read_early_data:TEST_EARLY_DATA_ACCEPTED From be883e19f50d9cb66d881598bb02102eabf3a957 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Mon, 22 Jun 2026 14:28:22 +0200 Subject: [PATCH 131/173] include: ssl: add a typedef for unused data in mbedtls_ssl_config and mbedtls_ssl_context Add mbedtls_ssl_unused_data_t type instead of embedding the union inside both structures. Signed-off-by: Valerio Setti --- include/mbedtls/ssl.h | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 2a6d98ab1c..c2f9507a78 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -1324,6 +1324,15 @@ typedef union { void *p; /* typically a pointer to extra data */ } mbedtls_ssl_user_data_t; +/** + * Added at the end of "struct mbedtls_ssl_config" and "struct mbedtls_ssl_context" + * to reserve a field for future use. + */ +typedef union { + size_t number; + void *ptr; +} mbedtls_ssl_unused_data_t; + /** * SSL/TLS configuration to be shared between mbedtls_ssl_context structures. */ @@ -1572,13 +1581,20 @@ struct mbedtls_ssl_config { const mbedtls_x509_crt *MBEDTLS_PRIVATE(dn_hints);/*!< acceptable client cert issuers */ #endif - /* Unused field reserved for future use */ - union { - size_t number; - void *ptr; - } MBEDTLS_PRIVATE(unused); + mbedtls_ssl_unused_data_t MBEDTLS_PRIVATE(unused); }; +/* + * Warning: whenever a change is applied to "mbedtls_ssl_context" please re-run + * the script "tests/scripts/generate_ssl_session_reset_check.py". + * Please note that this script has some limitation that should be considered + * when modifing "mbedtls_ssl_context": + * - Parsed structure must start with struct "mbedtls_ssl_context {" + * (not "typedef struct {"). + * - It must end with "}}" in column 0. + * - Must not contain "#else" or "#elif" conditionals. + * - Must not contain nested struct/union/enum definitions. + */ struct mbedtls_ssl_context { const mbedtls_ssl_config *MBEDTLS_PRIVATE(conf); /*!< configuration information */ @@ -1861,11 +1877,7 @@ struct mbedtls_ssl_context { */ mbedtls_ssl_user_data_t MBEDTLS_PRIVATE(user_data); - /* Unused field reserved for future use */ - union { - size_t number; - void *ptr; - } MBEDTLS_PRIVATE(unused); + mbedtls_ssl_unused_data_t MBEDTLS_PRIVATE(unused); }; /** From 150f1c7b403887b33f71335eae22daa08e1aad14 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Mon, 22 Jun 2026 14:37:41 +0200 Subject: [PATCH 132/173] tests: ssl: split ssl_helpers between public and internal functions Move functions in "ssl_helpers.h" that depend on internal headers to "ssl_helpers_internal.h". This allows to include "ssl_helpers.h" also in programs (which do not have access to internal headers). Signed-off-by: Valerio Setti --- tests/include/test/ssl_helpers.h | 92 ---------------- tests/include/test/ssl_helpers_internal.h | 110 +++++++++++++++++++ tests/src/test_helpers/ssl_helpers.c | 2 + tests/suites/test_suite_ssl.function | 1 + tests/suites/test_suite_ssl_decrypt.function | 1 + 5 files changed, 114 insertions(+), 92 deletions(-) create mode 100644 tests/include/test/ssl_helpers_internal.h diff --git a/tests/include/test/ssl_helpers.h b/tests/include/test/ssl_helpers.h index 467a27f342..c416f32eff 100644 --- a/tests/include/test/ssl_helpers.h +++ b/tests/include/test/ssl_helpers.h @@ -16,12 +16,10 @@ #include #include -#include #include #include #if defined(MBEDTLS_SSL_TLS_C) -#include #include #include @@ -31,10 +29,6 @@ #include "mbedtls/ssl_cache.h" #endif -#define PSA_TO_MBEDTLS_ERR(status) PSA_TO_MBEDTLS_ERR_LIST(status, \ - psa_to_ssl_errors, \ - psa_generic_status_to_mbedtls) - #if defined(MBEDTLS_SSL_PROTO_TLS1_3) #if defined(PSA_WANT_KEY_TYPE_AES) #if defined(PSA_WANT_ALG_GCM) @@ -106,13 +100,6 @@ #define MBEDTLS_TEST_HAS_ADDITIONAL_HASH #endif -enum { -#define MBEDTLS_SSL_TLS1_3_LABEL(name, string) \ - tls13_label_ ## name, - MBEDTLS_SSL_TLS1_3_LABEL_LIST -#undef MBEDTLS_SSL_TLS1_3_LABEL -}; - #if defined(MBEDTLS_SSL_ALPN) #define MBEDTLS_TEST_MAX_ALPN_LIST_SIZE 10 #endif @@ -614,68 +601,6 @@ int mbedtls_test_move_handshake_to_state(mbedtls_ssl_context *ssl, #endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */ -/* - * Helper function setting up inverse record transformations - * using given cipher, hash, EtM mode, authentication tag length, - * and version. - */ -#define CHK(x) \ - do \ - { \ - if (!(x)) \ - { \ - ret = -1; \ - goto cleanup; \ - } \ - } while (0) - -#if MBEDTLS_SSL_CID_OUT_LEN_MAX > MBEDTLS_SSL_CID_IN_LEN_MAX -#define SSL_CID_LEN_MIN MBEDTLS_SSL_CID_IN_LEN_MAX -#else -#define SSL_CID_LEN_MIN MBEDTLS_SSL_CID_OUT_LEN_MAX -#endif - -#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ - defined(PSA_WANT_ALG_CBC_NO_PADDING) && defined(PSA_WANT_KEY_TYPE_AES) -int mbedtls_test_psa_cipher_encrypt_helper(mbedtls_ssl_transform *transform, - const unsigned char *iv, - size_t iv_len, - const unsigned char *input, - size_t ilen, - unsigned char *output, - size_t *olen); -#endif /* MBEDTLS_SSL_PROTO_TLS1_2 && PSA_WANT_ALG_CBC_NO_PADDING && - PSA_WANT_KEY_TYPE_AES */ - -int mbedtls_test_ssl_build_transforms(mbedtls_ssl_transform *t_in, - mbedtls_ssl_transform *t_out, - int cipher_type, int hash_id, - int etm, int tag_mode, - mbedtls_ssl_protocol_version tls_version, - size_t cid0_len, - size_t cid1_len); - -#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) -/** - * \param[in,out] record The record to prepare. - * It must contain the data to MAC at offset - * `record->data_offset`, of length - * `record->data_length`. - * On success, write the MAC immediately - * after the data and increment - * `record->data_length` accordingly. - * \param[in,out] transform_out The out transform, typically prepared by - * mbedtls_test_ssl_build_transforms(). - * Its HMAC context may be used. Other than that - * it is treated as an input parameter. - * - * \return 0 on success, an `MBEDTLS_ERR_xxx` error code - * or -1 on error. - */ -int mbedtls_test_ssl_prepare_record_mac(mbedtls_record *record, - mbedtls_ssl_transform *transform_out); -#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */ - /* * Populate a session structure for serialization tests. * Choose dummy values, mostly non-0 to distinguish from the init default. @@ -775,23 +700,6 @@ void mbedtls_test_ssl_perform_handshake( const mbedtls_test_handshake_test_options *options); #endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */ -#if defined(MBEDTLS_TEST_HOOKS) -/* - * Tweak vector lengths in a TLS 1.3 Certificate message - * - * \param[in] buf Buffer containing the Certificate message to tweak - * \param[in]]out] end End of the buffer to parse - * \param tweak Tweak identifier (from 1 to the number of tweaks). - * \param[out] expected_result Error code expected from the parsing function - * \param[out] args Arguments of the MBEDTLS_SSL_CHK_BUF_READ_PTR call that - * is expected to fail. All zeroes if no - * MBEDTLS_SSL_CHK_BUF_READ_PTR failure is expected. - */ -int mbedtls_test_tweak_tls13_certificate_msg_vector_len( - unsigned char *buf, unsigned char **end, int tweak, - int *expected_result, mbedtls_ssl_chk_buf_ptr_args *args); -#endif /* MBEDTLS_TEST_HOOKS */ - #if defined(MBEDTLS_SSL_SESSION_TICKETS) int mbedtls_test_ticket_write( void *p_ticket, const mbedtls_ssl_session *session, diff --git a/tests/include/test/ssl_helpers_internal.h b/tests/include/test/ssl_helpers_internal.h new file mode 100644 index 0000000000..7180534f79 --- /dev/null +++ b/tests/include/test/ssl_helpers_internal.h @@ -0,0 +1,110 @@ +/** \file ssl_helpers.h + * + * \brief This file contains helper functions for TLS that rely on private + * headers. + */ + +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef SSL_HELPERS_INTERNAL_H +#define SSL_HELPERS_INTERNAL_H + +#if defined(MBEDTLS_SSL_TLS_C) +#include + +#define PSA_TO_MBEDTLS_ERR(status) PSA_TO_MBEDTLS_ERR_LIST(status, \ + psa_to_ssl_errors, \ + psa_generic_status_to_mbedtls) + +enum { +#define MBEDTLS_SSL_TLS1_3_LABEL(name, string) \ + tls13_label_ ## name, + MBEDTLS_SSL_TLS1_3_LABEL_LIST +#undef MBEDTLS_SSL_TLS1_3_LABEL +}; + +/* + * Helper function setting up inverse record transformations + * using given cipher, hash, EtM mode, authentication tag length, + * and version. + */ +#define CHK(x) \ + do \ + { \ + if (!(x)) \ + { \ + ret = -1; \ + goto cleanup; \ + } \ + } while (0) + +#if MBEDTLS_SSL_CID_OUT_LEN_MAX > MBEDTLS_SSL_CID_IN_LEN_MAX +#define SSL_CID_LEN_MIN MBEDTLS_SSL_CID_IN_LEN_MAX +#else +#define SSL_CID_LEN_MIN MBEDTLS_SSL_CID_OUT_LEN_MAX +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(PSA_WANT_ALG_CBC_NO_PADDING) && defined(PSA_WANT_KEY_TYPE_AES) +int mbedtls_test_psa_cipher_encrypt_helper(mbedtls_ssl_transform *transform, + const unsigned char *iv, + size_t iv_len, + const unsigned char *input, + size_t ilen, + unsigned char *output, + size_t *olen); +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 && PSA_WANT_ALG_CBC_NO_PADDING && + PSA_WANT_KEY_TYPE_AES */ + +int mbedtls_test_ssl_build_transforms(mbedtls_ssl_transform *t_in, + mbedtls_ssl_transform *t_out, + int cipher_type, int hash_id, + int etm, int tag_mode, + mbedtls_ssl_protocol_version tls_version, + size_t cid0_len, + size_t cid1_len); + +#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) +/** + * \param[in,out] record The record to prepare. + * It must contain the data to MAC at offset + * `record->data_offset`, of length + * `record->data_length`. + * On success, write the MAC immediately + * after the data and increment + * `record->data_length` accordingly. + * \param[in,out] transform_out The out transform, typically prepared by + * mbedtls_test_ssl_build_transforms(). + * Its HMAC context may be used. Other than that + * it is treated as an input parameter. + * + * \return 0 on success, an `MBEDTLS_ERR_xxx` error code + * or -1 on error. + */ +int mbedtls_test_ssl_prepare_record_mac(mbedtls_record *record, + mbedtls_ssl_transform *transform_out); +#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */ + +#if defined(MBEDTLS_TEST_HOOKS) +/* + * Tweak vector lengths in a TLS 1.3 Certificate message + * + * \param[in] buf Buffer containing the Certificate message to tweak + * \param[in]]out] end End of the buffer to parse + * \param tweak Tweak identifier (from 1 to the number of tweaks). + * \param[out] expected_result Error code expected from the parsing function + * \param[out] args Arguments of the MBEDTLS_SSL_CHK_BUF_READ_PTR call that + * is expected to fail. All zeroes if no + * MBEDTLS_SSL_CHK_BUF_READ_PTR failure is expected. + */ +int mbedtls_test_tweak_tls13_certificate_msg_vector_len( + unsigned char *buf, unsigned char **end, int tweak, + int *expected_result, mbedtls_ssl_chk_buf_ptr_args *args); +#endif /* MBEDTLS_TEST_HOOKS */ + +#endif /* MBEDTLS_SSL_TLS_C */ + +#endif /* SSL_HELPERS_INTERNAL_H */ diff --git a/tests/src/test_helpers/ssl_helpers.c b/tests/src/test_helpers/ssl_helpers.c index 08cfe252af..780c4f319b 100644 --- a/tests/src/test_helpers/ssl_helpers.c +++ b/tests/src/test_helpers/ssl_helpers.c @@ -9,6 +9,8 @@ */ #include +#include +#include #include "mbedtls/psa_util.h" #include diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index cc73f49aaf..e05cf72bcb 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -9,6 +9,7 @@ #include #include #include +#include #include #include diff --git a/tests/suites/test_suite_ssl_decrypt.function b/tests/suites/test_suite_ssl_decrypt.function index 7a22939eb4..dd26537127 100644 --- a/tests/suites/test_suite_ssl_decrypt.function +++ b/tests/suites/test_suite_ssl_decrypt.function @@ -5,6 +5,7 @@ #include #include #include +#include /* END_HEADER */ From 0ff7a2e8b7ac2348fd70d307fcb614ea779d3bf9 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Mon, 22 Jun 2026 14:39:15 +0200 Subject: [PATCH 133/173] tests: scripts: add generate_ssl_session_reset_check.py Togethere with the framework counterpart ('ssl_session_reset_check.py') this script is used to automatically generate the function 'mbedtls_test_ssl_check_context_after_session_reset()'. The goal of this function is to verify that 'mbedtls_ssl_session_reset()' properly handled (reset or keep) all the fields of the 'mbedtls_ssl_context' structure. Signed-off-by: Valerio Setti --- .../generate_ssl_session_reset_check.py | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100755 tests/scripts/generate_ssl_session_reset_check.py diff --git a/tests/scripts/generate_ssl_session_reset_check.py b/tests/scripts/generate_ssl_session_reset_check.py new file mode 100755 index 0000000000..fa67134ca4 --- /dev/null +++ b/tests/scripts/generate_ssl_session_reset_check.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +"""Generate test code to validate mbedtls_ssl_session_reset(). +""" + +# Copyright The Mbed TLS Contributors +# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + +import scripts_path # pylint: disable=unused-import +from mbedtls_framework import ssl_session_reset_check + +RULES = { + # Fields that are reset + 'state': ssl_session_reset_check.ResetBehavior.RESET, + 'renego_status': ssl_session_reset_check.ResetBehavior.RESET, + 'renego_records_seen': ssl_session_reset_check.ResetBehavior.RESET, + 'early_data_state': ssl_session_reset_check.ResetBehavior.RESET, + 'badmac_seen': ssl_session_reset_check.ResetBehavior.RESET, + 'session_in': ssl_session_reset_check.ResetBehavior.RESET, + 'session_out': ssl_session_reset_check.ResetBehavior.RESET, + 'session': ssl_session_reset_check.ResetBehavior.RESET, + 'transform_in': ssl_session_reset_check.ResetBehavior.RESET, + 'transform_out': ssl_session_reset_check.ResetBehavior.RESET, + 'transform': ssl_session_reset_check.ResetBehavior.RESET, + 'transform_application': ssl_session_reset_check.ResetBehavior.RESET, + 'in_offt': ssl_session_reset_check.ResetBehavior.RESET, + 'in_msgtype': ssl_session_reset_check.ResetBehavior.RESET, + 'in_msglen': ssl_session_reset_check.ResetBehavior.RESET, + 'in_left': ssl_session_reset_check.ResetBehavior.RESET, + 'in_epoch': ssl_session_reset_check.ResetBehavior.RESET, + 'next_record_offset': ssl_session_reset_check.ResetBehavior.RESET, + 'in_window_top': ssl_session_reset_check.ResetBehavior.RESET, + 'in_window': ssl_session_reset_check.ResetBehavior.RESET, + 'in_hslen': ssl_session_reset_check.ResetBehavior.RESET, + 'in_hsfraglen': ssl_session_reset_check.ResetBehavior.RESET, + 'nb_zero': ssl_session_reset_check.ResetBehavior.RESET, + 'keep_current_message': ssl_session_reset_check.ResetBehavior.RESET, + 'in_fatal_alert_recv': ssl_session_reset_check.ResetBehavior.RESET, + 'in_fatal_alert_type': ssl_session_reset_check.ResetBehavior.RESET, + 'send_alert': ssl_session_reset_check.ResetBehavior.RESET, + 'alert_type': ssl_session_reset_check.ResetBehavior.RESET, + 'alert_reason': ssl_session_reset_check.ResetBehavior.RESET, + 'discard_early_data_record': ssl_session_reset_check.ResetBehavior.RESET, + 'total_early_data_size': ssl_session_reset_check.ResetBehavior.RESET, + 'out_msgtype': ssl_session_reset_check.ResetBehavior.RESET, + 'out_msglen': ssl_session_reset_check.ResetBehavior.RESET, + 'out_left': ssl_session_reset_check.ResetBehavior.RESET, + 'cur_out_ctr': ssl_session_reset_check.ResetBehavior.RESET, + 'alpn_chosen': ssl_session_reset_check.ResetBehavior.RESET, + 'dtls_srtp_info': ssl_session_reset_check.ResetBehavior.RESET, + 'cli_id': ssl_session_reset_check.ResetBehavior.RESET, + 'cli_id_len': ssl_session_reset_check.ResetBehavior.RESET, + 'secure_renegotiation': ssl_session_reset_check.ResetBehavior.RESET, + 'verify_data_len': ssl_session_reset_check.ResetBehavior.RESET, + 'own_verify_data': ssl_session_reset_check.ResetBehavior.RESET, + 'peer_verify_data': ssl_session_reset_check.ResetBehavior.RESET, + + # Fields that are preserved during reset + 'conf': ssl_session_reset_check.ResetBehavior.KEEP, + 'f_vrfy': ssl_session_reset_check.ResetBehavior.KEEP, + 'p_vrfy': ssl_session_reset_check.ResetBehavior.KEEP, + 'f_send': ssl_session_reset_check.ResetBehavior.KEEP, + 'f_recv': ssl_session_reset_check.ResetBehavior.KEEP, + 'f_recv_timeout': ssl_session_reset_check.ResetBehavior.KEEP, + 'p_bio': ssl_session_reset_check.ResetBehavior.KEEP, + 'p_timer': ssl_session_reset_check.ResetBehavior.KEEP, + 'f_set_timer': ssl_session_reset_check.ResetBehavior.KEEP, + 'f_get_timer': ssl_session_reset_check.ResetBehavior.KEEP, + 'disable_datagram_packing': ssl_session_reset_check.ResetBehavior.KEEP, + 'mtu': ssl_session_reset_check.ResetBehavior.KEEP, + 'hostname': ssl_session_reset_check.ResetBehavior.KEEP, + 'own_cid': ssl_session_reset_check.ResetBehavior.KEEP, + 'own_cid_len': ssl_session_reset_check.ResetBehavior.KEEP, + 'negotiate_cid': ssl_session_reset_check.ResetBehavior.KEEP, + 'f_export_keys': ssl_session_reset_check.ResetBehavior.KEEP, + 'p_export_keys': ssl_session_reset_check.ResetBehavior.KEEP, + + # Fields which are intentionally not checked. + 'unused': ssl_session_reset_check.ResetBehavior.IGNORE, + + # Pointers which might be reallocated during reset + 'in_buf': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'in_ctr': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'in_hdr': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'in_cid': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'in_len': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'in_iv': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'in_msg': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'out_buf': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'out_ctr': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'out_hdr': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'out_cid': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'out_len': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'out_iv': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'out_msg': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'session_negotiate': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'handshake': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'transform_negotiate': ssl_session_reset_check.ResetBehavior.REALLOCATE, + + # Fields with custom check rules. Rules must be defined in the + # SPECIAL_BEHAVIORS dictionary below. + 'flags': ssl_session_reset_check.ResetBehavior.SPECIAL, + 'tls_version': ssl_session_reset_check.ResetBehavior.SPECIAL, + 'user_data': ssl_session_reset_check.ResetBehavior.SPECIAL, + 'in_buf_len': ssl_session_reset_check.ResetBehavior.SPECIAL, + 'out_buf_len': ssl_session_reset_check.ResetBehavior.SPECIAL, +} + +SPECIAL_BEHAVIORS = { + 'flags': ['TEST_EQUAL((after->flags & ~(MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION)), ' + 'initial.flags)', + 'TEST_EQUAL((before->flags & MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION), ' + + '(after->flags & MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION));'], + 'tls_version': ['TEST_ASSERT(after->tls_version == after->conf->max_tls_version);'], + 'user_data': ['TEST_ASSERT(before->user_data.n == after->user_data.n);'], + 'in_buf_len': ['TEST_ASSERT(after->in_buf_len == MBEDTLS_SSL_IN_BUFFER_LEN);'], + 'out_buf_len': ['TEST_ASSERT(after->out_buf_len == MBEDTLS_SSL_OUT_BUFFER_LEN);'], +} + +NAMED_STRUCTURES = [ + 'dtls_srtp_info', +] + +FIELDS_INFO = ssl_session_reset_check.FieldsInfo(RULES, + SPECIAL_BEHAVIORS, + NAMED_STRUCTURES) + +if __name__ == '__main__': + ssl_session_reset_check.main(FIELDS_INFO) From e19a4cfd8085bd91a3bb59df82e403d0fdd6729a Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Mon, 22 Jun 2026 14:49:38 +0200 Subject: [PATCH 134/173] tests: add prototype and implementation of mbedtls_test_ssl_check_context_after_session_reset Ideally the implementation shouldn't be checked in git, but for the time being there is no support in building source code for tests from the binary folder, so it's accepted as a temporary solution. Signed-off-by: Valerio Setti --- tests/include/test/ssl_helpers.h | 17 +++ tests/src/ssl_context_reset_verifier.c | 190 +++++++++++++++++++++++++ 2 files changed, 207 insertions(+) create mode 100644 tests/src/ssl_context_reset_verifier.c diff --git a/tests/include/test/ssl_helpers.h b/tests/include/test/ssl_helpers.h index c416f32eff..6a86937df4 100644 --- a/tests/include/test/ssl_helpers.h +++ b/tests/include/test/ssl_helpers.h @@ -746,6 +746,23 @@ int mbedtls_test_get_tls13_ticket( &psa_type, &psa_bits), \ PSA_ERROR_NOT_SUPPORTED); +/** + * Verify that mbedtls_ssl_session_reset() properly managed fields of the + * mbedtls_ssl_context structure. The expected action on reset depends on the + * specific field. + * + * Note: the code is automatically generated from the python script + * "tests/scripts/generate_ssl_session_reset_check.py". + * + * \param[in] before The SSL context before mbedtls_ssl_session_reset() + * is called on it. This is used for fields that + * should be kept untouched during the reset. + * \param[in] after The SSL context after mbedtls_ssl_session_reset() + * is called on it. + */ +int mbedtls_test_ssl_check_context_after_session_reset(const mbedtls_ssl_context *before, + const mbedtls_ssl_context *after); + #endif /* MBEDTLS_SSL_TLS_C */ #endif /* SSL_HELPERS_H */ diff --git a/tests/src/ssl_context_reset_verifier.c b/tests/src/ssl_context_reset_verifier.c new file mode 100644 index 0000000000..2f106e9067 --- /dev/null +++ b/tests/src/ssl_context_reset_verifier.c @@ -0,0 +1,190 @@ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +/* + * The following function was automatically generated through the script + * ./tests/scripts/generate_ssl_session_reset_check.py. + */ + +#include +#include +#include "mbedtls/psa_util.h" +#include + +#include + +#if defined(MBEDTLS_SSL_TLS_C) + +int mbedtls_test_ssl_check_context_after_session_reset(const mbedtls_ssl_context *before, + const mbedtls_ssl_context *after) +{ + mbedtls_ssl_context initial; + int ret = -1; + + /* Create a freshly initialized SSL context*/ + memset(&initial, 0, sizeof(initial)); + mbedtls_ssl_init(&initial); + TEST_EQUAL(mbedtls_ssl_setup(&initial, after->conf), 0); + + /* *INDENT-OFF* */ + TEST_ASSERT(before->conf == after->conf); + TEST_ASSERT(after->state == initial.state); + TEST_EQUAL((after->flags & ~(MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION)), initial.flags) + TEST_EQUAL((before->flags & MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION), (after->flags & MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION)); +#if defined(MBEDTLS_SSL_RENEGOTIATION) + TEST_ASSERT(after->renego_status == initial.renego_status); +#endif +#if defined(MBEDTLS_SSL_RENEGOTIATION) + TEST_ASSERT(after->renego_records_seen == initial.renego_records_seen); +#endif + TEST_ASSERT(after->tls_version == after->conf->max_tls_version); +#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C) + TEST_ASSERT(after->early_data_state == initial.early_data_state); +#endif + TEST_ASSERT(after->badmac_seen == initial.badmac_seen); +#if defined(MBEDTLS_X509_CRT_PARSE_C) + TEST_ASSERT(before->f_vrfy == after->f_vrfy); +#endif +#if defined(MBEDTLS_X509_CRT_PARSE_C) + TEST_ASSERT(before->p_vrfy == after->p_vrfy); +#endif + TEST_ASSERT(before->f_send == after->f_send); + TEST_ASSERT(before->f_recv == after->f_recv); + TEST_ASSERT(before->f_recv_timeout == after->f_recv_timeout); + TEST_ASSERT(before->p_bio == after->p_bio); + TEST_ASSERT(after->session_in == initial.session_in); + TEST_ASSERT(after->session_out == initial.session_out); + TEST_ASSERT(after->session == initial.session); + TEST_ASSERT(after->session_negotiate != NULL); + TEST_ASSERT(after->handshake != NULL); + TEST_ASSERT(after->transform_in == initial.transform_in); + TEST_ASSERT(after->transform_out == initial.transform_out); + TEST_ASSERT(after->transform == initial.transform); +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + TEST_ASSERT(after->transform_negotiate != NULL); +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3) + TEST_ASSERT(after->transform_application == initial.transform_application); +#endif + TEST_ASSERT(before->p_timer == after->p_timer); + TEST_ASSERT(before->f_set_timer == after->f_set_timer); + TEST_ASSERT(before->f_get_timer == after->f_get_timer); + TEST_ASSERT(after->in_buf != NULL); + TEST_ASSERT(after->in_ctr != NULL); + TEST_ASSERT(after->in_hdr != NULL); +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + TEST_ASSERT(after->in_cid != NULL); +#endif + TEST_ASSERT(after->in_len != NULL); + TEST_ASSERT(after->in_iv != NULL); + TEST_ASSERT(after->in_msg != NULL); + TEST_ASSERT(after->in_offt == initial.in_offt); + TEST_ASSERT(after->in_msgtype == initial.in_msgtype); + TEST_ASSERT(after->in_msglen == initial.in_msglen); + TEST_ASSERT(after->in_left == initial.in_left); +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + TEST_ASSERT(after->in_buf_len == MBEDTLS_SSL_IN_BUFFER_LEN); +#endif +#if defined(MBEDTLS_SSL_PROTO_DTLS) + TEST_ASSERT(after->in_epoch == initial.in_epoch); +#endif +#if defined(MBEDTLS_SSL_PROTO_DTLS) + TEST_ASSERT(after->next_record_offset == initial.next_record_offset); +#endif +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + TEST_ASSERT(after->in_window_top == initial.in_window_top); +#endif +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + TEST_ASSERT(after->in_window == initial.in_window); +#endif + TEST_ASSERT(after->in_hslen == initial.in_hslen); + TEST_ASSERT(after->in_hsfraglen == initial.in_hsfraglen); + TEST_ASSERT(after->nb_zero == initial.nb_zero); + TEST_ASSERT(after->keep_current_message == initial.keep_current_message); + TEST_ASSERT(after->in_fatal_alert_recv == initial.in_fatal_alert_recv); + TEST_ASSERT(after->in_fatal_alert_type == initial.in_fatal_alert_type); + TEST_ASSERT(after->send_alert == initial.send_alert); + TEST_ASSERT(after->alert_type == initial.alert_type); + TEST_ASSERT(after->alert_reason == initial.alert_reason); +#if defined(MBEDTLS_SSL_PROTO_DTLS) + TEST_EQUAL(before->disable_datagram_packing, after->disable_datagram_packing); +#endif +#if defined(MBEDTLS_SSL_EARLY_DATA) + +#if defined(MBEDTLS_SSL_SRV_C) + TEST_ASSERT(after->discard_early_data_record == initial.discard_early_data_record); +#endif +#endif +#if defined(MBEDTLS_SSL_EARLY_DATA) + TEST_ASSERT(after->total_early_data_size == initial.total_early_data_size); +#endif + TEST_ASSERT(after->out_buf != NULL); + TEST_ASSERT(after->out_ctr != NULL); + TEST_ASSERT(after->out_hdr != NULL); +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + TEST_ASSERT(after->out_cid != NULL); +#endif + TEST_ASSERT(after->out_len != NULL); + TEST_ASSERT(after->out_iv != NULL); + TEST_ASSERT(after->out_msg != NULL); + TEST_ASSERT(after->out_msgtype == initial.out_msgtype); + TEST_ASSERT(after->out_msglen == initial.out_msglen); + TEST_ASSERT(after->out_left == initial.out_left); +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + TEST_ASSERT(after->out_buf_len == MBEDTLS_SSL_OUT_BUFFER_LEN); +#endif + TEST_MEMORY_COMPARE(after->cur_out_ctr, sizeof(after->cur_out_ctr), initial.cur_out_ctr, sizeof(initial.cur_out_ctr)); +#if defined(MBEDTLS_SSL_PROTO_DTLS) + TEST_EQUAL(before->mtu, after->mtu); +#endif +#if defined(MBEDTLS_X509_CRT_PARSE_C) + TEST_ASSERT(before->hostname == after->hostname); +#endif +#if defined(MBEDTLS_SSL_ALPN) + TEST_ASSERT(after->alpn_chosen == initial.alpn_chosen); +#endif +#if defined(MBEDTLS_SSL_DTLS_SRTP) + TEST_MEMORY_COMPARE(&(after->dtls_srtp_info), sizeof(after->dtls_srtp_info), &(initial.dtls_srtp_info), sizeof(initial.dtls_srtp_info)); +#endif +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) + TEST_ASSERT(after->cli_id == initial.cli_id); +#endif +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) + TEST_ASSERT(after->cli_id_len == initial.cli_id_len); +#endif + TEST_ASSERT(after->secure_renegotiation == initial.secure_renegotiation); +#if defined(MBEDTLS_SSL_RENEGOTIATION) + TEST_ASSERT(after->verify_data_len == initial.verify_data_len); +#endif +#if defined(MBEDTLS_SSL_RENEGOTIATION) + TEST_MEMORY_COMPARE(after->own_verify_data, sizeof(after->own_verify_data), initial.own_verify_data, sizeof(initial.own_verify_data)); +#endif +#if defined(MBEDTLS_SSL_RENEGOTIATION) + TEST_MEMORY_COMPARE(after->peer_verify_data, sizeof(after->peer_verify_data), initial.peer_verify_data, sizeof(initial.peer_verify_data)); +#endif +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + TEST_MEMORY_COMPARE(before->own_cid, sizeof(before->own_cid), after->own_cid, sizeof(after->own_cid)); +#endif +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + TEST_EQUAL(before->own_cid_len, after->own_cid_len); +#endif +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + TEST_EQUAL(before->negotiate_cid, after->negotiate_cid); +#endif + TEST_ASSERT(before->f_export_keys == after->f_export_keys); + TEST_ASSERT(before->p_export_keys == after->p_export_keys); + TEST_ASSERT(before->user_data.n == after->user_data.n); + /* unused is ignored */ + /* *INDENT-ON* */ + + ret = 0; + +exit: + mbedtls_ssl_free(&initial); + + return ret; +} + +#endif /* MBEDTLS_SSL_TLS_C */ From 0e357891576768a03d1b0e519bf38eb8c978835d Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Mon, 22 Jun 2026 14:51:24 +0200 Subject: [PATCH 135/173] tests|programs: call check_context_after_session_reset whenever mbedtls_ssl_session_reset Call mbedtls_test_ssl_check_context_after_session_reset both in programs (ssl_client2 and ssl_server2) and tests to ensure that the SSL context has been properly handled when mbedtls_ssl_session_reset was called. Signed-off-by: Valerio Setti --- programs/ssl/ssl_client2.c | 10 ++++++++++ programs/ssl/ssl_server2.c | 9 +++++++++ tests/src/test_helpers/ssl_helpers.c | 8 ++++++++ 3 files changed, 27 insertions(+) diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 9dc99c3e0b..ad87e225da 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -22,6 +22,7 @@ int main(void) #else /* !MBEDTLS_SSL_TEST_IMPOSSIBLE && MBEDTLS_SSL_CLI_C */ #include "test/psa_crypto_helpers.h" +#include "test/ssl_helpers.h" /* Size of memory to be allocated for the heap, when using the library's memory * management and MBEDTLS_MEMORY_BUFFER_ALLOC_C is enabled. */ @@ -2800,12 +2801,21 @@ send_request: memset(peer_crt_info, 0, sizeof(peer_crt_info)); #endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */ + /* Dump the SSL context before resetting it. This will be used below + * to check if the reset function worked properly. */ + mbedtls_ssl_context ssl_before = ssl; if ((ret = mbedtls_ssl_session_reset(&ssl)) != 0) { mbedtls_printf(" failed\n ! mbedtls_ssl_session_reset returned -0x%x\n\n", (unsigned int) -ret); goto exit; } + if (mbedtls_test_ssl_check_context_after_session_reset(&ssl_before, &ssl) != 0) { + mbedtls_printf( + " failed\n ! mbedtls_ssl_session_reset didn't properly reset ssl context\n\n"); + goto exit; + } + while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 541c6a6b43..b5cdc817b8 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -52,6 +52,7 @@ int main(void) #endif #include "test/psa_crypto_helpers.h" +#include "test/ssl_helpers.h" #include "mbedtls/pk.h" #if defined(MBEDTLS_PK_HAVE_PRIVATE_HEADER) @@ -3271,7 +3272,15 @@ reset: mbedtls_net_free(&client_fd); + /* Dump the SSL context before resetting it. This will be used below + * to check if the reset function worked properly. */ + mbedtls_ssl_context ssl_before = ssl; mbedtls_ssl_session_reset(&ssl); + if (mbedtls_test_ssl_check_context_after_session_reset(&ssl_before, &ssl) != 0) { + mbedtls_printf( + " failed\n ! mbedtls_ssl_session_reset didn't properly reset ssl context\n\n"); + goto exit; + } /* * 3. Wait until a client connects diff --git a/tests/src/test_helpers/ssl_helpers.c b/tests/src/test_helpers/ssl_helpers.c index 780c4f319b..0d2687e795 100644 --- a/tests/src/test_helpers/ssl_helpers.c +++ b/tests/src/test_helpers/ssl_helpers.c @@ -1035,6 +1035,14 @@ int mbedtls_test_ssl_endpoint_init( void mbedtls_test_ssl_endpoint_free( mbedtls_test_ssl_endpoint *ep) { + mbedtls_ssl_context ssl_before; + + /* Dump the SSL context before resetting it */ + memcpy(&ssl_before, &(ep->ssl), sizeof(mbedtls_ssl_context)); + + mbedtls_ssl_session_reset(&(ep->ssl)); + /* Check that required fields were properly reset */ + mbedtls_test_ssl_check_context_after_session_reset(&ssl_before, &(ep->ssl)); mbedtls_ssl_free(&(ep->ssl)); mbedtls_ssl_config_free(&(ep->conf)); From 4b086ed04e12a0d621cee6dfbc30ee6f2e74d0bf Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Mon, 22 Jun 2026 14:53:21 +0200 Subject: [PATCH 136/173] library: ssl: reset some SSL context's fields in mbedtls_ssl_session_reset Following fields were not properly reset when mbedtls_ssl_session_reset was called: - badmac_seen - dtls_srtp_info - alert_reason - alert_type Signed-off-by: Valerio Setti --- library/ssl_tls.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index e8a44f834c..b1c6c22de1 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -1309,6 +1309,8 @@ void mbedtls_ssl_session_reset_msg_layer(mbedtls_ssl_context *ssl, ssl->in_fatal_alert_recv = 0; ssl->in_fatal_alert_type = 0; ssl->send_alert = 0; + ssl->alert_reason = 0; + ssl->alert_type = 0; /* Reset outgoing message writing */ ssl->out_msgtype = 0; @@ -1358,6 +1360,8 @@ int mbedtls_ssl_session_reset_int(mbedtls_ssl_context *ssl, int partial) ssl->flags &= MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION; ssl->tls_version = ssl->conf->max_tls_version; + ssl->badmac_seen = 0; + mbedtls_ssl_session_reset_msg_layer(ssl, partial); /* Reset renegotiation state */ @@ -1383,6 +1387,10 @@ int mbedtls_ssl_session_reset_int(mbedtls_ssl_context *ssl, int partial) ssl->alpn_chosen = NULL; #endif +#if defined(MBEDTLS_SSL_DTLS_SRTP) + memset(&ssl->dtls_srtp_info, 0, sizeof(ssl->dtls_srtp_info)); +#endif /* MBEDTLS_SSL_DTLS_SRTP */ + #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) int free_cli_id = 1; #if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) From f8a7d87fe1e7c73fff839c25bab135f389b04fa5 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Mon, 22 Jun 2026 14:55:31 +0200 Subject: [PATCH 137/173] changelog: add reset for some fields of the SSL context structure Signed-off-by: Valerio Setti --- ChangeLog.d/security1585.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 ChangeLog.d/security1585.txt diff --git a/ChangeLog.d/security1585.txt b/ChangeLog.d/security1585.txt new file mode 100644 index 0000000000..f9f21691db --- /dev/null +++ b/ChangeLog.d/security1585.txt @@ -0,0 +1,6 @@ +Security + * Ensure 'badmac_seen' and 'dtls_srtp_info' fields from 'mbedtls_ssl_context' + are properly zeroized when mbedtls_ssl_session_reset() is called. This + could cause premature DTLS connection failure or incorrect DTLS-SRTP + parameter inheritance for applications reusing an SSL context. + Reported by jjfz123. CVE-2026-50585. From aa6c52b6cd7f992958daef9432946ba09fb29d01 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Tue, 23 Jun 2026 18:14:15 +0200 Subject: [PATCH 138/173] include: ssl: fix documentation of mbedtls_ssl_set_cid Specify that the configured CID will apply to all subsequent handshakes not just to the next one. Signed-off-by: Valerio Setti --- include/mbedtls/ssl.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index c2f9507a78..00e28442d6 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -2181,7 +2181,7 @@ void mbedtls_ssl_set_bio(mbedtls_ssl_context *ssl, /** * \brief Configure the use of the Connection ID (CID) - * extension in the next handshake. + * extension in subsequent handshakes. * * Reference: RFC 9146 (or draft-ietf-tls-dtls-connection-id-05 * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05 @@ -2202,7 +2202,7 @@ void mbedtls_ssl_set_bio(mbedtls_ssl_context *ssl, * headers of outgoing messages. * * This API enables or disables the use of the CID extension - * in the next handshake and sets the value of the CID to + * in subsequent handshakes and sets the value of the CID to * be used for incoming messages. * * \param ssl The SSL context to configure. This must be initialized. @@ -2233,11 +2233,11 @@ void mbedtls_ssl_set_bio(mbedtls_ssl_context *ssl, * successful call to this function to run the handshake. * * \note This call cannot guarantee that the use of the CID - * will be successfully negotiated in the next handshake, + * will be successfully negotiated in subsequent handshakes, * because the peer might not support it. Specifically: * - On the Client, enabling the use of the CID through - * this call implies that the `ClientHello` in the next - * handshake will include the CID extension, thereby + * this call implies that the `ClientHello` in subsequent + * handshakes will include the CID extension, thereby * offering the use of the CID to the server. Only if * the `ServerHello` contains the CID extension, too, * the CID extension will actually be put to use. @@ -2260,7 +2260,7 @@ void mbedtls_ssl_set_bio(mbedtls_ssl_context *ssl, * Mbed TLS. * * \return \c 0 on success. In this case, the CID configuration - * applies to the next handshake. + * applies to subsequent handshakes. * \return A negative error code on failure. */ int mbedtls_ssl_set_cid(mbedtls_ssl_context *ssl, From f4dcb5c692e1b2adcc1434cc82e5ceab4bbcef2f Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Tue, 23 Jun 2026 22:36:04 +0200 Subject: [PATCH 139/173] changelog: add note for documentation fix for mbedtls_ssl_set_cid Signed-off-by: Valerio Setti --- ChangeLog.d/mbedtls_ssl_set_cid-documentation.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 ChangeLog.d/mbedtls_ssl_set_cid-documentation.txt diff --git a/ChangeLog.d/mbedtls_ssl_set_cid-documentation.txt b/ChangeLog.d/mbedtls_ssl_set_cid-documentation.txt new file mode 100644 index 0000000000..1ad970fdfb --- /dev/null +++ b/ChangeLog.d/mbedtls_ssl_set_cid-documentation.txt @@ -0,0 +1,3 @@ +Bugfix + * Fixed documentation of mbedtls_ssl_set_cid(): the set CID configuration + is applied to all subsequent handshakes, not just to the next one. From 673568a6a16f0e1f4946634fc4edbe90c64ee069 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Tue, 23 Jun 2026 22:37:54 +0200 Subject: [PATCH 140/173] tests: generate_ssl_session_reset_check: add missing semicolon in generated file Signed-off-by: Valerio Setti --- tests/scripts/generate_ssl_session_reset_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/scripts/generate_ssl_session_reset_check.py b/tests/scripts/generate_ssl_session_reset_check.py index fa67134ca4..303f27e251 100755 --- a/tests/scripts/generate_ssl_session_reset_check.py +++ b/tests/scripts/generate_ssl_session_reset_check.py @@ -107,7 +107,7 @@ RULES = { SPECIAL_BEHAVIORS = { 'flags': ['TEST_EQUAL((after->flags & ~(MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION)), ' - 'initial.flags)', + 'initial.flags);', 'TEST_EQUAL((before->flags & MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION), ' + '(after->flags & MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION));'], 'tls_version': ['TEST_ASSERT(after->tls_version == after->conf->max_tls_version);'], From b291d599279c743f1d97018566ae84170d5fa257 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Tue, 23 Jun 2026 22:38:41 +0200 Subject: [PATCH 141/173] tests: ssl_context_reset_verifier: add missing semicolon in generated file Signed-off-by: Valerio Setti --- tests/src/ssl_context_reset_verifier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/ssl_context_reset_verifier.c b/tests/src/ssl_context_reset_verifier.c index 2f106e9067..a0fda308ec 100644 --- a/tests/src/ssl_context_reset_verifier.c +++ b/tests/src/ssl_context_reset_verifier.c @@ -31,7 +31,7 @@ int mbedtls_test_ssl_check_context_after_session_reset(const mbedtls_ssl_context /* *INDENT-OFF* */ TEST_ASSERT(before->conf == after->conf); TEST_ASSERT(after->state == initial.state); - TEST_EQUAL((after->flags & ~(MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION)), initial.flags) + TEST_EQUAL((after->flags & ~(MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION)), initial.flags); TEST_EQUAL((before->flags & MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION), (after->flags & MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION)); #if defined(MBEDTLS_SSL_RENEGOTIATION) TEST_ASSERT(after->renego_status == initial.renego_status); From 57b2f5d4aa9cc96f8f6db254febe6439218b23a2 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Tue, 23 Jun 2026 22:39:41 +0200 Subject: [PATCH 142/173] tests: ssl_helpers: fix documentation of mbedtls_test_ssl_check_context_after_session_reset Signed-off-by: Valerio Setti --- tests/include/test/ssl_helpers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/include/test/ssl_helpers.h b/tests/include/test/ssl_helpers.h index 6a86937df4..21965b0c9a 100644 --- a/tests/include/test/ssl_helpers.h +++ b/tests/include/test/ssl_helpers.h @@ -758,7 +758,7 @@ int mbedtls_test_get_tls13_ticket( * is called on it. This is used for fields that * should be kept untouched during the reset. * \param[in] after The SSL context after mbedtls_ssl_session_reset() - * is called on it. + * has been called on it. */ int mbedtls_test_ssl_check_context_after_session_reset(const mbedtls_ssl_context *before, const mbedtls_ssl_context *after); From fd072d7103c0b45a6f016fd89c2e51fe527f6520 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Tue, 23 Jun 2026 22:49:11 +0200 Subject: [PATCH 143/173] tests: generate_ssl_session_reset_check: order rules as fields in the struct Signed-off-by: Valerio Setti --- .../generate_ssl_session_reset_check.py | 80 ++++++++----------- 1 file changed, 35 insertions(+), 45 deletions(-) diff --git a/tests/scripts/generate_ssl_session_reset_check.py b/tests/scripts/generate_ssl_session_reset_check.py index 303f27e251..96a5d3b078 100755 --- a/tests/scripts/generate_ssl_session_reset_check.py +++ b/tests/scripts/generate_ssl_session_reset_check.py @@ -9,23 +9,45 @@ import scripts_path # pylint: disable=unused-import from mbedtls_framework import ssl_session_reset_check RULES = { - # Fields that are reset + 'conf': ssl_session_reset_check.ResetBehavior.KEEP, 'state': ssl_session_reset_check.ResetBehavior.RESET, + 'flags': ssl_session_reset_check.ResetBehavior.SPECIAL, 'renego_status': ssl_session_reset_check.ResetBehavior.RESET, 'renego_records_seen': ssl_session_reset_check.ResetBehavior.RESET, + 'tls_version': ssl_session_reset_check.ResetBehavior.SPECIAL, 'early_data_state': ssl_session_reset_check.ResetBehavior.RESET, 'badmac_seen': ssl_session_reset_check.ResetBehavior.RESET, + 'f_vrfy': ssl_session_reset_check.ResetBehavior.KEEP, + 'p_vrfy': ssl_session_reset_check.ResetBehavior.KEEP, + 'f_send': ssl_session_reset_check.ResetBehavior.KEEP, + 'f_recv': ssl_session_reset_check.ResetBehavior.KEEP, + 'f_recv_timeout': ssl_session_reset_check.ResetBehavior.KEEP, + 'p_bio': ssl_session_reset_check.ResetBehavior.KEEP, 'session_in': ssl_session_reset_check.ResetBehavior.RESET, 'session_out': ssl_session_reset_check.ResetBehavior.RESET, 'session': ssl_session_reset_check.ResetBehavior.RESET, + 'session_negotiate': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'handshake': ssl_session_reset_check.ResetBehavior.REALLOCATE, 'transform_in': ssl_session_reset_check.ResetBehavior.RESET, 'transform_out': ssl_session_reset_check.ResetBehavior.RESET, 'transform': ssl_session_reset_check.ResetBehavior.RESET, + 'transform_negotiate': ssl_session_reset_check.ResetBehavior.REALLOCATE, 'transform_application': ssl_session_reset_check.ResetBehavior.RESET, + 'p_timer': ssl_session_reset_check.ResetBehavior.KEEP, + 'f_set_timer': ssl_session_reset_check.ResetBehavior.KEEP, + 'f_get_timer': ssl_session_reset_check.ResetBehavior.KEEP, + 'in_buf': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'in_ctr': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'in_hdr': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'in_cid': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'in_len': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'in_iv': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'in_msg': ssl_session_reset_check.ResetBehavior.REALLOCATE, 'in_offt': ssl_session_reset_check.ResetBehavior.RESET, 'in_msgtype': ssl_session_reset_check.ResetBehavior.RESET, 'in_msglen': ssl_session_reset_check.ResetBehavior.RESET, 'in_left': ssl_session_reset_check.ResetBehavior.RESET, + 'in_buf_len': ssl_session_reset_check.ResetBehavior.SPECIAL, 'in_epoch': ssl_session_reset_check.ResetBehavior.RESET, 'next_record_offset': ssl_session_reset_check.ResetBehavior.RESET, 'in_window_top': ssl_session_reset_check.ResetBehavior.RESET, @@ -39,12 +61,23 @@ RULES = { 'send_alert': ssl_session_reset_check.ResetBehavior.RESET, 'alert_type': ssl_session_reset_check.ResetBehavior.RESET, 'alert_reason': ssl_session_reset_check.ResetBehavior.RESET, + 'disable_datagram_packing': ssl_session_reset_check.ResetBehavior.KEEP, 'discard_early_data_record': ssl_session_reset_check.ResetBehavior.RESET, 'total_early_data_size': ssl_session_reset_check.ResetBehavior.RESET, + 'out_buf': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'out_ctr': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'out_hdr': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'out_cid': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'out_len': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'out_iv': ssl_session_reset_check.ResetBehavior.REALLOCATE, + 'out_msg': ssl_session_reset_check.ResetBehavior.REALLOCATE, 'out_msgtype': ssl_session_reset_check.ResetBehavior.RESET, 'out_msglen': ssl_session_reset_check.ResetBehavior.RESET, 'out_left': ssl_session_reset_check.ResetBehavior.RESET, + 'out_buf_len': ssl_session_reset_check.ResetBehavior.SPECIAL, 'cur_out_ctr': ssl_session_reset_check.ResetBehavior.RESET, + 'mtu': ssl_session_reset_check.ResetBehavior.KEEP, + 'hostname': ssl_session_reset_check.ResetBehavior.KEEP, 'alpn_chosen': ssl_session_reset_check.ResetBehavior.RESET, 'dtls_srtp_info': ssl_session_reset_check.ResetBehavior.RESET, 'cli_id': ssl_session_reset_check.ResetBehavior.RESET, @@ -53,56 +86,13 @@ RULES = { 'verify_data_len': ssl_session_reset_check.ResetBehavior.RESET, 'own_verify_data': ssl_session_reset_check.ResetBehavior.RESET, 'peer_verify_data': ssl_session_reset_check.ResetBehavior.RESET, - - # Fields that are preserved during reset - 'conf': ssl_session_reset_check.ResetBehavior.KEEP, - 'f_vrfy': ssl_session_reset_check.ResetBehavior.KEEP, - 'p_vrfy': ssl_session_reset_check.ResetBehavior.KEEP, - 'f_send': ssl_session_reset_check.ResetBehavior.KEEP, - 'f_recv': ssl_session_reset_check.ResetBehavior.KEEP, - 'f_recv_timeout': ssl_session_reset_check.ResetBehavior.KEEP, - 'p_bio': ssl_session_reset_check.ResetBehavior.KEEP, - 'p_timer': ssl_session_reset_check.ResetBehavior.KEEP, - 'f_set_timer': ssl_session_reset_check.ResetBehavior.KEEP, - 'f_get_timer': ssl_session_reset_check.ResetBehavior.KEEP, - 'disable_datagram_packing': ssl_session_reset_check.ResetBehavior.KEEP, - 'mtu': ssl_session_reset_check.ResetBehavior.KEEP, - 'hostname': ssl_session_reset_check.ResetBehavior.KEEP, 'own_cid': ssl_session_reset_check.ResetBehavior.KEEP, 'own_cid_len': ssl_session_reset_check.ResetBehavior.KEEP, 'negotiate_cid': ssl_session_reset_check.ResetBehavior.KEEP, 'f_export_keys': ssl_session_reset_check.ResetBehavior.KEEP, 'p_export_keys': ssl_session_reset_check.ResetBehavior.KEEP, - - # Fields which are intentionally not checked. - 'unused': ssl_session_reset_check.ResetBehavior.IGNORE, - - # Pointers which might be reallocated during reset - 'in_buf': ssl_session_reset_check.ResetBehavior.REALLOCATE, - 'in_ctr': ssl_session_reset_check.ResetBehavior.REALLOCATE, - 'in_hdr': ssl_session_reset_check.ResetBehavior.REALLOCATE, - 'in_cid': ssl_session_reset_check.ResetBehavior.REALLOCATE, - 'in_len': ssl_session_reset_check.ResetBehavior.REALLOCATE, - 'in_iv': ssl_session_reset_check.ResetBehavior.REALLOCATE, - 'in_msg': ssl_session_reset_check.ResetBehavior.REALLOCATE, - 'out_buf': ssl_session_reset_check.ResetBehavior.REALLOCATE, - 'out_ctr': ssl_session_reset_check.ResetBehavior.REALLOCATE, - 'out_hdr': ssl_session_reset_check.ResetBehavior.REALLOCATE, - 'out_cid': ssl_session_reset_check.ResetBehavior.REALLOCATE, - 'out_len': ssl_session_reset_check.ResetBehavior.REALLOCATE, - 'out_iv': ssl_session_reset_check.ResetBehavior.REALLOCATE, - 'out_msg': ssl_session_reset_check.ResetBehavior.REALLOCATE, - 'session_negotiate': ssl_session_reset_check.ResetBehavior.REALLOCATE, - 'handshake': ssl_session_reset_check.ResetBehavior.REALLOCATE, - 'transform_negotiate': ssl_session_reset_check.ResetBehavior.REALLOCATE, - - # Fields with custom check rules. Rules must be defined in the - # SPECIAL_BEHAVIORS dictionary below. - 'flags': ssl_session_reset_check.ResetBehavior.SPECIAL, - 'tls_version': ssl_session_reset_check.ResetBehavior.SPECIAL, 'user_data': ssl_session_reset_check.ResetBehavior.SPECIAL, - 'in_buf_len': ssl_session_reset_check.ResetBehavior.SPECIAL, - 'out_buf_len': ssl_session_reset_check.ResetBehavior.SPECIAL, + 'unused': ssl_session_reset_check.ResetBehavior.IGNORE, } SPECIAL_BEHAVIORS = { From 7a2a3179e2a25f757e0dd2a05076f992c5edb4c9 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Tue, 23 Jun 2026 23:34:01 +0200 Subject: [PATCH 144/173] tests: generate_ssl_session_reset_check: pacify pylint Signed-off-by: Valerio Setti --- tests/scripts/generate_ssl_session_reset_check.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/scripts/generate_ssl_session_reset_check.py b/tests/scripts/generate_ssl_session_reset_check.py index 96a5d3b078..78e0b6921f 100755 --- a/tests/scripts/generate_ssl_session_reset_check.py +++ b/tests/scripts/generate_ssl_session_reset_check.py @@ -96,7 +96,7 @@ RULES = { } SPECIAL_BEHAVIORS = { - 'flags': ['TEST_EQUAL((after->flags & ~(MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION)), ' + 'flags': ['TEST_EQUAL((after->flags & ~(MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION)), ' + 'initial.flags);', 'TEST_EQUAL((before->flags & MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION), ' + '(after->flags & MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION));'], @@ -106,9 +106,9 @@ SPECIAL_BEHAVIORS = { 'out_buf_len': ['TEST_ASSERT(after->out_buf_len == MBEDTLS_SSL_OUT_BUFFER_LEN);'], } -NAMED_STRUCTURES = [ +NAMED_STRUCTURES = frozenset([ 'dtls_srtp_info', -] +]) FIELDS_INFO = ssl_session_reset_check.FieldsInfo(RULES, SPECIAL_BEHAVIORS, From de1f7218d55395ec8c522e03d358b71c71ef2561 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Wed, 24 Jun 2026 09:04:15 +0200 Subject: [PATCH 145/173] tests: generate_ssl_session_reset_check: remove trailing whitespace Signed-off-by: Valerio Setti --- tests/scripts/generate_ssl_session_reset_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/scripts/generate_ssl_session_reset_check.py b/tests/scripts/generate_ssl_session_reset_check.py index 78e0b6921f..8e26d9ee1a 100755 --- a/tests/scripts/generate_ssl_session_reset_check.py +++ b/tests/scripts/generate_ssl_session_reset_check.py @@ -106,7 +106,7 @@ SPECIAL_BEHAVIORS = { 'out_buf_len': ['TEST_ASSERT(after->out_buf_len == MBEDTLS_SSL_OUT_BUFFER_LEN);'], } -NAMED_STRUCTURES = frozenset([ +NAMED_STRUCTURES = frozenset([ 'dtls_srtp_info', ]) From 8ef4559dfa8cb89d24893af160e62d6aee4aa051 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Wed, 24 Jun 2026 14:31:20 +0200 Subject: [PATCH 146/173] framework: update reference Signed-off-by: Valerio Setti --- framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework b/framework index d6dec17adf..dde0c4a0e4 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit d6dec17adfb5bf283c6a7a5bb6c451ecdc0b8201 +Subproject commit dde0c4a0e448a0552f18817dcea633bb851fd288 From 3b84f44c7fb2e987ad3a878e5d8abfaf549408be Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Wed, 24 Jun 2026 15:37:00 +0200 Subject: [PATCH 147/173] tests: ssl_helpers: run ssl_context reset check only when the SSL context is setup Signed-off-by: Valerio Setti --- tests/src/test_helpers/ssl_helpers.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/src/test_helpers/ssl_helpers.c b/tests/src/test_helpers/ssl_helpers.c index 0d2687e795..ebb9103de9 100644 --- a/tests/src/test_helpers/ssl_helpers.c +++ b/tests/src/test_helpers/ssl_helpers.c @@ -1035,14 +1035,17 @@ int mbedtls_test_ssl_endpoint_init( void mbedtls_test_ssl_endpoint_free( mbedtls_test_ssl_endpoint *ep) { - mbedtls_ssl_context ssl_before; + // mbedtls_ssl_session_reset() requires the SSL to be setup. + if (ep->ssl.conf != NULL) { + mbedtls_ssl_context ssl_before; - /* Dump the SSL context before resetting it */ - memcpy(&ssl_before, &(ep->ssl), sizeof(mbedtls_ssl_context)); + /* Dump the SSL context before resetting it */ + memcpy(&ssl_before, &(ep->ssl), sizeof(mbedtls_ssl_context)); - mbedtls_ssl_session_reset(&(ep->ssl)); - /* Check that required fields were properly reset */ - mbedtls_test_ssl_check_context_after_session_reset(&ssl_before, &(ep->ssl)); + mbedtls_ssl_session_reset(&(ep->ssl)); + /* Check that required fields were properly reset */ + mbedtls_test_ssl_check_context_after_session_reset(&ssl_before, &(ep->ssl)); + } mbedtls_ssl_free(&(ep->ssl)); mbedtls_ssl_config_free(&(ep->conf)); From 1d3ac2843c7846b437552212566fee6803c33f81 Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Wed, 24 Jun 2026 14:36:00 +0100 Subject: [PATCH 148/173] Changelog. Added attribution/CVE for 1569 Signed-off-by: Minos Galanakis --- ChangeLog.d/security-issue1569.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ChangeLog.d/security-issue1569.txt b/ChangeLog.d/security-issue1569.txt index c7d3ca0782..c9e285b80e 100644 --- a/ChangeLog.d/security-issue1569.txt +++ b/ChangeLog.d/security-issue1569.txt @@ -1,4 +1,7 @@ Security * Improved documentation of mbedtls_ssl_conf_sig_algs() to emphasize that this function only sets signature algorithms that are enforced during - TLS key exchange and not on certificate verification. + TLS key exchange and not on certificate verification. Reported by + Xiangdong Li, Beijing University of Posts and Telecommunications (BUPT). + CVE-2026-54441 + From 2aaedab1eb3e0ae94f95fc322946ccb629ded7f5 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Wed, 3 Jun 2026 15:25:09 +0200 Subject: [PATCH 149/173] test_suite_ssl: Add early data drop tests Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.data | 6 ++ tests/suites/test_suite_ssl.function | 153 +++++++++++++++++++++++++++ 2 files changed, 159 insertions(+) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index dbe0dfe44c..86cd311e01 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3586,3 +3586,9 @@ send_invalid_sig_alg:MBEDTLS_SSL_SIG_ECDSA:MBEDTLS_SSL_HASH_SHA512:MBEDTLS_ERR_S 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 + +TLS 1.3 drop early data +tls13_drop_early_data:0 + +TLS 1.3 drop early data and insert an EndOfEarlyData +tls13_drop_early_data:1 diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index aba395a8ce..3b80db0a79 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -6778,3 +6778,156 @@ exit: MD_OR_USE_PSA_DONE(); } /* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_SSL_EARLY_DATA:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED:MBEDTLS_TEST_HAS_DEFAULT_EC_GROUP:PSA_WANT_ALG_SHA_256:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:MBEDTLS_SSL_SESSION_TICKETS */ +void tls13_drop_early_data(int insert_end_of_early_data) +{ + int ret = -1; + mbedtls_test_ssl_endpoint client_ep, server_ep; + memset(&client_ep, 0, sizeof(client_ep)); + memset(&server_ep, 0, sizeof(server_ep)); + + mbedtls_test_handshake_test_options client_options, server_options; + mbedtls_test_init_handshake_options(&client_options); + mbedtls_test_init_handshake_options(&server_options); + + mbedtls_ssl_session saved_session; + mbedtls_ssl_session_init(&saved_session); + + const char *early_data = "This is early data."; + size_t early_data_len = strlen(early_data); + unsigned char buf[256]; + + PSA_INIT(); + + /* + * Run first handshake to get a ticket from the server. + */ + + client_options.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED; + server_options.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED; + ret = mbedtls_test_get_tls13_ticket(&client_options, &server_options, + &saved_session); + TEST_EQUAL(ret, 0); + + /* + * Prepare for handshake with the ticket. + */ + ret = mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT, + &client_options); + TEST_EQUAL(ret, 0); + + ret = mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER, + &server_options); + TEST_EQUAL(ret, 0); + + mbedtls_ssl_conf_session_tickets_cb(&server_ep.conf, + mbedtls_test_ticket_write, + mbedtls_test_ticket_parse, + NULL); + + ret = mbedtls_test_mock_socket_connect(&(client_ep.socket), + &(server_ep.socket), 1024); + TEST_EQUAL(ret, 0); + + ret = mbedtls_ssl_set_session(&(client_ep.ssl), &saved_session); + TEST_EQUAL(ret, 0); + + /* + * Initiate handshake with ticket, up to the point where the client has + * written the ClientHello and only the ClientHello in its output socket + * buffer. + */ +#if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE) + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + &(client_ep.ssl), &(server_ep.ssl), + MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO), 0); +#else + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + &(client_ep.ssl), &(server_ep.ssl), + MBEDTLS_SSL_SERVER_HELLO), 0); +#endif + TEST_EQUAL(mbedtls_ssl_flush_output(&client_ep.ssl), 0); + + if (insert_end_of_early_data) { + /* + * Append an EndOfEarlyData message at the end of the record, just + * after the ClientHello message. + */ + unsigned char *client_output_buffer = client_ep.socket.output->buffer; + size_t record_size = MBEDTLS_GET_UINT16_BE(client_output_buffer, 3); + + MBEDTLS_PUT_UINT16_BE(record_size + 4, client_output_buffer, 3); + unsigned char end_of_early_data[] = { 0x05, 0x00, 0x00, 0x00 }; + ret = mbedtls_test_ssl_buffer_put(client_ep.socket.output, + end_of_early_data, + sizeof(end_of_early_data)); + TEST_EQUAL(ret, (int) sizeof(end_of_early_data)); + } + + /* + * The server read the record containing the ClientHello and possibly the + * EndOfEarlyData message and parse the ClientHello. + */ + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + &(server_ep.ssl), &(client_ep.ssl), + MBEDTLS_SSL_SERVER_HELLO), 0); + + /* The client application writes early data */ + ret = mbedtls_ssl_write_early_data(&(client_ep.ssl), + (unsigned char *) early_data, + early_data_len); + TEST_EQUAL(ret, early_data_len); + + /* Drop early data */ + TEST_ASSERT(client_ep.socket.output->content_length <= sizeof(buf)); + mbedtls_test_ssl_buffer_get(client_ep.socket.output, buf, sizeof(buf)); + TEST_EQUAL(server_ep.socket.input->content_length, 0); + + /* + * Resume the handshake, up to the point where the client is about to write + * the EndOfEarlyData message. + */ + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + &(client_ep.ssl), &(server_ep.ssl), + MBEDTLS_SSL_END_OF_EARLY_DATA), 0); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_END_OF_EARLY_DATA); + + if (insert_end_of_early_data) { + /* + * Let the client write the EndOfEarlyData message and then read it + * from the output socket buffer, preventing it to reach the server as + * we have already inserted one. + */ + ret = mbedtls_ssl_handshake_step(&client_ep.ssl); + TEST_EQUAL(ret, 0); + ret = mbedtls_ssl_flush_output(&client_ep.ssl); + TEST_EQUAL(ret, 0); + TEST_ASSERT(client_ep.socket.output->content_length <= sizeof(buf)); + mbedtls_test_ssl_buffer_get(client_ep.socket.output, buf, sizeof(buf)); + } + + ret = mbedtls_test_move_handshake_to_state(&(server_ep.ssl), + &(client_ep.ssl), + MBEDTLS_SSL_HANDSHAKE_OVER); + if (insert_end_of_early_data) { + TEST_EQUAL(ret, 0); + } else { + /* + * If we have just dropped the early data then the EndOfEarlyData + * message is encrypted with the record number 1 while the server + * expects it to be encrypted with record number 0. Thus the + * handshake fails with MBEDTLS_ERR_SSL_INVALID_MAC. + */ + TEST_EQUAL(ret, MBEDTLS_ERR_SSL_INVALID_MAC); + } + +exit: + mbedtls_test_ssl_endpoint_free(&client_ep); + mbedtls_test_ssl_endpoint_free(&server_ep); + mbedtls_test_free_handshake_options(&client_options); + mbedtls_test_free_handshake_options(&server_options); + mbedtls_ssl_session_free(&saved_session); + PSA_DONE(); +} +/* END_CASE */ From f17c5ff90d625f6b793acf97c2d9ee0b811a483c Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Fri, 22 May 2026 18:10:49 +0200 Subject: [PATCH 150/173] tls13: Add record boundary checks RFC 8446 (TLS 1.3 specification), Section 5.1, states: Handshake messages MAY be coalesced into a single TLSPlaintext record or fragmented across several records, provided that: ... -Handshake messages MUST NOT span key changes. Implementations MUST verify that all messages immediately preceding a key change align with a record boundary; if not, then they MUST terminate the connection with an "unexpected_message" alert. Because the ClientHello, EndOfEarlyData, ServerHello, Finished, and KeyUpdate messages can immediately precede a key change, implementations MUST send these messages in alignment with a record boundary. Signed-off-by: Ronald Cron --- library/ssl_misc.h | 1 + library/ssl_tls13_client.c | 8 ++-- library/ssl_tls13_generic.c | 10 +++-- library/ssl_tls13_server.c | 4 +- tests/suites/test_suite_ssl.function | 65 ++++++++++------------------ 5 files changed, 36 insertions(+), 52 deletions(-) diff --git a/library/ssl_misc.h b/library/ssl_misc.h index f0ca823f33..d85dbc6e1d 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -2028,6 +2028,7 @@ static inline int mbedtls_ssl_tls13_key_exchange_mode_with_ephemeral( MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_tls13_fetch_handshake_msg(mbedtls_ssl_context *ssl, unsigned hs_type, + unsigned record_boundary, unsigned char **buf, size_t *buf_len); diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index ecdf507eab..e4138fa2c7 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -2002,7 +2002,7 @@ static int ssl_tls13_process_server_hello(mbedtls_ssl_context *ssl) MBEDTLS_SSL_DEBUG_MSG(2, ("=> %s", __func__)); MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_tls13_fetch_handshake_msg( - ssl, MBEDTLS_SSL_HS_SERVER_HELLO, &buf, &buf_len)); + ssl, MBEDTLS_SSL_HS_SERVER_HELLO, 1, &buf, &buf_len)); ret = ssl_tls13_preprocess_server_hello(ssl, buf, buf + buf_len); if (ret < 0) { @@ -2195,7 +2195,7 @@ static int ssl_tls13_process_encrypted_extensions(mbedtls_ssl_context *ssl) MBEDTLS_SSL_DEBUG_MSG(2, ("=> parse encrypted extensions")); MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_tls13_fetch_handshake_msg( - ssl, MBEDTLS_SSL_HS_ENCRYPTED_EXTENSIONS, + ssl, MBEDTLS_SSL_HS_ENCRYPTED_EXTENSIONS, 0, &buf, &buf_len)); /* Process the message contents */ @@ -2530,7 +2530,7 @@ static int ssl_tls13_process_certificate_request(mbedtls_ssl_context *ssl) size_t buf_len; MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_tls13_fetch_handshake_msg( - ssl, MBEDTLS_SSL_HS_CERTIFICATE_REQUEST, + ssl, MBEDTLS_SSL_HS_CERTIFICATE_REQUEST, 0, &buf, &buf_len)); MBEDTLS_SSL_PROC_CHK(ssl_tls13_parse_certificate_request( @@ -3025,7 +3025,7 @@ static int ssl_tls13_process_new_session_ticket(mbedtls_ssl_context *ssl) MBEDTLS_SSL_DEBUG_MSG(2, ("=> parse new session ticket")); MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_tls13_fetch_handshake_msg( - ssl, MBEDTLS_SSL_HS_NEW_SESSION_TICKET, + ssl, MBEDTLS_SSL_HS_NEW_SESSION_TICKET, 0, &buf, &buf_len)); /* diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index 078daea352..90891567ec 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -47,6 +47,7 @@ const uint8_t mbedtls_ssl_tls13_hello_retry_request_magic[ int mbedtls_ssl_tls13_fetch_handshake_msg(mbedtls_ssl_context *ssl, unsigned hs_type, + unsigned record_boundary, unsigned char **buf, size_t *buf_len) { @@ -58,7 +59,8 @@ int mbedtls_ssl_tls13_fetch_handshake_msg(mbedtls_ssl_context *ssl, } if (ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE || - ssl->in_msg[0] != hs_type) { + ssl->in_msg[0] != hs_type || + (record_boundary && (ssl->in_hslen != ssl->in_msglen))) { MBEDTLS_SSL_DEBUG_MSG(1, ("Receive unexpected handshake message.")); MBEDTLS_SSL_PEND_FATAL_ALERT(MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE); @@ -339,7 +341,7 @@ int mbedtls_ssl_tls13_process_certificate_verify(mbedtls_ssl_context *ssl) MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_tls13_fetch_handshake_msg( - ssl, MBEDTLS_SSL_HS_CERTIFICATE_VERIFY, &buf, &buf_len)); + ssl, MBEDTLS_SSL_HS_CERTIFICATE_VERIFY, 0, &buf, &buf_len)); /* Need to calculate the hash of the transcript first * before reading the message since otherwise it gets @@ -691,7 +693,7 @@ int mbedtls_ssl_tls13_process_certificate(mbedtls_ssl_context *ssl) size_t buf_len; MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_tls13_fetch_handshake_msg( - ssl, MBEDTLS_SSL_HS_CERTIFICATE, + ssl, MBEDTLS_SSL_HS_CERTIFICATE, 0, &buf, &buf_len)); /* Parse the certificate chain sent by the peer. */ @@ -1110,7 +1112,7 @@ int mbedtls_ssl_tls13_process_finished_message(mbedtls_ssl_context *ssl) MBEDTLS_SSL_DEBUG_MSG(2, ("=> parse finished message")); MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_tls13_fetch_handshake_msg( - ssl, MBEDTLS_SSL_HS_FINISHED, &buf, &buf_len)); + ssl, MBEDTLS_SSL_HS_FINISHED, 1, &buf, &buf_len)); /* Preprocessing step: Compute handshake digest */ MBEDTLS_SSL_PROC_CHK(ssl_tls13_preprocess_finished_message(ssl)); diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index 38f2fe9370..0db142c50a 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -1936,7 +1936,7 @@ static int ssl_tls13_process_client_hello(mbedtls_ssl_context *ssl) MBEDTLS_SSL_DEBUG_MSG(2, ("=> parse client hello")); MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_tls13_fetch_handshake_msg( - ssl, MBEDTLS_SSL_HS_CLIENT_HELLO, + ssl, MBEDTLS_SSL_HS_CLIENT_HELLO, 1, &buf, &buflen)); MBEDTLS_SSL_PROC_CHK_NEG(ssl_tls13_parse_client_hello(ssl, buf, @@ -3027,7 +3027,7 @@ static int ssl_tls13_process_end_of_early_data(mbedtls_ssl_context *ssl) size_t buf_len; MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_tls13_fetch_handshake_msg( - ssl, MBEDTLS_SSL_HS_END_OF_EARLY_DATA, + ssl, MBEDTLS_SSL_HS_END_OF_EARLY_DATA, 1, &buf, &buf_len)); MBEDTLS_SSL_PROC_CHK(ssl_tls13_parse_end_of_early_data( diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 3b80db0a79..d058401148 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4124,7 +4124,7 @@ void tls13_server_certificate_msg_invalid_vector_len() ret = mbedtls_ssl_tls13_fetch_handshake_msg(&(client_ep.ssl), MBEDTLS_SSL_HS_CERTIFICATE, - &buf, &buf_len); + 0, &buf, &buf_len); TEST_EQUAL(ret, 0); end = buf + buf_len; @@ -6865,14 +6865,21 @@ void tls13_drop_early_data(int insert_end_of_early_data) TEST_EQUAL(ret, (int) sizeof(end_of_early_data)); } - /* - * The server read the record containing the ClientHello and possibly the - * EndOfEarlyData message and parse the ClientHello. - */ - TEST_EQUAL(mbedtls_test_move_handshake_to_state( - &(server_ep.ssl), &(client_ep.ssl), - MBEDTLS_SSL_SERVER_HELLO), 0); + /* The server read the record containing the ClientHello. */ + ret = mbedtls_test_move_handshake_to_state(&(server_ep.ssl), + &(client_ep.ssl), + MBEDTLS_SSL_SERVER_HELLO); + if (insert_end_of_early_data) { + /* + * If an EndOfEarlyData message was appended to the record containing + * the ClientHello then the end of the ClientHello does not align with + * the record boundary and the handshake fails. + */ + TEST_EQUAL(ret, MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE); + goto exit; + } + TEST_EQUAL(ret, 0); /* The client application writes early data */ ret = mbedtls_ssl_write_early_data(&(client_ep.ssl), (unsigned char *) early_data, @@ -6884,43 +6891,17 @@ void tls13_drop_early_data(int insert_end_of_early_data) mbedtls_test_ssl_buffer_get(client_ep.socket.output, buf, sizeof(buf)); TEST_EQUAL(server_ep.socket.input->content_length, 0); - /* - * Resume the handshake, up to the point where the client is about to write - * the EndOfEarlyData message. - */ - TEST_EQUAL(mbedtls_test_move_handshake_to_state( - &(client_ep.ssl), &(server_ep.ssl), - MBEDTLS_SSL_END_OF_EARLY_DATA), 0); - TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_END_OF_EARLY_DATA); - - if (insert_end_of_early_data) { - /* - * Let the client write the EndOfEarlyData message and then read it - * from the output socket buffer, preventing it to reach the server as - * we have already inserted one. - */ - ret = mbedtls_ssl_handshake_step(&client_ep.ssl); - TEST_EQUAL(ret, 0); - ret = mbedtls_ssl_flush_output(&client_ep.ssl); - TEST_EQUAL(ret, 0); - TEST_ASSERT(client_ep.socket.output->content_length <= sizeof(buf)); - mbedtls_test_ssl_buffer_get(client_ep.socket.output, buf, sizeof(buf)); - } - + /* Resume the handshake */ ret = mbedtls_test_move_handshake_to_state(&(server_ep.ssl), &(client_ep.ssl), MBEDTLS_SSL_HANDSHAKE_OVER); - if (insert_end_of_early_data) { - TEST_EQUAL(ret, 0); - } else { - /* - * If we have just dropped the early data then the EndOfEarlyData - * message is encrypted with the record number 1 while the server - * expects it to be encrypted with record number 0. Thus the - * handshake fails with MBEDTLS_ERR_SSL_INVALID_MAC. - */ - TEST_EQUAL(ret, MBEDTLS_ERR_SSL_INVALID_MAC); - } + /* + * The early data were dropped. The EndOfEarlyData message is encrypted + * with the record number 1, but the server expects it to be encrypted + * with record number 0. Thus the handshake fails with + * MBEDTLS_ERR_SSL_INVALID_MAC. + */ + TEST_EQUAL(ret, MBEDTLS_ERR_SSL_INVALID_MAC); exit: mbedtls_test_ssl_endpoint_free(&client_ep); From dd97c26e9a661a44ca8b2930ee9659158b87e448 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Mon, 8 Jun 2026 13:06:08 +0200 Subject: [PATCH 151/173] test_suite_ssl: Test ClientHello on record boundary check Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.data | 3 + tests/suites/test_suite_ssl.function | 95 ++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 86cd311e01..43554ce112 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3592,3 +3592,6 @@ tls13_drop_early_data:0 TLS 1.3 drop early data and insert an EndOfEarlyData tls13_drop_early_data:1 + +TLS 1.3 ClientHello record boundary alignment enforcement +tls13_record_boundary_alignment:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_HS_CLIENT_HELLO diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index d058401148..772e64f02b 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -6912,3 +6912,98 @@ exit: PSA_DONE(); } /* END_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_DEBUG_C:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_TEST_HAS_DEFAULT_EC_GROUP:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:PSA_WANT_ALG_SHA_256:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_SIGN */ +void tls13_record_boundary_alignment(int endpoint, int handshake_message) +{ + int ret = -1; + int target_state, peer_target_state, encrypted; + mbedtls_test_ssl_endpoint client_ep, server_ep; + + mbedtls_test_handshake_test_options client_options, server_options; + mbedtls_test_init_handshake_options(&client_options); + mbedtls_test_init_handshake_options(&server_options); + + mbedtls_test_mock_socket *socket = NULL; + mbedtls_ssl_context *ssl_ctx = NULL; + mbedtls_ssl_context *peer_ssl_ctx = NULL; + unsigned char dummy_data[] = { 0x00 }; + + PSA_INIT(); + + switch (handshake_message) { + case MBEDTLS_SSL_HS_CLIENT_HELLO: + TEST_EQUAL(endpoint, MBEDTLS_SSL_IS_SERVER); + target_state = MBEDTLS_SSL_CLIENT_HELLO; + peer_target_state = MBEDTLS_SSL_SERVER_HELLO; + encrypted = 0; + break; + + default: + TEST_ASSERT(0); + } + + if (endpoint == MBEDTLS_SSL_IS_CLIENT) { + ssl_ctx = &client_ep.ssl; + peer_ssl_ctx = &server_ep.ssl; + socket = &client_ep.socket; + } else { + ssl_ctx = &server_ep.ssl; + peer_ssl_ctx = &client_ep.ssl; + socket = &server_ep.socket; + } + + TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT, + &client_options), 0); + TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER, + &server_options), 0); + TEST_EQUAL(mbedtls_test_mock_socket_connect(&(client_ep.socket), + &(server_ep.socket), 1024), 0); + + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + ssl_ctx, peer_ssl_ctx, target_state), 0); + TEST_EQUAL(mbedtls_ssl_flush_output(ssl_ctx), 0); + /* + * Advance the peer further through the handshake so that it emits the + * messages needed by the endpoint under test to proceed through its next + * step. + */ + if (peer_target_state != -1) { + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + peer_ssl_ctx, ssl_ctx, peer_target_state), 0); + TEST_EQUAL(mbedtls_ssl_flush_output(peer_ssl_ctx), 0); + } + TEST_EQUAL(ssl_ctx->state, target_state); + + if (encrypted) { + TEST_ASSERT(0); + } else { + /* + * In case of the unencrypted ClientHello or ServerHello, add an + * additional byte to the record that contains the handshake message. + * The byte is added in the socket buffer, before to be fetched by + * `mbedtls_ssl_read_record()`, simulating a man-in-the-middle tampering + * with the record. + */ + unsigned char *input_buffer = socket->input->buffer; + size_t record_size = MBEDTLS_GET_UINT16_BE(input_buffer, 3); + ret = mbedtls_test_ssl_buffer_put(socket->input, dummy_data, + sizeof(dummy_data)); + TEST_EQUAL(ret, (int) sizeof(dummy_data)); + MBEDTLS_PUT_UINT16_BE(record_size + sizeof(dummy_data), input_buffer, 3); + } + + ret = mbedtls_ssl_handshake_step(ssl_ctx); + TEST_EQUAL(ret, MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE); + TEST_EQUAL(ssl_ctx->in_msglen, + ssl_ctx->in_hslen + sizeof(dummy_data)); + TEST_EQUAL(ssl_ctx->in_msgtype, MBEDTLS_SSL_MSG_HANDSHAKE); + TEST_EQUAL(ssl_ctx->in_msg[0], handshake_message); + +exit: + mbedtls_test_ssl_endpoint_free(&client_ep); + mbedtls_test_ssl_endpoint_free(&server_ep); + mbedtls_test_free_handshake_options(&client_options); + mbedtls_test_free_handshake_options(&server_options); + PSA_DONE(); +} +/* END_CASE */ From b9793ca124ff86641d807925721cb9090ea69540 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Mon, 8 Jun 2026 13:18:20 +0200 Subject: [PATCH 152/173] test_suite_ssl: Test ServerHello on record boundary enforcement Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.data | 3 +++ tests/suites/test_suite_ssl.function | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 43554ce112..575b26a9e3 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3595,3 +3595,6 @@ tls13_drop_early_data:1 TLS 1.3 ClientHello record boundary alignment enforcement tls13_record_boundary_alignment:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_HS_CLIENT_HELLO + +TLS 1.3 ServerHello record boundary alignement enforcement +tls13_record_boundary_alignment:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_HS_SERVER_HELLO diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 772e64f02b..767c6a607c 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -6938,6 +6938,13 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) encrypted = 0; break; + case MBEDTLS_SSL_HS_SERVER_HELLO: + TEST_EQUAL(endpoint, MBEDTLS_SSL_IS_CLIENT); + target_state = MBEDTLS_SSL_SERVER_HELLO; + peer_target_state = MBEDTLS_SSL_ENCRYPTED_EXTENSIONS; + encrypted = 0; + break; + default: TEST_ASSERT(0); } From d00518a2ec5f667e54afc3ac34ed8856eb241006 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Mon, 8 Jun 2026 14:10:19 +0200 Subject: [PATCH 153/173] test_suite_ssl: Test server Finished on record boundary enforcement Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.data | 3 ++ tests/suites/test_suite_ssl.function | 78 +++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 575b26a9e3..7b9a81ce17 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3598,3 +3598,6 @@ tls13_record_boundary_alignment:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_HS_CLIENT_HELL TLS 1.3 ServerHello record boundary alignement enforcement tls13_record_boundary_alignment:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_HS_SERVER_HELLO + +TLS 1.3 server Finished record boundary alignement enforcement +tls13_record_boundary_alignment:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_HS_FINISHED diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 767c6a607c..617cbd58ae 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -552,6 +552,51 @@ exit: #endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED etc */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_DEBUG_C) && \ + defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_SRV_C) && \ + defined(MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE) && \ + defined(MBEDTLS_TEST_HAS_DEFAULT_EC_GROUP) && \ + defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED) && \ + defined(PSA_WANT_ALG_SHA_256) && \ + defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) && \ + defined(PSA_WANT_ALG_RSA_PKCS1V15_SIGN) +typedef struct { + /* Context for `tls_tweak_in_msglen()`. The debug callback + * watches for "<= read record" in the SSL debug trace. When the pattern is + * detected, it increases by `nb_bytes` the 'in_msglen' field of the + * associated SSL context. + */ + mbedtls_ssl_context *ssl; + int armed; + int nb_bytes; + int triggered; +} tls_tweak_in_msglen_context; + +static void tls_tweak_in_msglen(void *ctx, int level, + const char *file, int line, + const char *str) +{ + tls_tweak_in_msglen_context *tweak_in_msglen_ctx = ctx; + + (void) level; + (void) file; + (void) line; + + if (!tweak_in_msglen_ctx->armed) { + return; + } + if (strstr(str, "<= read record") == NULL) { + return; + } + + tweak_in_msglen_ctx->ssl->in_msglen += tweak_in_msglen_ctx->nb_bytes; + tweak_in_msglen_ctx->armed = 0; + tweak_in_msglen_ctx->triggered++; +} +#endif + + + /* END_HEADER */ /* BEGIN_DEPENDENCIES @@ -6923,6 +6968,9 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) mbedtls_test_init_handshake_options(&client_options); mbedtls_test_init_handshake_options(&server_options); + tls_tweak_in_msglen_context tweak_in_msglen_ctx; + memset(&tweak_in_msglen_ctx, 0, sizeof(tweak_in_msglen_ctx)); + mbedtls_test_mock_socket *socket = NULL; mbedtls_ssl_context *ssl_ctx = NULL; mbedtls_ssl_context *peer_ssl_ctx = NULL; @@ -6945,6 +6993,14 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) encrypted = 0; break; + case MBEDTLS_SSL_HS_FINISHED: + if (endpoint == MBEDTLS_SSL_IS_CLIENT) { + target_state = MBEDTLS_SSL_SERVER_FINISHED; + peer_target_state = MBEDTLS_SSL_CLIENT_CERTIFICATE; + } + encrypted = 1; + break; + default: TEST_ASSERT(0); } @@ -6953,12 +7009,19 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) ssl_ctx = &client_ep.ssl; peer_ssl_ctx = &server_ep.ssl; socket = &client_ep.socket; + client_options.cli_log_obj = &tweak_in_msglen_ctx; + client_options.cli_log_fun = tls_tweak_in_msglen; } else { ssl_ctx = &server_ep.ssl; peer_ssl_ctx = &client_ep.ssl; socket = &server_ep.socket; + server_options.srv_log_obj = &tweak_in_msglen_ctx; + server_options.srv_log_fun = tls_tweak_in_msglen; } + mbedtls_debug_set_threshold(2); + tweak_in_msglen_ctx.ssl = ssl_ctx; + TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT, &client_options), 0); TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER, @@ -6982,7 +7045,15 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) TEST_EQUAL(ssl_ctx->state, target_state); if (encrypted) { - TEST_ASSERT(0); + /* + * If the message we want to test the record boundary enforcement is + * encrypted, we cannot manipulate easily the record that contains it. + * In that case, we tamper with the record size after the record has been + * fetched from the socket buffer and decrypted by + * `mbedtls_ssl_read_record()`. + */ + tweak_in_msglen_ctx.armed = 1; + tweak_in_msglen_ctx.nb_bytes = sizeof(dummy_data); } else { /* * In case of the unencrypted ClientHello or ServerHello, add an @@ -7006,11 +7077,16 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) TEST_EQUAL(ssl_ctx->in_msgtype, MBEDTLS_SSL_MSG_HANDSHAKE); TEST_EQUAL(ssl_ctx->in_msg[0], handshake_message); + if (encrypted) { + TEST_EQUAL(tweak_in_msglen_ctx.triggered, 1); + } + exit: mbedtls_test_ssl_endpoint_free(&client_ep); mbedtls_test_ssl_endpoint_free(&server_ep); mbedtls_test_free_handshake_options(&client_options); mbedtls_test_free_handshake_options(&server_options); + mbedtls_debug_set_threshold(0); PSA_DONE(); } /* END_CASE */ From 996adce4b6dbe7240314c036d7088d829266f734 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Mon, 8 Jun 2026 16:21:57 +0200 Subject: [PATCH 154/173] test_suite_ssl: Test client Finished on record boundary enforcement Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.data | 3 +++ tests/suites/test_suite_ssl.function | 3 +++ 2 files changed, 6 insertions(+) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 7b9a81ce17..eecb4abfbd 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3601,3 +3601,6 @@ tls13_record_boundary_alignment:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_HS_SERVER_HELL TLS 1.3 server Finished record boundary alignement enforcement tls13_record_boundary_alignment:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_HS_FINISHED + +TLS 1.3 client Finished record boundary alignement enforcement +tls13_record_boundary_alignment:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_HS_FINISHED diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 617cbd58ae..e4857e0b21 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -6997,6 +6997,9 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) if (endpoint == MBEDTLS_SSL_IS_CLIENT) { target_state = MBEDTLS_SSL_SERVER_FINISHED; peer_target_state = MBEDTLS_SSL_CLIENT_CERTIFICATE; + } else { + target_state = MBEDTLS_SSL_CLIENT_FINISHED; + peer_target_state = MBEDTLS_SSL_FLUSH_BUFFERS; } encrypted = 1; break; From 0501eeb804e4ca06306c14f16caf47fdede3dcc9 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Tue, 9 Jun 2026 13:20:49 +0200 Subject: [PATCH 155/173] test_suite_ssl: Test EndOfEarlyData on record boundary enforcement Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.data | 4 ++++ tests/suites/test_suite_ssl.function | 32 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index eecb4abfbd..c856da44ff 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3604,3 +3604,7 @@ tls13_record_boundary_alignment:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_HS_FINISHED TLS 1.3 client Finished record boundary alignement enforcement tls13_record_boundary_alignment:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_HS_FINISHED + +TLS 1.3 EndOfEarlyData record boundary alignement enforcement +depends_on:MBEDTLS_SSL_EARLY_DATA:MBEDTLS_SSL_SESSION_TICKETS +tls13_record_boundary_alignment:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_HS_END_OF_EARLY_DATA diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index e4857e0b21..c7b15824b4 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -6968,6 +6968,9 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) mbedtls_test_init_handshake_options(&client_options); mbedtls_test_init_handshake_options(&server_options); + mbedtls_ssl_session saved_session; + mbedtls_ssl_session_init(&saved_session); + tls_tweak_in_msglen_context tweak_in_msglen_ctx; memset(&tweak_in_msglen_ctx, 0, sizeof(tweak_in_msglen_ctx)); @@ -7004,6 +7007,21 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) encrypted = 1; break; + +#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_SESSION_TICKETS) + case MBEDTLS_SSL_HS_END_OF_EARLY_DATA: + TEST_EQUAL(endpoint, MBEDTLS_SSL_IS_SERVER); + target_state = MBEDTLS_SSL_END_OF_EARLY_DATA; + peer_target_state = MBEDTLS_SSL_CLIENT_CERTIFICATE; + encrypted = 1; + client_options.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED; + server_options.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED; + ret = mbedtls_test_get_tls13_ticket(&client_options, &server_options, + &saved_session); + TEST_EQUAL(ret, 0); + break; +#endif + default: TEST_ASSERT(0); } @@ -7029,6 +7047,19 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) &client_options), 0); TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER, &server_options), 0); + +#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_SESSION_TICKETS) + if (handshake_message == MBEDTLS_SSL_HS_END_OF_EARLY_DATA) { + mbedtls_ssl_conf_session_tickets_cb(&server_ep.conf, + mbedtls_test_ticket_write, + mbedtls_test_ticket_parse, + NULL); + + ret = mbedtls_ssl_set_session(&(client_ep.ssl), &saved_session); + TEST_EQUAL(ret, 0); + } +#endif + TEST_EQUAL(mbedtls_test_mock_socket_connect(&(client_ep.socket), &(server_ep.socket), 1024), 0); @@ -7090,6 +7121,7 @@ exit: mbedtls_test_free_handshake_options(&client_options); mbedtls_test_free_handshake_options(&server_options); mbedtls_debug_set_threshold(0); + mbedtls_ssl_session_free(&saved_session); PSA_DONE(); } /* END_CASE */ From c4db00209af13b2f52c5a49bf84522341d925b06 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Wed, 10 Jun 2026 10:47:57 +0200 Subject: [PATCH 156/173] Add change log Signed-off-by: Ronald Cron --- ChangeLog.d/drop-early-data.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 ChangeLog.d/drop-early-data.txt diff --git a/ChangeLog.d/drop-early-data.txt b/ChangeLog.d/drop-early-data.txt new file mode 100644 index 0000000000..dc597a23f0 --- /dev/null +++ b/ChangeLog.d/drop-early-data.txt @@ -0,0 +1,7 @@ +Security + * Fixed a TLS 1.3 record-boundary validation issue that could allow + unauthenticated plaintext data to be processed across a key change. In + servers with MBEDTLS_SSL_EARLY_DATA enabled, this could be exploited by a + man-in-the-middle attacker to cause loss of 0-RTT early data. + Reported by Ben Smyth. + CVE-2026-TODO. From 62a9fa9f48c600f16e3d666f902fd36c629f1aba Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Thu, 11 Jun 2026 19:23:15 +0200 Subject: [PATCH 157/173] Fix typos Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.data | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index c856da44ff..a08bb2b961 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3596,15 +3596,15 @@ tls13_drop_early_data:1 TLS 1.3 ClientHello record boundary alignment enforcement tls13_record_boundary_alignment:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_HS_CLIENT_HELLO -TLS 1.3 ServerHello record boundary alignement enforcement +TLS 1.3 ServerHello record boundary alignment enforcement tls13_record_boundary_alignment:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_HS_SERVER_HELLO -TLS 1.3 server Finished record boundary alignement enforcement +TLS 1.3 server Finished record boundary alignment enforcement tls13_record_boundary_alignment:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_HS_FINISHED -TLS 1.3 client Finished record boundary alignement enforcement +TLS 1.3 client Finished record boundary alignment enforcement tls13_record_boundary_alignment:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_HS_FINISHED -TLS 1.3 EndOfEarlyData record boundary alignement enforcement +TLS 1.3 EndOfEarlyData record boundary alignment enforcement depends_on:MBEDTLS_SSL_EARLY_DATA:MBEDTLS_SSL_SESSION_TICKETS tls13_record_boundary_alignment:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_HS_END_OF_EARLY_DATA From d13352bc409ce47eb48053a3799e16392ed798a3 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Thu, 11 Jun 2026 19:38:42 +0200 Subject: [PATCH 158/173] test_suite_ssl: Add initialization to all zeroes of test endpoint structs Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.function | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index c7b15824b4..f6eeeabe1f 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -6963,6 +6963,8 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) int ret = -1; int target_state, peer_target_state, encrypted; mbedtls_test_ssl_endpoint client_ep, server_ep; + memset(&client_ep, 0, sizeof(client_ep)); + memset(&server_ep, 0, sizeof(server_ep)); mbedtls_test_handshake_test_options client_options, server_options; mbedtls_test_init_handshake_options(&client_options); From 7dc69f331fb19246b1b463feea97d79f709b6342 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Thu, 11 Jun 2026 19:40:36 +0200 Subject: [PATCH 159/173] tls13: Improve argument name Signed-off-by: Ronald Cron --- library/ssl_misc.h | 2 +- library/ssl_tls13_generic.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/ssl_misc.h b/library/ssl_misc.h index d85dbc6e1d..8d9323c6de 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -2028,7 +2028,7 @@ static inline int mbedtls_ssl_tls13_key_exchange_mode_with_ephemeral( MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_tls13_fetch_handshake_msg(mbedtls_ssl_context *ssl, unsigned hs_type, - unsigned record_boundary, + unsigned require_record_boundary, unsigned char **buf, size_t *buf_len); diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index 90891567ec..1465de1ec0 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -47,7 +47,7 @@ const uint8_t mbedtls_ssl_tls13_hello_retry_request_magic[ int mbedtls_ssl_tls13_fetch_handshake_msg(mbedtls_ssl_context *ssl, unsigned hs_type, - unsigned record_boundary, + unsigned require_record_boundary, unsigned char **buf, size_t *buf_len) { @@ -60,7 +60,7 @@ int mbedtls_ssl_tls13_fetch_handshake_msg(mbedtls_ssl_context *ssl, if (ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE || ssl->in_msg[0] != hs_type || - (record_boundary && (ssl->in_hslen != ssl->in_msglen))) { + (require_record_boundary && (ssl->in_hslen != ssl->in_msglen))) { MBEDTLS_SSL_DEBUG_MSG(1, ("Receive unexpected handshake message.")); MBEDTLS_SSL_PEND_FATAL_ALERT(MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE); From 1235722aa12df370f057540270d99f112b038e8f Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Mon, 15 Jun 2026 14:09:17 +0200 Subject: [PATCH 160/173] tls13: Rework mbedtls_ssl_tls13_fetch_handshake_msg() Signed-off-by: Ronald Cron --- library/ssl_tls13_generic.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index 1465de1ec0..92dfcc3dfc 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -53,19 +53,23 @@ int mbedtls_ssl_tls13_fetch_handshake_msg(mbedtls_ssl_context *ssl, { int ret; - if ((ret = mbedtls_ssl_read_record(ssl, 0)) != 0) { + ret = mbedtls_ssl_read_record(ssl, 0); + if (ret != 0) { MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_read_record", ret); - goto cleanup; + goto error; } + ret = MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; if (ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE || - ssl->in_msg[0] != hs_type || - (require_record_boundary && (ssl->in_hslen != ssl->in_msglen))) { + ssl->in_msg[0] != hs_type) { MBEDTLS_SSL_DEBUG_MSG(1, ("Receive unexpected handshake message.")); - MBEDTLS_SSL_PEND_FATAL_ALERT(MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, - MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE); - ret = MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; - goto cleanup; + goto error; + } + + if (require_record_boundary && (ssl->in_hslen != ssl->in_msglen)) { + MBEDTLS_SSL_DEBUG_MSG(1, ("Handshake message %s end not aligned with a record boundary", + mbedtls_ssl_get_hs_msg_name(hs_type))); + goto error; } /* @@ -75,11 +79,15 @@ int mbedtls_ssl_tls13_fetch_handshake_msg(mbedtls_ssl_context *ssl, * uint24 length; * ... */ - *buf = ssl->in_msg + 4; + *buf = ssl->in_msg + 4; *buf_len = ssl->in_hslen - 4; + return 0; -cleanup: - +error: + if (ret == MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE) { + MBEDTLS_SSL_PEND_FATAL_ALERT(MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE); + } return ret; } From 4165fe1dc27408463818a0f558c9a1c8665d23e4 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Mon, 15 Jun 2026 14:18:34 +0200 Subject: [PATCH 161/173] Various improvements of tls13_(drop_early_data|record_boundary_alignment)() Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.function | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index f6eeeabe1f..1f6d542eb4 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -6957,6 +6957,7 @@ exit: PSA_DONE(); } /* END_CASE */ + /* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_DEBUG_C:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_TEST_HAS_DEFAULT_EC_GROUP:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:PSA_WANT_ALG_SHA_256:MBEDTLS_X509_RSASSA_PSS_SUPPORT:PSA_WANT_ALG_RSA_PKCS1V15_SIGN */ void tls13_record_boundary_alignment(int endpoint, int handshake_message) { @@ -7025,7 +7026,7 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) #endif default: - TEST_ASSERT(0); + TEST_FAIL("Handshake message type not supported"); } if (endpoint == MBEDTLS_SSL_IS_CLIENT) { @@ -7073,11 +7074,10 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) * messages needed by the endpoint under test to proceed through its next * step. */ - if (peer_target_state != -1) { - TEST_EQUAL(mbedtls_test_move_handshake_to_state( - peer_ssl_ctx, ssl_ctx, peer_target_state), 0); - TEST_EQUAL(mbedtls_ssl_flush_output(peer_ssl_ctx), 0); - } + TEST_ASSERT(peer_target_state != -1); + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + peer_ssl_ctx, ssl_ctx, peer_target_state), 0); + TEST_EQUAL(mbedtls_ssl_flush_output(peer_ssl_ctx), 0); TEST_EQUAL(ssl_ctx->state, target_state); if (encrypted) { From 1208d1cc250b9ff5123ea7084976993d02ce38e6 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Mon, 15 Jun 2026 15:16:36 +0200 Subject: [PATCH 162/173] tls13_record_boundary_alignement: Append empty hs msg Append an empty handshake message to expand the record instead of just a zero byte. Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.function | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 1f6d542eb4..f48543d4c9 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -6980,7 +6980,7 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) mbedtls_test_mock_socket *socket = NULL; mbedtls_ssl_context *ssl_ctx = NULL; mbedtls_ssl_context *peer_ssl_ctx = NULL; - unsigned char dummy_data[] = { 0x00 }; + unsigned char additional_empty_hs_msg[4] = { 0, 0, 0, 0 }; PSA_INIT(); @@ -6989,6 +6989,7 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) TEST_EQUAL(endpoint, MBEDTLS_SSL_IS_SERVER); target_state = MBEDTLS_SSL_CLIENT_HELLO; peer_target_state = MBEDTLS_SSL_SERVER_HELLO; + additional_empty_hs_msg[0] = MBEDTLS_SSL_HS_CERTIFICATE; encrypted = 0; break; @@ -6996,6 +6997,7 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) TEST_EQUAL(endpoint, MBEDTLS_SSL_IS_CLIENT); target_state = MBEDTLS_SSL_SERVER_HELLO; peer_target_state = MBEDTLS_SSL_ENCRYPTED_EXTENSIONS; + additional_empty_hs_msg[0] = MBEDTLS_SSL_HS_ENCRYPTED_EXTENSIONS; encrypted = 0; break; @@ -7007,6 +7009,10 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) target_state = MBEDTLS_SSL_CLIENT_FINISHED; peer_target_state = MBEDTLS_SSL_FLUSH_BUFFERS; } + /* Finished messages are not followed by any handshake message, + * insert an empty Finished message at the end of the record. + */ + additional_empty_hs_msg[0] = MBEDTLS_SSL_HS_FINISHED; encrypted = 1; break; @@ -7016,6 +7022,7 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) TEST_EQUAL(endpoint, MBEDTLS_SSL_IS_SERVER); target_state = MBEDTLS_SSL_END_OF_EARLY_DATA; peer_target_state = MBEDTLS_SSL_CLIENT_CERTIFICATE; + additional_empty_hs_msg[0] = MBEDTLS_SSL_HS_FINISHED; encrypted = 1; client_options.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED; server_options.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED; @@ -7089,7 +7096,7 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) * `mbedtls_ssl_read_record()`. */ tweak_in_msglen_ctx.armed = 1; - tweak_in_msglen_ctx.nb_bytes = sizeof(dummy_data); + tweak_in_msglen_ctx.nb_bytes = sizeof(additional_empty_hs_msg); } else { /* * In case of the unencrypted ClientHello or ServerHello, add an @@ -7100,16 +7107,17 @@ void tls13_record_boundary_alignment(int endpoint, int handshake_message) */ unsigned char *input_buffer = socket->input->buffer; size_t record_size = MBEDTLS_GET_UINT16_BE(input_buffer, 3); - ret = mbedtls_test_ssl_buffer_put(socket->input, dummy_data, - sizeof(dummy_data)); - TEST_EQUAL(ret, (int) sizeof(dummy_data)); - MBEDTLS_PUT_UINT16_BE(record_size + sizeof(dummy_data), input_buffer, 3); + ret = mbedtls_test_ssl_buffer_put(socket->input, additional_empty_hs_msg, + sizeof(additional_empty_hs_msg)); + TEST_EQUAL(ret, (int) sizeof(additional_empty_hs_msg)); + MBEDTLS_PUT_UINT16_BE(record_size + sizeof(additional_empty_hs_msg), + input_buffer, 3); } ret = mbedtls_ssl_handshake_step(ssl_ctx); TEST_EQUAL(ret, MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE); TEST_EQUAL(ssl_ctx->in_msglen, - ssl_ctx->in_hslen + sizeof(dummy_data)); + ssl_ctx->in_hslen + sizeof(additional_empty_hs_msg)); TEST_EQUAL(ssl_ctx->in_msgtype, MBEDTLS_SSL_MSG_HANDSHAKE); TEST_EQUAL(ssl_ctx->in_msg[0], handshake_message); From 0fe502312d2fb2664985886db19693557de7e669 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Tue, 16 Jun 2026 18:41:56 +0200 Subject: [PATCH 163/173] tls13_fetch_handshake_msg(): Remove require_record_boundary parameter Deduce it from the handshake message type Signed-off-by: Ronald Cron --- library/ssl_misc.h | 1 - library/ssl_tls13_client.c | 8 ++++---- library/ssl_tls13_generic.c | 29 +++++++++++++++++++++++----- library/ssl_tls13_server.c | 4 ++-- tests/suites/test_suite_ssl.function | 2 +- 5 files changed, 31 insertions(+), 13 deletions(-) diff --git a/library/ssl_misc.h b/library/ssl_misc.h index 8d9323c6de..f0ca823f33 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -2028,7 +2028,6 @@ static inline int mbedtls_ssl_tls13_key_exchange_mode_with_ephemeral( MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_tls13_fetch_handshake_msg(mbedtls_ssl_context *ssl, unsigned hs_type, - unsigned require_record_boundary, unsigned char **buf, size_t *buf_len); diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index e4138fa2c7..ecdf507eab 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -2002,7 +2002,7 @@ static int ssl_tls13_process_server_hello(mbedtls_ssl_context *ssl) MBEDTLS_SSL_DEBUG_MSG(2, ("=> %s", __func__)); MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_tls13_fetch_handshake_msg( - ssl, MBEDTLS_SSL_HS_SERVER_HELLO, 1, &buf, &buf_len)); + ssl, MBEDTLS_SSL_HS_SERVER_HELLO, &buf, &buf_len)); ret = ssl_tls13_preprocess_server_hello(ssl, buf, buf + buf_len); if (ret < 0) { @@ -2195,7 +2195,7 @@ static int ssl_tls13_process_encrypted_extensions(mbedtls_ssl_context *ssl) MBEDTLS_SSL_DEBUG_MSG(2, ("=> parse encrypted extensions")); MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_tls13_fetch_handshake_msg( - ssl, MBEDTLS_SSL_HS_ENCRYPTED_EXTENSIONS, 0, + ssl, MBEDTLS_SSL_HS_ENCRYPTED_EXTENSIONS, &buf, &buf_len)); /* Process the message contents */ @@ -2530,7 +2530,7 @@ static int ssl_tls13_process_certificate_request(mbedtls_ssl_context *ssl) size_t buf_len; MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_tls13_fetch_handshake_msg( - ssl, MBEDTLS_SSL_HS_CERTIFICATE_REQUEST, 0, + ssl, MBEDTLS_SSL_HS_CERTIFICATE_REQUEST, &buf, &buf_len)); MBEDTLS_SSL_PROC_CHK(ssl_tls13_parse_certificate_request( @@ -3025,7 +3025,7 @@ static int ssl_tls13_process_new_session_ticket(mbedtls_ssl_context *ssl) MBEDTLS_SSL_DEBUG_MSG(2, ("=> parse new session ticket")); MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_tls13_fetch_handshake_msg( - ssl, MBEDTLS_SSL_HS_NEW_SESSION_TICKET, 0, + ssl, MBEDTLS_SSL_HS_NEW_SESSION_TICKET, &buf, &buf_len)); /* diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index 92dfcc3dfc..0cdce76903 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -47,11 +47,30 @@ const uint8_t mbedtls_ssl_tls13_hello_retry_request_magic[ int mbedtls_ssl_tls13_fetch_handshake_msg(mbedtls_ssl_context *ssl, unsigned hs_type, - unsigned require_record_boundary, unsigned char **buf, size_t *buf_len) { - int ret; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + int require_record_boundary; + + /* Require record-boundary alignment by default. The exceptions below are + * handshake messages that may legitimately be followed by additional + * handshake messages in the same record. Using the default behaviour for a + * message that should be exempt is an interoperability bug; exempting a + * message that should not be exempt may have security implications. + */ + switch (hs_type) { + case MBEDTLS_SSL_HS_NEW_SESSION_TICKET: + case MBEDTLS_SSL_HS_ENCRYPTED_EXTENSIONS: + case MBEDTLS_SSL_HS_CERTIFICATE: + case MBEDTLS_SSL_HS_CERTIFICATE_REQUEST: + case MBEDTLS_SSL_HS_CERTIFICATE_VERIFY: + require_record_boundary = 0; + break; + + default: + require_record_boundary = 1; + } ret = mbedtls_ssl_read_record(ssl, 0); if (ret != 0) { @@ -349,7 +368,7 @@ int mbedtls_ssl_tls13_process_certificate_verify(mbedtls_ssl_context *ssl) MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_tls13_fetch_handshake_msg( - ssl, MBEDTLS_SSL_HS_CERTIFICATE_VERIFY, 0, &buf, &buf_len)); + ssl, MBEDTLS_SSL_HS_CERTIFICATE_VERIFY, &buf, &buf_len)); /* Need to calculate the hash of the transcript first * before reading the message since otherwise it gets @@ -701,7 +720,7 @@ int mbedtls_ssl_tls13_process_certificate(mbedtls_ssl_context *ssl) size_t buf_len; MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_tls13_fetch_handshake_msg( - ssl, MBEDTLS_SSL_HS_CERTIFICATE, 0, + ssl, MBEDTLS_SSL_HS_CERTIFICATE, &buf, &buf_len)); /* Parse the certificate chain sent by the peer. */ @@ -1120,7 +1139,7 @@ int mbedtls_ssl_tls13_process_finished_message(mbedtls_ssl_context *ssl) MBEDTLS_SSL_DEBUG_MSG(2, ("=> parse finished message")); MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_tls13_fetch_handshake_msg( - ssl, MBEDTLS_SSL_HS_FINISHED, 1, &buf, &buf_len)); + ssl, MBEDTLS_SSL_HS_FINISHED, &buf, &buf_len)); /* Preprocessing step: Compute handshake digest */ MBEDTLS_SSL_PROC_CHK(ssl_tls13_preprocess_finished_message(ssl)); diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index 0db142c50a..38f2fe9370 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -1936,7 +1936,7 @@ static int ssl_tls13_process_client_hello(mbedtls_ssl_context *ssl) MBEDTLS_SSL_DEBUG_MSG(2, ("=> parse client hello")); MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_tls13_fetch_handshake_msg( - ssl, MBEDTLS_SSL_HS_CLIENT_HELLO, 1, + ssl, MBEDTLS_SSL_HS_CLIENT_HELLO, &buf, &buflen)); MBEDTLS_SSL_PROC_CHK_NEG(ssl_tls13_parse_client_hello(ssl, buf, @@ -3027,7 +3027,7 @@ static int ssl_tls13_process_end_of_early_data(mbedtls_ssl_context *ssl) size_t buf_len; MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_tls13_fetch_handshake_msg( - ssl, MBEDTLS_SSL_HS_END_OF_EARLY_DATA, 1, + ssl, MBEDTLS_SSL_HS_END_OF_EARLY_DATA, &buf, &buf_len)); MBEDTLS_SSL_PROC_CHK(ssl_tls13_parse_end_of_early_data( diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index f48543d4c9..f655b1cf90 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4169,7 +4169,7 @@ void tls13_server_certificate_msg_invalid_vector_len() ret = mbedtls_ssl_tls13_fetch_handshake_msg(&(client_ep.ssl), MBEDTLS_SSL_HS_CERTIFICATE, - 0, &buf, &buf_len); + &buf, &buf_len); TEST_EQUAL(ret, 0); end = buf + buf_len; From 45d892ea3d69d2996937503e269c2ec04a2e7557 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Tue, 23 Jun 2026 10:34:33 +0200 Subject: [PATCH 164/173] Check ServerHello record boundary alignment only in TLS 1.3 case Signed-off-by: Ronald Cron --- library/ssl_tls13_client.c | 13 +++++++++++++ library/ssl_tls13_generic.c | 10 ++++++++++ 2 files changed, 23 insertions(+) diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index ecdf507eab..e8b6063f32 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -2016,6 +2016,19 @@ static int ssl_tls13_process_server_hello(mbedtls_ssl_context *ssl) goto cleanup; } + /* + * TLS 1.3 is negotiated. Check that ServerHello/HRR ends at a record + * boundary. For HRR, which does not trigger a key update, this checks + * that HRR terminates the server flight. + */ + if (ssl->in_hslen != ssl->in_msglen) { + MBEDTLS_SSL_DEBUG_MSG(1, ("ServerHello end not aligned with a record boundary")); + ret = MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; + MBEDTLS_SSL_PEND_FATAL_ALERT(MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE); + goto cleanup; + } + MBEDTLS_SSL_PROC_CHK(ssl_tls13_parse_server_hello(ssl, buf, buf + buf_len, is_hrr)); diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index 0cdce76903..abb8b4f3e4 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -65,10 +65,20 @@ int mbedtls_ssl_tls13_fetch_handshake_msg(mbedtls_ssl_context *ssl, case MBEDTLS_SSL_HS_CERTIFICATE: case MBEDTLS_SSL_HS_CERTIFICATE_REQUEST: case MBEDTLS_SSL_HS_CERTIFICATE_VERIFY: + /* + * For TLS 1.3, ServerHello (including HelloRetryRequest) must end at a + * record boundary, but not for TLS 1.2. At this point the ServerHello + * has not yet been processed, so we do not know whether it negotiates + * TLS 1.3 or TLS 1.2. Defer the boundary check until the protocol + * version is known to be TLS 1.3. + */ + case MBEDTLS_SSL_HS_SERVER_HELLO: require_record_boundary = 0; break; default: + /* ClientHello, EndOfEarlyData, Finished, and KeyUpdate. + */ require_record_boundary = 1; } From 2bab33486e3781569de700afc097fb879df9e3ea Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Fri, 26 Jun 2026 22:11:24 +0100 Subject: [PATCH 165/173] Updated tf-psa-crypto submodule Signed-off-by: Minos Galanakis --- tf-psa-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tf-psa-crypto b/tf-psa-crypto index e0e92d56c7..a0632be94d 160000 --- a/tf-psa-crypto +++ b/tf-psa-crypto @@ -1 +1 @@ -Subproject commit e0e92d56c73bf2fee0cdc92e67bd35c90015d301 +Subproject commit a0632be94d883daa0295ac1eabf70359ad94f91b From 0c5fe5c6773e448268af0aad3ecc1b57e8ac7a28 Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Fri, 26 Jun 2026 22:14:46 +0100 Subject: [PATCH 166/173] Bump version --version 4.1.1 ./scripts/bump_version.sh --version 4.1.1 Signed-off-by: Minos Galanakis --- CMakeLists.txt | 2 +- doxygen/input/doc_mainpage.h | 2 +- doxygen/mbedtls.doxyfile | 2 +- include/mbedtls/build_info.h | 8 ++++---- tests/suites/test_suite_version.data | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c6d076346c..1c9b2c4b55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ cmake_policy(SET CMP0011 NEW) # is deprecated and will be removed in future versions. cmake_policy(SET CMP0012 NEW) -set(MBEDTLS_VERSION 4.1.0) +set(MBEDTLS_VERSION 4.1.1) set(MBEDTLS_CRYPTO_SOVERSION 18) set(MBEDTLS_X509_SOVERSION 9) set(MBEDTLS_TLS_SOVERSION 23) diff --git a/doxygen/input/doc_mainpage.h b/doxygen/input/doc_mainpage.h index b28b82b851..74799cf81e 100644 --- a/doxygen/input/doc_mainpage.h +++ b/doxygen/input/doc_mainpage.h @@ -10,7 +10,7 @@ */ /** - * @mainpage Mbed TLS v4.1.0 API Documentation + * @mainpage Mbed TLS v4.1.1 API Documentation * * This documentation describes the application programming interface (API) * of Mbed TLS. diff --git a/doxygen/mbedtls.doxyfile b/doxygen/mbedtls.doxyfile index c6a5e4f4fd..f2d5f2f83b 100644 --- a/doxygen/mbedtls.doxyfile +++ b/doxygen/mbedtls.doxyfile @@ -1,4 +1,4 @@ -PROJECT_NAME = "Mbed TLS v4.1.0" +PROJECT_NAME = "Mbed TLS v4.1.1" OUTPUT_DIRECTORY = ../apidoc/ FULL_PATH_NAMES = NO OPTIMIZE_OUTPUT_FOR_C = YES diff --git a/include/mbedtls/build_info.h b/include/mbedtls/build_info.h index e077bbce40..e83b7e99e2 100644 --- a/include/mbedtls/build_info.h +++ b/include/mbedtls/build_info.h @@ -28,16 +28,16 @@ */ #define MBEDTLS_VERSION_MAJOR 4 #define MBEDTLS_VERSION_MINOR 1 -#define MBEDTLS_VERSION_PATCH 0 +#define MBEDTLS_VERSION_PATCH 1 /** * The single version number has the following structure: * MMNNPP00 * Major version | Minor version | Patch version */ -#define MBEDTLS_VERSION_NUMBER 0x04010000 -#define MBEDTLS_VERSION_STRING "4.1.0" -#define MBEDTLS_VERSION_STRING_FULL "Mbed TLS 4.1.0" +#define MBEDTLS_VERSION_NUMBER 0x04010100 +#define MBEDTLS_VERSION_STRING "4.1.1" +#define MBEDTLS_VERSION_STRING_FULL "Mbed TLS 4.1.1" #if defined(MBEDTLS_CONFIG_FILES_READ) #error "Something went wrong: MBEDTLS_CONFIG_FILES_READ defined before reading the config files!" diff --git a/tests/suites/test_suite_version.data b/tests/suites/test_suite_version.data index 5ffdfe71f9..1d2c3f9b96 100644 --- a/tests/suites/test_suite_version.data +++ b/tests/suites/test_suite_version.data @@ -1,8 +1,8 @@ Check compile time library version -check_compiletime_version:"4.1.0" +check_compiletime_version:"4.1.1" Check runtime library version -check_runtime_version:"4.1.0" +check_runtime_version:"4.1.1" Check for MBEDTLS_VERSION_C check_feature:"MBEDTLS_VERSION_C":0 From 5089e9f62397c1efc41b2416520e73c1e397476e Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Fri, 26 Jun 2026 22:16:00 +0100 Subject: [PATCH 167/173] Assemble Changelog ./framework/scripts/assemble_changelog.py Signed-off-by: Minos Galanakis --- ChangeLog | 102 ++++++++++++++++++ .../1583-1584-ssl-transcript-errors.txt | 17 --- ChangeLog.d/cmake-destdir-instal.txt | 3 - ChangeLog.d/drop-early-data.txt | 7 -- ChangeLog.d/ecdh-psk-integer-overflow.txt | 3 - ChangeLog.d/fix-info-leak-in-ssl.txt | 6 -- ChangeLog.d/fix-tls12-rsa-pss-sigalgs.txt | 4 - ChangeLog.d/issue10740.txt | 3 - .../mbedtls_ssl_set_cid-documentation.txt | 3 - ChangeLog.d/oob-key-exchange-restricted.txt | 4 - ChangeLog.d/pkcs-free-stale-pointers.txt | 6 -- ChangeLog.d/pkcs7-reject-weak-hashes.txt | 9 -- .../pr_10695__fix_build_llvm_mingw.txt | 3 - ChangeLog.d/security-advice.txt | 2 - ChangeLog.d/security-issue1569.txt | 7 -- ChangeLog.d/security1585.txt | 6 -- .../serialized-data-load-hardening.txt | 5 - ...pare_new_session_ticket-psa_get_random.txt | 5 - ChangeLog.d/tls13-hrr-selected-group.txt | 7 -- .../x509-crt-parse-basicConstraints.txt | 15 --- .../x509-csr-extension-request-bounds.txt | 3 - 21 files changed, 102 insertions(+), 118 deletions(-) delete mode 100644 ChangeLog.d/1583-1584-ssl-transcript-errors.txt delete mode 100644 ChangeLog.d/cmake-destdir-instal.txt delete mode 100644 ChangeLog.d/drop-early-data.txt delete mode 100644 ChangeLog.d/ecdh-psk-integer-overflow.txt delete mode 100644 ChangeLog.d/fix-info-leak-in-ssl.txt delete mode 100644 ChangeLog.d/fix-tls12-rsa-pss-sigalgs.txt delete mode 100644 ChangeLog.d/issue10740.txt delete mode 100644 ChangeLog.d/mbedtls_ssl_set_cid-documentation.txt delete mode 100644 ChangeLog.d/oob-key-exchange-restricted.txt delete mode 100644 ChangeLog.d/pkcs-free-stale-pointers.txt delete mode 100644 ChangeLog.d/pkcs7-reject-weak-hashes.txt delete mode 100644 ChangeLog.d/pr_10695__fix_build_llvm_mingw.txt delete mode 100644 ChangeLog.d/security-advice.txt delete mode 100644 ChangeLog.d/security-issue1569.txt delete mode 100644 ChangeLog.d/security1585.txt delete mode 100644 ChangeLog.d/serialized-data-load-hardening.txt delete mode 100644 ChangeLog.d/ssl_tls13_prepare_new_session_ticket-psa_get_random.txt delete mode 100644 ChangeLog.d/tls13-hrr-selected-group.txt delete mode 100644 ChangeLog.d/x509-crt-parse-basicConstraints.txt delete mode 100644 ChangeLog.d/x509-csr-extension-request-bounds.txt diff --git a/ChangeLog b/ChangeLog index b7a79ce348..2cd99dc8f2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,107 @@ Mbed TLS ChangeLog (Sorted per branch, date) += Mbed TLS 4.1.1 branch released 2026-07-07 + +Features + * Restore DESTDIR support for CMake installs of compatibility + libmbedcrypto symlinks. Fixes #10627. + * SHA3-256, SHA3-384 and SHA3-512 are now accepted in the default X.509 + certificate profile. + +Security + * Added advice about compiler options in SECURITY.md. + * Fix a bug where transcript-hash computation errors during TLS 1.2 + extended master secret calculation could be ignored instead of causing the + handshake to fail. This could allow a handshake to continue with a master + secret that was not correctly bound to the handshake transcript, + undermining the security guarantees of the extended master secret + extension. Report by Mathew Gretton-Dann. CVE-2026-50581 + * Fix a TLS 1.3 server-side error-handling bug affecting session ticket + generation. Under rare conditions, such as memory allocation failures + while computing the resumption master secret, the server could issue + invalid session tickets instead of failing the handshake. Clients + presented with such tickets would fail session resumption and fall back to + a full handshake. In deployments relying on session resumption, repeated + occurrences could increase the frequency of full handshakes and amplify + resource consumption during periods of resource exhaustion or other + transient failures. Reported by jjfz123. + CVE-2026-50640 + * Fixed a TLS 1.3 record-boundary validation issue that could allow + unauthenticated plaintext data to be processed across a key change. In + servers with MBEDTLS_SSL_EARLY_DATA enabled, this could be exploited by a + man-in-the-middle attacker to cause loss of 0-RTT early data. + Reported by Ben Smyth. + CVE-2026-TODO. + * Fix a remote buffer overflow in (D)TLS with ECDHE-PSK cipher suites when + CBC is disabled. Reported by Karnakar Reddy. CVE-ID-50580 + * 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. + * Fix an out-of-bounds read when parsing TLS 1.2 ECJPAKE ServerKeyExchange + messages. Reported-by Biniam Demissie. + CVE-2026-50588 + * Fix a use-after-free/double-free risk in mbedtls_pkcs7_free() when reusing + an mbedtls_pkcs7 context across parse -> free -> parse -> free cycles. The + function now resets the context after freeing it, ensuring stale + signed_data.signers.next pointers cannot be walked by a later free + operation. CVE-2026-50579 + * PKCS7 now rejects weak hash algorithms (RIPEMD160, MD5, SHA-1, SHA-224, + SHA3-224) on signature verification. The new configuration option + MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES allows to keep using weak hash + algorithms in PKCS7 for backward compatibility purposes. + * Improved documentation of mbedtls_ssl_conf_sig_algs() to emphasize that + this function only sets signature algorithms that are enforced during + TLS key exchange and not on certificate verification. Reported by + Xiangdong Li, Beijing University of Posts and Telecommunications (BUPT). + CVE-2026-54441 + * Ensure 'badmac_seen' and 'dtls_srtp_info' fields from 'mbedtls_ssl_context' + are properly zeroized when mbedtls_ssl_session_reset() is called. This + could cause premature DTLS connection failure or incorrect DTLS-SRTP + parameter inheritance for applications reusing an SSL context. + Reported by jjfz123. CVE-2026-50585. + * Fix a bug where mbedtls_ssl_read() and mbedtls_ssl_write() could return + 1 instead of an error code if the random generator failed when a server + called these functions before the end of a TLS 1.3 handshake. + Reported by Mohammad Seet (mhdsait101). CVE-2026-40294 + * Fix TLS 1.3 clients to reject a HelloRetryRequest whose selected group was + not advertised in the original ClientHello. Reported independently by + Din Asotić / Xiangdong Li, Beijing University of Posts and + Telecommunications (BUPT), and NVIDIA Project Vanessa. + CVE-2026-25832. + * Fix two bugs in the X.509 certificate parser that caused some inputs + with a malformed basicConstraints extension to be accepted. This + could have dangerous results, in particular causing some certificates + to be parsed as CA certificates when other X.509 implementations would + parse them as end-entity certificates. Reported by Mohammad Seet + (mhdsait101), Pablo Ruiz García and NVIDIA Project Vanessa. CVE-2026-49300 + +Bugfix + * Fix a TLS 1.2 regression that caused clients to reject valid + ServerKeyExchange signatures using RSA-PSS signature algorithms. + Fixes #10668. + * Fix a build error using the LLVM based MinGW toolchain. + Bug reported and fix contributed by valord577. + * Fixed a bug which prevented the inclusion of standard C library header + files from the user provided configuration file. Fixes #10740. + * Reject malformed TLS 1.3 serialized sessions instead of accepting + unterminated strings or extra trailing data. + * Reject serialized SSL contexts whose DTLS Connection ID length exceeds + the maximum supported size, instead of overflowing the internal buffer. + * Fixed documentation of mbedtls_ssl_set_cid(): the set CID configuration + is applied to all subsequent handshakes, not just to the next one. + * Reject malformed X.509 CSRs where the extensionRequest attribute + wrappers do not exactly contain the requested extensions. + +Changes + * X.509 certificates with a basicConstraints extension starting with an + INTEGER field are no longer accepted. According to RFC 5280, such + certificates are syntactically valid and the first field is the + pathLenConstraint value, but certificate authorities must not emit such + certificates. Mbed TLS interpreted it as a cA value, which was nonstandard + and dangerous. + = Mbed TLS 4.1.0 branch released 2026-03-31 API changes diff --git a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt b/ChangeLog.d/1583-1584-ssl-transcript-errors.txt deleted file mode 100644 index f259bd711e..0000000000 --- a/ChangeLog.d/1583-1584-ssl-transcript-errors.txt +++ /dev/null @@ -1,17 +0,0 @@ -Security - * Fix a bug where transcript-hash computation errors during TLS 1.2 - extended master secret calculation could be ignored instead of causing the - handshake to fail. This could allow a handshake to continue with a master - secret that was not correctly bound to the handshake transcript, - undermining the security guarantees of the extended master secret - extension. Report by Mathew Gretton-Dann. CVE-2026-50581 - * Fix a TLS 1.3 server-side error-handling bug affecting session ticket - generation. Under rare conditions, such as memory allocation failures - while computing the resumption master secret, the server could issue - invalid session tickets instead of failing the handshake. Clients - presented with such tickets would fail session resumption and fall back to - a full handshake. In deployments relying on session resumption, repeated - occurrences could increase the frequency of full handshakes and amplify - resource consumption during periods of resource exhaustion or other - transient failures. Reported by jjfz123. - CVE-2026-50640 diff --git a/ChangeLog.d/cmake-destdir-instal.txt b/ChangeLog.d/cmake-destdir-instal.txt deleted file mode 100644 index 1638a4bea9..0000000000 --- a/ChangeLog.d/cmake-destdir-instal.txt +++ /dev/null @@ -1,3 +0,0 @@ -Features - * Restore DESTDIR support for CMake installs of compatibility - libmbedcrypto symlinks. Fixes #10627. diff --git a/ChangeLog.d/drop-early-data.txt b/ChangeLog.d/drop-early-data.txt deleted file mode 100644 index dc597a23f0..0000000000 --- a/ChangeLog.d/drop-early-data.txt +++ /dev/null @@ -1,7 +0,0 @@ -Security - * Fixed a TLS 1.3 record-boundary validation issue that could allow - unauthenticated plaintext data to be processed across a key change. In - servers with MBEDTLS_SSL_EARLY_DATA enabled, this could be exploited by a - man-in-the-middle attacker to cause loss of 0-RTT early data. - Reported by Ben Smyth. - CVE-2026-TODO. diff --git a/ChangeLog.d/ecdh-psk-integer-overflow.txt b/ChangeLog.d/ecdh-psk-integer-overflow.txt deleted file mode 100644 index 3ed448ee16..0000000000 --- a/ChangeLog.d/ecdh-psk-integer-overflow.txt +++ /dev/null @@ -1,3 +0,0 @@ -Security - * Fix a remote buffer overflow in (D)TLS with ECDHE-PSK cipher suites when - CBC is disabled. Reported by Karnakar Reddy. CVE-ID-50580 diff --git a/ChangeLog.d/fix-info-leak-in-ssl.txt b/ChangeLog.d/fix-info-leak-in-ssl.txt deleted file mode 100644 index 2a0309fc40..0000000000 --- a/ChangeLog.d/fix-info-leak-in-ssl.txt +++ /dev/null @@ -1,6 +0,0 @@ -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. diff --git a/ChangeLog.d/fix-tls12-rsa-pss-sigalgs.txt b/ChangeLog.d/fix-tls12-rsa-pss-sigalgs.txt deleted file mode 100644 index 34296b602e..0000000000 --- a/ChangeLog.d/fix-tls12-rsa-pss-sigalgs.txt +++ /dev/null @@ -1,4 +0,0 @@ -Bugfix - * Fix a TLS 1.2 regression that caused clients to reject valid - ServerKeyExchange signatures using RSA-PSS signature algorithms. - Fixes #10668. diff --git a/ChangeLog.d/issue10740.txt b/ChangeLog.d/issue10740.txt deleted file mode 100644 index eb7a36c063..0000000000 --- a/ChangeLog.d/issue10740.txt +++ /dev/null @@ -1,3 +0,0 @@ -Bugfix - * Fixed a bug which prevented the inclusion of standard C library header - files from the user provided configuration file. Fixes #10740. diff --git a/ChangeLog.d/mbedtls_ssl_set_cid-documentation.txt b/ChangeLog.d/mbedtls_ssl_set_cid-documentation.txt deleted file mode 100644 index 1ad970fdfb..0000000000 --- a/ChangeLog.d/mbedtls_ssl_set_cid-documentation.txt +++ /dev/null @@ -1,3 +0,0 @@ -Bugfix - * Fixed documentation of mbedtls_ssl_set_cid(): the set CID configuration - is applied to all subsequent handshakes, not just to the next one. diff --git a/ChangeLog.d/oob-key-exchange-restricted.txt b/ChangeLog.d/oob-key-exchange-restricted.txt deleted file mode 100644 index 2e48ce0fec..0000000000 --- a/ChangeLog.d/oob-key-exchange-restricted.txt +++ /dev/null @@ -1,4 +0,0 @@ -Security - * Fix an out-of-bounds read when parsing TLS 1.2 ECJPAKE ServerKeyExchange - messages. Reported-by Biniam Demissie. - CVE-2026-50588 diff --git a/ChangeLog.d/pkcs-free-stale-pointers.txt b/ChangeLog.d/pkcs-free-stale-pointers.txt deleted file mode 100644 index 2c29fed5ef..0000000000 --- a/ChangeLog.d/pkcs-free-stale-pointers.txt +++ /dev/null @@ -1,6 +0,0 @@ -Security - * Fix a use-after-free/double-free risk in mbedtls_pkcs7_free() when reusing - an mbedtls_pkcs7 context across parse -> free -> parse -> free cycles. The - function now resets the context after freeing it, ensuring stale - signed_data.signers.next pointers cannot be walked by a later free - operation. CVE-2026-50579 diff --git a/ChangeLog.d/pkcs7-reject-weak-hashes.txt b/ChangeLog.d/pkcs7-reject-weak-hashes.txt deleted file mode 100644 index ce3f295db1..0000000000 --- a/ChangeLog.d/pkcs7-reject-weak-hashes.txt +++ /dev/null @@ -1,9 +0,0 @@ -Security - * PKCS7 now rejects weak hash algorithms (RIPEMD160, MD5, SHA-1, SHA-224, - SHA3-224) on signature verification. The new configuration option - MBEDTLS_PKCS7_ALLOW_WEAK_SIGNATURES allows to keep using weak hash - algorithms in PKCS7 for backward compatibility purposes. - -Features - * SHA3-256, SHA3-384 and SHA3-512 are now accepted in the default X.509 - certificate profile. diff --git a/ChangeLog.d/pr_10695__fix_build_llvm_mingw.txt b/ChangeLog.d/pr_10695__fix_build_llvm_mingw.txt deleted file mode 100644 index 3fed87143f..0000000000 --- a/ChangeLog.d/pr_10695__fix_build_llvm_mingw.txt +++ /dev/null @@ -1,3 +0,0 @@ -Bugfix - * Fix a build error using the LLVM based MinGW toolchain. - Bug reported and fix contributed by valord577. diff --git a/ChangeLog.d/security-advice.txt b/ChangeLog.d/security-advice.txt deleted file mode 100644 index 1f7677a882..0000000000 --- a/ChangeLog.d/security-advice.txt +++ /dev/null @@ -1,2 +0,0 @@ -Security - * Added advice about compiler options in SECURITY.md. diff --git a/ChangeLog.d/security-issue1569.txt b/ChangeLog.d/security-issue1569.txt deleted file mode 100644 index c9e285b80e..0000000000 --- a/ChangeLog.d/security-issue1569.txt +++ /dev/null @@ -1,7 +0,0 @@ -Security - * Improved documentation of mbedtls_ssl_conf_sig_algs() to emphasize that - this function only sets signature algorithms that are enforced during - TLS key exchange and not on certificate verification. Reported by - Xiangdong Li, Beijing University of Posts and Telecommunications (BUPT). - CVE-2026-54441 - diff --git a/ChangeLog.d/security1585.txt b/ChangeLog.d/security1585.txt deleted file mode 100644 index f9f21691db..0000000000 --- a/ChangeLog.d/security1585.txt +++ /dev/null @@ -1,6 +0,0 @@ -Security - * Ensure 'badmac_seen' and 'dtls_srtp_info' fields from 'mbedtls_ssl_context' - are properly zeroized when mbedtls_ssl_session_reset() is called. This - could cause premature DTLS connection failure or incorrect DTLS-SRTP - parameter inheritance for applications reusing an SSL context. - Reported by jjfz123. CVE-2026-50585. diff --git a/ChangeLog.d/serialized-data-load-hardening.txt b/ChangeLog.d/serialized-data-load-hardening.txt deleted file mode 100644 index e068988dac..0000000000 --- a/ChangeLog.d/serialized-data-load-hardening.txt +++ /dev/null @@ -1,5 +0,0 @@ -Bugfix - * Reject malformed TLS 1.3 serialized sessions instead of accepting - unterminated strings or extra trailing data. - * Reject serialized SSL contexts whose DTLS Connection ID length exceeds - the maximum supported size, instead of overflowing the internal buffer. diff --git a/ChangeLog.d/ssl_tls13_prepare_new_session_ticket-psa_get_random.txt b/ChangeLog.d/ssl_tls13_prepare_new_session_ticket-psa_get_random.txt deleted file mode 100644 index b020546b12..0000000000 --- a/ChangeLog.d/ssl_tls13_prepare_new_session_ticket-psa_get_random.txt +++ /dev/null @@ -1,5 +0,0 @@ -Security - * Fix a bug where mbedtls_ssl_read() and mbedtls_ssl_write() could return - 1 instead of an error code if the random generator failed when a server - called these functions before the end of a TLS 1.3 handshake. - Reported by Mohammad Seet (mhdsait101). CVE-2026-40294 diff --git a/ChangeLog.d/tls13-hrr-selected-group.txt b/ChangeLog.d/tls13-hrr-selected-group.txt deleted file mode 100644 index 4c338480f6..0000000000 --- a/ChangeLog.d/tls13-hrr-selected-group.txt +++ /dev/null @@ -1,7 +0,0 @@ -Security - * Fix TLS 1.3 clients to reject a HelloRetryRequest whose selected group was - not advertised in the original ClientHello. Reported independently by - Din Asotić / Xiangdong Li, Beijing University of Posts and - Telecommunications (BUPT), and NVIDIA Project Vanessa. - CVE-2026-25832. - diff --git a/ChangeLog.d/x509-crt-parse-basicConstraints.txt b/ChangeLog.d/x509-crt-parse-basicConstraints.txt deleted file mode 100644 index 251dc8f0fd..0000000000 --- a/ChangeLog.d/x509-crt-parse-basicConstraints.txt +++ /dev/null @@ -1,15 +0,0 @@ -Security - * Fix two bugs in the X.509 certificate parser that caused some inputs - with a malformed basicConstraints extension to be accepted. This - could have dangerous results, in particular causing some certificates - to be parsed as CA certificates when other X.509 implementations would - parse them as end-entity certificates. Reported by Mohammad Seet - (mhdsait101), Pablo Ruiz García and NVIDIA Project Vanessa. CVE-2026-49300 - -Changes - * X.509 certificates with a basicConstraints extension starting with an - INTEGER field are no longer accepted. According to RFC 5280, such - certificates are syntactically valid and the first field is the - pathLenConstraint value, but certificate authorities must not emit such - certificates. Mbed TLS interpreted it as a cA value, which was nonstandard - and dangerous. diff --git a/ChangeLog.d/x509-csr-extension-request-bounds.txt b/ChangeLog.d/x509-csr-extension-request-bounds.txt deleted file mode 100644 index dfc706703c..0000000000 --- a/ChangeLog.d/x509-csr-extension-request-bounds.txt +++ /dev/null @@ -1,3 +0,0 @@ -Bugfix - * Reject malformed X.509 CSRs where the extensionRequest attribute - wrappers do not exactly contain the requested extensions. From 0f9f57a047b9e3e5e1a77a45255573d6831a0714 Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Mon, 29 Jun 2026 18:05:23 +0100 Subject: [PATCH 168/173] Changelog: Added reference to tf-psa-crypto update Signed-off-by: Minos Galanakis --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 2cd99dc8f2..4f39a4d9e0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -95,6 +95,7 @@ Bugfix wrappers do not exactly contain the requested extensions. Changes + * Upgraded TF-PSA-Crypto from 1.1.0 to 1.1.1. See tf-psa-crypto/ChangeLog. * X.509 certificates with a basicConstraints extension starting with an INTEGER field are no longer accepted. According to RFC 5280, such certificates are syntactically valid and the first field is the From d1f3eee6b581d531d9f4f00207b6cc938b22b2ab Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Mon, 29 Jun 2026 18:30:38 +0100 Subject: [PATCH 169/173] ChangeLog: Removed todo placeholder for CVE Signed-off-by: Minos Galanakis --- ChangeLog | 1 - 1 file changed, 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 4f39a4d9e0..643cc92bad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -31,7 +31,6 @@ Security servers with MBEDTLS_SSL_EARLY_DATA enabled, this could be exploited by a man-in-the-middle attacker to cause loss of 0-RTT early data. Reported by Ben Smyth. - CVE-2026-TODO. * Fix a remote buffer overflow in (D)TLS with ECDHE-PSK cipher suites when CBC is disabled. Reported by Karnakar Reddy. CVE-ID-50580 * Fix a potential information disclosure in TLS 1.2 servers using session From 5b6dd79f676951ca47f07e49d0b8576b88c8b3c3 Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Fri, 26 Jun 2026 22:17:39 +0100 Subject: [PATCH 170/173] Update BRANCHES.md Signed-off-by: Minos Galanakis --- BRANCHES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BRANCHES.md b/BRANCHES.md index 8abb39cefb..cce737cd25 100644 --- a/BRANCHES.md +++ b/BRANCHES.md @@ -88,9 +88,9 @@ The following branches are currently maintained: - [`development`](https://github.com/Mbed-TLS/mbedtls/) - [`mbedtls-3.6`](https://github.com/Mbed-TLS/mbedtls/tree/mbedtls-3.6) maintained until March 2027, see - . + . - [`mbedtls-4.1`](https://github.com/Mbed-TLS/mbedtls/tree/mbedtls-4.1) maintained until March 2029, see - . + . Users are urged to always use the latest version of a maintained branch. From 0a8fda272a5a0abef3b47c91bed37185d5a726b1 Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Wed, 1 Jul 2026 12:00:14 +0100 Subject: [PATCH 171/173] ChangeLog: Removed CVE-ID Signed-off-by: Minos Galanakis --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 643cc92bad..4212640731 100644 --- a/ChangeLog +++ b/ChangeLog @@ -63,7 +63,7 @@ Security * Fix a bug where mbedtls_ssl_read() and mbedtls_ssl_write() could return 1 instead of an error code if the random generator failed when a server called these functions before the end of a TLS 1.3 handshake. - Reported by Mohammad Seet (mhdsait101). CVE-2026-40294 + Reported by Mohammad Seet (mhdsait101). * Fix TLS 1.3 clients to reject a HelloRetryRequest whose selected group was not advertised in the original ClientHello. Reported independently by Din Asotić / Xiangdong Li, Beijing University of Posts and From cf644361ff7f0205e612cca1f4dc80f14de38fda Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Tue, 7 Jul 2026 16:56:04 +0100 Subject: [PATCH 172/173] Updated tf-psa-crypto submodule Signed-off-by: Minos Galanakis --- tf-psa-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tf-psa-crypto b/tf-psa-crypto index a0632be94d..07e5c26e5b 160000 --- a/tf-psa-crypto +++ b/tf-psa-crypto @@ -1 +1 @@ -Subproject commit a0632be94d883daa0295ac1eabf70359ad94f91b +Subproject commit 07e5c26e5b9be0d04596174763ee8b982bf16a10 From c8ab24b67cc7e5e47f76b0b5c479f7dc755c509f Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Tue, 7 Jul 2026 16:56:12 +0100 Subject: [PATCH 173/173] Updated framework Signed-off-by: Minos Galanakis --- framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework b/framework index dde0c4a0e4..a307955223 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit dde0c4a0e448a0552f18817dcea633bb851fd288 +Subproject commit a3079552234917a9831dd70693983af5e62c70de