diff --git a/linuxkm/linuxkm_wc_port.h b/linuxkm/linuxkm_wc_port.h index 2a47722ad0..84935e45c8 100644 --- a/linuxkm/linuxkm_wc_port.h +++ b/linuxkm/linuxkm_wc_port.h @@ -1920,7 +1920,7 @@ #define WC_LINUXKM_ROUND_UP_P_OF_2(x) ( \ { \ size_t _alloc_sz = (x); \ - if ((_alloc_sz < 8192) && (_alloc_sz != 0)) \ + if ((_alloc_sz < 8192) && (_alloc_sz > 1)) \ _alloc_sz = 1UL << \ ((sizeof(_alloc_sz) * 8UL) - __builtin_clzl(_alloc_sz - 1)); \ _alloc_sz; \ diff --git a/linuxkm/lkcapi_rsa_glue.c b/linuxkm/lkcapi_rsa_glue.c index 92cdef8f00..9f1774db3d 100644 --- a/linuxkm/lkcapi_rsa_glue.c +++ b/linuxkm/lkcapi_rsa_glue.c @@ -1259,6 +1259,12 @@ static int km_pkcs1pad_verify(struct akcipher_request *req) goto pkcs1pad_verify_out; } + /* bail if the padded ASN.1-prefixed digest won't fit in the given RSA key. */ + if ((word64)ctx->digest_len + (word64)hash_enc_len + RSA_MIN_PAD_SZ > ctx->key_len) { + err = -EOVERFLOW; + goto pkcs1pad_verify_out; + } + work_buffer = malloc(2 * ctx->key_len); if (unlikely(work_buffer == NULL)) { err = -ENOMEM; @@ -1513,6 +1519,12 @@ static int km_pkcs1_verify(struct crypto_sig *tfm, goto pkcs1_verify_out; } + /* bail if the padded ASN.1-prefixed digest won't fit in the given RSA key. */ + if ((word64)ctx->digest_len + (word64)hash_enc_len + RSA_MIN_PAD_SZ > ctx->key_len) { + err = -EOVERFLOW; + goto pkcs1_verify_out; + } + work_buffer = malloc(2 * ctx->key_len); if (unlikely(work_buffer == NULL)) { err = -ENOMEM; diff --git a/wolfcrypt/src/coding.c b/wolfcrypt/src/coding.c index b3f804fcf0..c89dab769c 100644 --- a/wolfcrypt/src/coding.c +++ b/wolfcrypt/src/coding.c @@ -192,6 +192,7 @@ int Base64_Decode_nonCT(const byte* in, word32 inLen, byte* out, word32* outLen) } e1 = in[j++]; if (e1 == '\0') { + inLen = 0; break; } inLen--; @@ -230,11 +231,6 @@ int Base64_Decode_nonCT(const byte* in, word32 inLen, byte* out, word32* outLen) return ASN_INPUT_E; } - if (i + 1 + !pad3 + !pad4 > *outLen) { - WOLFSSL_MSG("Bad Base64 Decode out buffer, too small"); - return BUFFER_E; - } - e1 = Base64_Char2Val_by_table(e1); e2 = Base64_Char2Val_by_table(e2); e3 = (byte)((e3 == PAD) ? 0 : Base64_Char2Val_by_table(e3)); @@ -245,6 +241,11 @@ int Base64_Decode_nonCT(const byte* in, word32 inLen, byte* out, word32* outLen) return ASN_INPUT_E; } + if (i + 1 + !pad3 + !pad4 > *outLen) { + WOLFSSL_MSG("Bad Base64 Decode out buffer, too small"); + return BUFFER_E; + } + b1 = (byte)((e1 << 2) | (e2 >> 4)); b2 = (byte)(((e2 & 0xF) << 4) | (e3 >> 2)); b3 = (byte)(((e3 & 0x3) << 6) | e4); @@ -258,6 +259,24 @@ int Base64_Decode_nonCT(const byte* in, word32 inLen, byte* out, word32* outLen) break; } + /* If there is still input available, and it's not whitespace or nulls, then + * the input is invalid. + */ + while (inLen > 0) { + word32 cur_j = j; + if (in[j] == 0) + break; + if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) { + if (ret == WC_NO_ERR_TRACE(BUFFER_E)) { + /* Running out of buffer here is not an error */ + break; + } + return ret; + } + if (j == cur_j) + return ASN_INPUT_E; + } + /* If the output buffer has a room for an extra byte, add a null terminator */ if (out && *outLen > i) out[i]= '\0'; @@ -294,6 +313,7 @@ int Base64_Decode(const byte* in, word32 inLen, byte* out, word32* outLen) } e1 = in[j++]; if (e1 == '\0') { + inLen = 0; break; } inLen--; @@ -321,11 +341,6 @@ int Base64_Decode(const byte* in, word32 inLen, byte* out, word32* outLen) if (pad3 && !pad4) return ASN_INPUT_E; - if (i + 1 + !pad3 + !pad4 > *outLen) { - WOLFSSL_MSG("Bad Base64 Decode out buffer, too small"); - return BUFFER_E; - } - e1 = Base64_Char2Val_CT(e1); e2 = Base64_Char2Val_CT(e2); e3 = (byte)((e3 == PAD) ? 0 : Base64_Char2Val_CT(e3)); @@ -336,6 +351,15 @@ int Base64_Decode(const byte* in, word32 inLen, byte* out, word32* outLen) return ASN_INPUT_E; } + /* Output space check needs to follow input character validation to + * assure ASN_INPUT_E is returned on truncated input with the + * terminating null included in the input buffer. + */ + if (i + 1 + !pad3 + !pad4 > *outLen) { + WOLFSSL_MSG("Bad Base64 Decode out buffer, too small"); + return BUFFER_E; + } + b1 = (byte)((e1 << 2) | (e2 >> 4)); b2 = (byte)(((e2 & 0xF) << 4) | (e3 >> 2)); b3 = (byte)(((e3 & 0x3) << 6) | e4); @@ -349,6 +373,24 @@ int Base64_Decode(const byte* in, word32 inLen, byte* out, word32* outLen) break; } + /* If there is still input available, and it's not whitespace or nulls, then + * the input is invalid. + */ + while (inLen > 0) { + word32 cur_j = j; + if (in[j] == 0) + break; + if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) { + if (ret == WC_NO_ERR_TRACE(BUFFER_E)) { + /* Running out of buffer here is not an error */ + break; + } + return ret; + } + if (j == cur_j) + return ASN_INPUT_E; + } + /* If the output buffer has a room for an extra byte, add a null terminator */ if (out && *outLen > i) out[i]= '\0'; diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 49deeaf0ce..928f573858 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -4130,12 +4130,18 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t base64_test(void) static const byte goodChar[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" - "0123456789+/;"; + "0123456789+/"; static const byte charTest[] = "A+Gd\0\0\0"; static const byte oneByteTest[] = "YQ=="; static const byte twoByteTest[] = "YWE="; static const byte threeByteTest[] = "YWFh"; static const byte fourByteTest[] = "YWFhYQ=="; + static const byte trailingLFTest[] = "YWFhYQ==\n\n"; + static const byte trailingSpaceTest[] = "YWFhYQ== "; + static const byte trailingCodesTest1[] = "YWFhY"; + static const byte trailingCodesTest2[] = "YWFhYW"; + static const byte trailingCodesTest3[] = "YWFhYWF"; + static const byte trailingJunkTest[] = "YWFhYQ==X"; static const byte byteTestOutput[] = "aaaa"; int i; WOLFSSL_ENTER("base64_test"); @@ -4255,6 +4261,26 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t base64_test(void) N_BYTE_TEST(Base64_Decode, 3, threeByteTest); N_BYTE_TEST(Base64_Decode, 4, fourByteTest); +#define N_BYTE_TRAILING_TEST(f, n, t, e) do { \ + outLen = (n); \ + ret = (f)(t, sizeof(t), out, &outLen); \ + if (ret != (e)) \ + return WC_TEST_RET_ENC_EC(ret); \ + else if (ret == 0) { \ + if (outLen != (n)) \ + return WC_TEST_RET_ENC_I(outLen); \ + if (XMEMCMP(out, byteTestOutput, n) != 0) \ + return WC_TEST_RET_ENC_NC; \ + } \ + } while (0) + + N_BYTE_TRAILING_TEST(Base64_Decode, 4, trailingLFTest, 0); + N_BYTE_TRAILING_TEST(Base64_Decode, 4, trailingSpaceTest, 0); + N_BYTE_TRAILING_TEST(Base64_Decode, 4, trailingCodesTest1, WC_NO_ERR_TRACE(ASN_INPUT_E)); + N_BYTE_TRAILING_TEST(Base64_Decode, 4, trailingCodesTest2, WC_NO_ERR_TRACE(ASN_INPUT_E)); + N_BYTE_TRAILING_TEST(Base64_Decode, 4, trailingCodesTest3, WC_NO_ERR_TRACE(ASN_INPUT_E)); + N_BYTE_TRAILING_TEST(Base64_Decode, 4, trailingJunkTest, WC_NO_ERR_TRACE(ASN_INPUT_E)); + /* Same tests again, using Base64_Decode_nonCT() */ /* Good Base64 encodings. */ @@ -4335,6 +4361,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t base64_test(void) N_BYTE_TEST(Base64_Decode_nonCT, 3, threeByteTest); N_BYTE_TEST(Base64_Decode_nonCT, 4, fourByteTest); + N_BYTE_TRAILING_TEST(Base64_Decode_nonCT, 4, trailingLFTest, 0); + N_BYTE_TRAILING_TEST(Base64_Decode_nonCT, 4, trailingSpaceTest, 0); + N_BYTE_TRAILING_TEST(Base64_Decode_nonCT, 4, trailingCodesTest1, WC_NO_ERR_TRACE(ASN_INPUT_E)); + N_BYTE_TRAILING_TEST(Base64_Decode_nonCT, 4, trailingCodesTest2, WC_NO_ERR_TRACE(ASN_INPUT_E)); + N_BYTE_TRAILING_TEST(Base64_Decode_nonCT, 4, trailingCodesTest3, WC_NO_ERR_TRACE(ASN_INPUT_E)); + N_BYTE_TRAILING_TEST(Base64_Decode_nonCT, 4, trailingJunkTest, WC_NO_ERR_TRACE(ASN_INPUT_E)); + #ifdef WOLFSSL_BASE64_ENCODE /* Decode and encode all symbols - non-alphanumeric. */ dataLen = sizeof(data);