Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/dtls13.c
Original file line number Diff line number Diff line change
Expand Up @@ -1889,6 +1889,21 @@ static int _Dtls13HandshakeRecv(WOLFSSL* ssl, byte* input, word32 size,
return INCOMPLETE_DATA;
}

/* Cap the handshake message size before it can be buffered for reassembly,
* matching the DTLSv1.2 path (DoDtlsHandShakeMsg()). RFC 9147 Sec 4.5.2
* says invalid records SHOULD be silently discarded, so only error out once
* the record is authenticated (received in an encrypted epoch); a plaintext
* message is just dropped. */
Comment on lines +1892 to +1896
if (messageLength > MAX_HANDSHAKE_SZ) {
WOLFSSL_MSG("Handshake message too large");
if (IsEncryptionOn(ssl, 0)) {
WOLFSSL_ERROR_VERBOSE(HANDSHAKE_SIZE_ERROR);
return HANDSHAKE_SIZE_ERROR;
}
*processedSize = idx + fragLength;
return 0;
}

if (fragOff + fragLength > messageLength)
return BUFFER_ERROR;

Expand Down
66 changes: 66 additions & 0 deletions tests/api/test_dtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,72 @@ int test_dtls13_short_read(void)
}
#endif /* WOLFSSL_DTLS13 && !defined(WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS) */

#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13)
/* A plaintext (epoch 0) handshake message whose handshake message_length claims
* more than MAX_HANDSHAKE_SZ must not be buffered for reassembly. We use the
* server's plaintext ServerHello: the client accepts a fragmented ServerHello
* (Dtls13AcceptFragmented()), so an incomplete one is normally stored for
* reassembly. Without the message_length cap in _Dtls13HandshakeRecv() the
* spoofed message would be added to the rx list; with it the unauthenticated
* message is silently dropped. */
int test_dtls13_oversized_msg_length(void)
{
EXPECT_DECLS;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
struct test_memio_ctx test_ctx;
char sh[TEST_MEMIO_BUF_SZ];
int shSz = (int)sizeof(sh);
int recLen = 0;

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 -> server, then server emits its first flight (plaintext ServerHello
* is the first record). */
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectIntEQ(wolfSSL_accept(ssl_s), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
ExpectIntGT(test_ctx.c_msg_count, 0);
ExpectIntEQ(test_memio_copy_message(&test_ctx, 1, sh, &shSz, 0), 0);
ExpectIntGE(shSz, DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ);
/* First record is a plaintext handshake ServerHello. */
ExpectIntEQ((byte)sh[0], handshake);
ExpectIntEQ((byte)sh[DTLS_RECORD_HEADER_SZ], server_hello);
if (EXPECT_SUCCESS())
recLen = (((byte)sh[11]) << 8) | (byte)sh[12];

/* Spoof only the handshake message_length of the ServerHello record,
* leaving the record length and fragment_length intact so it clears record
* parsing and looks like the first fragment of an oversized message. */
c32to24((word32)MAX_HANDSHAKE_SZ + 1,
(byte*)sh + DTLS_RECORD_HEADER_SZ + 1);
test_memio_clear_buffer(&test_ctx, 1);
ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, sh,
DTLS_RECORD_HEADER_SZ + recLen), 0);

/* The client must reject the oversized ServerHello without buffering it. */
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectNull(ssl_c->dtls_rx_msg_list);
ExpectIntEQ(ssl_c->dtls_rx_msg_list_sz, 0);

wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);

return EXPECT_RESULT();
}
#else
int test_dtls13_oversized_msg_length(void)
{
return TEST_SKIPPED;
}
#endif

#if !defined(WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS)
int test_dtls12_short_read(void)
{
Expand Down
2 changes: 2 additions & 0 deletions tests/api/test_dtls.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ int test_dtls12_record_length_mismatch(void);
int test_dtls12_short_read(void);
int test_dtls13_longer_length(void);
int test_dtls13_short_read(void);
int test_dtls13_oversized_msg_length(void);
int test_records_span_network_boundaries(void);
int test_dtls_record_cross_boundaries(void);
int test_dtls_rtx_across_epoch_change(void);
Expand Down Expand Up @@ -111,6 +112,7 @@ int test_WOLFSSL_dtls_version_alert(void);
TEST_DECL_GROUP("dtls", test_dtls12_short_read), \
TEST_DECL_GROUP("dtls", test_dtls13_longer_length), \
TEST_DECL_GROUP("dtls", test_dtls13_short_read), \
TEST_DECL_GROUP("dtls", test_dtls13_oversized_msg_length), \
TEST_DECL_GROUP("dtls", test_records_span_network_boundaries), \
TEST_DECL_GROUP("dtls", test_dtls_record_cross_boundaries), \
TEST_DECL_GROUP("dtls", test_dtls_rtx_across_epoch_change), \
Expand Down
Loading