]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: base64 - Add decode flag for prohibiting whitespace.
authorStephan Bosch <stephan.bosch@dovecot.fi>
Sat, 30 Mar 2019 17:57:34 +0000 (18:57 +0100)
committerStephan Bosch <stephan.bosch@open-xchange.com>
Tue, 27 Aug 2019 07:32:51 +0000 (09:32 +0200)
src/lib/base64.c
src/lib/base64.h
src/lib/test-base64.c

index 42bf5322f69f5e174bcc6f7a20b4a2a3b06321f4..980aa12005653cc96b248541275613514a916505 100644 (file)
@@ -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;
                }
        }
index 7121a38824fbcbff9e8dcc85716f653f720aa23d..cfb78070959003d1c944bb7812605688609a5fd3 100644 (file)
@@ -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.
index 79702de5d0fa65abad806267cce1f44c3e04332d..2926649283c63d7df9fa25341b298d3f192b8176 100644 (file)
@@ -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();