From ccfc95809b13c8c627254b532dcee97fd834b952 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Wed, 25 Mar 2026 08:36:33 +0100 Subject: [PATCH] test: dtls13: add ack test --- tests/api/test_dtls.c | 118 ++++++++++++++++++++++++++++++++++++++++++ tests/api/test_dtls.h | 4 ++ wolfssl/internal.h | 2 +- 3 files changed, 123 insertions(+), 1 deletion(-) diff --git a/tests/api/test_dtls.c b/tests/api/test_dtls.c index 16e1c93642..a72a940d95 100644 --- a/tests/api/test_dtls.c +++ b/tests/api/test_dtls.c @@ -939,6 +939,124 @@ int test_dtls13_ack_order(void) return EXPECT_RESULT(); } +int test_dtls13_ack_overflow(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + unsigned char readBuf[50]; + word32 length = 0; + int i; + + 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); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + + /* Edge case 1: one below limit - all inserts must succeed */ + for (i = 0; i < DTLS13_ACK_MAX_RECORDS - 1; i++) { + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 0), + w64From32(0, (word32)i)), 0); + } + ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, DTLS13_ACK_MAX_RECORDS - 1); + + /* Edge case 2: insert the last allowed record - must succeed */ + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 0), + w64From32(0, (word32)(DTLS13_ACK_MAX_RECORDS - 1))), 0); + ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, DTLS13_ACK_MAX_RECORDS); + + /* Writing a full-but-valid list must succeed */ + ExpectIntEQ(Dtls13WriteAckMessage(ssl_c, ssl_c->dtls13Rtx.seenRecords, + ssl_c->dtls13Rtx.seenRecordsCount, &length), 0); + + /* Edge case 3: one over limit - must be silently dropped */ + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 0), + w64From32(0, (word32)DTLS13_ACK_MAX_RECORDS)), 0); + ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, DTLS13_ACK_MAX_RECORDS); + + /* Bypass the insert guard to force the list one element over the limit, + * then verify Dtls13WriteAckMessage errors out instead of overflowing */ + ssl_c->dtls13Rtx.seenRecordsCount = 0; + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 1), + w64From32(0, (word32)DTLS13_ACK_MAX_RECORDS)), 0); + ssl_c->dtls13Rtx.seenRecordsCount = (word16)(DTLS13_ACK_MAX_RECORDS + 1); + ExpectIntEQ(Dtls13WriteAckMessage(ssl_c, ssl_c->dtls13Rtx.seenRecords, + ssl_c->dtls13Rtx.seenRecordsCount, &length), BUFFER_E); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +int test_dtls13_ack_dup_write_counter(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \ + && defined(HAVE_WRITE_DUP) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + WOLFSSL *ssl_c2 = NULL; + struct test_memio_ctx test_ctx; + unsigned char readBuf[50]; + int i; + + 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); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + /* Drain any post-handshake messages */ + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + + /* Split ssl_c: ssl_c becomes READ_DUP_SIDE, ssl_c2 becomes WRITE_DUP_SIDE */ + ExpectNotNull(ssl_c2 = wolfSSL_write_dup(ssl_c)); + + /* Cycle 1: add records, trigger handoff, verify counter is reset to 0 */ + for (i = 0; i < 5; i++) + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 3), + w64From32(0, (word32)i)), 0); + ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, 5); + ssl_c->dtls13Rtx.sendAcks = 1; + ExpectIntEQ(Dtls13DoScheduledWork(ssl_c), 0); + /* seenRecords ownership was transferred to dupWrite->sendAckList; + * seenRecordsCount must be reset to 0 — not left at 5. */ + ExpectNull(ssl_c->dtls13Rtx.seenRecords); + ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, 0); + + /* Cycle 2 (different epoch to avoid the dup-filter): verify the counter + * did not accumulate across the previous transfer. Without the fix, + * seenRecordsCount would now be 10 after this second batch. */ + for (i = 0; i < 5; i++) + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 4), + w64From32(0, (word32)i)), 0); + ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, 5); + ssl_c->dtls13Rtx.sendAcks = 1; + ExpectIntEQ(Dtls13DoScheduledWork(ssl_c), 0); + ExpectNull(ssl_c->dtls13Rtx.seenRecords); + ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, 0); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_c2); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + int test_dtls_version_checking(void) { EXPECT_DECLS; diff --git a/tests/api/test_dtls.h b/tests/api/test_dtls.h index 72a82d58b7..3593340ab6 100644 --- a/tests/api/test_dtls.h +++ b/tests/api/test_dtls.h @@ -30,6 +30,8 @@ int test_wolfSSL_dtls_cid_parse(void); int test_wolfSSL_dtls_set_pending_peer(void); int test_dtls13_epochs(void); int test_dtls13_ack_order(void); +int test_dtls13_ack_overflow(void); +int test_dtls13_ack_dup_write_counter(void); int test_dtls_version_checking(void); int test_dtls_short_ciphertext(void); int test_dtls12_record_length_mismatch(void); @@ -60,6 +62,8 @@ int test_dtls13_min_rtx_interval(void); TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_set_pending_peer), \ TEST_DECL_GROUP("dtls", test_dtls13_epochs), \ TEST_DECL_GROUP("dtls", test_dtls13_ack_order), \ + TEST_DECL_GROUP("dtls", test_dtls13_ack_overflow), \ + TEST_DECL_GROUP("dtls", test_dtls13_ack_dup_write_counter), \ TEST_DECL_GROUP("dtls", test_dtls_version_checking), \ TEST_DECL_GROUP("dtls", test_dtls_short_ciphertext), \ TEST_DECL_GROUP("dtls", test_dtls12_record_length_mismatch), \ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 0dc586a6e3..8b25a287a3 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -7244,7 +7244,7 @@ WOLFSSL_LOCAL int Dtls13GetSeq(WOLFSSL* ssl, int order, word32* seq, byte increment); WOLFSSL_LOCAL void Dtls13RtxRemoveRecord(WOLFSSL* ssl, w64wrapper epoch, w64wrapper seq); -WOLFSSL_LOCAL int Dtls13DoScheduledWork(WOLFSSL* ssl); +WOLFSSL_TEST_VIS int Dtls13DoScheduledWork(WOLFSSL* ssl); WOLFSSL_LOCAL int Dtls13DeriveSnKeys(WOLFSSL* ssl, int provision); WOLFSSL_LOCAL int Dtls13SetRecordNumberKeys(WOLFSSL* ssl, enum encrypt_side side);