diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index 693edc7b0b..fdf86343e5 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -1380,6 +1380,7 @@ static int ssl_tls13_parse_client_hello(mbedtls_ssl_context *ssl, } if (ret == 0) { + MBEDTLS_SSL_DEBUG_MSG(2, ("no supported_versions extension")); return SSL_CLIENT_HELLO_TLS1_2; } @@ -1401,6 +1402,7 @@ static int ssl_tls13_parse_client_hello(mbedtls_ssl_context *ssl, * the TLS version to negotiate. */ if (MBEDTLS_SSL_VERSION_TLS1_2 == ret) { + MBEDTLS_SSL_DEBUG_MSG(2, ("supported_versions without 1.3")); return SSL_CLIENT_HELLO_TLS1_2; } } @@ -1985,6 +1987,7 @@ static int ssl_tls13_process_client_hello(mbedtls_ssl_context *ssl) } ssl->keep_current_message = 1; ssl->tls_version = MBEDTLS_SSL_VERSION_TLS1_2; + MBEDTLS_SSL_DEBUG_MSG(1, ("non-1.3 ClientHello left for later processing")); return 0; } diff --git a/tests/src/test_helpers/ssl_helpers.c b/tests/src/test_helpers/ssl_helpers.c index 3cb6175b98..578b2eace9 100644 --- a/tests/src/test_helpers/ssl_helpers.c +++ b/tests/src/test_helpers/ssl_helpers.c @@ -28,9 +28,22 @@ void mbedtls_test_ssl_log_analyzer(void *ctx, int level, { mbedtls_test_ssl_log_pattern *p = (mbedtls_test_ssl_log_pattern *) ctx; +/* Change 0 to 1 for debugging of test cases that use this function. */ +#if 0 + const char *q, *basename; + /* Extract basename from file */ + for (q = basename = file; *q != '\0'; q++) { + if (*q == '/' || *q == '\\') { + basename = q + 1; + } + } + printf("%s:%04d: |%d| %s", + basename, line, level, str); +#else (void) level; (void) line; (void) file; +#endif if (NULL != p && NULL != p->pattern && diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index b6a843b77d..81cf5bdf0e 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3445,3 +3445,32 @@ tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:3:3 TLS 1.3 srv, max early data size, HRR, 98, wsz=49 tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:97:0 + +# 1.2 minimal ClientHello breakdown: +# 160303rlrl - record header, 2-byte record contents len +# 01hlhlhl - handshake header, 3-byte handshake message len +# 0303 - protocol version: 1.2 +# 0123456789abcdef (repeated, 4 times total) - 32-byte "random" +# 00 - session ID (empty) +# 0002cvcv - ciphersuite list: 2-byte len + list of 2-byte values (see below) +# 0100 - compression methods: 1-byte len then "null" (only legal value now) +# [then end, or extensions] +# elel - 2-byte extensions length +# ... +# +# Note: currently our TLS "1.3 or 1.2" code requires extension length to be +# present even it it's 0. This is not strictly compliant but doesn't matter +# much in practice as these days everyone wants to use signature_algorithms +# (for hashes better than SHA-1), secure_renego (even if you have renego +# disabled), and most people want either ECC or PSK related extensions. +# +# Note: cccc is currently not assigned, so can be used get a consistent +# "no matching ciphersuite" behaviour regardless of the configuration. +# 002f is MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA, MTI in 1.2, but removed in 4.0. +Inject ClientHello - TLS 1.2 good (for reference) +depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_KEY_EXCHANGE_RSA_ENABLED:MBEDTLS_SSL_HAVE_AES:MBEDTLS_MD_CAN_SHA1:MBEDTLS_SSL_HAVE_CBC +inject_client_content_on_the_wire:MBEDTLS_SSL_CLIENT_HELLO:"160303002f0100002b03030123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef000002002f01000000":"<= parse client hello":0 + +Inject ClientHello - TLS 1.2 unknown ciphersuite (for reference) +depends_on:MBEDTLS_SSL_PROTO_TLS1_2 +inject_client_content_on_the_wire:MBEDTLS_SSL_CLIENT_HELLO:"160303002f0100002b03030123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef000002cccc01000000":"got no ciphersuites in common":MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 10e10ba632..34671c7045 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -5037,3 +5037,75 @@ exit: PSA_DONE(); } /* END_CASE */ + +/* BEGIN_CASE */ +void inject_client_content_on_the_wire(int state, data_t *hello, char *log_pattern, + int expected_ret) +{ + /* This function allows us to inject content at a specific state + * in the handshake, or when it's completed. The content is injected + * on the mock TCP socket, as if we were an active network attacker. + * + * This function is suitable to inject: + * - crafted records, at any point; + * - valid records that contain crafted handshake messages, but only + * when the traffic is still unprotected (for TLS 1.2 that's most of the + * handshake, for TLS 1.3 that's only the Hello messages); + * - handshake messages that are fragmented in a specific way, + * under the same conditions as above. + */ + enum { BUFFSIZE = 16384 }; + mbedtls_test_ssl_endpoint server, client; + mbedtls_platform_zeroize(&server, sizeof(server)); + mbedtls_platform_zeroize(&client, sizeof(client)); + mbedtls_test_handshake_test_options options; + mbedtls_test_init_handshake_options(&options); + mbedtls_test_ssl_log_pattern srv_pattern; + memset(&srv_pattern, 0, sizeof(srv_pattern)); + int ret = -1; + + PSA_INIT(); + + srv_pattern.pattern = log_pattern; + options.srv_log_obj = &srv_pattern; + options.srv_log_fun = mbedtls_test_ssl_log_analyzer; + mbedtls_debug_set_threshold(3); + + ret = mbedtls_test_ssl_endpoint_init(&server, MBEDTLS_SSL_IS_SERVER, + &options, NULL, NULL, NULL); + TEST_EQUAL(ret, 0); + + ret = mbedtls_test_ssl_endpoint_init(&client, MBEDTLS_SSL_IS_CLIENT, + &options, NULL, NULL, NULL); + TEST_EQUAL(ret, 0); + + ret = mbedtls_test_mock_socket_connect(&server.socket, &client.socket, + BUFFSIZE); + TEST_EQUAL(ret, 0); + + /* Make the server move to the required state */ + ret = mbedtls_test_move_handshake_to_state(&client.ssl, &server.ssl, state); + TEST_EQUAL(ret, 0); + + /* Send the crafted message */ + ret = mbedtls_test_mock_tcp_send_b(&client.socket, hello->x, hello->len); + TEST_ASSERT(ret >= 0 && (size_t) ret == hello->len); + + /* Have the server process it. + * Need the loop because a server that support 1.3 and 1.2 + * will process a 1.2 ClientHello in two steps. + */ + do { + ret = mbedtls_ssl_handshake_step(&server.ssl); + } while (ret == 0 && server.ssl.state == state); + TEST_EQUAL(ret, expected_ret); + TEST_EQUAL(srv_pattern.counter, 1); + +exit: + mbedtls_test_free_handshake_options(&options); + mbedtls_test_ssl_endpoint_free(&server, NULL); + mbedtls_test_ssl_endpoint_free(&client, NULL); + mbedtls_debug_set_threshold(0); + PSA_DONE(); +} +/* END_CASE */