From 203067b9e30184d6d67ac981440161bc9bb183af Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 12 Jun 2026 12:14:48 -0700 Subject: [PATCH 1/7] Zero out buffer on error in AES_GCM_decrypt_C. Fixes F-5393. --- wolfcrypt/src/aes.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index f87a188ebf..2a46d6b7a7 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -11042,6 +11042,9 @@ int WARN_UNUSED_RESULT AES_GCM_decrypt_C( ret = (ret & ~res); ret |= (res & WC_NO_ERR_TRACE(AES_GCM_AUTH_E)); #endif + if (ret != 0) { + ForceZero(out, sz); + } return ret; } #elif (defined(__aarch64__) || defined(WOLFSSL_ARMASM_NO_HW_CRYPTO)) || \ From 4dffcffc402bde1992287ccd5a65d94ce44a8fbf Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 12 Jun 2026 12:21:02 -0700 Subject: [PATCH 2/7] Zero out the aead in wc_ChaCha20Poly1305_Encrypt/Decrypt before freeing it. Fixes F-4023. --- wolfcrypt/src/chacha20_poly1305.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index e9e5bb80c4..f3ebb52ff9 100644 --- a/wolfcrypt/src/chacha20_poly1305.c +++ b/wolfcrypt/src/chacha20_poly1305.c @@ -75,6 +75,7 @@ int wc_ChaCha20Poly1305_Encrypt( if (ret == 0) ret = wc_ChaCha20Poly1305_Final(aead, outAuthTag); + ForceZero(aead, sizeof(ChaChaPoly_Aead)); WC_FREE_VAR_EX(aead, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret; @@ -123,6 +124,7 @@ int wc_ChaCha20Poly1305_Decrypt( /* zero plaintext on error */ ForceZero(outPlaintext, inCiphertextLen); } + ForceZero(aead, sizeof(ChaChaPoly_Aead)); WC_FREE_VAR_EX(aead, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret; From bb82037f70fc06f5b0841f0b15e4892034b9f6ec Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 12 Jun 2026 12:27:15 -0700 Subject: [PATCH 3/7] Limit parsed port to 65535 in wolfIO_DecodeUrl. Fixes F-4228. --- src/wolfio.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/wolfio.c b/src/wolfio.c index 4ebff95c69..75ff9d47bd 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -1725,7 +1725,7 @@ int wolfIO_DecodeUrl(const char* url, int urlSz, char* outName, char* outPath, /* Need to pick out the path after the domain name */ if (cur < urlSz && url[cur] == ':') { - char port[6]; + char port[5]; int j; word32 bigPort = 0; i = 0; @@ -1733,15 +1733,27 @@ int wolfIO_DecodeUrl(const char* url, int urlSz, char* outName, char* outPath, XMEMSET(port, 0, sizeof(port)); - while (i < 6 && cur < urlSz && url[cur] != 0 && url[cur] != '/') { + while (i < 5 && cur < urlSz && url[cur] != 0 && url[cur] != '/') { port[i] = url[cur]; i++; cur++; } + /* A valid port is at most 5 digits; if more characters remain + * before the path/terminator the port field is malformed (e.g. + * a 6-digit port) and must be rejected rather than parsed from a + * truncated digit string. */ + if (cur < urlSz && url[cur] != 0 && url[cur] != '/') + return WOLFSSL_FATAL_ERROR; + for (j = 0; j < i; j++) { if (port[j] < '0' || port[j] > '9') return WOLFSSL_FATAL_ERROR; bigPort = (bigPort * 10) + (word32)(port[j] - '0'); } + /* Reject out-of-range ports rather than silently truncating to + * word16, which would otherwise wrap (e.g. 65536 -> 0) and + * connect to an unintended port. */ + if (bigPort > 65535) + return WOLFSSL_FATAL_ERROR; if (outPort) *outPort = (word16)bigPort; } From 998fd831e886249641bf2ce81d4b0811018d4b4f Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 12 Jun 2026 12:53:21 -0700 Subject: [PATCH 4/7] Fix length calculations in wolfSSL_BUF_MEM_grow_ex and wolfSSL_BUF_MEM_resize. Also fix a potential overread in wolfSSL_BUF_MEM_grow_ex for the non-realloc case. Fixes F-5730 --- src/ssl.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index c2a5827c9d..db42d6bb9b 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -15398,20 +15398,20 @@ WOLFSSL_BUF_MEM* wolfSSL_BUF_MEM_new(void) int wolfSSL_BUF_MEM_grow_ex(WOLFSSL_BUF_MEM* buf, size_t len, char zeroFill) { - - int len_int = (int)len; - int mx; + size_t mx; char* tmp; - /* verify provided arguments */ - if (buf == NULL || len_int < 0) { + /* verify provided arguments. The return value is an int holding the + * resulting length, so reject any len that cannot be represented as a + * non-negative int. This also prevents truncating size_t to int. */ + if (buf == NULL || len > (size_t)INT_MAX) { return 0; /* BAD_FUNC_ARG; */ } /* check to see if fits in existing length */ if (buf->length > len) { buf->length = len; - return len_int; + return (int)len; } /* check to see if fits in max buffer */ @@ -15420,16 +15420,19 @@ int wolfSSL_BUF_MEM_grow_ex(WOLFSSL_BUF_MEM* buf, size_t len, XMEMSET(&buf->data[buf->length], 0, len - buf->length); } buf->length = len; - return len_int; + return (int)len; } /* expand size, to handle growth */ - mx = (len_int + 3) / 3 * 4; + mx = (len + 3) / 3 * 4; #ifdef WOLFSSL_NO_REALLOC tmp = (char*)XMALLOC(mx, NULL, DYNAMIC_TYPE_OPENSSL); if (tmp != NULL && buf->data != NULL) { - XMEMCPY(tmp, buf->data, len_int); + /* Only buf->length bytes of the old buffer are valid; copying len + * bytes here would over-read the old allocation since this branch is + * only reached when buf->max < len. */ + XMEMCPY(tmp, buf->data, buf->length); XFREE(buf->data, NULL, DYNAMIC_TYPE_OPENSSL); buf->data = NULL; } @@ -15443,12 +15446,12 @@ int wolfSSL_BUF_MEM_grow_ex(WOLFSSL_BUF_MEM* buf, size_t len, } buf->data = tmp; - buf->max = (size_t)mx; + buf->max = mx; if (zeroFill) XMEMSET(&buf->data[buf->length], 0, len - buf->length); buf->length = len; - return len_int; + return (int)len; } @@ -15462,10 +15465,11 @@ int wolfSSL_BUF_MEM_grow(WOLFSSL_BUF_MEM* buf, size_t len) int wolfSSL_BUF_MEM_resize(WOLFSSL_BUF_MEM* buf, size_t len) { char* tmp; - int mx; + size_t mx; - /* verify provided arguments */ - if (buf == NULL || len == 0 || (int)len <= 0) { + /* verify provided arguments. The return value is an int, so reject any + * len that cannot be represented as a positive int. */ + if (buf == NULL || len == 0 || len > (size_t)INT_MAX) { return 0; /* BAD_FUNC_ARG; */ } @@ -15476,7 +15480,7 @@ int wolfSSL_BUF_MEM_resize(WOLFSSL_BUF_MEM* buf, size_t len) return wolfSSL_BUF_MEM_grow_ex(buf, len, 0); /* expand size, to handle growth */ - mx = ((int)len + 3) / 3 * 4; + mx = (len + 3) / 3 * 4; /* We want to shrink the internal buffer */ #ifdef WOLFSSL_NO_REALLOC @@ -15496,7 +15500,7 @@ int wolfSSL_BUF_MEM_resize(WOLFSSL_BUF_MEM* buf, size_t len) buf->data = tmp; buf->length = len; - buf->max = (size_t)mx; + buf->max = mx; return (int)len; } From 8aaaafb8416ad2a97824f5a215d2656616f9af8e Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 12 Jun 2026 13:25:56 -0700 Subject: [PATCH 5/7] Fix wolfIO_DecodeUrl handling of IPv6 brackets. Fixes F-4285. --- src/wolfio.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/wolfio.c b/src/wolfio.c index 75ff9d47bd..30d2022de4 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -1710,6 +1710,12 @@ int wolfIO_DecodeUrl(const char* url, int urlSz, char* outName, char* outPath, outName[i] = url[cur]; i++; cur++; } + /* A bracketed IPv6 literal must be terminated by ']'. The loop + * above can also stop on end-of-buffer, NUL, or the length cap, + * none of which represent a well-formed host. Reject those cases + * rather than accepting the unterminated tail as the hostname. */ + if (cur >= urlSz || url[cur] != ']') + return WOLFSSL_FATAL_ERROR; cur++; /* skip ']' */ } else { From 636fe2565a18deaa3c43e9d2f71742c2e371bf8a Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 15 Jun 2026 10:14:03 -0700 Subject: [PATCH 6/7] Code review feedback --- wolfcrypt/src/chacha20_poly1305.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index f3ebb52ff9..2a8228adf4 100644 --- a/wolfcrypt/src/chacha20_poly1305.c +++ b/wolfcrypt/src/chacha20_poly1305.c @@ -74,8 +74,10 @@ int wc_ChaCha20Poly1305_Encrypt( inPlaintextLen); if (ret == 0) ret = wc_ChaCha20Poly1305_Final(aead, outAuthTag); - - ForceZero(aead, sizeof(ChaChaPoly_Aead)); + #ifdef WOLFSSL_SMALL_STACK + if (aead != NULL) + #endif + ForceZero(aead, sizeof(ChaChaPoly_Aead)); WC_FREE_VAR_EX(aead, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret; From caebcd26febabc9e9a0e0f6348488d7778a480ce Mon Sep 17 00:00:00 2001 From: Kareem Date: Thu, 25 Jun 2026 17:42:05 -0700 Subject: [PATCH 7/7] Code review feedback --- src/ssl.c | 2 +- src/wolfio.c | 2 +- wolfcrypt/src/chacha20_poly1305.c | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index db42d6bb9b..b218d3be0a 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -15469,7 +15469,7 @@ int wolfSSL_BUF_MEM_resize(WOLFSSL_BUF_MEM* buf, size_t len) /* verify provided arguments. The return value is an int, so reject any * len that cannot be represented as a positive int. */ - if (buf == NULL || len == 0 || len > (size_t)INT_MAX) { + if (buf == NULL || len == 0 || len > (size_t)WOLFSSL_MAX_32BIT) { return 0; /* BAD_FUNC_ARG; */ } diff --git a/src/wolfio.c b/src/wolfio.c index 30d2022de4..ab85ecdef8 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -1758,7 +1758,7 @@ int wolfIO_DecodeUrl(const char* url, int urlSz, char* outName, char* outPath, /* Reject out-of-range ports rather than silently truncating to * word16, which would otherwise wrap (e.g. 65536 -> 0) and * connect to an unintended port. */ - if (bigPort > 65535) + if (bigPort > WOLFSSL_MAX_16BIT) return WOLFSSL_FATAL_ERROR; if (outPort) *outPort = (word16)bigPort; diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index 2a8228adf4..7c4218ac57 100644 --- a/wolfcrypt/src/chacha20_poly1305.c +++ b/wolfcrypt/src/chacha20_poly1305.c @@ -126,7 +126,10 @@ int wc_ChaCha20Poly1305_Decrypt( /* zero plaintext on error */ ForceZero(outPlaintext, inCiphertextLen); } - ForceZero(aead, sizeof(ChaChaPoly_Aead)); + #ifdef WOLFSSL_SMALL_STACK + if (aead != NULL) + #endif + ForceZero(aead, sizeof(ChaChaPoly_Aead)); WC_FREE_VAR_EX(aead, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret;