diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2022-06-08 18:10:55 +0300 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2022-06-09 16:56:05 +0300 |
commit | b1dd47abbf944e12beac30b1387a75d191b80c9f (patch) | |
tree | 612c4ce0484eb1ef5b1c3c3407e7b59da05ccacf | |
parent | 4866181f5338637220995cd573573787e39d78ec (diff) | |
download | libmicrohttpd-b1dd47abbf944e12beac30b1387a75d191b80c9f.tar.gz libmicrohttpd-b1dd47abbf944e12beac30b1387a75d191b80c9f.zip |
Implemented base64 decoding with thorough checks for the input data validity
-rw-r--r-- | src/microhttpd/mhd_str.c | 112 | ||||
-rw-r--r-- | src/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 index 014e71a3..d90008c0 100644 --- a/src/microhttpd/mhd_str.c +++ b/src/microhttpd/mhd_str.c | |||
@@ -1535,3 +1535,115 @@ MHD_str_quote (const char *unquoted, | |||
1535 | 1535 | ||
1536 | 1536 | ||
1537 | #endif /* DAUTH_SUPPORT || BAUTH_SUPPORT */ | 1537 | #endif /* DAUTH_SUPPORT || BAUTH_SUPPORT */ |
1538 | |||
1539 | #ifdef BAUTH_SUPPORT | ||
1540 | |||
1541 | size_t | ||
1542 | MHD_base64_to_bin_n (const char *base64, | ||
1543 | size_t base64_len, | ||
1544 | void *bin, | ||
1545 | size_t bin_size) | ||
1546 | { | ||
1547 | #ifndef MHD_FAVOR_SMALL_CODE | ||
1548 | #define map_type int | ||
1549 | #else /* MHD_FAVOR_SMALL_CODE */ | ||
1550 | #define map_type int8_t | ||
1551 | #endif /* MHD_FAVOR_SMALL_CODE */ | ||
1552 | static const map_type map[] = { | ||
1553 | /* -1 = invalid char, -2 = padding | ||
1554 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F */ | ||
1555 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 00..0F */ | ||
1556 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10..1F */ | ||
1557 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 20..2F */ | ||
1558 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, /* 30..3F */ | ||
1559 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 40..4F */ | ||
1560 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 50..5F */ | ||
1561 | -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 60..6F */ | ||
1562 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 70..7F */ | ||
1563 | #ifndef MHD_FAVOR_SMALL_CODE | ||
1564 | , | ||
1565 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80..8F */ | ||
1566 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90..9F */ | ||
1567 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A0..AF */ | ||
1568 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* B0..BF */ | ||
1569 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* C0..CF */ | ||
1570 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* D0..DF */ | ||
1571 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* E0..EF */ | ||
1572 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* F0..FF */ | ||
1573 | #endif /* ! MHD_FAVOR_SMALL_CODE */ | ||
1574 | }; | ||
1575 | const uint8_t *const in = (const uint8_t *) base64; | ||
1576 | uint8_t *const out = (uint8_t *) bin; | ||
1577 | size_t i; | ||
1578 | size_t j; | ||
1579 | if (0 == base64_len) | ||
1580 | return 0; /* Nothing to decode */ | ||
1581 | if (0 != base64_len % 4) | ||
1582 | return 0; /* Wrong input length */ | ||
1583 | if (base64_len / 4 * 3 - 2 > bin_size) | ||
1584 | return 0; | ||
1585 | |||
1586 | j = 0; | ||
1587 | for (i = 0; i < (base64_len - 4); i += 4) | ||
1588 | { | ||
1589 | #ifdef MHD_FAVOR_SMALL_CODE | ||
1590 | if (0 != (0x80 & (in[i] | in[i + 1] | in[i + 2] | in[i + 3]))) | ||
1591 | return 0; | ||
1592 | #endif /* MHD_FAVOR_SMALL_CODE */ | ||
1593 | if (1) | ||
1594 | { | ||
1595 | const map_type v1 = map[in[i + 0]]; | ||
1596 | const map_type v2 = map[in[i + 1]]; | ||
1597 | const map_type v3 = map[in[i + 2]]; | ||
1598 | const map_type v4 = map[in[i + 3]]; | ||
1599 | if ((0 > v1) || (0 > v2) || (0 > v3) || (0 > v4)) | ||
1600 | return 0; | ||
1601 | out[j + 0] = (uint8_t) ((((uint8_t) v1) << 2) | (((uint8_t) v2) >> 4)); | ||
1602 | out[j + 1] = (uint8_t) ((((uint8_t) v2) << 4) | (((uint8_t) v3) >> 2)); | ||
1603 | out[j + 2] = (uint8_t) ((((uint8_t) v3) << 6) | (((uint8_t) v4))); | ||
1604 | } | ||
1605 | j += 3; | ||
1606 | } | ||
1607 | #ifdef MHD_FAVOR_SMALL_CODE | ||
1608 | if (0 != (0x80 & (in[i] | in[i + 1] | in[i + 2] | in[i + 3]))) | ||
1609 | return 0; | ||
1610 | #endif /* MHD_FAVOR_SMALL_CODE */ | ||
1611 | if (1) | ||
1612 | { /* The last four chars block */ | ||
1613 | const map_type v1 = map[in[i + 0]]; | ||
1614 | const map_type v2 = map[in[i + 1]]; | ||
1615 | const map_type v3 = map[in[i + 2]]; | ||
1616 | const map_type v4 = map[in[i + 3]]; | ||
1617 | if ((0 > v1) || (0 > v2)) | ||
1618 | return 0; /* Invalid char or padding at first two positions */ | ||
1619 | mhd_assert (j < bin_size); | ||
1620 | out[j++] = (uint8_t) ((((uint8_t) v1) << 2) | (((uint8_t) v2) >> 4)); | ||
1621 | if (0 > v3) | ||
1622 | { /* Third char is either padding or invalid */ | ||
1623 | if ((-2 != v3) || (-2 != v4)) | ||
1624 | return 0; /* Both two last chars must be padding */ | ||
1625 | if (0 != (uint8_t) (((uint8_t) v2) << 4)) | ||
1626 | return 0; /* Wrong last char */ | ||
1627 | return j; | ||
1628 | } | ||
1629 | if (j >= bin_size) | ||
1630 | return 0; /* Not enough space */ | ||
1631 | out[j++] = (uint8_t) ((((uint8_t) v2) << 4) | (((uint8_t) v3) >> 2)); | ||
1632 | if (0 > v4) | ||
1633 | { /* Fourth char is either padding or invalid */ | ||
1634 | if (-2 != v4) | ||
1635 | return 0; /* The char must be padding */ | ||
1636 | if (0 != (uint8_t) (((uint8_t) v3) << 6)) | ||
1637 | return 0; /* Wrong last char */ | ||
1638 | return j; | ||
1639 | } | ||
1640 | if (j >= bin_size) | ||
1641 | return 0; /* Not enough space */ | ||
1642 | out[j++] = (uint8_t) ((((uint8_t) v3) << 6) | (((uint8_t) v4))); | ||
1643 | } | ||
1644 | return j; | ||
1645 | #undef map_type | ||
1646 | } | ||
1647 | |||
1648 | |||
1649 | #endif /* BAUTH_SUPPORT */ | ||
diff --git a/src/microhttpd/mhd_str.h b/src/microhttpd/mhd_str.h index af58d5d4..17921aa1 100644 --- a/src/microhttpd/mhd_str.h +++ b/src/microhttpd/mhd_str.h | |||
@@ -583,4 +583,31 @@ MHD_str_quote (const char *unquoted, | |||
583 | 583 | ||
584 | #endif /* DAUTH_SUPPORT || BAUTH_SUPPORT */ | 584 | #endif /* DAUTH_SUPPORT || BAUTH_SUPPORT */ |
585 | 585 | ||
586 | #ifdef BAUTH_SUPPORT | ||
587 | |||
588 | /** | ||
589 | * Convert Base64 encoded string to binary data. | ||
590 | * @param base64 the input string with Base64 encoded data, could be NOT zero | ||
591 | * terminated | ||
592 | * @param base64_len the number of characters to decode in @a base64 string, | ||
593 | * valid number must be a multiple of four | ||
594 | * @param[out] bin the pointer to the output buffer, the buffer may be altered | ||
595 | * even if decoding failed | ||
596 | * @param bin_size the size of the @a bin buffer in bytes, if the size is | ||
597 | * at least @a base64_len / 4 * 3 then result will always | ||
598 | * fit, regardless of the amount of the padding characters | ||
599 | * @return 0 if @base64_len is zero, or input string has wrong data (not | ||
600 | * valid Base64 sequence), or @a bin_size is too small; | ||
601 | * non-zero number of bytes written to the @a bin, the number must be | ||
602 | * (base64_len / 4 * 3 - 2), (base64_len / 4 * 3 - 1) or | ||
603 | * (base64_len / 4 * 3), depending on the number of padding characters. | ||
604 | */ | ||
605 | size_t | ||
606 | MHD_base64_to_bin_n (const char *base64, | ||
607 | size_t base64_len, | ||
608 | void *bin, | ||
609 | size_t bin_size); | ||
610 | |||
611 | #endif /* BAUTH_SUPPORT */ | ||
612 | |||
586 | #endif /* MHD_STR_H */ | 613 | #endif /* MHD_STR_H */ |