From c87339e5c324c78dd7f5d521b32a084c51cada93 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Wed, 29 Nov 2023 15:55:59 +0100 Subject: [PATCH] dtls13: Add support for 0.5-RTT data --- src/internal.c | 37 +++++++++++++++++++++++++++++++------ src/ssl.c | 10 ++++++++-- tests/api.c | 18 ++++++++++++++++-- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/src/internal.c b/src/internal.c index d69696f65..b7c8111a8 100644 --- a/src/internal.c +++ b/src/internal.c @@ -19597,7 +19597,8 @@ int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx, int sniff) return BUFFER_ERROR; } #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData > early_data_ext) { + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->earlyData > early_data_ext) { if (ssl->earlyDataSz + dataSz > ssl->options.maxEarlyDataSz) { if (sniff == NO_SNIFF) { SendAlert(ssl, alert_fatal, unexpected_message); @@ -19637,6 +19638,15 @@ int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx, int sniff) #endif *inOutIdx = idx; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.connectState == WAIT_FINISHED_ACK) { + /* Reset the processReply state since + * we finished processing this message. */ + ssl->options.processReply = doProcessInit; + /* DTLS 1.3 is waiting for an ACK but we can still return app data. */ + return APP_DATA_READY; + } +#endif #ifdef HAVE_SECURE_RENEGOTIATION if (IsSCR(ssl)) { /* Reset the processReply state since @@ -20234,7 +20244,7 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) #endif if (ssl->error != 0 && ssl->error != WANT_READ && ssl->error != WANT_WRITE - #ifdef HAVE_SECURE_RENEGOTIATION + #if defined(HAVE_SECURE_RENEGOTIATION) || defined(WOLFSSL_DTLS13) && ssl->error != APP_DATA_READY #endif #ifdef WOLFSSL_ASYNC_CRYPT @@ -21258,9 +21268,18 @@ default: /* input exhausted */ if (ssl->buffers.inputBuffer.idx >= ssl->buffers.inputBuffer.length #ifdef WOLFSSL_DTLS - /* If app data was processed then return now to avoid - * dropping any app data. */ - || (ssl->options.dtls && ssl->curRL.type == application_data) + || (ssl->options.dtls && + /* If app data was processed then return now to avoid + * dropping any app data. */ + (ssl->curRL.type == application_data || + /* client: if we processed a finished message, return to + * allow higher layers to establish the crypto + * parameters of the connection. The remaining data + * may be app data that we would drop without the + * crypto setup. */ + (ssl->options.side == WOLFSSL_CLIENT_END && + ssl->options.serverState == SERVER_FINISHED_COMPLETE && + ssl->options.handShakeState != HANDSHAKE_DONE))) #endif ) { /* Shrink input buffer when we successfully finish record @@ -23586,6 +23605,12 @@ int SendData(WOLFSSL* ssl, const void* data, int sz) groupMsgs = 1; #endif } + else if (IsAtLeastTLSv1_3(ssl->version) && + ssl->options.side == WOLFSSL_SERVER_END && + ssl->options.acceptState >= TLS13_ACCEPT_FINISHED_SENT) { + /* We can send data without waiting on peer finished msg */ + WOLFSSL_MSG("server sending data before receiving client finished"); + } else #endif if (ssl->options.handShakeState != HANDSHAKE_DONE && !IsSCR(ssl)) { @@ -23823,7 +23848,7 @@ int ReceiveData(WOLFSSL* ssl, byte* output, int sz, int peek) #ifdef WOLFSSL_ASYNC_CRYPT && ssl->error != WC_PENDING_E #endif -#ifdef HAVE_SECURE_RENEGOTIATION +#if defined(HAVE_SECURE_RENEGOTIATION) || defined(WOLFSSL_DTLS13) && ssl->error != APP_DATA_READY #endif ) { diff --git a/src/ssl.c b/src/ssl.c index 275fa5f71..e27e5b904 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -3233,8 +3233,14 @@ int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz) } #endif #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData != no_early_data && (ret = wolfSSL_negotiate(ssl)) < 0) { - ssl->error = ret; + if (IsAtLeastTLSv1_3(ssl->version) && + ssl->options.side == WOLFSSL_SERVER_END && + ssl->options.acceptState >= TLS13_ACCEPT_FINISHED_SENT) { + /* We can send data without waiting on peer finished msg */ + WOLFSSL_MSG("server sending data before receiving client finished"); + } + else if (ssl->earlyData != no_early_data && + (ret = wolfSSL_negotiate(ssl)) < 0) { return WOLFSSL_FATAL_ERROR; } ssl->earlyData = no_early_data; diff --git a/tests/api.c b/tests/api.c index fffd51249..e71f7a48d 100644 --- a/tests/api.c +++ b/tests/api.c @@ -68124,6 +68124,7 @@ static int test_dtls13_early_data(void) char msg[] = "This is early data"; char msg2[] = "This is client data"; char msg3[] = "This is server data"; + char msg4[] = "This is server immediate data"; char msgBuf[50]; XMEMSET(&test_ctx, 0, sizeof(test_ctx)); @@ -68151,6 +68152,7 @@ static int test_dtls13_early_data(void) ExpectIntEQ(wolfSSL_disable_hrr_cookie(ssl_s), WOLFSSL_SUCCESS); #endif + /* Test 0-RTT data */ ExpectIntEQ(wolfSSL_write_early_data(ssl_c, msg, sizeof(msg), &written), sizeof(msg)); ExpectIntEQ(written, sizeof(msg)); @@ -68160,6 +68162,15 @@ static int test_dtls13_early_data(void) ExpectIntEQ(read, sizeof(msg)); ExpectStrEQ(msg, msgBuf); + /* Test 0.5-RTT data */ + ExpectIntEQ(wolfSSL_write(ssl_s, msg4, sizeof(msg4)), sizeof(msg4)); + + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), APP_DATA_READY); + + ExpectIntEQ(wolfSSL_read(ssl_c, msgBuf, sizeof(msgBuf)), sizeof(msg4)); + ExpectStrEQ(msg4, msgBuf); + /* Complete handshake */ ExpectIntEQ(wolfSSL_connect(ssl_c), -1); ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); @@ -68171,11 +68182,14 @@ static int test_dtls13_early_data(void) * parsing logic. */ ExpectFalse(wolfSSL_is_init_finished(ssl_s)); ExpectIntEQ(wolfSSL_read_early_data(ssl_s, msgBuf, sizeof(msgBuf), - &read), WOLFSSL_FAILURE); - ExpectTrue(wolfSSL_is_init_finished(ssl_s)); + &read), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); + ExpectTrue(wolfSSL_is_init_finished(ssl_s)); + + /* Test bi-directional write */ ExpectIntEQ(wolfSSL_write(ssl_c, msg2, sizeof(msg2)), sizeof(msg2)); ExpectIntEQ(wolfSSL_read(ssl_s, msgBuf, sizeof(msgBuf)), sizeof(msg2));