From aba4df9dbb436343f7d29a47801d82a33dcaaad3 Mon Sep 17 00:00:00 2001 From: Stephan Bosch Date: Sat, 30 Mar 2019 18:57:34 +0100 Subject: [PATCH] lib: base64 - Add decode flag for prohibiting whitespace. --- src/lib/base64.c | 25 +++++++++++++++++++++---- src/lib/base64.h | 6 ++++-- src/lib/test-base64.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/lib/base64.c b/src/lib/base64.c index 42bf5322f6..980aa12005 100644 --- a/src/lib/base64.c +++ b/src/lib/base64.c @@ -324,10 +324,12 @@ bool base64_encode_finish(struct base64_encoder *enc, buffer_t *dest) ((c) == '\n' || (c) == '\r' || (c) == ' ' || (c) == '\t') static inline void -base64_skip_whitespace(struct base64_decoder *dec ATTR_UNUSED, - const unsigned char *src_c, +base64_skip_whitespace(struct base64_decoder *dec, const unsigned char *src_c, size_t src_size, size_t *src_pos) { + if (HAS_ALL_BITS(dec->flags, BASE64_DECODE_FLAG_NO_WHITESPACE)) + return; + /* skip any whitespace in the padding */ while ((*src_pos) < src_size && IS_EMPTY(src_c[(*src_pos)])) (*src_pos)++; @@ -341,6 +343,8 @@ int base64_decode_more(struct base64_decoder *dec, const unsigned char *src_c = src; bool expect_boundary = HAS_ALL_BITS(dec->flags, BASE64_DECODE_FLAG_EXPECT_BOUNDARY); + bool no_whitespace = HAS_ALL_BITS(dec->flags, + BASE64_DECODE_FLAG_NO_WHITESPACE); size_t src_pos, dst_avail; int ret = 1; @@ -369,6 +373,10 @@ int base64_decode_more(struct base64_decoder *dec, dec->seen_boundary = TRUE; return 0; } + if (no_whitespace) { + dec->seen_boundary = TRUE; + return 0; + } /* more whitespace may follow */ return 1; } @@ -391,6 +399,10 @@ int base64_decode_more(struct base64_decoder *dec, unsigned char dm = b64->decmap[in]; if (dm == 0xff) { + if (no_whitespace) { + ret = -1; + break; + } if (unlikely(!IS_EMPTY(in))) { ret = -1; break; @@ -492,8 +504,13 @@ int base64_decode_more(struct base64_decoder *dec, ret = -1; break; } - /* more whitespace may follow */ - ret = 1; + if (no_whitespace) { + dec->seen_boundary = TRUE; + ret = 0; + } else { + /* more whitespace may follow */ + ret = 1; + } break; } } diff --git a/src/lib/base64.h b/src/lib/base64.h index 7121a38824..cfb7807095 100644 --- a/src/lib/base64.h +++ b/src/lib/base64.h @@ -94,6 +94,8 @@ enum base64_decode_flags { to decode such a Base64 prefix. The base64_decode_finish() function will still check that the Base64 data ends properly (padding). */ BASE64_DECODE_FLAG_EXPECT_BOUNDARY = BIT(0), + /* Prohibit whitespace in the input. */ + BASE64_DECODE_FLAG_NO_WHITESPACE = BIT(1), }; struct base64_decoder { @@ -145,8 +147,8 @@ base64_decode_reset(struct base64_decoder *dec) buffer. dest may point to same buffer as src. Returns 1 if all ok, 0 if end of base64 data found, -1 if data is invalid. - Any CR, LF characters are ignored, as well as whitespace at beginning or end - of line. + By default, any CR, LF characters are ignored, as well as any whitespace. + This can be overridden using the BASE64_DECODE_FLAG_NO_WHITESPACE flag. If src_pos is non-NULL, it's updated to first non-translated character in src. diff --git a/src/lib/test-base64.c b/src/lib/test-base64.c index 79702de5d0..2926649283 100644 --- a/src/lib/test-base64.c +++ b/src/lib/test-base64.c @@ -365,6 +365,13 @@ tests_base64_decode_lowlevel[] = { .ret = 0, .src_pos = UINT_MAX, }, + { + .scheme = &base64_scheme, + .input = "aGVsbG8gd29ybGQ=\t", + .output = "hello world", + .ret = 0, + .src_pos = UINT_MAX, + }, { .scheme = &base64_scheme, .input = "\taGVsbG8gd29ybGQ=\t", @@ -388,6 +395,22 @@ tests_base64_decode_lowlevel[] = { .src_pos = 18, .flags = BASE64_DECODE_FLAG_EXPECT_BOUNDARY, }, + { + .scheme = &base64_scheme, + .input = "aGVsbG8gd29ybGQ=\t", + .output = "hello world", + .ret = -1, + .src_pos = 16, + .flags = BASE64_DECODE_FLAG_NO_WHITESPACE, + }, + { + .scheme = &base64_scheme, + .input = "\taGVsbG8gd29ybGQ=\t", + .output = "", + .ret = -1, + .src_pos = 0, + .flags = BASE64_DECODE_FLAG_NO_WHITESPACE, + }, { .scheme = &base64_scheme, .input = "\nZm9v\n \tIGJh \t\ncml0cw==", @@ -741,8 +764,13 @@ test_base64_random_lowlevel(void) BASE64_DECODE_FLAG_EXPECT_BOUNDARY); test_base64_random_lowlevel_case(&base64url_scheme, BASE64_DECODE_FLAG_EXPECT_BOUNDARY); + test_base64_random_lowlevel_case(&base64_scheme, + BASE64_DECODE_FLAG_NO_WHITESPACE); + test_base64_random_lowlevel_case(&base64url_scheme, + BASE64_DECODE_FLAG_NO_WHITESPACE); test_end(); } + void test_base64(void) { test_base64_encode(); -- 2.47.3