libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit b1dd47abbf944e12beac30b1387a75d191b80c9f
parent 4866181f5338637220995cd573573787e39d78ec
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
Date:   Wed,  8 Jun 2022 18:10:55 +0300

Implemented base64 decoding with thorough checks for the input data validity

Diffstat:
Msrc/microhttpd/mhd_str.c | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/microhttpd/mhd_str.h | 27+++++++++++++++++++++++++++
2 files changed, 139 insertions(+), 0 deletions(-)

diff --git a/src/microhttpd/mhd_str.c b/src/microhttpd/mhd_str.c @@ -1535,3 +1535,115 @@ MHD_str_quote (const char *unquoted, #endif /* DAUTH_SUPPORT || BAUTH_SUPPORT */ + +#ifdef BAUTH_SUPPORT + +size_t +MHD_base64_to_bin_n (const char *base64, + size_t base64_len, + void *bin, + size_t bin_size) +{ +#ifndef MHD_FAVOR_SMALL_CODE +#define map_type int +#else /* MHD_FAVOR_SMALL_CODE */ +#define map_type int8_t +#endif /* MHD_FAVOR_SMALL_CODE */ + static const map_type map[] = { + /* -1 = invalid char, -2 = padding + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 00..0F */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10..1F */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 20..2F */ + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, /* 30..3F */ + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 40..4F */ + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 50..5F */ + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 60..6F */ + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 70..7F */ +#ifndef MHD_FAVOR_SMALL_CODE + , + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80..8F */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90..9F */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A0..AF */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* B0..BF */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* C0..CF */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* D0..DF */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* E0..EF */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* F0..FF */ +#endif /* ! MHD_FAVOR_SMALL_CODE */ + }; + const uint8_t *const in = (const uint8_t *) base64; + uint8_t *const out = (uint8_t *) bin; + size_t i; + size_t j; + if (0 == base64_len) + return 0; /* Nothing to decode */ + if (0 != base64_len % 4) + return 0; /* Wrong input length */ + if (base64_len / 4 * 3 - 2 > bin_size) + return 0; + + j = 0; + for (i = 0; i < (base64_len - 4); i += 4) + { +#ifdef MHD_FAVOR_SMALL_CODE + if (0 != (0x80 & (in[i] | in[i + 1] | in[i + 2] | in[i + 3]))) + return 0; +#endif /* MHD_FAVOR_SMALL_CODE */ + if (1) + { + const map_type v1 = map[in[i + 0]]; + const map_type v2 = map[in[i + 1]]; + const map_type v3 = map[in[i + 2]]; + const map_type v4 = map[in[i + 3]]; + if ((0 > v1) || (0 > v2) || (0 > v3) || (0 > v4)) + return 0; + out[j + 0] = (uint8_t) ((((uint8_t) v1) << 2) | (((uint8_t) v2) >> 4)); + out[j + 1] = (uint8_t) ((((uint8_t) v2) << 4) | (((uint8_t) v3) >> 2)); + out[j + 2] = (uint8_t) ((((uint8_t) v3) << 6) | (((uint8_t) v4))); + } + j += 3; + } +#ifdef MHD_FAVOR_SMALL_CODE + if (0 != (0x80 & (in[i] | in[i + 1] | in[i + 2] | in[i + 3]))) + return 0; +#endif /* MHD_FAVOR_SMALL_CODE */ + if (1) + { /* The last four chars block */ + const map_type v1 = map[in[i + 0]]; + const map_type v2 = map[in[i + 1]]; + const map_type v3 = map[in[i + 2]]; + const map_type v4 = map[in[i + 3]]; + if ((0 > v1) || (0 > v2)) + return 0; /* Invalid char or padding at first two positions */ + mhd_assert (j < bin_size); + out[j++] = (uint8_t) ((((uint8_t) v1) << 2) | (((uint8_t) v2) >> 4)); + if (0 > v3) + { /* Third char is either padding or invalid */ + if ((-2 != v3) || (-2 != v4)) + return 0; /* Both two last chars must be padding */ + if (0 != (uint8_t) (((uint8_t) v2) << 4)) + return 0; /* Wrong last char */ + return j; + } + if (j >= bin_size) + return 0; /* Not enough space */ + out[j++] = (uint8_t) ((((uint8_t) v2) << 4) | (((uint8_t) v3) >> 2)); + if (0 > v4) + { /* Fourth char is either padding or invalid */ + if (-2 != v4) + return 0; /* The char must be padding */ + if (0 != (uint8_t) (((uint8_t) v3) << 6)) + return 0; /* Wrong last char */ + return j; + } + if (j >= bin_size) + return 0; /* Not enough space */ + out[j++] = (uint8_t) ((((uint8_t) v3) << 6) | (((uint8_t) v4))); + } + return j; +#undef map_type +} + + +#endif /* BAUTH_SUPPORT */ diff --git a/src/microhttpd/mhd_str.h b/src/microhttpd/mhd_str.h @@ -583,4 +583,31 @@ MHD_str_quote (const char *unquoted, #endif /* DAUTH_SUPPORT || BAUTH_SUPPORT */ +#ifdef BAUTH_SUPPORT + +/** + * Convert Base64 encoded string to binary data. + * @param base64 the input string with Base64 encoded data, could be NOT zero + * terminated + * @param base64_len the number of characters to decode in @a base64 string, + * valid number must be a multiple of four + * @param[out] bin the pointer to the output buffer, the buffer may be altered + * even if decoding failed + * @param bin_size the size of the @a bin buffer in bytes, if the size is + * at least @a base64_len / 4 * 3 then result will always + * fit, regardless of the amount of the padding characters + * @return 0 if @base64_len is zero, or input string has wrong data (not + * valid Base64 sequence), or @a bin_size is too small; + * non-zero number of bytes written to the @a bin, the number must be + * (base64_len / 4 * 3 - 2), (base64_len / 4 * 3 - 1) or + * (base64_len / 4 * 3), depending on the number of padding characters. + */ +size_t +MHD_base64_to_bin_n (const char *base64, + size_t base64_len, + void *bin, + size_t bin_size); + +#endif /* BAUTH_SUPPORT */ + #endif /* MHD_STR_H */