diff options
Diffstat (limited to 'src/microhttpd/digestauth.c')
-rw-r--r-- | src/microhttpd/digestauth.c | 475 |
1 files changed, 316 insertions, 159 deletions
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c index 5005bf2a..9cd9ac37 100644 --- a/src/microhttpd/digestauth.c +++ b/src/microhttpd/digestauth.c @@ -117,23 +117,48 @@ digest_calc_ha1 (const char *alg, unsigned char ha1[MD5_DIGEST_SIZE]; MD5Init (&md5); - MD5Update (&md5, (const unsigned char*)username, strlen (username)); - MD5Update (&md5, (const unsigned char*)":", 1); - MD5Update (&md5, (const unsigned char*)realm, strlen (realm)); - MD5Update (&md5, (const unsigned char*)":", 1); - MD5Update (&md5, (const unsigned char*)password, strlen (password)); - MD5Final (ha1, &md5); - if (MHD_str_equal_caseless_(alg, "md5-sess")) + MD5Update (&md5, + (const unsigned char *) username, + strlen (username)); + MD5Update (&md5, + (const unsigned char *) ":", + 1); + MD5Update (&md5, + (const unsigned char *) realm, + strlen (realm)); + MD5Update (&md5, + (const unsigned char *) ":", + 1); + MD5Update (&md5, + (const unsigned char *) password, + strlen (password)); + MD5Final (ha1, + &md5); + if (MHD_str_equal_caseless_(alg, + "md5-sess")) { MD5Init (&md5); - MD5Update (&md5, (const unsigned char*)ha1, sizeof (ha1)); - MD5Update (&md5, (const unsigned char*)":", 1); - MD5Update (&md5, (const unsigned char*)nonce, strlen (nonce)); - MD5Update (&md5, (const unsigned char*)":", 1); - MD5Update (&md5, (const unsigned char*)cnonce, strlen (cnonce)); - MD5Final (ha1, &md5); + MD5Update (&md5, + (const unsigned char *) ha1, + sizeof (ha1)); + MD5Update (&md5, + (const unsigned char *) ":", + 1); + MD5Update (&md5, + (const unsigned char *) nonce, + strlen (nonce)); + MD5Update (&md5, + (const unsigned char *) ":", + 1); + MD5Update (&md5, + (const unsigned char *) cnonce, + strlen (cnonce)); + MD5Final (ha1, + &md5); } - cvthex (ha1, sizeof (ha1), sessionkey); + cvthex (ha1, + sizeof (ha1), + sessionkey); } @@ -167,39 +192,78 @@ digest_calc_response (const char ha1[HASH_MD5_HEX_LEN + 1], char ha2hex[HASH_MD5_HEX_LEN + 1]; MD5Init (&md5); - MD5Update (&md5, (const unsigned char*)method, strlen(method)); - MD5Update (&md5, (const unsigned char*)":", 1); - MD5Update (&md5, (const unsigned char*)uri, strlen(uri)); + MD5Update (&md5, + (const unsigned char *) method, + strlen (method)); + MD5Update (&md5, + (const unsigned char *) ":", + 1); + MD5Update (&md5, + (const unsigned char *) uri, + strlen (uri)); #if 0 - if (0 == strcasecmp(qop, "auth-int")) + if (0 == strcasecmp(qop, + "auth-int")) { /* This is dead code since the rest of this module does not support auth-int. */ - MD5Update (&md5, ":", 1); + MD5Update (&md5, + ":", + 1); if (NULL != hentity) - MD5Update (&md5, hentity, strlen(hentity)); + MD5Update (&md5, + hentity, + strlen (hentity)); } #endif - MD5Final (ha2, &md5); - cvthex (ha2, MD5_DIGEST_SIZE, ha2hex); + MD5Final (ha2, + &md5); + cvthex (ha2, + MD5_DIGEST_SIZE, + ha2hex); MD5Init (&md5); /* calculate response */ - MD5Update (&md5, (const unsigned char*)ha1, HASH_MD5_HEX_LEN); - MD5Update (&md5, (const unsigned char*)":", 1); - MD5Update (&md5, (const unsigned char*)nonce, strlen(nonce)); - MD5Update (&md5, (const unsigned char*)":", 1); + MD5Update (&md5, + (const unsigned char *) ha1, + HASH_MD5_HEX_LEN); + MD5Update (&md5, + (const unsigned char *) ":", + 1); + MD5Update (&md5, + (const unsigned char *) nonce, + strlen (nonce)); + MD5Update (&md5, + (const unsigned char*) ":", + 1); if ('\0' != *qop) { - MD5Update (&md5, (const unsigned char*)noncecount, strlen(noncecount)); - MD5Update (&md5, (const unsigned char*)":", 1); - MD5Update (&md5, (const unsigned char*)cnonce, strlen(cnonce)); - MD5Update (&md5, (const unsigned char*)":", 1); - MD5Update (&md5, (const unsigned char*)qop, strlen(qop)); - MD5Update (&md5, (const unsigned char*)":", 1); + MD5Update (&md5, + (const unsigned char *) noncecount, + strlen (noncecount)); + MD5Update (&md5, + (const unsigned char *) ":", + 1); + MD5Update (&md5, + (const unsigned char *) cnonce, + strlen (cnonce)); + MD5Update (&md5, + (const unsigned char *) ":", + 1); + MD5Update (&md5, + (const unsigned char *) qop, + strlen (qop)); + MD5Update (&md5, + (const unsigned char *) ":", + 1); } - MD5Update (&md5, (const unsigned char*)ha2hex, HASH_MD5_HEX_LEN); - MD5Final (resphash, &md5); - cvthex (resphash, sizeof(resphash), response); + MD5Update (&md5, + (const unsigned char *) ha2hex, + HASH_MD5_HEX_LEN); + MD5Final (resphash, + &md5); + cvthex (resphash, + sizeof(resphash), + response); } @@ -237,27 +301,30 @@ lookup_sub_value (char *dest, ptr = data; while ('\0' != *ptr) { - if (NULL == (eq = strchr (ptr, '='))) + if (NULL == (eq = strchr (ptr, + '='))) return 0; q1 = eq + 1; while (' ' == *q1) q1++; if ('\"' != *q1) { - q2 = strchr (q1, ','); + q2 = strchr (q1, + ','); qn = q2; } else { q1++; - q2 = strchr (q1, '\"'); + q2 = strchr (q1, + '\"'); if (NULL == q2) return 0; /* end quote not found */ qn = q2 + 1; } - if ((MHD_str_equal_caseless_n_(ptr, - key, - keylen)) && + if ( (MHD_str_equal_caseless_n_(ptr, + key, + keylen)) && (eq == &ptr[keylen]) ) { if (NULL == q2) @@ -286,7 +353,8 @@ lookup_sub_value (char *dest, } if (NULL == qn) return 0; - ptr = strchr (qn, ','); + ptr = strchr (qn, + ','); if (NULL == ptr) return 0; ptr++; @@ -311,6 +379,8 @@ check_nonce_nc (struct MHD_Connection *connection, const char *nonce, uint64_t nc) { + struct MHD_Daemon *daemon = connection->daemon; + struct MHD_NonceNc *nn; uint32_t off; uint32_t mod; const char *np; @@ -320,7 +390,7 @@ check_nonce_nc (struct MHD_Connection *connection, tools have a hard time with it *and* this also protects against unsafe modifications that may happen in the future... */ - mod = connection->daemon->nonce_nc_size; + mod = daemon->nonce_nc_size; if (0 == mod) return MHD_NO; /* no array! */ /* super-fast xor-based "hash" function for HT lookup in nonce array */ @@ -337,28 +407,50 @@ check_nonce_nc (struct MHD_Connection *connection, * nonce counter is less than the current nonce counter by 1, * then only increase the nonce counter by one. */ - - (void) MHD_mutex_lock_ (&connection->daemon->nnc_lock); + nn = &daemon->nnc[off]; + (void) MHD_mutex_lock_ (&daemon->nnc_lock); if (0 == nc) { - strcpy (connection->daemon->nnc[off].nonce, + /* Fresh nonce, reinitialize array */ + strcpy (nn->nonce, nonce); - connection->daemon->nnc[off].nc = 0; - (void) MHD_mutex_unlock_ (&connection->daemon->nnc_lock); + nn->nc = 0; + nn->nmask = 0; + (void) MHD_mutex_unlock_ (&daemon->nnc_lock); return MHD_YES; } - if ( (nc <= connection->daemon->nnc[off].nc) || - (0 != strcmp(connection->daemon->nnc[off].nonce, nonce)) ) + /* Note that we use 64 here, as we do not store the + bit for 'nn->nc' itself in 'nn->nmask' */ + if ( (nc < nn->nc) && + (nc + 64 > nc /* checking for overflow */) && + (nc + 64 >= nn->nc) && + (0 == (1LLU < (nn->nc - nc - 1)) & nn->nmask) ) { - (void) MHD_mutex_unlock_ (&connection->daemon->nnc_lock); + /* Out-of-order nonce, but within 64-bit bitmask, set bit */ + nn->nmask |= (1LLU < (nn->nc - nc - 1)); + (void) MHD_mutex_unlock_ (&daemon->nnc_lock); + return MHD_YES; + } + + if ( (nc <= nn->nc) || + (0 != strcmp (nn->nonce, + nonce)) ) + { + /* Nonce does not match, fail */ + (void) MHD_mutex_unlock_ (&daemon->nnc_lock); #ifdef HAVE_MESSAGES - MHD_DLOG (connection->daemon, - "Stale nonce received. If this happens a lot, you should probably increase the size of the nonce array.\n"); + MHD_DLOG (daemon, + _("Stale nonce received. If this happens a lot, you should probably increase the size of the nonce array.\n")); #endif return MHD_NO; } - connection->daemon->nnc[off].nc = nc; - (void) MHD_mutex_unlock_ (&connection->daemon->nnc_lock); + /* Nonce is larger, shift bitmask and bump limit */ + if (64 > nc - nn->nc) + nn->nmask <<= (nc - nn->nc); /* small jump, less than mask width */ + else + nn->nmask = 0; /* big jump, unset all bits in the mask */ + nn->nc = nc; + (void) MHD_mutex_unlock_ (&daemon->nnc_lock); return MHD_YES; } @@ -378,11 +470,14 @@ MHD_digest_auth_get_username(struct MHD_Connection *connection) char user[MAX_USERNAME_LENGTH]; const char *header; - if (NULL == (header = MHD_lookup_connection_value (connection, - MHD_HEADER_KIND, - MHD_HTTP_HEADER_AUTHORIZATION))) + if (NULL == (header = + MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, + MHD_HTTP_HEADER_AUTHORIZATION))) return NULL; - if (0 != strncmp (header, _BASE, strlen (_BASE))) + if (0 != strncmp (header, + _BASE, + strlen (_BASE))) return NULL; header += strlen (_BASE); if (0 == (len = lookup_sub_value (user, @@ -426,20 +521,45 @@ calculate_nonce (uint32_t nonce_time, timestamp[1] = (unsigned char)((nonce_time & 0x00ff0000) >> 0x10); timestamp[2] = (unsigned char)((nonce_time & 0x0000ff00) >> 0x08); timestamp[3] = (unsigned char)((nonce_time & 0x000000ff)); - MD5Update (&md5, timestamp, sizeof(timestamp)); - MD5Update (&md5, (const unsigned char*)":", 1); - MD5Update (&md5, (const unsigned char*)method, strlen (method)); - MD5Update (&md5, (const unsigned char*)":", 1); + MD5Update (&md5, + timestamp, + sizeof (timestamp)); + MD5Update (&md5, + (const unsigned char *) ":", + 1); + MD5Update (&md5, + (const unsigned char *) method, + strlen (method)); + MD5Update (&md5, + (const unsigned char *) ":", + 1); if (rnd_size > 0) - MD5Update (&md5, (const unsigned char*)rnd, rnd_size); - MD5Update (&md5, (const unsigned char*)":", 1); - MD5Update (&md5, (const unsigned char*)uri, strlen (uri)); - MD5Update (&md5, (const unsigned char*)":", 1); - MD5Update (&md5, (const unsigned char*)realm, strlen (realm)); - MD5Final (tmpnonce, &md5); - cvthex (tmpnonce, sizeof (tmpnonce), nonce); - cvthex (timestamp, sizeof(timestamp), timestamphex); - strncat (nonce, timestamphex, 8); + MD5Update (&md5, + (const unsigned char *) rnd, + rnd_size); + MD5Update (&md5, + (const unsigned char *) ":", + 1); + MD5Update (&md5, + (const unsigned char *) uri, + strlen (uri)); + MD5Update (&md5, + (const unsigned char *) ":", + 1); + MD5Update (&md5, + (const unsigned char *) realm, + strlen (realm)); + MD5Final (tmpnonce, + &md5); + cvthex (tmpnonce, + sizeof (tmpnonce), + nonce); + cvthex (timestamp, + sizeof (timestamp), + timestamphex); + strncat (nonce, + timestamphex, + 8); } @@ -466,14 +586,16 @@ test_header (struct MHD_Connection *connection, { if (kind != pos->kind) continue; - if (0 != strcmp (key, pos->header)) + if (0 != strcmp (key, + pos->header)) continue; if ( (NULL == value) && (NULL == pos->value) ) return MHD_YES; if ( (NULL == value) || (NULL == pos->value) || - (0 != strcmp (value, pos->value)) ) + (0 != strcmp (value, + pos->value)) ) continue; return MHD_YES; } @@ -505,7 +627,7 @@ check_argument_match (struct MHD_Connection *connection, { #ifdef HAVE_MESSAGES MHD_DLOG (connection->daemon, - "Failed to allocate memory for copy of URI arguments\n"); + _("Failed to allocate memory for copy of URI arguments\n")); #endif /* HAVE_MESSAGES */ return MHD_NO; } @@ -553,6 +675,7 @@ MHD_digest_auth_check (struct MHD_Connection *connection, const char *password, unsigned int nonce_timeout) { + struct MHD_Daemon *daemon = connection->daemon; size_t len; const char *header; char nonce[MAX_NONCE_LENGTH]; @@ -574,7 +697,9 @@ MHD_digest_auth_check (struct MHD_Connection *connection, MHD_HTTP_HEADER_AUTHORIZATION); if (NULL == header) return MHD_NO; - if (0 != strncmp(header, _BASE, strlen(_BASE))) + if (0 != strncmp (header, + _BASE, + strlen(_BASE))) return MHD_NO; header += strlen (_BASE); left = strlen (header); @@ -584,9 +709,11 @@ MHD_digest_auth_check (struct MHD_Connection *connection, len = lookup_sub_value (un, sizeof (un), - header, "username"); + header, + "username"); if ( (0 == len) || - (0 != strcmp(username, un)) ) + (0 != strcmp (username, + un)) ) return MHD_NO; left -= strlen ("username") + len; } @@ -596,16 +723,19 @@ MHD_digest_auth_check (struct MHD_Connection *connection, len = lookup_sub_value (r, sizeof (r), - header, "realm"); + header, + "realm"); if ( (0 == len) || - (0 != strcmp(realm, r)) ) + (0 != strcmp (realm, + r)) ) return MHD_NO; left -= strlen ("realm") + len; } if (0 == (len = lookup_sub_value (nonce, sizeof (nonce), - header, "nonce"))) + header, + "nonce"))) return MHD_NO; left -= strlen ("nonce") + len; if (left > 32 * 1024) @@ -619,12 +749,14 @@ MHD_digest_auth_check (struct MHD_Connection *connection, header value. */ return MHD_NO; } - if (TIMESTAMP_HEX_LEN != MHD_strx_to_uint32_n_ (nonce + len - TIMESTAMP_HEX_LEN, - TIMESTAMP_HEX_LEN, &nonce_time)) + if (TIMESTAMP_HEX_LEN != + MHD_strx_to_uint32_n_ (nonce + len - TIMESTAMP_HEX_LEN, + TIMESTAMP_HEX_LEN, + &nonce_time)) { #ifdef HAVE_MESSAGES - MHD_DLOG (connection->daemon, - "Authentication failed, invalid timestamp format.\n"); + MHD_DLOG (daemon, + _("Authentication failed, invalid timestamp format.\n")); #endif return MHD_NO; } @@ -643,8 +775,8 @@ MHD_digest_auth_check (struct MHD_Connection *connection, calculate_nonce (nonce_time, connection->method, - connection->daemon->digest_auth_random, - connection->daemon->digest_auth_rand_size, + daemon->digest_auth_random, + daemon->digest_auth_rand_size, connection->url, realm, noncehashexp); @@ -664,34 +796,51 @@ MHD_digest_auth_check (struct MHD_Connection *connection, } if ( (0 == lookup_sub_value (cnonce, sizeof (cnonce), - header, "cnonce")) || - (0 == lookup_sub_value (qop, sizeof (qop), header, "qop")) || - ( (0 != strcmp (qop, "auth")) && - (0 != strcmp (qop, "")) ) || - (0 == (len = lookup_sub_value (nc, sizeof (nc), header, "nc")) ) || - (0 == lookup_sub_value (response, sizeof (response), header, "response")) ) + header, + "cnonce")) || + (0 == lookup_sub_value (qop, + sizeof (qop), + header, + "qop")) || + ( (0 != strcmp (qop, + "auth")) && + (0 != strcmp (qop, + "")) ) || + (0 == (len = lookup_sub_value (nc, + sizeof (nc), + header, + "nc")) ) || + (0 == lookup_sub_value (response, + sizeof (response), + header, + "response")) ) { #ifdef HAVE_MESSAGES - MHD_DLOG (connection->daemon, - "Authentication failed, invalid format.\n"); + MHD_DLOG (daemon, + _("Authentication failed, invalid format.\n")); #endif return MHD_NO; } - if (len != MHD_strx_to_uint64_n_ (nc, len, &nci)) + if (len != MHD_strx_to_uint64_n_ (nc, + len, + &nci)) { #ifdef HAVE_MESSAGES - MHD_DLOG (connection->daemon, - "Authentication failed, invalid nc format.\n"); + MHD_DLOG (daemon, + _("Authentication failed, invalid nc format.\n")); #endif return MHD_NO; /* invalid nonce format */ } + /* * Checking if that combination of nonce and nc is sound * and not a replay attack attempt. Also adds the nonce * to the nonce-nc map if it does not exist there. */ - - if (MHD_YES != check_nonce_nc (connection, nonce, nci)) + if (MHD_YES != + check_nonce_nc (connection, + nonce, + nci)) { return MHD_NO; } @@ -703,26 +852,27 @@ MHD_digest_auth_check (struct MHD_Connection *connection, if (NULL == uri) { #ifdef HAVE_MESSAGES - MHD_DLOG(connection->daemon, - "Failed to allocate memory for auth header processing\n"); + MHD_DLOG(daemon, + _("Failed to allocate memory for auth header processing\n")); #endif /* HAVE_MESSAGES */ return MHD_NO; } if (0 == lookup_sub_value (uri, left + 1, - header, "uri")) + header, + "uri")) { free (uri); return MHD_NO; } - digest_calc_ha1("md5", - username, - realm, - password, - nonce, - cnonce, - ha1); + digest_calc_ha1 ("md5", + username, + realm, + password, + nonce, + cnonce, + ha1); digest_calc_response (ha1, nonce, nc, @@ -734,23 +884,24 @@ MHD_digest_auth_check (struct MHD_Connection *connection, respexp); /* Need to unescape URI before comparing with connection->url */ - connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, - connection, - uri); + daemon->unescape_callback (daemon->unescape_callback_cls, + connection, + uri); if (0 != strncmp (uri, connection->url, strlen (connection->url))) { #ifdef HAVE_MESSAGES - MHD_DLOG (connection->daemon, - "Authentication failed, URI does not match.\n"); + MHD_DLOG (daemon, + _("Authentication failed, URI does not match.\n")); #endif free (uri); return MHD_NO; } { - const char *args = strchr (uri, '?'); + const char *args = strchr (uri, + '?'); if (NULL == args) args = ""; @@ -761,15 +912,16 @@ MHD_digest_auth_check (struct MHD_Connection *connection, args) ) { #ifdef HAVE_MESSAGES - MHD_DLOG (connection->daemon, - "Authentication failed, arguments do not match.\n"); + MHD_DLOG (daemon, + _("Authentication failed, arguments do not match.\n")); #endif free (uri); return MHD_NO; } } free (uri); - return (0 == strcmp(response, respexp)) + return (0 == strcmp(response, + respexp)) ? MHD_YES : MHD_NO; } @@ -809,66 +961,71 @@ MHD_queue_auth_fail_response (struct MHD_Connection *connection, connection->url, realm, nonce); - if (MHD_YES != check_nonce_nc (connection, nonce, 0)) + if (MHD_YES != + check_nonce_nc (connection, + nonce, + 0)) { #ifdef HAVE_MESSAGES MHD_DLOG (connection->daemon, - "Could not register nonce (is the nonce array size zero?).\n"); + _("Could not register nonce (is the nonce array size zero?).\n")); #endif return MHD_NO; } /* Building the authentication header */ - hlen = MHD_snprintf_(NULL, - 0, - "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s", - realm, - nonce, - opaque, - signal_stale - ? ",stale=\"true\"" - : ""); + hlen = MHD_snprintf_ (NULL, + 0, + "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s", + realm, + nonce, + opaque, + signal_stale + ? ",stale=\"true\"" + : ""); if (hlen > 0) - { - char *header; - - header = malloc(hlen + 1); - if (NULL == header) { + char *header; + + header = malloc (hlen + 1); + if (NULL == header) + { #ifdef HAVE_MESSAGES - MHD_DLOG(connection->daemon, - "Failed to allocate memory for auth response header\n"); + MHD_DLOG(connection->daemon, + _("Failed to allocate memory for auth response header\n")); #endif /* HAVE_MESSAGES */ - return MHD_NO; - } + return MHD_NO; + } - if (MHD_snprintf_(header, - hlen + 1, - "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s", - realm, - nonce, - opaque, - signal_stale - ? ",stale=\"true\"" - : "") == hlen) - ret = MHD_add_response_header(response, - MHD_HTTP_HEADER_WWW_AUTHENTICATE, - header); - else - ret = MHD_NO; - free(header); - } + if (MHD_snprintf_ (header, + hlen + 1, + "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s", + realm, + nonce, + opaque, + signal_stale + ? ",stale=\"true\"" + : "") == hlen) + ret = MHD_add_response_header(response, + MHD_HTTP_HEADER_WWW_AUTHENTICATE, + header); + else + ret = MHD_NO; + free (header); + } else ret = MHD_NO; if (MHD_YES == ret) - ret = MHD_queue_response(connection, - MHD_HTTP_UNAUTHORIZED, - response); + { + ret = MHD_queue_response (connection, + MHD_HTTP_UNAUTHORIZED, + response); + } else { #ifdef HAVE_MESSAGES MHD_DLOG (connection->daemon, - "Failed to add Digest auth header\n"); + _("Failed to add Digest auth header\n")); #endif /* HAVE_MESSAGES */ } return ret; |