aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-07-14 11:09:19 +0200
committerChristian Grothoff <christian@grothoff.org>2018-07-14 13:27:45 +0200
commit2ed04522e24b801251d7fd1768b7fccfd7b8deac (patch)
tree99b8cd397d1a2e17f1b559f24343e42e0549dac3
parent2ade9eaad8d61ffdf18de113ff0934ad84565ffb (diff)
downloadlibmicrohttpd-2ed04522e24b801251d7fd1768b7fccfd7b8deac.tar.gz
libmicrohttpd-2ed04522e24b801251d7fd1768b7fccfd7b8deac.zip
add support for digest auth with hashed password
-rw-r--r--ChangeLog5
-rw-r--r--doc/libmicrohttpd.texi15
-rw-r--r--src/include/microhttpd.h36
-rw-r--r--src/microhttpd/digestauth.c213
4 files changed, 215 insertions, 54 deletions
diff --git a/ChangeLog b/ChangeLog
index 8f06fb6a..1c4ddd61 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
1Sat Jul 14 11:03:37 CEST 2018
2 Integrate patch for checking digest authentication based on
3 a digest, allowing servers to store passwords only hashed.
4 Adding new function MHD_digest_auth_check_digest(). -CG/FIXME: ack co-author!
5
1Sat Mar 10 12:15:35 CET 2018 6Sat Mar 10 12:15:35 CET 2018
2 Upgrade to gettext-0.19.8.1. Switching to more canonical 7 Upgrade to gettext-0.19.8.1. Switching to more canonical
3 gettext integration. -CG 8 gettext integration. -CG
diff --git a/doc/libmicrohttpd.texi b/doc/libmicrohttpd.texi
index cac5dd29..e4437441 100644
--- a/doc/libmicrohttpd.texi
+++ b/doc/libmicrohttpd.texi
@@ -2393,6 +2393,21 @@ most probably it will be the result of a lookup of the username against a local
2393Most of the time it is sound to specify 300 seconds as its values. 2393Most of the time it is sound to specify 300 seconds as its values.
2394@end deftypefun 2394@end deftypefun
2395 2395
2396@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)
2397Checks if the provided values in the WWW-Authenticate header are valid
2398and sound according to RFC2716. If valid return @code{MHD_YES}, otherwise return @code{MHD_NO}.
2399
2400@var{realm} must reference to a zero-terminated string representing the realm.
2401
2402@var{username} must reference to a zero-terminated string representing the username,
2403it is usually the returned value from MHD_digest_auth_get_username.
2404
2405@var{digest} pointer to the binary MD5 sum for the precalculated hash value ``userame:realm:password'' of @code{MHD_MD5_DIGEST_SIZE} bytes.
2406
2407@var{nonce_timeout} is the amount of time in seconds for a nonce to be invalid.
2408Most of the time it is sound to specify 300 seconds as its values.
2409@end deftypefun
2410
2396@deftypefun int MHD_queue_auth_fail_response (struct MHD_Connection *connection, const char *realm, const char *opaque, struct MHD_Response *response, int signal_stale) 2411@deftypefun int MHD_queue_auth_fail_response (struct MHD_Connection *connection, const char *realm, const char *opaque, struct MHD_Response *response, int signal_stale)
2397Queues a response to request authentication from the client, 2412Queues a response to request authentication from the client,
2398return @code{MHD_YES} if successful, otherwise @code{MHD_NO}. 2413return @code{MHD_YES} if successful, otherwise @code{MHD_NO}.
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index cff084ed..cdbde609 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -294,6 +294,12 @@ _MHD_DEPR_MACRO("Macro MHD_LONG_LONG_PRINTF is deprecated, use MHD_UNSIGNED_LONG
294 294
295 295
296/** 296/**
297 * Length of the binary output of the MD5 hash function.
298 */
299#define MHD_MD5_DIGEST_SIZE 16
300
301
302/**
297 * @defgroup httpcode HTTP response codes. 303 * @defgroup httpcode HTTP response codes.
298 * These are the status codes defined for HTTP responses. 304 * These are the status codes defined for HTTP responses.
299 * @{ 305 * @{
@@ -3144,10 +3150,32 @@ MHD_free (void *ptr);
3144 */ 3150 */
3145_MHD_EXTERN int 3151_MHD_EXTERN int
3146MHD_digest_auth_check (struct MHD_Connection *connection, 3152MHD_digest_auth_check (struct MHD_Connection *connection,
3147 const char *realm, 3153 const char *realm,
3148 const char *username, 3154 const char *username,
3149 const char *password, 3155 const char *password,
3150 unsigned int nonce_timeout); 3156 unsigned int nonce_timeout);
3157
3158/**
3159 * Authenticates the authorization header sent by the client
3160 *
3161 * @param connection The MHD connection structure
3162 * @param realm The realm presented to the client
3163 * @param username The username needs to be authenticated
3164 * @param digest An `unsigned char *' pointer to the binary MD5 sum
3165 * for the precalculated hash value "username:realm:password"
3166 * of #MHD_MD5_DIGEST_SIZE bytes
3167 * @param nonce_timeout The amount of time for a nonce to be
3168 * invalid in seconds
3169 * @return #MHD_YES if authenticated, #MHD_NO if not,
3170 * #MHD_INVALID_NONCE if nonce is invalid
3171 * @ingroup authentication
3172 */
3173_MHD_EXTERN int
3174MHD_digest_auth_check_digest (struct MHD_Connection *connection,
3175 const char *realm,
3176 const char *username,
3177 const uint8_t digest[MHD_MD5_DIGEST_SIZE],
3178 unsigned int nonce_timeout);
3151 3179
3152 3180
3153/** 3181/**
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c
index b0e7ce00..0c5baffb 100644
--- a/src/microhttpd/digestauth.c
+++ b/src/microhttpd/digestauth.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of libmicrohttpd 2 This file is part of libmicrohttpd
3 Copyright (C) 2010, 2011, 2012, 2015 Daniel Pittman and Christian Grothoff 3 Copyright (C) 2010, 2011, 2012, 2015, 2018 Daniel Pittman and Christian Grothoff
4 4
5 This library is free software; you can redistribute it and/or 5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public 6 modify it under the terms of the GNU Lesser General Public
@@ -37,7 +37,7 @@
37#include <windows.h> 37#include <windows.h>
38#endif /* MHD_W32_MUTEX_ */ 38#endif /* MHD_W32_MUTEX_ */
39 39
40#define HASH_MD5_HEX_LEN (2 * MD5_DIGEST_SIZE) 40#define HASH_MD5_HEX_LEN (2 * MHD_MD5_DIGEST_SIZE)
41/* 32 bit value is 4 bytes */ 41/* 32 bit value is 4 bytes */
42#define TIMESTAMP_BIN_SIZE 4 42#define TIMESTAMP_BIN_SIZE 4
43#define TIMESTAMP_HEX_LEN (2 * TIMESTAMP_BIN_SIZE) 43#define TIMESTAMP_HEX_LEN (2 * TIMESTAMP_BIN_SIZE)
@@ -93,8 +93,65 @@ cvthex (const unsigned char *bin,
93 93
94 94
95/** 95/**
96 * calculate H(A1) as per RFC2617 spec and store the 96 * calculate H(A1) from given hash as per RFC2617 spec
97 * result in 'sessionkey'. 97 * and store the * result in 'sessionkey'.
98 *
99 * @param alg The hash algorithm used, can be "md5" or "md5-sess"
100 * @param digest An `unsigned char *' pointer to the binary MD5 sum
101 * for the precalculated hash value "username:realm:password"
102 * of #MHD_MD5_DIGEST_SIZE bytes
103 * @param nonce A `char *' pointer to the nonce value
104 * @param cnonce A `char *' pointer to the cnonce value
105 * @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes
106 */
107static void
108digest_calc_ha1_from_digest (const char *alg,
109 const uint8_t digest[MHD_MD5_DIGEST_SIZE],
110 const char *nonce,
111 const char *cnonce,
112 char sessionkey[HASH_MD5_HEX_LEN + 1])
113{
114 struct MD5Context md5;
115
116 if (MHD_str_equal_caseless_(alg,
117 "md5-sess"))
118 {
119 unsigned char ha1[MHD_MD5_DIGEST_SIZE];
120
121 MD5Init (&md5);
122 MD5Update (&md5,
123 digest,
124 MHD_MD5_DIGEST_SIZE);
125 MD5Update (&md5,
126 (const unsigned char *) ":",
127 1);
128 MD5Update (&md5,
129 (const unsigned char *) nonce,
130 strlen (nonce));
131 MD5Update (&md5,
132 (const unsigned char *) ":",
133 1);
134 MD5Update (&md5,
135 (const unsigned char *) cnonce,
136 strlen (cnonce));
137 MD5Final (ha1,
138 &md5);
139 cvthex (ha1,
140 sizeof (ha1),
141 sessionkey);
142 }
143 else
144 {
145 cvthex (digest,
146 MHD_MD5_DIGEST_SIZE,
147 sessionkey);
148 }
149}
150
151
152/**
153 * calculate H(A1) from username, realm and password as per RFC2617 spec
154 * and store the result in 'sessionkey'.
98 * 155 *
99 * @param alg The hash algorithm used, can be "md5" or "md5-sess" 156 * @param alg The hash algorithm used, can be "md5" or "md5-sess"
100 * @param username A `char *' pointer to the username value 157 * @param username A `char *' pointer to the username value
@@ -105,16 +162,16 @@ cvthex (const unsigned char *bin,
105 * @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes 162 * @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes
106 */ 163 */
107static void 164static void
108digest_calc_ha1 (const char *alg, 165digest_calc_ha1_from_user (const char *alg,
109 const char *username, 166 const char *username,
110 const char *realm, 167 const char *realm,
111 const char *password, 168 const char *password,
112 const char *nonce, 169 const char *nonce,
113 const char *cnonce, 170 const char *cnonce,
114 char sessionkey[HASH_MD5_HEX_LEN + 1]) 171 char sessionkey[HASH_MD5_HEX_LEN + 1])
115{ 172{
116 struct MD5Context md5; 173 struct MD5Context md5;
117 unsigned char ha1[MD5_DIGEST_SIZE]; 174 unsigned char ha1[MHD_MD5_DIGEST_SIZE];
118 175
119 MD5Init (&md5); 176 MD5Init (&md5);
120 MD5Update (&md5, 177 MD5Update (&md5,
@@ -134,31 +191,11 @@ digest_calc_ha1 (const char *alg,
134 strlen (password)); 191 strlen (password));
135 MD5Final (ha1, 192 MD5Final (ha1,
136 &md5); 193 &md5);
137 if (MHD_str_equal_caseless_(alg, 194 digest_calc_ha1_from_digest(alg,
138 "md5-sess")) 195 ha1,
139 { 196 nonce,
140 MD5Init (&md5); 197 cnonce,
141 MD5Update (&md5, 198 sessionkey);
142 (const unsigned char *) ha1,
143 sizeof (ha1));
144 MD5Update (&md5,
145 (const unsigned char *) ":",
146 1);
147 MD5Update (&md5,
148 (const unsigned char *) nonce,
149 strlen (nonce));
150 MD5Update (&md5,
151 (const unsigned char *) ":",
152 1);
153 MD5Update (&md5,
154 (const unsigned char *) cnonce,
155 strlen (cnonce));
156 MD5Final (ha1,
157 &md5);
158 }
159 cvthex (ha1,
160 sizeof (ha1),
161 sessionkey);
162} 199}
163 200
164 201
@@ -187,8 +224,8 @@ digest_calc_response (const char ha1[HASH_MD5_HEX_LEN + 1],
187 char response[HASH_MD5_HEX_LEN + 1]) 224 char response[HASH_MD5_HEX_LEN + 1])
188{ 225{
189 struct MD5Context md5; 226 struct MD5Context md5;
190 unsigned char ha2[MD5_DIGEST_SIZE]; 227 unsigned char ha2[MHD_MD5_DIGEST_SIZE];
191 unsigned char resphash[MD5_DIGEST_SIZE]; 228 unsigned char resphash[MHD_MD5_DIGEST_SIZE];
192 char ha2hex[HASH_MD5_HEX_LEN + 1]; 229 char ha2hex[HASH_MD5_HEX_LEN + 1];
193 (void)hentity; /* Unused. Silent compiler warning. */ 230 (void)hentity; /* Unused. Silent compiler warning. */
194 231
@@ -220,7 +257,7 @@ digest_calc_response (const char ha1[HASH_MD5_HEX_LEN + 1],
220 MD5Final (ha2, 257 MD5Final (ha2,
221 &md5); 258 &md5);
222 cvthex (ha2, 259 cvthex (ha2,
223 MD5_DIGEST_SIZE, 260 MHD_MD5_DIGEST_SIZE,
224 ha2hex); 261 ha2hex);
225 MD5Init (&md5); 262 MD5Init (&md5);
226 /* calculate response */ 263 /* calculate response */
@@ -518,7 +555,7 @@ calculate_nonce (uint32_t nonce_time,
518{ 555{
519 struct MD5Context md5; 556 struct MD5Context md5;
520 unsigned char timestamp[TIMESTAMP_BIN_SIZE]; 557 unsigned char timestamp[TIMESTAMP_BIN_SIZE];
521 unsigned char tmpnonce[MD5_DIGEST_SIZE]; 558 unsigned char tmpnonce[MHD_MD5_DIGEST_SIZE];
522 char timestamphex[TIMESTAMP_HEX_LEN + 1]; 559 char timestamphex[TIMESTAMP_HEX_LEN + 1];
523 560
524 MD5Init (&md5); 561 MD5Init (&md5);
@@ -667,17 +704,21 @@ check_argument_match (struct MHD_Connection *connection,
667 * @param realm The realm presented to the client 704 * @param realm The realm presented to the client
668 * @param username The username needs to be authenticated 705 * @param username The username needs to be authenticated
669 * @param password The password used in the authentication 706 * @param password The password used in the authentication
707 * @param digest An optional `unsigned char *' pointer to the binary MD5 sum
708 * for the precalculated hash value "username:realm:password"
709 * of #MHD_MD5_DIGEST_SIZE bytes
670 * @param nonce_timeout The amount of time for a nonce to be 710 * @param nonce_timeout The amount of time for a nonce to be
671 * invalid in seconds 711 * invalid in seconds
672 * @return #MHD_YES if authenticated, #MHD_NO if not, 712 * @return #MHD_YES if authenticated, #MHD_NO if not,
673 * #MHD_INVALID_NONCE if nonce is invalid 713 * #MHD_INVALID_NONCE if nonce is invalid
674 * @ingroup authentication 714 * @ingroup authentication
675 */ 715 */
676int 716static int
677MHD_digest_auth_check (struct MHD_Connection *connection, 717digest_auth_check_all (struct MHD_Connection *connection,
678 const char *realm, 718 const char *realm,
679 const char *username, 719 const char *username,
680 const char *password, 720 const char *password,
721 const uint8_t digest[MHD_MD5_DIGEST_SIZE],
681 unsigned int nonce_timeout) 722 unsigned int nonce_timeout)
682{ 723{
683 struct MHD_Daemon *daemon = connection->daemon; 724 struct MHD_Daemon *daemon = connection->daemon;
@@ -871,13 +912,24 @@ MHD_digest_auth_check (struct MHD_Connection *connection,
871 return MHD_NO; 912 return MHD_NO;
872 } 913 }
873 914
874 digest_calc_ha1 ("md5", 915 if (NULL != digest)
875 username, 916 {
876 realm, 917 digest_calc_ha1_from_digest ("md5",
877 password, 918 digest,
878 nonce, 919 nonce,
879 cnonce, 920 cnonce,
880 ha1); 921 ha1);
922 }
923 else
924 {
925 digest_calc_ha1_from_user ("md5",
926 username,
927 realm,
928 password,
929 nonce,
930 cnonce,
931 ha1);
932 }
881 digest_calc_response (ha1, 933 digest_calc_response (ha1,
882 nonce, 934 nonce,
883 nc, 935 nc,
@@ -888,6 +940,7 @@ MHD_digest_auth_check (struct MHD_Connection *connection,
888 hentity, 940 hentity,
889 respexp); 941 respexp);
890 942
943
891 /* Need to unescape URI before comparing with connection->url */ 944 /* Need to unescape URI before comparing with connection->url */
892 daemon->unescape_callback (daemon->unescape_callback_cls, 945 daemon->unescape_callback (daemon->unescape_callback_cls,
893 connection, 946 connection,
@@ -934,6 +987,66 @@ MHD_digest_auth_check (struct MHD_Connection *connection,
934 987
935 988
936/** 989/**
990 * Authenticates the authorization header sent by the client
991 *
992 * @param connection The MHD connection structure
993 * @param realm The realm presented to the client
994 * @param username The username needs to be authenticated
995 * @param password The password used in the authentication
996 * @param nonce_timeout The amount of time for a nonce to be
997 * invalid in seconds
998 * @return #MHD_YES if authenticated, #MHD_NO if not,
999 * #MHD_INVALID_NONCE if nonce is invalid
1000 * @ingroup authentication
1001 */
1002_MHD_EXTERN int
1003MHD_digest_auth_check (struct MHD_Connection *connection,
1004 const char *realm,
1005 const char *username,
1006 const char *password,
1007 unsigned int nonce_timeout)
1008{
1009 return digest_auth_check_all(connection,
1010 realm,
1011 username,
1012 password,
1013 NULL,
1014 nonce_timeout);
1015}
1016
1017
1018/**
1019 * Authenticates the authorization header sent by the client
1020 *
1021 * @param connection The MHD connection structure
1022 * @param realm The realm presented to the client
1023 * @param username The username needs to be authenticated
1024 * @param digest An `unsigned char *' pointer to the binary MD5 sum
1025 * for the precalculated hash value "username:realm:password"
1026 * of #MHD_MD5_DIGEST_SIZE bytes
1027 * @param nonce_timeout The amount of time for a nonce to be
1028 * invalid in seconds
1029 * @return #MHD_YES if authenticated, #MHD_NO if not,
1030 * #MHD_INVALID_NONCE if nonce is invalid
1031 * @ingroup authentication
1032 */
1033_MHD_EXTERN int
1034MHD_digest_auth_check_digest (struct MHD_Connection *connection,
1035 const char *realm,
1036 const char *username,
1037 const uint8_t digest[MD5_DIGEST_SIZE],
1038 unsigned int nonce_timeout)
1039{
1040 return digest_auth_check_all (connection,
1041 realm,
1042 username,
1043 NULL,
1044 digest,
1045 nonce_timeout);
1046}
1047
1048
1049/**
937 * Queues a response to request authentication from the client 1050 * Queues a response to request authentication from the client
938 * 1051 *
939 * @param connection The MHD connection structure 1052 * @param connection The MHD connection structure