From b7c3bbf1013f5facb56363f472afa2830cfdb0bc Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Wed, 18 Feb 2026 13:45:45 +0000 Subject: [PATCH] Fixes to size checking In `quic_record_transfer()`, the unsigned subtraction `qr->end - qr->start` could wrap around if `end < start`, and the subsequent `len <= 0` check was ineffective on a `word32`. Move the comparison before the subtraction so the function returns `0` safely. In `GetEchConfig()`, `XSTRLEN(config->publicName)` was assigned to a single byte, silently truncating names longer than 255 characters while `XMEMCPY` still copied the full string. Add a 255-byte length validation in both `wolfSSL_CTX_GenerateEchConfig()` and `GetEchConfig()`, and cache the length in a local variable to avoid redundant `XSTRLEN` calls. --- src/quic.c | 5 +++-- src/ssl_ech.c | 19 ++++++++++++++----- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/quic.c b/src/quic.c index 2d6e4a6c87..4860adbc68 100644 --- a/src/quic.c +++ b/src/quic.c @@ -184,13 +184,14 @@ static word32 add_rec_header(byte* output, word32 length, byte type) static sword32 quic_record_transfer(QuicRecord* qr, byte* buf, word32 sz) { - word32 len = qr->end - qr->start; + word32 len; word32 offset = 0; word32 rlen; - if (len <= 0) { + if (qr->end <= qr->start) { return 0; } + len = qr->end - qr->start; /* We check if the buf is at least RECORD_HEADER_SZ */ if (sz < RECORD_HEADER_SZ) { diff --git a/src/ssl_ech.c b/src/ssl_ech.c index 81419d8c10..c7ea7e0e61 100644 --- a/src/ssl_ech.c +++ b/src/ssl_ech.c @@ -48,6 +48,10 @@ int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName, if (ctx == NULL || publicName == NULL) return BAD_FUNC_ARG; + /* ECH spec limits public_name to 255 bytes (1-byte length prefix) */ + if (XSTRLEN(publicName) > 255) + return BAD_FUNC_ARG; + WC_ALLOC_VAR_EX(rng, WC_RNG, 1, ctx->heap, DYNAMIC_TYPE_RNG, return MEMORY_E); ret = wc_InitRng(rng); @@ -313,10 +317,16 @@ int GetEchConfig(WOLFSSL_EchConfig* config, byte* output, word32* outputLen) { int i; word16 totalLen = 0; + word16 publicNameLen; if (config == NULL || (output == NULL && outputLen == NULL)) return BAD_FUNC_ARG; + /* ECH spec limits public_name to 255 bytes (1-byte length prefix) */ + if (config->publicName == NULL || XSTRLEN(config->publicName) > 255) + return BAD_FUNC_ARG; + publicNameLen = (word16)XSTRLEN(config->publicName); + /* 2 for version */ totalLen += 2; /* 2 for length */ @@ -355,7 +365,7 @@ int GetEchConfig(WOLFSSL_EchConfig* config, byte* output, word32* outputLen) totalLen += 2; /* public name */ - totalLen += XSTRLEN(config->publicName); + totalLen += publicNameLen; /* trailing zeros */ totalLen += 2; @@ -435,13 +445,12 @@ int GetEchConfig(WOLFSSL_EchConfig* config, byte* output, word32* outputLen) output++; /* publicName len */ - *output = XSTRLEN(config->publicName); + *output = (byte)publicNameLen; output++; /* publicName */ - XMEMCPY(output, config->publicName, - XSTRLEN(config->publicName)); - output += XSTRLEN(config->publicName); + XMEMCPY(output, config->publicName, publicNameLen); + output += publicNameLen; /* terminating zeros */ c16toa(0, output);