mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2025-08-01 03:34:39 +02:00
wolfcrypt/src/coding.c, wolfssl/wolfcrypt/coding.h, wolfcrypt/src/asn.c,
wolfcrypt/test/test.c: refactor Base64_Decode() with separate always-CT Base64_Decode() and never-CT Base64_Decode_nonCT(), and use the latter only to decode known-public PEM objects, otherwise use always-CT Base64_Decode().
This commit is contained in:
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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");
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user