diff options
Diffstat (limited to 'src/microhttpd/digestauth.c')
-rw-r--r-- | src/microhttpd/digestauth.c | 217 |
1 files changed, 145 insertions, 72 deletions
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 | } |