From b10f9502f88c930a114a9e184bdad795d099d5f5 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Sat, 23 Jan 2016 13:09:56 +0100 Subject: [PATCH 01/10] add RFC4648 base64 decoding compliance --- src/headers/tomcrypt_custom.h | 5 +++++ src/headers/tomcrypt_misc.h | 10 ++++++---- src/misc/base64/base64_decode.c | 21 +++++++++++++-------- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/headers/tomcrypt_custom.h b/src/headers/tomcrypt_custom.h index 33e4bc0..c8bc690 100644 --- a/src/headers/tomcrypt_custom.h +++ b/src/headers/tomcrypt_custom.h @@ -476,6 +476,11 @@ #define LTC_PKCS_1 #endif +#if (defined(LTC_BASE64) || defined(LTC_BASE64_URL)) && !defined(LTC_BASE64_STRICT) + /* By default we're doing strict decoding now */ + #define LTC_BASE64_STRICT 1 +#endif + #if defined(TFM_DESC) && defined(LTC_RSA_BLINDING) #warning RSA blinding currently not supported in combination with TFM #undef LTC_RSA_BLINDING diff --git a/src/headers/tomcrypt_misc.h b/src/headers/tomcrypt_misc.h index 2f670cc..17aec20 100644 --- a/src/headers/tomcrypt_misc.h +++ b/src/headers/tomcrypt_misc.h @@ -3,16 +3,18 @@ int base64_encode(const unsigned char *in, unsigned long len, unsigned char *out, unsigned long *outlen); -int base64_decode(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen); +#define base64_decode(i, il, o, ol) base64_decode_ex(i, il, o, ol, LTC_BASE64_STRICT) +int base64_decode_ex(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, int strict); #endif #ifdef LTC_BASE64_URL int base64url_encode(const unsigned char *in, unsigned long len, unsigned char *out, unsigned long *outlen); -int base64url_decode(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) +int base64url_decode_ex(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, int strict); #endif /* ===> LTC_HKDF -- RFC5869 HMAC-based Key Derivation Function <=== */ diff --git a/src/misc/base64/base64_decode.c b/src/misc/base64/base64_decode.c index 423dc43..18f5aa5 100644 --- a/src/misc/base64/base64_decode.c +++ b/src/misc/base64/base64_decode.c @@ -73,7 +73,7 @@ static const unsigned char map_base64url[256] = { static int _base64_decode_internal(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, - const unsigned char *map) + const unsigned char *map, int strict) { unsigned long t, x, y, z; unsigned char c; @@ -86,7 +86,12 @@ static int _base64_decode_internal(const unsigned char *in, unsigned long inlen g = 3; for (x = y = z = t = 0; x < inlen; x++) { c = map[in[x]&0xFF]; - if (c == 255) continue; + if (c == 255) { + if (strict) + return CRYPT_INVALID_PACKET; + else + continue; + } /* the final = symbols are read and used to trim the remaining bytes */ if (c == 254) { c = 0; @@ -127,10 +132,10 @@ static int _base64_decode_internal(const unsigned char *in, unsigned long inlen @param outlen [in/out] The max size and resulting size of the decoded data @return CRYPT_OK if successful */ -int base64_decode(const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen) +int base64_decode_ex(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, int strict) { - return _base64_decode_internal(in, inlen, out, outlen, map_base64); + return _base64_decode_internal(in, inlen, out, outlen, map_base64, strict); } #endif /* LTC_BASE64 */ @@ -143,10 +148,10 @@ int base64_decode(const unsigned char *in, unsigned long inlen, @param outlen [in/out] The max size and resulting size of the decoded data @return CRYPT_OK if successful */ -int base64url_decode(const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen) +int base64url_decode_ex(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, int strict) { - return _base64_decode_internal(in, inlen, out, outlen, map_base64url); + return _base64_decode_internal(in, inlen, out, outlen, map_base64url, strict); } #endif /* LTC_BASE64_URL */ From 1c0edfdeaded15fa972bd50e75adc6b00e0f3e8e Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Sat, 23 Jan 2016 13:14:50 +0100 Subject: [PATCH 02/10] add/fix tests add explicit strict&loose base64-decode tests --- testprof/base64_test.c | 16 ++++++++++++++++ testprof/der_tests.c | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/testprof/base64_test.c b/testprof/base64_test.c index 8c15d3c..4b0ac89 100644 --- a/testprof/base64_test.c +++ b/testprof/base64_test.c @@ -56,6 +56,22 @@ int base64_test(void) return 1; } } + + x--; + memmove(&out[11], &out[10], l1 - 10); + out[10] = '\0'; + l1++; + l2 = sizeof(tmp); + DO(base64_decode_ex(out, l1, tmp, &l2, 0)); + if (l2 != x || memcmp(tmp, in, x)) { + fprintf(stderr, "loose base64 decoding failed %lu %lu %lu", x, l1, l2); + print_hex("is ", tmp, l2); + print_hex("should", in, x); + print_hex("input ", out, l1); + return 1; + } + l2 = sizeof(tmp); + DO(base64_decode_ex(out, l1, tmp, &l2, 1) == CRYPT_INVALID_PACKET ? CRYPT_OK : CRYPT_INVALID_PACKET); return 0; } #endif diff --git a/testprof/der_tests.c b/testprof/der_tests.c index b79a5ae..322b49a 100644 --- a/testprof/der_tests.c +++ b/testprof/der_tests.c @@ -392,7 +392,7 @@ static void der_cacert_test(void) ltc_asn1_list *decoded_list, *l, *l1, *l2; - DO(base64_decode(_der_tests_cacert_root_cert, sizeof(_der_tests_cacert_root_cert), buf, &len1)); + DO(base64_decode_ex(_der_tests_cacert_root_cert, sizeof(_der_tests_cacert_root_cert), buf, &len1, 0)); len2 = len1; DO(der_decode_sequence_flexi(buf, &len2, &decoded_list)); From 063bac396d7537acf66d9a843a881a8d72e8bc23 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Sat, 23 Jan 2016 17:04:53 +0100 Subject: [PATCH 03/10] add LTC_BASE64_STRICT to crypt_build_settings and crypt_constants --- src/misc/crypt/crypt.c | 3 +++ src/misc/crypt/crypt_constants.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/misc/crypt/crypt.c b/src/misc/crypt/crypt.c index d277901..fc1116a 100644 --- a/src/misc/crypt/crypt.c +++ b/src/misc/crypt/crypt.c @@ -337,6 +337,9 @@ const char *crypt_build_settings = #if defined(LTC_BASE64_URL) " BASE64-URL-SAFE " #endif +#if defined(LTC_BASE64) || defined(LTC_BASE64_URL) + " "NAME_VALUE(LTC_BASE64_STRICT)" " +#endif #if defined(LTC_CRC32) " CRC32 " #endif diff --git a/src/misc/crypt/crypt_constants.c b/src/misc/crypt/crypt_constants.c index 03755b0..79c6e0c 100755 --- a/src/misc/crypt/crypt_constants.c +++ b/src/misc/crypt/crypt_constants.c @@ -89,6 +89,10 @@ static const crypt_constant _crypt_constants[] = { {"LTC_CTR_MODE", 0}, #endif +#if defined(LTC_BASE64) || defined(LTC_BASE64_URL) + _C_STRINGIFY(LTC_BASE64_STRICT), +#endif + _C_STRINGIFY(MAXBLOCKSIZE), _C_STRINGIFY(TAB_SIZE), _C_STRINGIFY(ARGTYPE), From bc16c149fc6ab45c4f265f3b325c6b706ed7c4d5 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Sun, 3 Apr 2016 14:11:11 +0200 Subject: [PATCH 04/10] fix base64[url] strict/relaxed decode --- src/headers/tomcrypt_misc.h | 2 +- src/misc/base64/base64_decode.c | 8 +++++++- testprof/base64_test.c | 30 +++++++++++++++++++++++++++++- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/headers/tomcrypt_misc.h b/src/headers/tomcrypt_misc.h index 17aec20..3acb6a3 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 18f5aa5..922bc50 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 4b0ac89..1de0f7c 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); From 53359ccfc6a1c9384bd0cdd6a4c627f46068f987 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Sat, 24 Sep 2016 16:45:48 +0200 Subject: [PATCH 05/10] fix failing test --- testprof/base64_test.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/testprof/base64_test.c b/testprof/base64_test.c index 1de0f7c..5177fbc 100644 --- a/testprof/base64_test.c +++ b/testprof/base64_test.c @@ -5,9 +5,10 @@ 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 }; + const char special_case[] = { + 0xbe, 0xe8, 0x92, 0x3c, 0xa2, 0x25, 0xf0, 0xf8, + 0x91, 0xe4, 0xef, 0xab, 0x0b, 0x8c, 0xfd, 0xff, + 0x14, 0xd0, 0x29, 0x9d, 0x00 }; /* TEST CASES SOURCE: @@ -63,9 +64,9 @@ int base64_test(void) 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)) { + if (l1 != strlen(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)); + print_hex("\nbase64url should", special_case, strlen(special_case)); out[sizeof(out)-1] = '\0'; print_hex("\nbase64url is", out, l1); return 1; From c1dd1cbe309eb2c8fca2a1c489819975f665da3a Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Fri, 17 Feb 2017 11:18:58 +0100 Subject: [PATCH 06/10] re-work strict/relaxed base64 decoding implementation Instead of one API function with an option parameter, provide two API functions. Instead of defaulting to strict decoding, default to relaxed decoding. --- src/headers/tomcrypt_custom.h | 5 ---- src/headers/tomcrypt_misc.h | 14 +++++----- src/misc/base64/base64_decode.c | 45 ++++++++++++++++++++++++-------- src/misc/crypt/crypt.c | 3 --- src/misc/crypt/crypt_constants.c | 4 --- testprof/base64_test.c | 13 +++++---- testprof/der_tests.c | 2 +- 7 files changed, 51 insertions(+), 35 deletions(-) diff --git a/src/headers/tomcrypt_custom.h b/src/headers/tomcrypt_custom.h index c8bc690..33e4bc0 100644 --- a/src/headers/tomcrypt_custom.h +++ b/src/headers/tomcrypt_custom.h @@ -476,11 +476,6 @@ #define LTC_PKCS_1 #endif -#if (defined(LTC_BASE64) || defined(LTC_BASE64_URL)) && !defined(LTC_BASE64_STRICT) - /* By default we're doing strict decoding now */ - #define LTC_BASE64_STRICT 1 -#endif - #if defined(TFM_DESC) && defined(LTC_RSA_BLINDING) #warning RSA blinding currently not supported in combination with TFM #undef LTC_RSA_BLINDING diff --git a/src/headers/tomcrypt_misc.h b/src/headers/tomcrypt_misc.h index 3acb6a3..092c625 100644 --- a/src/headers/tomcrypt_misc.h +++ b/src/headers/tomcrypt_misc.h @@ -3,18 +3,20 @@ int base64_encode(const unsigned char *in, unsigned long len, unsigned char *out, unsigned long *outlen); -#define base64_decode(i, il, o, ol) base64_decode_ex(i, il, o, ol, LTC_BASE64_STRICT) -int base64_decode_ex(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, int strict); +int base64_decode(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen); +int base64_strict_decode(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen); #endif #ifdef LTC_BASE64_URL int base64url_encode(const unsigned char *in, unsigned long len, unsigned char *out, unsigned long *outlen); -#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); +int base64url_decode(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen); +int base64url_strict_decode(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen); #endif /* ===> LTC_HKDF -- RFC5869 HMAC-based Key Derivation Function <=== */ diff --git a/src/misc/base64/base64_decode.c b/src/misc/base64/base64_decode.c index 922bc50..410bc01 100644 --- a/src/misc/base64/base64_decode.c +++ b/src/misc/base64/base64_decode.c @@ -71,9 +71,14 @@ static const unsigned char map_base64url[256] = { 255, 255, 255, 255 }; #endif /* LTC_BASE64_URL */ +enum { + relaxed = 0, + strict = 1 +}; + static int _base64_decode_internal(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, - const unsigned char *map, int strict) + const unsigned char *map, int is_strict) { unsigned long t, x, y, z; unsigned char c; @@ -87,7 +92,7 @@ static int _base64_decode_internal(const unsigned char *in, unsigned long inlen for (x = y = z = t = 0; x < inlen; x++) { c = map[in[x]&0xFF]; if (c == 255) { - if (strict) + if (is_strict) return CRYPT_INVALID_PACKET; else continue; @@ -117,7 +122,7 @@ static int _base64_decode_internal(const unsigned char *in, unsigned long inlen } } if (y != 0) { - if (y == 1 || map != map_base64url || strict == 1) return CRYPT_INVALID_PACKET; + if (y == 1 || map != map_base64url || is_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); @@ -129,18 +134,31 @@ static int _base64_decode_internal(const unsigned char *in, unsigned long inlen #if defined(LTC_BASE64) /** - base64 decode a block of memory + Relaxed base64 decode a block of memory @param in The base64 data to decode @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, - unsigned char *out, unsigned long *outlen, int strict) +int base64_decode(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen) { - return _base64_decode_internal(in, inlen, out, outlen, map_base64, strict); + return _base64_decode_internal(in, inlen, out, outlen, map_base64, relaxed); +} + +/** + Strict base64 decode a block of memory + @param in The base64 data to decode + @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 + @return CRYPT_OK if successful +*/ +int base64_strict_decode(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen) +{ + return _base64_decode_internal(in, inlen, out, outlen, map_base64, strict); } #endif /* LTC_BASE64 */ @@ -151,11 +169,16 @@ 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, - unsigned char *out, unsigned long *outlen, int strict) +int base64url_decode(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen) +{ + return _base64_decode_internal(in, inlen, out, outlen, map_base64url, relaxed); +} + +int base64url_strict_decode(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen) { return _base64_decode_internal(in, inlen, out, outlen, map_base64url, strict); } diff --git a/src/misc/crypt/crypt.c b/src/misc/crypt/crypt.c index fc1116a..d277901 100644 --- a/src/misc/crypt/crypt.c +++ b/src/misc/crypt/crypt.c @@ -337,9 +337,6 @@ const char *crypt_build_settings = #if defined(LTC_BASE64_URL) " BASE64-URL-SAFE " #endif -#if defined(LTC_BASE64) || defined(LTC_BASE64_URL) - " "NAME_VALUE(LTC_BASE64_STRICT)" " -#endif #if defined(LTC_CRC32) " CRC32 " #endif diff --git a/src/misc/crypt/crypt_constants.c b/src/misc/crypt/crypt_constants.c index 79c6e0c..03755b0 100755 --- a/src/misc/crypt/crypt_constants.c +++ b/src/misc/crypt/crypt_constants.c @@ -89,10 +89,6 @@ static const crypt_constant _crypt_constants[] = { {"LTC_CTR_MODE", 0}, #endif -#if defined(LTC_BASE64) || defined(LTC_BASE64_URL) - _C_STRINGIFY(LTC_BASE64_STRICT), -#endif - _C_STRINGIFY(MAXBLOCKSIZE), _C_STRINGIFY(TAB_SIZE), _C_STRINGIFY(ARGTYPE), diff --git a/testprof/base64_test.c b/testprof/base64_test.c index 5177fbc..484507c 100644 --- a/testprof/base64_test.c +++ b/testprof/base64_test.c @@ -34,7 +34,7 @@ int base64_test(void) const struct { const char* s; - int mode; + int is_strict; } url_cases[] = { {"vuiSPKIl8PiR5O-rC4z9_xTQKZ0", 0}, {"vuiSPKIl8PiR5O-rC4z9_xTQKZ0=", 1}, @@ -63,7 +63,10 @@ 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(url_cases[x].is_strict) + DO(base64url_strict_decode((unsigned char*)url_cases[x].s, slen1, out, &l1)); + else + DO(base64url_decode((unsigned char*)url_cases[x].s, slen1, out, &l1)); if (l1 != strlen(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, strlen(special_case)); @@ -91,16 +94,16 @@ int base64_test(void) out[10] = '\0'; l1++; l2 = sizeof(tmp); - DO(base64_decode_ex(out, l1, tmp, &l2, 0)); + DO(base64_decode(out, l1, tmp, &l2)); if (l2 != x || memcmp(tmp, in, x)) { - fprintf(stderr, "loose base64 decoding failed %lu %lu %lu", x, l1, l2); + fprintf(stderr, "relaxed base64 decoding failed %lu %lu %lu", x, l1, l2); print_hex("is ", tmp, l2); print_hex("should", in, x); print_hex("input ", out, l1); return 1; } l2 = sizeof(tmp); - DO(base64_decode_ex(out, l1, tmp, &l2, 1) == CRYPT_INVALID_PACKET ? CRYPT_OK : CRYPT_INVALID_PACKET); + DO(base64_strict_decode(out, l1, tmp, &l2) == CRYPT_INVALID_PACKET ? CRYPT_OK : CRYPT_INVALID_PACKET); return 0; } #endif diff --git a/testprof/der_tests.c b/testprof/der_tests.c index 322b49a..b79a5ae 100644 --- a/testprof/der_tests.c +++ b/testprof/der_tests.c @@ -392,7 +392,7 @@ static void der_cacert_test(void) ltc_asn1_list *decoded_list, *l, *l1, *l2; - DO(base64_decode_ex(_der_tests_cacert_root_cert, sizeof(_der_tests_cacert_root_cert), buf, &len1, 0)); + DO(base64_decode(_der_tests_cacert_root_cert, sizeof(_der_tests_cacert_root_cert), buf, &len1)); len2 = len1; DO(der_decode_sequence_flexi(buf, &len2, &decoded_list)); From ff3a03a1d09ba0b16231cc19546a716dcc74788b Mon Sep 17 00:00:00 2001 From: Karel Miko Date: Mon, 20 Feb 2017 23:26:10 +0100 Subject: [PATCH 07/10] tuning base64 decoding implementation --- src/misc/base64/base64_decode.c | 41 ++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/misc/base64/base64_decode.c b/src/misc/base64/base64_decode.c index 410bc01..86060f6 100644 --- a/src/misc/base64/base64_decode.c +++ b/src/misc/base64/base64_decode.c @@ -88,41 +88,38 @@ static int _base64_decode_internal(const unsigned char *in, unsigned long inlen LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); - g = 3; + g = 0; /* '=' counter */ for (x = y = z = t = 0; x < inlen; x++) { c = map[in[x]&0xFF]; + if (c == 254) { + g++; + continue; + } + else if (is_strict && g > 0) { + /* we only allow '=' to be at the end */ + return CRYPT_INVALID_PACKET; + } if (c == 255) { if (is_strict) return CRYPT_INVALID_PACKET; else continue; } - /* the final = symbols are read and used to trim the remaining bytes */ - if (c == 254) { - c = 0; - /* prevent g < 0 which would potentially allow an overflow later */ - if (--g < 0) { - return CRYPT_INVALID_PACKET; - } - } else if (g != 3) { - /* we only allow = to be at the end */ - return CRYPT_INVALID_PACKET; - } t = (t<<6)|c; if (++y == 4) { - if (z + g > *outlen) { - return CRYPT_BUFFER_OVERFLOW; - } + if (z + 3 > *outlen) return CRYPT_BUFFER_OVERFLOW; out[z++] = (unsigned char)((t>>16)&255); - if (g > 1) out[z++] = (unsigned char)((t>>8)&255); - if (g > 2) out[z++] = (unsigned char)(t&255); + out[z++] = (unsigned char)((t>>8)&255); + out[z++] = (unsigned char)(t&255); y = t = 0; } } + if (y != 0) { - if (y == 1 || map != map_base64url || is_strict == 1) return CRYPT_INVALID_PACKET; + if (y == 1) return CRYPT_INVALID_PACKET; + if ((y + g) != 4 && is_strict) 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); @@ -177,6 +174,14 @@ int base64url_decode(const unsigned char *in, unsigned long inlen, return _base64_decode_internal(in, inlen, out, outlen, map_base64url, relaxed); } +/** + Strict base64 (URL Safe, RFC 4648 section 5) decode a block of memory + @param in The base64 data to decode + @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 + @return CRYPT_OK if successful +*/ int base64url_strict_decode(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen) { From 006c601efb298786f85b82fd4ebb2d12c198e4b4 Mon Sep 17 00:00:00 2001 From: Karel Miko Date: Tue, 21 Feb 2017 01:51:12 +0100 Subject: [PATCH 08/10] no trailing = for base64url --- src/misc/base64/base64_decode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/misc/base64/base64_decode.c b/src/misc/base64/base64_decode.c index 86060f6..1babfbc 100644 --- a/src/misc/base64/base64_decode.c +++ b/src/misc/base64/base64_decode.c @@ -119,7 +119,7 @@ static int _base64_decode_internal(const unsigned char *in, unsigned long inlen if (y != 0) { if (y == 1) return CRYPT_INVALID_PACKET; - if ((y + g) != 4 && is_strict) return CRYPT_INVALID_PACKET; + if ((y + g) != 4 && is_strict && map != map_base64url) 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); @@ -161,7 +161,7 @@ int base64_strict_decode(const unsigned char *in, unsigned long inlen, #if defined(LTC_BASE64_URL) /** - base64 (URL Safe, RFC 4648 section 5) decode a block of memory + Relaxed base64 (URL Safe, RFC 4648 section 5) decode a block of memory @param in The base64 data to decode @param inlen The length of the base64 data @param out [out] The destination of the binary decoded data From eee936d7528d327bc5ddccddbefab29f050a60a3 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Tue, 21 Feb 2017 00:37:16 +0100 Subject: [PATCH 09/10] add base64url_strict_encode() --- src/headers/tomcrypt_misc.h | 2 ++ src/misc/base64/base64_encode.c | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/src/headers/tomcrypt_misc.h b/src/headers/tomcrypt_misc.h index 092c625..4f5e8fa 100644 --- a/src/headers/tomcrypt_misc.h +++ b/src/headers/tomcrypt_misc.h @@ -12,6 +12,8 @@ int base64_strict_decode(const unsigned char *in, unsigned long len, #ifdef LTC_BASE64_URL int base64url_encode(const unsigned char *in, unsigned long len, unsigned char *out, unsigned long *outlen); +int base64url_strict_encode(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen); int base64url_decode(const unsigned char *in, unsigned long len, unsigned char *out, unsigned long *outlen); diff --git a/src/misc/base64/base64_encode.c b/src/misc/base64/base64_encode.c index 0ed0aa3..c87f302 100644 --- a/src/misc/base64/base64_encode.c +++ b/src/misc/base64/base64_encode.c @@ -110,6 +110,12 @@ int base64url_encode(const unsigned char *in, unsigned long inlen, { return _base64_encode_internal(in, inlen, out, outlen, codes_base64url, 0); } + +int base64url_strict_encode(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen) +{ + return _base64_encode_internal(in, inlen, out, outlen, codes_base64url, 1); +} #endif /* LTC_BASE64_URL */ #endif From abf0a18290eafb3cf662a5eaa6f04461ed0cdd87 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Tue, 21 Feb 2017 00:39:10 +0100 Subject: [PATCH 10/10] add some testcases --- testprof/base64_test.c | 47 +++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/testprof/base64_test.c b/testprof/base64_test.c index 484507c..9868a0f 100644 --- a/testprof/base64_test.c +++ b/testprof/base64_test.c @@ -40,22 +40,24 @@ int base64_test(void) {"vuiSPKIl8PiR5O-rC4z9_xTQKZ0=", 1}, {"vuiS*PKIl8P*iR5O-rC4*z9_xTQKZ0", 0}, {"vuiS*PKIl8P*iR5O-rC4*z9_xTQKZ0=", 0}, + {"vuiS*PKIl8P*iR5O-rC4*z9_xTQKZ0==", 0}, + {"vuiS*PKIl8P*iR5O-rC4*z9_xTQKZ0===", 0}, + {"vuiS*PKIl8P*iR5O-rC4*z9_xTQKZ0====", 0}, + {"vuiS*=PKIl8P*iR5O-rC4*z9_xTQKZ0=", 0}, + {"vuiS*==PKIl8P*iR5O-rC4*z9_xTQKZ0=", 0}, + {"vuiS*===PKIl8P*iR5O-rC4*z9_xTQKZ0=", 0}, }; for (x = 0; x < sizeof(cases)/sizeof(cases[0]); ++x) { + memset(out, 0, sizeof(out)); + memset(tmp, 0, sizeof(tmp)); slen1 = strlen(cases[x].s); l1 = sizeof(out); DO(base64_encode((unsigned char*)cases[x].s, slen1, out, &l1)); l2 = sizeof(tmp); - DO(base64_decode(out, l1, tmp, &l2)); - if (l2 != slen1 || l1 != strlen(cases[x].b64) || memcmp(tmp, cases[x].s, l2) || memcmp(out, cases[x].b64, l1)) { - fprintf(stderr, "\nbase64 failed case %lu", x); - fprintf(stderr, "\nbase64 should: %s", cases[x].b64); - out[sizeof(out)-1] = '\0'; - fprintf(stderr, "\nbase64 is: %s", out); - fprintf(stderr, "\nplain should: %s", cases[x].s); - tmp[sizeof(tmp)-1] = '\0'; - fprintf(stderr, "\nplain is: %s\n", tmp); + DO(base64_strict_decode(out, l1, tmp, &l2)); + if (compare_testvector(out, l1, cases[x].b64, strlen(cases[x].b64), "base64 encode", x) || + compare_testvector(tmp, l2, cases[x].s, slen1, "base64 decode", x)) { return 1; } } @@ -67,15 +69,22 @@ int base64_test(void) DO(base64url_strict_decode((unsigned char*)url_cases[x].s, slen1, out, &l1)); else DO(base64url_decode((unsigned char*)url_cases[x].s, slen1, out, &l1)); - if (l1 != strlen(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, strlen(special_case)); - out[sizeof(out)-1] = '\0'; - print_hex("\nbase64url is", out, l1); + if (compare_testvector(out, l1, special_case, strlen(special_case), "base64url decode", x)) { return 1; } + if(x < 2) { + l2 = sizeof(tmp); + if(x == 0) + DO(base64url_encode(out, l1, tmp, &l2)); + else + DO(base64url_strict_encode(out, l1, tmp, &l2)); + if (compare_testvector(tmp, l2, url_cases[x].s, strlen(url_cases[x].s), "base64url encode", x)) { + return 1; + } + } } + DO(base64url_strict_decode((unsigned char*)url_cases[4].s, slen1, out, &l1) == CRYPT_INVALID_PACKET ? CRYPT_OK : CRYPT_INVALID_PACKET); for (x = 0; x < 64; x++) { yarrow_read(in, x, &yarrow_prng); @@ -83,22 +92,18 @@ int base64_test(void) DO(base64_encode(in, x, out, &l1)); l2 = sizeof(tmp); DO(base64_decode(out, l1, tmp, &l2)); - if (l2 != x || memcmp(tmp, in, x)) { - fprintf(stderr, "base64 failed %lu %lu %lu", x, l1, l2); + if (compare_testvector(tmp, x, in, x, "random base64", x)) { return 1; } } x--; memmove(&out[11], &out[10], l1 - 10); - out[10] = '\0'; + out[10] = '='; l1++; l2 = sizeof(tmp); DO(base64_decode(out, l1, tmp, &l2)); - if (l2 != x || memcmp(tmp, in, x)) { - fprintf(stderr, "relaxed base64 decoding failed %lu %lu %lu", x, l1, l2); - print_hex("is ", tmp, l2); - print_hex("should", in, x); + if (compare_testvector(tmp, l2, in, l2, "relaxed base64 decoding", -1)) { print_hex("input ", out, l1); return 1; }