From c0cb3485fe24874b8d1d9cf0cb09d6a003bc53b1 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 23 Jun 2025 22:53:30 +0200 Subject: [PATCH] unit1302: expand the base64 encode/decode tests Closes #17726 --- tests/unit/unit1302.c | 298 +++++++++++++++++++++++------------------- 1 file changed, 163 insertions(+), 135 deletions(-) diff --git a/tests/unit/unit1302.c b/tests/unit/unit1302.c index f161cf29e3..1b1f4b44ba 100644 --- a/tests/unit/unit1302.c +++ b/tests/unit/unit1302.c @@ -28,145 +28,173 @@ #include #include "memdebug.h" /* LAST include file */ +struct etest { + const char *input; + size_t ilen; + const char *output; + size_t olen; +}; + static CURLcode test_unit1302(char *arg) { UNITTEST_BEGIN_SIMPLE - - char *output; - unsigned char *decoded; - size_t size = 0; - unsigned char anychar = 'x'; CURLcode rc; - - rc = curlx_base64_encode("i", 1, &output, &size); - fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); - fail_unless(size == 4, "size should be 4"); - verify_memory(output, "aQ==", 4); - Curl_safefree(output); - - rc = curlx_base64_encode("ii", 2, &output, &size); - fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); - fail_unless(size == 4, "size should be 4"); - verify_memory(output, "aWk=", 4); - Curl_safefree(output); - - rc = curlx_base64_encode("iii", 3, &output, &size); - fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); - fail_unless(size == 4, "size should be 4"); - verify_memory(output, "aWlp", 4); - Curl_safefree(output); - - rc = curlx_base64_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); - Curl_safefree(output); - - rc = curlx_base64_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); - Curl_safefree(output); - - rc = curlx_base64url_encode("\xff\x01\xfe\x02", 4, &output, &size); - fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); - fail_unless(size == 6, "size should be 6"); - verify_memory(output, "_wH-Ag", 6); - Curl_safefree(output); - - rc = curlx_base64url_encode("iiii", 4, &output, &size); - fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); - fail_unless(size == 6, "size should be 6"); - verify_memory(output, "aWlpaQ", 6); - Curl_safefree(output); - - /* 0 length makes it do strlen() */ - rc = curlx_base64_encode("iiii", 0, &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); - Curl_safefree(output); - - rc = curlx_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 = curlx_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 = curlx_base64_decode("aWlpaQ==", &decoded, &size); - fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); - fail_unless(size == 4, "size should be 4"); - verify_memory(decoded, "iiii", 4); - Curl_safefree(decoded); - - rc = curlx_base64_decode("aWlp", &decoded, &size); - fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); - fail_unless(size == 3, "size should be 3"); - verify_memory(decoded, "iii", 3); - Curl_safefree(decoded); - - rc = curlx_base64_decode("aWk=", &decoded, &size); - fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); - fail_unless(size == 2, "size should be 2"); - verify_memory(decoded, "ii", 2); - Curl_safefree(decoded); - - rc = curlx_base64_decode("aQ==", &decoded, &size); - fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); - fail_unless(size == 1, "size should be 1"); - verify_memory(decoded, "i", 2); - Curl_safefree(decoded); - - /* This is illegal input as the data is too short */ - size = 1; /* not zero */ - decoded = &anychar; /* not NULL */ - rc = curlx_base64_decode("aQ", &decoded, &size); - fail_unless(rc == CURLE_BAD_CONTENT_ENCODING, - "return code should be CURLE_BAD_CONTENT_ENCODING"); - fail_unless(size == 0, "size should be 0"); - fail_if(decoded, "returned pointer should be NULL"); - - /* This is illegal input as it contains three padding characters */ - size = 1; /* not zero */ - decoded = &anychar; /* not NULL */ - rc = curlx_base64_decode("a===", &decoded, &size); - fail_unless(rc == CURLE_BAD_CONTENT_ENCODING, - "return code should be CURLE_BAD_CONTENT_ENCODING"); - fail_unless(size == 0, "size should be 0"); - fail_if(decoded, "returned pointer should be NULL"); - - /* This is illegal input as it contains a padding character mid input */ - size = 1; /* not zero */ - decoded = &anychar; /* not NULL */ - rc = curlx_base64_decode("a=Q=", &decoded, &size); - fail_unless(rc == CURLE_BAD_CONTENT_ENCODING, - "return code should be CURLE_BAD_CONTENT_ENCODING"); - fail_unless(size == 0, "size should be 0"); - fail_if(decoded, "returned pointer should be NULL"); - - /* This is also illegal input as it contains a padding character mid input */ - size = 1; /* not zero */ - decoded = &anychar; /* not NULL */ - rc = curlx_base64_decode("aWlpa=Q=", &decoded, &size); - fail_unless(rc == CURLE_BAD_CONTENT_ENCODING, - "return code should be CURLE_BAD_CONTENT_ENCODING"); - fail_unless(size == 0, "size should be 0"); - fail_if(decoded, "returned pointer should be NULL"); - - /* This is garbage input as it contains an illegal base64 character */ - size = 1; /* not zero */ - decoded = &anychar; /* not NULL */ - rc = curlx_base64_decode("a\x1f==", &decoded, &size); - fail_unless(rc == CURLE_BAD_CONTENT_ENCODING, - "return code should be CURLE_BAD_CONTENT_ENCODING"); - fail_unless(size == 0, "size should be 0"); - fail_if(decoded, "returned pointer should be NULL"); + 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 }, + {"\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(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 } -- 2.47.2