From 24d6f80fd19cd237952e7ffd629d53dc30540ffc Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Tue, 2 Jun 2026 14:48:54 +0100 Subject: [PATCH] test_suite_ssl: Added tls13_duplicate_last_extension Signed-off-by: Minos Galanakis --- tests/suites/test_suite_ssl.function | 121 +++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 5a61ab684b..71317c490c 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -248,6 +248,111 @@ static void simulate_badmac_seen_on(mbedtls_test_ssl_endpoint *client, } } #endif +#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_SSL_PROTO_TLS1_3) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_2) && defined(MBEDTLS_SSL_CLI_C) && \ + defined(MBEDTLS_SSL_SRV_C) && \ + defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED) && \ + defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED) && \ + defined(MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE) && \ + defined(PSA_WANT_ECC_SECP_R1_384) +static int tls13_duplicate_last_extension(mbedtls_ssl_context *ssl, + unsigned int hs_type, + unsigned char *buf, + size_t buf_len) +{ + unsigned char *p; + unsigned char *extensions_len_p; + unsigned char *extensions_end = buf + buf_len; + unsigned char *last_ext = NULL; + unsigned char *content_end; + unsigned char *input_buf_end; + size_t extensions_len; + size_t last_ext_len = 0; + + TEST_ASSERT(ssl != NULL); + TEST_ASSERT(buf != NULL); + TEST_EQUAL(ssl->in_msgtype, MBEDTLS_SSL_MSG_HANDSHAKE); + TEST_EQUAL(ssl->in_msg[0], hs_type); + TEST_ASSERT(buf == ssl->in_msg + 4); + TEST_EQUAL(buf_len, ssl->in_hslen - 4); + + /* The tests fetch a syntactically valid Hello message generated by Mbed TLS + * and only need to locate its final extensions vector. Keep this parser + * narrow: skip the known prefix for the selected Hello type. */ + p = buf; + + if (hs_type == MBEDTLS_SSL_HS_CLIENT_HELLO) { + p += 2 + MBEDTLS_CLIENT_HELLO_RANDOM_LEN; + p += 1 + p[0]; + p += 2 + MBEDTLS_GET_UINT16_BE(p, 0); + p += 1 + p[0]; + } else { + p += 2 + MBEDTLS_SERVER_HELLO_RANDOM_LEN; + p += 1 + p[0]; + p += 3; + } + + TEST_LE_U((size_t) (p - buf) + 2, buf_len); + extensions_len_p = p; + extensions_len = MBEDTLS_GET_UINT16_BE(extensions_len_p, 0); + p += 2; + /* In TLS 1.3 ClientHello and ServerHello, extensions are the last field. */ + TEST_ASSERT(p + extensions_len == extensions_end); + + /* Extension data is variable-length, so walk the list to identify one + * complete extension. Duplicating the last one keeps the malformed message + * simple: append a well-formed extension entry to the existing vector. */ + while (p < extensions_end) { + TEST_LE_U(4, (size_t) (extensions_end - p)); + + last_ext = p; + last_ext_len = 4 + MBEDTLS_GET_UINT16_BE(p, 2); + + TEST_LE_U(last_ext_len, (size_t) (extensions_end - p)); + + p += last_ext_len; + } + + TEST_ASSERT(last_ext != NULL); + TEST_LE_U(ssl->in_hslen + last_ext_len, 0xffffffu); + TEST_LE_U(ssl->in_msglen + last_ext_len, 0xffffu); + TEST_LE_U(extensions_len + last_ext_len, 0xffffu); + + content_end = ssl->in_msg + ssl->in_msglen; +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + input_buf_end = ssl->in_buf + ssl->in_buf_len; +#else + input_buf_end = ssl->in_buf + MBEDTLS_SSL_IN_BUFFER_LEN; +#endif + TEST_LE_U((size_t) (content_end - ssl->in_buf) + last_ext_len, + (size_t) (input_buf_end - ssl->in_buf)); + + /* The fetched message is kept for the next handshake step. Patch both the + * wire-format lengths and ssl's in-memory length fields so the normal + * parser sees the appended duplicate extension. */ + memmove(extensions_end + last_ext_len, extensions_end, + content_end - extensions_end); + memcpy(extensions_end, last_ext, last_ext_len); + + ssl->in_hslen += last_ext_len; + ssl->in_msglen += last_ext_len; + + MBEDTLS_PUT_UINT24_BE(ssl->in_hslen - 4, ssl->in_msg, 1); + MBEDTLS_PUT_UINT16_BE(ssl->in_msglen, ssl->in_len, 0); + MBEDTLS_PUT_UINT16_BE(extensions_len + last_ext_len, + extensions_len_p, 0); + + return 0; + +exit: + return -1; +} +#endif /* MBEDTLS_TEST_HOOKS && MBEDTLS_SSL_PROTO_TLS1_3 && + * !MBEDTLS_SSL_PROTO_TLS1_2 && MBEDTLS_SSL_CLI_C && + * MBEDTLS_SSL_SRV_C && MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED && + * MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED && + * MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE && + * PSA_WANT_ECC_SECP_R1_384 */ typedef enum { RECOMBINE_NOMINAL, /* param: ignored */ @@ -4369,6 +4474,14 @@ void tls13_client_rejects_extension_duplicate() &buf, &buf_len); TEST_EQUAL(ret, 0); client_ep.ssl.keep_current_message = 1; + + ret = tls13_duplicate_last_extension( + &(client_ep.ssl), MBEDTLS_SSL_HS_SERVER_HELLO, buf, buf_len); + TEST_EQUAL(ret, 0); + + ret = mbedtls_ssl_handshake_step(&(client_ep.ssl)); + TEST_EQUAL(ret, MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER); + break; } exit: @@ -4432,6 +4545,14 @@ void tls13_server_rejects_extension_duplicate() &buf, &buf_len); TEST_EQUAL(ret, 0); server_ep.ssl.keep_current_message = 1; + + ret = tls13_duplicate_last_extension( + &(server_ep.ssl), MBEDTLS_SSL_HS_CLIENT_HELLO, buf, buf_len); + TEST_EQUAL(ret, 0); + + ret = mbedtls_ssl_handshake_step(&(server_ep.ssl)); + TEST_EQUAL(ret, MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER); + break; } exit: