From: Stephan Bosch Date: Fri, 17 May 2019 08:17:19 +0000 (+0200) Subject: lib: base64 - Add support for decoding without padding. X-Git-Tag: 2.3.8~125 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6f8140f188b14b911b3b707baed6c5d50a27cd2c;p=thirdparty%2Fdovecot%2Fcore.git lib: base64 - Add support for decoding without padding. --- diff --git a/src/lib/base64.c b/src/lib/base64.c index fb8eeace98..2994e59ee1 100644 --- a/src/lib/base64.c +++ b/src/lib/base64.c @@ -588,58 +588,65 @@ int base64_decode_more(struct base64_decoder *dec, /* try to parse the end (padding) of the base64 input */ i_assert(src_pos < src_size); - switch (dec->sub_pos) { - case 0: - case 1: - /* no padding expected */ + if (HAS_ALL_BITS(dec->flags, + BASE64_DECODE_FLAG_NO_PADDING)) { + /* no padding allowed */ + i_assert(!dec->seen_padding); ret = -1; - break; - case 2: - if (unlikely(src_c[src_pos] != '=')) { - /* invalid character */ - ret = -1; - break; - } - dec->seen_padding = TRUE; - dec->sub_pos++; - src_pos++; - if (src_pos == src_size) { - ret = 1; - break; - } - /* skip any whitespace in the padding */ - base64_skip_whitespace(dec, src_c, src_size, - &src_pos); - if (src_pos == src_size) { - ret = 1; - break; - } - /* fall through */ - case 3: - if (unlikely(src_c[src_pos] != '=')) { - /* invalid character */ + } else { + switch (dec->sub_pos) { + case 0: + case 1: + /* no padding expected */ ret = -1; break; - } - dec->seen_padding = TRUE; - dec->seen_end = TRUE; - dec->sub_pos = 0; - src_pos++; - /* skip any trailing whitespace */ - base64_skip_whitespace(dec, src_c, src_size, - &src_pos); - if (src_pos < src_size) { - ret = -1; + case 2: + if (unlikely(src_c[src_pos] != '=')) { + /* invalid character */ + ret = -1; + break; + } + dec->seen_padding = TRUE; + dec->sub_pos++; + src_pos++; + if (src_pos == src_size) { + ret = 1; + break; + } + /* skip any whitespace in the padding */ + base64_skip_whitespace(dec, src_c, src_size, + &src_pos); + if (src_pos == src_size) { + ret = 1; + break; + } + /* fall through */ + case 3: + if (unlikely(src_c[src_pos] != '=')) { + /* invalid character */ + ret = -1; + break; + } + dec->seen_padding = TRUE; + dec->seen_end = TRUE; + dec->sub_pos = 0; + src_pos++; + /* skip any trailing whitespace */ + base64_skip_whitespace(dec, src_c, src_size, + &src_pos); + if (src_pos < src_size) { + ret = -1; + break; + } + if (no_whitespace) { + dec->seen_boundary = TRUE; + ret = 0; + } else { + /* more whitespace may follow */ + ret = 1; + } break; } - if (no_whitespace) { - dec->seen_boundary = TRUE; - ret = 0; - } else { - /* more whitespace may follow */ - ret = 1; - } - break; } } @@ -661,7 +668,13 @@ int base64_decode_finish(struct base64_decoder *dec) i_assert(!dec->finished); dec->finished = TRUE; - return (!dec->failed && dec->sub_pos == 0 ? 0 : -1); + if (dec->failed) + return -1; + + if (HAS_ALL_BITS(dec->flags, + BASE64_DECODE_FLAG_NO_PADDING)) + return 0; + return (dec->sub_pos == 0 ? 0 : -1); } /* diff --git a/src/lib/base64.h b/src/lib/base64.h index 751adf10bf..28215529eb 100644 --- a/src/lib/base64.h +++ b/src/lib/base64.h @@ -116,6 +116,8 @@ enum base64_decode_flags { BASE64_DECODE_FLAG_EXPECT_BOUNDARY = BIT(0), /* Prohibit whitespace in the input. */ BASE64_DECODE_FLAG_NO_WHITESPACE = BIT(1), + /* Require absence of padding at the end of the input. */ + BASE64_DECODE_FLAG_NO_PADDING = BIT(2), }; struct base64_decoder { diff --git a/src/lib/test-base64.c b/src/lib/test-base64.c index 6e944694f3..e9e08dcb41 100644 --- a/src/lib/test-base64.c +++ b/src/lib/test-base64.c @@ -518,6 +518,22 @@ tests_base64_decode_lowlevel[] = { .src_pos = 0, .flags = BASE64_DECODE_FLAG_NO_WHITESPACE, }, + { + .scheme = &base64_scheme, + .flags = BASE64_DECODE_FLAG_NO_PADDING, + .input = "\taGVsbG8gd29ybGQ=", + .output = "hello world", + .ret = -1, + .src_pos = 16, + }, + { + .scheme = &base64_scheme, + .flags = BASE64_DECODE_FLAG_NO_PADDING, + .input = "\taGVsbG8gd29ybGQ", + .output = "hello world", + .ret = 0, + .src_pos = 16, + }, { .scheme = &base64_scheme, .input = "\nZm9v\n \tIGJh \t\ncml0cw==", @@ -553,6 +569,22 @@ tests_base64_decode_lowlevel[] = { .ret = 0, .src_pos = UINT_MAX, }, + { + .scheme = &base64_scheme, + .flags = BASE64_DECODE_FLAG_NO_PADDING, + .input = "\nZm9v\n \tIGJh \t\ncml0cw==", + .output = "foo barits", + .ret = -1, + .src_pos = 22, + }, + { + .scheme = &base64_scheme, + .flags = BASE64_DECODE_FLAG_NO_PADDING, + .input = "\nZm9v\n \tIGJh \t\ncml0cw", + .output = "foo barits", + .ret = 0, + .src_pos = 22, + }, { .scheme = &base64_scheme, .input = " anVzdCBuaWlu \n", @@ -567,6 +599,14 @@ tests_base64_decode_lowlevel[] = { .ret = 0, .src_pos = UINT_MAX, }, + { + .scheme = &base64_scheme, + .flags = BASE64_DECODE_FLAG_NO_PADDING, + .input = " anVzdCBuaWlu \n", + .output = "just niin", + .ret = 0, + .src_pos = UINT_MAX, + }, { .scheme = &base64_scheme, .input = "aGVsb", @@ -581,6 +621,14 @@ tests_base64_decode_lowlevel[] = { .ret = -1, .src_pos = 5, }, + { + .scheme = &base64_scheme, + .flags = BASE64_DECODE_FLAG_NO_PADDING, + .input = "aGVsb", + .output = "hel", + .ret = 0, + .src_pos = 5, + }, { .scheme = &base64_scheme, .input = "aGVsb!!!!!", @@ -635,6 +683,20 @@ tests_base64_decode_lowlevel[] = { .ret = 0, .src_pos = UINT_MAX, }, + { + .scheme = &base64_scheme, + .flags = BASE64_DECODE_FLAG_NO_PADDING, + .input = + "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt" + "C+INC60YPRgCDQtNC+0Y/MgdGCLg", + .output = + "\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc" + "\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0" + "\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc" + "\x81\xd1\x82\x2e", + .ret = 0, + .src_pos = UINT_MAX, + }, }; static void test_base64_decode_lowlevel(void) @@ -889,6 +951,20 @@ test_base64_random_lowlevel(void) BASE64_ENCODE_FLAG_CRLF, 0, 10); test_base64_random_lowlevel_case(&base64url_scheme, BASE64_ENCODE_FLAG_CRLF, 0, 10); + test_base64_random_lowlevel_case(&base64_scheme, + BASE64_ENCODE_FLAG_NO_PADDING, + BASE64_DECODE_FLAG_NO_PADDING, 0); + test_base64_random_lowlevel_case(&base64url_scheme, + BASE64_ENCODE_FLAG_NO_PADDING, + BASE64_DECODE_FLAG_NO_PADDING, 0); + test_base64_random_lowlevel_case(&base64_scheme, + BASE64_ENCODE_FLAG_NO_PADDING | + BASE64_ENCODE_FLAG_CRLF, + BASE64_DECODE_FLAG_NO_PADDING, 15); + test_base64_random_lowlevel_case(&base64url_scheme, + BASE64_ENCODE_FLAG_NO_PADDING | + BASE64_ENCODE_FLAG_CRLF, + BASE64_DECODE_FLAG_NO_PADDING, 15); test_end(); }