From 36931c8b98876527c0095772928eb473a71917a5 Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 12:42:35 -0700 Subject: [PATCH 1/8] Ensure the SNI extension has at least OPAQUE16_LEN bytes in TLSX_SNI_GetFromBuffer. Thanks to Zou Dikai for the report. --- src/tls.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tls.c b/src/tls.c index 02a0881352a..e9c198cec7d 100644 --- a/src/tls.c +++ b/src/tls.c @@ -2800,6 +2800,9 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, } else { word16 listLen; + if (extLen < OPAQUE16_LEN) + return BUFFER_ERROR; + ato16(clientHello + offset, &listLen); offset += OPAQUE16_LEN; From d0a0c32204846009855debf36f365d668b0d723c Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 14:23:17 -0700 Subject: [PATCH 2/8] Prevent cert chain count from exceeding array max size when calling WriteCSRToBuffer. Thanks to Zou Dikai for the report. --- src/tls13.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index b963ab0e3d7..75321d84873 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -8882,7 +8882,7 @@ static word32 NextCert(byte* data, word32 length, word32* idx) * extIdx The index number of certificate status request data * for the certificate. * offset index offset - * returns Total number of bytes written. + * returns Total number of bytes written on success or negative value on error. */ static int WriteCSRToBuffer(WOLFSSL* ssl, DerBuffer** certExts, word16* extSz, word16 extSz_num) @@ -8897,6 +8897,9 @@ static int WriteCSRToBuffer(WOLFSSL* ssl, DerBuffer** certExts, word32 extIdx; DerBuffer* der; + if (extSz_num > MAX_CERT_EXTENSIONS) + return BAD_FUNC_ARG; + ext = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST); csr = ext ? (CertificateStatusRequest*)ext->data : NULL; @@ -9148,8 +9151,11 @@ static int SendTls13Certificate(WOLFSSL* ssl) if (ret != 0) return ret; - ret = WriteCSRToBuffer(ssl, &ssl->buffers.certExts[0], &extSz[0], - 1 /* +1 for leaf */ + (word16)ssl->buffers.certChainCnt); + if ((word16)(1 + ssl->buffers.certChainCnt) > MAX_CERT_EXTENSIONS) + ret = BAD_FUNC_ARG; + if (ret == 0) + ret = WriteCSRToBuffer(ssl, &ssl->buffers.certExts[0], &extSz[0], + 1 /* +1 for leaf */ + (word16)ssl->buffers.certChainCnt); if (ret < 0) return ret; totalextSz += ret; From 5d0e050271f0b5e4dbce9b6915e3dd8cc2593b57 Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 15:17:30 -0700 Subject: [PATCH 3/8] Ensure ProcessChainOCSPRequest does not exceed the length of the cert chain. Thanks to Zou Dikai for the report. --- src/tls.c | 6 ++++++ src/tls13.c | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/tls.c b/src/tls.c index e9c198cec7d..c727ed8f826 100644 --- a/src/tls.c +++ b/src/tls.c @@ -3614,6 +3614,12 @@ int ProcessChainOCSPRequest(WOLFSSL* ssl) if (chain && chain->buffer) { while (ret == 0 && pos + OPAQUE24_LEN < chain->length) { + if (i >= MAX_CERT_EXTENSIONS) { + WOLFSSL_MSG("OCSP request cert chain exceeds maximum length."); + ret = MAX_CERT_EXTENSIONS_ERR; + break; + } + c24to32(chain->buffer + pos, &der.length); pos += OPAQUE24_LEN; der.buffer = chain->buffer + pos; diff --git a/src/tls13.c b/src/tls13.c index 75321d84873..cbccb77bc54 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -8898,7 +8898,7 @@ static int WriteCSRToBuffer(WOLFSSL* ssl, DerBuffer** certExts, DerBuffer* der; if (extSz_num > MAX_CERT_EXTENSIONS) - return BAD_FUNC_ARG; + return MAX_CERT_EXTENSIONS_ERR; ext = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST); csr = ext ? (CertificateStatusRequest*)ext->data : NULL; @@ -9152,7 +9152,7 @@ static int SendTls13Certificate(WOLFSSL* ssl) return ret; if ((word16)(1 + ssl->buffers.certChainCnt) > MAX_CERT_EXTENSIONS) - ret = BAD_FUNC_ARG; + ret = MAX_CERT_EXTENSIONS_ERR; if (ret == 0) ret = WriteCSRToBuffer(ssl, &ssl->buffers.certExts[0], &extSz[0], 1 /* +1 for leaf */ + (word16)ssl->buffers.certChainCnt); From 78abd541ec91cb6f4e2a7e9c6593bff0191a73ba Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 15:30:00 -0700 Subject: [PATCH 4/8] Enforce max size of responses array in SendCertificateStatus. Thanks to Zou Dikai for the report. --- src/internal.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/internal.c b/src/internal.c index a0618516694..4bbb22ceba9 100644 --- a/src/internal.c +++ b/src/internal.c @@ -25925,6 +25925,10 @@ int SendCertificateStatus(WOLFSSL* ssl) if (idx > chain->length) break; + if ((i + 1) >= MAX_CERT_EXTENSIONS) { + ret = MAX_CERT_EXTENSIONS_ERR; + break; + } ret = CreateOcspRequest(ssl, request, cert, der.buffer, der.length, &ctxOwnsRequest); if (ret == 0) { @@ -25953,6 +25957,11 @@ int SendCertificateStatus(WOLFSSL* ssl) else { while (ret == 0 && NULL != (request = ssl->ctx->chainOcspRequest[i])) { + if ((i + 1) >= MAX_CERT_EXTENSIONS) { + ret = MAX_CERT_EXTENSIONS_ERR; + break; + } + request->ssl = ssl; ret = CheckOcspRequest(SSL_CM(ssl)->ocsp_stapling, request, &responses[++i], ssl->heap); From d6c62cca60fd30cbb8878bfce8c497acc74a308d Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 15:47:33 -0700 Subject: [PATCH 5/8] In SSL sniffer, ensure the ClientHello extension length is sufficient to read the length before attempting the actual read. Thanks to Zou Dikai for the report. --- src/sniffer.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sniffer.c b/src/sniffer.c index e8664721b15..daad3d297c2 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -4195,6 +4195,9 @@ static int ProcessClientHello(const byte* input, int* sslBytes, { word16 listLen = 0, offset = 0; + if (extLen < OPAQUE16_LEN) + return BUFFER_ERROR; + ato16(input + offset, &listLen); offset += OPAQUE16_LEN; @@ -4228,6 +4231,9 @@ static int ProcessClientHello(const byte* input, int* sslBytes, #ifdef WOLFSSL_TLS13 case EXT_KEY_SHARE: { + if (extLen < OPAQUE16_LEN) + return BUFFER_ERROR; + word16 ksLen = (word16)((input[0] << 8) | input[1]); if (ksLen + OPAQUE16_LEN > extLen) { SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); @@ -4252,6 +4258,9 @@ static int ProcessClientHello(const byte* input, int* sslBytes, word32 ticketAge; const byte *identity, *binders; + if (extLen < OPAQUE16_LEN) + return BUFFER_ERROR; + idsLen = (word16)((input[idx] << 8) | input[idx+1]); if ((word32)idsLen + OPAQUE16_LEN + idx > (word32)extLen) { SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); From 74461e42509fcf42389b70376886c0ec0d784b51 Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 16:24:40 -0700 Subject: [PATCH 6/8] Code review feedback --- src/sniffer.c | 11 ++++++++--- src/tls.c | 4 +++- src/tls13.c | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/sniffer.c b/src/sniffer.c index daad3d297c2..c00915070bc 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -4231,10 +4231,13 @@ static int ProcessClientHello(const byte* input, int* sslBytes, #ifdef WOLFSSL_TLS13 case EXT_KEY_SHARE: { - if (extLen < OPAQUE16_LEN) + word16 ksLen = 0; + if (extLen < OPAQUE16_LEN) { + SetError(BUFFER_ERROR_STR, error, session, FATAL_ERROR_STATE); return BUFFER_ERROR; + } - word16 ksLen = (word16)((input[0] << 8) | input[1]); + ksLen = (word16)((input[0] << 8) | input[1]); if (ksLen + OPAQUE16_LEN > extLen) { SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); return WOLFSSL_FATAL_ERROR; @@ -4258,8 +4261,10 @@ static int ProcessClientHello(const byte* input, int* sslBytes, word32 ticketAge; const byte *identity, *binders; - if (extLen < OPAQUE16_LEN) + if (extLen < OPAQUE16_LEN) { + SetError(BUFFER_ERROR_STR, error, session, FATAL_ERROR_STATE); return BUFFER_ERROR; + } idsLen = (word16)((input[idx] << 8) | input[idx+1]); if ((word32)idsLen + OPAQUE16_LEN + idx > (word32)extLen) { diff --git a/src/tls.c b/src/tls.c index c727ed8f826..0aab3463cf5 100644 --- a/src/tls.c +++ b/src/tls.c @@ -3615,7 +3615,9 @@ int ProcessChainOCSPRequest(WOLFSSL* ssl) if (chain && chain->buffer) { while (ret == 0 && pos + OPAQUE24_LEN < chain->length) { if (i >= MAX_CERT_EXTENSIONS) { - WOLFSSL_MSG("OCSP request cert chain exceeds maximum length."); + WOLFSSL_ERROR_MSG_EX( + "OCSP request cert chain exceeds maximum length: " + "i=%d, MAX_CERT_EXTENSIONS=%d", i, MAX_CERT_EXTENSIONS); ret = MAX_CERT_EXTENSIONS_ERR; break; } diff --git a/src/tls13.c b/src/tls13.c index cbccb77bc54..12c610d8940 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -9151,7 +9151,7 @@ static int SendTls13Certificate(WOLFSSL* ssl) if (ret != 0) return ret; - if ((word16)(1 + ssl->buffers.certChainCnt) > MAX_CERT_EXTENSIONS) + if ((1 + ssl->buffers.certChainCnt) > MAX_CERT_EXTENSIONS) ret = MAX_CERT_EXTENSIONS_ERR; if (ret == 0) ret = WriteCSRToBuffer(ssl, &ssl->buffers.certExts[0], &extSz[0], From 7251018468603c98e3f348f2aed30c354faef663 Mon Sep 17 00:00:00 2001 From: Kareem Date: Tue, 7 Apr 2026 10:26:17 -0700 Subject: [PATCH 7/8] Fix incorrect logging function name. --- src/tls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tls.c b/src/tls.c index 0aab3463cf5..71f4a107c52 100644 --- a/src/tls.c +++ b/src/tls.c @@ -3615,7 +3615,7 @@ int ProcessChainOCSPRequest(WOLFSSL* ssl) if (chain && chain->buffer) { while (ret == 0 && pos + OPAQUE24_LEN < chain->length) { if (i >= MAX_CERT_EXTENSIONS) { - WOLFSSL_ERROR_MSG_EX( + WOLFSSL_MSG_EX( "OCSP request cert chain exceeds maximum length: " "i=%d, MAX_CERT_EXTENSIONS=%d", i, MAX_CERT_EXTENSIONS); ret = MAX_CERT_EXTENSIONS_ERR; From eb8ed9ed35562c437be36a99c68406a05905ab0b Mon Sep 17 00:00:00 2001 From: Kareem Date: Wed, 15 Apr 2026 17:38:41 -0700 Subject: [PATCH 8/8] Check i against the correct variable. MAX_CERT_EXTENSIONS doesn't always equal 1 + MAX_CHAIN_DEPTH, and the latter is the length of the array. --- src/internal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal.c b/src/internal.c index 4bbb22ceba9..39b0c12fc17 100644 --- a/src/internal.c +++ b/src/internal.c @@ -25925,7 +25925,7 @@ int SendCertificateStatus(WOLFSSL* ssl) if (idx > chain->length) break; - if ((i + 1) >= MAX_CERT_EXTENSIONS) { + if ((i + 1) >= (1 + MAX_CHAIN_DEPTH)) { ret = MAX_CERT_EXTENSIONS_ERR; break; }