Harden chain depth bounds and parser input validation

Enforce MAX_CHAIN_DEPTH limits in OCSP chain processing
(SendCertificateStatus, ProcessChainOCSPRequest), certificate loading
(ProcessUserChain), and TLS 1.3 certificate sending
(SendTls13Certificate). Add idx bounds checks to chain accessors
in ssl.c.

Harden SNI extension parser (TLSX_SNI_GetFromBuffer) with length
checks preventing buffer overreads on malformed ClientHello.

Fix off-by-one in TLSX_CSR_Free where <= should be < since
csr->requests is a count, not a max index.

Add remaining-buffer bounds checks to PKCS7 decoders:
DecodeEnvelopedData, DecodeAuthEnvelopedData (encryptedContentSz
and authTagSz), DecodeEncryptedData, SignedData null signature tag,
and PwriKek_KeyUnWrap cekLen validation.
This commit is contained in:
Colton Willey
2026-04-13 13:14:26 -07:00
parent 713a220fc9
commit 94b36c9092
6 changed files with 36 additions and 6 deletions
+3 -2
View File
@@ -26208,7 +26208,8 @@ int SendCertificateStatus(WOLFSSL* ssl)
}
if (chain && chain->buffer) {
while (ret == 0 && idx + OPAQUE24_LEN < chain->length) {
while (ret == 0 && i < MAX_CHAIN_DEPTH &&
idx + OPAQUE24_LEN < chain->length) {
c24to32(chain->buffer + idx, &der.length);
idx += OPAQUE24_LEN;
@@ -26249,7 +26250,7 @@ int SendCertificateStatus(WOLFSSL* ssl)
WC_FREE_VAR_EX(cert, ssl->heap, DYNAMIC_TYPE_DCERT);
}
else {
while (ret == 0 &&
while (ret == 0 && i < MAX_CHAIN_DEPTH &&
NULL != (request = ssl->ctx->chainOcspRequest[i])) {
if ((i + 1) >= MAX_CERT_EXTENSIONS) {
ret = MAX_CERT_EXTENSIONS_ERR;
+3 -3
View File
@@ -14121,7 +14121,7 @@ int wolfSSL_get_chain_count(WOLFSSL_X509_CHAIN* chain)
int wolfSSL_get_chain_length(WOLFSSL_X509_CHAIN* chain, int idx)
{
WOLFSSL_ENTER("wolfSSL_get_chain_length");
if (chain)
if (chain && idx >= 0 && idx < chain->count)
return chain->certs[idx].length;
return 0;
@@ -14132,7 +14132,7 @@ int wolfSSL_get_chain_length(WOLFSSL_X509_CHAIN* chain, int idx)
byte* wolfSSL_get_chain_cert(WOLFSSL_X509_CHAIN* chain, int idx)
{
WOLFSSL_ENTER("wolfSSL_get_chain_cert");
if (chain)
if (chain && idx >= 0 && idx < chain->count)
return chain->certs[idx].buffer;
return 0;
@@ -14147,7 +14147,7 @@ WOLFSSL_X509* wolfSSL_get_chain_X509(WOLFSSL_X509_CHAIN* chain, int idx)
WC_DECLARE_VAR(cert, DecodedCert, 1, 0);
WOLFSSL_ENTER("wolfSSL_get_chain_X509");
if (chain != NULL && idx < MAX_CHAIN_DEPTH) {
if (chain != NULL && idx >= 0 && idx < chain->count) {
#ifdef WOLFSSL_SMALL_STACK
cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
DYNAMIC_TYPE_DCERT);
+7
View File
@@ -325,6 +325,13 @@ static int ProcessUserChain(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
while ((ret == 0) && (consumed < sz)) {
DerBuffer* part = NULL;
/* Enforce maximum chain depth. */
if (cnt >= MAX_CHAIN_DEPTH) {
WOLFSSL_MSG("Chain depth limit reached");
ret = MAX_CHAIN_ERROR;
break;
}
/* Get a certificate as DER. */
ret = DataToDerBuffer(buff + consumed, (word32)(sz - consumed),
format, type, info, heap, &part, NULL);
+7 -1
View File
@@ -2826,6 +2826,9 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
ato16(clientHello + offset, &listLen);
offset += OPAQUE16_LEN;
if (listLen != extLen - OPAQUE16_LEN)
return BUFFER_ERROR;
if (helloSz < offset + listLen)
return BUFFER_ERROR;
@@ -2836,6 +2839,9 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
ato16(clientHello + offset, &sniLen);
offset += OPAQUE16_LEN;
if (sniLen > listLen - (ENUM_LEN + OPAQUE16_LEN))
return BUFFER_ERROR;
if (helloSz < offset + sniLen)
return BUFFER_ERROR;
@@ -3393,7 +3399,7 @@ static void TLSX_CSR_Free(CertificateStatusRequest* csr, void* heap)
switch (csr->status_type) {
case WOLFSSL_CSR_OCSP:
for (i = 0; i <= csr->requests; i++) {
for (i = 0; i < csr->requests; i++) {
FreeOcspRequest(&csr->request.ocsp[i]);
}
break;
+4
View File
@@ -9520,6 +9520,10 @@ static int SendTls13Certificate(WOLFSSL* ssl)
}
/* Certificate Data */
certSz = ssl->buffers.certificate->length;
if (ssl->buffers.certChainCnt > MAX_CHAIN_DEPTH) {
WOLFSSL_MSG("Certificate chain count exceeds maximum depth");
return MAX_CHAIN_ERROR;
}
/* Cert Req Ctx Len | Cert Req Ctx | Cert List Len | Cert Data Len */
headerSz = OPAQUE8_LEN + certReqCtxLen + CERT_HEADER_SZ +
CERT_HEADER_SZ;
+12
View File
@@ -14968,6 +14968,12 @@ int wc_PKCS7_DecodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* in,
}
}
if (ret == 0 && encryptedContentSz > (int)(pkiMsgSz - idx)) {
#ifdef NO_PKCS7_STREAM
ret = BUFFER_E;
#endif
}
if (ret < 0)
break;
@@ -15230,6 +15236,12 @@ authenv_atrbend:
#endif
idx = localIdx;
#ifdef NO_PKCS7_STREAM
if (ret == 0 && authTagSz > (word32)(pkiMsgSz - idx)) {
ret = BUFFER_E;
}
#endif
if (ret == 0 && authTagSz > (word32)sizeof(authTag)) {
WOLFSSL_MSG("AuthEnvelopedData authTag too large for buffer");
ret = ASN_PARSE_E;