From 9b51e8ee49d5b32178345f2c95e4e3ae68318d99 Mon Sep 17 00:00:00 2001 From: Waleed Elmelegy Date: Thu, 14 Mar 2024 01:48:40 +0000 Subject: [PATCH] Add ALPN checking when accepting early data Signed-off-by: Waleed Elmelegy --- library/ssl_tls.c | 15 ++++++++ library/ssl_tls13_server.c | 23 +++++++++++- tests/include/test/ssl_helpers.h | 7 ++++ tests/src/test_helpers/ssl_helpers.c | 6 ++++ tests/suites/test_suite_ssl.data | 16 +++++++++ tests/suites/test_suite_ssl.function | 52 ++++++++++++++++++++++++++++ 6 files changed, 118 insertions(+), 1 deletion(-) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index ffca53ed6031..ac53853a5beb 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -238,6 +238,11 @@ int mbedtls_ssl_session_copy(mbedtls_ssl_session *dst, #endif #endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_ALPN) && \ + defined(MBEDTLS_SSL_EARLY_DATA) + dst->ticket_alpn = NULL; +#endif + #if defined(MBEDTLS_X509_CRT_PARSE_C) #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) @@ -275,6 +280,16 @@ int mbedtls_ssl_session_copy(mbedtls_ssl_session *dst, #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_ALPN) && \ + defined(MBEDTLS_SSL_EARLY_DATA) + { + int ret = mbedtls_ssl_session_set_ticket_alpn(dst, src->ticket_alpn); + if (ret != 0) { + return ret; + } + } +#endif /* MBEDTLS_SSL_SRV_C && MBEDTLS_SSL_ALPN && MBEDTLS_SSL_EARLY_DATA */ + #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) if (src->ticket != NULL) { dst->ticket = mbedtls_calloc(1, src->ticket_len); diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index 9453c69392c4..d159760fe1a0 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -1819,7 +1819,6 @@ static int ssl_tls13_check_early_data_requirements(mbedtls_ssl_context *ssl) * NOTE: * - The TLS version number is checked in * ssl_tls13_offered_psks_check_identity_match_ticket(). - * - ALPN is not checked for the time being (TODO). */ if (handshake->selected_identity != 0) { @@ -1846,6 +1845,28 @@ static int ssl_tls13_check_early_data_requirements(mbedtls_ssl_context *ssl) return -1; } +#if defined(MBEDTLS_SSL_ALPN) + const char *alpn = mbedtls_ssl_get_alpn_protocol(ssl); + size_t alpn_len; + + if (alpn == NULL && ssl->session_negotiate->ticket_alpn == NULL) { + return 0; + } + + if (alpn != NULL) { + alpn_len = strlen(alpn); + } + + if (alpn == NULL || + ssl->session_negotiate->ticket_alpn == NULL || + alpn_len != strlen(ssl->session_negotiate->ticket_alpn) || + (memcmp(alpn, ssl->session_negotiate->ticket_alpn, alpn_len) != 0)) { + MBEDTLS_SSL_DEBUG_MSG(1, ("EarlyData: rejected, the selected ALPN is different " + "from the one associated with the pre-shared key.")); + return -1; + } +#endif + return 0; } #endif /* MBEDTLS_SSL_EARLY_DATA */ diff --git a/tests/include/test/ssl_helpers.h b/tests/include/test/ssl_helpers.h index 335386be1c56..77f85c4966ab 100644 --- a/tests/include/test/ssl_helpers.h +++ b/tests/include/test/ssl_helpers.h @@ -78,6 +78,10 @@ enum { #undef MBEDTLS_SSL_TLS1_3_LABEL }; +#if defined(MBEDTLS_SSL_ALPN) +#define MBEDTLS_TEST_MAX_ALPN_LIST_SIZE 10 +#endif + typedef struct mbedtls_test_ssl_log_pattern { const char *pattern; size_t counter; @@ -118,6 +122,9 @@ typedef struct mbedtls_test_handshake_test_options { #if defined(MBEDTLS_SSL_CACHE_C) mbedtls_ssl_cache_context *cache; #endif +#if defined(MBEDTLS_SSL_ALPN) + const char *alpn_list[MBEDTLS_TEST_MAX_ALPN_LIST_SIZE]; +#endif } mbedtls_test_handshake_test_options; /* diff --git a/tests/src/test_helpers/ssl_helpers.c b/tests/src/test_helpers/ssl_helpers.c index 963938f1f857..55201c0b7849 100644 --- a/tests/src/test_helpers/ssl_helpers.c +++ b/tests/src/test_helpers/ssl_helpers.c @@ -833,6 +833,12 @@ int mbedtls_test_ssl_endpoint_init( options->max_early_data_size); } #endif +#if defined(MBEDTLS_SSL_ALPN) + /* check that alpn_list contains at least one valid entry */ + if (options->alpn_list[0] != NULL) { + mbedtls_ssl_conf_alpn_protocols(&(ep->conf), options->alpn_list); + } +#endif #endif #if defined(MBEDTLS_SSL_CACHE_C) && defined(MBEDTLS_SSL_SRV_C) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 0ecf65c03190..734b94514809 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3294,6 +3294,22 @@ tls13_read_early_data:TEST_EARLY_DATA_SERVER_REJECTS TLS 1.3 read early data, discard after HRR tls13_read_early_data:TEST_EARLY_DATA_HRR +TLS 1.3 cli, early data, same ALPN +depends_on:MBEDTLS_SSL_ALPN +tls13_read_early_data:TEST_EARLY_DATA_SAME_ALPN + +TLS 1.3 cli, early data, different ALPN +depends_on:MBEDTLS_SSL_ALPN +tls13_read_early_data:TEST_EARLY_DATA_DIFF_ALPN + +TLS 1.3 cli, early data, no initial ALPN +depends_on:MBEDTLS_SSL_ALPN +tls13_read_early_data:TEST_EARLY_DATA_NO_INITIAL_ALPN + +TLS 1.3 cli, early data, no later ALPN +depends_on:MBEDTLS_SSL_ALPN +tls13_read_early_data:TEST_EARLY_DATA_NO_LATER_ALPN + TLS 1.3 cli, early data state, early data accepted tls13_cli_early_data_state:TEST_EARLY_DATA_ACCEPTED diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index e29667d0bce5..ffe9c1be68d5 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -17,6 +17,10 @@ #define TEST_EARLY_DATA_NO_INDICATION_SENT 1 #define TEST_EARLY_DATA_SERVER_REJECTS 2 #define TEST_EARLY_DATA_HRR 3 +#define TEST_EARLY_DATA_SAME_ALPN 4 +#define TEST_EARLY_DATA_DIFF_ALPN 5 +#define TEST_EARLY_DATA_NO_INITIAL_ALPN 6 +#define TEST_EARLY_DATA_NO_LATER_ALPN 7 #if (!defined(MBEDTLS_SSL_PROTO_TLS1_2)) && \ defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C) && \ @@ -3728,6 +3732,19 @@ void tls13_read_early_data(int scenario) server_options.group_list = group_list; server_options.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED; +#if defined(MBEDTLS_SSL_ALPN) + switch (scenario) { + case TEST_EARLY_DATA_SAME_ALPN: + case TEST_EARLY_DATA_DIFF_ALPN: + case TEST_EARLY_DATA_NO_LATER_ALPN: + client_options.alpn_list[0] = "ALPNExample"; + client_options.alpn_list[1] = NULL; + server_options.alpn_list[0] = "ALPNExample"; + server_options.alpn_list[1] = NULL; + break; + } +#endif + ret = mbedtls_test_get_tls13_ticket(&client_options, &server_options, &saved_session); TEST_EQUAL(ret, 0); @@ -3756,6 +3773,33 @@ void tls13_read_early_data(int scenario) "EarlyData: Ignore application message before 2nd ClientHello"; server_options.group_list = group_list + 1; break; +#if defined(MBEDTLS_SSL_ALPN) + case TEST_EARLY_DATA_SAME_ALPN: + client_options.alpn_list[0] = "ALPNExample"; + client_options.alpn_list[1] = NULL; + server_options.alpn_list[0] = "ALPNExample"; + server_options.alpn_list[1] = NULL; + break; + case TEST_EARLY_DATA_DIFF_ALPN: + case TEST_EARLY_DATA_NO_INITIAL_ALPN: + client_options.alpn_list[0] = "ALPNExample2"; + client_options.alpn_list[1] = NULL; + server_options.alpn_list[0] = "ALPNExample2"; + server_options.alpn_list[1] = NULL; + mbedtls_debug_set_threshold(3); + server_pattern.pattern = + "EarlyData: rejected, the selected ALPN is different " + "from the one associated with the pre-shared key."; + break; + case TEST_EARLY_DATA_NO_LATER_ALPN: + client_options.alpn_list[0] = NULL; + server_options.alpn_list[0] = NULL; + mbedtls_debug_set_threshold(3); + server_pattern.pattern = + "EarlyData: rejected, the selected ALPN is different " + "from the one associated with the pre-shared key."; + break; +#endif default: TEST_FAIL("Unknown scenario."); @@ -3807,6 +3851,9 @@ void tls13_read_early_data(int scenario) switch (scenario) { case TEST_EARLY_DATA_ACCEPTED: +#if defined(MBEDTLS_SSL_ALPN) + case TEST_EARLY_DATA_SAME_ALPN: +#endif TEST_EQUAL(ret, MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA); TEST_EQUAL(server_ep.ssl.handshake->early_data_accepted, 1); TEST_EQUAL(mbedtls_ssl_read_early_data(&(server_ep.ssl), @@ -3821,6 +3868,11 @@ void tls13_read_early_data(int scenario) case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */ case TEST_EARLY_DATA_HRR: +#if defined(MBEDTLS_SSL_ALPN) + case TEST_EARLY_DATA_DIFF_ALPN: + case TEST_EARLY_DATA_NO_INITIAL_ALPN: + case TEST_EARLY_DATA_NO_LATER_ALPN: +#endif TEST_EQUAL(ret, 0); TEST_EQUAL(server_ep.ssl.handshake->early_data_accepted, 0); TEST_EQUAL(server_pattern.counter, 1);