From 75b8b0f4d95d6c1520c7ec0016ecbc18cde95e8e Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Tue, 17 Feb 2026 10:46:42 +0100 Subject: [PATCH 1/7] Add unit test with TLS 1.2 nego after HRR Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.data | 3 + tests/suites/test_suite_ssl.function | 154 +++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index b05de38509..be7aa90bf0 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3367,3 +3367,6 @@ ssl_tls_exporter_too_early:MBEDTLS_SSL_VERSION_TLS1_3:1:MBEDTLS_SSL_SERVER_CERTI TLS fatal alert getter ssl_get_alert_after_fatal + +TLS 1.3 - HRR then TLS 1.2 second ClientHello +tls13_hrr_then_tls12_second_client_hello diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 628a183853..d438f230c4 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -5981,3 +5981,157 @@ exit: USE_PSA_DONE(); } /* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_TEST_HAS_TLS1_3_CHACHA20_POLY1305_SHA256: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_hrr_then_tls12_second_client_hello() +{ + int ret = -1; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + 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; + mbedtls_test_handshake_test_options server_options; + mbedtls_ssl_session saved_session; + uint16_t group_list[3] = { + MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1, + MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1, + MBEDTLS_SSL_IANA_TLS_GROUP_NONE + }; + const int tls12_ciphersuite_list[2] = { + MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + 0 + }; + + mbedtls_test_init_handshake_options(&client_options); + mbedtls_test_init_handshake_options(&server_options); + mbedtls_ssl_session_init(&saved_session); + + PSA_INIT(); + + /* + * Run first handshake to get a ticket from the server. + */ + client_options.pk_alg = MBEDTLS_PK_ECDSA; + client_options.group_list = group_list; + client_options.cipher = "TLS1-3-CHACHA20-POLY1305-SHA256"; + server_options.pk_alg = MBEDTLS_PK_ECDSA; + server_options.group_list = group_list; + + ret = mbedtls_test_get_tls13_ticket(&client_options, &server_options, + &saved_session); + TEST_EQUAL(ret, 0); + + /* + * Prepare for handshake with the ticket. + */ + /* Remove the group SECP256R1 fron the list of groups supported by the + * server such that it sends an HRR in response to the ClientHello. + */ + server_options.group_list = group_list + 1; + + 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); + + /* + * Progress the handshake up to the point where the server has sent the + * HRR and the client as received and processed the server HRR but not + * written the second ClientHello in response to the HRR. + */ + 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( + &(client_ep.ssl), &(server_ep.ssl), + MBEDTLS_SSL_CLIENT_HELLO); + TEST_EQUAL(ret, 0); + + #if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE) + /* If the compatibility mode is enabled, filter the dummy change_cipher_spec + * record sent by the server after the HRR. Otherwise, as we have switched + * the client to TLS 1.2 it would fail when reading this record. + */ + ret = mbedtls_ssl_read_record(&(client_ep.ssl), 0); + TEST_EQUAL(ret, MBEDTLS_ERR_SSL_WANT_READ); + #endif + + /* + * Reset the client and tweak its configuration and context such as it + * resumes a TLS 1.2 session using an all-zeroes master secret as the + * server will when it receives the TLS 1.2 ClientHello. + * To be able to compute the Finished message the server will expect, we + * also initiate the handshake transcript by cloning the server current one. + * This transcript is the server's one after the call to + * `mbedtls_ssl_reset_transcript_for_hrr()`. It is computed only + * with the data of the first ClientHello thus a man-in-the-middle could + * compute it without having access to the server context. Here we use + * the server context just for convenience. + */ + + client_ep.ssl.tls_version = MBEDTLS_SSL_VERSION_TLS1_2; + mbedtls_ssl_conf_min_tls_version((mbedtls_ssl_config *) client_ep.ssl.conf, + MBEDTLS_SSL_VERSION_TLS1_2); + mbedtls_ssl_conf_max_tls_version((mbedtls_ssl_config *) client_ep.ssl.conf, + MBEDTLS_SSL_VERSION_TLS1_2); + mbedtls_ssl_conf_ciphersuites((mbedtls_ssl_config *) client_ep.ssl.conf, + tls12_ciphersuite_list); + + ret = mbedtls_ssl_session_reset(&(client_ep.ssl)); + + client_ep.ssl.handshake->resume = 1; + client_ep.ssl.session_negotiate->tls_version = MBEDTLS_SSL_VERSION_TLS1_2; + memset(client_ep.ssl.session_negotiate->id, 0xa5, + sizeof(client_ep.ssl.session_negotiate->id)); + client_ep.ssl.session_negotiate->id_len = sizeof(client_ep.ssl.session_negotiate->id); + client_ep.ssl.session_negotiate->ciphersuite = + MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256; + + status = psa_hash_abort(&client_ep.ssl.handshake->fin_sha256_psa); + TEST_EQUAL(status, PSA_SUCCESS); + + status = psa_hash_clone(&server_ep.ssl.handshake->fin_sha256_psa, + &client_ep.ssl.handshake->fin_sha256_psa); + TEST_EQUAL(status, PSA_SUCCESS); + + /* + * Restart and complete the handshake. + */ + + ret = mbedtls_test_move_handshake_to_state( + &(server_ep.ssl), &(client_ep.ssl), + MBEDTLS_SSL_HANDSHAKE_OVER); + TEST_EQUAL(ret, 0); + + ret = mbedtls_test_move_handshake_to_state( + &(client_ep.ssl), &(server_ep.ssl), + MBEDTLS_SSL_HANDSHAKE_OVER); + TEST_EQUAL(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_ssl_session_free(&saved_session); + PSA_DONE(); +} +/* END_CASE */ From ed767bada9108fb7e15a1012f384a08e2cd637f2 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Thu, 19 Feb 2026 18:11:19 +0100 Subject: [PATCH 2/7] tls13: Do not negotiate TLS 1.2 after an HRR Signed-off-by: Ronald Cron --- library/ssl_tls13_server.c | 10 +++++- tests/suites/test_suite_ssl.function | 47 +++++++++------------------- 2 files changed, 23 insertions(+), 34 deletions(-) diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index 982e6f8c3b..b0e22230aa 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -1948,6 +1948,9 @@ static int ssl_tls13_process_client_hello(mbedtls_ssl_context *ssl) /* * Version 1.2 of the protocol has to be used for the handshake. + * If we have sent an HRR, then the second ClientHello is inconsistent + * with the first one and we abort the handshake with an `illegal_parameter` + * fatal alert. * If TLS 1.2 is not supported, abort the handshake. Otherwise, set the * ssl->keep_current_message flag for the ClientHello to be kept and parsed * as a TLS 1.2 ClientHello. We also change ssl->tls_version to @@ -1955,7 +1958,12 @@ static int ssl_tls13_process_client_hello(mbedtls_ssl_context *ssl) * will dispatch to the TLS 1.2 state machine. */ if (SSL_CLIENT_HELLO_TLS1_2 == parse_client_hello_ret) { - /* Check if server supports TLS 1.2 */ + if (ssl->handshake->hello_retry_request_flag) { + MBEDTLS_SSL_DEBUG_MSG(1, ("Non compliant 2nd ClientHello, TLS 1.2 version")); + MBEDTLS_SSL_PEND_FATAL_ALERT(MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER); + return MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER; + } if (!mbedtls_ssl_conf_is_tls12_enabled(ssl->conf)) { MBEDTLS_SSL_DEBUG_MSG( 1, ("TLS 1.2 not supported.")); diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index d438f230c4..a42ff8b964 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -5982,17 +5982,18 @@ exit: } /* END_CASE */ -/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_TEST_HAS_TLS1_3_CHACHA20_POLY1305_SHA256: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 */ +/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_TEST_HAS_TLS1_3_CHACHA20_POLY1305_SHA256: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:MBEDTLS_DEBUG_C */ void tls13_hrr_then_tls12_second_client_hello() { int ret = -1; - psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; 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; mbedtls_test_handshake_test_options server_options; mbedtls_ssl_session saved_session; + mbedtls_test_ssl_log_pattern server_pattern = + { "Non compliant 2nd ClientHello, TLS 1.2 version", 0 }; uint16_t group_list[3] = { MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1, MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1, @@ -6034,6 +6035,8 @@ void tls13_hrr_then_tls12_second_client_hello() &client_options); TEST_EQUAL(ret, 0); + server_options.srv_log_fun = mbedtls_test_ssl_log_analyzer; + server_options.srv_log_obj = &server_pattern; ret = mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER, &server_options); TEST_EQUAL(ret, 0); @@ -6075,16 +6078,8 @@ void tls13_hrr_then_tls12_second_client_hello() #endif /* - * Reset the client and tweak its configuration and context such as it - * resumes a TLS 1.2 session using an all-zeroes master secret as the - * server will when it receives the TLS 1.2 ClientHello. - * To be able to compute the Finished message the server will expect, we - * also initiate the handshake transcript by cloning the server current one. - * This transcript is the server's one after the call to - * `mbedtls_ssl_reset_transcript_for_hrr()`. It is computed only - * with the data of the first ClientHello thus a man-in-the-middle could - * compute it without having access to the server context. Here we use - * the server context just for convenience. + * Reset the client and force it to TLS 1.2 so that it sends a TLS 1.2 + * ClientHello. */ client_ep.ssl.tls_version = MBEDTLS_SSL_VERSION_TLS1_2; @@ -6097,34 +6092,20 @@ void tls13_hrr_then_tls12_second_client_hello() ret = mbedtls_ssl_session_reset(&(client_ep.ssl)); - client_ep.ssl.handshake->resume = 1; - client_ep.ssl.session_negotiate->tls_version = MBEDTLS_SSL_VERSION_TLS1_2; - memset(client_ep.ssl.session_negotiate->id, 0xa5, - sizeof(client_ep.ssl.session_negotiate->id)); - client_ep.ssl.session_negotiate->id_len = sizeof(client_ep.ssl.session_negotiate->id); - client_ep.ssl.session_negotiate->ciphersuite = - MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256; - - status = psa_hash_abort(&client_ep.ssl.handshake->fin_sha256_psa); - TEST_EQUAL(status, PSA_SUCCESS); - - status = psa_hash_clone(&server_ep.ssl.handshake->fin_sha256_psa, - &client_ep.ssl.handshake->fin_sha256_psa); - TEST_EQUAL(status, PSA_SUCCESS); - /* - * Restart and complete the handshake. + * Restart and try to complete the handshake on server side which is + * expected to fail early. */ + mbedtls_debug_set_threshold(1); ret = mbedtls_test_move_handshake_to_state( &(server_ep.ssl), &(client_ep.ssl), MBEDTLS_SSL_HANDSHAKE_OVER); - TEST_EQUAL(ret, 0); + TEST_EQUAL(ret, MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER); - ret = mbedtls_test_move_handshake_to_state( - &(client_ep.ssl), &(server_ep.ssl), - MBEDTLS_SSL_HANDSHAKE_OVER); - TEST_EQUAL(ret, 0); + TEST_EQUAL(server_pattern.counter, 1); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); + TEST_EQUAL(server_ep.ssl.state, MBEDTLS_SSL_CLIENT_HELLO); exit: mbedtls_test_ssl_endpoint_free(&client_ep); From 8731587e41379e8ea5cd7ddda7e418059947ed7a Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Thu, 26 Feb 2026 12:06:19 +0100 Subject: [PATCH 3/7] tls13: Commit to session resume only when we actually do it Signed-off-by: Ronald Cron --- library/ssl_tls13_server.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index b0e22230aa..19aa0e6b32 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -1755,6 +1755,11 @@ static int ssl_tls13_parse_client_hello(mbedtls_ssl_context *ssl, return MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER; } + if (handshake->key_exchange_mode != + MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK) { + hrr_required = (no_usable_share_for_key_agreement != 0); + } + #if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_PSK_ENABLED) if (handshake->key_exchange_mode & MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ALL) { @@ -1765,17 +1770,12 @@ static int ssl_tls13_parse_client_hello(mbedtls_ssl_context *ssl, ((unsigned) psk.ciphersuite_info->id), psk.ciphersuite_info->name)); - if (psk.type == MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION) { + if (psk.type == MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION && (!hrr_required)) { handshake->resume = 1; } } #endif - if (handshake->key_exchange_mode != - MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK) { - hrr_required = (no_usable_share_for_key_agreement != 0); - } - mbedtls_ssl_optimize_checksum(ssl, handshake->ciphersuite_info); return hrr_required ? SSL_CLIENT_HELLO_HRR_REQUIRED : SSL_CLIENT_HELLO_OK; From e051abd5e3830ae98014ed9b73903d3a07dd344b Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Tue, 10 Mar 2026 14:56:26 +0100 Subject: [PATCH 4/7] tls13_hrr_then_tls12_second_client_hello: Various improvements Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.function | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index a42ff8b964..b3c34aeac0 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -6026,7 +6026,7 @@ void tls13_hrr_then_tls12_second_client_hello() /* * Prepare for handshake with the ticket. */ - /* Remove the group SECP256R1 fron the list of groups supported by the + /* Remove the group SECP256R1 from the list of groups supported by the * server such that it sends an HRR in response to the ClientHello. */ server_options.group_list = group_list + 1; @@ -6055,7 +6055,7 @@ void tls13_hrr_then_tls12_second_client_hello() /* * Progress the handshake up to the point where the server has sent the - * HRR and the client as received and processed the server HRR but not + * HRR and the client has received and processed the server HRR but not * written the second ClientHello in response to the HRR. */ ret = mbedtls_test_move_handshake_to_state( @@ -6083,14 +6083,12 @@ void tls13_hrr_then_tls12_second_client_hello() */ client_ep.ssl.tls_version = MBEDTLS_SSL_VERSION_TLS1_2; - mbedtls_ssl_conf_min_tls_version((mbedtls_ssl_config *) client_ep.ssl.conf, - MBEDTLS_SSL_VERSION_TLS1_2); - mbedtls_ssl_conf_max_tls_version((mbedtls_ssl_config *) client_ep.ssl.conf, - MBEDTLS_SSL_VERSION_TLS1_2); - mbedtls_ssl_conf_ciphersuites((mbedtls_ssl_config *) client_ep.ssl.conf, - tls12_ciphersuite_list); + mbedtls_ssl_conf_min_tls_version(&client_ep.conf, MBEDTLS_SSL_VERSION_TLS1_2); + mbedtls_ssl_conf_max_tls_version(&client_ep.conf, MBEDTLS_SSL_VERSION_TLS1_2); + mbedtls_ssl_conf_ciphersuites(&client_ep.conf, tls12_ciphersuite_list); ret = mbedtls_ssl_session_reset(&(client_ep.ssl)); + TEST_EQUAL(ret, 0); /* * Restart and try to complete the handshake on server side which is @@ -6113,6 +6111,7 @@ exit: mbedtls_test_free_handshake_options(&client_options); mbedtls_test_free_handshake_options(&server_options); mbedtls_ssl_session_free(&saved_session); + mbedtls_debug_set_threshold(0); PSA_DONE(); } /* END_CASE */ From 139ac457ab92d56488d3619a7728d57830b4ebf0 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Tue, 10 Mar 2026 15:40:00 +0100 Subject: [PATCH 5/7] tls13_hrr_then_tls12_second_client_hello: Improve some comments Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.function | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index b3c34aeac0..c039b95c26 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -6027,7 +6027,8 @@ void tls13_hrr_then_tls12_second_client_hello() * Prepare for handshake with the ticket. */ /* Remove the group SECP256R1 from the list of groups supported by the - * server such that it sends an HRR in response to the ClientHello. + * server. Since it is the client's preferred group, the client will + * send a key share only for SECP256R1, forcing the server to send a HRR. */ server_options.group_list = group_list + 1; @@ -6078,10 +6079,12 @@ void tls13_hrr_then_tls12_second_client_hello() #endif /* - * Reset the client and force it to TLS 1.2 so that it sends a TLS 1.2 - * ClientHello. + * The client has just received the server's HRR and is expected to send a + * second ClientHello. Instead of sending a compliant second TLS 1.3 + * ClientHello, we want it to send a TLS 1.2-only ClientHello. To achieve + * this, we reset the client with a TLS 1.2-only configuration before + * resuming the handshake with the server. */ - client_ep.ssl.tls_version = MBEDTLS_SSL_VERSION_TLS1_2; mbedtls_ssl_conf_min_tls_version(&client_ep.conf, MBEDTLS_SSL_VERSION_TLS1_2); mbedtls_ssl_conf_max_tls_version(&client_ep.conf, MBEDTLS_SSL_VERSION_TLS1_2); From 759895e7df1b108ed640f6f5b9527bf10cb06e66 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Tue, 10 Mar 2026 16:16:19 +0100 Subject: [PATCH 6/7] tls13_hrr_then_tls12_second_client_hello: Improve client and server state checks 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 c039b95c26..8c57ec1b6e 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -6063,11 +6063,13 @@ void tls13_hrr_then_tls12_second_client_hello() &(server_ep.ssl), &(client_ep.ssl), MBEDTLS_SSL_HELLO_RETRY_REQUEST); TEST_EQUAL(ret, 0); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); ret = mbedtls_test_move_handshake_to_state( &(client_ep.ssl), &(server_ep.ssl), MBEDTLS_SSL_CLIENT_HELLO); TEST_EQUAL(ret, 0); + TEST_EQUAL(server_ep.ssl.state, MBEDTLS_SSL_CLIENT_HELLO); #if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE) /* If the compatibility mode is enabled, filter the dummy change_cipher_spec From 622b69d1d059d5e5b6dd5792cf8402f22908baab Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Tue, 10 Mar 2026 17:01:50 +0100 Subject: [PATCH 7/7] Add change log Signed-off-by: Ronald Cron --- ChangeLog.d/tls12-2nd-client-hello.txt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 ChangeLog.d/tls12-2nd-client-hello.txt diff --git a/ChangeLog.d/tls12-2nd-client-hello.txt b/ChangeLog.d/tls12-2nd-client-hello.txt new file mode 100644 index 0000000000..7513e0b945 --- /dev/null +++ b/ChangeLog.d/tls12-2nd-client-hello.txt @@ -0,0 +1,9 @@ +Security + * Fixed an issue in TLS 1.3 server handling of the second ClientHello, after + sending a HelloRetryRequest message. A man-in-the-middle attacker could + force a TLS 1.3 session resumption using a ticket to fall back to an + unintended TLS 1.2 session resumption with an all-zero master secret. + This could result in client authentication being bypassed and allow client + impersonation. + Found and reported by Jaehun Lee, Pohang University of Science and + Technology (POSTECH).