diff options
Diffstat (limited to 'src/lib/test-istream-base64-decoder.c')
-rw-r--r-- | src/lib/test-istream-base64-decoder.c | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/src/lib/test-istream-base64-decoder.c b/src/lib/test-istream-base64-decoder.c new file mode 100644 index 0000000..ea45f6d --- /dev/null +++ b/src/lib/test-istream-base64-decoder.c @@ -0,0 +1,337 @@ +/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */ + +#include "test-lib.h" +#include "str.h" +#include "istream-private.h" +#include "istream-base64.h" +#include "istream-sized.h" +#include "base64.h" + +struct base64_istream_test { + const char *input; + const char *output; + int stream_errno; +}; + +static const struct base64_istream_test base64_tests[] = { + { "", "", 0 }, + { "aGVsbG8gd29ybGQ=", "hello world", 0 }, + { "\naGVs\nbG8g\nd29y\nbGQ=\n", "hello world", 0 }, + { " aGVs \r\n bG8g \r\n d29y \t \r\n bGQ= \r\n\r\n", + "hello world", 0 }, + { "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgtC+INC60YPRgCDQtNC+0Y/MgdGCLg==", + "\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", 0 }, + { "\r", "", 0 }, + { "\n", "", 0 }, + { "\r\n", "", 0 }, + { " ", "", 0 }, + { "foo", "\x7e\x8a", EPIPE }, + { "foo ","\x7e\x8a", EPIPE }, + { "Zm9vC", "foo", EPIPE }, + { "Zm9v!", "foo", EINVAL }, + { "Zm9!v", "fo", EINVAL }, + { "Zm9 v", "foo", 0 }, + { "Zm 9v", "foo", 0 }, + { "Z m9v", "foo", 0 }, +}; + +static const struct base64_istream_test base64url_tests[] = { + { "", "", 0 }, + { "aGVsbG8gd29ybGQ=", "hello world", 0 }, + { "\naGVs\nbG8g\nd29y\nbGQ=\n", "hello world", 0 }, + { " aGVs \r\n bG8g \r\n d29y \t \r\n bGQ= \r\n\r\n", + "hello world", 0 }, + { "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgtC-INC60YPRgCDQtNC-0Y_MgdGCLg==", + "\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", 0 }, + { "\r", "", 0 }, + { "\n", "", 0 }, + { "\r\n", "", 0 }, + { " ", "", 0 }, + { "foo", "\x7e\x8a", EPIPE }, + { "foo ","\x7e\x8a", EPIPE }, + { "Zm9vC", "foo", EPIPE }, + { "Zm9v!", "foo", EINVAL }, + { "Zm9!v", "fo", EINVAL }, + { "Zm9 v", "foo", 0 }, + { "Zm 9v", "foo", 0 }, + { "Z m9v", "foo", 0 }, +}; + +static void +decode_test(unsigned int base64_input_len, + struct istream *input_data, struct istream *input, + const char *output, int stream_errno) +{ + const unsigned char *data; + size_t i, size; + int ret = 0; + + for (i = 1; i <= base64_input_len; i++) { + test_istream_set_size(input_data, i); + while ((ret = i_stream_read(input)) > 0) ; + if (ret == -1 && stream_errno != 0) + break; + test_assert(ret == 0); + } + if (ret == 0) { + test_istream_set_allow_eof(input_data, TRUE); + while ((ret = i_stream_read(input)) > 0) ; + } + test_assert(ret == -1); + test_assert(input->stream_errno == stream_errno); + + data = i_stream_get_data(input, &size); + test_assert(size == strlen(output)); + if (size > 0) + test_assert(memcmp(data, output, size) == 0); +} + +static void +decode_base64_test(const char *base64_input, const char *output, + int stream_errno) +{ + unsigned int base64_input_len = strlen(base64_input); + struct istream *input_data, *input; + + input_data = test_istream_create_data(base64_input, base64_input_len); + test_istream_set_allow_eof(input_data, FALSE); + input = i_stream_create_base64_decoder(input_data); + + decode_test(base64_input_len, input_data, input, output, stream_errno); + + i_stream_unref(&input); + i_stream_unref(&input_data); +} + +static void +decode_base64url_test(const char *base64_input, const char *output, + int stream_errno) +{ + unsigned int base64_input_len = strlen(base64_input); + struct istream *input_data, *input; + + input_data = test_istream_create_data(base64_input, base64_input_len); + test_istream_set_allow_eof(input_data, FALSE); + input = i_stream_create_base64url_decoder(input_data); + + decode_test(base64_input_len, input_data, input, output, stream_errno); + + i_stream_unref(&input); + i_stream_unref(&input_data); +} + +static void +test_istream_base64_io_random(void) +{ + unsigned char in_buf[2048]; + size_t in_buf_size; + buffer_t *out_buf; + unsigned int i, j; + int ret; + + out_buf = t_buffer_create(sizeof(in_buf)); + + test_begin("istream base64 random I/O"); + + for (i = 0; !test_has_failed() && i < 4000; i++) { + struct istream *input1, *input2, *input3, *input4, *input5; + struct istream *sinput1, *sinput2, *sinput3, *sinput4; + struct istream *top_input; + const unsigned char *data; + unsigned int chpl1, chpl2; + unsigned int sized_streams; + unsigned int crlf_encode; + size_t size; + struct base64_encoder b64enc; + + /* Initialize test data */ + in_buf_size = i_rand_limit(sizeof(in_buf)); + for (j = 0; j < in_buf_size; j++) + in_buf[j] = i_rand_uchar(); + + /* Reset final output buffer */ + buffer_set_used_size(out_buf, 0); + + /* Determine line lengths */ + chpl1 = i_rand_limit(30)*4; + chpl2 = i_rand_limit(30)*4; + + /* Create stream for test data */ + input1 = i_stream_create_from_data(in_buf, in_buf_size); + i_stream_set_name(input1, "[data]"); + + /* Determine which stages have sized streams */ + sized_streams = i_rand_minmax(0x00, 0x0f); + /* Determine which stages use CRLF */ + crlf_encode = i_rand_minmax(0x00, 0x03); + + /* Create first encoder stream */ + input2 = i_stream_create_base64_encoder( + input1, chpl1, HAS_ALL_BITS(crlf_encode, BIT(0))); + i_stream_set_name(input2, "[base64_encoder #1]"); + + if (HAS_ALL_BITS(sized_streams, BIT(0))) { + /* Wrap the first encoder stream in a sized stream to + check size and trigger any buffer overflow problems + */ + base64_encode_init(&b64enc, &base64_scheme, + (HAS_ALL_BITS(crlf_encode, BIT(0)) ? + BASE64_ENCODE_FLAG_CRLF : 0), + chpl1); + sinput1 = i_stream_create_sized(input2, + base64_get_full_encoded_size(&b64enc, + in_buf_size)); + i_stream_set_name(sinput1, "[sized #1]"); + } else { + sinput1 = input2; + i_stream_ref(sinput1); + } + + /* Create first decoder stream */ + input3 = i_stream_create_base64_decoder(sinput1); + i_stream_set_name(input3, "[base64_decoder #1]"); + + if (HAS_ALL_BITS(sized_streams, BIT(1))) { + /* Wrap the first decoder stream in a sized stream to + check size and trigger any buffer overflow problems + */ + sinput2 = i_stream_create_sized(input3, in_buf_size); + i_stream_set_name(sinput2, "[sized #2]"); + } else { + sinput2 = input3; + i_stream_ref(sinput2); + } + + /* Create second encoder stream */ + input4 = i_stream_create_base64_encoder( + sinput2, chpl2, HAS_ALL_BITS(crlf_encode, BIT(1))); + i_stream_set_name(input4, "[base64_encoder #2]"); + + if (HAS_ALL_BITS(sized_streams, BIT(2))) { + /* Wrap the second encoder stream in a sized stream to + check size and trigger any buffer overflow problems + */ + base64_encode_init(&b64enc, &base64_scheme, + (HAS_ALL_BITS(crlf_encode, BIT(1)) ? + BASE64_ENCODE_FLAG_CRLF : 0), + chpl2); + sinput3 = i_stream_create_sized(input4, + base64_get_full_encoded_size(&b64enc, + in_buf_size)); + i_stream_set_name(sinput3, "[sized #3]"); + } else { + sinput3 = input4; + i_stream_ref(sinput3); + } + + /* Create second deoder stream */ + input5 = i_stream_create_base64_decoder(sinput3); + i_stream_set_name(input5, "[base64_decoder #2]"); + + if (HAS_ALL_BITS(sized_streams, BIT(3))) { + /* Wrap the second decoder stream in a sized stream to + check size and trigger any buffer overflow problems + */ + sinput4 = i_stream_create_sized(input5, in_buf_size); + i_stream_set_name(sinput4, "[sized #4]"); + } else { + sinput4 = input5; + i_stream_ref(sinput4); + } + + + /* Assign random buffer sizes */ + i_stream_set_max_buffer_size(input5, i_rand_minmax(1, 512)); + i_stream_set_max_buffer_size(input4, i_rand_minmax(1, 512)); + i_stream_set_max_buffer_size(input3, i_rand_minmax(1, 512)); + i_stream_set_max_buffer_size(input2, i_rand_minmax(1, 512)); + + /* Read the outer stream in full with random increments. */ + top_input = sinput4; + while ((ret = i_stream_read_more( + top_input, &data, &size)) > 0) { + size_t ch = i_rand_limit(512); + + size = I_MIN(size, ch); + buffer_append(out_buf, data, size); + i_stream_skip(top_input, size); + } + if (ret < 0 && top_input->stream_errno == 0) { + data = i_stream_get_data(top_input, &size); + if (size > 0) { + buffer_append(out_buf, data, size); + i_stream_skip(top_input, size); + } + } + + /* Assert stream status */ + test_assert_idx(ret < 0 && top_input->stream_errno == 0, i); + /* Assert input/output equality */ + test_assert_idx(out_buf->used == in_buf_size && + memcmp(in_buf, out_buf->data, in_buf_size) == 0, + i); + + if (top_input->stream_errno != 0) { + i_error("%s: %s", i_stream_get_name(input1), + i_stream_get_error(input1)); + i_error("%s: %s", i_stream_get_name(input2), + i_stream_get_error(input2)); + i_error("%s: %s", i_stream_get_name(input3), + i_stream_get_error(input3)); + i_error("%s: %s", i_stream_get_name(input4), + i_stream_get_error(input4)); + i_error("%s: %s", i_stream_get_name(input5), + i_stream_get_error(input5)); + } + + if (test_has_failed()) { + i_info("Test parameters: size=%zu " + "line_length_1=%u line_length_2=%u", + in_buf_size, chpl1, chpl2); + } + + /* Clean up */ + i_stream_unref(&input1); + i_stream_unref(&input2); + i_stream_unref(&input3); + i_stream_unref(&input4); + i_stream_unref(&input5); + i_stream_unref(&sinput1); + i_stream_unref(&sinput2); + i_stream_unref(&sinput3); + i_stream_unref(&sinput4); + } + test_end(); +} + +void test_istream_base64_decoder(void) +{ + unsigned int i; + + for (i = 0; i < N_ELEMENTS(base64_tests); i++) { + const struct base64_istream_test *test = &base64_tests[i]; + + test_begin(t_strdup_printf("istream base64 decoder %u", i+1)); + decode_base64_test(test->input, test->output, + test->stream_errno); + test_end(); + } + + for (i = 0; i < N_ELEMENTS(base64url_tests); i++) { + const struct base64_istream_test *test = &base64url_tests[i]; + + test_begin(t_strdup_printf("istream base64url decoder %u", + i+1)); + decode_base64url_test(test->input, test->output, + test->stream_errno); + test_end(); + } + + test_istream_base64_io_random(); +} |