Skip to content

Commit

Permalink
DTLS 1.3: Don't error out on app data before finishing handshake
Browse files Browse the repository at this point in the history
  • Loading branch information
julek-wolfssl committed Nov 4, 2024
1 parent bdd6231 commit feca641
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 25 deletions.
59 changes: 34 additions & 25 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -20642,32 +20642,41 @@ int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx, int sniff)
byte decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA];
#endif

#ifdef WOLFSSL_EARLY_DATA
if (ssl->options.tls1_3 && ssl->options.handShakeDone == 0) {
int process = 0;

if (ssl->options.side == WOLFSSL_SERVER_END) {
if ((ssl->earlyData != no_early_data) &&
(ssl->options.clientState == CLIENT_HELLO_COMPLETE)) {
process = 1;
}
if (!process) {
WOLFSSL_MSG("Ignoring EarlyData!");
*inOutIdx += ssl->curSize;
if (*inOutIdx > ssl->buffers.inputBuffer.length)
return BUFFER_E;

return 0;
}
}
if (!process) {
WOLFSSL_MSG("Received App data before a handshake completed");
if (sniff == NO_SNIFF) {
SendAlert(ssl, alert_fatal, unexpected_message);
}
WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E);
return OUT_OF_ORDER_E;
}
#ifdef WOLFSSL_EARLY_DATA
if (ssl->options.tls1_3 && ssl->options.handShakeDone == 0 &&
ssl->options.side == WOLFSSL_SERVER_END &&
ssl->earlyData != no_early_data &&
ssl->options.clientState == CLIENT_HELLO_COMPLETE) {
WOLFSSL_MSG("Processing EarlyData");
}
else if (ssl->options.tls1_3 && ssl->options.handShakeDone == 0 &&
ssl->options.side == WOLFSSL_SERVER_END &&
!(ssl->earlyData != no_early_data &&
ssl->options.clientState == CLIENT_HELLO_COMPLETE)) {
WOLFSSL_MSG("Ignoring EarlyData!");
*inOutIdx += ssl->curSize;
if (*inOutIdx > ssl->buffers.inputBuffer.length)
return BUFFER_E;
#ifdef WOLFSSL_DTLS13
/* Receiving app data from the traffic epoch before the handshake is
* done means that there was a disruption. */
if (ssl->options.dtls &&
!w64Equal(ssl->keys.curEpoch64,
w64From32(0x0, DTLS13_EPOCH_EARLYDATA)))
ssl->dtls13Rtx.sendAcks = 1;
#endif
return 0;
}
else
#endif
#ifdef WOLFSSL_DTLS
if (ssl->options.handShakeDone == 0 && ssl->options.dtls) {
WOLFSSL_MSG("Dropping app data received before handshake complete");
*inOutIdx += ssl->curSize;
if (*inOutIdx > ssl->buffers.inputBuffer.length)
return BUFFER_E;
return 0;
}
else
#endif
Expand Down
124 changes: 124 additions & 0 deletions tests/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -96282,6 +96282,128 @@ static int test_dtls13_basic_connection_id(void)
return EXPECT_RESULT();
}

static int test_dtls12_missing_finished(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
const char test_str[] = "test string";
char test_buf[sizeof(test_str)];

XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0);

/* CH1 */
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
/* HVR */
ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
/* CH2 */
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
/* Server first flight */
ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
/* Client second flight with finished */
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
/* Server second flight with finished */
ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1);
/* Let's clear the output */
test_ctx.c_len = 0;
/* Let's send some app data */
ExpectIntEQ(wolfSSL_write(ssl_s, test_str, sizeof(test_str)),
sizeof(test_str));
/* Client should not error out on a missing finished */
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
/* Server rtx second flight with finished */
ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), 1);
/* Client process rest of handshake */
ExpectIntEQ(wolfSSL_negotiate(ssl_c), 1);

/* Let's send some app data */
ExpectIntEQ(wolfSSL_write(ssl_s, test_str, sizeof(test_str)),
sizeof(test_str));
ExpectIntEQ(wolfSSL_read(ssl_c, test_buf, sizeof(test_buf)),
sizeof(test_str));
ExpectBufEQ(test_buf, test_str, sizeof(test_str));

wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}

static int test_dtls13_missing_finished(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
const char test_str[] = "test string";
char test_buf[sizeof(test_str)];

XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);

/* CH1 */
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
/* HRR */
ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
/* CH2 */
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
/* Server first flight with finished */
ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
/* Client second flight with finished */
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
/* Let's clear the output */
test_ctx.s_len = 0;
/* We should signal that the handshake is done */
ExpectTrue(wolfSSL_is_init_finished(ssl_c));
/* Let's send some app data */
ExpectIntEQ(wolfSSL_write(ssl_c, test_str, sizeof(test_str)),
sizeof(test_str));
/* Server should not error out on a missing finished */
ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
/* Client rtx second flight with finished */
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
/* Server first flight with finished */
ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1);
/* Let's send some app data */
ExpectIntEQ(wolfSSL_write(ssl_c, test_str, sizeof(test_str)),
sizeof(test_str));
ExpectIntEQ(wolfSSL_read(ssl_s, test_buf, sizeof(test_buf)),
sizeof(test_str));
ExpectBufEQ(test_buf, test_str, sizeof(test_str));

wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}

#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \
defined(HAVE_LIBOQS)
static void test_tls13_pq_groups_ctx_ready(WOLFSSL_CTX* ctx)
Expand Down Expand Up @@ -98689,6 +98811,8 @@ TEST_CASE testCases[] = {
TEST_DECL(test_dtls_old_seq_number),
TEST_DECL(test_dtls12_basic_connection_id),
TEST_DECL(test_dtls13_basic_connection_id),
TEST_DECL(test_dtls12_missing_finished),
TEST_DECL(test_dtls13_missing_finished),
TEST_DECL(test_tls13_pq_groups),
TEST_DECL(test_tls13_early_data),
TEST_DECL(test_tls_multi_handshakes_one_record),
Expand Down

0 comments on commit feca641

Please sign in to comment.