aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2022-06-08 18:10:55 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2022-06-09 16:56:05 +0300
commitb1dd47abbf944e12beac30b1387a75d191b80c9f (patch)
tree612c4ce0484eb1ef5b1c3c3407e7b59da05ccacf
parent4866181f5338637220995cd573573787e39d78ec (diff)
downloadlibmicrohttpd-b1dd47abbf944e12beac30b1387a75d191b80c9f.tar.gz
libmicrohttpd-b1dd47abbf944e12beac30b1387a75d191b80c9f.zip
Implemented base64 decoding with thorough checks for the input data validity
-rw-r--r--src/microhttpd/mhd_str.c112
-rw-r--r--src/microhttpd/mhd_str.h27
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
1541size_t
1542MHD_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 */
605size_t
606MHD_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 */