diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2022-05-23 17:25:34 +0300 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2022-05-23 17:25:34 +0300 |
commit | d73c6d20e301775597feea322416e475262a9558 (patch) | |
tree | 1ef14ba658a5b5f33dbd1c126fc34fc6c42b4f6b /src/microhttpd/digestauth.c | |
parent | 4a4d659bac5040c7f7538e28535b4baaa1529ba8 (diff) | |
download | libmicrohttpd-d73c6d20e301775597feea322416e475262a9558.tar.gz libmicrohttpd-d73c6d20e301775597feea322416e475262a9558.zip |
digestauth: reworked support for multiple digest algorithms
Diffstat (limited to 'src/microhttpd/digestauth.c')
-rw-r--r-- | src/microhttpd/digestauth.c | 639 |
1 files changed, 380 insertions, 259 deletions
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c index a560f2a6..7ac5ad8b 100644 --- a/src/microhttpd/digestauth.c +++ b/src/microhttpd/digestauth.c | |||
@@ -175,74 +175,261 @@ enum MHD_CheckNonceNC_ | |||
175 | 175 | ||
176 | 176 | ||
177 | /** | 177 | /** |
178 | * Context passed to functions that need to calculate | 178 | * Digest context data |
179 | * a digest but are orthogonal to the specific | ||
180 | * algorithm. | ||
181 | */ | 179 | */ |
182 | struct DigestAlgorithm | 180 | union DigestCtx |
183 | { | 181 | { |
184 | /** | 182 | struct MD5Context md5_ctx; |
185 | * Size of the final digest returned by @e digest. | 183 | struct Sha256Ctx sha256_ctx; |
186 | */ | 184 | }; |
187 | unsigned int digest_size; | 185 | |
186 | /** | ||
187 | * Digest printed as hex digits. | ||
188 | */ | ||
189 | union DigestHex | ||
190 | { | ||
191 | char md5[MD5_DIGEST_STRING_LENGTH]; | ||
192 | char sha256[SHA256_DIGEST_STRING_SIZE]; | ||
193 | }; | ||
194 | |||
195 | /** | ||
196 | * Digest in binary form. | ||
197 | */ | ||
198 | union DigestBin | ||
199 | { | ||
200 | uint8_t md5[MD5_DIGEST_SIZE]; | ||
201 | uint8_t sha256[SHA256_DIGEST_SIZE]; | ||
202 | }; | ||
188 | 203 | ||
204 | /** | ||
205 | * The digest calculation structure. | ||
206 | */ | ||
207 | struct DigestAlgorithm | ||
208 | { | ||
189 | /** | 209 | /** |
190 | * A context for the digest algorithm, already initialized to be | 210 | * A context for the digest algorithm, already initialized to be |
191 | * useful for @e init, @e update and @e digest. | 211 | * useful for @e init, @e update and @e digest. |
192 | */ | 212 | */ |
193 | void *ctx; | 213 | union DigestCtx ctx; |
194 | 214 | ||
195 | /** | 215 | /** |
196 | * Name of the algorithm, "MD5" or "SHA-256". | 216 | * Digest in binary form. |
197 | * @sa #_MHD_MD5_TOKEN, #_MHD_SHA256_TOKEN | ||
198 | */ | 217 | */ |
199 | const char *alg; | 218 | union DigestBin digest; |
200 | |||
201 | /** | 219 | /** |
202 | * Buffer of @e digest_size * 2 + 1 bytes. | 220 | * The digest algorithm. |
203 | */ | 221 | */ |
204 | char *sessionkey; | 222 | enum MHD_DigestAuthAlgorithm algo; |
205 | 223 | ||
206 | /** | 224 | /** |
207 | * Call to initialize @e ctx. | 225 | * Buffer for hex-print of the final digest. |
208 | */ | 226 | */ |
209 | void | 227 | union DigestHex digest_hex; |
210 | (*init)(void *ctx); | 228 | #if _DEBUG |
229 | bool setup; /**< The structure was set-up */ | ||
230 | bool inited; /**< The calculation was initialised */ | ||
231 | bool digest_calculated; /**< The digest was calculated */ | ||
232 | #endif /* _DEBUG */ | ||
233 | }; | ||
211 | 234 | ||
212 | /** | ||
213 | * Feed more data into the digest function. | ||
214 | * | ||
215 | * @param ctx context to feed | ||
216 | * @param length number of bytes in @a data | ||
217 | * @param data data to add | ||
218 | */ | ||
219 | void | ||
220 | (*update)(void *ctx, | ||
221 | const uint8_t *data, | ||
222 | size_t length); | ||
223 | 235 | ||
224 | /** | 236 | /** |
225 | * Compute final @a digest. | 237 | * Return name of the algorithm as a string. |
226 | * | 238 | * @param da the digest calculation structure to identify |
227 | * @param ctx context to use | 239 | * @return the name of the @a algo as a string. |
228 | * @param[out] digest where to write the result, | 240 | */ |
229 | * must be @e digest_length bytes long | 241 | _MHD_static_inline const char * |
230 | */ | 242 | digest_get_algo_name (struct DigestAlgorithm *da) |
231 | void | 243 | { |
232 | (*digest)(void *ctx, | 244 | mhd_assert (da->setup); |
233 | uint8_t *digest); | 245 | if (MHD_DIGEST_ALG_MD5 == da->algo) |
234 | }; | 246 | return _MHD_MD5_TOKEN; |
247 | if (MHD_DIGEST_ALG_SHA256 == da->algo) | ||
248 | return _MHD_SHA256_TOKEN; | ||
249 | mhd_assert (0); /* May not happen */ | ||
250 | return ""; | ||
251 | } | ||
252 | |||
253 | |||
254 | /** | ||
255 | * Return the size of the digest. | ||
256 | * @param da the digest calculation structure to identify | ||
257 | * @return the size of the digest. | ||
258 | */ | ||
259 | _MHD_static_inline unsigned int | ||
260 | digest_get_size (struct DigestAlgorithm *da) | ||
261 | { | ||
262 | mhd_assert (da->setup); | ||
263 | if (MHD_DIGEST_ALG_MD5 == da->algo) | ||
264 | return MD5_DIGEST_SIZE; | ||
265 | if (MHD_DIGEST_ALG_SHA256 == da->algo) | ||
266 | return SHA256_DIGEST_SIZE; | ||
267 | mhd_assert (0); /* May not happen */ | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | |||
272 | /** | ||
273 | * Set-up the digest calculation structure. | ||
274 | * @param da the structure to set-up | ||
275 | * @param algo the algorithm to use for digest calculation | ||
276 | * @return boolean 'true' if successfully set-up, | ||
277 | * false otherwise. | ||
278 | */ | ||
279 | _MHD_static_inline bool | ||
280 | digest_setup (struct DigestAlgorithm *da, | ||
281 | enum MHD_DigestAuthAlgorithm algo) | ||
282 | { | ||
283 | #ifdef _DEBUG | ||
284 | da->setup = false; | ||
285 | da->inited = false; | ||
286 | da->digest_calculated = false; | ||
287 | #endif /* _DEBUG */ | ||
288 | if (MHD_DIGEST_ALG_AUTO == algo) | ||
289 | algo = MHD_DIGEST_ALG_SHA256; | ||
290 | |||
291 | if ((MHD_DIGEST_ALG_MD5 == algo) || | ||
292 | (MHD_DIGEST_ALG_SHA256 == algo)) | ||
293 | { | ||
294 | da->algo = algo; | ||
295 | #ifdef _DEBUG | ||
296 | da->setup = true; | ||
297 | #endif /* _DEBUG */ | ||
298 | return true; | ||
299 | } | ||
300 | mhd_assert (0); /* Bad parameter */ | ||
301 | return false; | ||
302 | } | ||
303 | |||
304 | |||
305 | /** | ||
306 | * Initialise/reset the digest calculation structure. | ||
307 | * @param da the structure to initialise/reset | ||
308 | */ | ||
309 | _MHD_static_inline void | ||
310 | digest_init (struct DigestAlgorithm *da) | ||
311 | { | ||
312 | mhd_assert (da->setup); | ||
313 | #ifdef _DEBUG | ||
314 | da->digest_calculated = false; | ||
315 | #endif | ||
316 | if (MHD_DIGEST_ALG_MD5 == da->algo) | ||
317 | { | ||
318 | MHD_MD5Init (&da->ctx.md5_ctx); | ||
319 | #ifdef _DEBUG | ||
320 | da->inited = true; | ||
321 | #endif | ||
322 | } | ||
323 | else if (MHD_DIGEST_ALG_SHA256 == da->algo) | ||
324 | { | ||
325 | MHD_SHA256_init (&da->ctx.sha256_ctx); | ||
326 | #ifdef _DEBUG | ||
327 | da->inited = true; | ||
328 | #endif | ||
329 | } | ||
330 | else | ||
331 | { | ||
332 | #ifdef _DEBUG | ||
333 | da->inited = false; | ||
334 | #endif | ||
335 | mhd_assert (0); /* Bad algorithm */ | ||
336 | } | ||
337 | } | ||
338 | |||
339 | |||
340 | /** | ||
341 | * Feed digest calculation with more data. | ||
342 | * @param da the digest calculation | ||
343 | * @param data the data to process | ||
344 | * @param length the size of the @a data in bytes | ||
345 | */ | ||
346 | _MHD_static_inline void | ||
347 | digest_update (struct DigestAlgorithm *da, | ||
348 | const uint8_t *data, | ||
349 | size_t length) | ||
350 | { | ||
351 | mhd_assert (da->inited); | ||
352 | mhd_assert (! da->digest_calculated); | ||
353 | if (MHD_DIGEST_ALG_MD5 == da->algo) | ||
354 | MHD_MD5Update (&da->ctx.md5_ctx, data, length); | ||
355 | else if (MHD_DIGEST_ALG_SHA256 == da->algo) | ||
356 | MHD_SHA256_update (&da->ctx.sha256_ctx, data, length); | ||
357 | else | ||
358 | mhd_assert (0); /* May not happen */ | ||
359 | } | ||
360 | |||
361 | |||
362 | /** | ||
363 | * Finally calculate hash (the digest). | ||
364 | * @param da the digest calculation | ||
365 | */ | ||
366 | _MHD_static_inline void | ||
367 | digest_calc_hash (struct DigestAlgorithm *da) | ||
368 | { | ||
369 | mhd_assert (da->inited); | ||
370 | mhd_assert (! da->digest_calculated); | ||
371 | if (MHD_DIGEST_ALG_MD5 == da->algo) | ||
372 | MHD_MD5Final (&da->ctx.md5_ctx, da->digest.md5); | ||
373 | else if (MHD_DIGEST_ALG_SHA256 == da->algo) | ||
374 | MHD_SHA256_finish (&da->ctx.sha256_ctx, da->digest.sha256); | ||
375 | else | ||
376 | mhd_assert (0); /* May not happen */ | ||
377 | #ifdef _DEBUG | ||
378 | da->digest_calculated = true; | ||
379 | #endif | ||
380 | } | ||
381 | |||
382 | |||
383 | /** | ||
384 | * Get pointer to the calculated digest in binary form. | ||
385 | * @param da the digest calculation | ||
386 | * @return the pointer to the calculated digest | ||
387 | */ | ||
388 | _MHD_static_inline const uint8_t * | ||
389 | digest_get_bin (struct DigestAlgorithm *da) | ||
390 | { | ||
391 | mhd_assert (da->inited); | ||
392 | mhd_assert (da->digest_calculated); | ||
393 | mhd_assert (da->digest.md5 == da->digest.sha256); | ||
394 | return da->digest.sha256; | ||
395 | } | ||
396 | |||
397 | |||
398 | /** | ||
399 | * Get pointer to the buffer for the printed digest. | ||
400 | * @param da the digest calculation | ||
401 | * @return the pointer to the buffer | ||
402 | */ | ||
403 | _MHD_static_inline char * | ||
404 | digest_get_hex_buffer (struct DigestAlgorithm *da) | ||
405 | { | ||
406 | return da->digest_hex.sha256; | ||
407 | } | ||
408 | |||
409 | |||
410 | /** | ||
411 | * Put calculated digest to the buffer as hex digits. | ||
412 | * @param da the digest calculation | ||
413 | * @return the pointer to the calculated digest | ||
414 | */ | ||
415 | _MHD_static_inline void | ||
416 | digest_make_hex (struct DigestAlgorithm *da) | ||
417 | { | ||
418 | MHD_bin_to_hex (digest_get_bin (da), | ||
419 | digest_get_size (da), | ||
420 | digest_get_hex_buffer (da)); | ||
421 | } | ||
235 | 422 | ||
236 | 423 | ||
237 | /** | 424 | /** |
238 | * calculate H(A1) from given hash as per RFC2617 spec | 425 | * calculate H(A1) from given hash as per RFC2617 spec |
239 | * and store the * result in 'sessionkey'. | 426 | * and store the result in 'digest_hex'. |
240 | * | 427 | * |
241 | * @param alg The hash algorithm used, can be "MD5" or "MD5-sess" | 428 | * @param alg The hash algorithm used, can be "MD5" or "MD5-sess" |
242 | * or "SHA-256" or "SHA-256-sess" | 429 | * or "SHA-256" or "SHA-256-sess" |
243 | * Note that the rest of the code does not support the the "-sess" variants! | 430 | * Note that the rest of the code does not support the the "-sess" variants! |
244 | * @param[in,out] da digest implementation, must match @a alg; the | 431 | * @param[in,out] da digest implementation, must match @a alg; the |
245 | * da->sessionkey will be initialized to the digest in HEX | 432 | * da->digest_hex will be initialized to the digest in HEX |
246 | * @param digest An `unsigned char *' pointer to the binary MD5 sum | 433 | * @param digest An `unsigned char *' pointer to the binary MD5 sum |
247 | * for the precalculated hash value "username:realm:password" | 434 | * for the precalculated hash value "username:realm:password" |
248 | * of #MHD_MD5_DIGEST_SIZE or #SHA256_DIGEST_SIZE bytes | 435 | * of #MHD_MD5_DIGEST_SIZE or #SHA256_DIGEST_SIZE bytes |
@@ -256,49 +443,43 @@ digest_calc_ha1_from_digest (const char *alg, | |||
256 | const char *nonce, | 443 | const char *nonce, |
257 | const char *cnonce) | 444 | const char *cnonce) |
258 | { | 445 | { |
259 | const unsigned int digest_size = da->digest_size; | 446 | /* TODO: disable unsupported code paths */ |
260 | if ( (MHD_str_equal_caseless_ (alg, | 447 | if ( (MHD_str_equal_caseless_ (alg, |
261 | _MHD_MD5_TOKEN _MHD_SESS_TOKEN)) || | 448 | _MHD_MD5_TOKEN _MHD_SESS_TOKEN)) || |
262 | (MHD_str_equal_caseless_ (alg, | 449 | (MHD_str_equal_caseless_ (alg, |
263 | _MHD_SHA256_TOKEN _MHD_SESS_TOKEN)) ) | 450 | _MHD_SHA256_TOKEN _MHD_SESS_TOKEN)) ) |
264 | { | 451 | { |
265 | uint8_t dig[VLA_ARRAY_LEN_DIGEST (digest_size)]; | 452 | digest_init (da); |
266 | 453 | digest_update (da, | |
267 | VLA_CHECK_LEN_DIGEST (digest_size); | 454 | digest, |
268 | da->init (da->ctx); | 455 | digest_get_size (da)); |
269 | da->update (da->ctx, | 456 | digest_update (da, |
270 | digest, | 457 | (const unsigned char *) ":", |
271 | MHD_MD5_DIGEST_SIZE); | 458 | 1); |
272 | da->update (da->ctx, | 459 | digest_update (da, |
273 | (const unsigned char *) ":", | 460 | (const unsigned char *) nonce, |
274 | 1); | 461 | strlen (nonce)); |
275 | da->update (da->ctx, | 462 | digest_update (da, |
276 | (const unsigned char *) nonce, | 463 | (const unsigned char *) ":", |
277 | strlen (nonce)); | 464 | 1); |
278 | da->update (da->ctx, | 465 | digest_update (da, |
279 | (const unsigned char *) ":", | 466 | (const unsigned char *) cnonce, |
280 | 1); | 467 | strlen (cnonce)); |
281 | da->update (da->ctx, | 468 | digest_calc_hash (da); |
282 | (const unsigned char *) cnonce, | 469 | digest_make_hex (da); |
283 | strlen (cnonce)); | ||
284 | da->digest (da->ctx, | ||
285 | dig); | ||
286 | MHD_bin_to_hex (dig, | ||
287 | digest_size, | ||
288 | da->sessionkey); | ||
289 | } | 470 | } |
290 | else | 471 | else |
291 | { | 472 | { |
292 | MHD_bin_to_hex (digest, | 473 | MHD_bin_to_hex (digest, |
293 | digest_size, | 474 | digest_get_size (da), |
294 | da->sessionkey); | 475 | digest_get_hex_buffer (da)); |
295 | } | 476 | } |
296 | } | 477 | } |
297 | 478 | ||
298 | 479 | ||
299 | /** | 480 | /** |
300 | * calculate H(A1) from username, realm and password as per RFC2617 spec | 481 | * calculate H(A1) from username, realm and password as per RFC2617 spec |
301 | * and store the result in 'sessionkey'. | 482 | * and store the result in 'digest_hex'. |
302 | * | 483 | * |
303 | * @param alg The hash algorithm used, can be "MD5" or "MD5-sess" | 484 | * @param alg The hash algorithm used, can be "MD5" or "MD5-sess" |
304 | * or "SHA-256" or "SHA-256-sess" | 485 | * or "SHA-256" or "SHA-256-sess" |
@@ -319,30 +500,26 @@ digest_calc_ha1_from_user (const char *alg, | |||
319 | const char *cnonce, | 500 | const char *cnonce, |
320 | struct DigestAlgorithm *da) | 501 | struct DigestAlgorithm *da) |
321 | { | 502 | { |
322 | unsigned char ha1[VLA_ARRAY_LEN_DIGEST (da->digest_size)]; | 503 | digest_init (da); |
323 | 504 | digest_update (da, | |
324 | VLA_CHECK_LEN_DIGEST (da->digest_size); | 505 | (const unsigned char *) username, |
325 | da->init (da->ctx); | 506 | strlen (username)); |
326 | da->update (da->ctx, | 507 | digest_update (da, |
327 | (const unsigned char *) username, | 508 | (const unsigned char *) ":", |
328 | strlen (username)); | 509 | 1); |
329 | da->update (da->ctx, | 510 | digest_update (da, |
330 | (const unsigned char *) ":", | 511 | (const unsigned char *) realm, |
331 | 1); | 512 | strlen (realm)); |
332 | da->update (da->ctx, | 513 | digest_update (da, |
333 | (const unsigned char *) realm, | 514 | (const unsigned char *) ":", |
334 | strlen (realm)); | 515 | 1); |
335 | da->update (da->ctx, | 516 | digest_update (da, |
336 | (const unsigned char *) ":", | 517 | (const unsigned char *) password, |
337 | 1); | 518 | strlen (password)); |
338 | da->update (da->ctx, | 519 | digest_calc_hash (da); |
339 | (const unsigned char *) password, | ||
340 | strlen (password)); | ||
341 | da->digest (da->ctx, | ||
342 | ha1); | ||
343 | digest_calc_ha1_from_digest (alg, | 520 | digest_calc_ha1_from_digest (alg, |
344 | da, | 521 | da, |
345 | ha1, | 522 | digest_get_bin (da), |
346 | nonce, | 523 | nonce, |
347 | cnonce); | 524 | cnonce); |
348 | } | 525 | } |
@@ -375,85 +552,78 @@ digest_calc_response (const char *ha1, | |||
375 | const char *hentity, | 552 | const char *hentity, |
376 | struct DigestAlgorithm *da) | 553 | struct DigestAlgorithm *da) |
377 | { | 554 | { |
378 | const unsigned int digest_size = da->digest_size; | ||
379 | unsigned char ha2[VLA_ARRAY_LEN_DIGEST (digest_size)]; | ||
380 | unsigned char resphash[VLA_ARRAY_LEN_DIGEST (digest_size)]; | ||
381 | (void) hentity; /* Unused. Silence compiler warning. */ | 555 | (void) hentity; /* Unused. Silence compiler warning. */ |
382 | 556 | ||
383 | VLA_CHECK_LEN_DIGEST (digest_size); | 557 | /* Calculate h(a2) */ |
384 | da->init (da->ctx); | 558 | digest_init (da); |
385 | da->update (da->ctx, | 559 | digest_update (da, |
386 | (const unsigned char *) method, | 560 | (const unsigned char *) method, |
387 | strlen (method)); | 561 | strlen (method)); |
388 | da->update (da->ctx, | 562 | digest_update (da, |
389 | (const unsigned char *) ":", | 563 | (const unsigned char *) ":", |
390 | 1); | 564 | 1); |
391 | da->update (da->ctx, | 565 | digest_update (da, |
392 | (const unsigned char *) uri, | 566 | (const unsigned char *) uri, |
393 | strlen (uri)); | 567 | strlen (uri)); |
394 | #if 0 | 568 | #if 0 |
395 | if (0 == strcasecmp (qop, | 569 | if (0 == strcasecmp (qop, |
396 | "auth-int")) | 570 | "auth-int")) |
397 | { | 571 | { |
398 | /* This is dead code since the rest of this module does | 572 | /* This is dead code since the rest of this module does |
399 | not support auth-int. */ | 573 | not support auth-int. */ |
400 | da->update (da->ctx, | 574 | digest_update (da, |
401 | ":", | 575 | ":", |
402 | 1); | 576 | 1); |
403 | if (NULL != hentity) | 577 | if (NULL != hentity) |
404 | da->update (da->ctx, | 578 | da->update (da->ctx, |
405 | hentity, | 579 | hentity, |
406 | strlen (hentity)); | 580 | strlen (hentity)); |
407 | } | 581 | } |
408 | #endif | 582 | #endif |
409 | da->digest (da->ctx, | 583 | digest_calc_hash (da); |
410 | ha2); | 584 | digest_make_hex (da); |
411 | MHD_bin_to_hex (ha2, | 585 | |
412 | digest_size, | ||
413 | da->sessionkey); | ||
414 | da->init (da->ctx); | ||
415 | /* calculate response */ | 586 | /* calculate response */ |
416 | da->update (da->ctx, | 587 | digest_init (da); |
417 | (const unsigned char *) ha1, | 588 | digest_update (da, |
418 | digest_size * 2); | 589 | (const unsigned char *) ha1, |
419 | da->update (da->ctx, | 590 | digest_get_size (da) * 2); |
420 | (const unsigned char *) ":", | 591 | digest_update (da, |
421 | 1); | 592 | (const unsigned char *) ":", |
422 | da->update (da->ctx, | 593 | 1); |
423 | (const unsigned char *) nonce, | 594 | digest_update (da, |
424 | strlen (nonce)); | 595 | (const unsigned char *) nonce, |
425 | da->update (da->ctx, | 596 | strlen (nonce)); |
426 | (const unsigned char *) ":", | 597 | digest_update (da, |
427 | 1); | 598 | (const unsigned char *) ":", |
599 | 1); | ||
428 | if ('\0' != *qop) | 600 | if ('\0' != *qop) |
429 | { | 601 | { |
430 | da->update (da->ctx, | 602 | digest_update (da, |
431 | (const unsigned char *) noncecount, | 603 | (const unsigned char *) noncecount, |
432 | strlen (noncecount)); | 604 | strlen (noncecount)); |
433 | da->update (da->ctx, | 605 | digest_update (da, |
434 | (const unsigned char *) ":", | 606 | (const unsigned char *) ":", |
435 | 1); | 607 | 1); |
436 | da->update (da->ctx, | 608 | digest_update (da, |
437 | (const unsigned char *) cnonce, | 609 | (const unsigned char *) cnonce, |
438 | strlen (cnonce)); | 610 | strlen (cnonce)); |
439 | da->update (da->ctx, | 611 | digest_update (da, |
440 | (const unsigned char *) ":", | 612 | (const unsigned char *) ":", |
441 | 1); | 613 | 1); |
442 | da->update (da->ctx, | 614 | digest_update (da, |
443 | (const unsigned char *) qop, | 615 | (const unsigned char *) qop, |
444 | strlen (qop)); | 616 | strlen (qop)); |
445 | da->update (da->ctx, | 617 | digest_update (da, |
446 | (const unsigned char *) ":", | 618 | (const unsigned char *) ":", |
447 | 1); | 619 | 1); |
448 | } | 620 | } |
449 | da->update (da->ctx, | 621 | digest_update (da, |
450 | (const unsigned char *) da->sessionkey, | 622 | (const unsigned char *) digest_get_hex_buffer (da), |
451 | digest_size * 2); | 623 | digest_get_size (da) * 2); |
452 | da->digest (da->ctx, | 624 | |
453 | resphash); | 625 | digest_calc_hash (da); |
454 | MHD_bin_to_hex (resphash, | 626 | digest_make_hex (da); |
455 | digest_size, | ||
456 | da->sessionkey); | ||
457 | } | 627 | } |
458 | 628 | ||
459 | 629 | ||
@@ -828,13 +998,8 @@ calculate_nonce (uint64_t nonce_time, | |||
828 | char *nonce) | 998 | char *nonce) |
829 | { | 999 | { |
830 | uint8_t timestamp[TIMESTAMP_BIN_SIZE]; | 1000 | uint8_t timestamp[TIMESTAMP_BIN_SIZE]; |
831 | const unsigned int digest_size = da->digest_size; | ||
832 | char tmpnonce[VLA_ARRAY_LEN_DIGEST (digest_size)]; | ||
833 | 1001 | ||
834 | mhd_assert (0 == (digest_size % 2)); | 1002 | digest_init (da); |
835 | mhd_assert (0 != digest_size); | ||
836 | VLA_CHECK_LEN_DIGEST (digest_size); | ||
837 | da->init (da->ctx); | ||
838 | /* If the nonce_time is milliseconds, then the same 48 bit value will repeat | 1003 | /* If the nonce_time is milliseconds, then the same 48 bit value will repeat |
839 | * every 8 925 years, which is more than enough to mitigate a replay attack */ | 1004 | * every 8 925 years, which is more than enough to mitigate a replay attack */ |
840 | #if TIMESTAMP_BIN_SIZE != 6 | 1005 | #if TIMESTAMP_BIN_SIZE != 6 |
@@ -846,42 +1011,41 @@ calculate_nonce (uint64_t nonce_time, | |||
846 | timestamp[3] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 3))); | 1011 | timestamp[3] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 3))); |
847 | timestamp[4] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 4))); | 1012 | timestamp[4] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 4))); |
848 | timestamp[5] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 5))); | 1013 | timestamp[5] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 5))); |
849 | da->update (da->ctx, | 1014 | digest_update (da, |
850 | timestamp, | 1015 | timestamp, |
851 | sizeof (timestamp)); | 1016 | sizeof (timestamp)); |
852 | da->update (da->ctx, | 1017 | digest_update (da, |
853 | (const unsigned char *) ":", | 1018 | (const unsigned char *) ":", |
854 | 1); | 1019 | 1); |
855 | da->update (da->ctx, | 1020 | digest_update (da, |
856 | (const unsigned char *) method, | 1021 | (const unsigned char *) method, |
857 | strlen (method)); | 1022 | strlen (method)); |
858 | da->update (da->ctx, | 1023 | digest_update (da, |
859 | (const unsigned char *) ":", | 1024 | (const unsigned char *) ":", |
860 | 1); | 1025 | 1); |
861 | if (rnd_size > 0) | 1026 | if (rnd_size > 0) |
862 | da->update (da->ctx, | 1027 | digest_update (da, |
863 | (const unsigned char *) rnd, | 1028 | (const unsigned char *) rnd, |
864 | rnd_size); | 1029 | rnd_size); |
865 | da->update (da->ctx, | 1030 | digest_update (da, |
866 | (const unsigned char *) ":", | 1031 | (const unsigned char *) ":", |
867 | 1); | 1032 | 1); |
868 | da->update (da->ctx, | 1033 | digest_update (da, |
869 | (const unsigned char *) uri, | 1034 | (const unsigned char *) uri, |
870 | strlen (uri)); | 1035 | strlen (uri)); |
871 | da->update (da->ctx, | 1036 | digest_update (da, |
872 | (const unsigned char *) ":", | 1037 | (const unsigned char *) ":", |
873 | 1); | 1038 | 1); |
874 | da->update (da->ctx, | 1039 | digest_update (da, |
875 | (const unsigned char *) realm, | 1040 | (const unsigned char *) realm, |
876 | strlen (realm)); | 1041 | strlen (realm)); |
877 | da->digest (da->ctx, | 1042 | digest_calc_hash (da); |
878 | (uint8_t *) tmpnonce); | 1043 | MHD_bin_to_hex (digest_get_bin (da), |
879 | MHD_bin_to_hex (tmpnonce, | 1044 | digest_get_size (da), |
880 | digest_size, | ||
881 | nonce); | 1045 | nonce); |
882 | MHD_bin_to_hex (timestamp, | 1046 | MHD_bin_to_hex (timestamp, |
883 | sizeof (timestamp), | 1047 | sizeof (timestamp), |
884 | nonce + digest_size * 2); | 1048 | nonce + digest_get_size (da) * 2); |
885 | } | 1049 | } |
886 | 1050 | ||
887 | 1051 | ||
@@ -965,7 +1129,7 @@ calculate_add_nonce (struct MHD_Connection *const connection, | |||
965 | { | 1129 | { |
966 | struct MHD_Daemon *const daemon = MHD_get_master (connection->daemon); | 1130 | struct MHD_Daemon *const daemon = MHD_get_master (connection->daemon); |
967 | struct MHD_NonceNc *nn; | 1131 | struct MHD_NonceNc *nn; |
968 | const size_t nonce_size = NONCE_STD_LEN (da->digest_size); | 1132 | const size_t nonce_size = NONCE_STD_LEN (digest_get_size (da)); |
969 | bool ret; | 1133 | bool ret; |
970 | 1134 | ||
971 | mhd_assert (MAX_NONCE_LENGTH >= nonce_size); | 1135 | mhd_assert (MAX_NONCE_LENGTH >= nonce_size); |
@@ -1033,7 +1197,7 @@ calculate_add_nonce_with_retry (struct MHD_Connection *const connection, | |||
1033 | * 2. Another nonce uses the same slot, and this nonce never has been | 1197 | * 2. Another nonce uses the same slot, and this nonce never has been |
1034 | * used by the client and this nonce is still fresh enough. | 1198 | * used by the client and this nonce is still fresh enough. |
1035 | */ | 1199 | */ |
1036 | const size_t digest_size = da->digest_size; | 1200 | const size_t digest_size = digest_get_size (da); |
1037 | char nonce2[NONCE_STD_LEN (VLA_ARRAY_LEN_DIGEST (digest_size)) + 1]; | 1201 | char nonce2[NONCE_STD_LEN (VLA_ARRAY_LEN_DIGEST (digest_size)) + 1]; |
1038 | uint64_t timestamp2; | 1202 | uint64_t timestamp2; |
1039 | if (0 == MHD_get_master (connection->daemon)->nonce_nc_size) | 1203 | if (0 == MHD_get_master (connection->daemon)->nonce_nc_size) |
@@ -1216,7 +1380,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1216 | char nonce[MAX_NONCE_LENGTH]; | 1380 | char nonce[MAX_NONCE_LENGTH]; |
1217 | size_t nonce_len; | 1381 | size_t nonce_len; |
1218 | char cnonce[MAX_NONCE_LENGTH]; | 1382 | char cnonce[MAX_NONCE_LENGTH]; |
1219 | const unsigned int digest_size = da->digest_size; | 1383 | const unsigned int digest_size = digest_get_size (da); |
1220 | char ha1[VLA_ARRAY_LEN_DIGEST (digest_size) * 2 + 1]; | 1384 | char ha1[VLA_ARRAY_LEN_DIGEST (digest_size) * 2 + 1]; |
1221 | char qop[15]; /* auth,auth-int */ | 1385 | char qop[15]; /* auth,auth-int */ |
1222 | char nc[20]; | 1386 | char nc[20]; |
@@ -1441,8 +1605,8 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1441 | } | 1605 | } |
1442 | if (NULL != digest) | 1606 | if (NULL != digest) |
1443 | { | 1607 | { |
1444 | /* This will initialize da->sessionkey (ha1) */ | 1608 | /* This will initialize da->digest_hex (ha1) */ |
1445 | digest_calc_ha1_from_digest (da->alg, | 1609 | digest_calc_ha1_from_digest (digest_get_algo_name (da), |
1446 | da, | 1610 | da, |
1447 | digest, | 1611 | digest, |
1448 | nonce, | 1612 | nonce, |
@@ -1450,9 +1614,9 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1450 | } | 1614 | } |
1451 | else | 1615 | else |
1452 | { | 1616 | { |
1453 | /* This will initialize da->sessionkey (ha1) */ | 1617 | /* This will initialize da->digest_hex (ha1) */ |
1454 | mhd_assert (NULL != password); /* NULL == digest => password != NULL */ | 1618 | mhd_assert (NULL != password); /* NULL == digest => password != NULL */ |
1455 | digest_calc_ha1_from_user (da->alg, | 1619 | digest_calc_ha1_from_user (digest_get_algo_name (da), |
1456 | username, | 1620 | username, |
1457 | realm, | 1621 | realm, |
1458 | password, | 1622 | password, |
@@ -1461,7 +1625,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1461 | da); | 1625 | da); |
1462 | } | 1626 | } |
1463 | memcpy (ha1, | 1627 | memcpy (ha1, |
1464 | da->sessionkey, | 1628 | digest_get_hex_buffer (da), |
1465 | digest_size * 2 + 1); | 1629 | digest_size * 2 + 1); |
1466 | /* This will initialize da->sessionkey (respexp) */ | 1630 | /* This will initialize da->sessionkey (respexp) */ |
1467 | digest_calc_response (ha1, | 1631 | digest_calc_response (ha1, |
@@ -1516,7 +1680,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
1516 | free (uri); | 1680 | free (uri); |
1517 | } | 1681 | } |
1518 | return (0 == strcmp (response, | 1682 | return (0 == strcmp (response, |
1519 | da->sessionkey)) | 1683 | digest_get_hex_buffer (da))) |
1520 | ? MHD_DAUTH_OK | 1684 | ? MHD_DAUTH_OK |
1521 | : MHD_DAUTH_RESPONSE_WRONG; | 1685 | : MHD_DAUTH_RESPONSE_WRONG; |
1522 | } | 1686 | } |
@@ -1557,55 +1721,6 @@ MHD_digest_auth_check (struct MHD_Connection *connection, | |||
1557 | 1721 | ||
1558 | 1722 | ||
1559 | /** | 1723 | /** |
1560 | * Setup digest authentication data structures (on the | ||
1561 | * stack, hence must be done inline!). Initializes a | ||
1562 | * "struct DigestAlgorithm da" for algorithm @a algo. | ||
1563 | * | ||
1564 | * @param algo digest algorithm to provide | ||
1565 | * @param da data structure to setup | ||
1566 | */ | ||
1567 | #define SETUP_DA(algo,da) \ | ||
1568 | union { \ | ||
1569 | struct MD5Context md5; \ | ||
1570 | struct sha256_ctx sha256; \ | ||
1571 | } ctx; \ | ||
1572 | union { \ | ||
1573 | char md5[MD5_DIGEST_SIZE * 2 + 1]; \ | ||
1574 | char sha256[SHA256_DIGEST_SIZE * 2 + 1]; \ | ||
1575 | } skey; \ | ||
1576 | struct DigestAlgorithm da; \ | ||
1577 | \ | ||
1578 | do { \ | ||
1579 | switch (algo) { \ | ||
1580 | case MHD_DIGEST_ALG_MD5: \ | ||
1581 | da.digest_size = MD5_DIGEST_SIZE; \ | ||
1582 | da.ctx = &ctx.md5; \ | ||
1583 | da.alg = _MHD_MD5_TOKEN; \ | ||
1584 | da.sessionkey = skey.md5; \ | ||
1585 | da.init = &MHD_MD5Init; \ | ||
1586 | da.update = &MHD_MD5Update; \ | ||
1587 | da.digest = &MHD_MD5Final; \ | ||
1588 | break; \ | ||
1589 | case MHD_DIGEST_ALG_AUTO: \ | ||
1590 | /* auto == SHA256, fall-though thus intentional! */ \ | ||
1591 | case MHD_DIGEST_ALG_SHA256: \ | ||
1592 | da.digest_size = SHA256_DIGEST_SIZE; \ | ||
1593 | da.ctx = &ctx.sha256; \ | ||
1594 | da.alg = _MHD_SHA256_TOKEN; \ | ||
1595 | da.sessionkey = skey.sha256; \ | ||
1596 | da.init = &MHD_SHA256_init; \ | ||
1597 | da.update = &MHD_SHA256_update; \ | ||
1598 | da.digest = &MHD_SHA256_finish; \ | ||
1599 | break; \ | ||
1600 | default: \ | ||
1601 | da.digest_size = 0; \ | ||
1602 | mhd_assert (false); \ | ||
1603 | break; \ | ||
1604 | } \ | ||
1605 | } while (0) | ||
1606 | |||
1607 | |||
1608 | /** | ||
1609 | * Authenticates the authorization header sent by the client. | 1724 | * Authenticates the authorization header sent by the client. |
1610 | * | 1725 | * |
1611 | * @param connection the MHD connection structure | 1726 | * @param connection the MHD connection structure |
@@ -1627,10 +1742,11 @@ MHD_digest_auth_check3 (struct MHD_Connection *connection, | |||
1627 | unsigned int nonce_timeout, | 1742 | unsigned int nonce_timeout, |
1628 | enum MHD_DigestAuthAlgorithm algo) | 1743 | enum MHD_DigestAuthAlgorithm algo) |
1629 | { | 1744 | { |
1630 | SETUP_DA (algo, da); | 1745 | struct DigestAlgorithm da; |
1631 | 1746 | ||
1632 | mhd_assert (NULL != password); | 1747 | mhd_assert (NULL != password); |
1633 | if (0 == da.digest_size) | 1748 | |
1749 | if (! digest_setup (&da, algo)) | ||
1634 | MHD_PANIC (_ ("Wrong algo value.\n")); /* API violation! */ | 1750 | MHD_PANIC (_ ("Wrong algo value.\n")); /* API violation! */ |
1635 | 1751 | ||
1636 | return digest_auth_check_all (connection, | 1752 | return digest_auth_check_all (connection, |
@@ -1669,10 +1785,13 @@ MHD_digest_auth_check_digest3 (struct MHD_Connection *connection, | |||
1669 | unsigned int nonce_timeout, | 1785 | unsigned int nonce_timeout, |
1670 | enum MHD_DigestAuthAlgorithm algo) | 1786 | enum MHD_DigestAuthAlgorithm algo) |
1671 | { | 1787 | { |
1672 | SETUP_DA (algo, da); | 1788 | struct DigestAlgorithm da; |
1673 | 1789 | ||
1674 | mhd_assert (NULL != digest); | 1790 | mhd_assert (NULL != digest); |
1675 | if ((da.digest_size != digest_size) || (0 == digest_size)) | 1791 | if (! digest_setup (&da, algo)) |
1792 | MHD_PANIC (_ ("Wrong algo value.\n")); /* API violation! */ | ||
1793 | |||
1794 | if (digest_get_size (&da) != digest_size) | ||
1676 | MHD_PANIC (_ ("Digest size mismatch.\n")); /* API violation! */ | 1795 | MHD_PANIC (_ ("Digest size mismatch.\n")); /* API violation! */ |
1677 | 1796 | ||
1678 | return digest_auth_check_all (connection, | 1797 | return digest_auth_check_all (connection, |
@@ -1832,9 +1951,10 @@ MHD_queue_auth_fail_response2 (struct MHD_Connection *connection, | |||
1832 | { | 1951 | { |
1833 | int ret; | 1952 | int ret; |
1834 | int hlen; | 1953 | int hlen; |
1835 | SETUP_DA (algo, da); | ||
1836 | 1954 | ||
1837 | if (0 == da.digest_size) | 1955 | struct DigestAlgorithm da; |
1956 | |||
1957 | if (! digest_setup (&da, algo)) | ||
1838 | MHD_PANIC (_ ("Wrong algo value.\n")); /* API violation! */ | 1958 | MHD_PANIC (_ ("Wrong algo value.\n")); /* API violation! */ |
1839 | 1959 | ||
1840 | if (NULL == response) | 1960 | if (NULL == response) |
@@ -1851,9 +1971,10 @@ MHD_queue_auth_fail_response2 (struct MHD_Connection *connection, | |||
1851 | 1971 | ||
1852 | if (1) | 1972 | if (1) |
1853 | { | 1973 | { |
1854 | char nonce[NONCE_STD_LEN (VLA_ARRAY_LEN_DIGEST (da.digest_size)) + 1]; | 1974 | char nonce[NONCE_STD_LEN (VLA_ARRAY_LEN_DIGEST (digest_get_size (&da))) |
1975 | + 1]; | ||
1855 | 1976 | ||
1856 | VLA_CHECK_LEN_DIGEST (da.digest_size); | 1977 | VLA_CHECK_LEN_DIGEST (digest_get_size (&da)); |
1857 | if (! calculate_add_nonce_with_retry (connection, realm, &da, nonce)) | 1978 | if (! calculate_add_nonce_with_retry (connection, realm, &da, nonce)) |
1858 | { | 1979 | { |
1859 | #ifdef HAVE_MESSAGES | 1980 | #ifdef HAVE_MESSAGES |
@@ -1872,7 +1993,7 @@ MHD_queue_auth_fail_response2 (struct MHD_Connection *connection, | |||
1872 | realm, | 1993 | realm, |
1873 | nonce, | 1994 | nonce, |
1874 | opaque, | 1995 | opaque, |
1875 | da.alg, | 1996 | digest_get_algo_name (&da), |
1876 | signal_stale | 1997 | signal_stale |
1877 | ? ",stale=\"true\"" | 1998 | ? ",stale=\"true\"" |
1878 | : ""); | 1999 | : ""); |
@@ -1897,7 +2018,7 @@ MHD_queue_auth_fail_response2 (struct MHD_Connection *connection, | |||
1897 | realm, | 2018 | realm, |
1898 | nonce, | 2019 | nonce, |
1899 | opaque, | 2020 | opaque, |
1900 | da.alg, | 2021 | digest_get_algo_name (&da), |
1901 | signal_stale | 2022 | signal_stale |
1902 | ? ",stale=\"true\"" | 2023 | ? ",stale=\"true\"" |
1903 | : "") == hlen) | 2024 | : "") == hlen) |