diff options
Diffstat (limited to 'src/microhttpd/digestauth.c')
-rw-r--r-- | src/microhttpd/digestauth.c | 779 |
1 files changed, 514 insertions, 265 deletions
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c index 80cba836..424c3761 100644 --- a/src/microhttpd/digestauth.c +++ b/src/microhttpd/digestauth.c | |||
@@ -21,11 +21,13 @@ | |||
21 | * @brief Implements HTTP digest authentication | 21 | * @brief Implements HTTP digest authentication |
22 | * @author Amr Ali | 22 | * @author Amr Ali |
23 | * @author Matthieu Speder | 23 | * @author Matthieu Speder |
24 | * @author Christian Grothoff (RFC 7616 support) | ||
24 | */ | 25 | */ |
25 | #include "platform.h" | 26 | #include "platform.h" |
26 | #include "mhd_limits.h" | 27 | #include "mhd_limits.h" |
27 | #include "internal.h" | 28 | #include "internal.h" |
28 | #include "md5.h" | 29 | #include "md5.h" |
30 | #include "sha256.h" | ||
29 | #include "mhd_mono_clock.h" | 31 | #include "mhd_mono_clock.h" |
30 | #include "mhd_str.h" | 32 | #include "mhd_str.h" |
31 | #include "mhd_compat.h" | 33 | #include "mhd_compat.h" |
@@ -37,13 +39,18 @@ | |||
37 | #include <windows.h> | 39 | #include <windows.h> |
38 | #endif /* MHD_W32_MUTEX_ */ | 40 | #endif /* MHD_W32_MUTEX_ */ |
39 | 41 | ||
40 | #define HASH_MD5_HEX_LEN (2 * MHD_MD5_DIGEST_SIZE) | 42 | /** |
41 | /* 32 bit value is 4 bytes */ | 43 | * 32 bit value is 4 bytes |
44 | */ | ||
42 | #define TIMESTAMP_BIN_SIZE 4 | 45 | #define TIMESTAMP_BIN_SIZE 4 |
43 | #define TIMESTAMP_HEX_LEN (2 * TIMESTAMP_BIN_SIZE) | ||
44 | 46 | ||
45 | /* Standard server nonce length, not including terminating null */ | 47 | /** |
46 | #define NONCE_STD_LEN (HASH_MD5_HEX_LEN + TIMESTAMP_HEX_LEN) | 48 | * Standard server nonce length, not including terminating null, |
49 | * | ||
50 | * @param digest_size digest size | ||
51 | */ | ||
52 | #define NONCE_STD_LEN(digest_size) \ | ||
53 | ((digest_size) * 2 + TIMESTAMP_BIN_SIZE * 2) | ||
47 | 54 | ||
48 | /** | 55 | /** |
49 | * Beginning string for any valid Digest authentication header. | 56 | * Beginning string for any valid Digest authentication header. |
@@ -63,7 +70,66 @@ | |||
63 | /** | 70 | /** |
64 | * Maximum length of the response in digest authentication. | 71 | * Maximum length of the response in digest authentication. |
65 | */ | 72 | */ |
66 | #define MAX_AUTH_RESPONSE_LENGTH 128 | 73 | #define MAX_AUTH_RESPONSE_LENGTH 256 |
74 | |||
75 | |||
76 | /** | ||
77 | * Context passed to functions that need to calculate | ||
78 | * a digest but are orthogonal to the specific | ||
79 | * algorithm. | ||
80 | */ | ||
81 | struct DigestAlgorithm | ||
82 | { | ||
83 | /** | ||
84 | * Size of the final digest returned by @e digest. | ||
85 | */ | ||
86 | unsigned int digest_size; | ||
87 | |||
88 | /** | ||
89 | * A context for the digest algorithm, already initialized to be | ||
90 | * useful for @e init, @e update and @e digest. | ||
91 | */ | ||
92 | void *ctx; | ||
93 | |||
94 | /** | ||
95 | * Name of the algorithm, "md5" or "sha-256" | ||
96 | */ | ||
97 | const char *alg; | ||
98 | |||
99 | /** | ||
100 | * Buffer of @e digest_size * 2 + 1 bytes. | ||
101 | */ | ||
102 | char *sessionkey; | ||
103 | |||
104 | /** | ||
105 | * Call to initialize @e ctx. | ||
106 | */ | ||
107 | void | ||
108 | (*init)(void *ctx); | ||
109 | |||
110 | /** | ||
111 | * Feed more data into the digest function. | ||
112 | * | ||
113 | * @param ctx context to feed | ||
114 | * @param length number of bytes in @a data | ||
115 | * @param data data to add | ||
116 | */ | ||
117 | void | ||
118 | (*update)(void *ctx, | ||
119 | const uint8_t *data, | ||
120 | size_t length); | ||
121 | |||
122 | /** | ||
123 | * Compute final @a digest. | ||
124 | * | ||
125 | * @param ctx context to use | ||
126 | * @param digest[out] where to write the result, | ||
127 | * must be @e digest_length bytes long | ||
128 | */ | ||
129 | void | ||
130 | (*digest)(void *ctx, | ||
131 | uint8_t *digest); | ||
132 | }; | ||
67 | 133 | ||
68 | 134 | ||
69 | /** | 135 | /** |
@@ -97,54 +163,57 @@ cvthex (const unsigned char *bin, | |||
97 | * and store the * result in 'sessionkey'. | 163 | * and store the * result in 'sessionkey'. |
98 | * | 164 | * |
99 | * @param alg The hash algorithm used, can be "md5" or "md5-sess" | 165 | * @param alg The hash algorithm used, can be "md5" or "md5-sess" |
166 | * or "sha-256" or "sha-256-sess" | ||
167 | * Note that the rest of the code does not support the the "-sess" variants! | ||
168 | * @param da[in,out] digest implementation, must match @a alg; the | ||
169 | * da->sessionkey will be initialized to the digest in HEX | ||
100 | * @param digest An `unsigned char *' pointer to the binary MD5 sum | 170 | * @param digest An `unsigned char *' pointer to the binary MD5 sum |
101 | * for the precalculated hash value "username:realm:password" | 171 | * for the precalculated hash value "username:realm:password" |
102 | * of #MHD_MD5_DIGEST_SIZE bytes | 172 | * of #MHD_MD5_DIGEST_SIZE or #MHD_SHA256_DIGEST_SIZE bytes |
103 | * @param nonce A `char *' pointer to the nonce value | 173 | * @param nonce A `char *' pointer to the nonce value |
104 | * @param cnonce A `char *' pointer to the cnonce value | 174 | * @param cnonce A `char *' pointer to the cnonce value |
105 | * @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes | ||
106 | */ | 175 | */ |
107 | static void | 176 | static void |
108 | digest_calc_ha1_from_digest (const char *alg, | 177 | digest_calc_ha1_from_digest (const char *alg, |
109 | const uint8_t digest[MHD_MD5_DIGEST_SIZE], | 178 | struct DigestAlgorithm *da, |
179 | const uint8_t *digest, | ||
110 | const char *nonce, | 180 | const char *nonce, |
111 | const char *cnonce, | 181 | const char *cnonce) |
112 | char sessionkey[HASH_MD5_HEX_LEN + 1]) | ||
113 | { | 182 | { |
114 | struct MD5Context md5; | 183 | if ( (MHD_str_equal_caseless_(alg, |
115 | 184 | "md5-sess")) || | |
116 | if (MHD_str_equal_caseless_(alg, | 185 | (MHD_str_equal_caseless_(alg, |
117 | "md5-sess")) | 186 | "sha-256-sess")) ) |
118 | { | 187 | { |
119 | unsigned char ha1[MHD_MD5_DIGEST_SIZE]; | 188 | uint8_t dig[da->digest_size]; |
120 | 189 | ||
121 | MD5Init (&md5); | 190 | da->init (da->ctx); |
122 | MD5Update (&md5, | 191 | da->update (da->ctx, |
123 | digest, | 192 | digest, |
124 | MHD_MD5_DIGEST_SIZE); | 193 | MHD_MD5_DIGEST_SIZE); |
125 | MD5Update (&md5, | 194 | da->update (da->ctx, |
195 | (const unsigned char *) ":", | ||
196 | 1); | ||
197 | da->update (da->ctx, | ||
198 | (const unsigned char *) nonce, | ||
199 | strlen (nonce)); | ||
200 | da->update (da->ctx, | ||
126 | (const unsigned char *) ":", | 201 | (const unsigned char *) ":", |
127 | 1); | 202 | 1); |
128 | MD5Update (&md5, | 203 | da->update (da->ctx, |
129 | (const unsigned char *) nonce, | 204 | (const unsigned char *) cnonce, |
130 | strlen (nonce)); | 205 | strlen (cnonce)); |
131 | MD5Update (&md5, | 206 | da->digest (da->ctx, |
132 | (const unsigned char *) ":", | 207 | dig); |
133 | 1); | 208 | cvthex (dig, |
134 | MD5Update (&md5, | 209 | sizeof (dig), |
135 | (const unsigned char *) cnonce, | 210 | da->sessionkey); |
136 | strlen (cnonce)); | ||
137 | MD5Final (ha1, | ||
138 | &md5); | ||
139 | cvthex (ha1, | ||
140 | sizeof (ha1), | ||
141 | sessionkey); | ||
142 | } | 211 | } |
143 | else | 212 | else |
144 | { | 213 | { |
145 | cvthex (digest, | 214 | cvthex (digest, |
146 | MHD_MD5_DIGEST_SIZE, | 215 | da->digest_size, |
147 | sessionkey); | 216 | da->sessionkey); |
148 | } | 217 | } |
149 | } | 218 | } |
150 | 219 | ||
@@ -154,12 +223,14 @@ digest_calc_ha1_from_digest (const char *alg, | |||
154 | * and store the result in 'sessionkey'. | 223 | * and store the result in 'sessionkey'. |
155 | * | 224 | * |
156 | * @param alg The hash algorithm used, can be "md5" or "md5-sess" | 225 | * @param alg The hash algorithm used, can be "md5" or "md5-sess" |
226 | * or "sha-256" or "sha-256-sess" | ||
157 | * @param username A `char *' pointer to the username value | 227 | * @param username A `char *' pointer to the username value |
158 | * @param realm A `char *' pointer to the realm value | 228 | * @param realm A `char *' pointer to the realm value |
159 | * @param password A `char *' pointer to the password value | 229 | * @param password A `char *' pointer to the password value |
160 | * @param nonce A `char *' pointer to the nonce value | 230 | * @param nonce A `char *' pointer to the nonce value |
161 | * @param cnonce A `char *' pointer to the cnonce value | 231 | * @param cnonce A `char *' pointer to the cnonce value |
162 | * @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes | 232 | * @param da[in,out] digest algorithm to use, and where to write |
233 | * the sessionkey to | ||
163 | */ | 234 | */ |
164 | static void | 235 | static void |
165 | digest_calc_ha1_from_user (const char *alg, | 236 | digest_calc_ha1_from_user (const char *alg, |
@@ -168,52 +239,54 @@ digest_calc_ha1_from_user (const char *alg, | |||
168 | const char *password, | 239 | const char *password, |
169 | const char *nonce, | 240 | const char *nonce, |
170 | const char *cnonce, | 241 | const char *cnonce, |
171 | char sessionkey[HASH_MD5_HEX_LEN + 1]) | 242 | struct DigestAlgorithm *da) |
172 | { | 243 | { |
173 | struct MD5Context md5; | 244 | unsigned char ha1[da->digest_size]; |
174 | unsigned char ha1[MHD_MD5_DIGEST_SIZE]; | ||
175 | 245 | ||
176 | MD5Init (&md5); | 246 | da->init (da->ctx); |
177 | MD5Update (&md5, | 247 | da->update (da->ctx, |
178 | (const unsigned char *) username, | 248 | (const unsigned char *) username, |
179 | strlen (username)); | 249 | strlen (username)); |
180 | MD5Update (&md5, | 250 | da->update (da->ctx, |
181 | (const unsigned char *) ":", | 251 | (const unsigned char *) ":", |
182 | 1); | 252 | 1); |
183 | MD5Update (&md5, | 253 | da->update (da->ctx, |
184 | (const unsigned char *) realm, | 254 | (const unsigned char *) realm, |
185 | strlen (realm)); | 255 | strlen (realm)); |
186 | MD5Update (&md5, | 256 | da->update (da->ctx, |
187 | (const unsigned char *) ":", | 257 | (const unsigned char *) ":", |
188 | 1); | 258 | 1); |
189 | MD5Update (&md5, | 259 | da->update (da->ctx, |
190 | (const unsigned char *) password, | 260 | (const unsigned char *) password, |
191 | strlen (password)); | 261 | strlen (password)); |
192 | MD5Final (ha1, | 262 | da->digest (da->ctx, |
193 | &md5); | 263 | ha1); |
194 | digest_calc_ha1_from_digest(alg, | 264 | digest_calc_ha1_from_digest (alg, |
195 | ha1, | 265 | da, |
196 | nonce, | 266 | ha1, |
197 | cnonce, | 267 | nonce, |
198 | sessionkey); | 268 | cnonce); |
199 | } | 269 | } |
200 | 270 | ||
201 | 271 | ||
202 | /** | 272 | /** |
203 | * Calculate request-digest/response-digest as per RFC2617 spec | 273 | * Calculate request-digest/response-digest as per RFC2617 / RFC7616 |
274 | * spec. | ||
204 | * | 275 | * |
205 | * @param ha1 H(A1) | 276 | * @param ha1 H(A1), twice the @a da->digest_size + 1 bytes (0-terminated), |
277 | * MUST NOT be aliased with `da->sessionkey`! | ||
206 | * @param nonce nonce from server | 278 | * @param nonce nonce from server |
207 | * @param noncecount 8 hex digits | 279 | * @param noncecount 8 hex digits |
208 | * @param cnonce client nonce | 280 | * @param cnonce client nonce |
209 | * @param qop qop-value: "", "auth" or "auth-int" | 281 | * @param qop qop-value: "", "auth" or "auth-int" (NOTE: only 'auth' is supported today.) |
210 | * @param method method from request | 282 | * @param method method from request |
211 | * @param uri requested URL | 283 | * @param uri requested URL |
212 | * @param hentity H(entity body) if qop="auth-int" | 284 | * @param hentity H(entity body) if qop="auth-int" |
213 | * @param response request-digest or response-digest | 285 | * @param da[in,out] digest algorithm to use, also |
286 | * we write da->sessionkey (set to response request-digest or response-digest) | ||
214 | */ | 287 | */ |
215 | static void | 288 | static void |
216 | digest_calc_response (const char ha1[HASH_MD5_HEX_LEN + 1], | 289 | digest_calc_response (const char *ha1, |
217 | const char *nonce, | 290 | const char *nonce, |
218 | const char *noncecount, | 291 | const char *noncecount, |
219 | const char *cnonce, | 292 | const char *cnonce, |
@@ -221,87 +294,85 @@ digest_calc_response (const char ha1[HASH_MD5_HEX_LEN + 1], | |||
221 | const char *method, | 294 | const char *method, |
222 | const char *uri, | 295 | const char *uri, |
223 | const char *hentity, | 296 | const char *hentity, |
224 | char response[HASH_MD5_HEX_LEN + 1]) | 297 | struct DigestAlgorithm *da) |
225 | { | 298 | { |
226 | struct MD5Context md5; | 299 | unsigned char ha2[da->digest_size]; |
227 | unsigned char ha2[MHD_MD5_DIGEST_SIZE]; | 300 | unsigned char resphash[da->digest_size]; |
228 | unsigned char resphash[MHD_MD5_DIGEST_SIZE]; | 301 | (void)hentity; /* Unused. Silence compiler warning. */ |
229 | char ha2hex[HASH_MD5_HEX_LEN + 1]; | 302 | |
230 | (void)hentity; /* Unused. Silent compiler warning. */ | 303 | da->init (da->ctx); |
231 | 304 | da->update (da->ctx, | |
232 | MD5Init (&md5); | 305 | (const unsigned char *) method, |
233 | MD5Update (&md5, | 306 | strlen (method)); |
234 | (const unsigned char *) method, | 307 | da->update (da->ctx, |
235 | strlen (method)); | 308 | (const unsigned char *) ":", |
236 | MD5Update (&md5, | 309 | 1); |
237 | (const unsigned char *) ":", | 310 | da->update (da->ctx, |
238 | 1); | ||
239 | MD5Update (&md5, | ||
240 | (const unsigned char *) uri, | 311 | (const unsigned char *) uri, |
241 | strlen (uri)); | 312 | strlen (uri)); |
242 | #if 0 | 313 | #if 0 |
243 | if (0 == strcasecmp(qop, | 314 | if (0 == strcasecmp (qop, |
244 | "auth-int")) | 315 | "auth-int")) |
245 | { | 316 | { |
246 | /* This is dead code since the rest of this module does | 317 | /* This is dead code since the rest of this module does |
247 | not support auth-int. */ | 318 | not support auth-int. */ |
248 | MD5Update (&md5, | 319 | da->update (da->ctx, |
249 | ":", | 320 | ":", |
250 | 1); | 321 | 1); |
251 | if (NULL != hentity) | 322 | if (NULL != hentity) |
252 | MD5Update (&md5, | 323 | da->update (da->ctx, |
253 | hentity, | 324 | hentity, |
254 | strlen (hentity)); | 325 | strlen (hentity)); |
255 | } | 326 | } |
256 | #endif | 327 | #endif |
257 | MD5Final (ha2, | 328 | da->digest (da->ctx, |
258 | &md5); | 329 | ha2); |
259 | cvthex (ha2, | 330 | cvthex (ha2, |
260 | MHD_MD5_DIGEST_SIZE, | 331 | da->digest_size, |
261 | ha2hex); | 332 | da->sessionkey); |
262 | MD5Init (&md5); | 333 | da->init (da->ctx); |
263 | /* calculate response */ | 334 | /* calculate response */ |
264 | MD5Update (&md5, | 335 | da->update (da->ctx, |
265 | (const unsigned char *) ha1, | 336 | (const unsigned char *) ha1, |
266 | HASH_MD5_HEX_LEN); | 337 | da->digest_size * 2); |
267 | MD5Update (&md5, | 338 | da->update (da->ctx, |
268 | (const unsigned char *) ":", | 339 | (const unsigned char *) ":", |
269 | 1); | 340 | 1); |
270 | MD5Update (&md5, | 341 | da->update (da->ctx, |
271 | (const unsigned char *) nonce, | 342 | (const unsigned char *) nonce, |
272 | strlen (nonce)); | 343 | strlen (nonce)); |
273 | MD5Update (&md5, | 344 | da->update (da->ctx, |
274 | (const unsigned char*) ":", | 345 | (const unsigned char*) ":", |
275 | 1); | 346 | 1); |
276 | if ('\0' != *qop) | 347 | if ('\0' != *qop) |
277 | { | 348 | { |
278 | MD5Update (&md5, | 349 | da->update (da->ctx, |
279 | (const unsigned char *) noncecount, | 350 | (const unsigned char *) noncecount, |
280 | strlen (noncecount)); | 351 | strlen (noncecount)); |
281 | MD5Update (&md5, | 352 | da->update (da->ctx, |
282 | (const unsigned char *) ":", | 353 | (const unsigned char *) ":", |
283 | 1); | 354 | 1); |
284 | MD5Update (&md5, | 355 | da->update (da->ctx, |
285 | (const unsigned char *) cnonce, | 356 | (const unsigned char *) cnonce, |
286 | strlen (cnonce)); | 357 | strlen (cnonce)); |
287 | MD5Update (&md5, | 358 | da->update (da->ctx, |
288 | (const unsigned char *) ":", | 359 | (const unsigned char *) ":", |
289 | 1); | 360 | 1); |
290 | MD5Update (&md5, | 361 | da->update (da->ctx, |
291 | (const unsigned char *) qop, | 362 | (const unsigned char *) qop, |
292 | strlen (qop)); | 363 | strlen (qop)); |
293 | MD5Update (&md5, | 364 | da->update (da->ctx, |
294 | (const unsigned char *) ":", | 365 | (const unsigned char *) ":", |
295 | 1); | 366 | 1); |
296 | } | 367 | } |
297 | MD5Update (&md5, | 368 | da->update (da->ctx, |
298 | (const unsigned char *) ha2hex, | 369 | (const unsigned char *) da->sessionkey, |
299 | HASH_MD5_HEX_LEN); | 370 | da->digest_size * 2); |
300 | MD5Final (resphash, | 371 | da->digest (da->ctx, |
301 | &md5); | 372 | resphash); |
302 | cvthex (resphash, | 373 | cvthex (resphash, |
303 | sizeof(resphash), | 374 | sizeof(resphash), |
304 | response); | 375 | da->sessionkey); |
305 | } | 376 | } |
306 | 377 | ||
307 | 378 | ||
@@ -552,7 +623,9 @@ MHD_digest_auth_get_username(struct MHD_Connection *connection) | |||
552 | * @param rnd_size The size of the random seed array @a rnd | 623 | * @param rnd_size The size of the random seed array @a rnd |
553 | * @param uri HTTP URI (in MHD, without the arguments ("?k=v") | 624 | * @param uri HTTP URI (in MHD, without the arguments ("?k=v") |
554 | * @param realm A string of characters that describes the realm of auth. | 625 | * @param realm A string of characters that describes the realm of auth. |
555 | * @param nonce A pointer to a character array for the nonce to put in | 626 | * @param da digest algorithm to use |
627 | * @param nonce A pointer to a character array for the nonce to put in, | ||
628 | * must provide NONCE_STD_LEN(da->digest_size)+1 bytes | ||
556 | */ | 629 | */ |
557 | static void | 630 | static void |
558 | calculate_nonce (uint32_t nonce_time, | 631 | calculate_nonce (uint32_t nonce_time, |
@@ -561,48 +634,48 @@ calculate_nonce (uint32_t nonce_time, | |||
561 | size_t rnd_size, | 634 | size_t rnd_size, |
562 | const char *uri, | 635 | const char *uri, |
563 | const char *realm, | 636 | const char *realm, |
564 | char nonce[NONCE_STD_LEN + 1]) | 637 | struct DigestAlgorithm *da, |
638 | char *nonce) | ||
565 | { | 639 | { |
566 | struct MD5Context md5; | ||
567 | unsigned char timestamp[TIMESTAMP_BIN_SIZE]; | 640 | unsigned char timestamp[TIMESTAMP_BIN_SIZE]; |
568 | unsigned char tmpnonce[MHD_MD5_DIGEST_SIZE]; | 641 | unsigned char tmpnonce[da->digest_size]; |
569 | char timestamphex[TIMESTAMP_HEX_LEN + 1]; | 642 | char timestamphex[TIMESTAMP_BIN_SIZE * 2 + 1]; |
570 | 643 | ||
571 | MD5Init (&md5); | 644 | da->init (da->ctx); |
572 | timestamp[0] = (unsigned char)((nonce_time & 0xff000000) >> 0x18); | 645 | timestamp[0] = (unsigned char)((nonce_time & 0xff000000) >> 0x18); |
573 | timestamp[1] = (unsigned char)((nonce_time & 0x00ff0000) >> 0x10); | 646 | timestamp[1] = (unsigned char)((nonce_time & 0x00ff0000) >> 0x10); |
574 | timestamp[2] = (unsigned char)((nonce_time & 0x0000ff00) >> 0x08); | 647 | timestamp[2] = (unsigned char)((nonce_time & 0x0000ff00) >> 0x08); |
575 | timestamp[3] = (unsigned char)((nonce_time & 0x000000ff)); | 648 | timestamp[3] = (unsigned char)((nonce_time & 0x000000ff)); |
576 | MD5Update (&md5, | 649 | da->update (da->ctx, |
577 | timestamp, | 650 | timestamp, |
578 | sizeof (timestamp)); | 651 | sizeof (timestamp)); |
579 | MD5Update (&md5, | 652 | da->update (da->ctx, |
580 | (const unsigned char *) ":", | 653 | (const unsigned char *) ":", |
581 | 1); | 654 | 1); |
582 | MD5Update (&md5, | 655 | da->update (da->ctx, |
583 | (const unsigned char *) method, | 656 | (const unsigned char *) method, |
584 | strlen (method)); | 657 | strlen (method)); |
585 | MD5Update (&md5, | 658 | da->update (da->ctx, |
586 | (const unsigned char *) ":", | 659 | (const unsigned char *) ":", |
587 | 1); | 660 | 1); |
588 | if (rnd_size > 0) | 661 | if (rnd_size > 0) |
589 | MD5Update (&md5, | 662 | da->update (da->ctx, |
590 | (const unsigned char *) rnd, | 663 | (const unsigned char *) rnd, |
591 | rnd_size); | 664 | rnd_size); |
592 | MD5Update (&md5, | 665 | da->update (da->ctx, |
593 | (const unsigned char *) ":", | 666 | (const unsigned char *) ":", |
594 | 1); | 667 | 1); |
595 | MD5Update (&md5, | 668 | da->update (da->ctx, |
596 | (const unsigned char *) uri, | 669 | (const unsigned char *) uri, |
597 | strlen (uri)); | 670 | strlen (uri)); |
598 | MD5Update (&md5, | 671 | da->update (da->ctx, |
599 | (const unsigned char *) ":", | 672 | (const unsigned char *) ":", |
600 | 1); | 673 | 1); |
601 | MD5Update (&md5, | 674 | da->update (da->ctx, |
602 | (const unsigned char *) realm, | 675 | (const unsigned char *) realm, |
603 | strlen (realm)); | 676 | strlen (realm)); |
604 | MD5Final (tmpnonce, | 677 | da->digest (da->ctx, |
605 | &md5); | 678 | tmpnonce); |
606 | cvthex (tmpnonce, | 679 | cvthex (tmpnonce, |
607 | sizeof (tmpnonce), | 680 | sizeof (tmpnonce), |
608 | nonce); | 681 | nonce); |
@@ -713,12 +786,15 @@ check_argument_match (struct MHD_Connection *connection, | |||
713 | * Authenticates the authorization header sent by the client | 786 | * Authenticates the authorization header sent by the client |
714 | * | 787 | * |
715 | * @param connection The MHD connection structure | 788 | * @param connection The MHD connection structure |
789 | * @param da[in,out] digest algorithm to use for checking (written to as | ||
790 | * part of the calculations, but the values left in the struct | ||
791 | * are not actually expected to be useful for the caller) | ||
716 | * @param realm The realm presented to the client | 792 | * @param realm The realm presented to the client |
717 | * @param username The username needs to be authenticated | 793 | * @param username The username needs to be authenticated |
718 | * @param password The password used in the authentication | 794 | * @param password The password used in the authentication |
719 | * @param digest An optional `unsigned char *' pointer to the binary MD5 sum | 795 | * @param digest An optional binary hash |
720 | * for the precalculated hash value "username:realm:password" | 796 | * of the precalculated hash value "username:realm:password" |
721 | * of #MHD_MD5_DIGEST_SIZE bytes | 797 | * (must contain "da->digest_size" bytes or be NULL) |
722 | * @param nonce_timeout The amount of time for a nonce to be | 798 | * @param nonce_timeout The amount of time for a nonce to be |
723 | * invalid in seconds | 799 | * invalid in seconds |
724 | * @return #MHD_YES if authenticated, #MHD_NO if not, | 800 | * @return #MHD_YES if authenticated, #MHD_NO if not, |
@@ -727,10 +803,11 @@ check_argument_match (struct MHD_Connection *connection, | |||
727 | */ | 803 | */ |
728 | static int | 804 | static int |
729 | digest_auth_check_all (struct MHD_Connection *connection, | 805 | digest_auth_check_all (struct MHD_Connection *connection, |
806 | struct DigestAlgorithm *da, | ||
730 | const char *realm, | 807 | const char *realm, |
731 | const char *username, | 808 | const char *username, |
732 | const char *password, | 809 | const char *password, |
733 | const uint8_t digest[MHD_MD5_DIGEST_SIZE], | 810 | const uint8_t *digest, |
734 | unsigned int nonce_timeout) | 811 | unsigned int nonce_timeout) |
735 | { | 812 | { |
736 | struct MHD_Daemon *daemon = connection->daemon; | 813 | struct MHD_Daemon *daemon = connection->daemon; |
@@ -738,13 +815,12 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
738 | const char *header; | 815 | const char *header; |
739 | char nonce[MAX_NONCE_LENGTH]; | 816 | char nonce[MAX_NONCE_LENGTH]; |
740 | char cnonce[MAX_NONCE_LENGTH]; | 817 | char cnonce[MAX_NONCE_LENGTH]; |
818 | char ha1[da->digest_size * 2 + 1]; | ||
741 | char qop[15]; /* auth,auth-int */ | 819 | char qop[15]; /* auth,auth-int */ |
742 | char nc[20]; | 820 | char nc[20]; |
743 | char response[MAX_AUTH_RESPONSE_LENGTH]; | 821 | char response[MAX_AUTH_RESPONSE_LENGTH]; |
744 | const char *hentity = NULL; /* "auth-int" is not supported */ | 822 | const char *hentity = NULL; /* "auth-int" is not supported */ |
745 | char ha1[HASH_MD5_HEX_LEN + 1]; | 823 | char noncehashexp[NONCE_STD_LEN(da->digest_size) + 1]; |
746 | char respexp[HASH_MD5_HEX_LEN + 1]; | ||
747 | char noncehashexp[NONCE_STD_LEN + 1]; | ||
748 | uint32_t nonce_time; | 824 | uint32_t nonce_time; |
749 | uint32_t t; | 825 | uint32_t t; |
750 | size_t left; /* number of characters left in 'header' for 'uri' */ | 826 | size_t left; /* number of characters left in 'header' for 'uri' */ |
@@ -807,9 +883,9 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
807 | header value. */ | 883 | header value. */ |
808 | return MHD_NO; | 884 | return MHD_NO; |
809 | } | 885 | } |
810 | if (TIMESTAMP_HEX_LEN != | 886 | if (TIMESTAMP_BIN_SIZE * 2 != |
811 | MHD_strx_to_uint32_n_ (nonce + len - TIMESTAMP_HEX_LEN, | 887 | MHD_strx_to_uint32_n_ (nonce + len - TIMESTAMP_BIN_SIZE * 2, |
812 | TIMESTAMP_HEX_LEN, | 888 | TIMESTAMP_BIN_SIZE * 2, |
813 | &nonce_time)) | 889 | &nonce_time)) |
814 | { | 890 | { |
815 | #ifdef HAVE_MESSAGES | 891 | #ifdef HAVE_MESSAGES |
@@ -837,6 +913,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
837 | daemon->digest_auth_rand_size, | 913 | daemon->digest_auth_rand_size, |
838 | connection->url, | 914 | connection->url, |
839 | realm, | 915 | realm, |
916 | da, | ||
840 | noncehashexp); | 917 | noncehashexp); |
841 | /* | 918 | /* |
842 | * Second level vetting for the nonce validity | 919 | * Second level vetting for the nonce validity |
@@ -848,7 +925,8 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
848 | * very hard to achieve. | 925 | * very hard to achieve. |
849 | */ | 926 | */ |
850 | 927 | ||
851 | if (0 != strcmp (nonce, noncehashexp)) | 928 | if (0 != strcmp (nonce, |
929 | noncehashexp)) | ||
852 | { | 930 | { |
853 | return MHD_INVALID_NONCE; | 931 | return MHD_INVALID_NONCE; |
854 | } | 932 | } |
@@ -908,40 +986,45 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
908 | 986 | ||
909 | uri = malloc (left + 1); | 987 | uri = malloc (left + 1); |
910 | if (NULL == uri) | 988 | if (NULL == uri) |
911 | { | 989 | { |
912 | #ifdef HAVE_MESSAGES | 990 | #ifdef HAVE_MESSAGES |
913 | MHD_DLOG(daemon, | 991 | MHD_DLOG(daemon, |
914 | _("Failed to allocate memory for auth header processing\n")); | 992 | _("Failed to allocate memory for auth header processing\n")); |
915 | #endif /* HAVE_MESSAGES */ | 993 | #endif /* HAVE_MESSAGES */ |
916 | return MHD_NO; | 994 | return MHD_NO; |
917 | } | 995 | } |
918 | if (0 == lookup_sub_value (uri, | 996 | if (0 == lookup_sub_value (uri, |
919 | left + 1, | 997 | left + 1, |
920 | header, | 998 | header, |
921 | "uri")) | 999 | "uri")) |
922 | { | 1000 | { |
923 | free (uri); | 1001 | free (uri); |
924 | return MHD_NO; | 1002 | return MHD_NO; |
925 | } | 1003 | } |
926 | |||
927 | if (NULL != digest) | 1004 | if (NULL != digest) |
928 | { | 1005 | { |
929 | digest_calc_ha1_from_digest ("md5", | 1006 | /* This will initialize da->sessionkey (ha1) */ |
1007 | digest_calc_ha1_from_digest (da->alg, | ||
1008 | da, | ||
930 | digest, | 1009 | digest, |
931 | nonce, | 1010 | nonce, |
932 | cnonce, | 1011 | cnonce); |
933 | ha1); | ||
934 | } | 1012 | } |
935 | else | 1013 | else |
936 | { | 1014 | { |
937 | digest_calc_ha1_from_user ("md5", | 1015 | /* This will initialize da->sessionkey (ha1) */ |
1016 | digest_calc_ha1_from_user (da->alg, | ||
938 | username, | 1017 | username, |
939 | realm, | 1018 | realm, |
940 | password, | 1019 | password, |
941 | nonce, | 1020 | nonce, |
942 | cnonce, | 1021 | cnonce, |
943 | ha1); | 1022 | da); |
944 | } | 1023 | } |
1024 | memcpy (ha1, | ||
1025 | da->sessionkey, | ||
1026 | sizeof (ha1)); | ||
1027 | /* This will initialize da->sessionkey (respexp) */ | ||
945 | digest_calc_response (ha1, | 1028 | digest_calc_response (ha1, |
946 | nonce, | 1029 | nonce, |
947 | nc, | 1030 | nc, |
@@ -950,7 +1033,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
950 | connection->method, | 1033 | connection->method, |
951 | uri, | 1034 | uri, |
952 | hentity, | 1035 | hentity, |
953 | respexp); | 1036 | da); |
954 | 1037 | ||
955 | 1038 | ||
956 | /* Need to unescape URI before comparing with connection->url */ | 1039 | /* Need to unescape URI before comparing with connection->url */ |
@@ -991,7 +1074,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
991 | } | 1074 | } |
992 | free (uri); | 1075 | free (uri); |
993 | return (0 == strcmp (response, | 1076 | return (0 == strcmp (response, |
994 | respexp)) | 1077 | da->sessionkey)) |
995 | ? MHD_YES | 1078 | ? MHD_YES |
996 | : MHD_NO; | 1079 | : MHD_NO; |
997 | } | 1080 | } |
@@ -999,7 +1082,11 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
999 | 1082 | ||
1000 | 1083 | ||
1001 | /** | 1084 | /** |
1002 | * Authenticates the authorization header sent by the client | 1085 | * Authenticates the authorization header sent by the client. |
1086 | * Uses #MHD_DIGEST_ALG_MD5 (for now, for backwards-compatibility). | ||
1087 | * Note that this MAY change to #MHD_DIGEST_ALG_AUTO in the future. | ||
1088 | * If you want to be sure you get MD5, use #MHD_digest_auth_check2 | ||
1089 | * and specifiy MD5 explicitly. | ||
1003 | * | 1090 | * |
1004 | * @param connection The MHD connection structure | 1091 | * @param connection The MHD connection structure |
1005 | * @param realm The realm presented to the client | 1092 | * @param realm The realm presented to the client |
@@ -1018,7 +1105,85 @@ MHD_digest_auth_check (struct MHD_Connection *connection, | |||
1018 | const char *password, | 1105 | const char *password, |
1019 | unsigned int nonce_timeout) | 1106 | unsigned int nonce_timeout) |
1020 | { | 1107 | { |
1108 | return MHD_digest_auth_check2 (connection, | ||
1109 | realm, | ||
1110 | username, | ||
1111 | password, | ||
1112 | nonce_timeout, | ||
1113 | MHD_DIGEST_ALG_MD5); | ||
1114 | } | ||
1115 | |||
1116 | |||
1117 | /** | ||
1118 | * Setup digest authentication data structures (on the | ||
1119 | * stack, hence must be done inline!). Initializes a | ||
1120 | * "struct DigestAlgorithm da" for algorithm @a algo. | ||
1121 | * | ||
1122 | * @param algo digest algorithm to provide | ||
1123 | * @param da data structure to setup | ||
1124 | */ | ||
1125 | #define SETUP_DA(algo,da) \ | ||
1126 | union { \ | ||
1127 | struct MD5Context md5; \ | ||
1128 | struct sha256_ctx sha256; \ | ||
1129 | } ctx; \ | ||
1130 | union { \ | ||
1131 | char md5[MD5_DIGEST_SIZE * 2 + 1]; \ | ||
1132 | char sha256[SHA256_DIGEST_SIZE * 2 + 1]; \ | ||
1133 | } skey; \ | ||
1134 | struct DigestAlgorithm da; \ | ||
1135 | \ | ||
1136 | switch (algo) { \ | ||
1137 | case MHD_DIGEST_ALG_MD5: \ | ||
1138 | da.digest_size = MD5_DIGEST_SIZE; \ | ||
1139 | da.ctx = &ctx.md5; \ | ||
1140 | da.alg = "md5"; \ | ||
1141 | da.sessionkey = skey.md5; \ | ||
1142 | da.init = &MD5Init; \ | ||
1143 | da.update = &MD5Update; \ | ||
1144 | da.digest = &MD5Final; \ | ||
1145 | break; \ | ||
1146 | case MHD_DIGEST_ALG_AUTO: \ | ||
1147 | /* auto == SHA256, fall-though thus intentional! */ \ | ||
1148 | case MHD_DIGEST_ALG_SHA256: \ | ||
1149 | da.digest_size = SHA256_DIGEST_SIZE; \ | ||
1150 | da.ctx = &ctx.sha256; \ | ||
1151 | da.alg = "sha-256"; \ | ||
1152 | da.sessionkey = skey.sha256; \ | ||
1153 | da.init = &sha256_init; \ | ||
1154 | da.update = &sha256_update; \ | ||
1155 | da.digest = &sha256_digest; \ | ||
1156 | break; \ | ||
1157 | } | ||
1158 | |||
1159 | |||
1160 | |||
1161 | /** | ||
1162 | * Authenticates the authorization header sent by the client. | ||
1163 | * | ||
1164 | * @param connection The MHD connection structure | ||
1165 | * @param realm The realm presented to the client | ||
1166 | * @param username The username needs to be authenticated | ||
1167 | * @param password The password used in the authentication | ||
1168 | * @param nonce_timeout The amount of time for a nonce to be | ||
1169 | * invalid in seconds | ||
1170 | * @param algo digest algorithms allowed for verification | ||
1171 | * @return #MHD_YES if authenticated, #MHD_NO if not, | ||
1172 | * #MHD_INVALID_NONCE if nonce is invalid | ||
1173 | * @ingroup authentication | ||
1174 | */ | ||
1175 | _MHD_EXTERN int | ||
1176 | MHD_digest_auth_check2 (struct MHD_Connection *connection, | ||
1177 | const char *realm, | ||
1178 | const char *username, | ||
1179 | const char *password, | ||
1180 | unsigned int nonce_timeout, | ||
1181 | enum MHD_DigestAuthAlgorithm algo) | ||
1182 | { | ||
1183 | SETUP_DA (algo, da); | ||
1184 | |||
1021 | return digest_auth_check_all (connection, | 1185 | return digest_auth_check_all (connection, |
1186 | &da, | ||
1022 | realm, | 1187 | realm, |
1023 | username, | 1188 | username, |
1024 | password, | 1189 | password, |
@@ -1028,7 +1193,7 @@ MHD_digest_auth_check (struct MHD_Connection *connection, | |||
1028 | 1193 | ||
1029 | 1194 | ||
1030 | /** | 1195 | /** |
1031 | * Authenticates the authorization header sent by the client | 1196 | * Authenticates the authorization header sent by the client. |
1032 | * | 1197 | * |
1033 | * @param connection The MHD connection structure | 1198 | * @param connection The MHD connection structure |
1034 | * @param realm The realm presented to the client | 1199 | * @param realm The realm presented to the client |
@@ -1036,20 +1201,29 @@ MHD_digest_auth_check (struct MHD_Connection *connection, | |||
1036 | * @param digest An `unsigned char *' pointer to the binary MD5 sum | 1201 | * @param digest An `unsigned char *' pointer to the binary MD5 sum |
1037 | * for the precalculated hash value "username:realm:password" | 1202 | * for the precalculated hash value "username:realm:password" |
1038 | * of #MHD_MD5_DIGEST_SIZE bytes | 1203 | * of #MHD_MD5_DIGEST_SIZE bytes |
1204 | * @param digest_size number of bytes in @a digest | ||
1039 | * @param nonce_timeout The amount of time for a nonce to be | 1205 | * @param nonce_timeout The amount of time for a nonce to be |
1040 | * invalid in seconds | 1206 | * invalid in seconds |
1207 | * @param algo digest algorithms allowed for verification | ||
1041 | * @return #MHD_YES if authenticated, #MHD_NO if not, | 1208 | * @return #MHD_YES if authenticated, #MHD_NO if not, |
1042 | * #MHD_INVALID_NONCE if nonce is invalid | 1209 | * #MHD_INVALID_NONCE if nonce is invalid |
1043 | * @ingroup authentication | 1210 | * @ingroup authentication |
1044 | */ | 1211 | */ |
1045 | _MHD_EXTERN int | 1212 | _MHD_EXTERN int |
1046 | MHD_digest_auth_check_digest (struct MHD_Connection *connection, | 1213 | MHD_digest_auth_check_digest2 (struct MHD_Connection *connection, |
1047 | const char *realm, | 1214 | const char *realm, |
1048 | const char *username, | 1215 | const char *username, |
1049 | const uint8_t digest[MD5_DIGEST_SIZE], | 1216 | const uint8_t *digest, |
1050 | unsigned int nonce_timeout) | 1217 | size_t digest_size, |
1218 | unsigned int nonce_timeout, | ||
1219 | enum MHD_DigestAuthAlgorithm algo) | ||
1051 | { | 1220 | { |
1221 | SETUP_DA (algo, da); | ||
1222 | |||
1223 | if (da.digest_size != digest_size) | ||
1224 | MHD_PANIC (_("digest size missmatch")); /* API violation! */ | ||
1052 | return digest_auth_check_all (connection, | 1225 | return digest_auth_check_all (connection, |
1226 | &da, | ||
1053 | realm, | 1227 | realm, |
1054 | username, | 1228 | username, |
1055 | NULL, | 1229 | NULL, |
@@ -1059,6 +1233,40 @@ MHD_digest_auth_check_digest (struct MHD_Connection *connection, | |||
1059 | 1233 | ||
1060 | 1234 | ||
1061 | /** | 1235 | /** |
1236 | * Authenticates the authorization header sent by the client. | ||
1237 | * Uses #MHD_DIGEST_ALG_MD5 (required, as @a digest is of fixed | ||
1238 | * size). | ||
1239 | * | ||
1240 | * @param connection The MHD connection structure | ||
1241 | * @param realm The realm presented to the client | ||
1242 | * @param username The username needs to be authenticated | ||
1243 | * @param digest An `unsigned char *' pointer to the binary digest | ||
1244 | * for the precalculated hash value "username:realm:password" | ||
1245 | * of @a digest_size bytes | ||
1246 | * @param nonce_timeout The amount of time for a nonce to be | ||
1247 | * invalid in seconds | ||
1248 | * @return #MHD_YES if authenticated, #MHD_NO if not, | ||
1249 | * #MHD_INVALID_NONCE if nonce is invalid | ||
1250 | * @ingroup authentication | ||
1251 | */ | ||
1252 | _MHD_EXTERN int | ||
1253 | MHD_digest_auth_check_digest (struct MHD_Connection *connection, | ||
1254 | const char *realm, | ||
1255 | const char *username, | ||
1256 | const uint8_t digest[MHD_MD5_DIGEST_SIZE], | ||
1257 | unsigned int nonce_timeout) | ||
1258 | { | ||
1259 | return MHD_digest_auth_check_digest2 (connection, | ||
1260 | realm, | ||
1261 | username, | ||
1262 | digest, | ||
1263 | MHD_MD5_DIGEST_SIZE, | ||
1264 | nonce_timeout, | ||
1265 | MHD_DIGEST_ALG_MD5); | ||
1266 | } | ||
1267 | |||
1268 | |||
1269 | /** | ||
1062 | * Queues a response to request authentication from the client | 1270 | * Queues a response to request authentication from the client |
1063 | * | 1271 | * |
1064 | * @param connection The MHD connection structure | 1272 | * @param connection The MHD connection structure |
@@ -1069,81 +1277,90 @@ MHD_digest_auth_check_digest (struct MHD_Connection *connection, | |||
1069 | * header and that the caller should not do this | 1277 | * header and that the caller should not do this |
1070 | * @param signal_stale #MHD_YES if the nonce is invalid to add | 1278 | * @param signal_stale #MHD_YES if the nonce is invalid to add |
1071 | * 'stale=true' to the authentication header | 1279 | * 'stale=true' to the authentication header |
1280 | * @param algo digest algorithm to use | ||
1072 | * @return #MHD_YES on success, #MHD_NO otherwise | 1281 | * @return #MHD_YES on success, #MHD_NO otherwise |
1073 | * @ingroup authentication | 1282 | * @ingroup authentication |
1074 | */ | 1283 | */ |
1075 | int | 1284 | int |
1076 | MHD_queue_auth_fail_response (struct MHD_Connection *connection, | 1285 | MHD_queue_auth_fail_response2 (struct MHD_Connection *connection, |
1077 | const char *realm, | 1286 | const char *realm, |
1078 | const char *opaque, | 1287 | const char *opaque, |
1079 | struct MHD_Response *response, | 1288 | struct MHD_Response *response, |
1080 | int signal_stale) | 1289 | int signal_stale, |
1290 | enum MHD_DigestAuthAlgorithm algo) | ||
1081 | { | 1291 | { |
1082 | int ret; | 1292 | int ret; |
1083 | int hlen; | 1293 | int hlen; |
1084 | char nonce[NONCE_STD_LEN + 1]; | 1294 | SETUP_DA (algo, da); |
1085 | 1295 | ||
1086 | /* Generating the server nonce */ | 1296 | { |
1087 | calculate_nonce ((uint32_t) MHD_monotonic_sec_counter(), | 1297 | char nonce[NONCE_STD_LEN(da.digest_size) + 1]; |
1088 | connection->method, | 1298 | /* Generating the server nonce */ |
1089 | connection->daemon->digest_auth_random, | 1299 | calculate_nonce ((uint32_t) MHD_monotonic_sec_counter(), |
1090 | connection->daemon->digest_auth_rand_size, | 1300 | connection->method, |
1091 | connection->url, | 1301 | connection->daemon->digest_auth_random, |
1092 | realm, | 1302 | connection->daemon->digest_auth_rand_size, |
1093 | nonce); | 1303 | connection->url, |
1094 | if (MHD_YES != | 1304 | realm, |
1095 | check_nonce_nc (connection, | 1305 | &da, |
1096 | nonce, | 1306 | nonce); |
1097 | 0)) | 1307 | if (MHD_YES != |
1098 | { | 1308 | check_nonce_nc (connection, |
1309 | nonce, | ||
1310 | 0)) | ||
1311 | { | ||
1099 | #ifdef HAVE_MESSAGES | 1312 | #ifdef HAVE_MESSAGES |
1100 | MHD_DLOG (connection->daemon, | 1313 | MHD_DLOG (connection->daemon, |
1101 | _("Could not register nonce (is the nonce array size zero?).\n")); | 1314 | _("Could not register nonce (is the nonce array size zero?).\n")); |
1102 | #endif | 1315 | #endif |
1103 | return MHD_NO; | 1316 | return MHD_NO; |
1104 | } | 1317 | } |
1105 | /* Building the authentication header */ | 1318 | /* Building the authentication header */ |
1106 | hlen = MHD_snprintf_ (NULL, | 1319 | hlen = MHD_snprintf_ (NULL, |
1107 | 0, | 1320 | 0, |
1108 | "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s", | 1321 | "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\",algorithm=%s%s", |
1109 | realm, | 1322 | realm, |
1110 | nonce, | 1323 | nonce, |
1111 | opaque, | 1324 | opaque, |
1112 | signal_stale | 1325 | da.alg, |
1113 | ? ",stale=\"true\"" | 1326 | signal_stale |
1114 | : ""); | 1327 | ? ",stale=\"true\"" |
1115 | if (hlen > 0) | 1328 | : ""); |
1116 | { | 1329 | if (hlen > 0) |
1117 | char *header; | 1330 | { |
1331 | char *header; | ||
1118 | 1332 | ||
1119 | header = MHD_calloc_ (1, hlen + 1); | 1333 | header = MHD_calloc_ (1, |
1120 | if (NULL == header) | 1334 | hlen + 1); |
1121 | { | 1335 | if (NULL == header) |
1336 | { | ||
1122 | #ifdef HAVE_MESSAGES | 1337 | #ifdef HAVE_MESSAGES |
1123 | MHD_DLOG(connection->daemon, | 1338 | MHD_DLOG(connection->daemon, |
1124 | _("Failed to allocate memory for auth response header\n")); | 1339 | _("Failed to allocate memory for auth response header\n")); |
1125 | #endif /* HAVE_MESSAGES */ | 1340 | #endif /* HAVE_MESSAGES */ |
1126 | return MHD_NO; | 1341 | return MHD_NO; |
1127 | } | 1342 | } |
1128 | 1343 | ||
1129 | if (MHD_snprintf_ (header, | 1344 | if (MHD_snprintf_ (header, |
1130 | hlen + 1, | 1345 | hlen + 1, |
1131 | "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s", | 1346 | "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\",algorithm=%s%s", |
1132 | realm, | 1347 | realm, |
1133 | nonce, | 1348 | nonce, |
1134 | opaque, | 1349 | opaque, |
1135 | signal_stale | 1350 | da.alg, |
1136 | ? ",stale=\"true\"" | 1351 | signal_stale |
1137 | : "") == hlen) | 1352 | ? ",stale=\"true\"" |
1138 | ret = MHD_add_response_header(response, | 1353 | : "") == hlen) |
1139 | MHD_HTTP_HEADER_WWW_AUTHENTICATE, | 1354 | ret = MHD_add_response_header(response, |
1140 | header); | 1355 | MHD_HTTP_HEADER_WWW_AUTHENTICATE, |
1141 | else | 1356 | header); |
1142 | ret = MHD_NO; | 1357 | else |
1143 | free (header); | 1358 | ret = MHD_NO; |
1144 | } | 1359 | free (header); |
1145 | else | 1360 | } |
1146 | ret = MHD_NO; | 1361 | else |
1362 | ret = MHD_NO; | ||
1363 | } | ||
1147 | 1364 | ||
1148 | if (MHD_YES == ret) | 1365 | if (MHD_YES == ret) |
1149 | { | 1366 | { |
@@ -1162,4 +1379,36 @@ MHD_queue_auth_fail_response (struct MHD_Connection *connection, | |||
1162 | } | 1379 | } |
1163 | 1380 | ||
1164 | 1381 | ||
1382 | /** | ||
1383 | * Queues a response to request authentication from the client. | ||
1384 | * For now uses MD5 (for backwards-compatibility). Still, if you | ||
1385 | * need to be sure, use #MHD_queue_fail_auth_response2(). | ||
1386 | * | ||
1387 | * @param connection The MHD connection structure | ||
1388 | * @param realm the realm presented to the client | ||
1389 | * @param opaque string to user for opaque value | ||
1390 | * @param response reply to send; should contain the "access denied" | ||
1391 | * body; note that this function will set the "WWW Authenticate" | ||
1392 | * header and that the caller should not do this | ||
1393 | * @param signal_stale #MHD_YES if the nonce is invalid to add | ||
1394 | * 'stale=true' to the authentication header | ||
1395 | * @return #MHD_YES on success, #MHD_NO otherwise | ||
1396 | * @ingroup authentication | ||
1397 | */ | ||
1398 | int | ||
1399 | MHD_queue_auth_fail_response (struct MHD_Connection *connection, | ||
1400 | const char *realm, | ||
1401 | const char *opaque, | ||
1402 | struct MHD_Response *response, | ||
1403 | int signal_stale) | ||
1404 | { | ||
1405 | return MHD_queue_auth_fail_response2 (connection, | ||
1406 | realm, | ||
1407 | opaque, | ||
1408 | response, | ||
1409 | signal_stale, | ||
1410 | MHD_DIGEST_ALG_MD5); | ||
1411 | } | ||
1412 | |||
1413 | |||
1165 | /* end of digestauth.c */ | 1414 | /* end of digestauth.c */ |