View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0005397 | libmicrohttpd | digest authentication (HTTP) | public | 2018-07-07 15:44 | 2018-11-06 19:46 |
Reporter | Dirk Brinkmeier | Assigned To | Christian Grothoff | ||
Priority | normal | Severity | tweak | Reproducibility | N/A |
Status | closed | Resolution | fixed | ||
Product Version | 0.9.59 | ||||
Target Version | 0.9.60 | Fixed in Version | 0.9.60 | ||
Summary | 0005397: Patch for digest authentication from user database with precalculated 'username:realm:password' hash | ||||
Description | I'm using a a user database for digest authentication. To avoid using clear text password storage, I precalculate the 'username:realm:password' MD5 hash and store the hash value in the database. To be able to use digest authentication with libmicrohttpd, I modified/duplicated the given function MHD_digest_auth_check(...) and extend this one to MHD_digest_auth_check_digest(...). I attached a patch for that purpose. I hope you can use the patch, if you think that this is a useful extension... Regards, Dirk. | ||||
Tags | No tags attached. | ||||
Attached Files | digestauth_by_hash.diff (9,039 bytes)
diff -ur ./libmicrohttpd-0.9.59_org/libmicrohttpd-0.9.59/src/include/microhttpd.h ./libmicrohttpd-0.9.59_new/libmicrohttpd-0.9.59/src/include/microhttpd.h --- ./libmicrohttpd-0.9.59_org/libmicrohttpd-0.9.59/src/include/microhttpd.h 2018-02-01 20:12:55.000000000 +0100 +++ ./libmicrohttpd-0.9.59_new/libmicrohttpd-0.9.59/src/include/microhttpd.h 2018-07-07 11:15:15.994086680 +0200 @@ -292,6 +292,9 @@ _MHD_DEPR_MACRO("Macro MHD_LONG_LONG_PRINTF is deprecated, use MHD_UNSIGNED_LONG_LONG_PRINTF") #endif +#ifndef MD5_DIGEST_SIZE +#define MD5_DIGEST_SIZE 16 +#endif /** * @defgroup httpcode HTTP response codes. @@ -3140,10 +3143,32 @@ */ _MHD_EXTERN int MHD_digest_auth_check (struct MHD_Connection *connection, - const char *realm, - const char *username, - const char *password, - unsigned int nonce_timeout); + const char *realm, + const char *username, + const char *password, + unsigned int nonce_timeout); + +/** + * Authenticates the authorization header sent by the client + * + * @param connection The MHD connection structure + * @param realm The realm presented to the client + * @param username The username needs to be authenticated + * @param digest An `unsigned char *' pointer to the binary MD5 sum + * for the precalculated hash value "username:realm:password" + * of MD5_DIGEST_SIZE bytes + * @param nonce_timeout The amount of time for a nonce to be + * invalid in seconds + * @return #MHD_YES if authenticated, #MHD_NO if not, + * #MHD_INVALID_NONCE if nonce is invalid + * @ingroup authentication + */ +_MHD_EXTERN int +MHD_digest_auth_check_digest (struct MHD_Connection *connection, + const char *realm, + const char *username, + const unsigned char digest[MD5_DIGEST_SIZE], + unsigned int nonce_timeout); /** diff -ur ./libmicrohttpd-0.9.59_org/libmicrohttpd-0.9.59/src/microhttpd/digestauth.c ./libmicrohttpd-0.9.59_new/libmicrohttpd-0.9.59/src/microhttpd/digestauth.c --- ./libmicrohttpd-0.9.59_org/libmicrohttpd-0.9.59/src/microhttpd/digestauth.c 2018-02-01 20:12:55.000000000 +0100 +++ ./libmicrohttpd-0.9.59_new/libmicrohttpd-0.9.59/src/microhttpd/digestauth.c 2018-07-07 11:16:41.251463205 +0200 @@ -93,8 +93,62 @@ /** - * calculate H(A1) as per RFC2617 spec and store the - * result in 'sessionkey'. + * calculate H(A1) from given hash as per RFC2617 spec + * and store the * result in 'sessionkey'. + * + * @param alg The hash algorithm used, can be "md5" or "md5-sess" + * @param digest An `unsigned char *' pointer to the binary MD5 sum + * for the precalculated hash value "username:realm:password" + * of MD5_DIGEST_SIZE bytes + * @param nonce A `char *' pointer to the nonce value + * @param cnonce A `char *' pointer to the cnonce value + * @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes + */ +static void +digest_calc_ha1_from_digest (const char *alg, + const unsigned char digest[MD5_DIGEST_SIZE], + const char *nonce, + const char *cnonce, + char sessionkey[HASH_MD5_HEX_LEN + 1]) +{ + struct MD5Context md5; + if (MHD_str_equal_caseless_(alg, + "md5-sess")) + { + unsigned char ha1[MD5_DIGEST_SIZE]; + MD5Init (&md5); + MD5Update (&md5, + (const unsigned char *) digest, + MD5_DIGEST_SIZE); + 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); + } + else + { + cvthex (digest, + MD5_DIGEST_SIZE, + sessionkey); + } +} + +/** + * calculate H(A1) from username, realm and password as per RFC2617 spec + * and store the result in 'sessionkey'. * * @param alg The hash algorithm used, can be "md5" or "md5-sess" * @param username A `char *' pointer to the username value @@ -105,7 +159,7 @@ * @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes */ static void -digest_calc_ha1 (const char *alg, +digest_calc_ha1_from_user (const char *alg, const char *username, const char *realm, const char *password, @@ -134,31 +188,7 @@ 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); - } - cvthex (ha1, - sizeof (ha1), - sessionkey); + digest_calc_ha1_from_digest(alg, ha1, nonce, cnonce, sessionkey); } @@ -664,6 +694,9 @@ * @param realm The realm presented to the client * @param username The username needs to be authenticated * @param password The password used in the authentication + * @param digest An optional `unsigned char *' pointer to the binary MD5 sum + * for the precalculated hash value "username:realm:password" + * of MD5_DIGEST_SIZE bytes * @param nonce_timeout The amount of time for a nonce to be * invalid in seconds * @return #MHD_YES if authenticated, #MHD_NO if not, @@ -671,10 +704,11 @@ * @ingroup authentication */ int -MHD_digest_auth_check (struct MHD_Connection *connection, +MHD_digest_auth_check_all (struct MHD_Connection *connection, const char *realm, const char *username, const char *password, + const unsigned char digest[MD5_DIGEST_SIZE], unsigned int nonce_timeout) { struct MHD_Daemon *daemon = connection->daemon; @@ -868,13 +902,21 @@ return MHD_NO; } - digest_calc_ha1 ("md5", - username, - realm, - password, - nonce, - cnonce, - ha1); + if (digest) { + digest_calc_ha1_from_digest ("md5", + digest, + nonce, + cnonce, + ha1); + } else { + digest_calc_ha1_from_user ("md5", + username, + realm, + password, + nonce, + cnonce, + ha1); + } digest_calc_response (ha1, nonce, nc, @@ -885,6 +927,7 @@ hentity, respexp); + /* Need to unescape URI before comparing with connection->url */ daemon->unescape_callback (daemon->unescape_callback_cls, connection, @@ -929,6 +972,62 @@ } } +/** + * Authenticates the authorization header sent by the client + * + * @param connection The MHD connection structure + * @param realm The realm presented to the client + * @param username The username needs to be authenticated + * @param password The password used in the authentication + * @param nonce_timeout The amount of time for a nonce to be + * invalid in seconds + * @return #MHD_YES if authenticated, #MHD_NO if not, + * #MHD_INVALID_NONCE if nonce is invalid + * @ingroup authentication + */ +_MHD_EXTERN int +MHD_digest_auth_check (struct MHD_Connection *connection, + const char *realm, + const char *username, + const char *password, + unsigned int nonce_timeout) +{ + return MHD_digest_auth_check_all( + connection, + realm, username, password, + NULL, + nonce_timeout); +} + +/** + * Authenticates the authorization header sent by the client + * + * @param connection The MHD connection structure + * @param realm The realm presented to the client + * @param username The username needs to be authenticated + * @param digest An `unsigned char *' pointer to the binary MD5 sum + * for the precalculated hash value "username:realm:password" + * of MD5_DIGEST_SIZE bytes + * @param nonce_timeout The amount of time for a nonce to be + * invalid in seconds + * @return #MHD_YES if authenticated, #MHD_NO if not, + * #MHD_INVALID_NONCE if nonce is invalid + * @ingroup authentication + */ +_MHD_EXTERN int +MHD_digest_auth_check_digest (struct MHD_Connection *connection, + const char *realm, + const char *username, + const unsigned char digest[MD5_DIGEST_SIZE], + unsigned int nonce_timeout) +{ + return MHD_digest_auth_check_all( + connection, + realm, username, NULL, + digest, + nonce_timeout); +} + /** * Queues a response to request authentication from the client | ||||
Date Modified | Username | Field | Change |
---|---|---|---|
2018-07-07 15:44 | Dirk Brinkmeier | New Issue | |
2018-07-07 15:44 | Dirk Brinkmeier | File Added: digestauth_by_hash.diff | |
2018-07-14 13:23 | Christian Grothoff | Assigned To | => Christian Grothoff |
2018-07-14 13:23 | Christian Grothoff | Status | new => assigned |
2018-07-14 13:24 | Christian Grothoff | Status | assigned => resolved |
2018-07-14 13:24 | Christian Grothoff | Resolution | open => fixed |
2018-07-14 13:24 | Christian Grothoff | Fixed in Version | => 0.9.60 |
2018-07-14 13:24 | Christian Grothoff | Note Added: 0013143 | |
2018-07-14 13:24 | Christian Grothoff | Target Version | => 0.9.60 |
2018-11-06 19:46 | Christian Grothoff | Status | resolved => closed |