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. 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 078daea352..abb8b4f3e4 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -50,20 +50,55 @@ int mbedtls_ssl_tls13_fetch_handshake_msg(mbedtls_ssl_context *ssl, unsigned char **buf, size_t *buf_len) { - int ret; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + int require_record_boundary; - if ((ret = mbedtls_ssl_read_record(ssl, 0)) != 0) { - MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_read_record", ret); - goto cleanup; + /* 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: + /* + * 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; } + ret = mbedtls_ssl_read_record(ssl, 0); + if (ret != 0) { + MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_read_record", ret); + goto error; + } + + ret = MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; if (ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE || 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; } /* @@ -73,11 +108,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; } diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index dbe0dfe44c..a08bb2b961 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3586,3 +3586,25 @@ 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 + +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 alignment enforcement +tls13_record_boundary_alignment:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_HS_SERVER_HELLO + +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 alignment enforcement +tls13_record_boundary_alignment:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_HS_FINISHED + +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 diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index aba395a8ce..f655b1cf90 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 @@ -6778,3 +6823,315 @@ 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. */ + 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, + 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 */ + ret = mbedtls_test_move_handshake_to_state(&(server_ep.ssl), + &(client_ep.ssl), + MBEDTLS_SSL_HANDSHAKE_OVER); + /* + * 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); + 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 */ + +/* 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; + 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); + + 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; + unsigned char additional_empty_hs_msg[4] = { 0, 0, 0, 0 }; + + 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; + additional_empty_hs_msg[0] = MBEDTLS_SSL_HS_CERTIFICATE; + 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; + additional_empty_hs_msg[0] = MBEDTLS_SSL_HS_ENCRYPTED_EXTENSIONS; + 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; + } else { + 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; + + +#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; + 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; + ret = mbedtls_test_get_tls13_ticket(&client_options, &server_options, + &saved_session); + TEST_EQUAL(ret, 0); + break; +#endif + + default: + TEST_FAIL("Handshake message type not supported"); + } + + if (endpoint == MBEDTLS_SSL_IS_CLIENT) { + 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, + &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); + + 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. + */ + 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) { + /* + * 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(additional_empty_hs_msg); + } 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, 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(additional_empty_hs_msg)); + 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); + mbedtls_ssl_session_free(&saved_session); + PSA_DONE(); +} +/* END_CASE */