diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 33547245f..814612350 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -526,6 +526,7 @@ WC_ASYNC_ENABLE_SHA384 WC_ASYNC_ENABLE_SHA512 WC_ASYNC_NO_CRYPT WC_ASYNC_NO_HASH +WC_CACHE_RESISTANT_BASE64_TABLE WC_DILITHIUM_CACHE_PRIV_VECTORS WC_DILITHIUM_CACHE_PUB_VECTORS WC_DILITHIUM_FIXED_ARRAY diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 5e544d013..d72855ba0 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -26556,10 +26556,27 @@ int PemToDer(const unsigned char* buff, long longSz, int type, } der = *pDer; - if (Base64_Decode((byte*)headerEnd, (word32)neededSz, - der->buffer, &der->length) < 0) { - WOLFSSL_ERROR(BUFFER_E); - return BUFFER_E; + switch (type) { + case PUBLICKEY_TYPE: + case ECC_PUBLICKEY_TYPE: + case RSA_PUBLICKEY_TYPE: + case CERT_TYPE: + case TRUSTED_CERT_TYPE: + case CRL_TYPE: + if (Base64_Decode_nonCT((byte*)headerEnd, (word32)neededSz, + der->buffer, &der->length) < 0) + { + WOLFSSL_ERROR(BUFFER_E); + return BUFFER_E; + } + break; + default: + if (Base64_Decode((byte*)headerEnd, (word32)neededSz, + der->buffer, &der->length) < 0) { + WOLFSSL_ERROR(BUFFER_E); + return BUFFER_E; + } + break; } if ((header == BEGIN_PRIV_KEY diff --git a/wolfcrypt/src/coding.c b/wolfcrypt/src/coding.c index 6e73bb193..1bed7598a 100644 --- a/wolfcrypt/src/coding.c +++ b/wolfcrypt/src/coding.c @@ -59,20 +59,19 @@ enum { #ifdef WOLFSSL_BASE64_DECODE -#ifdef BASE64_NO_TABLE -static WC_INLINE byte Base64_Char2Val(byte c) +static WC_INLINE byte Base64_Char2Val_CT(byte c) { - word16 v; - sword16 smallEnd = (sword16)c - 0x7b; - sword16 smallStart = (sword16)c - 0x61; - sword16 bigEnd = (sword16)c - 0x5b; - sword16 bigStart = (sword16)c - 0x41; - sword16 numEnd = (sword16)c - 0x3a; - sword16 numStart = (sword16)c - 0x30; - sword16 slashEnd = (sword16)c - 0x30; - sword16 slashStart = (sword16)c - 0x2f; - sword16 plusEnd = (sword16)c - 0x2c; - sword16 plusStart = (sword16)c - 0x2b; + int v; + int smallEnd = (int)c - 0x7b; + int smallStart = (int)c - 0x61; + int bigEnd = (int)c - 0x5b; + int bigStart = (int)c - 0x41; + int numEnd = (int)c - 0x3a; + int numStart = (int)c - 0x30; + int slashEnd = (int)c - 0x30; + int slashStart = (int)c - 0x2f; + int plusEnd = (int)c - 0x2c; + int plusStart = (int)c - 0x2b; v = ((smallStart >> 8) ^ (smallEnd >> 8)) & (smallStart + 26 + 1); v |= ((bigStart >> 8) ^ (bigEnd >> 8)) & (bigStart + 0 + 1); @@ -82,9 +81,9 @@ static WC_INLINE byte Base64_Char2Val(byte c) return (byte)(v - 1); } -#else + static -ALIGN64 const byte base64Decode[] = { /* + starts at 0x2B */ +ALIGN64 const byte base64Decode_table[] = { /* + starts at 0x2B */ /* 0x28: + , - . / */ 62, BAD, BAD, BAD, 63, /* 0x30: 0 1 2 3 4 5 6 7 */ 52, 53, 54, 55, 56, 57, 58, 59, /* 0x38: 8 9 : ; < = > ? */ 60, 61, BAD, BAD, BAD, BAD, BAD, BAD, @@ -97,11 +96,11 @@ ALIGN64 const byte base64Decode[] = { /* + starts at 0x2B */ /* 0x70: p q r s t u v w */ 41, 42, 43, 44, 45, 46, 47, 48, /* 0x78: x y z */ 49, 50, 51 }; -#define BASE64DECODE_SZ (byte)(sizeof(base64Decode)) +#define BASE64DECODE_TABLE_SZ (byte)(sizeof(base64Decode_table)) -static WC_INLINE byte Base64_Char2Val(byte c) +static WC_INLINE byte Base64_Char2Val_by_table(byte c) { -#ifndef WC_NO_CACHE_RESISTANT +#ifdef WC_CACHE_RESISTANT_BASE64_TABLE /* 80 characters in table. * 64 bytes in a cache line - first line has 64, second has 16 */ @@ -111,16 +110,15 @@ static WC_INLINE byte Base64_Char2Val(byte c) c = (byte)(c - BASE64_MIN); mask = (byte)((((byte)(0x3f - c)) >> 7) - 1); /* Load a value from the first cache line and use when mask set. */ - v = (byte)(base64Decode[ c & 0x3f ] & mask); + v = (byte)(base64Decode_table[ c & 0x3f ] & mask); /* Load a value from the second cache line and use when mask not set. */ - v |= (byte)(base64Decode[(c & 0x0f) | 0x40] & (~mask)); + v |= (byte)(base64Decode_table[(c & 0x0f) | 0x40] & (~mask)); return v; #else - return base64Decode[c - BASE64_MIN]; + return base64Decode_table[c - BASE64_MIN]; #endif } -#endif int Base64_SkipNewline(const byte* in, word32 *inLen, word32 *outJ) @@ -170,15 +168,13 @@ int Base64_SkipNewline(const byte* in, word32 *inLen, return 0; } -int Base64_Decode(const byte* in, word32 inLen, byte* out, word32* outLen) +int Base64_Decode_nonCT(const byte* in, word32 inLen, byte* out, word32* outLen) { word32 i = 0; word32 j = 0; word32 plainSz = inLen - ((inLen + (BASE64_LINE_SZ - 1)) / BASE64_LINE_SZ ); int ret; -#ifndef BASE64_NO_TABLE - const byte maxIdx = BASE64DECODE_SZ + BASE64_MIN - 1; -#endif + const byte maxIdx = BASE64DECODE_TABLE_SZ + BASE64_MIN - 1; plainSz = (plainSz * 3 + 3) / 4; if (plainSz > *outLen) return BAD_FUNC_ARG; @@ -225,7 +221,6 @@ int Base64_Decode(const byte* in, word32 inLen, byte* out, word32* outLen) if (pad3 && !pad4) return ASN_INPUT_E; -#ifndef BASE64_NO_TABLE if (e1 < BASE64_MIN || e2 < BASE64_MIN || e3 < BASE64_MIN || e4 < BASE64_MIN) { WOLFSSL_MSG("Bad Base64 Decode data, too small"); @@ -236,17 +231,104 @@ int Base64_Decode(const byte* in, word32 inLen, byte* out, word32* outLen) WOLFSSL_MSG("Bad Base64 Decode data, too big"); return ASN_INPUT_E; } -#endif if (i + 1 + !pad3 + !pad4 > *outLen) { WOLFSSL_MSG("Bad Base64 Decode out buffer, too small"); return BAD_FUNC_ARG; } - e1 = Base64_Char2Val(e1); - e2 = Base64_Char2Val(e2); - e3 = (byte)((e3 == PAD) ? 0 : Base64_Char2Val(e3)); - e4 = (byte)((e4 == PAD) ? 0 : Base64_Char2Val(e4)); + e1 = Base64_Char2Val_by_table(e1); + e2 = Base64_Char2Val_by_table(e2); + e3 = (byte)((e3 == PAD) ? 0 : Base64_Char2Val_by_table(e3)); + e4 = (byte)((e4 == PAD) ? 0 : Base64_Char2Val_by_table(e4)); + + if (e1 == BAD || e2 == BAD || e3 == BAD || e4 == BAD) { + WOLFSSL_MSG("Bad Base64 Decode bad character"); + return ASN_INPUT_E; + } + + b1 = (byte)((e1 << 2) | (e2 >> 4)); + b2 = (byte)(((e2 & 0xF) << 4) | (e3 >> 2)); + b3 = (byte)(((e3 & 0x3) << 6) | e4); + + out[i++] = b1; + if (!pad3) + out[i++] = b2; + if (!pad4) + out[i++] = b3; + else + break; + } +/* If the output buffer has a room for an extra byte, add a null terminator */ + if (out && *outLen > i) + out[i]= '\0'; + + *outLen = i; + + return 0; +} + +int Base64_Decode(const byte* in, word32 inLen, byte* out, word32* outLen) +{ + word32 i = 0; + word32 j = 0; + word32 plainSz = inLen - ((inLen + (BASE64_LINE_SZ - 1)) / BASE64_LINE_SZ ); + int ret; + + plainSz = (plainSz * 3 + 3) / 4; + if (plainSz > *outLen) return BAD_FUNC_ARG; + + while (inLen > 3) { + int pad3 = 0; + int pad4 = 0; + byte b1, b2, b3; + byte e1, e2, e3, e4; + + 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; + } + e1 = in[j++]; + if (e1 == '\0') { + break; + } + inLen--; + if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) { + return ret; + } + e2 = in[j++]; + inLen--; + if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) { + return ret; + } + e3 = in[j++]; + inLen--; + if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) { + return ret; + } + e4 = in[j++]; + inLen--; + + if (e3 == PAD) + pad3 = 1; + if (e4 == PAD) + pad4 = 1; + + if (pad3 && !pad4) + return ASN_INPUT_E; + + if (i + 1 + !pad3 + !pad4 > *outLen) { + WOLFSSL_MSG("Bad Base64 Decode out buffer, too small"); + return BAD_FUNC_ARG; + } + + e1 = Base64_Char2Val_CT(e1); + e2 = Base64_Char2Val_CT(e2); + e3 = (byte)((e3 == PAD) ? 0 : Base64_Char2Val_CT(e3)); + e4 = (byte)((e4 == PAD) ? 0 : Base64_Char2Val_CT(e4)); if (e1 == BAD || e2 == BAD || e3 == BAD || e4 == BAD) { WOLFSSL_MSG("Bad Base64 Decode bad character"); diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 9639e4096..f6167b1c2 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -2871,27 +2871,27 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t error_test(void) WOLFSSL_TEST_SUBROUTINE wc_test_ret_t base64_test(void) { wc_test_ret_t ret; - WOLFSSL_SMALL_STACK_STATIC const byte good[] = "A+Gd\0\0\0"; - WOLFSSL_SMALL_STACK_STATIC const byte goodEnd[] = "A+Gd \r\n"; - WOLFSSL_SMALL_STACK_STATIC const byte good_spaces[] = " A + G d \0"; + static const byte good[] = "A+Gd\0\0\0"; + static const byte goodEnd[] = "A+Gd \r\n"; + static const byte good_spaces[] = " A + G d \0"; byte out[128]; word32 outLen; #ifdef WOLFSSL_BASE64_ENCODE byte data[3]; word32 dataLen; byte longData[79] = { 0 }; - WOLFSSL_SMALL_STACK_STATIC const byte symbols[] = "+/A="; + static const byte symbols[] = "+/A="; #endif - WOLFSSL_SMALL_STACK_STATIC const byte badSmall[] = "AAA!Gdj="; - WOLFSSL_SMALL_STACK_STATIC const byte badLarge[] = "AAA~Gdj="; - WOLFSSL_SMALL_STACK_STATIC const byte badEOL[] = "A+Gd!AA"; - WOLFSSL_SMALL_STACK_STATIC const byte badPadding[] = "AA=A"; - WOLFSSL_SMALL_STACK_STATIC const byte badChar[] = ",-.:;<=>?@[\\]^_`"; - byte goodChar[] = + static const byte badSmall[] = "AAA!Gdj="; + static const byte badLarge[] = "AAA~Gdj="; + static const byte badEOL[] = "A+Gd!AA"; + static const byte badPadding[] = "AA=A"; + static const byte badChar[] = ",-.:;<=>?@[\\]^_`"; + static const byte goodChar[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/;"; - byte charTest[] = "A+Gd\0\0\0"; + static const byte charTest[] = "A+Gd\0\0\0"; int i; WOLFSSL_ENTER("base64_test"); @@ -2905,7 +2905,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t base64_test(void) if (ret != 0) return WC_TEST_RET_ENC_EC(ret); outLen = sizeof(goodChar); - ret = Base64_Decode(goodChar, sizeof(goodChar), goodChar, &outLen); + XMEMCPY(out, goodChar, sizeof(goodChar)); + ret = Base64_Decode(out, sizeof(goodChar), out, &outLen); if (ret != 0) return WC_TEST_RET_ENC_EC(ret); if (outLen != 64 / 4 * 3) @@ -2942,24 +2943,102 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t base64_test(void) /* Invalid character less than 0x2b */ for (i = 1; i < 0x2b; i++) { outLen = sizeof(out); - charTest[0] = (byte)i; - ret = Base64_Decode(charTest, sizeof(charTest), out, &outLen); + XMEMCPY(out, charTest, sizeof(charTest)); + out[0] = (byte)i; + ret = Base64_Decode(out, sizeof(charTest), out, &outLen); if (ret != WC_NO_ERR_TRACE(ASN_INPUT_E)) return WC_TEST_RET_ENC_I(i); } /* Bad characters in range 0x2b - 0x7a. */ for (i = 0; i < (int)sizeof(badChar) - 1; i++) { outLen = sizeof(out); - charTest[0] = badChar[i]; - ret = Base64_Decode(charTest, sizeof(charTest), out, &outLen); + XMEMCPY(out, charTest, sizeof(charTest)); + out[0] = badChar[i]; + ret = Base64_Decode(out, sizeof(charTest), out, &outLen); if (ret != WC_NO_ERR_TRACE(ASN_INPUT_E)) return WC_TEST_RET_ENC_I(i); } /* Invalid character greater than 0x7a */ for (i = 0x7b; i < 0x100; i++) { outLen = sizeof(out); - charTest[0] = (byte)i; - ret = Base64_Decode(charTest, sizeof(charTest), out, &outLen); + XMEMCPY(out, charTest, sizeof(charTest)); + out[0] = (byte)i; + ret = Base64_Decode(out, sizeof(charTest), out, &outLen); + if (ret != WC_NO_ERR_TRACE(ASN_INPUT_E)) + return WC_TEST_RET_ENC_I(i); + } + + /* Same tests again, using Base64_Decode_nonCT() */ + + /* Good Base64 encodings. */ + outLen = sizeof(out); + ret = Base64_Decode_nonCT(good, sizeof(good), out, &outLen); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + outLen = sizeof(out); + ret = Base64_Decode_nonCT(goodEnd, sizeof(goodEnd), out, &outLen); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + outLen = sizeof(goodChar); + XMEMCPY(out, goodChar, sizeof(goodChar)); + ret = Base64_Decode_nonCT(out, sizeof(goodChar), out, &outLen); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + if (outLen != 64 / 4 * 3) + return WC_TEST_RET_ENC_NC; + outLen = sizeof(out); + ret = Base64_Decode_nonCT(good_spaces, sizeof(good_spaces), out, &outLen); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* Bad parameters. */ + outLen = 1; + ret = Base64_Decode_nonCT(good, sizeof(good), out, &outLen); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_EC(ret); + + outLen = sizeof(out); + ret = Base64_Decode_nonCT(badEOL, sizeof(badEOL), out, &outLen); + if (ret != WC_NO_ERR_TRACE(ASN_INPUT_E)) + return WC_TEST_RET_ENC_EC(ret); + outLen = sizeof(out); + ret = Base64_Decode_nonCT(badPadding, sizeof(badPadding), out, &outLen); + if (ret != WC_NO_ERR_TRACE(ASN_INPUT_E)) + return WC_TEST_RET_ENC_EC(ret); + /* Bad character at each offset 0-3. */ + for (i = 0; i < 4; i++) { + outLen = sizeof(out); + ret = Base64_Decode_nonCT(badSmall + i, 4, out, &outLen); + if (ret != WC_NO_ERR_TRACE(ASN_INPUT_E)) + return WC_TEST_RET_ENC_I(i); + ret = Base64_Decode_nonCT(badLarge + i, 4, out, &outLen); + if (ret != WC_NO_ERR_TRACE(ASN_INPUT_E)) + return WC_TEST_RET_ENC_I(i); + } + /* Invalid character less than 0x2b */ + for (i = 1; i < 0x2b; i++) { + outLen = sizeof(out); + XMEMCPY(out, charTest, sizeof(charTest)); + out[0] = (byte)i; + ret = Base64_Decode_nonCT(out, sizeof(charTest), out, &outLen); + if (ret != WC_NO_ERR_TRACE(ASN_INPUT_E)) + return WC_TEST_RET_ENC_I(i); + } + /* Bad characters in range 0x2b - 0x7a. */ + for (i = 0; i < (int)sizeof(badChar) - 1; i++) { + outLen = sizeof(out); + XMEMCPY(out, charTest, sizeof(charTest)); + out[0] = badChar[i]; + ret = Base64_Decode_nonCT(out, sizeof(charTest), out, &outLen); + if (ret != WC_NO_ERR_TRACE(ASN_INPUT_E)) + return WC_TEST_RET_ENC_I(i); + } + /* Invalid character greater than 0x7a */ + for (i = 0x7b; i < 0x100; i++) { + outLen = sizeof(out); + XMEMCPY(out, charTest, sizeof(charTest)); + out[0] = (byte)i; + ret = Base64_Decode_nonCT(out, sizeof(charTest), out, &outLen); if (ret != WC_NO_ERR_TRACE(ASN_INPUT_E)) return WC_TEST_RET_ENC_I(i); } diff --git a/wolfssl/wolfcrypt/coding.h b/wolfssl/wolfcrypt/coding.h index a97976eb9..ef87ab403 100644 --- a/wolfssl/wolfcrypt/coding.h +++ b/wolfssl/wolfcrypt/coding.h @@ -36,6 +36,9 @@ WOLFSSL_API int Base64_Decode(const byte* in, word32 inLen, byte* out, word32* outLen); +WOLFSSL_API int Base64_Decode_nonCT(const byte* in, word32 inLen, byte* out, + word32* outLen); + #if defined(OPENSSL_EXTRA) || defined(SESSION_CERTS) || defined(WOLFSSL_KEY_GEN) \ || defined(WOLFSSL_CERT_GEN) || defined(HAVE_WEBSERVER) || !defined(NO_DSA) #ifndef WOLFSSL_BASE64_ENCODE