diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2022-08-14 14:10:03 +0300 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2022-08-15 16:21:45 +0300 |
commit | 2f8eefada8be541c82c7fb4ed9bca7e88e720cd8 (patch) | |
tree | 5fabda78dfe6ef9448c2a10195a0edf023d45d04 | |
parent | 25863e1c897b63eb56d248fde9634d0477ca8830 (diff) | |
download | libmicrohttpd-2f8eefada8be541c82c7fb4ed9bca7e88e720cd8.tar.gz libmicrohttpd-2f8eefada8be541c82c7fb4ed9bca7e88e720cd8.zip |
Added MHD_OPTION_DIGEST_AUTH_NONCE_BIND_TYPE to control how to generate and
check nonces for Digest Auth
-rw-r--r-- | src/include/microhttpd.h | 93 | ||||
-rw-r--r-- | src/microhttpd/daemon.c | 7 | ||||
-rw-r--r-- | src/microhttpd/digestauth.c | 217 | ||||
-rw-r--r-- | src/microhttpd/internal.h | 4 | ||||
-rw-r--r-- | src/testcurl/test_digestauth2.c | 4 |
5 files changed, 250 insertions, 75 deletions
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h index 78a31f29..83006001 100644 --- a/src/include/microhttpd.h +++ b/src/include/microhttpd.h | |||
@@ -96,7 +96,7 @@ extern "C" | |||
96 | * they are parsed as decimal numbers. | 96 | * they are parsed as decimal numbers. |
97 | * Example: 0x01093001 = 1.9.30-1. | 97 | * Example: 0x01093001 = 1.9.30-1. |
98 | */ | 98 | */ |
99 | #define MHD_VERSION 0x00097530 | 99 | #define MHD_VERSION 0x00097531 |
100 | 100 | ||
101 | /* If generic headers don't work on your platform, include headers | 101 | /* If generic headers don't work on your platform, include headers |
102 | which define 'va_list', 'size_t', 'ssize_t', 'intptr_t', 'off_t', | 102 | which define 'va_list', 'size_t', 'ssize_t', 'intptr_t', 'off_t', |
@@ -1541,6 +1541,69 @@ typedef int | |||
1541 | size_t *psk_size); | 1541 | size_t *psk_size); |
1542 | 1542 | ||
1543 | /** | 1543 | /** |
1544 | * Values for #MHD_OPTION_DIGEST_AUTH_NONCE_BIND_TYPE. | ||
1545 | * | ||
1546 | * These values can limit the scope of validity of MHD-generated nonces. | ||
1547 | * Values can be combined with bitwise OR. | ||
1548 | * Any value, except #MHD_DAUTH_BIND_NONCE_NONE, enforce function | ||
1549 | * #MHD_digest_auth_check3() (and similar) to check nonce by re-generating | ||
1550 | * it again with the same parameters, which is CPU-intensive operation. | ||
1551 | * @note Available since #MHD_VERSION 0x00097531 | ||
1552 | */ | ||
1553 | enum MHD_DAuthBindNonce | ||
1554 | { | ||
1555 | /** | ||
1556 | * Generated nonces are valid for any request from any client until expired. | ||
1557 | * This is default and recommended value. | ||
1558 | * #MHD_digest_auth_check3() (and similar function) would check only whether | ||
1559 | * the nonce value that is used by client has been generated by MHD and not | ||
1560 | * expired yet. | ||
1561 | * It is recommended because RFC 7616 allows clients to use the same nonce | ||
1562 | * for any request in the same "protection space". | ||
1563 | * CPU is loaded less when this value is used when checking client's | ||
1564 | * authorisation request. | ||
1565 | * This value cannot be combined with other values. | ||
1566 | */ | ||
1567 | MHD_DAUTH_BIND_NONCE_NONE = 0, | ||
1568 | |||
1569 | /** | ||
1570 | * Generated nonces are valid only for the same realm. | ||
1571 | */ | ||
1572 | MHD_DAUTH_BIND_NONCE_REALM = 1 << 0, | ||
1573 | |||
1574 | /** | ||
1575 | * Generated nonces are valid only for the same URI (excluding parameters | ||
1576 | * after '?' in URI) and request method (GET, POST etc). | ||
1577 | * Not recommended unless "protection space" is limited to a single URI as | ||
1578 | * RFC 7616 allows clients to re-use server-generated nonces for any URI | ||
1579 | * in the same "protection space" which is by default consists of all server | ||
1580 | * URIs. | ||
1581 | * This was default (and only supported) value before #MHD_VERSION 0x00097518 | ||
1582 | */ | ||
1583 | MHD_DAUTH_BIND_NONCE_URI = 1 << 1, | ||
1584 | |||
1585 | /** | ||
1586 | * Generated nonces are valid only for the same URI including URI parameters | ||
1587 | * and request method (GET, POST etc). | ||
1588 | * This value implies #MHD_DAUTH_BIND_NONCE_URI. | ||
1589 | * Not recommended for that same reasons as #MHD_DAUTH_BIND_NONCE_URI. | ||
1590 | */ | ||
1591 | MHD_DAUTH_BIND_NONCE_URI_PARAMS = 1 << 2, | ||
1592 | |||
1593 | /** | ||
1594 | * Generated nonces are valid only for the single client's IP. | ||
1595 | * While it looks like security improvement, in practice the same client may | ||
1596 | * jump from one IP to another (mobile or Wi-Fi handover, DHCP re-assignment, | ||
1597 | * Multi-NAT, different proxy chain and other reasons), while IP address | ||
1598 | * spoofing could be used relatively easily. | ||
1599 | * However, if server gets intensive requests with Digest Authentication | ||
1600 | * this value helps to generate unique nonces for several requests, received | ||
1601 | * exactly at the same time (within one millisecond) from different clients. | ||
1602 | */ | ||
1603 | MHD_DAUTH_BIND_NONCE_CLIENT_IP = 1 << 3 | ||
1604 | } _MHD_FLAGS_ENUM; | ||
1605 | |||
1606 | /** | ||
1544 | * @brief MHD options. | 1607 | * @brief MHD options. |
1545 | * | 1608 | * |
1546 | * Passed in the varargs portion of #MHD_start_daemon. | 1609 | * Passed in the varargs portion of #MHD_start_daemon. |
@@ -1943,7 +2006,17 @@ enum MHD_OPTION | |||
1943 | * @sa #MHD_OPTION_DIGEST_AUTH_RANDOM | 2006 | * @sa #MHD_OPTION_DIGEST_AUTH_RANDOM |
1944 | * @note Available since #MHD_VERSION 0x00097529 | 2007 | * @note Available since #MHD_VERSION 0x00097529 |
1945 | */ | 2008 | */ |
1946 | MHD_OPTION_DIGEST_AUTH_RANDOM_COPY = 35 | 2009 | MHD_OPTION_DIGEST_AUTH_RANDOM_COPY = 35, |
2010 | |||
2011 | /** | ||
2012 | * Allow to controls the scope of validity of MHD-generated nonces. | ||
2013 | * This regulates how "nonces" are generated and how "nonces" are checked by | ||
2014 | * #MHD_digest_auth_check3() and similar functions. | ||
2015 | * This option should be followed by an 'unsigned int` argument with value | ||
2016 | * formed as bitwise OR combination of #MHD_DAuthBindNonce values. | ||
2017 | * @note Available since #MHD_VERSION 0x00097531 | ||
2018 | */ | ||
2019 | MHD_OPTION_DIGEST_AUTH_NONCE_BIND_TYPE = 36 | ||
1947 | } _MHD_FIXED_ENUM; | 2020 | } _MHD_FIXED_ENUM; |
1948 | 2021 | ||
1949 | 2022 | ||
@@ -4906,7 +4979,7 @@ MHD_digest_auth_get_username3 (struct MHD_Connection *connection); | |||
4906 | * | 4979 | * |
4907 | * All error values are zero or negative. | 4980 | * All error values are zero or negative. |
4908 | * | 4981 | * |
4909 | * @note Available since #MHD_VERSION 0x00097521 | 4982 | * @note Available since #MHD_VERSION 0x00097531 |
4910 | */ | 4983 | */ |
4911 | enum MHD_DigestAuthResult | 4984 | enum MHD_DigestAuthResult |
4912 | { | 4985 | { |
@@ -4968,6 +5041,20 @@ enum MHD_DigestAuthResult | |||
4968 | MHD_DAUTH_NONCE_STALE = -17, | 5041 | MHD_DAUTH_NONCE_STALE = -17, |
4969 | 5042 | ||
4970 | /** | 5043 | /** |
5044 | * The 'nonce' was generated by MHD for other conditions. | ||
5045 | * This value is only returned if #MHD_OPTION_DIGEST_AUTH_NONCE_BIND_TYPE | ||
5046 | * is set to anything other than #MHD_DAUTH_BIND_NONCE_NONE. | ||
5047 | * The interpretation of this code could be different. For example, if | ||
5048 | * #MHD_DAUTH_BIND_NONCE_URI is set and client just used the same 'nonce' for | ||
5049 | * another URI, the code could be handled as #MHD_DAUTH_NONCE_STALE as | ||
5050 | * it is allowed to re-use nonces for other URIs in the same "protection | ||
5051 | * space". However, if only #MHD_DAUTH_BIND_NONCE_CLIENT_IP bit is set and | ||
5052 | * it is know that clients have fixed IP addresses, this return code could | ||
5053 | * be handled like #MHD_DAUTH_NONCE_WRONG. | ||
5054 | */ | ||
5055 | MHD_DAUTH_NONCE_OTHER_COND = -18, | ||
5056 | |||
5057 | /** | ||
4971 | * The 'nonce' is wrong. May indicate an attack attempt. | 5058 | * The 'nonce' is wrong. May indicate an attack attempt. |
4972 | */ | 5059 | */ |
4973 | MHD_DAUTH_NONCE_WRONG = -33, | 5060 | MHD_DAUTH_NONCE_WRONG = -33, |
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index f548b434..6a92e733 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c | |||
@@ -6257,6 +6257,12 @@ parse_options_va (struct MHD_Daemon *daemon, | |||
6257 | daemon->nonce_nc_size = va_arg (ap, | 6257 | daemon->nonce_nc_size = va_arg (ap, |
6258 | unsigned int); | 6258 | unsigned int); |
6259 | break; | 6259 | break; |
6260 | case MHD_OPTION_DIGEST_AUTH_NONCE_BIND_TYPE: | ||
6261 | daemon->dauth_bind_type = va_arg (ap, | ||
6262 | unsigned int); | ||
6263 | if (0 != (daemon->dauth_bind_type & MHD_DAUTH_BIND_NONCE_URI_PARAMS)) | ||
6264 | daemon->dauth_bind_type |= MHD_DAUTH_BIND_NONCE_URI; | ||
6265 | break; | ||
6260 | #endif | 6266 | #endif |
6261 | case MHD_OPTION_LISTEN_SOCKET: | 6267 | case MHD_OPTION_LISTEN_SOCKET: |
6262 | if (0 != (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) | 6268 | if (0 != (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) |
@@ -6379,6 +6385,7 @@ parse_options_va (struct MHD_Daemon *daemon, | |||
6379 | case MHD_OPTION_LISTENING_ADDRESS_REUSE: | 6385 | case MHD_OPTION_LISTENING_ADDRESS_REUSE: |
6380 | case MHD_OPTION_LISTEN_BACKLOG_SIZE: | 6386 | case MHD_OPTION_LISTEN_BACKLOG_SIZE: |
6381 | case MHD_OPTION_SERVER_INSANITY: | 6387 | case MHD_OPTION_SERVER_INSANITY: |
6388 | case MHD_OPTION_DIGEST_AUTH_NONCE_BIND_TYPE: | ||
6382 | if (MHD_NO == parse_options (daemon, | 6389 | if (MHD_NO == parse_options (daemon, |
6383 | servaddr, | 6390 | servaddr, |
6384 | opt, | 6391 | opt, |
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c index 4b4eac7c..ba112bd6 100644 --- a/src/microhttpd/digestauth.c +++ b/src/microhttpd/digestauth.c | |||
@@ -23,7 +23,9 @@ | |||
23 | * @author Amr Ali | 23 | * @author Amr Ali |
24 | * @author Matthieu Speder | 24 | * @author Matthieu Speder |
25 | * @author Christian Grothoff (RFC 7616 support) | 25 | * @author Christian Grothoff (RFC 7616 support) |
26 | * @author Karlson2k (Evgeny Grin) | 26 | * @author Karlson2k (Evgeny Grin) (fixes, new API, improvements, large rewrite, |
27 | * many RFC 7616 features implementation, | ||
28 | * old RFC 2069 support) | ||
27 | */ | 29 | */ |
28 | #include "digestauth.h" | 30 | #include "digestauth.h" |
29 | #include "gen_auth.h" | 31 | #include "gen_auth.h" |
@@ -1314,85 +1316,140 @@ MHD_digest_auth_get_username (struct MHD_Connection *connection) | |||
1314 | * H(timestamp ":" method ":" random ":" uri ":" realm) + Hex(timestamp) | 1316 | * H(timestamp ":" method ":" random ":" uri ":" realm) + Hex(timestamp) |
1315 | * | 1317 | * |
1316 | * @param nonce_time The amount of time in seconds for a nonce to be invalid | 1318 | * @param nonce_time The amount of time in seconds for a nonce to be invalid |
1317 | * @param method HTTP method | 1319 | * @param mthd_e HTTP method as enum value |
1318 | * @param rnd A pointer to a character array for the random seed | 1320 | * @param method HTTP method as a string |
1321 | * @param rnd the pointer to a character array for the random seed | ||
1319 | * @param rnd_size The size of the random seed array @a rnd | 1322 | * @param rnd_size The size of the random seed array @a rnd |
1320 | * @param uri HTTP URI (in MHD, without the arguments ("?k=v") | 1323 | * @param saddr the pointer to the socket address structure |
1324 | * @param saddr_size the size of the socket address structure @a saddr | ||
1325 | * @param uri the HTTP URI (in MHD, without the arguments ("?k=v") | ||
1326 | * @param uri_len the length of the @a uri | ||
1327 | * @param first_header the pointer to the first request's header | ||
1321 | * @param realm A string of characters that describes the realm of auth. | 1328 | * @param realm A string of characters that describes the realm of auth. |
1322 | * @param realm_len the length of the @a realm. | 1329 | * @param realm_len the length of the @a realm. |
1330 | * @param bind_options the nonce bind options (#MHD_DAuthBindNonce values). | ||
1323 | * @param da digest algorithm to use | 1331 | * @param da digest algorithm to use |
1324 | * @param[out] nonce A pointer to a character array for the nonce to put in, | 1332 | * @param[out] nonce the pointer to a character array for the nonce to put in, |
1325 | * must provide NONCE_STD_LEN(digest_get_size(da))+1 bytes | 1333 | * must provide NONCE_STD_LEN(digest_get_size(da)) bytes, |
1334 | * result is NOT zero-terminated | ||
1326 | */ | 1335 | */ |
1327 | static void | 1336 | static void |
1328 | calculate_nonce (uint64_t nonce_time, | 1337 | calculate_nonce (uint64_t nonce_time, |
1338 | enum MHD_HTTP_Method mthd_e, | ||
1329 | const char *method, | 1339 | const char *method, |
1330 | const char *rnd, | 1340 | const char *rnd, |
1331 | size_t rnd_size, | 1341 | size_t rnd_size, |
1342 | const struct sockaddr_storage *saddr, | ||
1343 | size_t saddr_size, | ||
1332 | const char *uri, | 1344 | const char *uri, |
1333 | size_t uri_len, | 1345 | size_t uri_len, |
1334 | struct MHD_HTTP_Req_Header *first_header, | 1346 | const struct MHD_HTTP_Req_Header *first_header, |
1335 | const char *realm, | 1347 | const char *realm, |
1336 | size_t realm_len, | 1348 | size_t realm_len, |
1349 | unsigned int bind_options, | ||
1337 | struct DigestAlgorithm *da, | 1350 | struct DigestAlgorithm *da, |
1338 | char *nonce) | 1351 | char *nonce) |
1339 | { | 1352 | { |
1340 | uint8_t timestamp[TIMESTAMP_BIN_SIZE]; | ||
1341 | struct MHD_HTTP_Req_Header *h; | ||
1342 | |||
1343 | digest_init (da); | 1353 | digest_init (da); |
1344 | /* If the nonce_time is milliseconds, then the same 48 bit value will repeat | 1354 | if (1) |
1345 | * every 8 925 years, which is more than enough to mitigate a replay attack */ | 1355 | { |
1356 | uint8_t timestamp[TIMESTAMP_BIN_SIZE]; | ||
1357 | /* If the nonce_time is milliseconds, then the same 48 bit value will repeat | ||
1358 | * every 8 925 years, which is more than enough to mitigate a replay attack */ | ||
1346 | #if TIMESTAMP_BIN_SIZE != 6 | 1359 | #if TIMESTAMP_BIN_SIZE != 6 |
1347 | #error The code needs to be updated here | 1360 | #error The code needs to be updated here |
1348 | #endif | 1361 | #endif |
1349 | timestamp[0] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 0))); | 1362 | timestamp[0] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 0))); |
1350 | timestamp[1] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 1))); | 1363 | timestamp[1] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 1))); |
1351 | timestamp[2] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 2))); | 1364 | timestamp[2] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 2))); |
1352 | timestamp[3] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 3))); | 1365 | timestamp[3] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 3))); |
1353 | timestamp[4] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 4))); | 1366 | timestamp[4] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 4))); |
1354 | timestamp[5] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 5))); | 1367 | timestamp[5] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 5))); |
1355 | digest_update (da, | 1368 | MHD_bin_to_hex (timestamp, |
1356 | timestamp, | 1369 | sizeof (timestamp), |
1357 | sizeof (timestamp)); | 1370 | nonce + digest_get_size (da) * 2); |
1358 | digest_update_with_colon (da); | 1371 | digest_update (da, |
1359 | digest_update_str (da, method); | 1372 | timestamp, |
1360 | digest_update_with_colon (da); | 1373 | sizeof (timestamp)); |
1374 | digest_update_with_colon (da); | ||
1375 | } | ||
1361 | if (rnd_size > 0) | 1376 | if (rnd_size > 0) |
1377 | { | ||
1362 | digest_update (da, | 1378 | digest_update (da, |
1363 | rnd, | 1379 | rnd, |
1364 | rnd_size); | 1380 | rnd_size); |
1365 | digest_update_with_colon (da); | 1381 | digest_update_with_colon (da); |
1366 | digest_update (da, | 1382 | } |
1367 | uri, | 1383 | if ( (0 != (bind_options & MHD_DAUTH_BIND_NONCE_CLIENT_IP)) && |
1368 | uri_len); | 1384 | (0 != saddr_size) ) |
1369 | for (h = first_header; NULL != h; h = h->next) | 1385 | { |
1386 | if (AF_INET == saddr->ss_family) | ||
1387 | digest_update (da, | ||
1388 | &((const struct sockaddr_in *) saddr)->sin_addr, | ||
1389 | sizeof(((const struct sockaddr_in *) saddr)->sin_addr)); | ||
1390 | #ifdef HAVE_INET6 | ||
1391 | else if (AF_INET6 == saddr->ss_family) | ||
1392 | digest_update (da, | ||
1393 | &((const struct sockaddr_in6 *) saddr)->sin6_addr, | ||
1394 | sizeof(((const struct sockaddr_in6 *) saddr)->sin6_addr)); | ||
1395 | #endif /* HAVE_INET6 */ | ||
1396 | digest_update_with_colon (da); | ||
1397 | } | ||
1398 | if (0 != (bind_options & MHD_DAUTH_BIND_NONCE_URI)) | ||
1399 | { | ||
1400 | if (MHD_HTTP_MTHD_OTHER != mthd_e) | ||
1401 | { | ||
1402 | uint8_t mthd_for_hash; | ||
1403 | if (MHD_HTTP_MTHD_HEAD != mthd_e) | ||
1404 | mthd_for_hash = (uint8_t) mthd_e; | ||
1405 | else /* Treat HEAD method in the same way as GET method */ | ||
1406 | mthd_for_hash = (uint8_t) MHD_HTTP_MTHD_GET; | ||
1407 | digest_update (da, | ||
1408 | &mthd_for_hash, | ||
1409 | sizeof(mthd_for_hash)); | ||
1410 | } | ||
1411 | else | ||
1412 | digest_update_str (da, method); | ||
1413 | |||
1414 | digest_update_with_colon (da); | ||
1415 | |||
1416 | digest_update (da, | ||
1417 | uri, | ||
1418 | uri_len); | ||
1419 | digest_update_with_colon (da); | ||
1420 | } | ||
1421 | if (0 != (bind_options & MHD_DAUTH_BIND_NONCE_URI_PARAMS)) | ||
1370 | { | 1422 | { |
1371 | if (MHD_GET_ARGUMENT_KIND != h->kind) | 1423 | const struct MHD_HTTP_Req_Header *h; |
1372 | continue; | 1424 | |
1373 | digest_update (da, "\0", 2); | 1425 | for (h = first_header; NULL != h; h = h->next) |
1374 | if (0 != h->header_size) | 1426 | { |
1375 | digest_update (da, h->header, h->header_size); | 1427 | if (MHD_GET_ARGUMENT_KIND != h->kind) |
1376 | digest_update (da, "", 1); | 1428 | continue; |
1377 | if (0 != h->value_size) | 1429 | digest_update (da, "\0", 2); |
1378 | digest_update (da, h->value, h->value_size); | 1430 | if (0 != h->header_size) |
1431 | digest_update (da, h->header, h->header_size); | ||
1432 | digest_update (da, "", 1); | ||
1433 | if (0 != h->value_size) | ||
1434 | digest_update (da, h->value, h->value_size); | ||
1435 | } | ||
1436 | digest_update_with_colon (da); | ||
1437 | } | ||
1438 | if (0 != (bind_options & MHD_DAUTH_BIND_NONCE_REALM)) | ||
1439 | { | ||
1440 | digest_update (da, | ||
1441 | realm, | ||
1442 | realm_len); | ||
1443 | digest_update_with_colon (da); | ||
1379 | } | 1444 | } |
1380 | digest_update_with_colon (da); | ||
1381 | digest_update (da, | ||
1382 | realm, | ||
1383 | realm_len); | ||
1384 | if (1) | 1445 | if (1) |
1385 | { | 1446 | { |
1386 | const unsigned int digest_size = digest_get_size (da); | ||
1387 | uint8_t hash[MAX_DIGEST]; | 1447 | uint8_t hash[MAX_DIGEST]; |
1388 | digest_calc_hash (da, hash); | 1448 | digest_calc_hash (da, hash); |
1389 | MHD_bin_to_hex (hash, | 1449 | MHD_bin_to_hex (hash, |
1390 | digest_size, | 1450 | digest_get_size (da), |
1391 | nonce); | 1451 | nonce); |
1392 | } | 1452 | } |
1393 | MHD_bin_to_hex (timestamp, | ||
1394 | sizeof (timestamp), | ||
1395 | nonce + digest_get_size (da) * 2); | ||
1396 | } | 1453 | } |
1397 | 1454 | ||
1398 | 1455 | ||
@@ -1464,7 +1521,8 @@ is_slot_available (const struct MHD_NonceNc *const nn, | |||
1464 | * @param realm_len the length of the @a realm | 1521 | * @param realm_len the length of the @a realm |
1465 | * @param da the digest algorithm to use | 1522 | * @param da the digest algorithm to use |
1466 | * @param[out] nonce the pointer to a character array for the nonce to put in, | 1523 | * @param[out] nonce the pointer to a character array for the nonce to put in, |
1467 | * must provide NONCE_STD_LEN(digest_get_size(da))+1 bytes | 1524 | * must provide NONCE_STD_LEN(digest_get_size(da)) bytes, |
1525 | * result is NOT zero-terminated | ||
1468 | * @return true if the new nonce has been added to the nonce-nc map array, | 1526 | * @return true if the new nonce has been added to the nonce-nc map array, |
1469 | * false otherwise. | 1527 | * false otherwise. |
1470 | */ | 1528 | */ |
@@ -1485,14 +1543,18 @@ calculate_add_nonce (struct MHD_Connection *const connection, | |||
1485 | mhd_assert (0 != nonce_size); | 1543 | mhd_assert (0 != nonce_size); |
1486 | 1544 | ||
1487 | calculate_nonce (timestamp, | 1545 | calculate_nonce (timestamp, |
1546 | connection->rq.http_mthd, | ||
1488 | connection->rq.method, | 1547 | connection->rq.method, |
1489 | daemon->digest_auth_random, | 1548 | daemon->digest_auth_random, |
1490 | daemon->digest_auth_rand_size, | 1549 | daemon->digest_auth_rand_size, |
1550 | connection->addr, | ||
1551 | (size_t) connection->addr_len, | ||
1491 | connection->rq.url, | 1552 | connection->rq.url, |
1492 | connection->rq.url_len, | 1553 | connection->rq.url_len, |
1493 | connection->rq.headers_received, | 1554 | connection->rq.headers_received, |
1494 | realm, | 1555 | realm, |
1495 | realm_len, | 1556 | realm_len, |
1557 | daemon->dauth_bind_type, | ||
1496 | da, | 1558 | da, |
1497 | nonce); | 1559 | nonce); |
1498 | 1560 | ||
@@ -1532,8 +1594,9 @@ calculate_add_nonce (struct MHD_Connection *const connection, | |||
1532 | * @param connection the MHD connection structure | 1594 | * @param connection the MHD connection structure |
1533 | * @param realm A string of characters that describes the realm of auth. | 1595 | * @param realm A string of characters that describes the realm of auth. |
1534 | * @param da digest algorithm to use | 1596 | * @param da digest algorithm to use |
1535 | * @param[out] nonce A pointer to a character array for the nonce to put in, | 1597 | * @param[out] nonce the pointer to a character array for the nonce to put in, |
1536 | * must provide NONCE_STD_LEN(digest_get_size(da))+1 bytes | 1598 | * must provide NONCE_STD_LEN(digest_get_size(da)) bytes, |
1599 | * result is NOT zero-terminated | ||
1537 | */ | 1600 | */ |
1538 | static bool | 1601 | static bool |
1539 | calculate_add_nonce_with_retry (struct MHD_Connection *const connection, | 1602 | calculate_add_nonce_with_retry (struct MHD_Connection *const connection, |
@@ -2213,7 +2276,7 @@ digest_auth_check_all_inner (struct MHD_Connection *connection, | |||
2213 | digest_update_with_colon (&da); | 2276 | digest_update_with_colon (&da); |
2214 | digest_update (&da, realm, realm_len); | 2277 | digest_update (&da, realm, realm_len); |
2215 | digest_calc_hash (&da, hash1_bin); | 2278 | digest_calc_hash (&da, hash1_bin); |
2216 | mhd_assert (sizeof (tmp1) >= (2 * digest_size + 1)); | 2279 | mhd_assert (sizeof (tmp1) >= (2 * digest_size)); |
2217 | MHD_bin_to_hex (hash1_bin, digest_size, tmp1); | 2280 | MHD_bin_to_hex (hash1_bin, digest_size, tmp1); |
2218 | if (! is_param_equal_caseless (¶ms->username, tmp1, 2 * digest_size)) | 2281 | if (! is_param_equal_caseless (¶ms->username, tmp1, 2 * digest_size)) |
2219 | return MHD_DAUTH_WRONG_USERNAME; | 2282 | return MHD_DAUTH_WRONG_USERNAME; |
@@ -2368,7 +2431,7 @@ digest_auth_check_all_inner (struct MHD_Connection *connection, | |||
2368 | 2431 | ||
2369 | digest_init (&da); | 2432 | digest_init (&da); |
2370 | /* Update digest with H(A1) */ | 2433 | /* Update digest with H(A1) */ |
2371 | mhd_assert (sizeof (tmp1) >= (digest_size * 2 + 1)); | 2434 | mhd_assert (sizeof (tmp1) >= (digest_size * 2)); |
2372 | if (NULL == userdigest) | 2435 | if (NULL == userdigest) |
2373 | MHD_bin_to_hex (hash1_bin, digest_size, tmp1); | 2436 | MHD_bin_to_hex (hash1_bin, digest_size, tmp1); |
2374 | else | 2437 | else |
@@ -2432,25 +2495,33 @@ digest_auth_check_all_inner (struct MHD_Connection *connection, | |||
2432 | if (0 != memcmp (hash1_bin, hash2_bin, digest_size)) | 2495 | if (0 != memcmp (hash1_bin, hash2_bin, digest_size)) |
2433 | return MHD_DAUTH_RESPONSE_WRONG; | 2496 | return MHD_DAUTH_RESPONSE_WRONG; |
2434 | 2497 | ||
2435 | mhd_assert (sizeof(tmp1) >= (NONCE_STD_LEN (digest_size) + 1)); | 2498 | if (MHD_DAUTH_BIND_NONCE_NONE != daemon->dauth_bind_type) |
2436 | /* It was already checked that 'nonce' (including timestamp) was generated | 2499 | { |
2437 | by MHD. The next check is mostly an overcaution. */ | 2500 | mhd_assert (sizeof(tmp1) >= (NONCE_STD_LEN (digest_size) + 1)); |
2438 | calculate_nonce (nonce_time, | 2501 | /* It was already checked that 'nonce' (including timestamp) was generated |
2439 | connection->rq.method, | 2502 | by MHD. */ |
2440 | daemon->digest_auth_random, | 2503 | calculate_nonce (nonce_time, |
2441 | daemon->digest_auth_rand_size, | 2504 | connection->rq.http_mthd, |
2442 | connection->rq.url, | 2505 | connection->rq.method, |
2443 | connection->rq.url_len, | 2506 | daemon->digest_auth_random, |
2444 | connection->rq.headers_received, | 2507 | daemon->digest_auth_rand_size, |
2445 | realm, | 2508 | connection->addr, |
2446 | realm_len, | 2509 | (size_t) connection->addr_len, |
2447 | &da, | 2510 | connection->rq.url, |
2448 | tmp1); | 2511 | connection->rq.url_len, |
2449 | 2512 | connection->rq.headers_received, | |
2450 | if (! is_param_equal (¶ms->nonce, tmp1, | 2513 | realm, |
2451 | NONCE_STD_LEN (digest_size))) | 2514 | realm_len, |
2452 | return MHD_DAUTH_NONCE_WRONG; | 2515 | daemon->dauth_bind_type, |
2453 | /* The 'nonce' was generated in the same conditions */ | 2516 | &da, |
2517 | tmp1); | ||
2518 | |||
2519 | |||
2520 | if (! is_param_equal (¶ms->nonce, tmp1, | ||
2521 | NONCE_STD_LEN (digest_size))) | ||
2522 | return MHD_DAUTH_NONCE_OTHER_COND; | ||
2523 | /* The 'nonce' was generated in the same conditions */ | ||
2524 | } | ||
2454 | 2525 | ||
2455 | return MHD_DAUTH_OK; | 2526 | return MHD_DAUTH_OK; |
2456 | } | 2527 | } |
@@ -2716,7 +2787,8 @@ MHD_digest_auth_check2 (struct MHD_Connection *connection, | |||
2716 | malgo3); | 2787 | malgo3); |
2717 | if (MHD_DAUTH_OK == res) | 2788 | if (MHD_DAUTH_OK == res) |
2718 | return MHD_YES; | 2789 | return MHD_YES; |
2719 | else if ((MHD_DAUTH_NONCE_STALE == res) || (MHD_DAUTH_NONCE_WRONG == res)) | 2790 | else if ((MHD_DAUTH_NONCE_STALE == res) || (MHD_DAUTH_NONCE_WRONG == res) || |
2791 | (MHD_DAUTH_NONCE_OTHER_COND == res) ) | ||
2720 | return MHD_INVALID_NONCE; | 2792 | return MHD_INVALID_NONCE; |
2721 | return MHD_NO; | 2793 | return MHD_NO; |
2722 | 2794 | ||
@@ -2773,7 +2845,8 @@ MHD_digest_auth_check_digest2 (struct MHD_Connection *connection, | |||
2773 | malgo3); | 2845 | malgo3); |
2774 | if (MHD_DAUTH_OK == res) | 2846 | if (MHD_DAUTH_OK == res) |
2775 | return MHD_YES; | 2847 | return MHD_YES; |
2776 | else if ((MHD_DAUTH_NONCE_STALE == res) || (MHD_DAUTH_NONCE_WRONG == res)) | 2848 | else if ((MHD_DAUTH_NONCE_STALE == res) || (MHD_DAUTH_NONCE_WRONG == res) || |
2849 | (MHD_DAUTH_NONCE_OTHER_COND == res) ) | ||
2777 | return MHD_INVALID_NONCE; | 2850 | return MHD_INVALID_NONCE; |
2778 | return MHD_NO; | 2851 | return MHD_NO; |
2779 | } | 2852 | } |
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h index 35620bff..3a81b2a2 100644 --- a/src/microhttpd/internal.h +++ b/src/microhttpd/internal.h | |||
@@ -2225,6 +2225,10 @@ struct MHD_Daemon | |||
2225 | */ | 2225 | */ |
2226 | unsigned int nonce_nc_size; | 2226 | unsigned int nonce_nc_size; |
2227 | 2227 | ||
2228 | /** | ||
2229 | * Nonce bind type. | ||
2230 | */ | ||
2231 | unsigned int dauth_bind_type; | ||
2228 | #endif | 2232 | #endif |
2229 | 2233 | ||
2230 | #ifdef TCP_FASTOPEN | 2234 | #ifdef TCP_FASTOPEN |
diff --git a/src/testcurl/test_digestauth2.c b/src/testcurl/test_digestauth2.c index 6054af7d..4c3af9bf 100644 --- a/src/testcurl/test_digestauth2.c +++ b/src/testcurl/test_digestauth2.c | |||
@@ -694,6 +694,10 @@ ahc_echo (void *cls, | |||
694 | mhdErrorExitDesc ("MHD_digest_auth_check[_digest]3()' returned " \ | 694 | mhdErrorExitDesc ("MHD_digest_auth_check[_digest]3()' returned " \ |
695 | "MHD_DAUTH_NONCE_WRONG"); | 695 | "MHD_DAUTH_NONCE_WRONG"); |
696 | break; | 696 | break; |
697 | case MHD_DAUTH_NONCE_OTHER_COND: | ||
698 | mhdErrorExitDesc ("MHD_digest_auth_check[_digest]3()' returned " \ | ||
699 | "MHD_DAUTH_NONCE_OTHER_COND"); | ||
700 | break; | ||
697 | case MHD_DAUTH_ERROR: | 701 | case MHD_DAUTH_ERROR: |
698 | externalErrorExitDesc ("General error returned " \ | 702 | externalErrorExitDesc ("General error returned " \ |
699 | "by 'MHD_digest_auth_check[_digest]3()'"); | 703 | "by 'MHD_digest_auth_check[_digest]3()'"); |