diff --git a/src/headers/tomcrypt_misc.h b/src/headers/tomcrypt_misc.h index 17aec209..3acb6a3f 100644 --- a/src/headers/tomcrypt_misc.h +++ b/src/headers/tomcrypt_misc.h @@ -12,7 +12,7 @@ int base64_decode_ex(const unsigned char *in, unsigned long len, int base64url_encode(const unsigned char *in, unsigned long len, unsigned char *out, unsigned long *outlen); -#define base64url_decode(i, il, o, ol) base64_decode_ex(i, il, o, ol, LTC_BASE64_STRICT) +#define base64url_decode(i, il, o, ol) base64url_decode_ex(i, il, o, ol, LTC_BASE64_STRICT) int base64url_decode_ex(const unsigned char *in, unsigned long len, unsigned char *out, unsigned long *outlen, int strict); #endif diff --git a/src/misc/base64/base64_decode.c b/src/misc/base64/base64_decode.c index 18f5aa57..922bc506 100644 --- a/src/misc/base64/base64_decode.c +++ b/src/misc/base64/base64_decode.c @@ -117,7 +117,11 @@ static int _base64_decode_internal(const unsigned char *in, unsigned long inlen } } if (y != 0) { - return CRYPT_INVALID_PACKET; + if (y == 1 || map != map_base64url || strict == 1) return CRYPT_INVALID_PACKET; + t = t << (6 * (4 - y)); + if (z + y - 1 > *outlen) return CRYPT_BUFFER_OVERFLOW; + if (y >= 2) out[z++] = (unsigned char) ((t >> 16) & 255); + if (y == 3) out[z++] = (unsigned char) ((t >> 8) & 255); } *outlen = z; return CRYPT_OK; @@ -130,6 +134,7 @@ static int _base64_decode_internal(const unsigned char *in, unsigned long inlen @param inlen The length of the base64 data @param out [out] The destination of the binary decoded data @param outlen [in/out] The max size and resulting size of the decoded data + @param strict Strict[1] or relaxed[0] decoding of the input @return CRYPT_OK if successful */ int base64_decode_ex(const unsigned char *in, unsigned long inlen, @@ -146,6 +151,7 @@ int base64_decode_ex(const unsigned char *in, unsigned long inlen, @param inlen The length of the base64 data @param out [out] The destination of the binary decoded data @param outlen [in/out] The max size and resulting size of the decoded data + @param strict Strict[1] or relaxed[0] decoding of the input @return CRYPT_OK if successful */ int base64url_decode_ex(const unsigned char *in, unsigned long inlen, diff --git a/testprof/base64_test.c b/testprof/base64_test.c index 4b0ac893..1de0f7c0 100644 --- a/testprof/base64_test.c +++ b/testprof/base64_test.c @@ -5,6 +5,9 @@ int base64_test(void) { unsigned char in[64], out[256], tmp[64]; unsigned long x, l1, l2, slen1; + const char special_case[] = + { 0xbe, 0xe8, 0x92, 0x3c, 0xa2, 0x25, 0xf0, 0xf8, 0x91, 0xe4, 0xef, 0xab, + 0x0b, 0x8c, 0xfd, 0xff, 0x14, 0xd0, 0x29, 0x9d }; /* TEST CASES SOURCE: @@ -24,7 +27,18 @@ int base64_test(void) {"foo", "Zm9v" }, {"foob", "Zm9vYg==" }, {"fooba", "Zm9vYmE=" }, - {"foobar", "Zm9vYmFy"} + {"foobar", "Zm9vYmFy"}, + {special_case,"vuiSPKIl8PiR5O+rC4z9/xTQKZ0="} + }; + + const struct { + const char* s; + int mode; + } url_cases[] = { + {"vuiSPKIl8PiR5O-rC4z9_xTQKZ0", 0}, + {"vuiSPKIl8PiR5O-rC4z9_xTQKZ0=", 1}, + {"vuiS*PKIl8P*iR5O-rC4*z9_xTQKZ0", 0}, + {"vuiS*PKIl8P*iR5O-rC4*z9_xTQKZ0=", 0}, }; for (x = 0; x < sizeof(cases)/sizeof(cases[0]); ++x) { @@ -45,6 +59,20 @@ int base64_test(void) } } + for (x = 0; x < sizeof(url_cases)/sizeof(url_cases[0]); ++x) { + slen1 = strlen(url_cases[x].s); + l1 = sizeof(out); + DO(base64url_decode_ex((unsigned char*)url_cases[x].s, slen1, out, &l1, url_cases[x].mode)); + if (l1 != sizeof(special_case) || memcmp(out, special_case, l1)) { + fprintf(stderr, "\nbase64url failed case %lu: %s", x, url_cases[x].s); + print_hex("\nbase64url should", special_case, sizeof(special_case)); + out[sizeof(out)-1] = '\0'; + print_hex("\nbase64url is", out, l1); + return 1; + } + } + + for (x = 0; x < 64; x++) { yarrow_read(in, x, &yarrow_prng); l1 = sizeof(out);