From 5d3036e6d5f8269cb7c77b23128ff3be289e0d72 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Fri, 23 Feb 2024 07:43:45 +0100 Subject: [PATCH 01/20] tests: ssl: Add max_early_data_size option Signed-off-by: Ronald Cron --- tests/include/test/ssl_helpers.h | 1 + tests/src/test_helpers/ssl_helpers.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/tests/include/test/ssl_helpers.h b/tests/include/test/ssl_helpers.h index 5b071f75aa..71259d66f5 100644 --- a/tests/include/test/ssl_helpers.h +++ b/tests/include/test/ssl_helpers.h @@ -114,6 +114,7 @@ typedef struct mbedtls_test_handshake_test_options { void (*cli_log_fun)(void *, int, const char *, int, const char *); int resize_buffers; int early_data; + int max_early_data_size; #if defined(MBEDTLS_SSL_CACHE_C) mbedtls_ssl_cache_context *cache; #endif diff --git a/tests/src/test_helpers/ssl_helpers.c b/tests/src/test_helpers/ssl_helpers.c index 7a28bd8795..bf29b474a7 100644 --- a/tests/src/test_helpers/ssl_helpers.c +++ b/tests/src/test_helpers/ssl_helpers.c @@ -68,6 +68,7 @@ void mbedtls_test_init_handshake_options( opts->legacy_renegotiation = MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION; opts->resize_buffers = 1; opts->early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED; + opts->max_early_data_size = -1; #if defined(MBEDTLS_SSL_CACHE_C) TEST_CALLOC(opts->cache, 1); mbedtls_ssl_cache_init(opts->cache); @@ -815,6 +816,13 @@ int mbedtls_test_ssl_endpoint_init( #if defined(MBEDTLS_SSL_EARLY_DATA) mbedtls_ssl_conf_early_data(&(ep->conf), options->early_data); +#if defined(MBEDTLS_SSL_SRV_C) + if (endpoint_type == MBEDTLS_SSL_IS_SERVER && + (options->max_early_data_size >= 0)) { + mbedtls_ssl_conf_max_early_data_size(&(ep->conf), + options->max_early_data_size); + } +#endif #endif #if defined(MBEDTLS_SSL_CACHE_C) && defined(MBEDTLS_SSL_SRV_C) From 26a9811027cef5a8e87d033f56454a8dfe934d7c Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Fri, 23 Feb 2024 08:23:40 +0100 Subject: [PATCH 02/20] ssl: Add early_data_count field Signed-off-by: Ronald Cron --- include/mbedtls/ssl.h | 5 ++++- library/ssl_tls.c | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 78395d2a67..15bd6fd7d3 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -1859,7 +1859,8 @@ struct mbedtls_ssl_context { * within a single datagram. */ #endif /* MBEDTLS_SSL_PROTO_DTLS */ -#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_SRV_C) +#if defined(MBEDTLS_SSL_EARLY_DATA) +#if defined(MBEDTLS_SSL_SRV_C) /* * One of: * MBEDTLS_SSL_EARLY_DATA_NO_DISCARD @@ -1868,6 +1869,8 @@ struct mbedtls_ssl_context { */ uint8_t MBEDTLS_PRIVATE(discard_early_data_record); #endif + uint32_t MBEDTLS_PRIVATE(early_data_count); /*!< Number of received/written early data bytes */ +#endif /* MBEDTLS_SSL_EARLY_DATA */ /* * Record layer (outgoing data) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 5b0a4b97ab..ee72179997 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -1105,6 +1105,7 @@ static int ssl_handshake_init(mbedtls_ssl_context *ssl) #if defined(MBEDTLS_SSL_SRV_C) ssl->discard_early_data_record = MBEDTLS_SSL_EARLY_DATA_NO_DISCARD; #endif + ssl->early_data_count = 0; #endif /* MBEDTLS_SSL_EARLY_DATA */ /* Initialize structures */ From c2865197478cddf22572c774481fb90db2c2f461 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Wed, 7 Feb 2024 14:01:03 +0100 Subject: [PATCH 03/20] tls13: srv: Do not forget to include max_early_data_size in the ticket Signed-off-by: Ronald Cron --- library/ssl_tls13_server.c | 1 + 1 file changed, 1 insertion(+) diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index 3a968aa964..2391915357 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -3141,6 +3141,7 @@ static int ssl_tls13_prepare_new_session_ticket(mbedtls_ssl_context *ssl, ssl->conf->max_early_data_size > 0) { mbedtls_ssl_tls13_session_set_ticket_flags( session, MBEDTLS_SSL_TLS1_3_TICKET_ALLOW_EARLY_DATA); + session->max_early_data_size = ssl->conf->max_early_data_size; } #endif /* MBEDTLS_SSL_EARLY_DATA */ From 85718043820d3dd9bd8922e269332430278b820c Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Thu, 22 Feb 2024 10:22:09 +0100 Subject: [PATCH 04/20] tls13: srv: Enforce maximum size of early data Signed-off-by: Ronald Cron --- library/ssl_misc.h | 3 +++ library/ssl_tls13_generic.c | 41 +++++++++++++++++++++++++++++++++++++ library/ssl_tls13_server.c | 13 +++++------- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/library/ssl_misc.h b/library/ssl_misc.h index d8844fcc32..883b98828d 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -2150,6 +2150,9 @@ int mbedtls_ssl_tls13_write_early_data_ext(mbedtls_ssl_context *ssl, unsigned char *buf, const unsigned char *end, size_t *out_len); + +int mbedtls_ssl_tls13_check_early_data_len(mbedtls_ssl_context *ssl, + size_t early_data_len); #endif /* MBEDTLS_SSL_EARLY_DATA */ #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */ diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index bc737047a4..a3b4d355b4 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -1454,6 +1454,47 @@ int mbedtls_ssl_tls13_write_early_data_ext(mbedtls_ssl_context *ssl, return 0; } + +#if defined(MBEDTLS_SSL_SRV_C) +int mbedtls_ssl_tls13_check_early_data_len(mbedtls_ssl_context *ssl, + size_t early_data_len) +{ + uint32_t uint32_early_data_len = (uint32_t) early_data_len; + + /* + * This function should be called only while an handshake is in progress + * and thus a session under negotiation. Add a sanity check to detect a + * misuse. + */ + if (ssl->session_negotiate == NULL) { + return MBEDTLS_ERR_SSL_INTERNAL_ERROR; + } + + /* RFC 8446 section 4.6.1 + * + * A server receiving more than max_early_data_size bytes of 0-RTT data + * SHOULD terminate the connection with an "unexpected_message" alert. + */ + if (uint32_early_data_len > + (ssl->session_negotiate->max_early_data_size - + ssl->early_data_count)) { + + MBEDTLS_SSL_DEBUG_MSG( + 2, ("EarlyData: Too many early data received, %u > %u", + ssl->early_data_count + uint32_early_data_len, + ssl->session_negotiate->max_early_data_size)); + + MBEDTLS_SSL_PEND_FATAL_ALERT( + MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE); + return MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; + } + + ssl->early_data_count += uint32_early_data_len; + + return 0; +} +#endif /* MBEDTLS_SSL_SRV_C */ #endif /* MBEDTLS_SSL_EARLY_DATA */ /* Reset SSL context and update hash for handling HRR. diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index 2391915357..449fa380f1 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -2913,17 +2913,14 @@ static int ssl_tls13_end_of_early_data_coordinate(mbedtls_ssl_context *ssl) } if (ssl->in_msgtype == MBEDTLS_SSL_MSG_APPLICATION_DATA) { - MBEDTLS_SSL_DEBUG_MSG(3, ("Received early data")); - /* RFC 8446 section 4.6.1 - * - * A server receiving more than max_early_data_size bytes of 0-RTT data - * SHOULD terminate the connection with an "unexpected_message" alert. - * - * TODO: Add received data size check here. - */ if (ssl->in_offt == NULL) { + MBEDTLS_SSL_DEBUG_MSG(3, ("Received early data")); /* Set the reading pointer */ ssl->in_offt = ssl->in_msg; + ret = mbedtls_ssl_tls13_check_early_data_len(ssl, ssl->in_msglen); + if (ret != 0) { + return ret; + } } return SSL_GOT_EARLY_DATA; } From 2160bfe4e23af0c290c23a0c7d83637fb7adb658 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Wed, 7 Feb 2024 08:04:07 +0100 Subject: [PATCH 05/20] tests: ssl: Test enforcement of maximum early data size Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.data | 9 ++ tests/suites/test_suite_ssl.function | 163 +++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 385682ae12..1f705382b0 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3309,3 +3309,12 @@ tls13_write_early_data:TEST_EARLY_DATA_SERVER_REJECTS TLS 1.3 write early data, hello retry request tls13_write_early_data:TEST_EARLY_DATA_HRR + +TLS 1.3 srv, max early data size, default +tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:-1 + +TLS 1.3 srv, max early data size, max=3 (small but !0) +tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:3 + +TLS 1.3 srv, max early data size, max=97 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:97 diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index d327828bcd..1408361795 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4448,3 +4448,166 @@ exit: PSA_DONE(); } /* END_CASE */ + +/* + * The !MBEDTLS_SSL_PROTO_TLS1_2 dependency of tls13_early_data() below is + * a temporary workaround to not run the test in Windows-2013 where there is + * an issue with mbedtls_vsnprintf(). + */ +/* BEGIN_CASE depends_on:!MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_EARLY_DATA:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_DEBUG_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_MD_CAN_SHA256:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_ECP_HAVE_SECP384R1:MBEDTLS_PK_CAN_ECDSA_VERIFY:MBEDTLS_SSL_SESSION_TICKETS */ +void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg) +{ + 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; + mbedtls_ssl_session saved_session; + mbedtls_test_ssl_log_pattern server_pattern = { NULL, 0 }; + char pattern[128]; + unsigned char buf_write[64]; + size_t early_data_len = sizeof(buf_write); + uint32_t written_early_data_size = 0; + int write_early_data_flag = 1; + uint32_t max_early_data_size; + + mbedtls_platform_zeroize(&client_ep, sizeof(client_ep)); + mbedtls_platform_zeroize(&server_ep, sizeof(server_ep)); + 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.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED; + server_options.pk_alg = MBEDTLS_PK_ECDSA; + server_options.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED; + server_options.max_early_data_size = max_early_data_size_arg; + + ret = mbedtls_test_get_tls13_ticket(&client_options, &server_options, + &saved_session); + TEST_EQUAL(ret, 0); + + /* + * Prepare for handshake with the ticket. + */ + server_options.srv_log_fun = mbedtls_test_ssl_log_analyzer; + server_options.srv_log_obj = &server_pattern; + server_pattern.pattern = pattern; + + switch (scenario) { + case TEST_EARLY_DATA_ACCEPTED: + break; + + default: + TEST_FAIL("Unknown scenario."); + } + + ret = mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT, + &client_options, NULL, NULL, NULL); + TEST_EQUAL(ret, 0); + + ret = mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER, + &server_options, NULL, NULL, NULL); + 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); + + max_early_data_size = saved_session.max_early_data_size; + + ret = mbedtls_ssl_set_session(&(client_ep.ssl), &saved_session); + TEST_EQUAL(ret, 0); + + /* + * Start an handshake based on the ticket up to the point where early data + * can be sent from client side. Then send in a loop as much early data as + * possible without going over the maximum permitted size for the ticket. + * Finally, do a last writting to go past that maximum permitted size and + * check that we detect it. + */ + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + &(client_ep.ssl), &(server_ep.ssl), + MBEDTLS_SSL_SERVER_HELLO), 0); + + TEST_ASSERT(client_ep.ssl.early_data_status != + MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT); + + ret = mbedtls_ssl_handshake(&(server_ep.ssl)); + TEST_EQUAL(ret, MBEDTLS_ERR_SSL_WANT_READ); + + while (write_early_data_flag) { + unsigned char buf_read[23]; + uint32_t read_early_data_size = 0; + uint32_t remaining = max_early_data_size - + server_ep.ssl.early_data_count; + + /* Reach maximum early data exactly */ + if (early_data_len >= remaining) { + early_data_len = remaining; + write_early_data_flag = 0; + } + + for (size_t i = 0; i < early_data_len; i++) { + buf_write[i] = (unsigned char) (written_early_data_size + i); + } + + ret = write_early_data(&(client_ep.ssl), buf_write, early_data_len); + TEST_EQUAL(ret, early_data_len); + written_early_data_size += early_data_len; + + switch (scenario) { + case TEST_EARLY_DATA_ACCEPTED: + while (read_early_data_size < early_data_len) { + ret = mbedtls_ssl_handshake(&(server_ep.ssl)); + TEST_EQUAL(ret, MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA); + + ret = mbedtls_ssl_read_early_data(&(server_ep.ssl), + buf_read, + sizeof(buf_read)); + TEST_ASSERT(ret > 0); + + TEST_MEMORY_COMPARE(buf_read, ret, + buf_write + read_early_data_size, ret); + read_early_data_size += ret; + + TEST_EQUAL(server_ep.ssl.early_data_count, + written_early_data_size); + } + break; + } + TEST_ASSERT(server_ep.ssl.early_data_count <= max_early_data_size); + } + + mbedtls_debug_set_threshold(3); + ret = write_early_data(&(client_ep.ssl), buf_write, 1); + TEST_EQUAL(ret, 1); + + ret = mbedtls_snprintf(pattern, sizeof(pattern), + "EarlyData: Too many early data received"); + TEST_ASSERT(ret < (int) sizeof(pattern)); + + ret = mbedtls_ssl_handshake(&(server_ep.ssl)); + TEST_EQUAL(ret, MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE); + TEST_EQUAL(server_pattern.counter, 1); + +exit: + mbedtls_test_ssl_endpoint_free(&client_ep, NULL); + mbedtls_test_ssl_endpoint_free(&server_ep, NULL); + 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 919e596c05c14f7754655b970c5fab47824a2bd5 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Thu, 8 Feb 2024 15:48:29 +0100 Subject: [PATCH 06/20] Enforce maximum size of early data when rejected Signed-off-by: Ronald Cron --- library/ssl_msg.c | 6 +++- tests/suites/test_suite_ssl.data | 9 ++++++ tests/suites/test_suite_ssl.function | 45 ++++++++++++++++++++++++++-- 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 2a6d4341be..6c508d6234 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -4005,7 +4005,11 @@ static int ssl_prepare_record_content(mbedtls_ssl_context *ssl, MBEDTLS_SSL_EARLY_DATA_TRY_TO_DEPROTECT_AND_DISCARD)) { MBEDTLS_SSL_DEBUG_MSG( 3, ("EarlyData: deprotect and discard app data records.")); - /* TODO: Add max_early_data_size check here, see issue 6347 */ + + ret = mbedtls_ssl_tls13_check_early_data_len(ssl, rec->data_len); + if (ret != 0) { + return ret; + } ret = MBEDTLS_ERR_SSL_CONTINUE_PROCESSING; } #endif /* MBEDTLS_SSL_EARLY_DATA && MBEDTLS_SSL_SRV_C */ diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 1f705382b0..6fb3d837c0 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3318,3 +3318,12 @@ tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:3 TLS 1.3 srv, max early data size, max=97 tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:97 + +TLS 1.3 srv, max early data size, server rejects, default +tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:-1 + +TLS 1.3 srv, max early data size, server rejects, max=3 (very small) +tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:3 + +TLS 1.3 srv, max early data size, server rejects, max=97 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:97 diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 1408361795..0c1d606909 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4466,6 +4466,7 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg) char pattern[128]; unsigned char buf_write[64]; size_t early_data_len = sizeof(buf_write); + uint32_t expended_early_data_len = 0; uint32_t written_early_data_size = 0; int write_early_data_flag = 1; uint32_t max_early_data_size; @@ -4503,6 +4504,14 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg) case TEST_EARLY_DATA_ACCEPTED: break; + case TEST_EARLY_DATA_SERVER_REJECTS: + server_options.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED; + ret = mbedtls_snprintf(pattern, sizeof(pattern), + "EarlyData: deprotect and discard app data records."); + TEST_ASSERT(ret < (int) sizeof(pattern)); + mbedtls_debug_set_threshold(3); + break; + default: TEST_FAIL("Unknown scenario."); } @@ -4552,7 +4561,7 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg) uint32_t remaining = max_early_data_size - server_ep.ssl.early_data_count; - /* Reach maximum early data exactly */ + /* In case of accepted early data, reach max_early_data_size exactly. */ if (early_data_len >= remaining) { early_data_len = remaining; write_early_data_flag = 0; @@ -4585,13 +4594,43 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg) written_early_data_size); } break; + + case TEST_EARLY_DATA_SERVER_REJECTS: + ret = mbedtls_ssl_handshake(&(server_ep.ssl)); + /* + * Can be the case if max_early_data_size is smaller then the + * smallest inner content or protected record. + */ + if (ret == MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE) { + /* Beyond 64 for max_early_data_size it is suspicious */ + TEST_ASSERT(max_early_data_size < 64); + goto exit; + } + + TEST_ASSERT(ret == MBEDTLS_ERR_SSL_WANT_READ); + + TEST_EQUAL(server_pattern.counter, 1); + server_pattern.counter = 0; + if (expended_early_data_len == 0) { + expended_early_data_len = server_ep.ssl.early_data_count; + } + remaining = max_early_data_size - server_ep.ssl.early_data_count; + + if (expended_early_data_len > remaining) { + write_early_data_flag = 0; + } + break; } TEST_ASSERT(server_ep.ssl.early_data_count <= max_early_data_size); } mbedtls_debug_set_threshold(3); - ret = write_early_data(&(client_ep.ssl), buf_write, 1); - TEST_EQUAL(ret, 1); + + early_data_len = (scenario == TEST_EARLY_DATA_ACCEPTED) ? + 1 : sizeof(buf_write); + + ret = write_early_data(&(client_ep.ssl), buf_write, early_data_len); + TEST_EQUAL(ret, early_data_len); ret = mbedtls_snprintf(pattern, sizeof(pattern), "EarlyData: Too many early data received"); From 01d273d31f40402dce5ec47dc43782702ad5c5c3 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Fri, 9 Feb 2024 16:17:10 +0100 Subject: [PATCH 07/20] Enforce maximum size of early data in case of HRR Signed-off-by: Ronald Cron --- library/ssl_msg.c | 7 ++++++- tests/suites/test_suite_ssl.data | 9 +++++++++ tests/suites/test_suite_ssl.function | 19 ++++++++++++++++++- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 6c508d6234..a8ff1c1a15 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -4135,7 +4135,12 @@ static int ssl_prepare_record_content(mbedtls_ssl_context *ssl, if (rec->type == MBEDTLS_SSL_MSG_APPLICATION_DATA) { MBEDTLS_SSL_DEBUG_MSG( 3, ("EarlyData: Ignore application message before 2nd ClientHello")); - /* TODO: Add max_early_data_size check here, see issue 6347 */ + + ret = mbedtls_ssl_tls13_check_early_data_len(ssl, rec->data_len); + if (ret != 0) { + return ret; + } + return MBEDTLS_ERR_SSL_CONTINUE_PROCESSING; } else if (rec->type == MBEDTLS_SSL_MSG_HANDSHAKE) { ssl->discard_early_data_record = MBEDTLS_SSL_EARLY_DATA_NO_DISCARD; diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 6fb3d837c0..03de4a99f6 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3327,3 +3327,12 @@ tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:3 TLS 1.3 srv, max early data size, server rejects, max=97 tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:97 + +TLS 1.3 srv, max early data size, HRR, default +tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:-1 + +TLS 1.3 srv, max early data size, HRR, max=3 (very small) +tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:3 + +TLS 1.3 srv, max early data size, HRR, max=97 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:97 diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 0c1d606909..fc1bc3ee85 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4463,6 +4463,11 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg) mbedtls_test_handshake_test_options server_options; mbedtls_ssl_session saved_session; mbedtls_test_ssl_log_pattern server_pattern = { NULL, 0 }; + uint16_t group_list[3] = { + MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1, + MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1, + MBEDTLS_SSL_IANA_TLS_GROUP_NONE + }; char pattern[128]; unsigned char buf_write[64]; size_t early_data_len = sizeof(buf_write); @@ -4484,8 +4489,10 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg) */ client_options.pk_alg = MBEDTLS_PK_ECDSA; + client_options.group_list = group_list; client_options.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED; server_options.pk_alg = MBEDTLS_PK_ECDSA; + server_options.group_list = group_list; server_options.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED; server_options.max_early_data_size = max_early_data_size_arg; @@ -4512,6 +4519,15 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg) mbedtls_debug_set_threshold(3); break; + case TEST_EARLY_DATA_HRR: + server_options.group_list = group_list + 1; + ret = mbedtls_snprintf( + pattern, sizeof(pattern), + "EarlyData: Ignore application message before 2nd ClientHello"); + TEST_ASSERT(ret < (int) sizeof(pattern)); + mbedtls_debug_set_threshold(3); + break; + default: TEST_FAIL("Unknown scenario."); } @@ -4595,7 +4611,8 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg) } break; - case TEST_EARLY_DATA_SERVER_REJECTS: + case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */ + case TEST_EARLY_DATA_HRR: ret = mbedtls_ssl_handshake(&(server_ep.ssl)); /* * Can be the case if max_early_data_size is smaller then the From dc81b7343f325f7e62ec038330d4f7505a37ed96 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Mon, 26 Feb 2024 15:02:26 +0100 Subject: [PATCH 08/20] tests: srv max early data size: Add reach_max test arg Add the reach_max flag argument for the test13_srv_max_early_data_size test function. Non zero value only valid in case of TEST_EARLY_DATA_ACCEPTED scenario. Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.data | 27 +++++++++++++------- tests/suites/test_suite_ssl.function | 37 ++++++++++++++++++++++------ 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 03de4a99f6..f3d9ef05b4 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3311,28 +3311,37 @@ TLS 1.3 write early data, hello retry request tls13_write_early_data:TEST_EARLY_DATA_HRR TLS 1.3 srv, max early data size, default -tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:-1 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:-1:0 + +TLS 1.3 srv, max early data size, default, reach max +tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:-1:1 TLS 1.3 srv, max early data size, max=3 (small but !0) -tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:3 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:3:0 + +TLS 1.3 srv, max early data size, max=3 (small but !0), reach max +tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:3:1 TLS 1.3 srv, max early data size, max=97 -tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:97 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:97:0 + +TLS 1.3 srv, max early data size, max=97, reach max +tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:97:1 TLS 1.3 srv, max early data size, server rejects, default -tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:-1 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:-1:0 TLS 1.3 srv, max early data size, server rejects, max=3 (very small) -tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:3 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:3:0 TLS 1.3 srv, max early data size, server rejects, max=97 -tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:97 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:97:0 TLS 1.3 srv, max early data size, HRR, default -tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:-1 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:-1:0 TLS 1.3 srv, max early data size, HRR, max=3 (very small) -tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:3 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:3:0 TLS 1.3 srv, max early data size, HRR, max=97 -tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:97 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:97:0 diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index fc1bc3ee85..5f6029e225 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4455,7 +4455,7 @@ exit: * an issue with mbedtls_vsnprintf(). */ /* BEGIN_CASE depends_on:!MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_EARLY_DATA:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_DEBUG_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_MD_CAN_SHA256:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_ECP_HAVE_SECP384R1:MBEDTLS_PK_CAN_ECDSA_VERIFY:MBEDTLS_SSL_SESSION_TICKETS */ -void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg) +void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, int reach_max) { int ret = -1; mbedtls_test_ssl_endpoint client_ep, server_ep; @@ -4470,7 +4470,7 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg) }; char pattern[128]; unsigned char buf_write[64]; - size_t early_data_len = sizeof(buf_write); + size_t early_data_len; uint32_t expended_early_data_len = 0; uint32_t written_early_data_size = 0; int write_early_data_flag = 1; @@ -4484,6 +4484,14 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg) PSA_INIT(); + /* + * Reach maximum early data size exactly option only available in case of + * TEST_EARLY_DATA_ACCEPTED scenario. + */ + if (reach_max) { + TEST_EQUAL(scenario, TEST_EARLY_DATA_ACCEPTED); + } + /* * Run first handshake to get a ticket from the server. */ @@ -4577,10 +4585,24 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg) uint32_t remaining = max_early_data_size - server_ep.ssl.early_data_count; - /* In case of accepted early data, reach max_early_data_size exactly. */ + early_data_len = sizeof(buf_write); + /* + * Adjust the length of next data to write depending on the remaining + * number of early data bytes we are allowed to write and if we want + * to reach the maximum exactly or not. + */ if (early_data_len >= remaining) { - early_data_len = remaining; - write_early_data_flag = 0; + if (reach_max) { + early_data_len = remaining; + write_early_data_flag = 0; + } else { + if (early_data_len == remaining) { + early_data_len /= 2; + } else { + early_data_len = remaining + 1; + break; + } + } } for (size_t i = 0; i < early_data_len; i++) { @@ -4643,8 +4665,9 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg) mbedtls_debug_set_threshold(3); - early_data_len = (scenario == TEST_EARLY_DATA_ACCEPTED) ? - 1 : sizeof(buf_write); + if (reach_max) { + TEST_EQUAL(server_ep.ssl.early_data_count, max_early_data_size); + } ret = write_early_data(&(client_ep.ssl), buf_write, early_data_len); TEST_EQUAL(ret, early_data_len); From 70eab45ba6c91a5a840d8beaf8d440b23dcb0867 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Mon, 26 Feb 2024 15:50:15 +0100 Subject: [PATCH 09/20] tls13: generic: Fix log Signed-off-by: Ronald Cron --- library/ssl_tls13_generic.c | 2 +- tests/suites/test_suite_ssl.function | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index a3b4d355b4..c5698f6ee4 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -1480,7 +1480,7 @@ int mbedtls_ssl_tls13_check_early_data_len(mbedtls_ssl_context *ssl, ssl->early_data_count)) { MBEDTLS_SSL_DEBUG_MSG( - 2, ("EarlyData: Too many early data received, %u > %u", + 2, ("EarlyData: Too much early data received, %u > %u", ssl->early_data_count + uint32_early_data_len, ssl->session_negotiate->max_early_data_size)); diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 5f6029e225..aca8276e6e 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4673,7 +4673,7 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, in TEST_EQUAL(ret, early_data_len); ret = mbedtls_snprintf(pattern, sizeof(pattern), - "EarlyData: Too many early data received"); + "EarlyData: Too much early data received"); TEST_ASSERT(ret < (int) sizeof(pattern)); ret = mbedtls_ssl_handshake(&(server_ep.ssl)); From 19bfe0a6310acd686cbf70b429ed80b075f9a0d1 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Mon, 26 Feb 2024 16:43:01 +0100 Subject: [PATCH 10/20] tls13: Rename early_data_count to total_early_data_size Signed-off-by: Ronald Cron --- include/mbedtls/ssl.h | 2 +- library/ssl_tls.c | 2 +- library/ssl_tls13_generic.c | 6 +++--- tests/suites/test_suite_ssl.function | 12 ++++++------ 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 15bd6fd7d3..9a66663318 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -1869,7 +1869,7 @@ struct mbedtls_ssl_context { */ uint8_t MBEDTLS_PRIVATE(discard_early_data_record); #endif - uint32_t MBEDTLS_PRIVATE(early_data_count); /*!< Number of received/written early data bytes */ + uint32_t MBEDTLS_PRIVATE(total_early_data_size); /*!< Number of received/written early data bytes */ #endif /* MBEDTLS_SSL_EARLY_DATA */ /* diff --git a/library/ssl_tls.c b/library/ssl_tls.c index ee72179997..5bedd91389 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -1105,7 +1105,7 @@ static int ssl_handshake_init(mbedtls_ssl_context *ssl) #if defined(MBEDTLS_SSL_SRV_C) ssl->discard_early_data_record = MBEDTLS_SSL_EARLY_DATA_NO_DISCARD; #endif - ssl->early_data_count = 0; + ssl->total_early_data_size = 0; #endif /* MBEDTLS_SSL_EARLY_DATA */ /* Initialize structures */ diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index c5698f6ee4..eec2bb4b75 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -1477,11 +1477,11 @@ int mbedtls_ssl_tls13_check_early_data_len(mbedtls_ssl_context *ssl, */ if (uint32_early_data_len > (ssl->session_negotiate->max_early_data_size - - ssl->early_data_count)) { + ssl->total_early_data_size)) { MBEDTLS_SSL_DEBUG_MSG( 2, ("EarlyData: Too much early data received, %u > %u", - ssl->early_data_count + uint32_early_data_len, + ssl->total_early_data_size + uint32_early_data_len, ssl->session_negotiate->max_early_data_size)); MBEDTLS_SSL_PEND_FATAL_ALERT( @@ -1490,7 +1490,7 @@ int mbedtls_ssl_tls13_check_early_data_len(mbedtls_ssl_context *ssl, return MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; } - ssl->early_data_count += uint32_early_data_len; + ssl->total_early_data_size += uint32_early_data_len; return 0; } diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index aca8276e6e..791386b276 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4583,7 +4583,7 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, in unsigned char buf_read[23]; uint32_t read_early_data_size = 0; uint32_t remaining = max_early_data_size - - server_ep.ssl.early_data_count; + server_ep.ssl.total_early_data_size; early_data_len = sizeof(buf_write); /* @@ -4628,7 +4628,7 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, in buf_write + read_early_data_size, ret); read_early_data_size += ret; - TEST_EQUAL(server_ep.ssl.early_data_count, + TEST_EQUAL(server_ep.ssl.total_early_data_size, written_early_data_size); } break; @@ -4651,22 +4651,22 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, in TEST_EQUAL(server_pattern.counter, 1); server_pattern.counter = 0; if (expended_early_data_len == 0) { - expended_early_data_len = server_ep.ssl.early_data_count; + expended_early_data_len = server_ep.ssl.total_early_data_size; } - remaining = max_early_data_size - server_ep.ssl.early_data_count; + remaining = max_early_data_size - server_ep.ssl.total_early_data_size; if (expended_early_data_len > remaining) { write_early_data_flag = 0; } break; } - TEST_ASSERT(server_ep.ssl.early_data_count <= max_early_data_size); + TEST_ASSERT(server_ep.ssl.total_early_data_size <= max_early_data_size); } mbedtls_debug_set_threshold(3); if (reach_max) { - TEST_EQUAL(server_ep.ssl.early_data_count, max_early_data_size); + TEST_EQUAL(server_ep.ssl.total_early_data_size, max_early_data_size); } ret = write_early_data(&(client_ep.ssl), buf_write, early_data_len); From 25ad10a920979c2236ca14494a055a596c21e93c Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Thu, 29 Feb 2024 00:39:23 +0100 Subject: [PATCH 11/20] tests: ssl: Improve tls13_srv_max_early_data_size() Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.data | 46 +++++++------- tests/suites/test_suite_ssl.function | 93 ++++++++++++---------------- 2 files changed, 63 insertions(+), 76 deletions(-) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index f3d9ef05b4..c0c816c2db 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3310,38 +3310,38 @@ tls13_write_early_data:TEST_EARLY_DATA_SERVER_REJECTS TLS 1.3 write early data, hello retry request tls13_write_early_data:TEST_EARLY_DATA_HRR -TLS 1.3 srv, max early data size, default -tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:-1:0 +TLS 1.3 srv, max early data size, dflt, wsz=96 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:-1:96 -TLS 1.3 srv, max early data size, default, reach max -tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:-1:1 +TLS 1.3 srv, max early data size, dflt, wsz=128 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:-1:128 -TLS 1.3 srv, max early data size, max=3 (small but !0) -tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:3:0 +TLS 1.3 srv, max early data size, 3, wsz=2 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:3:2 -TLS 1.3 srv, max early data size, max=3 (small but !0), reach max -tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:3:1 +TLS 1.3 srv, max early data size, 3, wsz=3 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:3:3 -TLS 1.3 srv, max early data size, max=97 -tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:97:0 +TLS 1.3 srv, max early data size, 98, wsz=23 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:98:23 -TLS 1.3 srv, max early data size, max=97, reach max -tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:97:1 +TLS 1.3 srv, max early data size, 98, wsz=49 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:98:49 -TLS 1.3 srv, max early data size, server rejects, default -tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:-1:0 +TLS 1.3 srv, max early data size, server rejects, dflt, wsz=128 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:-1:128 -TLS 1.3 srv, max early data size, server rejects, max=3 (very small) -tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:3:0 +TLS 1.3 srv, max early data size, server rejects, 3, wsz=3 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:3:3 -TLS 1.3 srv, max early data size, server rejects, max=97 -tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:97:0 +TLS 1.3 srv, max early data size, server rejects, 98, wsz=49 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:98:49 -TLS 1.3 srv, max early data size, HRR, default -tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:-1:0 +TLS 1.3 srv, max early data size, HRR, dflt, wsz=128 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:-1:128 -TLS 1.3 srv, max early data size, HRR, max=3 (very small) -tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:3:0 +TLS 1.3 srv, max early data size, HRR, 3, wsz=3 +tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:3:3 -TLS 1.3 srv, max early data size, HRR, max=97 +TLS 1.3 srv, max early data size, HRR, 98, wsz=49 tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:97:0 diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 791386b276..d89d8ac8b2 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4455,7 +4455,7 @@ exit: * an issue with mbedtls_vsnprintf(). */ /* BEGIN_CASE depends_on:!MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_EARLY_DATA:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_DEBUG_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_MD_CAN_SHA256:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_ECP_HAVE_SECP384R1:MBEDTLS_PK_CAN_ECDSA_VERIFY:MBEDTLS_SSL_SESSION_TICKETS */ -void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, int reach_max) +void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, int write_size_arg) { int ret = -1; mbedtls_test_ssl_endpoint client_ep, server_ep; @@ -4469,11 +4469,12 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, in MBEDTLS_SSL_IANA_TLS_GROUP_NONE }; char pattern[128]; - unsigned char buf_write[64]; - size_t early_data_len; + unsigned char *buf_write = NULL; + uint32_t write_size = (uint32_t) write_size_arg; + unsigned char *buf_read = NULL; + uint32_t read_size; uint32_t expended_early_data_len = 0; uint32_t written_early_data_size = 0; - int write_early_data_flag = 1; uint32_t max_early_data_size; mbedtls_platform_zeroize(&client_ep, sizeof(client_ep)); @@ -4481,16 +4482,16 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, in mbedtls_test_init_handshake_options(&client_options); mbedtls_test_init_handshake_options(&server_options); mbedtls_ssl_session_init(&saved_session); - - PSA_INIT(); + TEST_CALLOC(buf_write, write_size); /* - * Reach maximum early data size exactly option only available in case of - * TEST_EARLY_DATA_ACCEPTED scenario. + * Allocate a smaller buffer for early data reading to exercise the reading + * of data in one record in multiple calls. */ - if (reach_max) { - TEST_EQUAL(scenario, TEST_EARLY_DATA_ACCEPTED); - } + read_size = (write_size / 2) + 1; + TEST_CALLOC(buf_read, read_size); + + PSA_INIT(); /* * Run first handshake to get a ticket from the server. @@ -4579,49 +4580,45 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, in ret = mbedtls_ssl_handshake(&(server_ep.ssl)); TEST_EQUAL(ret, MBEDTLS_ERR_SSL_WANT_READ); - while (write_early_data_flag) { - unsigned char buf_read[23]; + /* + * Write and if possible read as much as possible chunks of write_size + * bytes data without getting over the max_early_data_size limit. + */ + do { uint32_t read_early_data_size = 0; - uint32_t remaining = max_early_data_size - - server_ep.ssl.total_early_data_size; - early_data_len = sizeof(buf_write); - /* - * Adjust the length of next data to write depending on the remaining - * number of early data bytes we are allowed to write and if we want - * to reach the maximum exactly or not. - */ - if (early_data_len >= remaining) { - if (reach_max) { - early_data_len = remaining; - write_early_data_flag = 0; - } else { - if (early_data_len == remaining) { - early_data_len /= 2; - } else { - early_data_len = remaining + 1; - break; - } - } + if ((written_early_data_size + write_size) > max_early_data_size) { + break; } - for (size_t i = 0; i < early_data_len; i++) { + /* + * If the server rejected early data, base the determination of when + * to stop the loop on the expended size (padding and encryption + * expansion) of early data on server side and the number of early data + * received so far by the server (multiple of the expended size). + */ + if ((expended_early_data_len != 0) && + ((server_ep.ssl.total_early_data_size + + expended_early_data_len) > max_early_data_size)) { + break; + } + + for (size_t i = 0; i < write_size; i++) { buf_write[i] = (unsigned char) (written_early_data_size + i); } - ret = write_early_data(&(client_ep.ssl), buf_write, early_data_len); - TEST_EQUAL(ret, early_data_len); - written_early_data_size += early_data_len; + ret = write_early_data(&(client_ep.ssl), buf_write, write_size); + TEST_EQUAL(ret, write_size); + written_early_data_size += write_size; switch (scenario) { case TEST_EARLY_DATA_ACCEPTED: - while (read_early_data_size < early_data_len) { + while (read_early_data_size < write_size) { ret = mbedtls_ssl_handshake(&(server_ep.ssl)); TEST_EQUAL(ret, MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA); ret = mbedtls_ssl_read_early_data(&(server_ep.ssl), - buf_read, - sizeof(buf_read)); + buf_read, read_size); TEST_ASSERT(ret > 0); TEST_MEMORY_COMPARE(buf_read, ret, @@ -4653,24 +4650,14 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, in if (expended_early_data_len == 0) { expended_early_data_len = server_ep.ssl.total_early_data_size; } - remaining = max_early_data_size - server_ep.ssl.total_early_data_size; - - if (expended_early_data_len > remaining) { - write_early_data_flag = 0; - } break; } TEST_ASSERT(server_ep.ssl.total_early_data_size <= max_early_data_size); - } + } while (1); mbedtls_debug_set_threshold(3); - - if (reach_max) { - TEST_EQUAL(server_ep.ssl.total_early_data_size, max_early_data_size); - } - - ret = write_early_data(&(client_ep.ssl), buf_write, early_data_len); - TEST_EQUAL(ret, early_data_len); + ret = write_early_data(&(client_ep.ssl), buf_write, write_size); + TEST_EQUAL(ret, write_size); ret = mbedtls_snprintf(pattern, sizeof(pattern), "EarlyData: Too much early data received"); From fcbf776d0661bdeee4c7b663c041e16561e8ca0e Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Fri, 1 Mar 2024 10:00:42 +0100 Subject: [PATCH 12/20] tests: ssl: Restore write_early_data test function For negative testing of early data (tests related to max_early_data_size in this PR), restore the test function to write early data that was first introduced to be able to test the reading of early data with the writing part and was removed (as not used anymore) by the PR 8760. Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.function | 41 ++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index d89d8ac8b2..c1622e3484 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -18,6 +18,47 @@ #define TEST_EARLY_DATA_SERVER_REJECTS 2 #define TEST_EARLY_DATA_HRR 3 +#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) && \ + defined(MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE) && \ + defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED) && \ + defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED) && \ + defined(MBEDTLS_MD_CAN_SHA256) && \ + defined(MBEDTLS_ECP_HAVE_SECP256R1) && defined(MBEDTLS_ECP_HAVE_SECP384R1) && \ + defined(MBEDTLS_PK_CAN_ECDSA_VERIFY) && defined(MBEDTLS_SSL_SESSION_TICKETS) +/* + * Test function to write early data for negative tests where + * mbedtls_ssl_write_early_data() cannot be used. + */ +static int write_early_data(mbedtls_ssl_context *ssl, + unsigned char *buf, size_t len) +{ + int ret = mbedtls_ssl_get_max_out_record_payload(ssl); + + TEST_ASSERT(ret > 0); + TEST_ASSERT(len <= (size_t) ret); + + ret = mbedtls_ssl_flush_output(ssl); + TEST_EQUAL(ret, 0); + TEST_EQUAL(ssl->out_left, 0); + + ssl->out_msglen = len; + ssl->out_msgtype = MBEDTLS_SSL_MSG_APPLICATION_DATA; + if (len > 0) { + memcpy(ssl->out_msg, buf, len); + } + + ret = mbedtls_ssl_write_record(ssl, 1); + TEST_EQUAL(ret, 0); + + ret = len; + +exit: + return ret; +} +#endif + /* END_HEADER */ /* BEGIN_DEPENDENCIES From e93cd1b5805e2ee52ab7a1aefd1634f6cb90c0e1 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Fri, 1 Mar 2024 19:30:00 +0100 Subject: [PATCH 13/20] tests: ssl: Free write/read test buffers Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.function | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index c1622e3484..c381860f95 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4523,6 +4523,8 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, in mbedtls_test_init_handshake_options(&client_options); mbedtls_test_init_handshake_options(&server_options); mbedtls_ssl_session_init(&saved_session); + PSA_INIT(); + TEST_CALLOC(buf_write, write_size); /* @@ -4532,8 +4534,6 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, in read_size = (write_size / 2) + 1; TEST_CALLOC(buf_read, read_size); - PSA_INIT(); - /* * Run first handshake to get a ticket from the server. */ @@ -4714,6 +4714,8 @@ exit: mbedtls_test_free_handshake_options(&client_options); mbedtls_test_free_handshake_options(&server_options); mbedtls_ssl_session_free(&saved_session); + mbedtls_free(buf_write); + mbedtls_free(buf_read); mbedtls_debug_set_threshold(0); PSA_DONE(); } From 2e7dfd518121f483f20c06ac58f0a6062b1c7e4a Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Tue, 5 Mar 2024 10:54:33 +0100 Subject: [PATCH 14/20] tls13: Remove unnecessary cast from size_t to uint32_t Signed-off-by: Ronald Cron --- library/ssl_tls13_generic.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index eec2bb4b75..9fbd3ac276 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -1459,8 +1459,6 @@ int mbedtls_ssl_tls13_write_early_data_ext(mbedtls_ssl_context *ssl, int mbedtls_ssl_tls13_check_early_data_len(mbedtls_ssl_context *ssl, size_t early_data_len) { - uint32_t uint32_early_data_len = (uint32_t) early_data_len; - /* * This function should be called only while an handshake is in progress * and thus a session under negotiation. Add a sanity check to detect a @@ -1475,13 +1473,13 @@ int mbedtls_ssl_tls13_check_early_data_len(mbedtls_ssl_context *ssl, * A server receiving more than max_early_data_size bytes of 0-RTT data * SHOULD terminate the connection with an "unexpected_message" alert. */ - if (uint32_early_data_len > + if (early_data_len > (ssl->session_negotiate->max_early_data_size - ssl->total_early_data_size)) { MBEDTLS_SSL_DEBUG_MSG( - 2, ("EarlyData: Too much early data received, %u > %u", - ssl->total_early_data_size + uint32_early_data_len, + 2, ("EarlyData: Too much early data received, %u + %" MBEDTLS_PRINTF_SIZET " > %u", + ssl->total_early_data_size, early_data_len, ssl->session_negotiate->max_early_data_size)); MBEDTLS_SSL_PEND_FATAL_ALERT( @@ -1490,7 +1488,13 @@ int mbedtls_ssl_tls13_check_early_data_len(mbedtls_ssl_context *ssl, return MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; } - ssl->total_early_data_size += uint32_early_data_len; + /* + * The check just above implies that early_data_len is lower than + * UINT32_MAX thus its cast to an uint32_t below is safe. We need it + * to appease some compilers. + */ + + ssl->total_early_data_size += (uint32_t) early_data_len; return 0; } From 93795f2639a4ab68ced9b9211fc55bf1d5343108 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Thu, 7 Mar 2024 09:24:56 +0100 Subject: [PATCH 15/20] tls13: Improve comment about cast to uint32_t Signed-off-by: Ronald Cron --- library/ssl_tls13_generic.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index 9fbd3ac276..d448a054a9 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -1472,6 +1472,10 @@ int mbedtls_ssl_tls13_check_early_data_len(mbedtls_ssl_context *ssl, * * A server receiving more than max_early_data_size bytes of 0-RTT data * SHOULD terminate the connection with an "unexpected_message" alert. + * Note that if it is still possible to send early_data_len bytes of early + * data, it means that early_data_len is smaller than max_early_data_size + * (type uint32_t) and can fit in an uint32_t. We use this further + * down. */ if (early_data_len > (ssl->session_negotiate->max_early_data_size - @@ -1489,11 +1493,10 @@ int mbedtls_ssl_tls13_check_early_data_len(mbedtls_ssl_context *ssl, } /* - * The check just above implies that early_data_len is lower than - * UINT32_MAX thus its cast to an uint32_t below is safe. We need it - * to appease some compilers. + * early_data_len has been checked to be less than max_early_data_size + * that is uint32_t. Its cast to an uint32_t below is thus safe. We need + * the cast to appease some compilers. */ - ssl->total_early_data_size += (uint32_t) early_data_len; return 0; From db944a78636de2e18b77a911a20d9ee20f06dee9 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Fri, 8 Mar 2024 11:32:53 +0100 Subject: [PATCH 16/20] ssl_msg.c: Fix log position Signed-off-by: Ronald Cron --- library/ssl_msg.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/ssl_msg.c b/library/ssl_msg.c index a8ff1c1a15..0c711571d5 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -4133,14 +4133,15 @@ static int ssl_prepare_record_content(mbedtls_ssl_context *ssl, */ if (ssl->discard_early_data_record == MBEDTLS_SSL_EARLY_DATA_DISCARD) { if (rec->type == MBEDTLS_SSL_MSG_APPLICATION_DATA) { - MBEDTLS_SSL_DEBUG_MSG( - 3, ("EarlyData: Ignore application message before 2nd ClientHello")); ret = mbedtls_ssl_tls13_check_early_data_len(ssl, rec->data_len); if (ret != 0) { return ret; } + MBEDTLS_SSL_DEBUG_MSG( + 3, ("EarlyData: Ignore application message before 2nd ClientHello")); + return MBEDTLS_ERR_SSL_CONTINUE_PROCESSING; } else if (rec->type == MBEDTLS_SSL_MSG_HANDSHAKE) { ssl->discard_early_data_record = MBEDTLS_SSL_EARLY_DATA_NO_DISCARD; From 1a13e2f43ee62c626ef794bb9896cc543fc29777 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Fri, 8 Mar 2024 14:44:35 +0100 Subject: [PATCH 17/20] tests: ssl: Improve test code for very small max_early_data_size Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.function | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index c381860f95..7ba5670a98 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4675,12 +4675,27 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, in case TEST_EARLY_DATA_HRR: ret = mbedtls_ssl_handshake(&(server_ep.ssl)); /* - * Can be the case if max_early_data_size is smaller then the - * smallest inner content or protected record. + * In this write loop we try to always stay below the + * max_early_data_size limit but if max_early_data_size is very + * small we may exceed the max_early_data_size limit on the + * first write. In TEST_EARLY_DATA_SERVER_REJECTS/ + * TEST_EARLY_DATA_HRR scenario, this is for sure the case if + * max_early_data_size is smaller than the smallest possible + * inner content/protected record. Take into account this + * possibility here but only for max_early_data_size values + * that are close to write_size. Below, chosen 1 for one byte + * of inner type and 16 bytes for AEAD expansion (IV, ...). */ if (ret == MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE) { - /* Beyond 64 for max_early_data_size it is suspicious */ - TEST_ASSERT(max_early_data_size < 64); + if (scenario == TEST_EARLY_DATA_SERVER_REJECTS) { + TEST_LE_U(max_early_data_size, + write_size + 1 + + MBEDTLS_SSL_CID_TLS1_3_PADDING_GRANULARITY); + } else { + TEST_LE_U(max_early_data_size, + write_size + 1 + 16 + + MBEDTLS_SSL_CID_TLS1_3_PADDING_GRANULARITY); + } goto exit; } From 4facb0a9cd27ace3ee681a63bb107d509830bab7 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Fri, 8 Mar 2024 11:40:07 +0100 Subject: [PATCH 18/20] tests: ssl: Improve early data test code Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.function | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 7ba5670a98..f4288d1830 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -37,7 +37,7 @@ static int write_early_data(mbedtls_ssl_context *ssl, int ret = mbedtls_ssl_get_max_out_record_payload(ssl); TEST_ASSERT(ret > 0); - TEST_ASSERT(len <= (size_t) ret); + TEST_LE_U(len, (size_t) ret); ret = mbedtls_ssl_flush_output(ssl); TEST_EQUAL(ret, 0); @@ -4514,7 +4514,7 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, in uint32_t write_size = (uint32_t) write_size_arg; unsigned char *buf_read = NULL; uint32_t read_size; - uint32_t expended_early_data_len = 0; + uint32_t expanded_early_data_chunk_size = 0; uint32_t written_early_data_size = 0; uint32_t max_early_data_size; @@ -4634,13 +4634,13 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, in /* * If the server rejected early data, base the determination of when - * to stop the loop on the expended size (padding and encryption + * to stop the loop on the expanded size (padding and encryption * expansion) of early data on server side and the number of early data - * received so far by the server (multiple of the expended size). + * received so far by the server (multiple of the expanded size). */ - if ((expended_early_data_len != 0) && + if ((expanded_early_data_chunk_size != 0) && ((server_ep.ssl.total_early_data_size + - expended_early_data_len) > max_early_data_size)) { + expanded_early_data_chunk_size) > max_early_data_size)) { break; } @@ -4703,12 +4703,12 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, in TEST_EQUAL(server_pattern.counter, 1); server_pattern.counter = 0; - if (expended_early_data_len == 0) { - expended_early_data_len = server_ep.ssl.total_early_data_size; + if (expanded_early_data_chunk_size == 0) { + expanded_early_data_chunk_size = server_ep.ssl.total_early_data_size; } break; } - TEST_ASSERT(server_ep.ssl.total_early_data_size <= max_early_data_size); + TEST_LE_U(server_ep.ssl.total_early_data_size, max_early_data_size); } while (1); mbedtls_debug_set_threshold(3); From 52472104a24637e94abe5926abe7682476006913 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Fri, 8 Mar 2024 11:29:28 +0100 Subject: [PATCH 19/20] tests: suite: early data: Add comments Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.function | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index f4288d1830..64ee0f711c 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4200,6 +4200,10 @@ void tls13_write_early_data(int scenario) break; case TEST_EARLY_DATA_HRR: + /* + * Remove server support for the group negotiated in + * mbedtls_test_get_tls13_ticket() forcing an HelloRetryRequest. + */ server_options.group_list = group_list + 1; break; @@ -4570,6 +4574,10 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, in break; case TEST_EARLY_DATA_HRR: + /* + * Remove server support for the group negotiated in + * mbedtls_test_get_tls13_ticket() forcing an HelloRetryRequest. + */ server_options.group_list = group_list + 1; ret = mbedtls_snprintf( pattern, sizeof(pattern), @@ -4628,6 +4636,11 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, in do { uint32_t read_early_data_size = 0; + /* + * The contents of the early data are not very important, write a + * pattern that varies byte-by-byte and is different for every chunk of + * early data. + */ if ((written_early_data_size + write_size) > max_early_data_size) { break; } From e1295fabaf39abd5cadea749a6c1e07fee2b7de3 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Fri, 8 Mar 2024 17:03:16 +0100 Subject: [PATCH 20/20] tests: ssl: early data: Fix comments Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.function | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 64ee0f711c..20f80379be 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4202,7 +4202,7 @@ void tls13_write_early_data(int scenario) case TEST_EARLY_DATA_HRR: /* * Remove server support for the group negotiated in - * mbedtls_test_get_tls13_ticket() forcing an HelloRetryRequest. + * mbedtls_test_get_tls13_ticket() forcing a HelloRetryRequest. */ server_options.group_list = group_list + 1; break; @@ -4696,8 +4696,9 @@ void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, in * max_early_data_size is smaller than the smallest possible * inner content/protected record. Take into account this * possibility here but only for max_early_data_size values - * that are close to write_size. Below, chosen 1 for one byte - * of inner type and 16 bytes for AEAD expansion (IV, ...). + * that are close to write_size. Below, '1' is for the inner + * type byte and '16' is to take into account some AEAD + * expansion (tag, ...). */ if (ret == MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE) { if (scenario == TEST_EARLY_DATA_SERVER_REJECTS) {