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 |