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
This commit is contained in:
Patrick Monnerat 2022-07-12 19:03:45 +02:00 committed by Daniel Stenberg
parent dfe5a3023b
commit c2e72c7812
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
2 changed files with 49 additions and 45 deletions

View File

@ -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,

View File

@ -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");