From b62732e1d645e5d7d21e198f556e94437bc69d7f Mon Sep 17 00:00:00 2001 From: Xiaokang Qian Date: Thu, 30 Nov 2023 09:58:08 +0000 Subject: [PATCH 01/31] tls13: cli: Add mbedtls_ssl_write_early_data() API Signed-off-by: Xiaokang Qian Signed-off-by: Ronald Cron --- library/ssl_msg.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/library/ssl_msg.c b/library/ssl_msg.c index c2e64c609..f3bb32360 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -6058,6 +6058,81 @@ int mbedtls_ssl_write(mbedtls_ssl_context *ssl, const unsigned char *buf, size_t return ret; } +#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C) +int mbedtls_ssl_write_early_data(mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + const struct mbedtls_ssl_config *conf; + int written_data_len = 0; + + MBEDTLS_SSL_DEBUG_MSG(2, ("=> write early_data")); + + if (ssl == NULL || (conf = ssl->conf) == NULL) { + return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; + } + + if ((!mbedtls_ssl_conf_is_tls13_enabled(conf)) || + (conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) || + (conf->early_data_enabled != MBEDTLS_SSL_EARLY_DATA_ENABLED)) { + return MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA; + } + + if (ssl->tls_version != MBEDTLS_SSL_VERSION_TLS1_3) { + return MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA; + } + + /* + * If we are at the beginning of the handshake, advance the handshake just + * enough to be able to send early data if possible. That way, we can + * guarantee that when starting the handshake with this function we will + * send at least one record of early data. + * Otherwise, resume the handshake and if the handshake sequence stops + * waiting for some message from the server, send early data if we can. + */ + + if ((ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN) || + (ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_SENT)) { + while ((ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN) || + (ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_SENT)) { + ret = mbedtls_ssl_handshake_step(ssl); + if (ret != 0) { + MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_handshake_step", ret); + return ret; + } + + ret = mbedtls_ssl_flush_output(ssl); + if (ret != 0) { + MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_flush_output", ret); + return ret; + } + } + } else { + if ((ssl->early_data_status != MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE) && + (ssl->early_data_status != MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED)) { + return MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA; + } + + ret = mbedtls_ssl_handshake(ssl); + if ((ret != 0) && (ret != MBEDTLS_ERR_SSL_WANT_READ)) { + MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_handshake", ret); + return ret; + } + } + + if ((ssl->early_data_status != MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE) && + (ssl->early_data_status != MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED)) { + return MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA; + } + + written_data_len = ssl_write_real(ssl, buf, len); + + MBEDTLS_SSL_DEBUG_MSG(2, ("<= write early_data, len=%d", written_data_len)); + + return written_data_len; +} +#endif /* MBEDTLS_SSL_EARLY_DATA && MBEDTLS_SSL_CLI_C */ + /* * Notify the peer that the connection is being closed */ From 54a382945334a179e9437c8ef78f6c6f6490bd50 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Thu, 25 Jan 2024 09:39:59 +0100 Subject: [PATCH 02/31] ssl_client2: Simplify early_data option No need to define specific early data, the idea is rather to just send the usual request data as early data instead of standard application data. Signed-off-by: Ronald Cron --- programs/ssl/ssl_client2.c | 40 +++++++++++-------------------- tests/opt-testcases/tls13-misc.sh | 4 ++-- 2 files changed, 16 insertions(+), 28 deletions(-) diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 1b3dedb22..83be1073f 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -52,7 +52,7 @@ int main(void) #define DFL_KEY_OPAQUE 0 #define DFL_KEY_PWD "" #define DFL_PSK "" -#define DFL_EARLY_DATA "" +#define DFL_EARLY_DATA MBEDTLS_SSL_EARLY_DATA_DISABLED #define DFL_PSK_OPAQUE 0 #define DFL_PSK_IDENTITY "Client_identity" #define DFL_ECJPAKE_PW NULL @@ -347,9 +347,8 @@ int main(void) #if defined(MBEDTLS_SSL_EARLY_DATA) #define USAGE_EARLY_DATA \ - " early_data=%%s The file path to read early data from\n" \ - " default: \"\" (do nothing)\n" \ - " option: a file path\n" + " early_data=%%d default: 0 (disabled)\n" \ + " options: 0 (disabled), 1 (enabled)\n" #else #define USAGE_EARLY_DATA "" #endif /* MBEDTLS_SSL_EARLY_DATA && MBEDTLS_SSL_PROTO_TLS1_3 */ @@ -544,7 +543,7 @@ struct options { int reproducible; /* make communication reproducible */ int skip_close_notify; /* skip sending the close_notify alert */ #if defined(MBEDTLS_SSL_EARLY_DATA) - const char *early_data; /* the path of the file to read early data from */ + int early_data; /* early data enablement flag */ #endif int query_config_mode; /* whether to read config */ int use_srtp; /* Support SRTP */ @@ -742,10 +741,6 @@ int main(int argc, char *argv[]) size_t cid_renego_len = 0; #endif -#if defined(MBEDTLS_SSL_EARLY_DATA) - FILE *early_data_fp = NULL; -#endif /* MBEDTLS_SSL_EARLY_DATA */ - #if defined(MBEDTLS_SSL_ALPN) const char *alpn_list[ALPN_LIST_SIZE]; #endif @@ -1201,7 +1196,15 @@ usage: #if defined(MBEDTLS_SSL_PROTO_TLS1_3) #if defined(MBEDTLS_SSL_EARLY_DATA) else if (strcmp(p, "early_data") == 0) { - opt.early_data = q; + switch (atoi(q)) { + case 0: + opt.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED; + break; + case 1: + opt.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED; + break; + default: goto usage; + } } #endif /* MBEDTLS_SSL_EARLY_DATA */ @@ -1968,16 +1971,7 @@ usage: } #if defined(MBEDTLS_SSL_EARLY_DATA) - int early_data_enabled = MBEDTLS_SSL_EARLY_DATA_DISABLED; - if (strlen(opt.early_data) > 0) { - if ((early_data_fp = fopen(opt.early_data, "rb")) == NULL) { - mbedtls_printf("failed\n ! Cannot open '%s' for reading.\n", - opt.early_data); - goto exit; - } - early_data_enabled = MBEDTLS_SSL_EARLY_DATA_ENABLED; - } - mbedtls_ssl_conf_early_data(&conf, early_data_enabled); + mbedtls_ssl_conf_early_data(&conf, opt.early_data); #endif /* MBEDTLS_SSL_EARLY_DATA */ if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) { @@ -3035,12 +3029,6 @@ exit: mbedtls_ssl_config_free(&conf); mbedtls_ssl_session_free(&saved_session); -#if defined(MBEDTLS_SSL_EARLY_DATA) - if (early_data_fp != NULL) { - fclose(early_data_fp); - } -#endif - if (session_data != NULL) { mbedtls_platform_zeroize(session_data, session_data_len); } diff --git a/tests/opt-testcases/tls13-misc.sh b/tests/opt-testcases/tls13-misc.sh index 4e6bf876d..b24f71803 100755 --- a/tests/opt-testcases/tls13-misc.sh +++ b/tests/opt-testcases/tls13-misc.sh @@ -263,7 +263,7 @@ requires_any_configs_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ run_test "TLS 1.3 m->G: EarlyData: basic check, good" \ "$G_NEXT_SRV -d 10 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:+CIPHER-ALL:+ECDHE-PSK:+PSK \ --earlydata --maxearlydata 16384 --disable-client-cert" \ - "$P_CLI debug_level=4 early_data=$EARLY_DATA_INPUT reco_mode=1 reconnect=1 reco_delay=900" \ + "$P_CLI debug_level=4 early_data=1 reco_mode=1 reconnect=1 reco_delay=900" \ 0 \ -c "received max_early_data_size: 16384" \ -c "Reconnecting with saved session" \ @@ -287,7 +287,7 @@ requires_any_configs_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED run_test "TLS 1.3 m->G: EarlyData: no early_data in NewSessionTicket, good" \ "$G_NEXT_SRV -d 10 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:+CIPHER-ALL:+ECDHE-PSK:+PSK --disable-client-cert" \ - "$P_CLI debug_level=4 early_data=$EARLY_DATA_INPUT reco_mode=1 reconnect=1" \ + "$P_CLI debug_level=4 early_data=1 reco_mode=1 reconnect=1" \ 0 \ -c "Reconnecting with saved session" \ -C "NewSessionTicket: early_data(42) extension received." \ From 4e1bd470fb1f1d8fc526cd5b7dfef45ca3199814 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Tue, 23 Jan 2024 09:18:54 +0100 Subject: [PATCH 03/31] ssl_client2: Move code to build http request Move code to build http request into a dedicated function. Signed-off-by: Ronald Cron --- programs/ssl/ssl_client2.c | 67 ++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 83be1073f..da58899c6 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -716,9 +716,46 @@ exit: return ret; } +/* + * Build HTTP request + */ +static void build_http_request(unsigned char *buf, size_t buf_size, int *request_len) +{ + int len, tail_len; + + len = mbedtls_snprintf((char *) buf, buf_size, GET_REQUEST, opt.request_page); + tail_len = (int) strlen(GET_REQUEST_END); + + /* Add padding to GET request to reach opt.request_size in length */ + if (opt.request_size != DFL_REQUEST_SIZE && + len + tail_len < opt.request_size) { + memset(buf + len, 'A', opt.request_size - len - tail_len); + len += opt.request_size - len - tail_len; + } + + strncpy((char *) buf + len, GET_REQUEST_END, buf_size - len); + len += tail_len; + + /* Truncate if request size is smaller than the "natural" size */ + if (opt.request_size != DFL_REQUEST_SIZE && + len > opt.request_size) { + len = opt.request_size; + + /* Still end with \r\n unless that's really not possible */ + if (len >= 2) { + buf[len - 2] = '\r'; + } + if (len >= 1) { + buf[len - 1] = '\n'; + } + } + + *request_len = len; +} + int main(int argc, char *argv[]) { - int ret = 0, len, tail_len, i, written, frags, retry_left; + int ret = 0, len, i, written, frags, retry_left; int query_config_ret = 0; mbedtls_net_context server_fd; io_ctx_t io_ctx; @@ -2442,33 +2479,7 @@ send_request: mbedtls_printf(" > Write to server:"); fflush(stdout); - len = mbedtls_snprintf((char *) buf, sizeof(buf) - 1, GET_REQUEST, - opt.request_page); - tail_len = (int) strlen(GET_REQUEST_END); - - /* Add padding to GET request to reach opt.request_size in length */ - if (opt.request_size != DFL_REQUEST_SIZE && - len + tail_len < opt.request_size) { - memset(buf + len, 'A', opt.request_size - len - tail_len); - len += opt.request_size - len - tail_len; - } - - strncpy((char *) buf + len, GET_REQUEST_END, sizeof(buf) - len - 1); - len += tail_len; - - /* Truncate if request size is smaller than the "natural" size */ - if (opt.request_size != DFL_REQUEST_SIZE && - len > opt.request_size) { - len = opt.request_size; - - /* Still end with \r\n unless that's really not possible */ - if (len >= 2) { - buf[len - 2] = '\r'; - } - if (len >= 1) { - buf[len - 1] = '\n'; - } - } + build_http_request(buf, sizeof(buf) - 1, &len); if (opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM) { written = 0; From ccfaefa361631c95d183611c02722dafe08b7455 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Thu, 25 Jan 2024 14:34:16 +0100 Subject: [PATCH 04/31] ssl_client2: Switch from int to size_t Switch from int to size_t for some data lengths and counter local variables. Signed-off-by: Ronald Cron --- programs/ssl/ssl_client2.c | 52 +++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index da58899c6..0939393e9 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -719,18 +719,27 @@ exit: /* * Build HTTP request */ -static void build_http_request(unsigned char *buf, size_t buf_size, int *request_len) +static int build_http_request(unsigned char *buf, size_t buf_size, size_t *request_len) { - int len, tail_len; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t len, tail_len, request_size; - len = mbedtls_snprintf((char *) buf, buf_size, GET_REQUEST, opt.request_page); - tail_len = (int) strlen(GET_REQUEST_END); + ret = mbedtls_snprintf((char *) buf, buf_size, GET_REQUEST, opt.request_page); + if (ret < 0) { + return ret; + } + + len = (size_t) ret; + tail_len = strlen(GET_REQUEST_END); + if (opt.request_size != DFL_REQUEST_SIZE) { + request_size = (size_t) opt.request_size; + } /* Add padding to GET request to reach opt.request_size in length */ if (opt.request_size != DFL_REQUEST_SIZE && - len + tail_len < opt.request_size) { - memset(buf + len, 'A', opt.request_size - len - tail_len); - len += opt.request_size - len - tail_len; + len + tail_len < request_size) { + memset(buf + len, 'A', request_size - len - tail_len); + len = request_size - tail_len; } strncpy((char *) buf + len, GET_REQUEST_END, buf_size - len); @@ -738,8 +747,8 @@ static void build_http_request(unsigned char *buf, size_t buf_size, int *request /* Truncate if request size is smaller than the "natural" size */ if (opt.request_size != DFL_REQUEST_SIZE && - len > opt.request_size) { - len = opt.request_size; + len > request_size) { + len = request_size; /* Still end with \r\n unless that's really not possible */ if (len >= 2) { @@ -751,11 +760,14 @@ static void build_http_request(unsigned char *buf, size_t buf_size, int *request } *request_len = len; + + return 0; } int main(int argc, char *argv[]) { - int ret = 0, len, i, written, frags, retry_left; + int ret = 0, i; + size_t len, written, frags, retry_left; int query_config_ret = 0; mbedtls_net_context server_fd; io_ctx_t io_ctx; @@ -2479,7 +2491,10 @@ send_request: mbedtls_printf(" > Write to server:"); fflush(stdout); - build_http_request(buf, sizeof(buf) - 1, &len); + ret = build_http_request(buf, sizeof(buf) - 1, &len); + if (ret != 0) { + goto exit; + } if (opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM) { written = 0; @@ -2550,8 +2565,11 @@ send_request: } buf[written] = '\0'; - mbedtls_printf(" %d bytes written in %d fragments\n\n%s\n", - written, frags, (char *) buf); + mbedtls_printf( + " %" MBEDTLS_PRINTF_SIZET " bytes written in %" MBEDTLS_PRINTF_SIZET " fragments\n\n%s\n", + written, + frags, + (char *) buf); /* Send a non-empty request if request_size == 0 */ if (len == 0) { @@ -2658,7 +2676,9 @@ send_request: len = ret; buf[len] = '\0'; - mbedtls_printf(" < Read from server: %d bytes read\n\n%s", len, (char *) buf); + mbedtls_printf(" < Read from server: %" MBEDTLS_PRINTF_SIZET " bytes read\n\n%s", + len, + (char *) buf); fflush(stdout); /* End of message should be detected according to the syntax of the * application protocol (eg HTTP), just use a dummy test here. */ @@ -2717,7 +2737,9 @@ send_request: len = ret; buf[len] = '\0'; - mbedtls_printf(" < Read from server: %d bytes read\n\n%s", len, (char *) buf); + mbedtls_printf(" < Read from server: %" MBEDTLS_PRINTF_SIZET " bytes read\n\n%s", + len, + (char *) buf); ret = 0; } From 2fe0ec8c3195a4fdea120228f543a37120daf3fc Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Tue, 23 Jan 2024 17:20:46 +0100 Subject: [PATCH 05/31] ssl_client2: Add buffer overflow check Add buffer overflow check to build_http_request(). Signed-off-by: Ronald Cron --- programs/ssl/ssl_client2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 0939393e9..b501b9f58 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -733,6 +733,12 @@ static int build_http_request(unsigned char *buf, size_t buf_size, size_t *reque tail_len = strlen(GET_REQUEST_END); if (opt.request_size != DFL_REQUEST_SIZE) { request_size = (size_t) opt.request_size; + } else { + request_size = len + tail_len; + } + + if (request_size > buf_size) { + return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL; } /* Add padding to GET request to reach opt.request_size in length */ From a5561893e76acd5f9a3a822e4ad323875c0c4fde Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Tue, 23 Jan 2024 10:30:57 +0100 Subject: [PATCH 06/31] ssl_client2: Add support for early data writing Signed-off-by: Ronald Cron --- programs/ssl/ssl_client2.c | 49 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index b501b9f58..0723be8a8 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -3035,6 +3035,55 @@ reconnect: goto exit; } + ret = build_http_request(buf, sizeof(buf) - 1, &len); + if (ret != 0) { + goto exit; + } + +#if defined(MBEDTLS_SSL_EARLY_DATA) + if (opt.early_data == MBEDTLS_SSL_EARLY_DATA_ENABLED) { + frags = 0; + written = 0; + do { + while ((ret = mbedtls_ssl_write_early_data(&ssl, buf + written, + len - written)) < 0) { + if (ret == MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA) { + break; + } + if (ret != MBEDTLS_ERR_SSL_WANT_READ && + ret != MBEDTLS_ERR_SSL_WANT_WRITE && + ret != MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) { + mbedtls_printf(" failed\n ! mbedtls_ssl_write returned -0x%x\n\n", + (unsigned int) -ret); + goto exit; + } + + /* For event-driven IO, wait for socket to become available */ + if (opt.event == 1 /* level triggered IO */) { +#if defined(MBEDTLS_TIMING_C) + idle(&server_fd, &timer, ret); +#else + idle(&server_fd, ret); +#endif + } + } + if (ret == MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA) { + break; + } + + frags++; + written += ret; + } while (written < len); + } + + buf[written] = '\0'; + mbedtls_printf( + " %" MBEDTLS_PRINTF_SIZET " bytes of early data written in %" MBEDTLS_PRINTF_SIZET " fragments\n\n%s\n", + written, + frags, + (char *) buf); +#endif /* MBEDTLS_SSL_EARLY_DATA */ + while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && From 30bb7ce9a23bb809a9d336c27d714cf37495cff8 Mon Sep 17 00:00:00 2001 From: Xiaokang Qian Date: Thu, 30 Nov 2023 09:59:09 +0000 Subject: [PATCH 07/31] Add test case for early data writing Signed-off-by: Xiaokang Qian Signed-off-by: Ronald Cron --- tests/opt-testcases/tls13-misc.sh | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/opt-testcases/tls13-misc.sh b/tests/opt-testcases/tls13-misc.sh index b24f71803..ad062dccf 100755 --- a/tests/opt-testcases/tls13-misc.sh +++ b/tests/opt-testcases/tls13-misc.sh @@ -277,6 +277,31 @@ run_test "TLS 1.3 m->G: EarlyData: basic check, good" \ -s "END OF EARLY DATA (5) was received." \ -s "early data accepted" +requires_gnutls_tls1_3 +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_SSL_CLI_C +requires_all_configs_enabled MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE \ + MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED \ + MBEDTLS_SSL_EARLY_DATA +requires_any_configs_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED \ + MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED +run_test "TLS 1.3 m->G: EarlyData: write early data, good" \ + "$G_NEXT_SRV -d 10 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:+CIPHER-ALL:+ECDHE-PSK:+PSK --earlydata --disable-client-cert" \ + "$P_CLI debug_level=4 early_data=1 reco_mode=1 reconnect=1 reco_delay=900" \ + 0 \ + -c "Reconnecting with saved session" \ + -c "NewSessionTicket: early_data(42) extension received." \ + -c "ClientHello: early_data(42) extension exists." \ + -c "EncryptedExtensions: early_data(42) extension received." \ + -c "EncryptedExtensions: early_data(42) extension exists." \ + -c "<= write early_data" \ + -c "<= write EndOfEarlyData" \ + -s "Parsing extension 'Early Data/42' (0 bytes)" \ + -s "Sending extension Early Data/42 (0 bytes)" \ + -s "END OF EARLY DATA (5) was received." \ + -s "early data accepted" \ + -s "decrypted early data with length" + requires_gnutls_tls1_3 requires_config_enabled MBEDTLS_DEBUG_C requires_config_enabled MBEDTLS_SSL_CLI_C From 2fbbba9c5199cfaa425a287be0dcb8cda00737b0 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Fri, 26 Jan 2024 20:13:42 +0100 Subject: [PATCH 08/31] tests: ssl: Add write early data unit test Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.data | 3 + tests/suites/test_suite_ssl.function | 200 +++++++++++++++++++++++++++ 2 files changed, 203 insertions(+) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 69ccf26ee..0592a5f54 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3294,3 +3294,6 @@ tls13_cli_early_data_status:TEST_EARLY_DATA_SERVER_REJECTS TLS 1.3 cli, early data status, hello retry request tls13_cli_early_data_status:TEST_EARLY_DATA_HRR + +TLS 1.3 write early data, early data accepted +tls13_write_early_data:TEST_EARLY_DATA_ACCEPTED diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 2751e58c1..840a201fb 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4101,3 +4101,203 @@ exit: 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_MD_CAN_SHA256:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_ECP_HAVE_SECP384R1:MBEDTLS_PK_CAN_ECDSA_VERIFY:MBEDTLS_SSL_SESSION_TICKETS */ +void tls13_write_early_data(int scenario) +{ + 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; + + int client_state, previous_client_state; + const char *early_data_string = "This is early data."; + const unsigned char *early_data = (const unsigned char *) early_data_string; + size_t early_data_len = strlen(early_data_string); + int write_early_data_ret; + + 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; + + ret = mbedtls_test_get_tls13_ticket(&client_options, &server_options, + &saved_session); + TEST_EQUAL(ret, 0); + + + /* + * Prepare for handshake with the ticket. + */ + 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); + + ret = mbedtls_ssl_set_session(&(client_ep.ssl), &saved_session); + TEST_EQUAL(ret, 0); + + /* + * Run handshakes and test the writing of early data in each possible + * state. + */ + previous_client_state = MBEDTLS_SSL_HELLO_REQUEST; + client_state = MBEDTLS_SSL_HELLO_REQUEST; + + while (client_state != MBEDTLS_SSL_HANDSHAKE_OVER) { + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + &(client_ep.ssl), &(server_ep.ssl), + previous_client_state), 0); + + /* Progress the handshake from at least one state */ + while (client_ep.ssl.state == previous_client_state) { + ret = mbedtls_ssl_handshake_step(&(client_ep.ssl)); + TEST_ASSERT((ret == 0) || + (ret == MBEDTLS_ERR_SSL_WANT_READ) || + (ret == MBEDTLS_ERR_SSL_WANT_WRITE)); + if (client_ep.ssl.state != previous_client_state) { + break; + } + ret = mbedtls_ssl_handshake_step(&(server_ep.ssl)); + TEST_ASSERT((ret == 0) || + (ret == MBEDTLS_ERR_SSL_WANT_READ) || + (ret == MBEDTLS_ERR_SSL_WANT_WRITE)); + } + + client_state = client_ep.ssl.state; + write_early_data_ret = mbedtls_ssl_write_early_data(&(client_ep.ssl), + early_data, + early_data_len); + + switch (client_state) { + case MBEDTLS_SSL_CLIENT_HELLO: + switch (scenario) { + case TEST_EARLY_DATA_ACCEPTED: + TEST_EQUAL(write_early_data_ret, early_data_len); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); + break; + } + break; + + case MBEDTLS_SSL_SERVER_HELLO: + switch (scenario) { + case TEST_EARLY_DATA_ACCEPTED: + TEST_EQUAL(write_early_data_ret, early_data_len); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); + break; + } + break; + + case MBEDTLS_SSL_ENCRYPTED_EXTENSIONS: + switch (scenario) { + case TEST_EARLY_DATA_ACCEPTED: + TEST_EQUAL(write_early_data_ret, early_data_len); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS); + break; + } + break; + + case MBEDTLS_SSL_SERVER_FINISHED: + switch (scenario) { + case TEST_EARLY_DATA_ACCEPTED: + TEST_EQUAL(write_early_data_ret, early_data_len); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_FINISHED); + break; + } + break; + + case MBEDTLS_SSL_END_OF_EARLY_DATA: + TEST_EQUAL(scenario, TEST_EARLY_DATA_ACCEPTED); + TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_END_OF_EARLY_DATA); + break; + +#if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE) + case MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO: + switch (scenario) { + case TEST_EARLY_DATA_ACCEPTED: + TEST_EQUAL(write_early_data_ret, early_data_len); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); + break; + } + break; + +#endif /* MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE */ + + case MBEDTLS_SSL_CLIENT_CERTIFICATE: /* Intentional fallthrough */ + case MBEDTLS_SSL_CLIENT_FINISHED: /* Intentional fallthrough */ + case MBEDTLS_SSL_FLUSH_BUFFERS: /* Intentional fallthrough */ + case MBEDTLS_SSL_HANDSHAKE_WRAPUP: /* Intentional fallthrough */ + case MBEDTLS_SSL_HANDSHAKE_OVER: + switch (scenario) { + case TEST_EARLY_DATA_ACCEPTED: + TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); + TEST_EQUAL(client_ep.ssl.state, client_state); + break; + } + break; + + default: + TEST_FAIL("Unexpected state."); + } + + mbedtls_test_mock_socket_close(&(client_ep.socket)); + mbedtls_test_mock_socket_close(&(server_ep.socket)); + + ret = mbedtls_ssl_session_reset(&(client_ep.ssl)); + TEST_EQUAL(ret, 0); + + ret = mbedtls_ssl_set_session(&(client_ep.ssl), &saved_session); + TEST_EQUAL(ret, 0); + + ret = mbedtls_ssl_session_reset(&(server_ep.ssl)); + TEST_EQUAL(ret, 0); + + ret = mbedtls_test_mock_socket_connect(&(client_ep.socket), + &(server_ep.socket), 1024); + TEST_EQUAL(ret, 0); + + previous_client_state = client_state; + } + +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); + PSA_DONE(); +} +/* END_CASE */ From 8fe2b01b524dc88edd6e788d9e44bf8d0a5ed516 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Fri, 26 Jan 2024 20:25:00 +0100 Subject: [PATCH 09/31] tests: write early data: Add "not sent" scenario Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.data | 3 +++ tests/suites/test_suite_ssl.function | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 0592a5f54..9bf44a143 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3297,3 +3297,6 @@ tls13_cli_early_data_status:TEST_EARLY_DATA_HRR TLS 1.3 write early data, early data accepted tls13_write_early_data:TEST_EARLY_DATA_ACCEPTED + +TLS 1.3 write early data, no early data indication +tls13_write_early_data:TEST_EARLY_DATA_NO_INDICATION_SENT diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 840a201fb..cf00b4e9a 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4145,6 +4145,10 @@ void tls13_write_early_data(int scenario) case TEST_EARLY_DATA_ACCEPTED: break; + case TEST_EARLY_DATA_NO_INDICATION_SENT: + client_options.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED; + break; + default: TEST_FAIL("Unknown scenario."); } @@ -4201,6 +4205,11 @@ void tls13_write_early_data(int scenario) early_data, early_data_len); + if (scenario == TEST_EARLY_DATA_NO_INDICATION_SENT) { + TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); + TEST_EQUAL(client_ep.ssl.state, client_state); + } + switch (client_state) { case MBEDTLS_SSL_CLIENT_HELLO: switch (scenario) { From 05600e26f4dd4ba5f20a8f860db9e987d49813a5 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Fri, 26 Jan 2024 10:23:31 +0100 Subject: [PATCH 10/31] tests: write early data: Add "server rejects" scenario Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.data | 3 +++ tests/suites/test_suite_ssl.function | 34 +++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 9bf44a143..15ad96c52 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3300,3 +3300,6 @@ tls13_write_early_data:TEST_EARLY_DATA_ACCEPTED TLS 1.3 write early data, no early data indication tls13_write_early_data:TEST_EARLY_DATA_NO_INDICATION_SENT + +TLS 1.3 write early data, server rejects early data +tls13_write_early_data:TEST_EARLY_DATA_SERVER_REJECTS diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index cf00b4e9a..6681c04a4 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4110,7 +4110,6 @@ void tls13_write_early_data(int scenario) mbedtls_test_handshake_test_options client_options; mbedtls_test_handshake_test_options server_options; mbedtls_ssl_session saved_session; - int client_state, previous_client_state; const char *early_data_string = "This is early data."; const unsigned char *early_data = (const unsigned char *) early_data_string; @@ -4149,6 +4148,10 @@ void tls13_write_early_data(int scenario) client_options.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED; break; + case TEST_EARLY_DATA_SERVER_REJECTS: + server_options.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED; + break; + default: TEST_FAIL("Unknown scenario."); } @@ -4213,7 +4216,8 @@ void tls13_write_early_data(int scenario) switch (client_state) { case MBEDTLS_SSL_CLIENT_HELLO: switch (scenario) { - case TEST_EARLY_DATA_ACCEPTED: + case TEST_EARLY_DATA_ACCEPTED: /* Intentional fallthrough */ + case TEST_EARLY_DATA_SERVER_REJECTS: TEST_EQUAL(write_early_data_ret, early_data_len); TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); break; @@ -4222,7 +4226,8 @@ void tls13_write_early_data(int scenario) case MBEDTLS_SSL_SERVER_HELLO: switch (scenario) { - case TEST_EARLY_DATA_ACCEPTED: + case TEST_EARLY_DATA_ACCEPTED: /* Intentional fallthrough */ + case TEST_EARLY_DATA_SERVER_REJECTS: TEST_EQUAL(write_early_data_ret, early_data_len); TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); break; @@ -4231,7 +4236,8 @@ void tls13_write_early_data(int scenario) case MBEDTLS_SSL_ENCRYPTED_EXTENSIONS: switch (scenario) { - case TEST_EARLY_DATA_ACCEPTED: + case TEST_EARLY_DATA_ACCEPTED: /* Intentional fallthrough */ + case TEST_EARLY_DATA_SERVER_REJECTS: TEST_EQUAL(write_early_data_ret, early_data_len); TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS); break; @@ -4244,6 +4250,11 @@ void tls13_write_early_data(int scenario) TEST_EQUAL(write_early_data_ret, early_data_len); TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_FINISHED); break; + + case TEST_EARLY_DATA_SERVER_REJECTS: + TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_FINISHED); + break; } break; @@ -4256,13 +4267,23 @@ void tls13_write_early_data(int scenario) #if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE) case MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO: switch (scenario) { - case TEST_EARLY_DATA_ACCEPTED: + case TEST_EARLY_DATA_ACCEPTED: /* Intentional fallthrough */ + case TEST_EARLY_DATA_SERVER_REJECTS: TEST_EQUAL(write_early_data_ret, early_data_len); TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); break; } break; + case MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED: + TEST_ASSERT(scenario != TEST_EARLY_DATA_ACCEPTED); + switch (scenario) { + case TEST_EARLY_DATA_SERVER_REJECTS: + TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED); + break; + } + break; #endif /* MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE */ case MBEDTLS_SSL_CLIENT_CERTIFICATE: /* Intentional fallthrough */ @@ -4271,7 +4292,8 @@ void tls13_write_early_data(int scenario) case MBEDTLS_SSL_HANDSHAKE_WRAPUP: /* Intentional fallthrough */ case MBEDTLS_SSL_HANDSHAKE_OVER: switch (scenario) { - case TEST_EARLY_DATA_ACCEPTED: + case TEST_EARLY_DATA_ACCEPTED: /* Intentional fallthrough */ + case TEST_EARLY_DATA_SERVER_REJECTS: TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); TEST_EQUAL(client_ep.ssl.state, client_state); break; From b3d42fddaee3a2a0051c177ec39494ce24fd028d Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Fri, 26 Jan 2024 11:54:06 +0100 Subject: [PATCH 11/31] tests: write early data: Add HRR scenario Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.data | 3 + tests/suites/test_suite_ssl.function | 83 +++++++++++++++++++++++++--- 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 15ad96c52..b30fc9315 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3303,3 +3303,6 @@ tls13_write_early_data:TEST_EARLY_DATA_NO_INDICATION_SENT TLS 1.3 write early data, server rejects early data 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 diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 6681c04a4..d6a0d7487 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4110,7 +4110,12 @@ void tls13_write_early_data(int scenario) mbedtls_test_handshake_test_options client_options; mbedtls_test_handshake_test_options server_options; mbedtls_ssl_session saved_session; - int client_state, previous_client_state; + uint16_t group_list[3] = { + MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1, + MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1, + MBEDTLS_SSL_IANA_TLS_GROUP_NONE + }; + int client_state, previous_client_state, beyond_first_hello = 0; const char *early_data_string = "This is early data."; const unsigned char *early_data = (const unsigned char *) early_data_string; size_t early_data_len = strlen(early_data_string); @@ -4131,12 +4136,15 @@ void tls13_write_early_data(int scenario) 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; + if (scenario == TEST_EARLY_DATA_HRR) { + client_options.group_list = group_list; + server_options.group_list = group_list; + } ret = mbedtls_test_get_tls13_ticket(&client_options, &server_options, &saved_session); TEST_EQUAL(ret, 0); - /* * Prepare for handshake with the ticket. */ @@ -4152,6 +4160,10 @@ void tls13_write_early_data(int scenario) server_options.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED; break; + case TEST_EARLY_DATA_HRR: + server_options.group_list = group_list + 1; + break; + default: TEST_FAIL("Unknown scenario."); } @@ -4184,6 +4196,19 @@ void tls13_write_early_data(int scenario) client_state = MBEDTLS_SSL_HELLO_REQUEST; while (client_state != MBEDTLS_SSL_HANDSHAKE_OVER) { + /* In case of HRR scenario, once we have been through it, move over + * the first ClientHello and ServerHello otherwise we just keep playing + * this first part of the handshake with HRR. + */ + if ((scenario == TEST_EARLY_DATA_HRR) && (beyond_first_hello)) { + TEST_ASSERT(mbedtls_test_move_handshake_to_state( + &(client_ep.ssl), &(server_ep.ssl), + MBEDTLS_SSL_SERVER_HELLO) == 0); + TEST_ASSERT(mbedtls_test_move_handshake_to_state( + &(client_ep.ssl), &(server_ep.ssl), + MBEDTLS_SSL_CLIENT_HELLO) == 0); + } + TEST_EQUAL(mbedtls_test_move_handshake_to_state( &(client_ep.ssl), &(server_ep.ssl), previous_client_state), 0); @@ -4221,6 +4246,18 @@ void tls13_write_early_data(int scenario) TEST_EQUAL(write_early_data_ret, early_data_len); TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); break; + + case TEST_EARLY_DATA_HRR: + if (client_ep.ssl.handshake->hello_retry_request_count == 0) { + TEST_EQUAL(write_early_data_ret, early_data_len); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); + } else { + beyond_first_hello = 1; + TEST_EQUAL(write_early_data_ret, + MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_CLIENT_HELLO); + } + break; } break; @@ -4231,6 +4268,17 @@ void tls13_write_early_data(int scenario) TEST_EQUAL(write_early_data_ret, early_data_len); TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); break; + + case TEST_EARLY_DATA_HRR: + if (client_ep.ssl.handshake->hello_retry_request_count == 0) { + TEST_EQUAL(write_early_data_ret, early_data_len); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); + } else { + TEST_EQUAL(write_early_data_ret, + MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); + } + break; } break; @@ -4241,6 +4289,11 @@ void tls13_write_early_data(int scenario) TEST_EQUAL(write_early_data_ret, early_data_len); TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS); break; + + case TEST_EARLY_DATA_HRR: + TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS); + break; } break; @@ -4255,6 +4308,11 @@ void tls13_write_early_data(int scenario) TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_FINISHED); break; + + case TEST_EARLY_DATA_HRR: + TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_FINISHED); + break; } break; @@ -4268,19 +4326,29 @@ void tls13_write_early_data(int scenario) case MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO: switch (scenario) { case TEST_EARLY_DATA_ACCEPTED: /* Intentional fallthrough */ - case TEST_EARLY_DATA_SERVER_REJECTS: + case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */ + case TEST_EARLY_DATA_HRR: TEST_EQUAL(write_early_data_ret, early_data_len); TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); break; } break; + case MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO: + TEST_EQUAL(scenario, TEST_EARLY_DATA_HRR); + TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); + TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO); + break; + case MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED: TEST_ASSERT(scenario != TEST_EARLY_DATA_ACCEPTED); switch (scenario) { - case TEST_EARLY_DATA_SERVER_REJECTS: - TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); - TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED); + case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */ + case TEST_EARLY_DATA_HRR: + TEST_EQUAL(write_early_data_ret, + MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); + TEST_EQUAL(client_ep.ssl.state, + MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED); break; } break; @@ -4293,7 +4361,8 @@ void tls13_write_early_data(int scenario) case MBEDTLS_SSL_HANDSHAKE_OVER: switch (scenario) { case TEST_EARLY_DATA_ACCEPTED: /* Intentional fallthrough */ - case TEST_EARLY_DATA_SERVER_REJECTS: + case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */ + case TEST_EARLY_DATA_HRR: TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); TEST_EQUAL(client_ep.ssl.state, client_state); break; From e273f7203dfa7d6533ed868a02a4a8ae73138a66 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Tue, 13 Feb 2024 18:22:26 +0100 Subject: [PATCH 12/31] tls13: client: Improve CCS handling Call unconditionally the CCS writing function when sending a CCS may be necessary in the course of an handshake. Enforce in the writing function and only in the writing function that only one CCS is sent. Signed-off-by: Ronald Cron --- library/ssl_tls13_client.c | 18 ++++++------------ library/ssl_tls13_generic.c | 6 ++++++ library/ssl_tls13_server.c | 9 +++------ 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index 5d7a49590..cedebad29 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -3063,23 +3063,17 @@ int mbedtls_ssl_tls13_handshake_client_step(mbedtls_ssl_context *ssl) */ #if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE) case MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO: - ret = 0; - if (ssl->handshake->ccs_count == 0) { - ret = mbedtls_ssl_tls13_write_change_cipher_spec(ssl); - if (ret != 0) { - break; - } + ret = mbedtls_ssl_tls13_write_change_cipher_spec(ssl); + if (ret != 0) { + break; } mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_CLIENT_HELLO); break; case MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED: - ret = 0; - if (ssl->handshake->ccs_count == 0) { - ret = mbedtls_ssl_tls13_write_change_cipher_spec(ssl); - if (ret != 0) { - break; - } + ret = mbedtls_ssl_tls13_write_change_cipher_spec(ssl); + if (ret != 0) { + break; } mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE); break; diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index 386a75402..c6bb77027 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -1379,6 +1379,12 @@ int mbedtls_ssl_tls13_write_change_cipher_spec(mbedtls_ssl_context *ssl) MBEDTLS_SSL_DEBUG_MSG(2, ("=> write change cipher spec")); + /* Only one CCS to send. */ + if (ssl->handshake->ccs_count > 0) { + ret = 0; + goto cleanup; + } + /* Write CCS message */ MBEDTLS_SSL_PROC_CHK(ssl_tls13_write_change_cipher_spec_body( ssl, ssl->out_msg, diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index 05693f3bf..f9f3cc571 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -3482,12 +3482,9 @@ int mbedtls_ssl_tls13_handshake_server_step(mbedtls_ssl_context *ssl) break; case MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO: - ret = 0; - if (ssl->handshake->ccs_count == 0) { - ret = mbedtls_ssl_tls13_write_change_cipher_spec(ssl); - if (ret != 0) { - break; - } + ret = mbedtls_ssl_tls13_write_change_cipher_spec(ssl); + if (ret != 0) { + break; } mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS); break; From 5fbd27055d15c8ac234a229389ff4e31977487a0 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Wed, 14 Feb 2024 10:03:36 +0100 Subject: [PATCH 13/31] tls13: Use a flag not a counter for CCS and HRR handling Signed-off-by: Ronald Cron --- library/ssl_misc.h | 17 +++++++++++------ library/ssl_tls13_client.c | 8 ++++---- library/ssl_tls13_generic.c | 4 ++-- library/ssl_tls13_server.c | 6 +++--- tests/suites/test_suite_ssl.function | 10 +++++----- 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/library/ssl_misc.h b/library/ssl_misc.h index 942d4ad22..30113d3eb 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -730,16 +730,21 @@ struct mbedtls_ssl_handshake_params { #if defined(MBEDTLS_SSL_PROTO_TLS1_3) uint8_t key_exchange_mode; /*!< Selected key exchange mode */ - /** Number of HelloRetryRequest messages received/sent from/to the server. */ - uint8_t hello_retry_request_count; + /** + * Flag indicating if, in the course of the current handshake, an + * HelloRetryRequest message has been sent by the server or received by + * the client (<> 0) or not (0). + */ + uint8_t hello_retry_request_flag; #if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE) /** - * Number of dummy change_cipher_spec (CCS) record sent. Used to send only - * one CCS per handshake without having to complicate the handshake state - * transitions. + * Flag indicating if, in the course of the current handshake, a dummy + * change_cipher_spec (CCS) record has already been sent. Used to send only + * one CCS per handshake while not complicating the handshake state + * transitions for that purpose. */ - uint8_t ccs_count; + uint8_t ccs_sent; #endif #if defined(MBEDTLS_SSL_SRV_C) diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index cedebad29..a055d4d0b 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -1180,7 +1180,7 @@ int mbedtls_ssl_tls13_write_client_hello_exts(mbedtls_ssl_context *ssl, #endif #if defined(MBEDTLS_SSL_EARLY_DATA) - if (ssl->handshake->hello_retry_request_count == 0) { + if (!ssl->handshake->hello_retry_request_flag) { if (mbedtls_ssl_conf_tls13_is_some_psk_enabled(ssl) && ssl_tls13_early_data_has_valid_ticket(ssl) && ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_ENABLED) { @@ -1497,7 +1497,7 @@ static int ssl_tls13_preprocess_server_hello(mbedtls_ssl_context *ssl, * to a HelloRetryRequest), it MUST abort the handshake with an * "unexpected_message" alert. */ - if (handshake->hello_retry_request_count > 0) { + if (handshake->hello_retry_request_flag) { MBEDTLS_SSL_DEBUG_MSG(1, ("Multiple HRRs received")); MBEDTLS_SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, @@ -1519,7 +1519,7 @@ static int ssl_tls13_preprocess_server_hello(mbedtls_ssl_context *ssl, return MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER; } - handshake->hello_retry_request_count++; + handshake->hello_retry_request_flag = 1; break; } @@ -1674,7 +1674,7 @@ static int ssl_tls13_parse_server_hello(mbedtls_ssl_context *ssl, * proposed in the HRR, we abort the handshake and send an * "illegal_parameter" alert. */ - else if ((!is_hrr) && (handshake->hello_retry_request_count > 0) && + else if ((!is_hrr) && handshake->hello_retry_request_flag && (cipher_suite != ssl->session_negotiate->ciphersuite)) { fatal_alert = MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER; } diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index c6bb77027..3e6d8d068 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -1380,7 +1380,7 @@ int mbedtls_ssl_tls13_write_change_cipher_spec(mbedtls_ssl_context *ssl) MBEDTLS_SSL_DEBUG_MSG(2, ("=> write change cipher spec")); /* Only one CCS to send. */ - if (ssl->handshake->ccs_count > 0) { + if (ssl->handshake->ccs_sent) { ret = 0; goto cleanup; } @@ -1396,7 +1396,7 @@ int mbedtls_ssl_tls13_write_change_cipher_spec(mbedtls_ssl_context *ssl) /* Dispatch message */ MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_write_record(ssl, 0)); - ssl->handshake->ccs_count++; + ssl->handshake->ccs_sent = 1; cleanup: diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index f9f3cc571..b9f8870cc 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -1535,7 +1535,7 @@ static int ssl_tls13_parse_client_hello(mbedtls_ssl_context *ssl, const unsigned char *extension_data_end; uint32_t allowed_exts = MBEDTLS_SSL_TLS1_3_ALLOWED_EXTS_OF_CH; - if (ssl->handshake->hello_retry_request_count > 0) { + if (ssl->handshake->hello_retry_request_flag) { /* Do not accept early data extension in 2nd ClientHello */ allowed_exts &= ~MBEDTLS_SSL_EXT_MASK(EARLY_DATA); } @@ -2431,7 +2431,7 @@ MBEDTLS_CHECK_RETURN_CRITICAL static int ssl_tls13_prepare_hello_retry_request(mbedtls_ssl_context *ssl) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - if (ssl->handshake->hello_retry_request_count > 0) { + if (ssl->handshake->hello_retry_request_flag) { MBEDTLS_SSL_DEBUG_MSG(1, ("Too many HRRs")); MBEDTLS_SSL_PEND_FATAL_ALERT(MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE, MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE); @@ -2478,7 +2478,7 @@ static int ssl_tls13_write_hello_retry_request(mbedtls_ssl_context *ssl) MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_finish_handshake_msg(ssl, buf_len, msg_len)); - ssl->handshake->hello_retry_request_count++; + ssl->handshake->hello_retry_request_flag = 1; #if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE) /* The server sends a dummy change_cipher_spec record immediately diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index d6a0d7487..35eef692f 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -3903,7 +3903,7 @@ void tls13_cli_early_data_status(int scenario) break; case TEST_EARLY_DATA_HRR: - if (client_ep.ssl.handshake->hello_retry_request_count == 0) { + if (!client_ep.ssl.handshake->hello_retry_request_flag) { TEST_EQUAL(client_ep.ssl.early_data_status, MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN); } else { @@ -3928,7 +3928,7 @@ void tls13_cli_early_data_status(int scenario) break; case TEST_EARLY_DATA_HRR: - if (client_ep.ssl.handshake->hello_retry_request_count == 0) { + if (!client_ep.ssl.handshake->hello_retry_request_flag) { TEST_EQUAL(client_ep.ssl.early_data_status, MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE); } else { @@ -4089,7 +4089,7 @@ void tls13_cli_early_data_status(int scenario) } while (client_ep.ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER); #if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE) - TEST_EQUAL(client_ep.ssl.handshake->ccs_count, 1); + TEST_EQUAL(client_ep.ssl.handshake->ccs_sent, 1); #endif exit: @@ -4248,7 +4248,7 @@ void tls13_write_early_data(int scenario) break; case TEST_EARLY_DATA_HRR: - if (client_ep.ssl.handshake->hello_retry_request_count == 0) { + if (!client_ep.ssl.handshake->hello_retry_request_flag) { TEST_EQUAL(write_early_data_ret, early_data_len); TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); } else { @@ -4270,7 +4270,7 @@ void tls13_write_early_data(int scenario) break; case TEST_EARLY_DATA_HRR: - if (client_ep.ssl.handshake->hello_retry_request_count == 0) { + if (!client_ep.ssl.handshake->hello_retry_request_flag) { TEST_EQUAL(write_early_data_ret, early_data_len); TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); } else { From 84dfbf488acca39c08e9e74ee029b47678800646 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Wed, 14 Feb 2024 10:38:09 +0100 Subject: [PATCH 14/31] tls13: client: Add comment about early data in 2nd ClientHello Signed-off-by: Ronald Cron --- library/ssl_tls13_client.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index a055d4d0b..215c6474c 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -1180,6 +1180,14 @@ int mbedtls_ssl_tls13_write_client_hello_exts(mbedtls_ssl_context *ssl, #endif #if defined(MBEDTLS_SSL_EARLY_DATA) + /* In the first ClientHello, write the early data indication extension if + * necessary and update the early data status. + * If an HRR has been received and thus we are currently writing the + * second ClientHello, the second ClientHello must not contain an early + * data extension and the early data status must stay as it is: + * MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT or + * MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED. + */ if (!ssl->handshake->hello_retry_request_flag) { if (mbedtls_ssl_conf_tls13_is_some_psk_enabled(ssl) && ssl_tls13_early_data_has_valid_ticket(ssl) && From b9a9b1f5a5a08d5ad9f4f72a80bc4087c1003f1e Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Wed, 14 Feb 2024 11:28:05 +0100 Subject: [PATCH 15/31] tls13: Fix/Improve comments Signed-off-by: Ronald Cron --- include/mbedtls/ssl.h | 30 +++++++++++++++--------------- library/ssl_misc.h | 28 ++++++++++++++-------------- tests/include/test/ssl_helpers.h | 4 +--- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 9583a15be..7299bbbd7 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -1657,31 +1657,31 @@ struct mbedtls_ssl_context { #endif /* MBEDTLS_SSL_RENEGOTIATION */ /** - * Maximum TLS version to be negotiated, then negotiated TLS version. + * Maximum TLS version to be negotiated, then negotiated TLS version. * - * It is initialized as the configured maximum TLS version to be - * negotiated by mbedtls_ssl_setup(). + * It is initialized as the configured maximum TLS version to be + * negotiated by mbedtls_ssl_setup(). * - * When renegotiating or resuming a session, it is overwritten in the - * ClientHello writing preparation stage with the previously negotiated - * TLS version. + * When renegotiating or resuming a session, it is overwritten in the + * ClientHello writing preparation stage with the previously negotiated + * TLS version. * - * On client side, it is updated to the TLS version selected by the server - * for the handshake when the ServerHello is received. + * On client side, it is updated to the TLS version selected by the server + * for the handshake when the ServerHello is received. * - * On server side, it is updated to the TLS version the server selects for - * the handshake when the ClientHello is received. + * On server side, it is updated to the TLS version the server selects for + * the handshake when the ClientHello is received. */ mbedtls_ssl_protocol_version MBEDTLS_PRIVATE(tls_version); #if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C) /** - * Status of the negotiation of the use of early data. - * See the documentation of mbedtls_ssl_get_early_data_status() for more - * information. + * Status of the negotiation of the use of early data. + * See the documentation of mbedtls_ssl_get_early_data_status() for more + * information. * - * Reset to #MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT when the context is - * reset. + * Reset to #MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN when the context is + * reset. */ int MBEDTLS_PRIVATE(early_data_status); #endif diff --git a/library/ssl_misc.h b/library/ssl_misc.h index 30113d3eb..bccfbb299 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -665,21 +665,21 @@ struct mbedtls_ssl_handshake_params { #if defined(MBEDTLS_SSL_CLI_C) /** Minimum TLS version to be negotiated. * - * It is set up in the ClientHello writing preparation stage and used - * throughout the ClientHello writing. Not relevant anymore as soon as - * the protocol version has been negotiated thus as soon as the - * ServerHello is received. - * For a fresh handshake not linked to any previous handshake, it is - * equal to the configured minimum minor version to be negotiated. When - * renegotiating or resuming a session, it is equal to the previously - * negotiated minor version. + * It is set up in the ClientHello writing preparation stage and used + * throughout the ClientHello writing. Not relevant anymore as soon as + * the protocol version has been negotiated thus as soon as the + * ServerHello is received. + * For a fresh handshake not linked to any previous handshake, it is + * equal to the configured minimum minor version to be negotiated. When + * renegotiating or resuming a session, it is equal to the previously + * negotiated minor version. * - * There is no maximum TLS version field in this handshake context. - * From the start of the handshake, we need to define a current protocol - * version for the record layer which we define as the maximum TLS - * version to be negotiated. The `tls_version` field of the SSL context is - * used to store this maximum value until it contains the actual - * negotiated value. + * There is no maximum TLS version field in this handshake context. + * From the start of the handshake, we need to define a current protocol + * version for the record layer which we define as the maximum TLS + * version to be negotiated. The `tls_version` field of the SSL context is + * used to store this maximum value until it contains the actual + * negotiated value. */ mbedtls_ssl_protocol_version min_tls_version; #endif diff --git a/tests/include/test/ssl_helpers.h b/tests/include/test/ssl_helpers.h index 3506609ac..29f3b7cd4 100644 --- a/tests/include/test/ssl_helpers.h +++ b/tests/include/test/ssl_helpers.h @@ -607,9 +607,7 @@ int mbedtls_test_get_tls13_ticket( mbedtls_test_handshake_test_options *client_options, mbedtls_test_handshake_test_options *server_options, mbedtls_ssl_session *session); -#endif /* MBEDTLS_SSL_CLI_C && MBEDTLS_SSL_SRV_C && - MBEDTLS_SSL_PROTO_TLS1_3 && MBEDTLS_SSL_SESSION_TICKETS && - MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */ +#endif #define ECJPAKE_TEST_PWD "bla" From d6d32b9210153862daf54f259c1eea62a65f36e5 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Wed, 14 Feb 2024 12:01:50 +0100 Subject: [PATCH 16/31] tls13: Improve declaration and doc of early data status Signed-off-by: Ronald Cron --- include/mbedtls/ssl.h | 59 ++++++++++++++++++++++++++++++------- library/ssl_debug_helpers.h | 4 +++ library/ssl_misc.h | 32 -------------------- 3 files changed, 52 insertions(+), 43 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 7299bbbd7..6727419c7 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -734,6 +734,51 @@ typedef enum { } mbedtls_ssl_states; +/* + * Early data status, client side only. + */ + +#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C) +typedef enum { +/* + * The client has not sent the first ClientHello yet, it is unknown if the + * client will send an early data indication extension or not. + */ + MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN, + +/* + * See documentation of mbedtls_ssl_get_early_data_status(). + */ + MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT, + MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED, + MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED, + +/* + * The client has sent an early data indication extension in its first + * ClientHello, it has not received the response (ServerHello or + * HelloRetryRequest) from the server yet. The transform to protect early data + * is not set and early data cannot be sent yet. + */ + MBEDTLS_SSL_EARLY_DATA_STATUS_SENT, + +/* + * The client has sent an early data indication extension in its first + * ClientHello, it has not received the response (ServerHello or + * HelloRetryRequest) from the server yet. The transform to protect early data + * has been set and early data can be written now. + */ + MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE, + +/* + * The client has sent an early data indication extension in its first + * ClientHello, the server has accepted them and the client has received the + * server Finished message. It cannot send early data to the server anymore. + */ + MBEDTLS_SSL_EARLY_DATA_STATUS_SERVER_FINISHED_RECEIVED, +} mbedtls_ssl_early_data_status; + +#endif /* MBEDTLS_SSL_EARLY_DATA && MBEDTLS_SSL_CLI_C */ + /** * \brief Callback type: send data on the network. * @@ -1676,14 +1721,10 @@ struct mbedtls_ssl_context { #if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C) /** - * Status of the negotiation of the use of early data. - * See the documentation of mbedtls_ssl_get_early_data_status() for more - * information. - * - * Reset to #MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN when the context is - * reset. + * Status of the negotiation of the use of early data. Reset to + * MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN when the context is reset. */ - int MBEDTLS_PRIVATE(early_data_status); + mbedtls_ssl_early_data_status MBEDTLS_PRIVATE(early_data_status); #endif unsigned MBEDTLS_PRIVATE(badmac_seen); /*!< records with a bad MAC received */ @@ -5106,10 +5147,6 @@ int mbedtls_ssl_close_notify(mbedtls_ssl_context *ssl); #if defined(MBEDTLS_SSL_EARLY_DATA) -#define MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT 1 -#define MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED 2 -#define MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED 3 - #if defined(MBEDTLS_SSL_SRV_C) /** * \brief Read at most 'len' bytes of early data diff --git a/library/ssl_debug_helpers.h b/library/ssl_debug_helpers.h index 2b0e73772..a8e31409f 100644 --- a/library/ssl_debug_helpers.h +++ b/library/ssl_debug_helpers.h @@ -21,6 +21,10 @@ const char *mbedtls_ssl_states_str(mbedtls_ssl_states in); +#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C) +const char *mbedtls_ssl_early_data_status_str(mbedtls_ssl_early_data_status in); +#endif + const char *mbedtls_ssl_protocol_version_str(mbedtls_ssl_protocol_version in); const char *mbedtls_tls_prf_types_str(mbedtls_tls_prf_types in); diff --git a/library/ssl_misc.h b/library/ssl_misc.h index bccfbb299..d8844fcc3 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -2150,38 +2150,6 @@ int mbedtls_ssl_tls13_write_early_data_ext(mbedtls_ssl_context *ssl, unsigned char *buf, const unsigned char *end, size_t *out_len); - -#if defined(MBEDTLS_SSL_CLI_C) -/* - * The client has not sent the first ClientHello yet, it is unknown if the - * client will send an early data indication extension or not. - */ -#define MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN 0 - -/* - * The client has sent an early data indication extension in its first - * ClientHello, it has not received the response (ServerHello or - * HelloRetryRequest) from the server yet. The transform to protect early data - * is not set and early data cannot be sent yet. - */ -#define MBEDTLS_SSL_EARLY_DATA_STATUS_SENT 4 - -/* - * The client has sent an early data indication extension in its first - * ClientHello, it has not received the response (ServerHello or - * HelloRetryRequest) from the server yet. The transform to protect early data - * has been set and early data can be written now. - */ -#define MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE 5 - -/* - * The client has sent an early data indication extension in its first - * ClientHello, the server has accepted them and the client has received the - * server Finished message. It cannot send early data to the server anymore. - */ -#define MBEDTLS_SSL_EARLY_DATA_STATUS_SERVER_FINISHED_RECEIVED 6 -#endif /* MBEDTLS_SSL_CLI_C */ - #endif /* MBEDTLS_SSL_EARLY_DATA */ #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */ From 24da9917a6f57713be8e930a4d21a618c7fed733 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Thu, 15 Feb 2024 16:13:44 +0100 Subject: [PATCH 17/31] tests: ssl: early data: Add systematic default case in scenario switches In TLS 1.3 early data tests, to reduce the risk of not updating a switch over possible scenarios when adding a new scenario, add systematically a default case that fails the test. Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.function | 53 ++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 35eef692f..eb5fc120e 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -3772,6 +3772,9 @@ void tls13_early_data(int scenario) TEST_EQUAL(server_ep.ssl.handshake->early_data_accepted, 0); TEST_EQUAL(server_pattern.counter, 1); break; + + default: + TEST_FAIL("Unknown scenario."); } TEST_EQUAL(mbedtls_test_move_handshake_to_state( @@ -3911,6 +3914,9 @@ void tls13_cli_early_data_status(int scenario) MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED); } break; + + default: + TEST_FAIL("Unknown scenario."); } break; @@ -3936,6 +3942,9 @@ void tls13_cli_early_data_status(int scenario) MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED); } break; + + default: + TEST_FAIL("Unknown scenario."); } break; @@ -3956,6 +3965,9 @@ void tls13_cli_early_data_status(int scenario) TEST_EQUAL(client_ep.ssl.early_data_status, MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED); break; + + default: + TEST_FAIL("Unknown scenario."); } break; @@ -3976,6 +3988,9 @@ void tls13_cli_early_data_status(int scenario) TEST_EQUAL(client_ep.ssl.early_data_status, MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED); break; + + default: + TEST_FAIL("Unknown scenario."); } break; @@ -4002,6 +4017,9 @@ void tls13_cli_early_data_status(int scenario) TEST_EQUAL(client_ep.ssl.early_data_status, MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED); break; + + default: + TEST_FAIL("Unknown scenario."); } break; @@ -4022,12 +4040,14 @@ void tls13_cli_early_data_status(int scenario) TEST_EQUAL(client_ep.ssl.early_data_status, MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED); break; + + default: + TEST_FAIL("Unknown scenario."); } break; #if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE) case MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO: - TEST_ASSERT(scenario != TEST_EARLY_DATA_NO_INDICATION_SENT); switch (scenario) { case TEST_EARLY_DATA_ACCEPTED: /* Intentional fallthrough */ case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */ @@ -4035,6 +4055,9 @@ void tls13_cli_early_data_status(int scenario) TEST_EQUAL(client_ep.ssl.early_data_status, MBEDTLS_SSL_EARLY_DATA_STATUS_SENT); break; + + default: + TEST_FAIL("Unexpected or unknown scenario."); } break; @@ -4045,7 +4068,6 @@ void tls13_cli_early_data_status(int scenario) break; case MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED: - TEST_ASSERT(scenario != TEST_EARLY_DATA_ACCEPTED); switch (scenario) { case TEST_EARLY_DATA_NO_INDICATION_SENT: TEST_EQUAL(client_ep.ssl.early_data_status, @@ -4057,6 +4079,9 @@ void tls13_cli_early_data_status(int scenario) TEST_EQUAL(client_ep.ssl.early_data_status, MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED); break; + + default: + TEST_FAIL("Unexpected or unknown scenario."); } break; #endif /* MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE */ @@ -4080,6 +4105,9 @@ void tls13_cli_early_data_status(int scenario) TEST_EQUAL(client_ep.ssl.early_data_status, MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED); break; + + default: + TEST_FAIL("Unknown scenario."); } break; @@ -4236,6 +4264,7 @@ void tls13_write_early_data(int scenario) if (scenario == TEST_EARLY_DATA_NO_INDICATION_SENT) { TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); TEST_EQUAL(client_ep.ssl.state, client_state); + goto reset; } switch (client_state) { @@ -4258,6 +4287,9 @@ void tls13_write_early_data(int scenario) TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_CLIENT_HELLO); } break; + + default: + TEST_FAIL("Unknown scenario."); } break; @@ -4279,6 +4311,9 @@ void tls13_write_early_data(int scenario) TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); } break; + + default: + TEST_FAIL("Unknown scenario."); } break; @@ -4294,6 +4329,9 @@ void tls13_write_early_data(int scenario) TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS); break; + + default: + TEST_FAIL("Unknown scenario."); } break; @@ -4313,6 +4351,9 @@ void tls13_write_early_data(int scenario) TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_FINISHED); break; + + default: + TEST_FAIL("Unknown scenario."); } break; @@ -4331,6 +4372,8 @@ void tls13_write_early_data(int scenario) TEST_EQUAL(write_early_data_ret, early_data_len); TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO); break; + default: + TEST_FAIL("Unknown scenario."); } break; @@ -4341,7 +4384,6 @@ void tls13_write_early_data(int scenario) break; case MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED: - TEST_ASSERT(scenario != TEST_EARLY_DATA_ACCEPTED); switch (scenario) { case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */ case TEST_EARLY_DATA_HRR: @@ -4350,6 +4392,8 @@ void tls13_write_early_data(int scenario) TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED); break; + default: + TEST_FAIL("Unexpected or unknown scenario."); } break; #endif /* MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE */ @@ -4366,6 +4410,8 @@ void tls13_write_early_data(int scenario) TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); TEST_EQUAL(client_ep.ssl.state, client_state); break; + default: + TEST_FAIL("Unknown scenario."); } break; @@ -4373,6 +4419,7 @@ void tls13_write_early_data(int scenario) TEST_FAIL("Unexpected state."); } +reset: mbedtls_test_mock_socket_close(&(client_ep.socket)); mbedtls_test_mock_socket_close(&(server_ep.socket)); From 49221900b0c8edd214902014281203f297290fbb Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Wed, 21 Feb 2024 13:39:14 +0100 Subject: [PATCH 18/31] tls13: write_early_data: Add endpoint check Return in error of the API is not called from a client endpoint. Signed-off-by: Ronald Cron --- library/ssl_msg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/ssl_msg.c b/library/ssl_msg.c index f3bb32360..68f5cf10d 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -6072,6 +6072,10 @@ int mbedtls_ssl_write_early_data(mbedtls_ssl_context *ssl, return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; } + if (conf->endpoint != MBEDTLS_SSL_IS_CLIENT) { + return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; + } + if ((!mbedtls_ssl_conf_is_tls13_enabled(conf)) || (conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) || (conf->early_data_enabled != MBEDTLS_SSL_EARLY_DATA_ENABLED)) { From d4069247b828fee6423a28811e41e14ad223f768 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Wed, 21 Feb 2024 13:45:52 +0100 Subject: [PATCH 19/31] Improve comments/documentation Signed-off-by: Ronald Cron --- include/mbedtls/ssl.h | 32 +++++++++++++++++++++++++--- library/ssl_msg.c | 19 ++++++++++++----- tests/suites/test_suite_ssl.function | 7 ++++-- 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 6727419c7..83d2ab834 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -5199,17 +5199,43 @@ int mbedtls_ssl_read_early_data(mbedtls_ssl_context *ssl, * \brief Try to write exactly 'len' application data bytes while * performing the handshake (early data). * + * \warning Early data is defined in the TLS 1.3 specification, RFC 8446. + * IMPORTANT NOTE from section 2.3 of the specification: + * + * The security properties for 0-RTT data are weaker than + * those for other kinds of TLS data. Specifically: + * - This data is not forward secret, as it is encrypted + * solely under keys derived using the offered PSK. + * - There are no guarantees of non-replay between connections. + * Protection against replay for ordinary TLS 1.3 1-RTT data + * is provided via the server's Random value, but 0-RTT data + * does not depend on the ServerHello and therefore has + * weaker guarantees. This is especially relevant if the + * data is authenticated either with TLS client + * authentication or inside the application protocol. The + * same warnings apply to any use of the + * early_exporter_master_secret. + * * \note This function behaves mainly as mbedtls_ssl_write(). The * specification of mbedtls_ssl_write() relevant to TLS 1.3 * (thus not the parts specific to (D)TLS1.2) applies to this - * function and the present documentation is restricted to the - * differences with mbedtls_ssl_write(). + * function and the present documentation is mainly restricted + * to the differences with mbedtls_ssl_write(). One noticeable + * difference though is that mbedtls_ssl_write() aims to + * complete the handshake before to write application data + * while mbedtls_ssl_write_early() aims to drive the handshake + * just past the point where it is not possible to send early + * data anymore. * * \param ssl SSL context * \param buf buffer holding the data * \param len how many bytes must be written * - * \return One additional specific return value: + * \return The (non-negative) number of bytes actually written if + * successful (may be less than \p len). + * + * \return One additional specific error code compared to + * mbedtls_ssl_write(): * #MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA. * * #MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA is returned when it diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 68f5cf10d..2a6d4341b 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -6087,14 +6087,17 @@ int mbedtls_ssl_write_early_data(mbedtls_ssl_context *ssl, } /* - * If we are at the beginning of the handshake, advance the handshake just + * If we are at the beginning of the handshake, the early data status being + * equal to MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN or + * MBEDTLS_SSL_EARLY_DATA_STATUS_SENT advance the handshake just * enough to be able to send early data if possible. That way, we can * guarantee that when starting the handshake with this function we will - * send at least one record of early data. - * Otherwise, resume the handshake and if the handshake sequence stops - * waiting for some message from the server, send early data if we can. + * send at least one record of early data. Note that when the status is + * MBEDTLS_SSL_EARLY_DATA_STATUS_SENT and not yet + * MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE, we cannot send early data yet + * as the early data outbound transform has not been set as we may have to + * first send a dummy CCS in clear. */ - if ((ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN) || (ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_SENT)) { while ((ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN) || @@ -6112,6 +6115,12 @@ int mbedtls_ssl_write_early_data(mbedtls_ssl_context *ssl, } } } else { + /* + * If we are past the point where we can send early data, return + * immediatly. Otherwise, progress the handshake as much as possible to + * not delay it too much. If we reach a point where we can still send + * early data, then we will send some. + */ if ((ssl->early_data_status != MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE) && (ssl->early_data_status != MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED)) { return MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA; diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index eb5fc120e..f6319eeb8 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4217,8 +4217,11 @@ void tls13_write_early_data(int scenario) TEST_EQUAL(ret, 0); /* - * Run handshakes and test the writing of early data in each possible - * state. + * Run handshakes going one state further in the handshake sequence at each + * loop up to the point where we reach the MBEDTLS_SSL_HANDSHAKE_OVER + * state. For each reached handshake state, check the result of the call + * to mbedtls_ssl_write_early_data() and then restart the handshake from + * scratch (see reset label). */ previous_client_state = MBEDTLS_SSL_HELLO_REQUEST; client_state = MBEDTLS_SSL_HELLO_REQUEST; From b4fd47e8976585dc948e84135685a225f31c9925 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Wed, 21 Feb 2024 14:37:25 +0100 Subject: [PATCH 20/31] ssl_client2: Default to library default for early data enablement Signed-off-by: Ronald Cron --- programs/ssl/ssl_client2.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 0723be8a8..bcf44b7f8 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -52,7 +52,7 @@ int main(void) #define DFL_KEY_OPAQUE 0 #define DFL_KEY_PWD "" #define DFL_PSK "" -#define DFL_EARLY_DATA MBEDTLS_SSL_EARLY_DATA_DISABLED +#define DFL_EARLY_DATA -1 #define DFL_PSK_OPAQUE 0 #define DFL_PSK_IDENTITY "Client_identity" #define DFL_ECJPAKE_PW NULL @@ -347,7 +347,7 @@ int main(void) #if defined(MBEDTLS_SSL_EARLY_DATA) #define USAGE_EARLY_DATA \ - " early_data=%%d default: 0 (disabled)\n" \ + " early_data=%%d default: library default\n" \ " options: 0 (disabled), 1 (enabled)\n" #else #define USAGE_EARLY_DATA "" @@ -2026,7 +2026,9 @@ usage: } #if defined(MBEDTLS_SSL_EARLY_DATA) - mbedtls_ssl_conf_early_data(&conf, opt.early_data); + if (opt.early_data != DFL_EARLY_DATA) { + mbedtls_ssl_conf_early_data(&conf, opt.early_data); + } #endif /* MBEDTLS_SSL_EARLY_DATA */ if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) { @@ -3041,7 +3043,7 @@ reconnect: } #if defined(MBEDTLS_SSL_EARLY_DATA) - if (opt.early_data == MBEDTLS_SSL_EARLY_DATA_ENABLED) { + if (ssl.conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_ENABLED) { frags = 0; written = 0; do { From 0aead12706a1d340c014bfd1edc93b1aa0746638 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Wed, 21 Feb 2024 14:46:56 +0100 Subject: [PATCH 21/31] ssl_client2: Improve loop writing early data Signed-off-by: Ronald Cron --- programs/ssl/ssl_client2.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index bcf44b7f8..0597298c6 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -3050,7 +3050,7 @@ reconnect: while ((ret = mbedtls_ssl_write_early_data(&ssl, buf + written, len - written)) < 0) { if (ret == MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA) { - break; + goto end_of_early_data; } if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && @@ -3069,15 +3069,14 @@ reconnect: #endif } } - if (ret == MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA) { - break; - } frags++; written += ret; } while (written < len); } +end_of_early_data: + buf[written] = '\0'; mbedtls_printf( " %" MBEDTLS_PRINTF_SIZET " bytes of early data written in %" MBEDTLS_PRINTF_SIZET " fragments\n\n%s\n", From bf5e909467269d54e3fe21fb989b487409a9c5d4 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Wed, 21 Feb 2024 15:31:36 +0100 Subject: [PATCH 22/31] tests: write early data: Check we can complete handshake after writing Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.function | 30 +++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index f6319eeb8..b9d8c61fd 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4147,7 +4147,8 @@ void tls13_write_early_data(int scenario) const char *early_data_string = "This is early data."; const unsigned char *early_data = (const unsigned char *) early_data_string; size_t early_data_len = strlen(early_data_string); - int write_early_data_ret; + int write_early_data_ret, read_early_data_ret; + unsigned char read_buf[64]; mbedtls_platform_zeroize(&client_ep, sizeof(client_ep)); mbedtls_platform_zeroize(&server_ep, sizeof(server_ep)); @@ -4220,8 +4221,9 @@ void tls13_write_early_data(int scenario) * Run handshakes going one state further in the handshake sequence at each * loop up to the point where we reach the MBEDTLS_SSL_HANDSHAKE_OVER * state. For each reached handshake state, check the result of the call - * to mbedtls_ssl_write_early_data() and then restart the handshake from - * scratch (see reset label). + * to mbedtls_ssl_write_early_data(), make sure we can complete the + * handshake successfully and then reset the connection to restart the + * handshake from scratch. */ previous_client_state = MBEDTLS_SSL_HELLO_REQUEST; client_state = MBEDTLS_SSL_HELLO_REQUEST; @@ -4267,7 +4269,7 @@ void tls13_write_early_data(int scenario) if (scenario == TEST_EARLY_DATA_NO_INDICATION_SENT) { TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); TEST_EQUAL(client_ep.ssl.state, client_state); - goto reset; + goto complete_handshake; } switch (client_state) { @@ -4422,7 +4424,25 @@ void tls13_write_early_data(int scenario) TEST_FAIL("Unexpected state."); } -reset: +complete_handshake: + do { + ret = mbedtls_test_move_handshake_to_state( + &(server_ep.ssl), &(client_ep.ssl), + MBEDTLS_SSL_HANDSHAKE_OVER); + + if (ret == MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA) { + read_early_data_ret = mbedtls_ssl_read_early_data( + &(server_ep.ssl), read_buf, sizeof(read_buf)); + + TEST_EQUAL(read_early_data_ret, early_data_len); + } + } while (ret == MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA); + + TEST_EQUAL(ret, 0); + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + &(client_ep.ssl), &(server_ep.ssl), + MBEDTLS_SSL_HANDSHAKE_OVER), 0); + mbedtls_test_mock_socket_close(&(client_ep.socket)); mbedtls_test_mock_socket_close(&(server_ep.socket)); From 00046007023ffc2a4f05186c25620b8cc2a0599a Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Wed, 21 Feb 2024 16:00:12 +0100 Subject: [PATCH 23/31] tests: write early data: Inverse loop over state logic Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.function | 89 ++++++++++++++-------------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index b9d8c61fd..bcc0b1ff1 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4143,12 +4143,7 @@ void tls13_write_early_data(int scenario) MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1, MBEDTLS_SSL_IANA_TLS_GROUP_NONE }; - int client_state, previous_client_state, beyond_first_hello = 0; - const char *early_data_string = "This is early data."; - const unsigned char *early_data = (const unsigned char *) early_data_string; - size_t early_data_len = strlen(early_data_string); - int write_early_data_ret, read_early_data_ret; - unsigned char read_buf[64]; + int beyond_first_hello = 0; mbedtls_platform_zeroize(&client_ep, sizeof(client_ep)); mbedtls_platform_zeroize(&server_ep, sizeof(server_ep)); @@ -4225,43 +4220,15 @@ void tls13_write_early_data(int scenario) * handshake successfully and then reset the connection to restart the * handshake from scratch. */ - previous_client_state = MBEDTLS_SSL_HELLO_REQUEST; - client_state = MBEDTLS_SSL_HELLO_REQUEST; + do { + int client_state = client_ep.ssl.state; + int previous_client_state; + const char *early_data_string = "This is early data."; + const unsigned char *early_data = (const unsigned char *) early_data_string; + size_t early_data_len = strlen(early_data_string); + int write_early_data_ret, read_early_data_ret; + unsigned char read_buf[64]; - while (client_state != MBEDTLS_SSL_HANDSHAKE_OVER) { - /* In case of HRR scenario, once we have been through it, move over - * the first ClientHello and ServerHello otherwise we just keep playing - * this first part of the handshake with HRR. - */ - if ((scenario == TEST_EARLY_DATA_HRR) && (beyond_first_hello)) { - TEST_ASSERT(mbedtls_test_move_handshake_to_state( - &(client_ep.ssl), &(server_ep.ssl), - MBEDTLS_SSL_SERVER_HELLO) == 0); - TEST_ASSERT(mbedtls_test_move_handshake_to_state( - &(client_ep.ssl), &(server_ep.ssl), - MBEDTLS_SSL_CLIENT_HELLO) == 0); - } - - TEST_EQUAL(mbedtls_test_move_handshake_to_state( - &(client_ep.ssl), &(server_ep.ssl), - previous_client_state), 0); - - /* Progress the handshake from at least one state */ - while (client_ep.ssl.state == previous_client_state) { - ret = mbedtls_ssl_handshake_step(&(client_ep.ssl)); - TEST_ASSERT((ret == 0) || - (ret == MBEDTLS_ERR_SSL_WANT_READ) || - (ret == MBEDTLS_ERR_SSL_WANT_WRITE)); - if (client_ep.ssl.state != previous_client_state) { - break; - } - ret = mbedtls_ssl_handshake_step(&(server_ep.ssl)); - TEST_ASSERT((ret == 0) || - (ret == MBEDTLS_ERR_SSL_WANT_READ) || - (ret == MBEDTLS_ERR_SSL_WANT_WRITE)); - } - - client_state = client_ep.ssl.state; write_early_data_ret = mbedtls_ssl_write_early_data(&(client_ep.ssl), early_data, early_data_len); @@ -4273,6 +4240,7 @@ void tls13_write_early_data(int scenario) } switch (client_state) { + case MBEDTLS_SSL_HELLO_REQUEST: /* Intentional fallthrough */ case MBEDTLS_SSL_CLIENT_HELLO: switch (scenario) { case TEST_EARLY_DATA_ACCEPTED: /* Intentional fallthrough */ @@ -4460,7 +4428,42 @@ complete_handshake: TEST_EQUAL(ret, 0); previous_client_state = client_state; - } + if (previous_client_state == MBEDTLS_SSL_HANDSHAKE_OVER) { + break; + } + + /* In case of HRR scenario, once we have been through it, move over + * the first ClientHello and ServerHello otherwise we just keep playing + * this first part of the handshake with HRR. + */ + if ((scenario == TEST_EARLY_DATA_HRR) && (beyond_first_hello)) { + TEST_ASSERT(mbedtls_test_move_handshake_to_state( + &(client_ep.ssl), &(server_ep.ssl), + MBEDTLS_SSL_SERVER_HELLO) == 0); + TEST_ASSERT(mbedtls_test_move_handshake_to_state( + &(client_ep.ssl), &(server_ep.ssl), + MBEDTLS_SSL_CLIENT_HELLO) == 0); + } + + TEST_EQUAL(mbedtls_test_move_handshake_to_state( + &(client_ep.ssl), &(server_ep.ssl), + previous_client_state), 0); + + /* Progress the handshake from at least one state */ + while (client_ep.ssl.state == previous_client_state) { + ret = mbedtls_ssl_handshake_step(&(client_ep.ssl)); + TEST_ASSERT((ret == 0) || + (ret == MBEDTLS_ERR_SSL_WANT_READ) || + (ret == MBEDTLS_ERR_SSL_WANT_WRITE)); + if (client_ep.ssl.state != previous_client_state) { + break; + } + ret = mbedtls_ssl_handshake_step(&(server_ep.ssl)); + TEST_ASSERT((ret == 0) || + (ret == MBEDTLS_ERR_SSL_WANT_READ) || + (ret == MBEDTLS_ERR_SSL_WANT_WRITE)); + } + } while (1); exit: mbedtls_test_ssl_endpoint_free(&client_ep, NULL); From e21c2d2ce18d46818c3a22d552e9190aaebdb954 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Wed, 21 Feb 2024 16:37:16 +0100 Subject: [PATCH 24/31] tls13: cli: Add missing MBEDTLS_SSL_EARLY_DATA guards Signed-off-by: Ronald Cron --- library/ssl_tls13_client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index 215c6474c..635c703b7 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -2280,6 +2280,7 @@ cleanup: } +#if defined(MBEDTLS_SSL_EARLY_DATA) /* * Handler for MBEDTLS_SSL_END_OF_EARLY_DATA * @@ -2317,6 +2318,7 @@ cleanup: MBEDTLS_SSL_DEBUG_MSG(2, ("<= write EndOfEarlyData")); return ret; } +#endif /* MBEDTLS_SSL_EARLY_DATA */ #if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED) /* @@ -3040,9 +3042,11 @@ int mbedtls_ssl_tls13_handshake_client_step(mbedtls_ssl_context *ssl) ret = ssl_tls13_process_server_finished(ssl); break; +#if defined(MBEDTLS_SSL_EARLY_DATA) case MBEDTLS_SSL_END_OF_EARLY_DATA: ret = ssl_tls13_write_end_of_early_data(ssl); break; +#endif case MBEDTLS_SSL_CLIENT_CERTIFICATE: ret = ssl_tls13_write_client_certificate(ssl); From 9f2c3c09dfad7443e8c8bcae96b689d4fbb28a29 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Wed, 21 Feb 2024 17:03:22 +0100 Subject: [PATCH 25/31] tls13: cli: Add mbedtls_ssl_get_early_data_status() API Add mbedtls_ssl_get_early_data_status() API and its testing. Signed-off-by: Ronald Cron --- library/ssl_tls13_client.c | 25 +++++++++++++++++++++++++ tests/suites/test_suite_ssl.function | 24 ++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index 635c703b7..5fbcf45e2 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -2318,6 +2318,31 @@ cleanup: MBEDTLS_SSL_DEBUG_MSG(2, ("<= write EndOfEarlyData")); return ret; } + +int mbedtls_ssl_get_early_data_status(mbedtls_ssl_context *ssl) +{ + if ((ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER) || + (!mbedtls_ssl_is_handshake_over(ssl))) { + return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; + } + + switch (ssl->early_data_status) { + case MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT: + return MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT; + break; + + case MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED: + return MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED; + break; + + case MBEDTLS_SSL_EARLY_DATA_STATUS_SERVER_FINISHED_RECEIVED: + return MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED; + break; + + default: + return MBEDTLS_ERR_SSL_INTERNAL_ERROR; + } +} #endif /* MBEDTLS_SSL_EARLY_DATA */ #if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index bcc0b1ff1..3baa8599f 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -3895,6 +3895,11 @@ void tls13_cli_early_data_status(int scenario) (ret == MBEDTLS_ERR_SSL_WANT_WRITE)); } + if (client_ep.ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER) { + TEST_EQUAL(mbedtls_ssl_get_early_data_status(&(client_ep.ssl)), + MBEDTLS_ERR_SSL_BAD_INPUT_DATA); + } + switch (client_ep.ssl.state) { case MBEDTLS_SSL_CLIENT_HELLO: switch (scenario) { @@ -4116,6 +4121,25 @@ void tls13_cli_early_data_status(int scenario) } } while (client_ep.ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER); + ret = mbedtls_ssl_get_early_data_status(&(client_ep.ssl)); + switch (scenario) { + case TEST_EARLY_DATA_ACCEPTED: + TEST_EQUAL(ret, MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED); + break; + + case TEST_EARLY_DATA_NO_INDICATION_SENT: + TEST_EQUAL(ret, MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT); + break; + + case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */ + case TEST_EARLY_DATA_HRR: + TEST_EQUAL(ret, MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED); + break; + + default: + TEST_FAIL("Unknown scenario."); + } + #if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE) TEST_EQUAL(client_ep.ssl.handshake->ccs_sent, 1); #endif From 86d288c0d4eb0eb1d0486a781a95eaea8f051ee7 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Thu, 22 Feb 2024 11:28:29 +0100 Subject: [PATCH 26/31] tests: ssl: Rename tls13_early_data to tls13_read_early_data Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.data | 12 ++++++------ tests/suites/test_suite_ssl.function | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index b30fc9315..6cfda5d7e 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3274,14 +3274,14 @@ elliptic_curve_get_properties TLS 1.3 resume session with ticket tls13_resume_session_with_ticket -TLS 1.3 early data, early data accepted -tls13_early_data:TEST_EARLY_DATA_ACCEPTED +TLS 1.3 read early data, early data accepted +tls13_read_early_data:TEST_EARLY_DATA_ACCEPTED -TLS 1.3 early data, server rejects early data -tls13_early_data:TEST_EARLY_DATA_SERVER_REJECTS +TLS 1.3 read early data, server rejects early data +tls13_read_early_data:TEST_EARLY_DATA_SERVER_REJECTS -TLS 1.3 early data, discard after HRR -tls13_early_data:TEST_EARLY_DATA_HRR +TLS 1.3 read early data, discard after HRR +tls13_read_early_data:TEST_EARLY_DATA_HRR TLS 1.3 cli, early data status, early data accepted tls13_cli_early_data_status:TEST_EARLY_DATA_ACCEPTED diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 3baa8599f..78b022241 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -3647,12 +3647,12 @@ exit: /* END_CASE */ /* - * The !MBEDTLS_SSL_PROTO_TLS1_2 dependency of tls13_early_data() below is + * The !MBEDTLS_SSL_PROTO_TLS1_2 dependency of tls13_read_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_early_data(int scenario) +void tls13_read_early_data(int scenario) { int ret = -1; unsigned char buf[64]; From 110303fbe5c059d3c0a2d8580c5724959a0f069a Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Thu, 22 Feb 2024 11:35:21 +0100 Subject: [PATCH 27/31] tests: read early data: Add no early data indication sent scenario Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.data | 3 +++ tests/suites/test_suite_ssl.function | 21 +++++++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 6cfda5d7e..385682ae1 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -3277,6 +3277,9 @@ tls13_resume_session_with_ticket TLS 1.3 read early data, early data accepted tls13_read_early_data:TEST_EARLY_DATA_ACCEPTED +TLS 1.3 read early data, no early data indication +tls13_read_early_data:TEST_EARLY_DATA_NO_INDICATION_SENT + TLS 1.3 read early data, server rejects early data tls13_read_early_data:TEST_EARLY_DATA_SERVER_REJECTS diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 78b022241..61f38335e 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -3699,6 +3699,10 @@ void tls13_read_early_data(int scenario) case TEST_EARLY_DATA_ACCEPTED: break; + case TEST_EARLY_DATA_NO_INDICATION_SENT: + client_options.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED; + break; + case TEST_EARLY_DATA_SERVER_REJECTS: mbedtls_debug_set_threshold(3); server_pattern.pattern = @@ -3746,12 +3750,12 @@ void tls13_read_early_data(int scenario) &(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 = write_early_data(&(client_ep.ssl), (unsigned char *) early_data, - early_data_len); - TEST_EQUAL(ret, early_data_len); + if (client_ep.ssl.early_data_status != + MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT) { + ret = write_early_data(&(client_ep.ssl), (unsigned char *) early_data, + early_data_len); + TEST_EQUAL(ret, early_data_len); + } ret = mbedtls_test_move_handshake_to_state( &(server_ep.ssl), &(client_ep.ssl), @@ -3766,6 +3770,11 @@ void tls13_read_early_data(int scenario) TEST_MEMORY_COMPARE(buf, early_data_len, early_data, early_data_len); break; + case TEST_EARLY_DATA_NO_INDICATION_SENT: + TEST_EQUAL(ret, 0); + TEST_EQUAL(server_ep.ssl.handshake->early_data_accepted, 0); + break; + case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */ case TEST_EARLY_DATA_HRR: TEST_EQUAL(ret, 0); From 7d158f41ca083ac76b151b9e6df610341f67ffc1 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Thu, 22 Feb 2024 11:39:39 +0100 Subject: [PATCH 28/31] tests: read early data: Use write API to send early data Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.function | 51 ++++------------------------ 1 file changed, 6 insertions(+), 45 deletions(-) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 61f38335e..9a9548939 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -18,49 +18,6 @@ #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) -/* - * The implementation of the function should be based on - * mbedtls_ssl_write_early_data() eventually. The current version aims at - * removing the dependency on mbedtls_ssl_write_early_data() for the - * development and testing of reading early data. - */ -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 @@ -3750,11 +3707,15 @@ void tls13_read_early_data(int scenario) &(client_ep.ssl), &(server_ep.ssl), MBEDTLS_SSL_SERVER_HELLO), 0); + ret = mbedtls_ssl_write_early_data(&(client_ep.ssl), + (unsigned char *) early_data, + early_data_len); + if (client_ep.ssl.early_data_status != MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT) { - ret = write_early_data(&(client_ep.ssl), (unsigned char *) early_data, - early_data_len); TEST_EQUAL(ret, early_data_len); + } else { + TEST_EQUAL(ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA); } ret = mbedtls_test_move_handshake_to_state( From 8f1de7e029abba12d1ef7007dc603be0246bb2c0 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Thu, 22 Feb 2024 12:02:39 +0100 Subject: [PATCH 29/31] tls13: Improve documentation Signed-off-by: Ronald Cron --- include/mbedtls/ssl.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 83d2ab834..4b2206d8d 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -5256,9 +5256,11 @@ int mbedtls_ssl_read_early_data(mbedtls_ssl_context *ssl, * already completed. * * It is not possible to write early data for the SSL context - * \p ssl but this does not preclude for using it with + * \p ssl and any subsequent call to this API will return this + * error code. But this does not preclude for using it with * mbedtls_ssl_write(), mbedtls_ssl_read() or - * mbedtls_ssl_handshake(). + * mbedtls_ssl_handshake() and the handshake can be + * completed by calling one of these APIs. * * \note This function may write early data only if the SSL context * has been configured for the handshake with a PSK for which From f19989da313724e54a624c22846f18bb90cb4cba Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Thu, 22 Feb 2024 12:05:42 +0100 Subject: [PATCH 30/31] tls13: Improve sanity check in get_early_data_status Signed-off-by: Ronald Cron --- library/ssl_tls13_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index 5fbcf45e2..df0519a08 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -2321,7 +2321,7 @@ cleanup: int mbedtls_ssl_get_early_data_status(mbedtls_ssl_context *ssl) { - if ((ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER) || + if ((ssl->conf->endpoint != MBEDTLS_SSL_IS_CLIENT) || (!mbedtls_ssl_is_handshake_over(ssl))) { return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; } From dcb09ca6dfc90e7ac31855fe699eecba6586217d Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Thu, 22 Feb 2024 12:12:45 +0100 Subject: [PATCH 31/31] tests: write early data: Improve get_early_data_status testing Signed-off-by: Ronald Cron --- tests/suites/test_suite_ssl.function | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 9a9548939..394fbbc54 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4110,6 +4110,9 @@ void tls13_cli_early_data_status(int scenario) TEST_FAIL("Unknown scenario."); } + ret = mbedtls_ssl_get_early_data_status(&(server_ep.ssl)); + TEST_EQUAL(ret, MBEDTLS_ERR_SSL_BAD_INPUT_DATA); + #if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE) TEST_EQUAL(client_ep.ssl.handshake->ccs_sent, 1); #endif