xrdp/tests/common/test_base64.c
2022-01-28 12:23:40 +00:00

401 lines
12 KiB
C

#if defined(HAVE_CONFIG_H)
#include "config_ac.h"
#endif
#include "os_calls.h"
#include "string_calls.h"
#include "base64.h"
#include "test_common.h"
/*
* These are the example test strings in RFC4648(10)
*/
static const char *rfc4648_ex1_text = "";
static const char *rfc4648_ex1_b64 = "";
static const char *rfc4648_ex2_text = "f";
static const char *rfc4648_ex2_b64 = "Zg==";
static const char *rfc4648_ex3_text = "fo";
static const char *rfc4648_ex3_b64 = "Zm8=";
static const char *rfc4648_ex4_text = "foo";
static const char *rfc4648_ex4_b64 = "Zm9v";
static const char *rfc4648_ex5_text = "foob";
static const char *rfc4648_ex5_b64 = "Zm9vYg==";
static const char *rfc4648_ex6_text = "fooba";
static const char *rfc4648_ex6_b64 = "Zm9vYmE=";
static const char *rfc4648_ex7_text = "foobar";
static const char *rfc4648_ex7_b64 = "Zm9vYmFy";
/* Every single valid base64 character, except padding */
static const char *all_b64 =
"ABCDEFGHIJKL"
"MNOPQRSTUVWX"
"YZabcdefghij"
"klmnopqrstuv"
"wxyz01234567"
"89+/";
/* What we should get as binary if we decode this */
static const char all_b64_decoded[] =
{
'\x00', '\x10', '\x83', '\x10', '\x51', '\x87', '\x20', '\x92', '\x8b',
'\x30', '\xd3', '\x8f', '\x41', '\x14', '\x93', '\x51', '\x55', '\x97',
'\x61', '\x96', '\x9b', '\x71', '\xd7', '\x9f', '\x82', '\x18', '\xa3',
'\x92', '\x59', '\xa7', '\xa2', '\x9a', '\xab', '\xb2', '\xdb', '\xaf',
'\xc3', '\x1c', '\xb3', '\xd3', '\x5d', '\xb7', '\xe3', '\x9e', '\xbb',
'\xf3', '\xdf', '\xbf'
};
static void
test_rfc4648_to_b64(const char *plaintext, size_t len, const char *b64)
{
char buff[256];
size_t result;
result = base64_encode(plaintext, len, buff, sizeof(buff));
ck_assert_int_eq(result, len);
ck_assert_str_eq(buff, b64);
}
/* Text-only encoder wrapper */
static void
test_rfc4648_to_b64_text(const char *plaintext, const char *b64)
{
test_rfc4648_to_b64(plaintext, g_strlen(plaintext), b64);
}
/* Text-only decoder wrapper for valid base64 */
static void
test_rfc4648_from_b64_text(const char *b64, const char *text)
{
char buff[256];
size_t actual_len;
int result;
result = base64_decode(b64, buff, sizeof(buff), &actual_len);
ck_assert_int_eq(result, 0);
ck_assert_int_lt(actual_len, sizeof(buff));
buff[actual_len] = '\0';
ck_assert_str_eq(buff, text);
}
/******************************************************************************/
START_TEST(test_b64_rfc4648_ex1_to)
{
test_rfc4648_to_b64_text(rfc4648_ex1_text, rfc4648_ex1_b64);
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_rfc4648_ex1_from)
{
test_rfc4648_from_b64_text(rfc4648_ex1_b64, rfc4648_ex1_text);
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_rfc4648_ex2_to)
{
test_rfc4648_to_b64_text(rfc4648_ex2_text, rfc4648_ex2_b64);
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_rfc4648_ex2_from)
{
test_rfc4648_from_b64_text(rfc4648_ex2_b64, rfc4648_ex2_text);
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_rfc4648_ex3_to)
{
test_rfc4648_to_b64_text(rfc4648_ex3_text, rfc4648_ex3_b64);
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_rfc4648_ex3_from)
{
test_rfc4648_from_b64_text(rfc4648_ex3_b64, rfc4648_ex3_text);
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_rfc4648_ex4_to)
{
test_rfc4648_to_b64_text(rfc4648_ex4_text, rfc4648_ex4_b64);
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_rfc4648_ex4_from)
{
test_rfc4648_from_b64_text(rfc4648_ex4_b64, rfc4648_ex4_text);
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_rfc4648_ex5_to)
{
test_rfc4648_to_b64_text(rfc4648_ex5_text, rfc4648_ex5_b64);
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_rfc4648_ex5_from)
{
test_rfc4648_from_b64_text(rfc4648_ex5_b64, rfc4648_ex5_text);
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_rfc4648_ex6_to)
{
test_rfc4648_to_b64_text(rfc4648_ex6_text, rfc4648_ex6_b64);
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_rfc4648_ex6_from)
{
test_rfc4648_from_b64_text(rfc4648_ex6_b64, rfc4648_ex6_text);
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_rfc4648_ex7_to)
{
test_rfc4648_to_b64_text(rfc4648_ex7_text, rfc4648_ex7_b64);
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_rfc4648_ex7_from)
{
test_rfc4648_from_b64_text(rfc4648_ex7_b64, rfc4648_ex7_text);
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_all_valid_from)
{
char buff[256];
size_t actual_len;
int result;
char *str_result;
char *str_expected;
result = base64_decode(all_b64, buff, sizeof(buff), &actual_len);
ck_assert_int_eq(result, 0);
ck_assert_int_eq(actual_len, sizeof(all_b64_decoded));
str_result = bin_to_hex(buff, actual_len);
str_expected = bin_to_hex(all_b64_decoded, sizeof(all_b64_decoded));
ck_assert_str_eq(str_result, str_expected);
free(str_result);
free(str_expected);
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_all_valid_to)
{
char buff[256];
size_t result;
result = base64_encode(all_b64_decoded, sizeof(all_b64_decoded),
buff, sizeof(buff));
ck_assert_int_eq(result, sizeof(all_b64_decoded));
ck_assert_str_eq(buff, all_b64);
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_all_invalid)
{
char buff[256];
size_t actual_len;
char valid[256] = {0};
char encoded[5] = { "T0sh" }; /* Decodes to 'OK!' */
int result;
/* Make a note of all the valid b64 characters */
unsigned int i = 0;
unsigned char c;
while ((c = all_b64[i]) != '\0')
{
valid[c] = 1;
++i;
}
/* Check the decoder's working on a simple string...*/
result = base64_decode(encoded, buff, sizeof(buff), &actual_len);
ck_assert_int_eq(result, 0);
ck_assert_int_eq(actual_len, 3);
buff[actual_len] = '\0';
ck_assert_str_eq(buff, "OK!");
/* Now replace the 1st character with all invalid characters in turn,
* and check they're rejected */
for (i = 0 ; i < 256; ++i)
{
if (i != '\0' && !valid[i]) /* Don't try the string terminator char! */
{
encoded[0] = i;
result = base64_decode(encoded, buff, sizeof(buff), &actual_len);
if (result == 0)
{
ck_abort_msg("Character 0x%02x was not rejected", i);
}
}
}
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_small_buffer_encode)
{
char buff[10 * 4 + 1]; /* Enough space for 10 quanta */
size_t result;
result = base64_encode(all_b64_decoded, sizeof(all_b64_decoded),
buff, sizeof(buff));
/* Should have read 10 lots of 24 bits from the input */
ck_assert_int_eq(result, 10 * 3);
ck_assert_str_eq(buff, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn");
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_small_buffer_decode)
{
char buff[10]; /* Enough space for 10 chars */
size_t actual_len;
int result;
char *str_result;
char *str_expected;
result = base64_decode(all_b64, buff, sizeof(buff), &actual_len);
ck_assert_int_eq(result, 0);
ck_assert_int_eq(actual_len, sizeof(all_b64_decoded));
str_result = bin_to_hex(buff, sizeof(buff));
str_expected = bin_to_hex(all_b64_decoded, sizeof(buff));
ck_assert_str_eq(str_result, str_expected);
free(str_result);
free(str_expected);
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_add_pad_one)
{
/* Check that a missing trailing '=' is added when decoding */
test_rfc4648_from_b64_text("Zm8", "fo"); /* RFC4648 example 3 */
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_add_pad_two)
{
/* Check that two missing trailing '=' chars are added when decoding */
test_rfc4648_from_b64_text("Zg", "f"); /* RFC4648 example 2 */
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_bad_pad)
{
char buff[16];
size_t actual_len;
/* Check all bad quanta with padding chars */
static const char *bad_pad[] =
{
"=AAA",
"A=AA",
"AA=A",
"==AA",
"=A=A",
"=AA=",
"A==A",
"A=A=",
"===A",
"A===",
NULL
};
const char **p;
for (p = bad_pad ; *p != NULL ; ++p)
{
int result = base64_decode(*p, buff, sizeof(buff), &actual_len);
if (result == 0)
{
ck_abort_msg("Padding '%s' was not rejected", *p);
}
}
}
END_TEST
/******************************************************************************/
START_TEST(test_b64_concat_pad)
{
const char *src =
"VGVzdA==" /* Test */
"IA==" /* <space> */
"Y29uY2F0ZW5hdGVk" /* concatenated */
"IA==" /* <space> */
"cGFkZGluZw=="; /*padding */
const char *expected = "Test concatenated padding";
char buff[64];
size_t actual_len;
int result;
result = base64_decode(src, buff, sizeof(buff), &actual_len);
ck_assert_int_eq(result, 0);
ck_assert_int_eq(actual_len, g_strlen(expected));
buff[actual_len] = '\0';
ck_assert_str_eq(buff, expected);
}
END_TEST
/******************************************************************************/
Suite *
make_suite_test_base64(void)
{
Suite *s;
TCase *tc_b64;
s = suite_create("base64");
tc_b64 = tcase_create("base64");
suite_add_tcase(s, tc_b64);
tcase_add_test(tc_b64, test_b64_rfc4648_ex1_to);
tcase_add_test(tc_b64, test_b64_rfc4648_ex1_from);
tcase_add_test(tc_b64, test_b64_rfc4648_ex2_to);
tcase_add_test(tc_b64, test_b64_rfc4648_ex2_from);
tcase_add_test(tc_b64, test_b64_rfc4648_ex3_to);
tcase_add_test(tc_b64, test_b64_rfc4648_ex3_from);
tcase_add_test(tc_b64, test_b64_rfc4648_ex4_to);
tcase_add_test(tc_b64, test_b64_rfc4648_ex4_from);
tcase_add_test(tc_b64, test_b64_rfc4648_ex5_to);
tcase_add_test(tc_b64, test_b64_rfc4648_ex5_from);
tcase_add_test(tc_b64, test_b64_rfc4648_ex6_to);
tcase_add_test(tc_b64, test_b64_rfc4648_ex6_from);
tcase_add_test(tc_b64, test_b64_rfc4648_ex7_to);
tcase_add_test(tc_b64, test_b64_rfc4648_ex7_from);
tcase_add_test(tc_b64, test_b64_all_valid_from);
tcase_add_test(tc_b64, test_b64_all_valid_to);
tcase_add_test(tc_b64, test_b64_all_invalid);
tcase_add_test(tc_b64, test_b64_small_buffer_encode);
tcase_add_test(tc_b64, test_b64_small_buffer_decode);
tcase_add_test(tc_b64, test_b64_add_pad_one);
tcase_add_test(tc_b64, test_b64_add_pad_two);
tcase_add_test(tc_b64, test_b64_bad_pad);
tcase_add_test(tc_b64, test_b64_concat_pad);
return s;
}