From ef4e11b0166f64c59306690050dbe5ac0f34c557 Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Mon, 13 Apr 2026 15:31:28 +0200 Subject: [PATCH 1/2] add missing WOLFSSL_QUIC_MAX_RECORD_CAPACITY check on the early-data path in quic_record_make() and added a unit test for it --- src/quic.c | 5 +++++ tests/quic.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/quic.c b/src/quic.c index be8c53ee38e..d178f66bceb 100644 --- a/src/quic.c +++ b/src/quic.c @@ -76,6 +76,11 @@ static QuicRecord *quic_record_make(WOLFSSL *ssl, qr->level = level; if (level == wolfssl_encryption_early_data) { qr->capacity = qr->len = (word32)len; + if (qr->capacity > WOLFSSL_QUIC_MAX_RECORD_CAPACITY) { + WOLFSSL_MSG("QUIC early data length larger than expected"); + quic_record_free(ssl, qr); + return NULL; + } } else { qr->capacity = qr->len = (word32) qr_length(data, len); diff --git a/tests/quic.c b/tests/quic.c index 29099a136ce..13266922604 100644 --- a/tests/quic.c +++ b/tests/quic.c @@ -390,6 +390,51 @@ static int test_provide_quic_data(void) { return EXPECT_RESULT(); } +static int test_quic_record_cap(void) { + EXPECT_DECLS; + WOLFSSL_CTX * ctx = NULL; + WOLFSSL * ssl = NULL; + size_t over = (size_t)WOLFSSL_QUIC_MAX_RECORD_CAPACITY + 512U * 1024U; + uint8_t * buf = NULL; + uint8_t hdr[4]; + word32 rlen; + + ExpectNotNull(buf = (uint8_t*)XMALLOC(over, NULL, DYNAMIC_TYPE_TMP_BUFFER)); + if (buf != NULL) + XMEMSET(buf, 0, over); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method())); + ExpectTrue(wolfSSL_CTX_set_quic_method(ctx, &dummy_method) == WOLFSSL_SUCCESS); + + /* early_data with over-cap length must be rejected */ + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectTrue(provide_data(ssl, wolfssl_encryption_early_data, buf, over, 1)); + wolfSSL_free(ssl); + ssl = NULL; + + /* early_data within cap must succeed */ + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectTrue(provide_data(ssl, wolfssl_encryption_early_data, buf, 1024, 0)); + wolfSSL_free(ssl); + ssl = NULL; + + /* handshake with over-cap record header must also be rejected */ + rlen = (word32)WOLFSSL_QUIC_MAX_RECORD_CAPACITY + 16U - 4U; + hdr[0] = 0x16; + hdr[1] = (byte)(rlen >> 16); + hdr[2] = (byte)(rlen >> 8); + hdr[3] = (byte)rlen; + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectTrue(provide_data(ssl, wolfssl_encryption_handshake, hdr, 4, 1)); + wolfSSL_free(ssl); + + wolfSSL_CTX_free(ctx); + if (buf != NULL) + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + printf(" test_quic_record_cap: %s\n", (EXPECT_SUCCESS()) ? pass : fail); + return EXPECT_RESULT(); +} static int test_quic_crypt(void) { EXPECT_DECLS; @@ -1939,6 +1984,7 @@ int QuicTest(void) if ((ret = test_set_quic_method()) != TEST_SUCCESS) goto leave; #ifndef NO_WOLFSSL_CLIENT if ((ret = test_provide_quic_data()) != TEST_SUCCESS) goto leave; + if ((ret = test_quic_record_cap()) != TEST_SUCCESS) goto leave; if ((ret = test_quic_crypt()) != TEST_SUCCESS) goto leave; if ((ret = test_quic_client_hello(verbose)) != TEST_SUCCESS) goto leave; #endif From 1576cf9edcbf97eff34786c55e491f33b1af45ed Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Wed, 15 Apr 2026 14:36:35 +0200 Subject: [PATCH 2/2] add exact-boundary tests at wolfssl_quic_max_record_capacity and cap+1 to catch off-by-onee mutations in the early data capacity check --- tests/quic.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/quic.c b/tests/quic.c index 13266922604..3e8ed2a4283 100644 --- a/tests/quic.c +++ b/tests/quic.c @@ -412,7 +412,21 @@ static int test_quic_record_cap(void) { wolfSSL_free(ssl); ssl = NULL; - /* early_data within cap must succeed */ + /* early_data at exactly cap must succeed */ + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectTrue(provide_data(ssl, wolfssl_encryption_early_data, buf, + WOLFSSL_QUIC_MAX_RECORD_CAPACITY, 0)); + wolfSSL_free(ssl); + ssl = NULL; + + /* early_data at cap+1 must be rejected */ + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectTrue(provide_data(ssl, wolfssl_encryption_early_data, buf, + (size_t)WOLFSSL_QUIC_MAX_RECORD_CAPACITY + 1U, 1)); + wolfSSL_free(ssl); + ssl = NULL; + + /* early_data well within cap must succeed */ ExpectNotNull(ssl = wolfSSL_new(ctx)); ExpectTrue(provide_data(ssl, wolfssl_encryption_early_data, buf, 1024, 0)); wolfSSL_free(ssl);