From d86fc4071ccb8590d922e3456c5c80c0f7bb9d6f Mon Sep 17 00:00:00 2001 From: Kristian Høgsberg Date: Mon, 17 May 2004 22:19:04 +0000 Subject: 2004-05-17 Kristian Høgsberg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove base64 encoding, replace with hex encoding. Original patch from trow@ximian.com, added error handling. * dbus/dbus-string.c (_dbus_string_base64_encode) (_dbus_string_base64_decode): Remove. (_dbus_string_hex_decode): Add end_return argument so we can distinguish between OOM and invalid hex encoding. (_dbus_string_test): Remove base64 tests and add test case for invalid hex. * dbus/dbus-keyring.c, dbus/dbus-auth-script.c, dbus/dbus-auth.c: Replace base64 with hex. * test/data/auth/invalid-hex-encoding.auth-script: New test case for invalid hex encoded data in auth protocol. --- dbus/dbus-string.c | 478 +++-------------------------------------------------- 1 file changed, 26 insertions(+), 452 deletions(-) (limited to 'dbus/dbus-string.c') diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c index 6a83398d..8820273d 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -2125,400 +2125,6 @@ _dbus_string_ends_with_c_str (const DBusString *a, return TRUE; } -static const signed char base64_table[] = { - /* 0 */ 'A', - /* 1 */ 'B', - /* 2 */ 'C', - /* 3 */ 'D', - /* 4 */ 'E', - /* 5 */ 'F', - /* 6 */ 'G', - /* 7 */ 'H', - /* 8 */ 'I', - /* 9 */ 'J', - /* 10 */ 'K', - /* 11 */ 'L', - /* 12 */ 'M', - /* 13 */ 'N', - /* 14 */ 'O', - /* 15 */ 'P', - /* 16 */ 'Q', - /* 17 */ 'R', - /* 18 */ 'S', - /* 19 */ 'T', - /* 20 */ 'U', - /* 21 */ 'V', - /* 22 */ 'W', - /* 23 */ 'X', - /* 24 */ 'Y', - /* 25 */ 'Z', - /* 26 */ 'a', - /* 27 */ 'b', - /* 28 */ 'c', - /* 29 */ 'd', - /* 30 */ 'e', - /* 31 */ 'f', - /* 32 */ 'g', - /* 33 */ 'h', - /* 34 */ 'i', - /* 35 */ 'j', - /* 36 */ 'k', - /* 37 */ 'l', - /* 38 */ 'm', - /* 39 */ 'n', - /* 40 */ 'o', - /* 41 */ 'p', - /* 42 */ 'q', - /* 43 */ 'r', - /* 44 */ 's', - /* 45 */ 't', - /* 46 */ 'u', - /* 47 */ 'v', - /* 48 */ 'w', - /* 49 */ 'x', - /* 50 */ 'y', - /* 51 */ 'z', - /* 52 */ '0', - /* 53 */ '1', - /* 54 */ '2', - /* 55 */ '3', - /* 56 */ '4', - /* 57 */ '5', - /* 58 */ '6', - /* 59 */ '7', - /* 60 */ '8', - /* 61 */ '9', - /* 62 */ '+', - /* 63 */ '/' -}; - -/** The minimum char that's a valid char in Base64-encoded text */ -#define UNBASE64_MIN_CHAR (43) -/** The maximum char that's a valid char in Base64-encoded text */ -#define UNBASE64_MAX_CHAR (122) -/** Must subtract this from a char's integer value before offsetting - * into unbase64_table - */ -#define UNBASE64_TABLE_OFFSET UNBASE64_MIN_CHAR -static const signed char unbase64_table[] = { - /* 43 + */ 62, - /* 44 , */ -1, - /* 45 - */ -1, - /* 46 . */ -1, - /* 47 / */ 63, - /* 48 0 */ 52, - /* 49 1 */ 53, - /* 50 2 */ 54, - /* 51 3 */ 55, - /* 52 4 */ 56, - /* 53 5 */ 57, - /* 54 6 */ 58, - /* 55 7 */ 59, - /* 56 8 */ 60, - /* 57 9 */ 61, - /* 58 : */ -1, - /* 59 ; */ -1, - /* 60 < */ -1, - /* 61 = */ -1, - /* 62 > */ -1, - /* 63 ? */ -1, - /* 64 @ */ -1, - /* 65 A */ 0, - /* 66 B */ 1, - /* 67 C */ 2, - /* 68 D */ 3, - /* 69 E */ 4, - /* 70 F */ 5, - /* 71 G */ 6, - /* 72 H */ 7, - /* 73 I */ 8, - /* 74 J */ 9, - /* 75 K */ 10, - /* 76 L */ 11, - /* 77 M */ 12, - /* 78 N */ 13, - /* 79 O */ 14, - /* 80 P */ 15, - /* 81 Q */ 16, - /* 82 R */ 17, - /* 83 S */ 18, - /* 84 T */ 19, - /* 85 U */ 20, - /* 86 V */ 21, - /* 87 W */ 22, - /* 88 X */ 23, - /* 89 Y */ 24, - /* 90 Z */ 25, - /* 91 [ */ -1, - /* 92 \ */ -1, - /* 93 ] */ -1, - /* 94 ^ */ -1, - /* 95 _ */ -1, - /* 96 ` */ -1, - /* 97 a */ 26, - /* 98 b */ 27, - /* 99 c */ 28, - /* 100 d */ 29, - /* 101 e */ 30, - /* 102 f */ 31, - /* 103 g */ 32, - /* 104 h */ 33, - /* 105 i */ 34, - /* 106 j */ 35, - /* 107 k */ 36, - /* 108 l */ 37, - /* 109 m */ 38, - /* 110 n */ 39, - /* 111 o */ 40, - /* 112 p */ 41, - /* 113 q */ 42, - /* 114 r */ 43, - /* 115 s */ 44, - /* 116 t */ 45, - /* 117 u */ 46, - /* 118 v */ 47, - /* 119 w */ 48, - /* 120 x */ 49, - /* 121 y */ 50, - /* 122 z */ 51 -}; - -/** - * Encodes a string using Base64, as documented in RFC 2045. - * - * @param source the string to encode - * @param start byte index to start encoding - * @param dest string where encoded data should be placed - * @param insert_at where to place encoded data - * @returns #TRUE if encoding was successful, #FALSE if no memory etc. - */ -dbus_bool_t -_dbus_string_base64_encode (const DBusString *source, - int start, - DBusString *dest, - int insert_at) -{ - int source_len; - unsigned int dest_len; /* unsigned for overflow checks below */ - const unsigned char *s; - unsigned char *d; - const unsigned char *triplet_end; - const unsigned char *final_end; - DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at); - _dbus_assert (source != dest); - - /* For each 24 bits (3 bytes) of input, we have 4 bytes of - * output. - */ - source_len = real_source->len - start; - dest_len = (source_len / 3) * 4; - if (source_len % 3 != 0) - dest_len += 4; - - if (dest_len > (unsigned int) real_dest->max_length) - return FALSE; - - if (source_len == 0) - return TRUE; - - if (!open_gap (dest_len, real_dest, insert_at)) - return FALSE; - - d = real_dest->str + insert_at; - s = real_source->str + start; - final_end = real_source->str + (start + source_len); - triplet_end = final_end - (source_len % 3); - _dbus_assert (triplet_end <= final_end); - _dbus_assert ((final_end - triplet_end) < 3); - -#define ENCODE_64(v) (base64_table[ (unsigned char) (v) ]) -#define SIX_BITS_MASK (0x3f) - _dbus_assert (SIX_BITS_MASK < _DBUS_N_ELEMENTS (base64_table)); - - while (s != triplet_end) - { - unsigned int triplet; - - triplet = s[2] | (s[1] << 8) | (s[0] << 16); - - /* Encode each 6 bits. */ - - *d++ = ENCODE_64 (triplet >> 18); - *d++ = ENCODE_64 ((triplet >> 12) & SIX_BITS_MASK); - *d++ = ENCODE_64 ((triplet >> 6) & SIX_BITS_MASK); - *d++ = ENCODE_64 (triplet & SIX_BITS_MASK); - - s += 3; - } - - switch (final_end - triplet_end) - { - case 2: - { - unsigned int doublet; - - doublet = s[1] | (s[0] << 8); - - *d++ = ENCODE_64 (doublet >> 12); - *d++ = ENCODE_64 ((doublet >> 6) & SIX_BITS_MASK); - *d++ = ENCODE_64 (doublet & SIX_BITS_MASK); - *d++ = '='; - } - break; - case 1: - { - unsigned int singlet; - - singlet = s[0]; - - *d++ = ENCODE_64 ((singlet >> 6) & SIX_BITS_MASK); - *d++ = ENCODE_64 (singlet & SIX_BITS_MASK); - *d++ = '='; - *d++ = '='; - } - break; - case 0: - break; - } - - _dbus_assert (d == (real_dest->str + (insert_at + dest_len))); - - return TRUE; -} - -/** - * Decodes a string from Base64, as documented in RFC 2045. - * - * @todo sort out the AUDIT comment in here. The case it mentions - * ("====" or "x===") is not allowed in correct base64, so need to - * decide what to do with that kind of input. Probably ignore it - * since we ignore any other junk seen. - * - * @param source the string to decode - * @param start byte index to start decode - * @param dest string where decoded data should be placed - * @param insert_at where to place decoded data - * @returns #TRUE if decoding was successful, #FALSE if no memory etc. - */ -dbus_bool_t -_dbus_string_base64_decode (const DBusString *source, - int start, - DBusString *dest, - int insert_at) -{ - int source_len; - const char *s; - const char *end; - DBusString result; - unsigned int triplet = 0; - int sextet_count; - int pad_count; - DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at); - _dbus_assert (source != dest); - - source_len = real_source->len - start; - s = real_source->str + start; - end = real_source->str + source_len; - - if (source_len == 0) - return TRUE; - - if (!_dbus_string_init (&result)) - return FALSE; - - pad_count = 0; - sextet_count = 0; - while (s != end) - { - /* The idea is to just skip anything that isn't - * a base64 char - it's allowed to have whitespace, - * newlines, etc. in here. We also ignore trailing - * base64 chars, though that's suspicious. - */ - - if (*s >= UNBASE64_MIN_CHAR && - *s <= UNBASE64_MAX_CHAR) - { - if (*s == '=') - { - /* '=' is padding, doesn't represent additional data - * but does increment our count. - */ - pad_count += 1; - sextet_count += 1; - } - else - { - int val; - - val = unbase64_table[(*s) - UNBASE64_TABLE_OFFSET]; - - if (val >= 0) - { - triplet <<= 6; - triplet |= (unsigned int) val; - sextet_count += 1; - } - } - - if (sextet_count == 4) - { - /* no pad = 3 bytes, 1 pad = 2 bytes, 2 pad = 1 byte */ - - - /* AUDIT: Comment doesn't mention 4 pad => 0, - * 3 pad => 1 byte, though the code should - * work fine if those are the required outputs. - * - * I assume that the spec requires dropping - * the top two bits of, say, ///= which is > 2 - * bytes worth of bits. (Or otherwise, you couldn't - * actually represent 2 byte sequences. - */ - - if (pad_count < 1) - { - if (!_dbus_string_append_byte (&result, - triplet >> 16)) - goto failed; - } - - if (pad_count < 2) - { - if (!_dbus_string_append_byte (&result, - (triplet >> 8) & 0xff)) - goto failed; - } - - if (!_dbus_string_append_byte (&result, - triplet & 0xff)) - goto failed; - - sextet_count = 0; - pad_count = 0; - triplet = 0; - } - } - - ++s; - } - - if (!_dbus_string_move (&result, 0, dest, insert_at)) - { - _dbus_string_free (&result); - return FALSE; - } - - _dbus_string_free (&result); - - return TRUE; - - failed: - _dbus_string_free (&result); - - return FALSE; -} - /** * Encodes a string in hex, the way MD5 and SHA-1 are usually * encoded. (Each byte is two hex digits.) @@ -2583,13 +2189,15 @@ _dbus_string_hex_encode (const DBusString *source, * * @param source the string to decode * @param start byte index to start decode + * @param end_return return location of the end of the hex data, or #NULL * @param dest string where decoded data should be placed * @param insert_at where to place decoded data - * @returns #TRUE if decoding was successful, #FALSE if no memory etc. + * @returns #TRUE if decoding was successful, #FALSE if no memory. */ dbus_bool_t _dbus_string_hex_decode (const DBusString *source, int start, + int *end_return, DBusString *dest, int insert_at) { @@ -2672,17 +2280,14 @@ _dbus_string_hex_decode (const DBusString *source, val = 15; break; default: - val = 0; - _dbus_verbose ("invalid character '%c' in hex encoded text\n", - *p); - goto out; + goto done; } if (high_bits) { if (!_dbus_string_append_byte (&result, val << 4)) - goto out; + goto out; } else { @@ -2703,9 +2308,13 @@ _dbus_string_hex_decode (const DBusString *source, ++p; } + done: if (!_dbus_string_move (&result, 0, dest, insert_at)) goto out; + if (end_return) + *end_return = p - (const unsigned char*) _dbus_string_get_const_data (source); + retval = TRUE; out: @@ -3227,54 +2836,6 @@ test_max_len (DBusString *str, _dbus_assert_not_reached ("setting len to zero should have worked"); } -static void -test_base64_roundtrip (const unsigned char *data, - int len) -{ - DBusString orig; - DBusString encoded; - DBusString decoded; - - if (len < 0) - len = strlen (data); - - if (!_dbus_string_init (&orig)) - _dbus_assert_not_reached ("could not init string"); - - if (!_dbus_string_init (&encoded)) - _dbus_assert_not_reached ("could not init string"); - - if (!_dbus_string_init (&decoded)) - _dbus_assert_not_reached ("could not init string"); - - if (!_dbus_string_append_len (&orig, data, len)) - _dbus_assert_not_reached ("couldn't append orig data"); - - if (!_dbus_string_base64_encode (&orig, 0, &encoded, 0)) - _dbus_assert_not_reached ("could not encode"); - - if (!_dbus_string_base64_decode (&encoded, 0, &decoded, 0)) - _dbus_assert_not_reached ("could not decode"); - - if (!_dbus_string_equal (&orig, &decoded)) - { - const char *s; - - printf ("Original string %d bytes encoded %d bytes decoded %d bytes\n", - _dbus_string_get_length (&orig), - _dbus_string_get_length (&encoded), - _dbus_string_get_length (&decoded)); - printf ("Original: %s\n", data); - s = _dbus_string_get_const_data (&decoded); - printf ("Decoded: %s\n", s); - _dbus_assert_not_reached ("original string not the same as string decoded from base64"); - } - - _dbus_string_free (&orig); - _dbus_string_free (&encoded); - _dbus_string_free (&decoded); -} - static void test_hex_roundtrip (const unsigned char *data, int len) @@ -3282,6 +2843,7 @@ test_hex_roundtrip (const unsigned char *data, DBusString orig; DBusString encoded; DBusString decoded; + int end; if (len < 0) len = strlen (data); @@ -3301,9 +2863,11 @@ test_hex_roundtrip (const unsigned char *data, if (!_dbus_string_hex_encode (&orig, 0, &encoded, 0)) _dbus_assert_not_reached ("could not encode"); - if (!_dbus_string_hex_decode (&encoded, 0, &decoded, 0)) + if (!_dbus_string_hex_decode (&encoded, 0, &end, &decoded, 0)) _dbus_assert_not_reached ("could not decode"); + _dbus_assert (_dbus_string_get_length (&encoded) == end); + if (!_dbus_string_equal (&orig, &decoded)) { const char *s; @@ -3315,7 +2879,7 @@ test_hex_roundtrip (const unsigned char *data, printf ("Original: %s\n", data); s = _dbus_string_get_const_data (&decoded); printf ("Decoded: %s\n", s); - _dbus_assert_not_reached ("original string not the same as string decoded from base64"); + _dbus_assert_not_reached ("original string not the same as string decoded from hex"); } _dbus_string_free (&orig); @@ -3867,8 +3431,18 @@ _dbus_string_test (void) _dbus_string_free (&str); - /* Base 64 and Hex encoding */ - test_roundtrips (test_base64_roundtrip); + /* Hex encoding */ + _dbus_string_init_const (&str, "cafebabe, this is a bogus hex string"); + if (!_dbus_string_init (&other)) + _dbus_assert_not_reached ("could not init string"); + + if (!_dbus_string_hex_decode (&str, 0, &end, &other, 0)) + _dbus_assert_not_reached ("deccoded bogus hex string with no error"); + + _dbus_assert (end == 8); + + _dbus_string_free (&other); + test_roundtrips (test_hex_roundtrip); /* Path validation */ -- cgit