mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-08-17 19:41:32 +02:00
Fix EVP_DecodeUpdate overflow on NUL byte in base64 input
The quad decoding loop broke out on a NUL byte without clearing the remaining input length, unlike the equivalent loops in Base64_Decode and Base64_Decode_nonCT. Control then fell into the block that buffers the leftover input in the context, which copied the full remaining byte count into the 48 byte ctx->data with an unbounded index, and read one byte past the end of the caller's buffer. An application decoding attacker supplied base64 with an explicit, binary safe length could write attacker controlled data past the end of a heap allocated encode context. Clear the length before breaking, and bound the leftover copy loop at one decode block, which is the most that loop can legitimately buffer. That also keeps ctx->remaining below the block size, so a reused context cannot underflow the copy size in the next update call or over-read ctx->data in EVP_DecodeFinal. Add a negative test feeding a NUL byte followed by more non-whitespace data than the context buffer can hold. Fixes F-7445.
This commit is contained in:
@@ -584,6 +584,33 @@ int test_wolfSSL_EVP_DecodeUpdate(void)
|
||||
0);
|
||||
}
|
||||
|
||||
/* decode input holding a NUL byte at the start of a 4 byte group, followed
|
||||
* by more data than the context buffer can hold */
|
||||
|
||||
{
|
||||
unsigned char enc5[64];
|
||||
|
||||
XMEMSET(enc5, 'A', sizeof(enc5));
|
||||
enc5[0] = '\0';
|
||||
|
||||
EVP_DecodeInit(ctx);
|
||||
|
||||
ExpectIntEQ(
|
||||
EVP_DecodeUpdate(
|
||||
ctx,
|
||||
decOutBuff,
|
||||
&outl,
|
||||
enc5,
|
||||
(int)sizeof(enc5)),
|
||||
1 /* expected result code 1: success */
|
||||
);
|
||||
ExpectIntEQ(outl, 0);
|
||||
/* Before the fix all 64 input bytes were buffered into the 48 byte
|
||||
* ctx->data. The NUL byte ends the input, so nothing may be buffered
|
||||
* at all. */
|
||||
ExpectIntEQ(ctx->remaining, 0);
|
||||
}
|
||||
|
||||
EVP_ENCODE_CTX_free(ctx);
|
||||
#endif /* OPENSSL && WOLFSSL_BASE_DECODE */
|
||||
return EXPECT_RESULT();
|
||||
|
||||
@@ -13925,6 +13925,8 @@ int wolfSSL_EVP_DecodeUpdate(WOLFSSL_EVP_ENCODE_CTX* ctx,
|
||||
}
|
||||
e[0] = in[j++];
|
||||
if (e[0] == '\0') {
|
||||
/* a NUL byte ends the input, nothing is left to buffer */
|
||||
inLen = 0;
|
||||
break;
|
||||
}
|
||||
inLen--;
|
||||
@@ -14005,6 +14007,15 @@ int wolfSSL_EVP_DecodeUpdate(WOLFSSL_EVP_ENCODE_CTX* ctx,
|
||||
if (c == '=') {
|
||||
pad = 1;
|
||||
}
|
||||
if (i >= BASE64_DECODE_BLOCK_SIZE) {
|
||||
/* More leftover data than one decode block can hold. The loops
|
||||
* above leave at most a partial block behind, so this is a
|
||||
* bound on the buffer and not a reachable input error. */
|
||||
XMEMSET(ctx->data, 0, sizeof(ctx->data));
|
||||
ctx->remaining = 0;
|
||||
*outl = 0;
|
||||
return -1;
|
||||
}
|
||||
ctx->data[i++] = c;
|
||||
ctx->remaining++;
|
||||
inLen--;
|
||||
|
||||
Reference in New Issue
Block a user