From: Patrick Monnerat Date: Tue, 12 Jul 2022 17:03:45 +0000 (+0200) Subject: base64: base64url encoding has no padding X-Git-Tag: curl-7_85_0~155 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c2e72c7812e83fe59f4e84e12c7fda705b8e236b;p=thirdparty%2Fcurl.git base64: base64url encoding has no padding See RFC4648 section 5 and RFC7540 section 3.2.1. Suppress generation of '=' padding of base64url encoding. This is accomplished by considering the string beginning at offset 64 in the character table as the padding: this is "=" for base64, "" for base64url. Also use strchr() to replace character search loops where possible. Suppress erroneous comments about empty encoding results. Adjust unit test 1302 to unpadded base64url encoding and add tests for empty results. Closes #9139 --- diff --git a/lib/base64.c b/lib/base64.c index d5d79cf96b..53ebc3db30 100644 --- a/lib/base64.c +++ b/lib/base64.c @@ -43,8 +43,9 @@ #include "memdebug.h" /* ---- Base64 Encoding/Decoding Table --- */ +/* Padding character string starts at offset 64. */ static const char base64[]= - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; /* The Base 64 encoding with an URL and filename safe alphabet, RFC 4648 section 5 */ @@ -54,25 +55,18 @@ static const char base64url[]= static size_t decodeQuantum(unsigned char *dest, const char *src) { size_t padding = 0; - const char *s, *p; + const char *s; unsigned long i, x = 0; for(i = 0, s = src; i < 4; i++, s++) { if(*s == '=') { - x = (x << 6); + x <<= 6; padding++; } else { - unsigned long v = 0; - p = base64; - - while(*p && (*p != *s)) { - v++; - p++; - } - - if(*p == *s) - x = (x << 6) + v; + const char *p = strchr(base64, *s); + if(p) + x = (x << 6) + curlx_uztoul(p - base64); else return 0; } @@ -109,11 +103,11 @@ CURLcode Curl_base64_decode(const char *src, unsigned char **outptr, size_t *outlen) { size_t srclen = 0; - size_t length = 0; size_t padding = 0; size_t i; size_t numQuantums; size_t rawlen = 0; + const char *padptr; unsigned char *pos; unsigned char *newstr; @@ -126,19 +120,17 @@ CURLcode Curl_base64_decode(const char *src, return CURLE_BAD_CONTENT_ENCODING; /* Find the position of any = padding characters */ - while((src[length] != '=') && src[length]) - length++; - - /* A maximum of two = padding characters is allowed */ - if(src[length] == '=') { + padptr = strchr(src, '='); + if(padptr) { padding++; - if(src[length + 1] == '=') + /* A maximum of two = padding characters is allowed */ + if(padptr[1] == '=') padding++; - } - /* Check the = padding characters weren't part way through the input */ - if(length + padding != srclen) - return CURLE_BAD_CONTENT_ENCODING; + /* Check the = padding characters weren't part way through the input */ + if(padptr + padding != src + srclen) + return CURLE_BAD_CONTENT_ENCODING; + } /* Calculate the number of quantums */ numQuantums = srclen / 4; @@ -187,6 +179,7 @@ static CURLcode base64_encode(const char *table64, char *output; char *base64data; const char *indata = inputbuff; + const char *padstr = &table64[64]; /* Point to padding string. */ *outptr = NULL; *outlen = 0; @@ -224,27 +217,30 @@ static CURLcode base64_encode(const char *table64, switch(inputparts) { case 1: /* only one byte read */ - msnprintf(output, 5, "%c%c==", - table64[obuf[0]], - table64[obuf[1]]); + i = msnprintf(output, 5, "%c%c%s%s", + table64[obuf[0]], + table64[obuf[1]], + padstr, + padstr); break; case 2: /* two bytes read */ - msnprintf(output, 5, "%c%c%c=", - table64[obuf[0]], - table64[obuf[1]], - table64[obuf[2]]); + i = msnprintf(output, 5, "%c%c%c%s", + table64[obuf[0]], + table64[obuf[1]], + table64[obuf[2]], + padstr); break; default: - msnprintf(output, 5, "%c%c%c%c", - table64[obuf[0]], - table64[obuf[1]], - table64[obuf[2]], - table64[obuf[3]]); + i = msnprintf(output, 5, "%c%c%c%c", + table64[obuf[0]], + table64[obuf[1]], + table64[obuf[2]], + table64[obuf[3]]); break; } - output += 4; + output += i; } /* Zero terminate */ @@ -272,8 +268,6 @@ static CURLcode base64_encode(const char *table64, * Returns CURLE_OK on success, otherwise specific error code. Function * output shall not be considered valid unless CURLE_OK is returned. * - * When encoded data length is 0, returns NULL in *outptr. - * * @unittest: 1302 */ CURLcode Curl_base64_encode(const char *inputbuff, size_t insize, @@ -295,8 +289,6 @@ CURLcode Curl_base64_encode(const char *inputbuff, size_t insize, * Returns CURLE_OK on success, otherwise specific error code. Function * output shall not be considered valid unless CURLE_OK is returned. * - * When encoded data length is 0, returns NULL in *outptr. - * * @unittest: 1302 */ CURLcode Curl_base64url_encode(const char *inputbuff, size_t insize, diff --git a/tests/unit/unit1302.c b/tests/unit/unit1302.c index 77c8b1a74c..12be3c3590 100644 --- a/tests/unit/unit1302.c +++ b/tests/unit/unit1302.c @@ -89,14 +89,14 @@ Curl_safefree(output); rc = Curl_base64url_encode("\xff\x01\xfe\x02", 4, &output, &size); fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); -fail_unless(size == 8, "size should be 8"); -verify_memory(output, "_wH-Ag==", 8); +fail_unless(size == 6, "size should be 6"); +verify_memory(output, "_wH-Ag", 6); Curl_safefree(output); rc = Curl_base64url_encode("iiii", 4, &output, &size); fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); -fail_unless(size == 8, "size should be 8"); -verify_memory(output, "aWlpaQ==", 8); +fail_unless(size == 6, "size should be 6"); +verify_memory(output, "aWlpaQ", 6); Curl_safefree(output); /* 0 length makes it do strlen() */ @@ -106,6 +106,18 @@ fail_unless(size == 8, "size should be 8"); verify_memory(output, "aWlpaQ==", 8); Curl_safefree(output); +rc = Curl_base64_encode("", 0, &output, &size); +fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); +fail_unless(size == 0, "size should be 0"); +fail_unless(output && !output[0], "output should be a zero-length string"); +Curl_safefree(output); + +rc = Curl_base64url_encode("", 0, &output, &size); +fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); +fail_unless(size == 0, "size should be 0"); +fail_unless(output && !output[0], "output should be a zero-length string"); +Curl_safefree(output); + rc = Curl_base64_decode("aWlpaQ==", &decoded, &size); fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); fail_unless(size == 4, "size should be 4");