mirror of
https://github.com/curl/curl.git
synced 2026-04-14 00:51:42 +08:00
We used to treat 0 as "call strlen() to get the length" for curlx_base64_encode, but it turns out this is rather fragile as we easily do the mistake of passing in zero when the data is actually not there and then calling strlen() is wrong. Force the caller to pass in the correct size. A zero length input string now returns a zero length output and a NULL pointer. Closes #18617
200 lines
6.9 KiB
C
200 lines
6.9 KiB
C
/***************************************************************************
|
|
* _ _ ____ _
|
|
* Project ___| | | | _ \| |
|
|
* / __| | | | |_) | |
|
|
* | (__| |_| | _ <| |___
|
|
* \___|\___/|_| \_\_____|
|
|
*
|
|
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
|
*
|
|
* This software is licensed as described in the file COPYING, which
|
|
* you should have received as part of this distribution. The terms
|
|
* are also available at https://curl.se/docs/copyright.html.
|
|
*
|
|
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
|
* copies of the Software, and permit persons to whom the Software is
|
|
* furnished to do so, under the terms of the COPYING file.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
* SPDX-License-Identifier: curl
|
|
*
|
|
***************************************************************************/
|
|
#include "unitcheck.h"
|
|
|
|
#include "urldata.h"
|
|
#include "url.h" /* for Curl_safefree */
|
|
#include "memdebug.h" /* LAST include file */
|
|
|
|
struct etest {
|
|
const char *input;
|
|
size_t ilen;
|
|
const char *output;
|
|
size_t olen;
|
|
};
|
|
|
|
static CURLcode test_unit1302(const char *arg)
|
|
{
|
|
UNITTEST_BEGIN_SIMPLE
|
|
CURLcode rc;
|
|
unsigned int i;
|
|
|
|
/* common base64 encoding */
|
|
struct etest encode[] = {
|
|
{"iiiiii", 1, "aQ==", 4 },
|
|
{"iiiiii", 2, "aWk=", 4 },
|
|
{"iiiiii", 3, "aWlp", 4 },
|
|
{"iiiiii", 4, "aWlpaQ==", 8 },
|
|
{"iiiiii", 5, "aWlpaWk=", 8 },
|
|
{"iiiiii", 6, "aWlpaWlp", 8 },
|
|
{"iiiiiii", 7, "aWlpaWlpaQ==", 12 },
|
|
{"iiiiiiii", 8, "aWlpaWlpaWk=", 12 },
|
|
{"iiiiiiiii", 9, "aWlpaWlpaWlp", 12 },
|
|
{"iiiiiiiiii", 10, "aWlpaWlpaWlpaQ==", 16 },
|
|
{"iiiiiiiiiii", 11, "aWlpaWlpaWlpaWk=", 16 },
|
|
{"iiiiiiiiiiii", 12, "aWlpaWlpaWlpaWlp", 16 },
|
|
{"\xff\x01\xfe\x02", 4, "/wH+Ag==", 8 },
|
|
{"\xff\xff\xff\xff", 4, "/////w==", 8 },
|
|
{"\x00\x00\x00\x00", 4, "AAAAAA==", 8 },
|
|
{"\x00\x00\x00\x00", 1, "AA==", 4 },
|
|
};
|
|
|
|
/* base64 URL encoding */
|
|
struct etest url[] = {
|
|
{"", 0, "", 0 },
|
|
{"iiiiiiiiiii", 1, "aQ", 2 },
|
|
{"iiiiiiiiiii", 2, "aWk", 3 },
|
|
{"iiiiiiiiiii", 3, "aWlp", 4 },
|
|
{"iiiiiiiiiii", 4, "aWlpaQ", 6 },
|
|
{"iiiiiiiiiii", 5, "aWlpaWk", 7 },
|
|
{"iiiiiiiiiii", 6, "aWlpaWlp", 8 },
|
|
{"iiiiiiiiiii", 7, "aWlpaWlpaQ", 10 },
|
|
{"iiiiiiiiiii", 8, "aWlpaWlpaWk", 11 },
|
|
{"iiiiiiiiiii", 9, "aWlpaWlpaWlp", 12 },
|
|
{"iiiiiiiiiii", 10, "aWlpaWlpaWlpaQ", 14 },
|
|
{"iiiiiiiiiii", 11, "aWlpaWlpaWlpaWk", 15 },
|
|
{"iiiiiiiiiiii", 12, "aWlpaWlpaWlpaWlp", 16 },
|
|
{"\xff\x01\xfe\x02", 4, "_wH-Ag", 6 },
|
|
{"\xff\xff\xff\xff", 4, "_____w", 6 },
|
|
{"\xff\x00\xff\x00", 4, "_wD_AA", 6 },
|
|
{"\x00\xff\x00\xff", 4, "AP8A_w", 6 },
|
|
{"\x00\x00\x00\x00", 4, "AAAAAA", 6 },
|
|
{"\x00", 1, "AA", 2 },
|
|
{"\x01", 1, "AQ", 2 },
|
|
{"\x02", 1, "Ag", 2 },
|
|
{"\x03", 1, "Aw", 2 },
|
|
{"\x04", 1, "BA", 2 }, /* spellchecker:disable-line */
|
|
{"\x05", 1, "BQ", 2 },
|
|
{"\x06", 1, "Bg", 2 },
|
|
{"\x07", 1, "Bw", 2 },
|
|
{"\x08", 1, "CA", 2 },
|
|
{"\x09", 1, "CQ", 2 },
|
|
{"\x0a", 1, "Cg", 2 },
|
|
{"\x0b", 1, "Cw", 2 },
|
|
{"\x0c", 1, "DA", 2 },
|
|
{"\x0d", 1, "DQ", 2 },
|
|
{"\x0e", 1, "Dg", 2 },
|
|
{"\x0f", 1, "Dw", 2 },
|
|
{"\x10", 1, "EA", 2 },
|
|
};
|
|
|
|
/* bad decode inputs */
|
|
struct etest badecode[] = {
|
|
{"", 0, "", 0 }, /* no dats means error */
|
|
{"", 0, "a", 1 }, /* data is too short */
|
|
{"", 0, "aQ", 2 }, /* data is too short */
|
|
{"", 0, "aQ=", 3 }, /* data is too short */
|
|
{"", 0, "====", 1 }, /* data is only padding characters */
|
|
{"", 0, "====", 2 }, /* data is only padding characters */
|
|
{"", 0, "====", 3 }, /* data is only padding characters */
|
|
{"", 0, "====", 4 }, /* data is only padding characters */
|
|
{"", 0, "a===", 4 }, /* contains three padding characters */
|
|
{"", 0, "a=Q=", 4 }, /* contains a padding character mid input */
|
|
{"", 0, "aWlpa=Q=", 8 }, /* contains a padding character mid input */
|
|
{"", 0, "a\x1f==", 4 }, /* contains illegal base64 character */
|
|
{"", 0, "abcd ", 5 }, /* contains illegal base64 character */
|
|
{"", 0, "abcd ", 6 }, /* contains illegal base64 character */
|
|
{"", 0, " abcd", 5 }, /* contains illegal base64 character */
|
|
{"", 0, "_abcd", 5 }, /* contains illegal base64 character */
|
|
{"", 0, "abcd-", 5 }, /* contains illegal base64 character */
|
|
{"", 0, "abcd_", 5 }, /* contains illegal base64 character */
|
|
{"", 0, "aWlpaWlpaQ==-", 17}, /* bad character after padding */
|
|
{"", 0, "aWlpaWlpaQ==_", 17}, /* bad character after padding */
|
|
{"", 0, "aWlpaWlpaQ== ", 17}, /* bad character after padding */
|
|
{"", 0, "aWlpaWlpaQ=", 15} /* unaligned size, missing a padding char */
|
|
};
|
|
|
|
for(i = 0 ; i < CURL_ARRAYSIZE(encode); i++) {
|
|
struct etest *e = &encode[i];
|
|
char *out;
|
|
unsigned char *decoded;
|
|
size_t olen;
|
|
size_t dlen;
|
|
|
|
/* first encode */
|
|
rc = curlx_base64_encode(e->input, e->ilen, &out, &olen);
|
|
abort_unless(rc == CURLE_OK, "return code should be CURLE_OK");
|
|
abort_unless(olen == e->olen, "wrong output size");
|
|
if(memcmp(out, e->output, e->olen)) {
|
|
fprintf(stderr, "Test %u encoded badly\n", i);
|
|
unitfail++;
|
|
}
|
|
Curl_safefree(out);
|
|
|
|
/* then verify decode */
|
|
rc = curlx_base64_decode(e->output, &decoded, &dlen);
|
|
if(rc != CURLE_OK) {
|
|
fprintf(stderr, "Test %u URL decode returned %d\n", i, (int)rc);
|
|
unitfail++;
|
|
}
|
|
if(dlen != e->ilen) {
|
|
fprintf(stderr, "Test %u URL decode output length %d instead of %d\n",
|
|
i, (int)dlen, (int)e->ilen);
|
|
unitfail++;
|
|
}
|
|
if(memcmp(decoded, e->input, dlen)) {
|
|
fprintf(stderr, "Test %u URL decoded badly. Got '%s', expected '%s'\n",
|
|
i, decoded, e->input);
|
|
unitfail++;
|
|
}
|
|
|
|
Curl_safefree(decoded);
|
|
}
|
|
|
|
for(i = 0 ; i < CURL_ARRAYSIZE(url); i++) {
|
|
struct etest *e = &url[i];
|
|
char *out;
|
|
size_t olen;
|
|
rc = curlx_base64url_encode(e->input, e->ilen, &out, &olen);
|
|
abort_unless(rc == CURLE_OK, "return code should be CURLE_OK");
|
|
if(olen != e->olen) {
|
|
fprintf(stderr, "Test %u URL encoded output length %d instead of %d\n",
|
|
i, (int)olen, (int)e->olen);
|
|
}
|
|
if(out && memcmp(out, e->output, e->olen)) {
|
|
fprintf(stderr, "Test %u URL encoded badly. Got '%s', expected '%s'\n",
|
|
i, out, e->output);
|
|
unitfail++;
|
|
}
|
|
Curl_safefree(out);
|
|
}
|
|
|
|
for(i = 0 ; i < CURL_ARRAYSIZE(badecode); i++) {
|
|
struct etest *e = &badecode[i];
|
|
unsigned char *decoded;
|
|
size_t dlen;
|
|
|
|
/* then verify decode with illegal inputs */
|
|
rc = curlx_base64_decode(e->output, &decoded, &dlen);
|
|
if(rc != CURLE_BAD_CONTENT_ENCODING) {
|
|
fprintf(stderr, "Test %u URL bad decoded badly. "
|
|
"Returned '%d', expected '%d'\n",
|
|
i, (int)rc, CURLE_BAD_CONTENT_ENCODING);
|
|
unitfail++;
|
|
}
|
|
}
|
|
|
|
UNITTEST_END_SIMPLE
|
|
}
|