aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2022-08-14 14:10:03 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2022-08-15 16:21:45 +0300
commit2f8eefada8be541c82c7fb4ed9bca7e88e720cd8 (patch)
tree5fabda78dfe6ef9448c2a10195a0edf023d45d04
parent25863e1c897b63eb56d248fde9634d0477ca8830 (diff)
downloadlibmicrohttpd-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.h93
-rw-r--r--src/microhttpd/daemon.c7
-rw-r--r--src/microhttpd/digestauth.c217
-rw-r--r--src/microhttpd/internal.h4
-rw-r--r--src/testcurl/test_digestauth2.c4
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 */
1553enum 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 */
4911enum MHD_DigestAuthResult 4984enum 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 */
1327static void 1336static void
1328calculate_nonce (uint64_t nonce_time, 1337calculate_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 */
1538static bool 1601static bool
1539calculate_add_nonce_with_retry (struct MHD_Connection *const connection, 1602calculate_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 (&params->username, tmp1, 2 * digest_size)) 2281 if (! is_param_equal_caseless (&params->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 (&params->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 (&params->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()'");