Guard against negative length in BIO, I/O callbacks and PKCS12 PBKDF

- src/bio.c: Add BIO self-cycle UAF guard and negative nread/nwrite checks
- src/wolfio.c: Add negative sz guards to EmbedSend/EmbedReceive
- wolfcrypt/src/pwdbased.c: Add pLen/sLen/totalLen overflow checks in
  wc_PKCS12_PBKDF_ex
This commit is contained in:
Colton Willey
2026-04-13 17:46:41 -07:00
committed by Mattia Moffa
parent 3181e2bcf8
commit 37d66b8be9
3 changed files with 73 additions and 0 deletions
+24
View File
@@ -281,6 +281,10 @@ int wolfSSL_BIO_read(WOLFSSL_BIO* bio, void* buf, int len)
}
}
if (len < 0) {
return WOLFSSL_BIO_ERROR;
}
/* start at end of list (or a WOLFSSL_BIO_SSL object since it takes care of
* the rest of the chain) and work backwards */
while (bio != NULL && bio->next != NULL && bio->type != WOLFSSL_BIO_SSL) {
@@ -699,6 +703,10 @@ int wolfSSL_BIO_write(WOLFSSL_BIO* bio, const void* data, int len)
}
}
if (len < 0) {
return WOLFSSL_BIO_ERROR;
}
while (bio != NULL && ret >= 0) {
#ifdef WOLFSSL_BIO_HAVE_FLOW_STATS
int inhibit_flow_increment = 0;
@@ -1569,6 +1577,10 @@ int wolfSSL_BIO_nread(WOLFSSL_BIO *bio, char **buf, int num)
return 0;
}
if (num < 0) {
return WOLFSSL_BIO_ERROR;
}
/* get amount able to read and set buffer pointer */
sz = wolfSSL_BIO_nread0(bio, buf);
if (sz < 0) {
@@ -1623,6 +1635,10 @@ int wolfSSL_BIO_nwrite(WOLFSSL_BIO *bio, char **buf, int num)
return 0;
}
if (num < 0) {
return WOLFSSL_BIO_ERROR;
}
if (bio->wrIdx < bio->rdIdx) {
/* if wrapped around only write up to read index. In this case
* rdIdx is always greater then wrIdx so sz will not be negative. */
@@ -3137,6 +3153,14 @@ int wolfSSL_BIO_flush(WOLFSSL_BIO* bio)
if (top == NULL) {
return append;
}
{
WOLFSSL_BIO* cur = append;
while (cur != NULL) {
if (cur == top)
return top; /* would create cycle */
cur = cur->next;
}
}
top->next = append;
if (append != NULL) {
append->prev = top;
+24
View File
@@ -675,6 +675,9 @@ int EmbedReceiveFrom(WOLFSSL *ssl, char *buf, int sz, void *ctx)
WOLFSSL_ENTER("EmbedReceiveFrom");
(void)ret; /* possibly unused */
if (sz < 0)
return WOLFSSL_CBIO_ERR_GENERAL;
XMEMSET(&lclPeer, 0, sizeof(lclPeer));
#ifdef WOLFSSL_RW_THREADED
@@ -918,6 +921,9 @@ int EmbedSendTo(WOLFSSL* ssl, char *buf, int sz, void *ctx)
WOLFSSL_ENTER("EmbedSendTo");
if (sz < 0)
return WOLFSSL_CBIO_ERR_GENERAL;
if (!isDGramSock(sd)) {
/* Probably a TCP socket. peer and peerSz MUST be NULL and 0 */
}
@@ -964,6 +970,9 @@ int EmbedReceiveFromMcast(WOLFSSL *ssl, char *buf, int sz, void *ctx)
WOLFSSL_ENTER("EmbedReceiveFromMcast");
if (sz < 0)
return WOLFSSL_CBIO_ERR_GENERAL;
recvd = (int)DTLS_RECVFROM_FUNCTION(sd, buf, (size_t)sz, ssl->rflags, NULL, NULL);
recvd = TranslateIoReturnCode(recvd, sd, SOCKET_RECEIVING);
@@ -994,6 +1003,9 @@ int EmbedGenerateCookie(WOLFSSL* ssl, byte *buf, int sz, void *ctx)
(void)ctx;
if (sz < 0)
return BAD_FUNC_ARG;
XMEMSET(&peer, 0, sizeof(peer));
if (getpeername(sd, (SOCKADDR*)&peer, &peerSz) != 0) {
WOLFSSL_MSG("getpeername failed in EmbedGenerateCookie");
@@ -1222,6 +1234,9 @@ int wolfIO_Recv(SOCKET_T sd, char *buf, int sz, int rdFlags)
{
int recvd;
if (sz < 0)
return WOLFSSL_CBIO_ERR_GENERAL;
recvd = (int)RECV_FUNCTION(sd, buf, (size_t)sz, rdFlags);
recvd = TranslateIoReturnCode(recvd, sd, SOCKET_RECEIVING);
@@ -1232,6 +1247,9 @@ int wolfIO_Send(SOCKET_T sd, char *buf, int sz, int wrFlags)
{
int sent;
if (sz < 0)
return WOLFSSL_CBIO_ERR_GENERAL;
sent = (int)SEND_FUNCTION(sd, buf, (size_t)sz, wrFlags);
sent = TranslateIoReturnCode(sent, sd, SOCKET_SENDING);
@@ -1245,6 +1263,9 @@ int wolfIO_RecvFrom(SOCKET_T sd, WOLFSSL_BIO_ADDR *addr, char *buf, int sz, int
int recvd;
socklen_t addr_len = (socklen_t)sizeof(*addr);
if (sz < 0)
return WOLFSSL_CBIO_ERR_GENERAL;
recvd = (int)DTLS_RECVFROM_FUNCTION(sd, buf, (size_t)sz, rdFlags,
addr ? &addr->sa : NULL,
addr ? &addr_len : 0);
@@ -1258,6 +1279,9 @@ int wolfIO_SendTo(SOCKET_T sd, WOLFSSL_BIO_ADDR *addr, char *buf, int sz, int wr
int sent;
socklen_t addr_len = addr ? wolfSSL_BIO_ADDR_size(addr) : 0;
if (sz < 0)
return WOLFSSL_CBIO_ERR_GENERAL;
sent = (int)DTLS_SENDTO_FUNCTION(sd, buf, (size_t)sz, wrFlags,
addr ? &addr->sa : NULL,
addr_len);
+25
View File
@@ -442,8 +442,22 @@ int wc_PKCS12_PBKDF_ex(byte* output, const byte* passwd, int passLen,
/* with passLen checked at the top of the function for >= 0 then passLen
* must be 1 or greater here and is always 'true' */
pLen = v * (((word32)passLen + v - 1) / v);
/* Guard against overflow in iLen = sLen + pLen and totalLen = dLen + iLen.
* Individual sLen/pLen values fit in word32 (max 0x80000000 for INT_MAX
* inputs), but their sum can overflow. */
if (sLen > 0xFFFFFFFFU - pLen) {
WC_FREE_VAR_EX(Ai, heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(B, heap, DYNAMIC_TYPE_TMP_BUFFER);
return BAD_FUNC_ARG;
}
iLen = sLen + pLen;
if (iLen > 0xFFFFFFFFU - v) {
WC_FREE_VAR_EX(Ai, heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(B, heap, DYNAMIC_TYPE_TMP_BUFFER);
return BAD_FUNC_ARG;
}
totalLen = dLen + sLen + pLen;
if (totalLen > sizeof(staticBuffer)) {
@@ -635,8 +649,19 @@ int wc_PKCS12_PBKDF_ex(byte* output, const byte* passwd, int passLen,
sLen = v * (((word32)saltLen + v - 1) / v);
/* RFC 7292 B.2 step 3: P = password repeated to ceil(passLen/v)*v bytes */
pLen = v * (((word32)passLen + v - 1) / v);
/* Guard against overflow in iLen = sLen + pLen and totalLen = v + iLen.
* Individual sLen/pLen values fit in word32 (max 0x80000000 for INT_MAX
* inputs), but their sum can overflow. */
if (sLen > 0xFFFFFFFFU - pLen) {
return BAD_FUNC_ARG;
}
/* RFC 7292 B.2 step 4: I = S || P */
iLen = sLen + pLen;
if (iLen > 0xFFFFFFFFU - v) {
return BAD_FUNC_ARG;
}
totalLen = v + iLen;
nwc = v / (word32)sizeof(PKCS12_WORD);