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; } diff --git a/src/wolfio.c b/src/wolfio.c index 4ebff95c69..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 { @@ -1725,7 +1731,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 +1739,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; } diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index 8223bcc8fb..0b19e8e293 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -11023,6 +11023,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)) || \ diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index e9e5bb80c4..2a8228adf4 100644 --- a/wolfcrypt/src/chacha20_poly1305.c +++ b/wolfcrypt/src/chacha20_poly1305.c @@ -74,7 +74,10 @@ int wc_ChaCha20Poly1305_Encrypt( inPlaintextLen); if (ret == 0) ret = wc_ChaCha20Poly1305_Final(aead, outAuthTag); - + #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; @@ -123,6 +126,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;