Skip to content

Commit 98edc78

Browse files
authored
Merge pull request #10769 from rizlik/dtls13_max_handshake_sz
dtls13: add check over handshake message length
2 parents 244a6d4 + 6cc88ff commit 98edc78

4 files changed

Lines changed: 124 additions & 1 deletion

File tree

src/dtls13.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,6 +1898,21 @@ static int _Dtls13HandshakeRecv(WOLFSSL* ssl, byte* input, word32 size,
18981898
return INCOMPLETE_DATA;
18991899
}
19001900

1901+
/* Cap the handshake message size before it can be buffered for reassembly,
1902+
* matching the DTLSv1.2 path (DoDtlsHandShakeMsg()). RFC 9147 Sec 4.5.2
1903+
* says invalid records SHOULD be silently discarded, so only error out once
1904+
* the record is authenticated (received in an encrypted epoch); a plaintext
1905+
* message is just dropped. */
1906+
if (messageLength > MAX_HANDSHAKE_SZ) {
1907+
WOLFSSL_MSG("Handshake message too large");
1908+
if (IsEncryptionOn(ssl, 0)) {
1909+
WOLFSSL_ERROR_VERBOSE(HANDSHAKE_SIZE_ERROR);
1910+
return HANDSHAKE_SIZE_ERROR;
1911+
}
1912+
*processedSize = idx + fragLength;
1913+
return 0;
1914+
}
1915+
19011916
if (fragOff + fragLength > messageLength)
19021917
return BUFFER_ERROR;
19031918

tests/api/test_dtls.c

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1411,6 +1411,107 @@ int test_dtls13_short_read(void)
14111411
}
14121412
#endif /* WOLFSSL_DTLS13 && !defined(WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS) */
14131413

1414+
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13)
1415+
/* A plaintext (epoch 0) handshake message whose handshake message_length claims
1416+
* more than MAX_HANDSHAKE_SZ must not be buffered for reassembly. We use the
1417+
* server's plaintext ServerHello: the client accepts a fragmented ServerHello
1418+
* (Dtls13AcceptFragmented()), so an incomplete one is normally stored for
1419+
* reassembly. Without the message_length cap in _Dtls13HandshakeRecv() the
1420+
* spoofed message would be added to the rx list; with it the unauthenticated
1421+
* message is silently dropped. */
1422+
int test_dtls13_oversized_msg_length(void)
1423+
{
1424+
EXPECT_DECLS;
1425+
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
1426+
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
1427+
struct test_memio_ctx test_ctx;
1428+
char sh[TEST_MEMIO_BUF_SZ];
1429+
int shSz = (int)sizeof(sh);
1430+
int recLen = 0;
1431+
byte hsMsg[DTLS_HANDSHAKE_HEADER_SZ + 1];
1432+
word32 idx = 0;
1433+
1434+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
1435+
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
1436+
wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);
1437+
1438+
/* CH1 -> server, then server emits its first flight (plaintext ServerHello
1439+
* is the first record). */
1440+
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
1441+
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
1442+
ExpectIntEQ(wolfSSL_accept(ssl_s), -1);
1443+
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
1444+
ExpectIntGT(test_ctx.c_msg_count, 0);
1445+
ExpectIntEQ(test_memio_copy_message(&test_ctx, 1, sh, &shSz, 0), 0);
1446+
ExpectIntGE(shSz, DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ);
1447+
/* First record is a plaintext handshake ServerHello. */
1448+
ExpectIntEQ((byte)sh[0], handshake);
1449+
ExpectIntEQ((byte)sh[DTLS_RECORD_HEADER_SZ], server_hello);
1450+
if (EXPECT_SUCCESS())
1451+
recLen = (((byte)sh[DTLS_RECORD_HEADER_SZ - 2]) << 8) |
1452+
(byte)sh[DTLS_RECORD_HEADER_SZ - 1];
1453+
/* the ServerHello record must be fully contained in the copied message */
1454+
ExpectIntLE(DTLS_RECORD_HEADER_SZ + recLen, shSz);
1455+
1456+
/* Spoof only the handshake message_length of the ServerHello record,
1457+
* leaving the record length and fragment_length intact so it clears record
1458+
* parsing and looks like the first fragment of an oversized message. */
1459+
c32to24((word32)MAX_HANDSHAKE_SZ + 1,
1460+
(byte*)sh + DTLS_RECORD_HEADER_SZ + 1);
1461+
test_memio_clear_buffer(&test_ctx, 1);
1462+
ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, sh,
1463+
DTLS_RECORD_HEADER_SZ + recLen), 0);
1464+
1465+
/* The client must reject the oversized ServerHello without buffering it. */
1466+
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
1467+
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
1468+
ExpectNull(ssl_c->dtls_rx_msg_list);
1469+
ExpectIntEQ(ssl_c->dtls_rx_msg_list_sz, 0);
1470+
1471+
wolfSSL_free(ssl_c);
1472+
ssl_c = NULL;
1473+
wolfSSL_CTX_free(ctx_c);
1474+
ctx_c = NULL;
1475+
wolfSSL_free(ssl_s);
1476+
ssl_s = NULL;
1477+
wolfSSL_CTX_free(ctx_s);
1478+
ctx_s = NULL;
1479+
1480+
/* Stretching the test suite a bit, ideally we should not test using
1481+
* internal state, but we have no way to forge encrypted packet yet */
1482+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
1483+
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
1484+
wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);
1485+
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
1486+
if (EXPECT_SUCCESS()) {
1487+
ssl_c->keys.curEpoch64 = w64From32(0x0, DTLS13_EPOCH_TRAFFIC0);
1488+
ssl_c->keys.decryptedCur = 1;
1489+
ssl_c->curRL.pvMajor = ssl_c->version.major;
1490+
ssl_c->curRL.pvMinor = DTLSv1_2_MINOR;
1491+
}
1492+
XMEMSET(hsMsg, 0, sizeof(hsMsg));
1493+
hsMsg[0] = key_update;
1494+
/* oversized message_length, single-byte first fragment of it */
1495+
c32to24((word32)MAX_HANDSHAKE_SZ + 1, hsMsg + 1);
1496+
hsMsg[DTLS_HANDSHAKE_HEADER_SZ - 1] = 1;
1497+
ExpectIntEQ(Dtls13HandshakeRecv(ssl_c, hsMsg, &idx, (word32)sizeof(hsMsg)),
1498+
HANDSHAKE_SIZE_ERROR);
1499+
ExpectNull(ssl_c->dtls_rx_msg_list);
1500+
1501+
wolfSSL_free(ssl_c);
1502+
wolfSSL_CTX_free(ctx_c);
1503+
wolfSSL_free(ssl_s);
1504+
wolfSSL_CTX_free(ctx_s);
1505+
1506+
return EXPECT_RESULT();
1507+
}
1508+
#else
1509+
int test_dtls13_oversized_msg_length(void)
1510+
{
1511+
return TEST_SKIPPED;
1512+
}
1513+
#endif /* HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES && WOLFSSL_DTLS13 */
1514+
14141515
#if !defined(WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS)
14151516
int test_dtls12_short_read(void)
14161517
{
@@ -1658,6 +1759,10 @@ int test_dtls13_longer_length(void)
16581759
{
16591760
return TEST_SKIPPED;
16601761
}
1762+
int test_dtls13_oversized_msg_length(void)
1763+
{
1764+
return TEST_SKIPPED;
1765+
}
16611766
int test_dtls_record_cross_boundaries(void)
16621767
{
16631768
return TEST_SKIPPED;

tests/api/test_dtls.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ int test_dtls12_record_length_mismatch(void);
3737
int test_dtls12_short_read(void);
3838
int test_dtls13_longer_length(void);
3939
int test_dtls13_short_read(void);
40+
int test_dtls13_oversized_msg_length(void);
4041
int test_records_span_network_boundaries(void);
4142
int test_dtls_record_cross_boundaries(void);
4243
int test_dtls_rtx_across_epoch_change(void);
@@ -124,6 +125,7 @@ int test_WOLFSSL_dtls_version_alert(void);
124125
TEST_DECL_GROUP("dtls", test_dtls12_short_read), \
125126
TEST_DECL_GROUP("dtls", test_dtls13_longer_length), \
126127
TEST_DECL_GROUP("dtls", test_dtls13_short_read), \
128+
TEST_DECL_GROUP("dtls", test_dtls13_oversized_msg_length), \
127129
TEST_DECL_GROUP("dtls", test_records_span_network_boundaries), \
128130
TEST_DECL_GROUP("dtls", test_dtls_record_cross_boundaries), \
129131
TEST_DECL_GROUP("dtls", test_dtls_rtx_across_epoch_change), \

wolfssl/internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7461,6 +7461,7 @@ WOLFSSL_LOCAL void DtlsSetSeqNumForReply(WOLFSSL* ssl);
74617461
#ifdef WOLFSSL_API_PREFIX_MAP
74627462
#define Dtls13GetEpoch wolfSSL_Dtls13GetEpoch
74637463
#define Dtls13CheckEpoch wolfSSL_Dtls13CheckEpoch
7464+
#define Dtls13HandshakeRecv wolfSSL_Dtls13HandshakeRecv
74647465
#define Dtls13WriteAckMessage wolfSSL_Dtls13WriteAckMessage
74657466
#define Dtls13RtxAddAck wolfSSL_Dtls13RtxAddAck
74667467
#define Dtls13DoScheduledWork wolfSSL_Dtls13DoScheduledWork
@@ -7505,7 +7506,7 @@ WOLFSSL_LOCAL int Dtls13HandshakeSend(WOLFSSL* ssl, byte* output,
75057506
int hash_output);
75067507
WOLFSSL_LOCAL int Dtls13RecordRecvd(WOLFSSL* ssl);
75077508
WOLFSSL_TEST_VIS int Dtls13CheckEpoch(WOLFSSL* ssl, enum HandShakeType type);
7508-
WOLFSSL_LOCAL int Dtls13HandshakeRecv(WOLFSSL* ssl, byte* input,
7509+
WOLFSSL_TEST_VIS int Dtls13HandshakeRecv(WOLFSSL* ssl, byte* input,
75097510
word32* inOutIdx, word32 totalSz);
75107511
WOLFSSL_LOCAL int Dtls13HandshakeAddHeader(WOLFSSL* ssl, byte* output,
75117512
enum HandShakeType msg_type, word32 length);

0 commit comments

Comments
 (0)