From 1cd585136d760ac40e1211667c1a71aacabc9f33 Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 12:42:35 -0700 Subject: [PATCH 1/7] 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 b854b8f8cd..1199e20ecd 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 257cae0272f4ba3497fab9047e1d0c422a9f4d25 Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 14:23:17 -0700 Subject: [PATCH 2/7] 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 a591532be2..78e69578c3 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -8871,7 +8871,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) @@ -8886,6 +8886,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; @@ -9137,8 +9140,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 e815571b8e001425d5cb1cf183c58f6221445ec3 Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 15:17:30 -0700 Subject: [PATCH 3/7] 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 1199e20ecd..d0fdc18028 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 78e69578c3..4dfe747363 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -8887,7 +8887,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; @@ -9141,7 +9141,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 9254bf7a515bba944f21fb307f6e45e4d967f65a Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 15:30:00 -0700 Subject: [PATCH 4/7] 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 067b7a6c08..f90e07c2b9 100644 --- a/src/internal.c +++ b/src/internal.c @@ -25909,6 +25909,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) { @@ -25937,6 +25941,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 d8fb381129ff1e46321bbdc8a89195008afc3c2e Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 15:47:33 -0700 Subject: [PATCH 5/7] 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 e8664721b1..daad3d297c 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 392f7e25135b6d5ce29e69fd8bcd508edf52c490 Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 16:24:40 -0700 Subject: [PATCH 6/7] 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 daad3d297c..c00915070b 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 d0fdc18028..dbc7924ab3 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 4dfe747363..573751c4b9 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -9140,7 +9140,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 d83ef81325a75bbfb45c9f851709b1dc4677ad60 Mon Sep 17 00:00:00 2001 From: Kareem Date: Tue, 7 Apr 2026 10:26:17 -0700 Subject: [PATCH 7/7] 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 dbc7924ab3..a329c935a6 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;