add support for digest auth with hashed password

This commit is contained in:
Christian Grothoff
2018-07-14 13:27:45 +02:00
parent 2ade9eaad8
commit 2ed04522e2
4 changed files with 215 additions and 54 deletions
+5
View File
@@ -1,3 +1,8 @@
Sat Jul 14 11:03:37 CEST 2018
Integrate patch for checking digest authentication based on
a digest, allowing servers to store passwords only hashed.
Adding new function MHD_digest_auth_check_digest(). -CG/FIXME: ack co-author!
Sat Mar 10 12:15:35 CET 2018
Upgrade to gettext-0.19.8.1. Switching to more canonical
gettext integration. -CG
+15
View File
@@ -2393,6 +2393,21 @@ most probably it will be the result of a lookup of the username against a local
Most of the time it is sound to specify 300 seconds as its values.
@end deftypefun
@deftypefun int MHD_digest_auth_check_digest (struct MHD_Connection *connection, const char *realm, const char *username, const unsigned char digest[MHD_MD5_DIGEST_SIZE], unsigned int nonce_timeout)
Checks if the provided values in the WWW-Authenticate header are valid
and sound according to RFC2716. If valid return @code{MHD_YES}, otherwise return @code{MHD_NO}.
@var{realm} must reference to a zero-terminated string representing the realm.
@var{username} must reference to a zero-terminated string representing the username,
it is usually the returned value from MHD_digest_auth_get_username.
@var{digest} pointer to the binary MD5 sum for the precalculated hash value ``userame:realm:password'' of @code{MHD_MD5_DIGEST_SIZE} bytes.
@var{nonce_timeout} is the amount of time in seconds for a nonce to be invalid.
Most of the time it is sound to specify 300 seconds as its values.
@end deftypefun
@deftypefun int MHD_queue_auth_fail_response (struct MHD_Connection *connection, const char *realm, const char *opaque, struct MHD_Response *response, int signal_stale)
Queues a response to request authentication from the client,
return @code{MHD_YES} if successful, otherwise @code{MHD_NO}.
+32 -4
View File
@@ -293,6 +293,12 @@ _MHD_DEPR_MACRO("Macro MHD_LONG_LONG_PRINTF is deprecated, use MHD_UNSIGNED_LONG
#endif
/**
* Length of the binary output of the MD5 hash function.
*/
#define MHD_MD5_DIGEST_SIZE 16
/**
* @defgroup httpcode HTTP response codes.
* These are the status codes defined for HTTP responses.
@@ -3144,10 +3150,32 @@ MHD_free (void *ptr);
*/
_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 #MHD_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 uint8_t digest[MHD_MD5_DIGEST_SIZE],
unsigned int nonce_timeout);
/**
+163 -50
View File
@@ -1,6 +1,6 @@
/*
This file is part of libmicrohttpd
Copyright (C) 2010, 2011, 2012, 2015 Daniel Pittman and Christian Grothoff
Copyright (C) 2010, 2011, 2012, 2015, 2018 Daniel Pittman and Christian Grothoff
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -37,7 +37,7 @@
#include <windows.h>
#endif /* MHD_W32_MUTEX_ */
#define HASH_MD5_HEX_LEN (2 * MD5_DIGEST_SIZE)
#define HASH_MD5_HEX_LEN (2 * MHD_MD5_DIGEST_SIZE)
/* 32 bit value is 4 bytes */
#define TIMESTAMP_BIN_SIZE 4
#define TIMESTAMP_HEX_LEN (2 * TIMESTAMP_BIN_SIZE)
@@ -93,8 +93,65 @@ cvthex (const unsigned char *bin,
/**
* 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 #MHD_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 uint8_t digest[MHD_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[MHD_MD5_DIGEST_SIZE];
MD5Init (&md5);
MD5Update (&md5,
digest,
MHD_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,
MHD_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,16 +162,16 @@ cvthex (const unsigned char *bin,
* @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes
*/
static void
digest_calc_ha1 (const char *alg,
const char *username,
const char *realm,
const char *password,
const char *nonce,
const char *cnonce,
char sessionkey[HASH_MD5_HEX_LEN + 1])
digest_calc_ha1_from_user (const char *alg,
const char *username,
const char *realm,
const char *password,
const char *nonce,
const char *cnonce,
char sessionkey[HASH_MD5_HEX_LEN + 1])
{
struct MD5Context md5;
unsigned char ha1[MD5_DIGEST_SIZE];
unsigned char ha1[MHD_MD5_DIGEST_SIZE];
MD5Init (&md5);
MD5Update (&md5,
@@ -134,31 +191,11 @@ digest_calc_ha1 (const char *alg,
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);
}
@@ -187,8 +224,8 @@ digest_calc_response (const char ha1[HASH_MD5_HEX_LEN + 1],
char response[HASH_MD5_HEX_LEN + 1])
{
struct MD5Context md5;
unsigned char ha2[MD5_DIGEST_SIZE];
unsigned char resphash[MD5_DIGEST_SIZE];
unsigned char ha2[MHD_MD5_DIGEST_SIZE];
unsigned char resphash[MHD_MD5_DIGEST_SIZE];
char ha2hex[HASH_MD5_HEX_LEN + 1];
(void)hentity; /* Unused. Silent compiler warning. */
@@ -220,7 +257,7 @@ digest_calc_response (const char ha1[HASH_MD5_HEX_LEN + 1],
MD5Final (ha2,
&md5);
cvthex (ha2,
MD5_DIGEST_SIZE,
MHD_MD5_DIGEST_SIZE,
ha2hex);
MD5Init (&md5);
/* calculate response */
@@ -518,7 +555,7 @@ calculate_nonce (uint32_t nonce_time,
{
struct MD5Context md5;
unsigned char timestamp[TIMESTAMP_BIN_SIZE];
unsigned char tmpnonce[MD5_DIGEST_SIZE];
unsigned char tmpnonce[MHD_MD5_DIGEST_SIZE];
char timestamphex[TIMESTAMP_HEX_LEN + 1];
MD5Init (&md5);
@@ -667,17 +704,21 @@ check_argument_match (struct MHD_Connection *connection,
* @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 #MHD_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
*/
int
MHD_digest_auth_check (struct MHD_Connection *connection,
static int
digest_auth_check_all (struct MHD_Connection *connection,
const char *realm,
const char *username,
const char *password,
const uint8_t digest[MHD_MD5_DIGEST_SIZE],
unsigned int nonce_timeout)
{
struct MHD_Daemon *daemon = connection->daemon;
@@ -871,13 +912,24 @@ MHD_digest_auth_check (struct MHD_Connection *connection,
return MHD_NO;
}
digest_calc_ha1 ("md5",
username,
realm,
password,
nonce,
cnonce,
ha1);
if (NULL != 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,
@@ -888,6 +940,7 @@ MHD_digest_auth_check (struct MHD_Connection *connection,
hentity,
respexp);
/* Need to unescape URI before comparing with connection->url */
daemon->unescape_callback (daemon->unescape_callback_cls,
connection,
@@ -933,6 +986,66 @@ MHD_digest_auth_check (struct MHD_Connection *connection,
}
/**
* 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 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 #MHD_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 uint8_t digest[MD5_DIGEST_SIZE],
unsigned int nonce_timeout)
{
return digest_auth_check_all (connection,
realm,
username,
NULL,
digest,
nonce_timeout);
}
/**
* Queues a response to request authentication from the client
*