aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd/digestauth.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/microhttpd/digestauth.c')
-rw-r--r--src/microhttpd/digestauth.c282
1 files changed, 259 insertions, 23 deletions
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c
index 0a892e22..fac3e280 100644
--- a/src/microhttpd/digestauth.c
+++ b/src/microhttpd/digestauth.c
@@ -225,6 +225,8 @@ digest_get_hash_size (enum MHD_DigestAuthAlgo3 algo3)
225 * @return the size of the digest (either #MHD_MD5_DIGEST_SIZE or 225 * @return the size of the digest (either #MHD_MD5_DIGEST_SIZE or
226 * #MHD_SHA256_DIGEST_SIZE) or zero if the input value is not 226 * #MHD_SHA256_DIGEST_SIZE) or zero if the input value is not
227 * recognised/valid 227 * recognised/valid
228 * @sa #MHD_digest_auth_calc_userdigest()
229 * @sa #MHD_digest_auth_calc_userhash(), #MHD_digest_auth_calc_userhash_hex()
228 * @note Available since #MHD_VERSION 0x00097526 230 * @note Available since #MHD_VERSION 0x00097526
229 * @ingroup authentication 231 * @ingroup authentication
230 */ 232 */
@@ -1137,7 +1139,7 @@ MHD_digest_auth_get_username (struct MHD_Connection *connection)
1137/** 1139/**
1138 * Calculate the server nonce so that it mitigates replay attacks 1140 * Calculate the server nonce so that it mitigates replay attacks
1139 * The current format of the nonce is ... 1141 * The current format of the nonce is ...
1140 * H(various parameters) + Hex(timestamp) 1142 * H(timestamp:random data:various parameters) + Hex(timestamp)
1141 * 1143 *
1142 * @param nonce_time The amount of time in seconds for a nonce to be invalid 1144 * @param nonce_time The amount of time in seconds for a nonce to be invalid
1143 * @param mthd_e HTTP method as enum value 1145 * @param mthd_e HTTP method as enum value
@@ -1516,6 +1518,240 @@ calculate_add_nonce_with_retry (struct MHD_Connection *const connection,
1516} 1518}
1517 1519
1518 1520
1521/**
1522 * Calculate userdigest, return it as binary data.
1523 *
1524 * It is equal to H(A1) for non-session algorithms.
1525 *
1526 * MHD internal version.
1527 *
1528 * @param da the digest algorithm
1529 * @param username the username to use
1530 * @param username_len the length of the @a username
1531 * @param realm the realm to use
1532 * @param realm_len the length of the @a realm
1533 * @param password the password, must be zero-terminated
1534 * @param[out] ha1_bin the output buffer, must have at least
1535 * #digest_get_size(da) bytes available
1536 */
1537_MHD_static_inline void
1538calc_userdigest (struct DigestAlgorithm *da,
1539 const char *username, const size_t username_len,
1540 const char *realm, const size_t realm_len,
1541 const char *password,
1542 uint8_t *ha1_bin)
1543{
1544 digest_init (da);
1545 digest_update (da, username, username_len);
1546 digest_update_with_colon (da);
1547 digest_update (da, realm, realm_len);
1548 digest_update_with_colon (da);
1549 digest_update_str (da, password);
1550 digest_calc_hash (da, ha1_bin);
1551}
1552
1553
1554/**
1555 * Calculate userdigest, return it as binary data.
1556 *
1557 * The "userdigest" is the hash of the "username:realm:password" string.
1558 *
1559 * The "userdigest" can be used to avoid storing the password in clear text
1560 * in database/files
1561 *
1562 * This function is designed to improve security of stored credentials,
1563 * the "userdigest" does not improve security of the authentication process.
1564 *
1565 * The results can be used to store username & userdigest pairs instead of
1566 * username & password pairs. To further improve security, application may
1567 * store username & userhash & userdigest triplets.
1568 *
1569 * @param algo3 the digest algorithm
1570 * @param username the username
1571 * @param realm the realm
1572 * @param password the password, must be zero-terminated
1573 * @param[out] userdigest_bin the output buffer for userdigest;
1574 * if this function succeeds, then this buffer has
1575 * #MHD_digest_get_hash_size(algo3) bytes of
1576 * userdigest upon return
1577 * @param userdigest_bin the size of the @a userdigest_bin buffer, must be
1578 * at least #MHD_digest_get_hash_size(algo3) bytes long
1579 * @return MHD_YES on success, MHD_NO if @a userdigest_bin is too small or
1580 * if @a algo3 algorithm is not supported.
1581 * @sa #MHD_digest_auth_check_digest3()
1582 * @note Available since #MHD_VERSION 0x00097535
1583 * @ingroup authentication
1584 */
1585_MHD_EXTERN enum MHD_Result
1586MHD_digest_auth_calc_userdigest (enum MHD_DigestAuthAlgo3 algo3,
1587 const char *username,
1588 const char *realm,
1589 const char *password,
1590 void *userdigest_bin,
1591 size_t bin_buf_size)
1592{
1593 struct DigestAlgorithm da;
1594 if (! digest_setup (&da, get_base_digest_algo (algo3)))
1595 return MHD_NO;
1596 if (digest_get_size (&da) > bin_buf_size)
1597 return MHD_NO;
1598 calc_userdigest (&da,
1599 username,
1600 strlen (username),
1601 realm,
1602 strlen (realm),
1603 password,
1604 userdigest_bin);
1605 return MHD_YES;
1606}
1607
1608
1609/**
1610 * Calculate userhash, return it as binary data.
1611 *
1612 * MHD internal version.
1613 *
1614 * @param da the digest algorithm
1615 * @param username the username to use
1616 * @param username_len the length of the @a username
1617 * @param realm the realm to use
1618 * @param realm_len the length of the @a realm
1619 * @param[out] digest_bin the output buffer, must have at least
1620 * #MHD_digest_get_hash_size(algo3) bytes available
1621 */
1622_MHD_static_inline void
1623calc_userhash (struct DigestAlgorithm *da,
1624 const char *username, const size_t username_len,
1625 const char *realm, const size_t realm_len,
1626 uint8_t *digest_bin)
1627{
1628 mhd_assert (NULL != username);
1629 digest_init (da);
1630 digest_update (da, username, username_len);
1631 digest_update_with_colon (da);
1632 digest_update (da, realm, realm_len);
1633 digest_calc_hash (da, digest_bin);
1634}
1635
1636
1637/**
1638 * Calculate "userhash", return it as binary data.
1639 *
1640 * The "userhash" is the hash of the string "username:realm".
1641 *
1642 * The "Userhash" could be used to avoid sending username in cleartext in Digest
1643 * Authorization client's header.
1644 *
1645 * Userhash is not designed to hide the username in local database or files,
1646 * as username in cleartext is required for #MHD_digest_auth_check3() function
1647 * to check the response, but it can be used to hide username in HTTP headers.
1648 *
1649 * This function could be used when the new username is added to the username
1650 * database to save the "userhash" alongside with the username (preferably) or
1651 * when loading list of the usernames to generate the userhash for every loaded
1652 * username (this will cause delays at the start with the long lists).
1653 *
1654 * Once "userhash" is generated it could be used to identify users for clients
1655 * with "userhash" support.
1656 * Avoid repetitive usage of this function for the same username/realm
1657 * combination as it will cause excessive CPU load; save and re-use the result
1658 * instead.
1659 *
1660 * @param algo3 the algorithm for userhash calculations
1661 * @param username the username
1662 * @param realm the realm
1663 * @param[out] userhash_bin the output buffer for userhash as binary data;
1664 * if this function succeeds, then this buffer has
1665 * #MHD_digest_get_hash_size(algo3) bytes of userhash
1666 * upon return
1667 * @param bin_buf_size the size of the @a userhash_bin buffer, must be
1668 * at least #MHD_digest_get_hash_size(algo3) bytes long
1669 * @return MHD_YES on success, MHD_NO if @a bin_buf_size is too small or
1670 * if @a algo3 algorithm is not supported.
1671 * @note Available since #MHD_VERSION 0x00097535
1672 * @ingroup authentication
1673 */
1674_MHD_EXTERN enum MHD_Result
1675MHD_digest_auth_calc_userhash (enum MHD_DigestAuthAlgo3 algo3,
1676 const char *username,
1677 const char *realm,
1678 void *userhash_bin,
1679 size_t bin_buf_size)
1680{
1681 struct DigestAlgorithm da;
1682 if (! digest_setup (&da, get_base_digest_algo (algo3)))
1683 return MHD_NO;
1684 if (digest_get_size (&da) > bin_buf_size)
1685 return MHD_NO;
1686 calc_userhash (&da,
1687 username,
1688 strlen (username),
1689 realm,
1690 strlen (realm),
1691 userhash_bin);
1692 return MHD_YES;
1693}
1694
1695
1696/**
1697 * Calculate "userhash", return it as hexadecimal data.
1698 *
1699 * The "userhash" is the hash of the string "username:realm".
1700 *
1701 * The "Userhash" could be used to avoid sending username in cleartext in Digest
1702 * Authorization client's header.
1703 *
1704 * Userhash is not designed to hide the username in local database or files,
1705 * as username in cleartext is required for #MHD_digest_auth_check3() function
1706 * to check the response, but it can be used to hide username in HTTP headers.
1707 *
1708 * This function could be used when the new username is added to the username
1709 * database to save the "userhash" alongside with the username (preferably) or
1710 * when loading list of the usernames to generate the userhash for every loaded
1711 * username (this will cause delays at the start with the long lists).
1712 *
1713 * Once "userhash" is generated it could be used to identify users for clients
1714 * with "userhash" support.
1715 * Avoid repetitive usage of this function for the same username/realm
1716 * combination as it will cause excessive CPU load; save and re-use the result
1717 * instead.
1718 *
1719 * @param algo3 the algorithm for userhash calculations
1720 * @param username the username
1721 * @param realm the realm
1722 * @param[out] userhash_hex the output buffer for userhash as hex data;
1723 * if this function succeeds, then this buffer has
1724 * #MHD_digest_get_hash_size(algo3)*2 chars long
1725 * userhash string
1726 * @param bin_buf_size the size of the @a userhash_bin buffer, must be
1727 * at least #MHD_digest_get_hash_size(algo3)*2+1 chars long
1728 * @return MHD_YES on success, MHD_NO if @a bin_buf_size is too small or
1729 * if @a algo3 algorithm is not supported.
1730 * @note Available since #MHD_VERSION 0x00097535
1731 * @ingroup authentication
1732 */
1733_MHD_EXTERN enum MHD_Result
1734MHD_digest_auth_calc_userhash_hex (enum MHD_DigestAuthAlgo3 algo3,
1735 const char *username,
1736 const char *realm,
1737 char *userhash_hex,
1738 size_t hex_buf_size)
1739{
1740 uint8_t userhash_bin[MAX_DIGEST];
1741 size_t digest_size;
1742
1743 digest_size = digest_get_hash_size (algo3);
1744 if (digest_size * 2 + 1 > hex_buf_size)
1745 return MHD_NO;
1746 if (MHD_NO == MHD_digest_auth_calc_userhash (algo3, username, realm,
1747 userhash_bin, MAX_DIGEST))
1748 return MHD_NO;
1749
1750 MHD_bin_to_hex_z (userhash_bin, digest_size, userhash_hex);
1751 return MHD_YES;
1752}
1753
1754
1519struct test_header_param 1755struct test_header_param
1520{ 1756{
1521 struct MHD_Connection *connection; 1757 struct MHD_Connection *connection;
@@ -2116,11 +2352,7 @@ digest_auth_check_all_inner (struct MHD_Connection *connection,
2116 else 2352 else
2117 { /* Userhash */ 2353 { /* Userhash */
2118 mhd_assert (NULL != params->username.value.str); 2354 mhd_assert (NULL != params->username.value.str);
2119 digest_init (&da); 2355 calc_userhash (&da, username, username_len, realm, realm_len, hash1_bin);
2120 digest_update (&da, username, username_len);
2121 digest_update_with_colon (&da);
2122 digest_update (&da, realm, realm_len);
2123 digest_calc_hash (&da, hash1_bin);
2124 mhd_assert (sizeof (tmp1) >= (2 * digest_size)); 2356 mhd_assert (sizeof (tmp1) >= (2 * digest_size));
2125 MHD_bin_to_hex (hash1_bin, digest_size, tmp1); 2357 MHD_bin_to_hex (hash1_bin, digest_size, tmp1);
2126 if (! is_param_equal_caseless (&params->username, tmp1, 2 * digest_size)) 2358 if (! is_param_equal_caseless (&params->username, tmp1, 2 * digest_size))
@@ -2260,15 +2492,11 @@ digest_auth_check_all_inner (struct MHD_Connection *connection,
2260 2492
2261 /* ** Build H(A1) ** */ 2493 /* ** Build H(A1) ** */
2262 if (NULL == userdigest) 2494 if (NULL == userdigest)
2263 { 2495 calc_userdigest (&da,
2264 digest_init (&da); 2496 username, username_len,
2265 digest_update (&da, (const uint8_t *) username, username_len); 2497 realm, realm_len,
2266 digest_update_with_colon (&da); 2498 password,
2267 digest_update (&da, (const uint8_t *) realm, realm_len); 2499 hash1_bin);
2268 digest_update_with_colon (&da);
2269 digest_update_str (&da, password);
2270 digest_calc_hash (&da, hash1_bin);
2271 }
2272 /* TODO: support '-sess' versions */ 2500 /* TODO: support '-sess' versions */
2273 /* Got H(A1) */ 2501 /* Got H(A1) */
2274 2502
@@ -2476,7 +2704,8 @@ MHD_digest_auth_check (struct MHD_Connection *connection,
2476 * 2704 *
2477 * @param connection the MHD connection structure 2705 * @param connection the MHD connection structure
2478 * @param realm the realm to be used for authorization of the client 2706 * @param realm the realm to be used for authorization of the client
2479 * @param username the username needs to be authenticated 2707 * @param username the username needs to be authenticated, must be in clear text
2708 * even if userhash is used by the client
2480 * @param password the password used in the authentication 2709 * @param password the password used in the authentication
2481 * @param nonce_timeout the nonce validity duration in seconds 2710 * @param nonce_timeout the nonce validity duration in seconds
2482 * @param max_nc the maximum allowed nc (Nonce Count) value, if client's nc 2711 * @param max_nc the maximum allowed nc (Nonce Count) value, if client's nc
@@ -2528,13 +2757,15 @@ MHD_digest_auth_check3 (struct MHD_Connection *connection,
2528 * nonce and second time to perform an authorised request). 2757 * nonce and second time to perform an authorised request).
2529 * 2758 *
2530 * @param connection the MHD connection structure 2759 * @param connection the MHD connection structure
2531 * @param realm the realm presented to the client 2760 * @param realm the realm to be used for authorization of the client
2532 * @param username the username needs to be authenticated 2761 * @param username the username needs to be authenticated, must be in clear text
2762 * even if userhash is used by the client
2533 * @param userdigest the precalculated binary hash of the string 2763 * @param userdigest the precalculated binary hash of the string
2534 * "username:realm:password" 2764 * "username:realm:password",
2765 * see #MHD_digest_auth_calc_userdigest()
2535 * @param userdigest_size the size of the @a userdigest in bytes, must match the 2766 * @param userdigest_size the size of the @a userdigest in bytes, must match the
2536 * hashing algorithm (see #MHD_MD5_DIGEST_SIZE, 2767 * hashing algorithm (see #MHD_MD5_DIGEST_SIZE,
2537 * #MHD_SHA256_DIGEST_SIZE) 2768 * #MHD_SHA256_DIGEST_SIZE, #MHD_digest_get_hash_size())
2538 * @param nonce_timeout the period of seconds since nonce generation, when 2769 * @param nonce_timeout the period of seconds since nonce generation, when
2539 * the nonce is recognised as valid and not stale. 2770 * the nonce is recognised as valid and not stale.
2540 * @param max_nc the maximum allowed nc (Nonce Count) value, if client's nc 2771 * @param max_nc the maximum allowed nc (Nonce Count) value, if client's nc
@@ -2549,6 +2780,7 @@ MHD_digest_auth_check3 (struct MHD_Connection *connection,
2549 * match specified algorithm 2780 * match specified algorithm
2550 * @return #MHD_DAUTH_OK if authenticated, 2781 * @return #MHD_DAUTH_OK if authenticated,
2551 * the error code otherwise 2782 * the error code otherwise
2783 * @sa #MHD_digest_auth_calc_userdigest()
2552 * @note Available since #MHD_VERSION 0x00097528 2784 * @note Available since #MHD_VERSION 0x00097528
2553 * @ingroup authentication 2785 * @ingroup authentication
2554 */ 2786 */
@@ -2777,9 +3009,13 @@ MHD_digest_auth_check_digest (struct MHD_Connection *connection,
2777 * @param userhash_support if set to non-zero value (#MHD_YES) then support of 3009 * @param userhash_support if set to non-zero value (#MHD_YES) then support of
2778 * userhash is indicated, the client may provide 3010 * userhash is indicated, the client may provide
2779 * hash("username:realm") instead of username in 3011 * hash("username:realm") instead of username in
2780 * clear text; note that client is allowed to provide 3012 * clear text;
2781 * the username in cleartext even if this parameter set 3013 * note that clients are allowed to provide the username
2782 * to non-zero 3014 * in cleartext even if this parameter set to non-zero;
3015 * when userhash is used, application must be ready to
3016 * identify users by provided userhash value instead of
3017 * username; see #MHD_digest_auth_calc_userhash() and
3018 * #MHD_digest_auth_calc_userhash_hex()
2783 * @param prefer_utf8 if not set to #MHD_NO, parameter 'charset=UTF-8' is 3019 * @param prefer_utf8 if not set to #MHD_NO, parameter 'charset=UTF-8' is
2784 * added, indicating for the client that UTF-8 encoding 3020 * added, indicating for the client that UTF-8 encoding
2785 * is preferred 3021 * is preferred