GNU libmicrohttpd  1.0.1
digestauth.c
Go to the documentation of this file.
1 /*
2  This file is part of libmicrohttpd
3  Copyright (C) 2010, 2011, 2012, 2015, 2018 Daniel Pittman and Christian Grothoff
4  Copyright (C) 2014-2024 Evgeny Grin (Karlson2k)
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Lesser General Public
8  License as published by the Free Software Foundation; either
9  version 2.1 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public
17  License along with this library; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
30 #include "digestauth.h"
31 #include "gen_auth.h"
32 #include "platform.h"
33 #include "mhd_limits.h"
34 #include "internal.h"
35 #include "response.h"
36 #ifdef MHD_MD5_SUPPORT
37 # include "mhd_md5_wrap.h"
38 #endif /* MHD_MD5_SUPPORT */
39 #ifdef MHD_SHA256_SUPPORT
40 # include "mhd_sha256_wrap.h"
41 #endif /* MHD_SHA256_SUPPORT */
42 #ifdef MHD_SHA512_256_SUPPORT
43 # include "sha512_256.h"
44 #endif /* MHD_SHA512_256_SUPPORT */
45 #include "mhd_locks.h"
46 #include "mhd_mono_clock.h"
47 #include "mhd_str.h"
48 #include "mhd_compat.h"
49 #include "mhd_bithelpers.h"
50 #include "mhd_assert.h"
51 
52 
59 #define REUSE_TIMEOUT 30
60 
65 #define DAUTH_JUMPBACK_MAX (0x7F)
66 
67 
71 #define TIMESTAMP_BIN_SIZE (48 / 8)
72 
73 
77 #define TRIM_TO_TIMESTAMP(value) \
78  ((value) & ((UINT64_C (1) << (TIMESTAMP_BIN_SIZE * 8)) - 1))
79 
80 
84 #define TIMESTAMP_CHARS_LEN (TIMESTAMP_BIN_SIZE * 2)
85 
86 
92 #define NONCE_STD_LEN(digest_size) \
93  ((digest_size) * 2 + TIMESTAMP_CHARS_LEN)
94 
95 
96 #ifdef MHD_SHA512_256_SUPPORT
101 #define MAX_DIGEST SHA512_256_DIGEST_SIZE
102 
106 #define SHA256_SHA512_256_DIGEST_SIZE SHA512_256_DIGEST_SIZE
107 #elif defined(MHD_SHA256_SUPPORT)
112 #define MAX_DIGEST SHA256_DIGEST_SIZE
113 
117 #define SHA256_SHA512_256_DIGEST_SIZE SHA256_DIGEST_SIZE
118 #elif defined(MHD_MD5_SUPPORT)
122 #define MAX_DIGEST MD5_DIGEST_SIZE
123 #else /* ! MHD_MD5_SUPPORT */
124 #error At least one hashing algorithm must be enabled
125 #endif /* ! MHD_MD5_SUPPORT */
126 
127 
131 #ifndef HAVE_C_VARARRAYS
137 #define VLA_ARRAY_LEN_DIGEST(n) (MAX_DIGEST)
138 
139 #else
145 #define VLA_ARRAY_LEN_DIGEST(n) (n)
146 #endif
147 
151 #define VLA_CHECK_LEN_DIGEST(n) \
152  do { if ((n) > MAX_DIGEST) MHD_PANIC (_ ("VLA too big.\n")); } while (0)
153 
157 #define MAX_USERNAME_LENGTH 128
158 
162 #define MAX_REALM_LENGTH 256
163 
167 #define MAX_AUTH_RESPONSE_LENGTH (MAX_DIGEST * 2)
168 
172 #define MHD_DAUTH_EXT_PARAM_PREFIX "UTF-8'"
173 
177 #define MHD_DAUTH_EXT_PARAM_MIN_LEN \
178  MHD_STATICSTR_LEN_ (MHD_DAUTH_EXT_PARAM_PREFIX "'")
179 
184 {
189 
196 
201 };
202 
203 
209 _MHD_static_inline enum MHD_DigestBaseAlgo
211 {
212  unsigned int base_algo;
213 
214  base_algo =
215  ((unsigned int) algo3)
216  & ~((unsigned int)
219  return (enum MHD_DigestBaseAlgo) base_algo;
220 }
221 
222 
231 _MHD_static_inline size_t
233 {
234 #ifdef MHD_MD5_SUPPORT
236 #endif /* MHD_MD5_SUPPORT */
237 #ifdef MHD_SHA256_SUPPORT
239 #endif /* MHD_SHA256_SUPPORT */
240 #ifdef MHD_SHA512_256_SUPPORT
242 #ifdef MHD_SHA256_SUPPORT
244 #endif /* MHD_SHA256_SUPPORT */
245 #endif /* MHD_SHA512_256_SUPPORT */
246  /* Only one algorithm must be specified */
247  mhd_assert (1 == \
248  (((0 != (algo3 & MHD_DIGEST_BASE_ALGO_MD5)) ? 1 : 0) \
249  + ((0 != (algo3 & MHD_DIGEST_BASE_ALGO_SHA256)) ? 1 : 0) \
250  + ((0 != (algo3 & MHD_DIGEST_BASE_ALGO_SHA512_256)) ? 1 : 0)));
251 #ifdef MHD_MD5_SUPPORT
252  if (0 != (((unsigned int) algo3)
253  & ((unsigned int) MHD_DIGEST_BASE_ALGO_MD5)))
254  return MHD_MD5_DIGEST_SIZE;
255  else
256 #endif /* MHD_MD5_SUPPORT */
257 #if defined(MHD_SHA256_SUPPORT) && defined(MHD_SHA512_256_SUPPORT)
258  if (0 != (((unsigned int) algo3)
259  & ( ((unsigned int) MHD_DIGEST_BASE_ALGO_SHA256)
260  | ((unsigned int) MHD_DIGEST_BASE_ALGO_SHA512_256))))
261  return MHD_SHA256_DIGEST_SIZE; /* The same as SHA512_256_DIGEST_SIZE */
262  else
263 #elif defined(MHD_SHA256_SUPPORT)
264  if (0 != (((unsigned int) algo3)
265  & ((unsigned int) MHD_DIGEST_BASE_ALGO_SHA256)))
266  return MHD_SHA256_DIGEST_SIZE;
267  else
268 #elif defined(MHD_SHA512_256_SUPPORT)
269  if (0 != (((unsigned int) algo3)
270  & ((unsigned int) MHD_DIGEST_BASE_ALGO_SHA512_256)))
272  else
273 #endif /* MHD_SHA512_256_SUPPORT */
274  (void) 0; /* Unsupported algorithm */
275 
276  return 0; /* Wrong input or unsupported algorithm */
277 }
278 
279 
294 _MHD_EXTERN size_t
296 {
297  return digest_get_hash_size (algo3);
298 }
299 
300 
304 union DigestCtx
305 {
306 #ifdef MHD_MD5_SUPPORT
307  struct Md5CtxWr md5_ctx;
308 #endif /* MHD_MD5_SUPPORT */
309 #ifdef MHD_SHA256_SUPPORT
310  struct Sha256CtxWr sha256_ctx;
311 #endif /* MHD_SHA256_SUPPORT */
312 #ifdef MHD_SHA512_256_SUPPORT
313  struct Sha512_256Ctx sha512_256_ctx;
314 #endif /* MHD_SHA512_256_SUPPORT */
315 };
316 
320 struct DigestAlgorithm
321 {
326  union DigestCtx ctx;
327 
331  enum MHD_DigestBaseAlgo algo;
332 
336 #ifdef _DEBUG
337  bool uninitialised;
338  bool algo_selected;
339  bool ready_for_hashing;
340  bool hashing;
341 #endif /* _DEBUG */
342 };
343 
344 
350 _MHD_static_inline unsigned int
351 digest_get_size (struct DigestAlgorithm *da)
352 {
353  mhd_assert (! da->uninitialised);
354  mhd_assert (da->algo_selected);
355 #ifdef MHD_MD5_SUPPORT
356  if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
357  return MD5_DIGEST_SIZE;
358 #endif /* MHD_MD5_SUPPORT */
359 #ifdef MHD_SHA256_SUPPORT
360  if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
361  return SHA256_DIGEST_SIZE;
362 #endif /* MHD_SHA256_SUPPORT */
363 #ifdef MHD_SHA512_256_SUPPORT
364  if (MHD_DIGEST_BASE_ALGO_SHA512_256 == da->algo)
365  return SHA512_256_DIGEST_SIZE;
366 #endif /* MHD_SHA512_256_SUPPORT */
367  mhd_assert (0); /* May not happen */
368  return 0;
369 }
370 
371 
372 #if defined(MHD_MD5_HAS_DEINIT) || defined(MHD_SHA256_HAS_DEINIT)
376 #define MHD_DIGEST_HAS_DEINIT 1
377 #endif /* MHD_MD5_HAS_DEINIT || MHD_SHA256_HAS_DEINIT */
378 
379 #ifdef MHD_DIGEST_HAS_DEINIT
387 _MHD_static_inline void
388 digest_setup_zero (struct DigestAlgorithm *da)
389 {
390 #ifdef _DEBUG
391  da->uninitialised = false;
392  da->algo_selected = false;
393  da->ready_for_hashing = false;
394  da->hashing = false;
395 #endif /* _DEBUG */
396  da->algo = MHD_DIGEST_BASE_ALGO_INVALID;
397 }
398 
399 
409 _MHD_static_inline void
410 digest_deinit (struct DigestAlgorithm *da)
411 {
412  mhd_assert (! da->uninitialised);
413 #ifdef MHD_MD5_HAS_DEINIT
414  if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
415  MHD_MD5_deinit (&da->ctx.md5_ctx);
416  else
417 #endif /* MHD_MD5_HAS_DEINIT */
418 #ifdef MHD_SHA256_HAS_DEINIT
419  if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
420  MHD_SHA256_deinit (&da->ctx.sha256_ctx);
421  else
422 #endif /* MHD_SHA256_HAS_DEINIT */
423  (void) 0;
424  digest_setup_zero (da);
425 }
426 
427 
428 #else /* ! MHD_DIGEST_HAS_DEINIT */
429 #define digest_setup_zero(da) (void)0
430 #define digest_deinit(da) (void)0
431 #endif /* ! MHD_DIGEST_HAS_DEINIT */
432 
433 
447 _MHD_static_inline bool
448 digest_init_one_time (struct DigestAlgorithm *da,
449  enum MHD_DigestBaseAlgo algo)
450 {
451 #ifdef _DEBUG
452  da->uninitialised = false;
453  da->algo_selected = false;
454  da->ready_for_hashing = false;
455  da->hashing = false;
456 #endif /* _DEBUG */
457 #ifdef MHD_MD5_SUPPORT
458  if (MHD_DIGEST_BASE_ALGO_MD5 == algo)
459  {
460  da->algo = MHD_DIGEST_BASE_ALGO_MD5;
461 #ifdef _DEBUG
462  da->algo_selected = true;
463 #endif
464  MHD_MD5_init_one_time (&da->ctx.md5_ctx);
465 #ifdef _DEBUG
466  da->ready_for_hashing = true;
467 #endif
468  return true;
469  }
470 #endif /* MHD_MD5_SUPPORT */
471 #ifdef MHD_SHA256_SUPPORT
472  if (MHD_DIGEST_BASE_ALGO_SHA256 == algo)
473  {
474  da->algo = MHD_DIGEST_BASE_ALGO_SHA256;
475 #ifdef _DEBUG
476  da->algo_selected = true;
477 #endif
478  MHD_SHA256_init_one_time (&da->ctx.sha256_ctx);
479 #ifdef _DEBUG
480  da->ready_for_hashing = true;
481 #endif
482  return true;
483  }
484 #endif /* MHD_SHA256_SUPPORT */
485 #ifdef MHD_SHA512_256_SUPPORT
487  {
489 #ifdef _DEBUG
490  da->algo_selected = true;
491 #endif
492  MHD_SHA512_256_init (&da->ctx.sha512_256_ctx);
493 #ifdef _DEBUG
494  da->ready_for_hashing = true;
495 #endif
496  return true;
497  }
498 #endif /* MHD_SHA512_256_SUPPORT */
499 
500  da->algo = MHD_DIGEST_BASE_ALGO_INVALID;
501  return false; /* Unsupported or bad algorithm */
502 }
503 
504 
511 _MHD_static_inline void
512 digest_update (struct DigestAlgorithm *da,
513  const void *data,
514  size_t length)
515 {
516  mhd_assert (! da->uninitialised);
517  mhd_assert (da->algo_selected);
518  mhd_assert (da->ready_for_hashing);
519 #ifdef MHD_MD5_SUPPORT
520  if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
521  MHD_MD5_update (&da->ctx.md5_ctx, (const uint8_t *) data, length);
522  else
523 #endif /* MHD_MD5_SUPPORT */
524 #ifdef MHD_SHA256_SUPPORT
525  if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
526  MHD_SHA256_update (&da->ctx.sha256_ctx, (const uint8_t *) data, length);
527  else
528 #endif /* MHD_SHA256_SUPPORT */
529 #ifdef MHD_SHA512_256_SUPPORT
530  if (MHD_DIGEST_BASE_ALGO_SHA512_256 == da->algo)
531  MHD_SHA512_256_update (&da->ctx.sha512_256_ctx,
532  (const uint8_t *) data, length);
533  else
534 #endif /* MHD_SHA512_256_SUPPORT */
535  mhd_assert (0); /* May not happen */
536 #ifdef _DEBUG
537  da->hashing = true;
538 #endif
539 }
540 
541 
547 _MHD_static_inline void
548 digest_update_str (struct DigestAlgorithm *da,
549  const char *str)
550 {
551  const size_t str_len = strlen (str);
552  digest_update (da, (const uint8_t *) str, str_len);
553 }
554 
555 
561 _MHD_static_inline void
562 digest_update_with_colon (struct DigestAlgorithm *da)
563 {
564  static const uint8_t colon = (uint8_t) ':';
565  digest_update (da, &colon, 1);
566 }
567 
568 
575 _MHD_static_inline void
576 digest_calc_hash (struct DigestAlgorithm *da, uint8_t *digest)
577 {
578  mhd_assert (! da->uninitialised);
579  mhd_assert (da->algo_selected);
580  mhd_assert (da->ready_for_hashing);
581 #ifdef MHD_MD5_SUPPORT
582  if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
583  {
584 #ifdef MHD_MD5_HAS_FINISH
585  MHD_MD5_finish (&da->ctx.md5_ctx, digest);
586 #ifdef _DEBUG
587  da->ready_for_hashing = false;
588 #endif /* _DEBUG */
589 #else /* ! MHD_MD5_HAS_FINISH */
590  MHD_MD5_finish_reset (&da->ctx.md5_ctx, digest);
591 #ifdef _DEBUG
592  da->ready_for_hashing = true;
593 #endif /* _DEBUG */
594 #endif /* ! MHD_MD5_HAS_FINISH */
595  }
596  else
597 #endif /* MHD_MD5_SUPPORT */
598 #ifdef MHD_SHA256_SUPPORT
599  if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
600  {
601 #ifdef MHD_SHA256_HAS_FINISH
602  MHD_SHA256_finish (&da->ctx.sha256_ctx, digest);
603 #ifdef _DEBUG
604  da->ready_for_hashing = false;
605 #endif /* _DEBUG */
606 #else /* ! MHD_SHA256_HAS_FINISH */
607  MHD_SHA256_finish_reset (&da->ctx.sha256_ctx, digest);
608 #ifdef _DEBUG
609  da->ready_for_hashing = true;
610 #endif /* _DEBUG */
611 #endif /* ! MHD_SHA256_HAS_FINISH */
612  }
613  else
614 #endif /* MHD_SHA256_SUPPORT */
615 #ifdef MHD_SHA512_256_SUPPORT
616  if (MHD_DIGEST_BASE_ALGO_SHA512_256 == da->algo)
617  {
618  MHD_SHA512_256_finish (&da->ctx.sha512_256_ctx, digest);
619 #ifdef _DEBUG
620  da->ready_for_hashing = false;
621 #endif /* _DEBUG */
622  }
623  else
624 #endif /* MHD_SHA512_256_SUPPORT */
625  mhd_assert (0); /* Should not happen */
626 #ifdef _DEBUG
627  da->hashing = false;
628 #endif /* _DEBUG */
629 }
630 
631 
637 _MHD_static_inline void
638 digest_reset (struct DigestAlgorithm *da)
639 {
640  mhd_assert (! da->uninitialised);
641  mhd_assert (da->algo_selected);
642  mhd_assert (! da->hashing);
643 #ifdef MHD_MD5_SUPPORT
644  if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
645  {
646 #ifdef MHD_MD5_HAS_FINISH
647  mhd_assert (! da->ready_for_hashing);
648 #else /* ! MHD_MD5_HAS_FINISH */
649  mhd_assert (da->ready_for_hashing);
650 #endif /* ! MHD_MD5_HAS_FINISH */
651  MHD_MD5_reset (&da->ctx.md5_ctx);
652 #ifdef _DEBUG
653  da->ready_for_hashing = true;
654 #endif /* _DEBUG */
655  }
656  else
657 #endif /* MHD_MD5_SUPPORT */
658 #ifdef MHD_SHA256_SUPPORT
659  if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
660  {
661 #ifdef MHD_SHA256_HAS_FINISH
662  mhd_assert (! da->ready_for_hashing);
663 #else /* ! MHD_SHA256_HAS_FINISH */
664  mhd_assert (da->ready_for_hashing);
665 #endif /* ! MHD_SHA256_HAS_FINISH */
666  MHD_SHA256_reset (&da->ctx.sha256_ctx);
667 #ifdef _DEBUG
668  da->ready_for_hashing = true;
669 #endif /* _DEBUG */
670  }
671  else
672 #endif /* MHD_SHA256_SUPPORT */
673 #ifdef MHD_SHA512_256_SUPPORT
674  if (MHD_DIGEST_BASE_ALGO_SHA512_256 == da->algo)
675  {
676  mhd_assert (! da->ready_for_hashing);
677  MHD_SHA512_256_init (&da->ctx.sha512_256_ctx);
678 #ifdef _DEBUG
679  da->ready_for_hashing = true;
680 #endif
681  }
682  else
683 #endif /* MHD_SHA512_256_SUPPORT */
684  {
685 #ifdef _DEBUG
686  da->ready_for_hashing = false;
687 #endif
688  mhd_assert (0); /* May not happen, bad algorithm */
689  }
690 }
691 
692 
693 #if defined(MHD_MD5_HAS_EXT_ERROR) || defined(MHD_SHA256_HAS_EXT_ERROR)
697 #define MHD_DIGEST_HAS_EXT_ERROR 1
698 #endif /* MHD_MD5_HAS_EXT_ERROR || MHD_SHA256_HAS_EXT_ERROR */
699 
700 #ifdef MHD_DIGEST_HAS_EXT_ERROR
710 _MHD_static_inline bool
711 digest_ext_error (struct DigestAlgorithm *da)
712 {
713  mhd_assert (! da->uninitialised);
714  mhd_assert (da->algo_selected);
715 #ifdef MHD_MD5_HAS_EXT_ERROR
716  if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
717  return 0 != da->ctx.md5_ctx.ext_error;
718 #endif /* MHD_MD5_HAS_EXT_ERROR */
719 #ifdef MHD_SHA256_HAS_EXT_ERROR
720  if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
721  return 0 != da->ctx.sha256_ctx.ext_error;
722 #endif /* MHD_MD5_HAS_EXT_ERROR */
723  return false;
724 }
725 
726 
727 #else /* ! MHD_DIGEST_HAS_EXT_ERROR */
728 #define digest_ext_error(da) (false)
729 #endif /* ! MHD_DIGEST_HAS_EXT_ERROR */
730 
731 
740 static bool
741 get_nonce_timestamp (const char *const nonce,
742  size_t noncelen,
743  uint64_t *const ptimestamp)
744 {
745  if (0 == noncelen)
746  noncelen = strlen (nonce);
747 
748  if (true
749 #ifdef MHD_MD5_SUPPORT
750  && (NONCE_STD_LEN (MD5_DIGEST_SIZE) != noncelen)
751 #endif /* MHD_MD5_SUPPORT */
752 #if defined(MHD_SHA256_SUPPORT) || defined(MHD_SHA512_256_SUPPORT)
753  && (NONCE_STD_LEN (SHA256_SHA512_256_DIGEST_SIZE) != noncelen)
754 #endif /* MHD_SHA256_SUPPORT */
755  )
756  return false;
757 
758  if (TIMESTAMP_CHARS_LEN !=
759  MHD_strx_to_uint64_n_ (nonce + noncelen - TIMESTAMP_CHARS_LEN,
761  ptimestamp))
762  return false;
763  return true;
764 }
765 
766 
768 
776 static uint32_t
777 fast_simple_hash (const uint8_t *data,
778  size_t data_size)
779 {
780  uint32_t hash;
781 
782  if (0 != data_size)
783  {
784  size_t i;
785  hash = data[0];
786  for (i = 1; i < data_size; i++)
787  hash = _MHD_ROTL32 (hash, 7) ^ data[i];
788  }
789  else
790  hash = 0;
791 
792  return hash;
793 }
794 
795 
797 
806 static size_t
807 get_nonce_nc_idx (size_t arr_size,
808  const char *nonce,
809  size_t noncelen)
810 {
811  mhd_assert (0 != arr_size);
812  mhd_assert (0 != noncelen);
813  return fast_simple_hash ((const uint8_t *) nonce, noncelen) % arr_size;
814 }
815 
816 
831 static enum MHD_CheckNonceNC_
832 check_nonce_nc (struct MHD_Connection *connection,
833  const char *nonce,
834  size_t noncelen,
835  uint64_t nonce_time,
836  uint64_t nc)
837 {
838  struct MHD_Daemon *daemon = MHD_get_master (connection->daemon);
839  struct MHD_NonceNc *nn;
840  uint32_t mod;
841  enum MHD_CheckNonceNC_ ret;
842 
843  mhd_assert (0 != noncelen);
844  mhd_assert (0 != nc);
845  if (MAX_DIGEST_NONCE_LENGTH < noncelen)
846  return MHD_CHECK_NONCENC_WRONG; /* This should be impossible, but static analysis
847  tools have a hard time with it *and* this also
848  protects against unsafe modifications that may
849  happen in the future... */
850  mod = daemon->nonce_nc_size;
851  if (0 == mod)
852  return MHD_CHECK_NONCENC_STALE; /* no array! */
853  if (nc >= UINT32_MAX - 64)
854  return MHD_CHECK_NONCENC_STALE; /* Overflow, unrealistically high value */
855 
856  nn = &daemon->nnc[get_nonce_nc_idx (mod, nonce, noncelen)];
857 
858  MHD_mutex_lock_chk_ (&daemon->nnc_lock);
859 
860  mhd_assert (0 == nn->nonce[noncelen]); /* The old value must be valid */
861 
862  if ( (0 != memcmp (nn->nonce, nonce, noncelen)) ||
863  (0 != nn->nonce[noncelen]) )
864  { /* The nonce in the slot does not match nonce from the client */
865  if (0 == nn->nonce[0])
866  { /* The slot was never used, while the client's nonce value should be
867  * recorded when it was generated by MHD */
869  }
870  else if (0 != nn->nonce[noncelen])
871  { /* The value is the slot is wrong */
873  }
874  else
875  {
876  uint64_t slot_ts;
877  if (! get_nonce_timestamp (nn->nonce, noncelen, &slot_ts))
878  {
879  mhd_assert (0); /* The value is the slot is wrong */
881  }
882  else
883  {
884  /* Unsigned value, will be large if nonce_time is less than slot_ts */
885  const uint64_t ts_diff = TRIM_TO_TIMESTAMP (nonce_time - slot_ts);
886  if ((REUSE_TIMEOUT * 1000) >= ts_diff)
887  {
888  /* The nonce from the client may not have been placed in the slot
889  * because another nonce in that slot has not yet expired. */
891  }
892  else if (TRIM_TO_TIMESTAMP (UINT64_MAX) / 2 >= ts_diff)
893  {
894  /* Too large value means that nonce_time is less than slot_ts.
895  * The nonce from the client may have been overwritten by the newer
896  * nonce. */
898  }
899  else
900  {
901  /* The nonce from the client should be generated after the nonce
902  * in the slot has been expired, the nonce must be recorded, but
903  * it's not. */
905  }
906  }
907  }
908  }
909  else if (nc > nn->nc)
910  {
911  /* 'nc' is larger, shift bitmask and bump limit */
912  const uint32_t jump_size = (uint32_t) nc - nn->nc;
913  if (64 > jump_size)
914  {
915  /* small jump, less than mask width */
916  nn->nmask <<= jump_size;
917  /* Set bit for the old 'nc' value */
918  nn->nmask |= (UINT64_C (1) << (jump_size - 1));
919  }
920  else if (64 == jump_size)
921  nn->nmask = (UINT64_C (1) << 63);
922  else
923  nn->nmask = 0; /* big jump, unset all bits in the mask */
924  nn->nc = (uint32_t) nc;
925  ret = MHD_CHECK_NONCENC_OK;
926  }
927  else if (nc < nn->nc)
928  {
929  /* Note that we use 64 here, as we do not store the
930  bit for 'nn->nc' itself in 'nn->nmask' */
931  if ( (nc + 64 >= nn->nc) &&
932  (0 == ((UINT64_C (1) << (nn->nc - nc - 1)) & nn->nmask)) )
933  {
934  /* Out-of-order nonce, but within 64-bit bitmask, set bit */
935  nn->nmask |= (UINT64_C (1) << (nn->nc - nc - 1));
936  ret = MHD_CHECK_NONCENC_OK;
937  }
938  else
939  /* 'nc' was already used or too old (more then 64 values ago) */
941  }
942  else /* if (nc == nn->nc) */
943  /* 'nc' was already used */
945 
946  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
947 
948  return ret;
949 }
950 
951 
959 _MHD_static_inline enum MHD_DigestAuthUsernameType
960 get_rq_uname_type (const struct MHD_RqDAuth *params)
961 {
962  if (NULL != params->username.value.str)
963  {
964  if (NULL == params->username_ext.value.str)
965  return params->userhash ?
968  else /* Both 'username' and 'username*' are used */
970  }
971  else if (NULL != params->username_ext.value.str)
972  {
973  if (! params->username_ext.quoted && ! params->userhash &&
974  (MHD_DAUTH_EXT_PARAM_MIN_LEN <= params->username_ext.value.len) )
976  else
978  }
979 
981 }
982 
983 
991 _MHD_static_inline size_t
992 get_rq_unames_size (const struct MHD_RqDAuth *params,
993  enum MHD_DigestAuthUsernameType uname_type)
994 {
995  size_t s;
996 
997  mhd_assert (get_rq_uname_type (params) == uname_type);
998  s = 0;
999  if ((MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD == uname_type) ||
1000  (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH == uname_type) )
1001  {
1002  s += params->username.value.len + 1; /* Add one byte for zero-termination */
1003  if (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH == uname_type)
1004  s += (params->username.value.len + 1) / 2;
1005  }
1006  else if (MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED == uname_type)
1007  s += params->username_ext.value.len
1008  - MHD_DAUTH_EXT_PARAM_MIN_LEN + 1; /* Add one byte for zero-termination */
1009  return s;
1010 }
1011 
1012 
1021 static size_t
1022 get_rq_param_unquoted_copy_z (const struct MHD_RqDAuthParam *param, char *buf)
1023 {
1024  size_t len;
1025  mhd_assert (NULL != param->value.str);
1026  if (! param->quoted)
1027  {
1028  memcpy (buf, param->value.str, param->value.len);
1029  buf [param->value.len] = 0;
1030  return param->value.len;
1031  }
1032 
1033  len = MHD_str_unquote (param->value.str, param->value.len, buf);
1034  mhd_assert (0 != len);
1035  mhd_assert (len < param->value.len);
1036  buf[len] = 0;
1037  return len;
1038 }
1039 
1040 
1051 static ssize_t
1052 get_rq_extended_uname_copy_z (const char *uname_ext, size_t uname_ext_len,
1053  char *buf, size_t buf_size)
1054 {
1055  size_t r;
1056  size_t w;
1057  if ((size_t) SSIZE_MAX < uname_ext_len)
1058  return -1; /* Too long input string */
1059 
1060  if (MHD_DAUTH_EXT_PARAM_MIN_LEN > uname_ext_len)
1061  return -1; /* Required prefix is missing */
1062 
1064  MHD_STATICSTR_LEN_ ( \
1066  return -1; /* Only UTF-8 is supported, as it is implied by RFC 7616 */
1067 
1069  /* Skip language tag */
1070  while (r < uname_ext_len && '\'' != uname_ext[r])
1071  {
1072  const char chr = uname_ext[r];
1073  if ((' ' == chr) || ('\t' == chr) || ('\"' == chr) || (',' == chr) ||
1074  (';' == chr) )
1075  return -1; /* Wrong char in language tag */
1076  r++;
1077  }
1078  if (r >= uname_ext_len)
1079  return -1; /* The end of the language tag was not found */
1080  r++; /* Advance to the next char */
1081 
1082  w = MHD_str_pct_decode_strict_n_ (uname_ext + r, uname_ext_len - r,
1083  buf, buf_size);
1084  if ((0 == w) && (0 != uname_ext_len - r))
1085  return -1; /* Broken percent encoding */
1086  buf[w] = 0; /* Zero terminate the result */
1087  mhd_assert (SSIZE_MAX > w);
1088  return (ssize_t) w;
1089 }
1090 
1091 
1101 static size_t
1102 get_rq_uname (const struct MHD_RqDAuth *params,
1103  enum MHD_DigestAuthUsernameType uname_type,
1104  struct MHD_DigestAuthUsernameInfo *uname_info,
1105  uint8_t *buf,
1106  size_t buf_size)
1107 {
1108  size_t buf_used;
1109 
1110  buf_used = 0;
1111  mhd_assert (get_rq_uname_type (params) == uname_type);
1114 
1115  uname_info->username = NULL;
1116  uname_info->username_len = 0;
1117  uname_info->userhash_hex = NULL;
1118  uname_info->userhash_hex_len = 0;
1119  uname_info->userhash_bin = NULL;
1120 
1121  if (MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD == uname_type)
1122  {
1123  uname_info->username = (char *) (buf + buf_used);
1124  uname_info->username_len =
1125  get_rq_param_unquoted_copy_z (&params->username,
1126  uname_info->username);
1127  buf_used += uname_info->username_len + 1;
1129  }
1130  else if (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH == uname_type)
1131  {
1132  size_t res;
1133 
1134  uname_info->userhash_hex = (char *) (buf + buf_used);
1135  uname_info->userhash_hex_len =
1136  get_rq_param_unquoted_copy_z (&params->username,
1137  uname_info->userhash_hex);
1138  buf_used += uname_info->userhash_hex_len + 1;
1139  uname_info->userhash_bin = (uint8_t *) (buf + buf_used);
1140  res = MHD_hex_to_bin (uname_info->userhash_hex,
1141  uname_info->userhash_hex_len,
1142  uname_info->userhash_bin);
1143  if (res != uname_info->userhash_hex_len / 2)
1144  {
1145  uname_info->userhash_bin = NULL;
1147  }
1148  else
1149  {
1150  /* Avoid pointers outside allocated region when the size is zero */
1151  if (0 == res)
1152  uname_info->userhash_bin = (uint8_t *) uname_info->username;
1154  buf_used += res;
1155  }
1156  }
1157  else if (MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED == uname_type)
1158  {
1159  ssize_t res;
1160  res = get_rq_extended_uname_copy_z (params->username_ext.value.str,
1161  params->username_ext.value.len,
1162  (char *) (buf + buf_used),
1163  buf_size - buf_used);
1164  if (0 > res)
1166  else
1167  {
1168  uname_info->username = (char *) (buf + buf_used);
1169  uname_info->username_len = (size_t) res;
1171  buf_used += uname_info->username_len + 1;
1172  }
1173  }
1174  else
1175  {
1176  mhd_assert (0);
1178  }
1179  mhd_assert (buf_size >= buf_used);
1180  return buf_used;
1181 }
1182 
1183 
1188 {
1194 };
1195 
1196 
1203 static enum MHD_GetRqNCResult
1204 get_rq_nc (const struct MHD_RqDAuth *params,
1205  uint32_t *nc)
1206 {
1207  const struct MHD_RqDAuthParam *const nc_param =
1208  &params->nc;
1209  char unq[16];
1210  const char *val;
1211  size_t val_len;
1212  size_t res;
1213  uint64_t nc_val;
1214 
1215  if (NULL == nc_param->value.str)
1216  return MHD_GET_RQ_NC_NONE;
1217 
1218  if (0 == nc_param->value.len)
1219  return MHD_GET_RQ_NC_BROKEN;
1220 
1221  if (! nc_param->quoted)
1222  {
1223  val = nc_param->value.str;
1224  val_len = nc_param->value.len;
1225  }
1226  else
1227  {
1228  /* Actually no backslashes must be used in 'nc' */
1229  if (sizeof(unq) < params->nc.value.len)
1230  return MHD_GET_RQ_NC_TOO_LONG;
1231  val_len = MHD_str_unquote (nc_param->value.str, nc_param->value.len, unq);
1232  if (0 == val_len)
1233  return MHD_GET_RQ_NC_BROKEN;
1234  val = unq;
1235  }
1236 
1237  res = MHD_strx_to_uint64_n_ (val, val_len, &nc_val);
1238  if (0 == res)
1239  {
1240  const char f = val[0];
1241  if ( (('9' >= f) && ('0' <= f)) ||
1242  (('F' >= f) && ('A' <= f)) ||
1243  (('a' <= f) && ('f' >= f)) )
1244  return MHD_GET_RQ_NC_TOO_LARGE;
1245  else
1246  return MHD_GET_RQ_NC_BROKEN;
1247  }
1248  if (val_len != res)
1249  return MHD_GET_RQ_NC_BROKEN;
1250  if (UINT32_MAX < nc_val)
1251  return MHD_GET_RQ_NC_TOO_LARGE;
1252  *nc = (uint32_t) nc_val;
1253  return MHD_GET_RQ_NC_VALID;
1254 }
1255 
1256 
1269 {
1270  const struct MHD_RqDAuth *params;
1271  struct MHD_DigestAuthInfo *info;
1273  size_t unif_buf_size;
1274  uint8_t *unif_buf_ptr;
1275  size_t unif_buf_used;
1276  enum MHD_GetRqNCResult nc_res;
1277 
1278  params = MHD_get_rq_dauth_params_ (connection);
1279  if (NULL == params)
1280  return NULL;
1281 
1282  unif_buf_size = 0;
1283 
1284  uname_type = get_rq_uname_type (params);
1285 
1286  unif_buf_size += get_rq_unames_size (params, uname_type);
1287 
1288  if (NULL != params->opaque.value.str)
1289  unif_buf_size += params->opaque.value.len + 1; /* Add one for zero-termination */
1290  if (NULL != params->realm.value.str)
1291  unif_buf_size += params->realm.value.len + 1; /* Add one for zero-termination */
1292  info = (struct MHD_DigestAuthInfo *)
1293  MHD_calloc_ (1, (sizeof(struct MHD_DigestAuthInfo)) + unif_buf_size);
1294  unif_buf_ptr = (uint8_t *) (info + 1);
1295  unif_buf_used = 0;
1296 
1297  info->algo3 = params->algo3;
1298 
1301  unif_buf_used +=
1302  get_rq_uname (params, uname_type,
1303  (struct MHD_DigestAuthUsernameInfo *) info,
1304  unif_buf_ptr + unif_buf_used,
1305  unif_buf_size - unif_buf_used);
1306  else
1307  info->uname_type = uname_type;
1308 
1309  if (NULL != params->opaque.value.str)
1310  {
1311  info->opaque = (char *) (unif_buf_ptr + unif_buf_used);
1312  info->opaque_len = get_rq_param_unquoted_copy_z (&params->opaque,
1313  info->opaque);
1314  unif_buf_used += info->opaque_len + 1;
1315  }
1316  if (NULL != params->realm.value.str)
1317  {
1318  info->realm = (char *) (unif_buf_ptr + unif_buf_used);
1319  info->realm_len = get_rq_param_unquoted_copy_z (&params->realm,
1320  info->realm);
1321  unif_buf_used += info->realm_len + 1;
1322  }
1323 
1324  mhd_assert (unif_buf_size >= unif_buf_used);
1325 
1326  info->qop = params->qop;
1327 
1328  if (NULL != params->cnonce.value.str)
1329  info->cnonce_len = params->cnonce.value.len;
1330  else
1331  info->cnonce_len = 0;
1332 
1333  nc_res = get_rq_nc (params, &info->nc);
1334  if (MHD_GET_RQ_NC_VALID != nc_res)
1336 
1337  return info;
1338 }
1339 
1340 
1357 {
1358  const struct MHD_RqDAuth *params;
1359  struct MHD_DigestAuthUsernameInfo *uname_info;
1361  size_t unif_buf_size;
1362  uint8_t *unif_buf_ptr;
1363  size_t unif_buf_used;
1364 
1365  params = MHD_get_rq_dauth_params_ (connection);
1366  if (NULL == params)
1367  return NULL;
1368 
1369  uname_type = get_rq_uname_type (params);
1372  return NULL;
1373 
1374  unif_buf_size = get_rq_unames_size (params, uname_type);
1375 
1376  uname_info = (struct MHD_DigestAuthUsernameInfo *)
1377  MHD_calloc_ (1, (sizeof(struct MHD_DigestAuthUsernameInfo))
1378  + unif_buf_size);
1379  unif_buf_ptr = (uint8_t *) (uname_info + 1);
1380  unif_buf_used = get_rq_uname (params, uname_type, uname_info, unif_buf_ptr,
1381  unif_buf_size);
1382  mhd_assert (unif_buf_size >= unif_buf_used);
1383  (void) unif_buf_used; /* Mute compiler warning on non-debug builds */
1385 
1387  {
1388  free (uname_info);
1389  return NULL;
1390  }
1391  mhd_assert (uname_type == uname_info->uname_type);
1392  uname_info->algo3 = params->algo3;
1393 
1394  return uname_info;
1395 }
1396 
1397 
1413 _MHD_EXTERN char *
1415 {
1416  const struct MHD_RqDAuth *params;
1417  char *username;
1418  size_t buf_size;
1419  enum MHD_DigestAuthUsernameType uname_type;
1420 
1421  params = MHD_get_rq_dauth_params_ (connection);
1422  if (NULL == params)
1423  return NULL;
1424 
1425  uname_type = get_rq_uname_type (params);
1426 
1427  if ( (MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD != uname_type) &&
1428  (MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED != uname_type) )
1429  return NULL;
1430 
1431  buf_size = get_rq_unames_size (params, uname_type);
1432 
1433  mhd_assert (0 != buf_size);
1434 
1435  username = (char *) MHD_calloc_ (1, buf_size);
1436  if (NULL == username)
1437  return NULL;
1438 
1439  if (1)
1440  {
1441  struct MHD_DigestAuthUsernameInfo uname_strct;
1442  size_t used;
1443 
1444  memset (&uname_strct, 0, sizeof(uname_strct));
1445 
1446  used = get_rq_uname (params, uname_type, &uname_strct,
1447  (uint8_t *) username, buf_size);
1448  if (uname_type != uname_strct.uname_type)
1449  { /* Broken encoding for extended notation */
1450  free (username);
1451  return NULL;
1452  }
1453  (void) used; /* Mute compiler warning for non-debug builds */
1454  mhd_assert (buf_size >= used);
1455  }
1456 
1457  return username;
1458 }
1459 
1460 
1484 static void
1485 calculate_nonce (uint64_t nonce_time,
1486  enum MHD_HTTP_Method mthd_e,
1487  const char *method,
1488  const char *rnd,
1489  size_t rnd_size,
1490  const struct sockaddr_storage *saddr,
1491  size_t saddr_size,
1492  const char *uri,
1493  size_t uri_len,
1494  const struct MHD_HTTP_Req_Header *first_header,
1495  const char *realm,
1496  size_t realm_len,
1497  unsigned int bind_options,
1498  struct DigestAlgorithm *da,
1499  char *nonce)
1500 {
1501  mhd_assert (! da->hashing);
1502  if (1)
1503  {
1504  /* Add the timestamp to the hash calculation */
1505  uint8_t timestamp[TIMESTAMP_BIN_SIZE];
1506  /* If the nonce_time is milliseconds, then the same 48 bit value will repeat
1507  * every 8 919 years, which is more than enough to mitigate a replay attack */
1508 #if TIMESTAMP_BIN_SIZE != 6
1509 #error The code needs to be updated here
1510 #endif
1511  timestamp[0] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 0)));
1512  timestamp[1] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 1)));
1513  timestamp[2] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 2)));
1514  timestamp[3] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 3)));
1515  timestamp[4] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 4)));
1516  timestamp[5] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 5)));
1517  MHD_bin_to_hex (timestamp,
1518  sizeof (timestamp),
1519  nonce + digest_get_size (da) * 2);
1520  digest_update (da,
1521  timestamp,
1522  sizeof (timestamp));
1523  }
1524  if (rnd_size > 0)
1525  {
1526  /* Add the unique random value to the hash calculation */
1528  digest_update (da,
1529  rnd,
1530  rnd_size);
1531  }
1532  if ( (MHD_DAUTH_BIND_NONCE_NONE == bind_options) &&
1533  (0 != saddr_size) )
1534  {
1535  /* Add full client address including source port to make unique nonces
1536  * for requests received exactly at the same time */
1538  digest_update (da,
1539  saddr,
1540  saddr_size);
1541  }
1542  if ( (0 != (bind_options & MHD_DAUTH_BIND_NONCE_CLIENT_IP)) &&
1543  (0 != saddr_size) )
1544  {
1545  /* Add the client's IP address to the hash calculation */
1547  if (AF_INET == saddr->ss_family)
1548  digest_update (da,
1549  &((const struct sockaddr_in *) saddr)->sin_addr,
1550  sizeof(((const struct sockaddr_in *) saddr)->sin_addr));
1551 #ifdef HAVE_INET6
1552  else if (AF_INET6 == saddr->ss_family)
1553  digest_update (da,
1554  &((const struct sockaddr_in6 *) saddr)->sin6_addr,
1555  sizeof(((const struct sockaddr_in6 *) saddr)->sin6_addr));
1556 #endif /* HAVE_INET6 */
1557  }
1558  if ( (MHD_DAUTH_BIND_NONCE_NONE == bind_options) ||
1559  (0 != (bind_options & MHD_DAUTH_BIND_NONCE_URI)))
1560  {
1561  /* Add the request method to the hash calculation */
1563  if (MHD_HTTP_MTHD_OTHER != mthd_e)
1564  {
1565  uint8_t mthd_for_hash;
1566  if (MHD_HTTP_MTHD_HEAD != mthd_e)
1567  mthd_for_hash = (uint8_t) mthd_e;
1568  else /* Treat HEAD method in the same way as GET method */
1569  mthd_for_hash = (uint8_t) MHD_HTTP_MTHD_GET;
1570  digest_update (da,
1571  &mthd_for_hash,
1572  sizeof(mthd_for_hash));
1573  }
1574  else
1575  digest_update_str (da, method);
1576  }
1577 
1578  if (0 != (bind_options & MHD_DAUTH_BIND_NONCE_URI))
1579  {
1580  /* Add the request URI to the hash calculation */
1582 
1583  digest_update (da,
1584  uri,
1585  uri_len);
1586  }
1587  if (0 != (bind_options & MHD_DAUTH_BIND_NONCE_URI_PARAMS))
1588  {
1589  /* Add the request URI parameters to the hash calculation */
1590  const struct MHD_HTTP_Req_Header *h;
1591 
1593  for (h = first_header; NULL != h; h = h->next)
1594  {
1595  if (MHD_GET_ARGUMENT_KIND != h->kind)
1596  continue;
1597  digest_update (da, "\0", 2);
1598  if (0 != h->header_size)
1599  digest_update (da, h->header, h->header_size);
1600  digest_update (da, "", 1);
1601  if (0 != h->value_size)
1602  digest_update (da, h->value, h->value_size);
1603  }
1604  }
1605  if ( (MHD_DAUTH_BIND_NONCE_NONE == bind_options) ||
1606  (0 != (bind_options & MHD_DAUTH_BIND_NONCE_REALM)))
1607  {
1608  /* Add the realm to the hash calculation */
1610  digest_update (da,
1611  realm,
1612  realm_len);
1613  }
1614  if (1)
1615  {
1616  uint8_t hash[MAX_DIGEST];
1617  digest_calc_hash (da, hash);
1618  MHD_bin_to_hex (hash,
1619  digest_get_size (da),
1620  nonce);
1621  }
1622 }
1623 
1624 
1640 static bool
1641 is_slot_available (const struct MHD_NonceNc *const nn,
1642  const uint64_t now,
1643  const char *const new_nonce,
1644  size_t new_nonce_len)
1645 {
1646  uint64_t timestamp;
1647  bool timestamp_valid;
1648  mhd_assert (new_nonce_len <= NONCE_STD_LEN (MAX_DIGEST));
1650  if (0 == nn->nonce[0])
1651  return true; /* The slot is empty */
1652 
1653  if (0 == memcmp (nn->nonce, new_nonce, new_nonce_len))
1654  {
1655  /* The slot has the same nonce already. This nonce cannot be registered
1656  * again as it would just clear 'nc' usage history. */
1657  return false;
1658  }
1659 
1660  if (0 != nn->nc)
1661  return true; /* Client already used the nonce in this slot at least
1662  one time, re-use the slot */
1663 
1664  /* The nonce must be zero-terminated */
1665  mhd_assert (0 == nn->nonce[sizeof(nn->nonce) - 1]);
1666  if (0 != nn->nonce[sizeof(nn->nonce) - 1])
1667  return true; /* Wrong nonce format in the slot */
1668 
1669  timestamp_valid = get_nonce_timestamp (nn->nonce, 0, &timestamp);
1670  mhd_assert (timestamp_valid);
1671  if (! timestamp_valid)
1672  return true; /* Invalid timestamp in nonce-nc, should not be possible */
1673 
1674  if ((REUSE_TIMEOUT * 1000) < TRIM_TO_TIMESTAMP (now - timestamp))
1675  return true;
1676 
1677  return false;
1678 }
1679 
1680 
1696 static bool
1697 calculate_add_nonce (struct MHD_Connection *const connection,
1698  uint64_t timestamp,
1699  const char *realm,
1700  size_t realm_len,
1701  struct DigestAlgorithm *da,
1702  char *nonce)
1703 {
1704  struct MHD_Daemon *const daemon = MHD_get_master (connection->daemon);
1705  struct MHD_NonceNc *nn;
1706  const size_t nonce_size = NONCE_STD_LEN (digest_get_size (da));
1707  bool ret;
1708 
1709  mhd_assert (! da->hashing);
1710  mhd_assert (MAX_DIGEST_NONCE_LENGTH >= nonce_size);
1711  mhd_assert (0 != nonce_size);
1712 
1713  calculate_nonce (timestamp,
1714  connection->rq.http_mthd,
1715  connection->rq.method,
1716  daemon->digest_auth_random,
1717  daemon->digest_auth_rand_size,
1718  connection->addr,
1719  (size_t) connection->addr_len,
1720  connection->rq.url,
1721  connection->rq.url_len,
1722  connection->rq.headers_received,
1723  realm,
1724  realm_len,
1725  daemon->dauth_bind_type,
1726  da,
1727  nonce);
1728 
1729 #ifdef MHD_DIGEST_HAS_EXT_ERROR
1730  if (digest_ext_error (da))
1731  return false;
1732 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
1733 
1734  if (0 == daemon->nonce_nc_size)
1735  return false;
1736 
1737  /* Sanity check for values */
1739 
1740  nn = daemon->nnc + get_nonce_nc_idx (daemon->nonce_nc_size,
1741  nonce,
1742  nonce_size);
1743 
1744  MHD_mutex_lock_chk_ (&daemon->nnc_lock);
1745  if (is_slot_available (nn, timestamp, nonce, nonce_size))
1746  {
1747  memcpy (nn->nonce,
1748  nonce,
1749  nonce_size);
1750  nn->nonce[nonce_size] = 0; /* With terminating zero */
1751  nn->nc = 0;
1752  nn->nmask = 0;
1753  ret = true;
1754  }
1755  else
1756  ret = false;
1757  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
1758 
1759  return ret;
1760 }
1761 
1762 
1764 
1776 static bool
1778  const char *realm,
1779  struct DigestAlgorithm *da,
1780  char *nonce)
1781 {
1782  const uint64_t timestamp1 = MHD_monotonic_msec_counter ();
1783  const size_t realm_len = strlen (realm);
1784  mhd_assert (! da->hashing);
1785 
1786 #ifdef HAVE_MESSAGES
1787  if (0 == MHD_get_master (connection->daemon)->digest_auth_rand_size)
1788  MHD_DLOG (connection->daemon,
1789  _ ("Random value was not initialised by " \
1790  "MHD_OPTION_DIGEST_AUTH_RANDOM or " \
1791  "MHD_OPTION_DIGEST_AUTH_RANDOM_COPY, generated nonces " \
1792  "are predictable.\n"));
1793 #endif
1794 
1795  if (! calculate_add_nonce (connection, timestamp1, realm, realm_len, da,
1796  nonce))
1797  {
1798  /* Either:
1799  * 1. The same nonce was already generated. If it will be used then one
1800  * of the clients will fail (as no initial 'nc' value could be given to
1801  * the client, the second client which will use 'nc=00000001' will fail).
1802  * 2. Another nonce uses the same slot, and this nonce never has been
1803  * used by the client and this nonce is still fresh enough.
1804  */
1805  const size_t digest_size = digest_get_size (da);
1806  char nonce2[NONCE_STD_LEN (MAX_DIGEST) + 1];
1807  uint64_t timestamp2;
1808 #ifdef MHD_DIGEST_HAS_EXT_ERROR
1809  if (digest_ext_error (da))
1810  return false; /* No need to re-try */
1811 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
1812  if (0 == MHD_get_master (connection->daemon)->nonce_nc_size)
1813  return false; /* No need to re-try */
1814 
1815  timestamp2 = MHD_monotonic_msec_counter ();
1816  if (timestamp1 == timestamp2)
1817  {
1818  /* The timestamps are equal, need to generate some arbitrary
1819  * difference for nonce. */
1820  /* As the number is needed only to differentiate clients, weak
1821  * pseudo-random generators could be used. Seeding is not needed. */
1822  uint64_t base1;
1823  uint32_t base2;
1824  uint16_t base3;
1825  uint8_t base4;
1826 #ifdef HAVE_RANDOM
1827  base1 = ((uint64_t) random ()) ^ UINT64_C (0x54a5acff5be47e63);
1828  base4 = 0xb8;
1829 #elif defined(HAVE_RAND)
1830  base1 = ((uint64_t) rand ()) ^ UINT64_C (0xc4bcf553b12f3965);
1831  base4 = 0x92;
1832 #else
1833  /* Monotonic msec counter alone does not really help here as it is already
1834  known that this value is not unique. */
1835  base1 = ((uint64_t) (uintptr_t) nonce2) ^ UINT64_C (0xf2e1b21bc6c92655);
1836  base2 = ((uint32_t) (base1 >> 32)) ^ ((uint32_t) base1);
1837  base2 = _MHD_ROTR32 (base2, 4);
1838  base3 = ((uint16_t) (base2 >> 16)) ^ ((uint16_t) base2);
1839  base4 = ((uint8_t) (base3 >> 8)) ^ ((uint8_t) base3);
1840  base1 = ((uint64_t) MHD_monotonic_msec_counter ())
1841  ^ UINT64_C (0xccab93f72cf5b15);
1842 #endif
1843  base2 = ((uint32_t) (base1 >> 32)) ^ ((uint32_t) base1);
1844  base2 = _MHD_ROTL32 (base2, (((base4 >> 4) ^ base4) % 32));
1845  base3 = ((uint16_t) (base2 >> 16)) ^ ((uint16_t) base2);
1846  base4 = ((uint8_t) (base3 >> 8)) ^ ((uint8_t) base3);
1847  /* Use up to 127 ms difference */
1848  timestamp2 -= (base4 & DAUTH_JUMPBACK_MAX);
1849  if (timestamp1 == timestamp2)
1850  timestamp2 -= 2; /* Fallback value */
1851  }
1852  digest_reset (da);
1853  if (! calculate_add_nonce (connection, timestamp2, realm, realm_len, da,
1854  nonce2))
1855  {
1856  /* No free slot has been found. Re-tries are expensive, just use
1857  * the generated nonce. As it is not stored in nonce-nc map array,
1858  * the next request of the client will be recognized as valid, but 'stale'
1859  * so client should re-try automatically. */
1860  return false;
1861  }
1862  memcpy (nonce, nonce2, NONCE_STD_LEN (digest_size));
1863  }
1864  return true;
1865 }
1866 
1867 
1869 
1886 _MHD_static_inline void
1887 calc_userdigest (struct DigestAlgorithm *da,
1888  const char *username, const size_t username_len,
1889  const char *realm, const size_t realm_len,
1890  const char *password,
1891  uint8_t *ha1_bin)
1892 {
1893  mhd_assert (! da->hashing);
1894  digest_update (da, username, username_len);
1896  digest_update (da, realm, realm_len);
1898  digest_update_str (da, password);
1899  digest_calc_hash (da, ha1_bin);
1900 }
1901 
1902 
1938  const char *username,
1939  const char *realm,
1940  const char *password,
1941  void *userdigest_bin,
1942  size_t bin_buf_size)
1943 {
1944  struct DigestAlgorithm da;
1945  enum MHD_Result ret;
1946  if (! digest_init_one_time (&da, get_base_digest_algo (algo3)))
1947  return MHD_NO;
1948 
1949  if (digest_get_size (&da) > bin_buf_size)
1950  ret = MHD_NO;
1951  else
1952  {
1953  calc_userdigest (&da,
1954  username,
1955  strlen (username),
1956  realm,
1957  strlen (realm),
1958  password,
1959  userdigest_bin);
1960  ret = MHD_YES;
1961 
1962 #ifdef MHD_DIGEST_HAS_EXT_ERROR
1963  if (digest_ext_error (&da))
1964  ret = MHD_NO;
1965 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
1966  }
1967  digest_deinit (&da);
1968 
1969  return ret;
1970 }
1971 
1972 
1986 _MHD_static_inline void
1987 calc_userhash (struct DigestAlgorithm *da,
1988  const char *username, const size_t username_len,
1989  const char *realm, const size_t realm_len,
1990  uint8_t *digest_bin)
1991 {
1992  mhd_assert (NULL != username);
1993  mhd_assert (! da->hashing);
1994  digest_update (da, username, username_len);
1996  digest_update (da, realm, realm_len);
1997  digest_calc_hash (da, digest_bin);
1998 }
1999 
2000 
2043  const char *username,
2044  const char *realm,
2045  void *userhash_bin,
2046  size_t bin_buf_size)
2047 {
2048  struct DigestAlgorithm da;
2049  enum MHD_Result ret;
2050 
2051  if (! digest_init_one_time (&da, get_base_digest_algo (algo3)))
2052  return MHD_NO;
2053  if (digest_get_size (&da) > bin_buf_size)
2054  ret = MHD_NO;
2055  else
2056  {
2057  calc_userhash (&da,
2058  username,
2059  strlen (username),
2060  realm,
2061  strlen (realm),
2062  userhash_bin);
2063  ret = MHD_YES;
2064 
2065 #ifdef MHD_DIGEST_HAS_EXT_ERROR
2066  if (digest_ext_error (&da))
2067  ret = MHD_NO;
2068 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
2069  }
2070  digest_deinit (&da);
2071 
2072  return ret;
2073 }
2074 
2075 
2118  const char *username,
2119  const char *realm,
2120  char *userhash_hex,
2121  size_t hex_buf_size)
2122 {
2123  uint8_t userhash_bin[MAX_DIGEST];
2124  size_t digest_size;
2125 
2126  digest_size = digest_get_hash_size (algo3);
2127  if (digest_size * 2 + 1 > hex_buf_size)
2128  return MHD_NO;
2129  if (MHD_NO == MHD_digest_auth_calc_userhash (algo3, username, realm,
2130  userhash_bin, MAX_DIGEST))
2131  return MHD_NO;
2132 
2133  MHD_bin_to_hex_z (userhash_bin, digest_size, userhash_hex);
2134  return MHD_YES;
2135 }
2136 
2137 
2138 struct test_header_param
2139 {
2140  struct MHD_Connection *connection;
2141  size_t num_headers;
2142 };
2143 
2157 static enum MHD_Result
2158 test_header (void *cls,
2159  const char *key,
2160  size_t key_size,
2161  const char *value,
2162  size_t value_size,
2163  enum MHD_ValueKind kind)
2164 {
2165  struct test_header_param *const param = (struct test_header_param *) cls;
2166  struct MHD_Connection *connection = param->connection;
2167  struct MHD_HTTP_Req_Header *pos;
2168  size_t i;
2169 
2170  param->num_headers++;
2171  i = 0;
2172  for (pos = connection->rq.headers_received; NULL != pos; pos = pos->next)
2173  {
2174  if (kind != pos->kind)
2175  continue;
2176  if (++i == param->num_headers)
2177  {
2178  if (key_size != pos->header_size)
2179  return MHD_NO;
2180  if (value_size != pos->value_size)
2181  return MHD_NO;
2182  if (0 != key_size)
2183  {
2184  mhd_assert (NULL != key);
2185  mhd_assert (NULL != pos->header);
2186  if (0 != memcmp (key,
2187  pos->header,
2188  key_size))
2189  return MHD_NO;
2190  }
2191  if (0 != value_size)
2192  {
2193  mhd_assert (NULL != value);
2194  mhd_assert (NULL != pos->value);
2195  if (0 != memcmp (value,
2196  pos->value,
2197  value_size))
2198  return MHD_NO;
2199  }
2200  return MHD_YES;
2201  }
2202  }
2203  return MHD_NO;
2204 }
2205 
2206 
2218 static bool
2220  char *args)
2221 {
2222  struct MHD_HTTP_Req_Header *pos;
2223  enum MHD_Result ret;
2224  struct test_header_param param;
2225 
2226  param.connection = connection;
2227  param.num_headers = 0;
2228  ret = MHD_parse_arguments_ (connection,
2230  args,
2231  &test_header,
2232  &param);
2233  if (MHD_NO == ret)
2234  {
2235  return false;
2236  }
2237  /* also check that the number of headers matches */
2238  for (pos = connection->rq.headers_received; NULL != pos; pos = pos->next)
2239  {
2240  if (MHD_GET_ARGUMENT_KIND != pos->kind)
2241  continue;
2242  param.num_headers--;
2243  }
2244  if (0 != param.num_headers)
2245  {
2246  /* argument count mismatch */
2247  return false;
2248  }
2249  return true;
2250 }
2251 
2252 
2265 static bool
2266 check_uri_match (struct MHD_Connection *connection, char *uri, size_t uri_len)
2267 {
2268  char *qmark;
2269  char *args;
2270  struct MHD_Daemon *const daemon = connection->daemon;
2271 
2272  uri[uri_len] = 0;
2273  qmark = memchr (uri,
2274  '?',
2275  uri_len);
2276  if (NULL != qmark)
2277  *qmark = '\0';
2278 
2279  /* Need to unescape URI before comparing with connection->url */
2280  uri_len = daemon->unescape_callback (daemon->unescape_callback_cls,
2281  connection,
2282  uri);
2283  if ((uri_len != connection->rq.url_len) ||
2284  (0 != memcmp (uri, connection->rq.url, uri_len)))
2285  {
2286 #ifdef HAVE_MESSAGES
2287  MHD_DLOG (daemon,
2288  _ ("Authentication failed, URI does not match.\n"));
2289 #endif
2290  return false;
2291  }
2292 
2293  args = (NULL != qmark) ? (qmark + 1) : uri + uri_len;
2294 
2295  if (! check_argument_match (connection,
2296  args) )
2297  {
2298 #ifdef HAVE_MESSAGES
2299  MHD_DLOG (daemon,
2300  _ ("Authentication failed, arguments do not match.\n"));
2301 #endif
2302  return false;
2303  }
2304  return true;
2305 }
2306 
2307 
2311 #define _MHD_STATIC_UNQ_BUFFER_SIZE 128
2312 
2313 
2323 static char *
2325  char **ptmp2,
2326  size_t *ptmp2_size,
2327  size_t required_size)
2328 {
2329  mhd_assert ((0 == *ptmp2_size) || (NULL != *ptmp2));
2330  mhd_assert ((NULL != *ptmp2) || (0 == *ptmp2_size));
2331  mhd_assert ((0 == *ptmp2_size) || \
2332  (_MHD_STATIC_UNQ_BUFFER_SIZE < *ptmp2_size));
2333 
2334  if (required_size <= _MHD_STATIC_UNQ_BUFFER_SIZE)
2335  return tmp1;
2336 
2337  if (required_size <= *ptmp2_size)
2338  return *ptmp2;
2339 
2340  if (required_size > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE)
2341  return NULL;
2342  if (NULL != *ptmp2)
2343  free (*ptmp2);
2344  *ptmp2 = (char *) malloc (required_size);
2345  if (NULL == *ptmp2)
2346  *ptmp2_size = 0;
2347  else
2348  *ptmp2_size = required_size;
2349  return *ptmp2;
2350 }
2351 
2352 
2357 {
2360  _MHD_UNQ_OUT_OF_MEM = 3
2361 };
2362 
2372 static enum _MHD_GetUnqResult
2373 get_unquoted_param (const struct MHD_RqDAuthParam *param,
2374  char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE],
2375  char **ptmp2,
2376  size_t *ptmp2_size,
2377  struct _MHD_str_w_len *unquoted)
2378 {
2379  char *str;
2380  size_t len;
2381  mhd_assert (NULL != param->value.str);
2382  mhd_assert (0 != param->value.len);
2383 
2384  if (! param->quoted)
2385  {
2386  unquoted->str = param->value.str;
2387  unquoted->len = param->value.len;
2388  return _MHD_UNQ_OK;
2389  }
2390  /* The value is present and is quoted, needs to be copied and unquoted */
2391  str = get_buffer_for_size (tmp1, ptmp2, ptmp2_size, param->value.len);
2392  if (NULL == str)
2393  return (param->value.len > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE) ?
2395 
2396  len = MHD_str_unquote (param->value.str, param->value.len, str);
2397  unquoted->str = str;
2398  unquoted->len = len;
2399  mhd_assert (0 != unquoted->len);
2400  mhd_assert (unquoted->len < param->value.len);
2401  return _MHD_UNQ_OK;
2402 }
2403 
2404 
2415 static enum _MHD_GetUnqResult
2416 get_unquoted_param_copy (const struct MHD_RqDAuthParam *param,
2417  char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE],
2418  char **ptmp2,
2419  size_t *ptmp2_size,
2420  struct _MHD_mstr_w_len *unquoted)
2421 {
2422  mhd_assert (NULL != param->value.str);
2423  mhd_assert (0 != param->value.len);
2424 
2425  /* The value is present and is quoted, needs to be copied and unquoted */
2426  /* Allocate buffer with one more additional byte for zero-termination */
2427  unquoted->str =
2428  get_buffer_for_size (tmp1, ptmp2, ptmp2_size, param->value.len + 1);
2429 
2430  if (NULL == unquoted->str)
2431  return (param->value.len + 1 > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE) ?
2433 
2434  if (! param->quoted)
2435  {
2436  memcpy (unquoted->str, param->value.str, param->value.len);
2437  unquoted->len = param->value.len;
2438  return _MHD_UNQ_OK;
2439  }
2440 
2441  unquoted->len =
2442  MHD_str_unquote (param->value.str, param->value.len, unquoted->str);
2443  mhd_assert (0 != unquoted->len);
2444  mhd_assert (unquoted->len < param->value.len);
2445  return _MHD_UNQ_OK;
2446 }
2447 
2448 
2457 _MHD_static_inline bool
2458 is_param_equal (const struct MHD_RqDAuthParam *param,
2459  const char *const str,
2460  const size_t str_len)
2461 {
2462  mhd_assert (NULL != param->value.str);
2463  mhd_assert (0 != param->value.len);
2464  if (param->quoted)
2465  return MHD_str_equal_quoted_bin_n (param->value.str, param->value.len,
2466  str, str_len);
2467  return (str_len == param->value.len) &&
2468  (0 == memcmp (str, param->value.str, str_len));
2469 
2470 }
2471 
2472 
2481 _MHD_static_inline bool
2482 is_param_equal_caseless (const struct MHD_RqDAuthParam *param,
2483  const char *const str,
2484  const size_t str_len)
2485 {
2486  mhd_assert (NULL != param->value.str);
2487  mhd_assert (0 != param->value.len);
2488  if (param->quoted)
2489  return MHD_str_equal_quoted_bin_n (param->value.str, param->value.len,
2490  str, str_len);
2491  return (str_len == param->value.len) &&
2492  (0 == memcmp (str, param->value.str, str_len));
2493 
2494 }
2495 
2496 
2533 static enum MHD_DigestAuthResult
2534 digest_auth_check_all_inner (struct MHD_Connection *connection,
2535  const char *realm,
2536  const char *username,
2537  const char *password,
2538  const uint8_t *userdigest,
2539  unsigned int nonce_timeout,
2540  uint32_t max_nc,
2541  enum MHD_DigestAuthMultiQOP mqop,
2542  enum MHD_DigestAuthMultiAlgo3 malgo3,
2543  char **pbuf,
2544  struct DigestAlgorithm *da)
2545 {
2546  struct MHD_Daemon *daemon = MHD_get_master (connection->daemon);
2547  enum MHD_DigestAuthAlgo3 c_algo;
2548  enum MHD_DigestAuthQOP c_qop;
2549  unsigned int digest_size;
2550  uint8_t hash1_bin[MAX_DIGEST];
2551  uint8_t hash2_bin[MAX_DIGEST];
2552 #if 0
2553  const char *hentity = NULL; /* "auth-int" is not supported */
2554 #endif
2555  uint64_t nonce_time;
2556  uint64_t nci;
2557  const struct MHD_RqDAuth *params;
2561  char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE];
2562  char **const ptmp2 = pbuf;
2563  size_t tmp2_size;
2564  struct _MHD_str_w_len unquoted;
2565  struct _MHD_mstr_w_len unq_copy;
2566  enum _MHD_GetUnqResult unq_res;
2567  size_t username_len;
2568  size_t realm_len;
2569 
2570  mhd_assert ((NULL != password) || (NULL != userdigest));
2571  mhd_assert (! ((NULL != userdigest) && (NULL != password)));
2572 
2573  tmp2_size = 0;
2574 
2575  params = MHD_get_rq_dauth_params_ (connection);
2576  if (NULL == params)
2577  return MHD_DAUTH_WRONG_HEADER;
2578 
2579  /* ** Initial parameters checks and setup ** */
2580  /* Get client's algorithm */
2581  c_algo = params->algo3;
2582  /* Check whether client's algorithm is allowed by function parameter */
2583  if (((unsigned int) c_algo) !=
2584  (((unsigned int) c_algo) & ((unsigned int) malgo3)))
2585  return MHD_DAUTH_WRONG_ALGO;
2586  /* Check whether client's algorithm is supported */
2587  if (0 != (((unsigned int) c_algo) & MHD_DIGEST_AUTH_ALGO3_SESSION))
2588  {
2589 #ifdef HAVE_MESSAGES
2590  MHD_DLOG (connection->daemon,
2591  _ ("The 'session' algorithms are not supported.\n"));
2592 #endif /* HAVE_MESSAGES */
2593  return MHD_DAUTH_WRONG_ALGO;
2594  }
2595 #ifndef MHD_MD5_SUPPORT
2596  if (0 != (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_MD5))
2597  {
2598 #ifdef HAVE_MESSAGES
2599  MHD_DLOG (connection->daemon,
2600  _ ("The MD5 algorithm is not supported by this MHD build.\n"));
2601 #endif /* HAVE_MESSAGES */
2602  return MHD_DAUTH_WRONG_ALGO;
2603  }
2604 #endif /* ! MHD_MD5_SUPPORT */
2605 #ifndef MHD_SHA256_SUPPORT
2606  if (0 != (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_SHA256))
2607  {
2608 #ifdef HAVE_MESSAGES
2609  MHD_DLOG (connection->daemon,
2610  _ ("The SHA-256 algorithm is not supported by "
2611  "this MHD build.\n"));
2612 #endif /* HAVE_MESSAGES */
2613  return MHD_DAUTH_WRONG_ALGO;
2614  }
2615 #endif /* ! MHD_SHA256_SUPPORT */
2616 #ifndef MHD_SHA512_256_SUPPORT
2617  if (0 != (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_SHA512_256))
2618  {
2619 #ifdef HAVE_MESSAGES
2620  MHD_DLOG (connection->daemon,
2621  _ ("The SHA-512/256 algorithm is not supported by "
2622  "this MHD build.\n"));
2623 #endif /* HAVE_MESSAGES */
2624  return MHD_DAUTH_WRONG_ALGO;
2625  }
2626 #endif /* ! MHD_SHA512_256_SUPPORT */
2627  if (! digest_init_one_time (da, get_base_digest_algo (c_algo)))
2628  MHD_PANIC (_ ("Wrong 'malgo3' value, API violation"));
2629  /* Check 'mqop' value */
2630  c_qop = params->qop;
2631  /* Check whether client's QOP is allowed by function parameter */
2632  if (((unsigned int) c_qop) !=
2633  (((unsigned int) c_qop) & ((unsigned int) mqop)))
2634  return MHD_DAUTH_WRONG_QOP;
2635  if (0 != (((unsigned int) c_qop) & MHD_DIGEST_AUTH_QOP_AUTH_INT))
2636  {
2637 #ifdef HAVE_MESSAGES
2638  MHD_DLOG (connection->daemon,
2639  _ ("The 'auth-int' QOP is not supported.\n"));
2640 #endif /* HAVE_MESSAGES */
2641  return MHD_DAUTH_WRONG_QOP;
2642  }
2643 #ifdef HAVE_MESSAGES
2644  if ((MHD_DIGEST_AUTH_QOP_NONE == c_qop) &&
2645  (0 == (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_MD5)))
2646  MHD_DLOG (connection->daemon,
2647  _ ("RFC2069 with SHA-256 or SHA-512/256 algorithm is " \
2648  "non-standard extension.\n"));
2649 #endif /* HAVE_MESSAGES */
2650 
2651  digest_size = digest_get_size (da);
2652 
2653  /* ** A quick check for presence of all required parameters ** */
2654 
2655  if ((NULL == params->username.value.str) &&
2656  (NULL == params->username_ext.value.str))
2657  return MHD_DAUTH_WRONG_USERNAME;
2658  else if ((NULL != params->username.value.str) &&
2659  (NULL != params->username_ext.value.str))
2660  return MHD_DAUTH_WRONG_USERNAME; /* Parameters cannot be used together */
2661  else if ((NULL != params->username_ext.value.str) &&
2662  (MHD_DAUTH_EXT_PARAM_MIN_LEN > params->username_ext.value.len))
2663  return MHD_DAUTH_WRONG_USERNAME; /* Broken extended notation */
2664  else if (params->userhash && (NULL == params->username.value.str))
2665  return MHD_DAUTH_WRONG_USERNAME; /* Userhash cannot be used with extended notation */
2666  else if (params->userhash && (digest_size * 2 > params->username.value.len))
2667  return MHD_DAUTH_WRONG_USERNAME; /* Too few chars for correct userhash */
2668  else if (params->userhash && (digest_size * 4 < params->username.value.len))
2669  return MHD_DAUTH_WRONG_USERNAME; /* Too many chars for correct userhash */
2670 
2671  if (NULL == params->realm.value.str)
2672  return MHD_DAUTH_WRONG_REALM;
2673  else if (((NULL == userdigest) || params->userhash) &&
2674  (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < params->realm.value.len))
2675  return MHD_DAUTH_TOO_LARGE; /* Realm is too large and should be used in hash calculations */
2676 
2677  if (MHD_DIGEST_AUTH_QOP_NONE != c_qop)
2678  {
2679  if (NULL == params->nc.value.str)
2680  return MHD_DAUTH_WRONG_HEADER;
2681  else if (0 == params->nc.value.len)
2682  return MHD_DAUTH_WRONG_HEADER;
2683  else if (4 * 8 < params->nc.value.len) /* Four times more than needed */
2684  return MHD_DAUTH_WRONG_HEADER;
2685 
2686  if (NULL == params->cnonce.value.str)
2687  return MHD_DAUTH_WRONG_HEADER;
2688  else if (0 == params->cnonce.value.len)
2689  return MHD_DAUTH_WRONG_HEADER;
2690  else if (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < params->cnonce.value.len)
2691  return MHD_DAUTH_TOO_LARGE;
2692  }
2693 
2694  /* The QOP parameter was checked already */
2695 
2696  if (NULL == params->uri.value.str)
2697  return MHD_DAUTH_WRONG_URI;
2698  else if (0 == params->uri.value.len)
2699  return MHD_DAUTH_WRONG_URI;
2700  else if (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < params->uri.value.len)
2701  return MHD_DAUTH_TOO_LARGE;
2702 
2703  if (NULL == params->nonce.value.str)
2704  return MHD_DAUTH_NONCE_WRONG;
2705  else if (0 == params->nonce.value.len)
2706  return MHD_DAUTH_NONCE_WRONG;
2707  else if (NONCE_STD_LEN (digest_size) * 2 < params->nonce.value.len)
2708  return MHD_DAUTH_NONCE_WRONG;
2709 
2710  if (NULL == params->response.value.str)
2711  return MHD_DAUTH_RESPONSE_WRONG;
2712  else if (0 == params->response.value.len)
2713  return MHD_DAUTH_RESPONSE_WRONG;
2714  else if (digest_size * 4 < params->response.value.len)
2715  return MHD_DAUTH_RESPONSE_WRONG;
2716 
2717  /* ** Check simple parameters match ** */
2718 
2719  /* Check 'algorithm' */
2720  /* The 'algorithm' was checked at the start of the function */
2721  /* 'algorithm' valid */
2722 
2723  /* Check 'qop' */
2724  /* The 'qop' was checked at the start of the function */
2725  /* 'qop' valid */
2726 
2727  /* Check 'realm' */
2728  realm_len = strlen (realm);
2729  if (! is_param_equal (&params->realm, realm, realm_len))
2730  return MHD_DAUTH_WRONG_REALM;
2731  /* 'realm' valid */
2732 
2733  /* Check 'username' */
2734  username_len = strlen (username);
2735  if (! params->userhash)
2736  {
2737  if (NULL != params->username.value.str)
2738  { /* Username in standard notation */
2739  if (! is_param_equal (&params->username, username, username_len))
2740  return MHD_DAUTH_WRONG_USERNAME;
2741  }
2742  else
2743  { /* Username in extended notation */
2744  char *r_uname;
2745  size_t buf_size = params->username_ext.value.len;
2746  ssize_t res;
2747 
2748  mhd_assert (NULL != params->username_ext.value.str);
2749  mhd_assert (MHD_DAUTH_EXT_PARAM_MIN_LEN <= buf_size); /* It was checked already */
2750  buf_size += 1; /* For zero-termination */
2751  buf_size -= MHD_DAUTH_EXT_PARAM_MIN_LEN;
2752  r_uname = get_buffer_for_size (tmp1, ptmp2, &tmp2_size, buf_size);
2753  if (NULL == r_uname)
2754  return (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < buf_size) ?
2756  res = get_rq_extended_uname_copy_z (params->username_ext.value.str,
2757  params->username_ext.value.len,
2758  r_uname, buf_size);
2759  if (0 > res)
2760  return MHD_DAUTH_WRONG_HEADER; /* Broken extended notation */
2761  if ((username_len != (size_t) res) ||
2762  (0 != memcmp (username, r_uname, username_len)))
2763  return MHD_DAUTH_WRONG_USERNAME;
2764  }
2765  }
2766  else
2767  { /* Userhash */
2768  mhd_assert (NULL != params->username.value.str);
2769  calc_userhash (da, username, username_len, realm, realm_len, hash1_bin);
2770 #ifdef MHD_DIGEST_HAS_EXT_ERROR
2771  if (digest_ext_error (da))
2772  return MHD_DAUTH_ERROR;
2773 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
2774  mhd_assert (sizeof (tmp1) >= (2 * digest_size));
2775  MHD_bin_to_hex (hash1_bin, digest_size, tmp1);
2776  if (! is_param_equal_caseless (&params->username, tmp1, 2 * digest_size))
2777  return MHD_DAUTH_WRONG_USERNAME;
2778  /* To simplify the logic, the digest is reset here instead of resetting
2779  before the next hash calculation. */
2780  digest_reset (da);
2781  }
2782  /* 'username' valid */
2783 
2784  /* ** Do basic nonce and nonce-counter checks (size, timestamp) ** */
2785 
2786  /* Get 'nc' digital value */
2787  if (MHD_DIGEST_AUTH_QOP_NONE != c_qop)
2788  {
2789 
2790  unq_res = get_unquoted_param (&params->nc, tmp1, ptmp2, &tmp2_size,
2791  &unquoted);
2792  if (_MHD_UNQ_OK != unq_res)
2793  return MHD_DAUTH_ERROR;
2794 
2795  if (unquoted.len != MHD_strx_to_uint64_n_ (unquoted.str,
2796  unquoted.len,
2797  &nci))
2798  {
2799 #ifdef HAVE_MESSAGES
2800  MHD_DLOG (daemon,
2801  _ ("Authentication failed, invalid nc format.\n"));
2802 #endif
2803  return MHD_DAUTH_WRONG_HEADER; /* invalid nonce format */
2804  }
2805  if (0 == nci)
2806  {
2807 #ifdef HAVE_MESSAGES
2808  MHD_DLOG (daemon,
2809  _ ("Authentication failed, invalid 'nc' value.\n"));
2810 #endif
2811  return MHD_DAUTH_WRONG_HEADER; /* invalid nc value */
2812  }
2813  if ((0 != max_nc) && (max_nc < nci))
2814  return MHD_DAUTH_NONCE_STALE; /* Too large 'nc' value */
2815  }
2816  else
2817  nci = 1; /* Force 'nc' value */
2818  /* Got 'nc' digital value */
2819 
2820  /* Get 'nonce' with basic checks */
2821  unq_res = get_unquoted_param (&params->nonce, tmp1, ptmp2, &tmp2_size,
2822  &unquoted);
2823  if (_MHD_UNQ_OK != unq_res)
2824  return MHD_DAUTH_ERROR;
2825 
2826  if ((NONCE_STD_LEN (digest_size) != unquoted.len) ||
2827  (! get_nonce_timestamp (unquoted.str, unquoted.len, &nonce_time)))
2828  {
2829 #ifdef HAVE_MESSAGES
2830  MHD_DLOG (daemon,
2831  _ ("Authentication failed, invalid nonce format.\n"));
2832 #endif
2833  return MHD_DAUTH_NONCE_WRONG;
2834  }
2835 
2836  if (1)
2837  {
2838  uint64_t t;
2839 
2841  /*
2842  * First level vetting for the nonce validity: if the timestamp
2843  * attached to the nonce exceeds `nonce_timeout', then the nonce is
2844  * stale.
2845  */
2846  if (TRIM_TO_TIMESTAMP (t - nonce_time) > (nonce_timeout * 1000))
2847  return MHD_DAUTH_NONCE_STALE; /* too old */
2848  }
2849  if (1)
2850  {
2851  enum MHD_CheckNonceNC_ nonce_nc_check;
2852  /*
2853  * Checking if that combination of nonce and nc is sound
2854  * and not a replay attack attempt. Refuse if nonce was not
2855  * generated previously.
2856  */
2857  nonce_nc_check = check_nonce_nc (connection,
2858  unquoted.str,
2859  NONCE_STD_LEN (digest_size),
2860  nonce_time,
2861  nci);
2862  if (MHD_CHECK_NONCENC_STALE == nonce_nc_check)
2863  {
2864 #ifdef HAVE_MESSAGES
2865  if (MHD_DIGEST_AUTH_QOP_NONE != c_qop)
2866  MHD_DLOG (daemon,
2867  _ ("Stale nonce received. If this happens a lot, you should "
2868  "probably increase the size of the nonce array.\n"));
2869  else
2870  MHD_DLOG (daemon,
2871  _ ("Stale nonce received. This is expected when client " \
2872  "uses RFC2069-compatible mode and makes more than one " \
2873  "request.\n"));
2874 #endif
2875  return MHD_DAUTH_NONCE_STALE;
2876  }
2877  else if (MHD_CHECK_NONCENC_WRONG == nonce_nc_check)
2878  {
2879 #ifdef HAVE_MESSAGES
2880  MHD_DLOG (daemon,
2881  _ ("Received nonce that was not "
2882  "generated by MHD. This may indicate an attack attempt.\n"));
2883 #endif
2884  return MHD_DAUTH_NONCE_WRONG;
2885  }
2886  mhd_assert (MHD_CHECK_NONCENC_OK == nonce_nc_check);
2887  }
2888  /* The nonce was generated by MHD, is not stale and nonce-nc combination was
2889  not used before */
2890 
2891  /* ** Build H(A2) and check URI match in the header and in the request ** */
2892 
2893  /* Get 'uri' */
2894  mhd_assert (! da->hashing);
2895  digest_update_str (da, connection->rq.method);
2897 #if 0
2898  /* TODO: add support for "auth-int" */
2899  digest_update_str (da, hentity);
2901 #endif
2902  unq_res = get_unquoted_param_copy (&params->uri, tmp1, ptmp2, &tmp2_size,
2903  &unq_copy);
2904  if (_MHD_UNQ_OK != unq_res)
2905  return MHD_DAUTH_ERROR;
2906 
2907  digest_update (da, unq_copy.str, unq_copy.len);
2908  /* The next check will modify copied URI string */
2909  if (! check_uri_match (connection, unq_copy.str, unq_copy.len))
2910  return MHD_DAUTH_WRONG_URI;
2911  digest_calc_hash (da, hash2_bin);
2912 #ifdef MHD_DIGEST_HAS_EXT_ERROR
2913  /* Skip digest calculation external error check, the next one checks both */
2914 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
2915  /* Got H(A2) */
2916 
2917  /* ** Build H(A1) ** */
2918  if (NULL == userdigest)
2919  {
2920  mhd_assert (! da->hashing);
2921  digest_reset (da);
2922  calc_userdigest (da,
2923  username, username_len,
2924  realm, realm_len,
2925  password,
2926  hash1_bin);
2927  }
2928  /* TODO: support '-sess' versions */
2929 #ifdef MHD_DIGEST_HAS_EXT_ERROR
2930  if (digest_ext_error (da))
2931  return MHD_DAUTH_ERROR;
2932 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
2933  /* Got H(A1) */
2934 
2935  /* ** Check 'response' ** */
2936 
2937  mhd_assert (! da->hashing);
2938  digest_reset (da);
2939  /* Update digest with H(A1) */
2940  mhd_assert (sizeof (tmp1) >= (digest_size * 2));
2941  if (NULL == userdigest)
2942  MHD_bin_to_hex (hash1_bin, digest_size, tmp1);
2943  else
2944  MHD_bin_to_hex (userdigest, digest_size, tmp1);
2945  digest_update (da, (const uint8_t *) tmp1, digest_size * 2);
2946 
2947  /* H(A1) is not needed anymore, reuse the buffer.
2948  * Use hash1_bin for the client's 'response' decoded to binary form. */
2949  unq_res = get_unquoted_param (&params->response, tmp1, ptmp2, &tmp2_size,
2950  &unquoted);
2951  if (_MHD_UNQ_OK != unq_res)
2952  return MHD_DAUTH_ERROR;
2953  if (digest_size != MHD_hex_to_bin (unquoted.str, unquoted.len, hash1_bin))
2954  return MHD_DAUTH_RESPONSE_WRONG;
2955 
2956  /* Update digest with ':' */
2958  /* Update digest with 'nonce' text value */
2959  unq_res = get_unquoted_param (&params->nonce, tmp1, ptmp2, &tmp2_size,
2960  &unquoted);
2961  if (_MHD_UNQ_OK != unq_res)
2962  return MHD_DAUTH_ERROR;
2963  digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
2964  /* Update digest with ':' */
2966  if (MHD_DIGEST_AUTH_QOP_NONE != c_qop)
2967  {
2968  /* Update digest with 'nc' text value */
2969  unq_res = get_unquoted_param (&params->nc, tmp1, ptmp2, &tmp2_size,
2970  &unquoted);
2971  if (_MHD_UNQ_OK != unq_res)
2972  return MHD_DAUTH_ERROR;
2973  digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
2974  /* Update digest with ':' */
2976  /* Update digest with 'cnonce' value */
2977  unq_res = get_unquoted_param (&params->cnonce, tmp1, ptmp2, &tmp2_size,
2978  &unquoted);
2979  if (_MHD_UNQ_OK != unq_res)
2980  return MHD_DAUTH_ERROR;
2981  digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
2982  /* Update digest with ':' */
2984  /* Update digest with 'qop' value */
2985  unq_res = get_unquoted_param (&params->qop_raw, tmp1, ptmp2, &tmp2_size,
2986  &unquoted);
2987  if (_MHD_UNQ_OK != unq_res)
2988  return MHD_DAUTH_ERROR;
2989  digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
2990  /* Update digest with ':' */
2992  }
2993  /* Update digest with H(A2) */
2994  MHD_bin_to_hex (hash2_bin, digest_size, tmp1);
2995  digest_update (da, (const uint8_t *) tmp1, digest_size * 2);
2996 
2997  /* H(A2) is not needed anymore, reuse the buffer.
2998  * Use hash2_bin for the calculated response in binary form */
2999  digest_calc_hash (da, hash2_bin);
3000 #ifdef MHD_DIGEST_HAS_EXT_ERROR
3001  if (digest_ext_error (da))
3002  return MHD_DAUTH_ERROR;
3003 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
3004 
3005  if (0 != memcmp (hash1_bin, hash2_bin, digest_size))
3006  return MHD_DAUTH_RESPONSE_WRONG;
3007 
3008  if (MHD_DAUTH_BIND_NONCE_NONE != daemon->dauth_bind_type)
3009  {
3010  mhd_assert (sizeof(tmp1) >= (NONCE_STD_LEN (digest_size) + 1));
3011  /* It was already checked that 'nonce' (including timestamp) was generated
3012  by MHD. */
3013  mhd_assert (! da->hashing);
3014  digest_reset (da);
3015  calculate_nonce (nonce_time,
3016  connection->rq.http_mthd,
3017  connection->rq.method,
3018  daemon->digest_auth_random,
3019  daemon->digest_auth_rand_size,
3020  connection->addr,
3021  (size_t) connection->addr_len,
3022  connection->rq.url,
3023  connection->rq.url_len,
3024  connection->rq.headers_received,
3025  realm,
3026  realm_len,
3027  daemon->dauth_bind_type,
3028  da,
3029  tmp1);
3030 
3031 #ifdef MHD_DIGEST_HAS_EXT_ERROR
3032  if (digest_ext_error (da))
3033  return MHD_DAUTH_ERROR;
3034 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
3035 
3036  if (! is_param_equal (&params->nonce, tmp1,
3037  NONCE_STD_LEN (digest_size)))
3039  /* The 'nonce' was generated in the same conditions */
3040  }
3041 
3042  return MHD_DAUTH_OK;
3043 }
3044 
3045 
3080 static enum MHD_DigestAuthResult
3081 digest_auth_check_all (struct MHD_Connection *connection,
3082  const char *realm,
3083  const char *username,
3084  const char *password,
3085  const uint8_t *userdigest,
3086  unsigned int nonce_timeout,
3087  uint32_t max_nc,
3088  enum MHD_DigestAuthMultiQOP mqop,
3089  enum MHD_DigestAuthMultiAlgo3 malgo3)
3090 {
3091  enum MHD_DigestAuthResult res;
3092  char *buf;
3093  struct DigestAlgorithm da;
3094 
3095  buf = NULL;
3096  digest_setup_zero (&da);
3097  if (0 == nonce_timeout)
3098  nonce_timeout = connection->daemon->dauth_def_nonce_timeout;
3099  if (0 == max_nc)
3100  max_nc = connection->daemon->dauth_def_max_nc;
3101  res = digest_auth_check_all_inner (connection, realm, username, password,
3102  userdigest,
3103  nonce_timeout,
3104  max_nc, mqop, malgo3,
3105  &buf, &da);
3106  digest_deinit (&da);
3107  if (NULL != buf)
3108  free (buf);
3109 
3110  return res;
3111 }
3112 
3113 
3132 _MHD_EXTERN int
3134  const char *realm,
3135  const char *username,
3136  const char *password,
3137  unsigned int nonce_timeout)
3138 {
3139  return MHD_digest_auth_check2 (connection,
3140  realm,
3141  username,
3142  password,
3143  nonce_timeout,
3145 }
3146 
3147 
3180 MHD_digest_auth_check3 (struct MHD_Connection *connection,
3181  const char *realm,
3182  const char *username,
3183  const char *password,
3184  unsigned int nonce_timeout,
3185  uint32_t max_nc,
3186  enum MHD_DigestAuthMultiQOP mqop,
3187  enum MHD_DigestAuthMultiAlgo3 malgo3)
3188 {
3189  mhd_assert (NULL != password);
3190 
3191  return digest_auth_check_all (connection,
3192  realm,
3193  username,
3194  password,
3195  NULL,
3196  nonce_timeout,
3197  max_nc,
3198  mqop,
3199  malgo3);
3200 }
3201 
3202 
3246 MHD_digest_auth_check_digest3 (struct MHD_Connection *connection,
3247  const char *realm,
3248  const char *username,
3249  const void *userdigest,
3250  size_t userdigest_size,
3251  unsigned int nonce_timeout,
3252  uint32_t max_nc,
3253  enum MHD_DigestAuthMultiQOP mqop,
3254  enum MHD_DigestAuthMultiAlgo3 malgo3)
3255 {
3256  if (1 != (((0 != (malgo3 & MHD_DIGEST_BASE_ALGO_MD5)) ? 1 : 0)
3257  + ((0 != (malgo3 & MHD_DIGEST_BASE_ALGO_SHA256)) ? 1 : 0)
3258  + ((0 != (malgo3 & MHD_DIGEST_BASE_ALGO_SHA512_256)) ? 1 : 0)))
3259  MHD_PANIC (_ ("Wrong 'malgo3' value, only one base hashing algorithm " \
3260  "(MD5, SHA-256 or SHA-512/256) must be specified, " \
3261  "API violation"));
3262 
3263 #ifndef MHD_MD5_SUPPORT
3264  if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_MD5))
3265  {
3266 #ifdef HAVE_MESSAGES
3267  MHD_DLOG (connection->daemon,
3268  _ ("The MD5 algorithm is not supported by this MHD build.\n"));
3269 #endif /* HAVE_MESSAGES */
3270  return MHD_DAUTH_WRONG_ALGO;
3271  }
3272 #endif /* ! MHD_MD5_SUPPORT */
3273 #ifndef MHD_SHA256_SUPPORT
3274  if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA256))
3275  {
3276 #ifdef HAVE_MESSAGES
3277  MHD_DLOG (connection->daemon,
3278  _ ("The SHA-256 algorithm is not supported by "
3279  "this MHD build.\n"));
3280 #endif /* HAVE_MESSAGES */
3281  return MHD_DAUTH_WRONG_ALGO;
3282  }
3283 #endif /* ! MHD_SHA256_SUPPORT */
3284 #ifndef MHD_SHA512_256_SUPPORT
3285  if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA512_256))
3286  {
3287 #ifdef HAVE_MESSAGES
3288  MHD_DLOG (connection->daemon,
3289  _ ("The SHA-512/256 algorithm is not supported by "
3290  "this MHD build.\n"));
3291 #endif /* HAVE_MESSAGES */
3292  return MHD_DAUTH_WRONG_ALGO;
3293  }
3294 #endif /* ! MHD_SHA512_256_SUPPORT */
3295 
3296  if (digest_get_hash_size ((enum MHD_DigestAuthAlgo3) malgo3) !=
3297  userdigest_size)
3298  MHD_PANIC (_ ("Wrong 'userdigest_size' value, does not match 'malgo3', "
3299  "API violation"));
3300 
3301  return digest_auth_check_all (connection,
3302  realm,
3303  username,
3304  NULL,
3305  (const uint8_t *) userdigest,
3306  nonce_timeout,
3307  max_nc,
3308  mqop,
3309  malgo3);
3310 }
3311 
3312 
3329 _MHD_EXTERN int
3331  const char *realm,
3332  const char *username,
3333  const char *password,
3334  unsigned int nonce_timeout,
3335  enum MHD_DigestAuthAlgorithm algo)
3336 {
3337  enum MHD_DigestAuthResult res;
3338  enum MHD_DigestAuthMultiAlgo3 malgo3;
3339 
3340  if (MHD_DIGEST_ALG_AUTO == algo)
3342  else if (MHD_DIGEST_ALG_MD5 == algo)
3344  else if (MHD_DIGEST_ALG_SHA256 == algo)
3346  else
3347  MHD_PANIC (_ ("Wrong 'algo' value, API violation"));
3348 
3349  res = MHD_digest_auth_check3 (connection,
3350  realm,
3351  username,
3352  password,
3353  nonce_timeout,
3355  malgo3);
3356  if (MHD_DAUTH_OK == res)
3357  return MHD_YES;
3358  else if ((MHD_DAUTH_NONCE_STALE == res) || (MHD_DAUTH_NONCE_WRONG == res) ||
3359  (MHD_DAUTH_NONCE_OTHER_COND == res) )
3360  return MHD_INVALID_NONCE;
3361  return MHD_NO;
3362 
3363 }
3364 
3365 
3385 _MHD_EXTERN int
3387  const char *realm,
3388  const char *username,
3389  const uint8_t *digest,
3390  size_t digest_size,
3391  unsigned int nonce_timeout,
3392  enum MHD_DigestAuthAlgorithm algo)
3393 {
3394  enum MHD_DigestAuthResult res;
3395  enum MHD_DigestAuthMultiAlgo3 malgo3;
3396 
3397  if (MHD_DIGEST_ALG_AUTO == algo)
3399  else if (MHD_DIGEST_ALG_MD5 == algo)
3401  else if (MHD_DIGEST_ALG_SHA256 == algo)
3403  else
3404  MHD_PANIC (_ ("Wrong 'algo' value, API violation"));
3405 
3406  res = MHD_digest_auth_check_digest3 (connection,
3407  realm,
3408  username,
3409  digest,
3410  digest_size,
3411  nonce_timeout,
3413  malgo3);
3414  if (MHD_DAUTH_OK == res)
3415  return MHD_YES;
3416  else if ((MHD_DAUTH_NONCE_STALE == res) || (MHD_DAUTH_NONCE_WRONG == res) ||
3417  (MHD_DAUTH_NONCE_OTHER_COND == res) )
3418  return MHD_INVALID_NONCE;
3419  return MHD_NO;
3420 }
3421 
3422 
3442 _MHD_EXTERN int
3444  const char *realm,
3445  const char *username,
3446  const uint8_t digest[MHD_MD5_DIGEST_SIZE],
3447  unsigned int nonce_timeout)
3448 {
3449  return MHD_digest_auth_check_digest2 (connection,
3450  realm,
3451  username,
3452  digest,
3454  nonce_timeout,
3456 }
3457 
3458 
3508 static enum MHD_Result
3510  const char *realm,
3511  const char *opaque,
3512  const char *domain,
3513  struct MHD_Response *response,
3514  int signal_stale,
3515  enum MHD_DigestAuthMultiQOP mqop,
3516  enum MHD_DigestAuthMultiAlgo3 malgo3,
3517  int userhash_support,
3518  int prefer_utf8,
3519  char **buf_ptr,
3520  struct DigestAlgorithm *da)
3521 {
3522  static const char prefix_realm[] = "realm=\"";
3523  static const char prefix_qop[] = "qop=\"";
3524  static const char prefix_algo[] = "algorithm=";
3525  static const char prefix_nonce[] = "nonce=\"";
3526  static const char prefix_opaque[] = "opaque=\"";
3527  static const char prefix_domain[] = "domain=\"";
3528  static const char str_charset[] = "charset=UTF-8";
3529  static const char str_userhash[] = "userhash=true";
3530  static const char str_stale[] = "stale=true";
3531  enum MHD_DigestAuthAlgo3 s_algo;
3532  size_t realm_len;
3533  size_t opaque_len;
3534  size_t domain_len;
3535  size_t buf_size;
3536  char *buf;
3537  size_t p; /* The position in the buffer */
3538  char *hdr_name;
3539 
3540  if (0 == (((unsigned int) malgo3) & MHD_DIGEST_AUTH_ALGO3_NON_SESSION))
3541  {
3542 #ifdef HAVE_MESSAGES
3543  MHD_DLOG (connection->daemon,
3544  _ ("Only non-'session' algorithms are supported.\n"));
3545 #endif /* HAVE_MESSAGES */
3546  return MHD_NO;
3547  }
3548  malgo3 =
3550  (malgo3
3552 #ifdef MHD_MD5_SUPPORT
3553  if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_MD5))
3554  s_algo = MHD_DIGEST_AUTH_ALGO3_MD5;
3555  else
3556 #endif /* MHD_MD5_SUPPORT */
3557 #ifdef MHD_SHA256_SUPPORT
3558  if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA256))
3560  else
3561 #endif /* MHD_SHA256_SUPPORT */
3562 #ifdef MHD_SHA512_256_SUPPORT
3563  if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA512_256))
3565  else
3566 #endif /* MHD_SHA512_256_SUPPORT */
3567  {
3568  if (0 == (((unsigned int) malgo3)
3571  MHD_PANIC (_ ("Wrong 'malgo3' value, API violation"));
3572  else
3573  {
3574 #ifdef HAVE_MESSAGES
3575  MHD_DLOG (connection->daemon,
3576  _ ("No requested algorithm is supported by this MHD build.\n"));
3577 #endif /* HAVE_MESSAGES */
3578  }
3579  return MHD_NO;
3580  }
3581 
3583  MHD_PANIC (_ ("Wrong 'mqop' value, API violation"));
3584 
3585  mqop = (enum MHD_DigestAuthMultiQOP)
3586  (mqop
3588 
3589  if (! digest_init_one_time (da, get_base_digest_algo (s_algo)))
3590  MHD_PANIC (_ ("Wrong 'algo' value, API violation"));
3591 
3592  if (MHD_DIGEST_AUTH_MULT_QOP_NONE == mqop)
3593  {
3594 #ifdef HAVE_MESSAGES
3595  if ((0 != userhash_support) || (0 != prefer_utf8))
3596  MHD_DLOG (connection->daemon,
3597  _ ("The 'userhash' and 'charset' ('prefer_utf8') parameters " \
3598  "are not compatible with RFC2069 and ignored.\n"));
3599  if (0 == (((unsigned int) s_algo) & MHD_DIGEST_BASE_ALGO_MD5))
3600  MHD_DLOG (connection->daemon,
3601  _ ("RFC2069 with SHA-256 or SHA-512/256 algorithm is " \
3602  "non-standard extension.\n"));
3603 #endif
3604  userhash_support = 0;
3605  prefer_utf8 = 0;
3606  }
3607 
3608  if (0 == MHD_get_master (connection->daemon)->nonce_nc_size)
3609  {
3610 #ifdef HAVE_MESSAGES
3611  MHD_DLOG (connection->daemon,
3612  _ ("The nonce array size is zero.\n"));
3613 #endif /* HAVE_MESSAGES */
3614  return MHD_NO;
3615  }
3616 
3617  /* Calculate required size */
3618  buf_size = 0;
3619  /* 'Digest ' */
3620  buf_size += MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE) + 1; /* 1 for ' ' */
3621  buf_size += MHD_STATICSTR_LEN_ (prefix_realm) + 3; /* 3 for '", ' */
3622  /* 'realm="xxxx", ' */
3623  realm_len = strlen (realm);
3624  if (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < realm_len)
3625  {
3626 #ifdef HAVE_MESSAGES
3627  MHD_DLOG (connection->daemon,
3628  _ ("The 'realm' is too large.\n"));
3629 #endif /* HAVE_MESSAGES */
3630  return MHD_NO;
3631  }
3632  if ((NULL != memchr (realm, '\r', realm_len)) ||
3633  (NULL != memchr (realm, '\n', realm_len)))
3634  return MHD_NO;
3635 
3636  buf_size += realm_len * 2; /* Quoting may double the size */
3637  /* 'qop="xxxx", ' */
3638  if (MHD_DIGEST_AUTH_MULT_QOP_NONE != mqop)
3639  {
3640  buf_size += MHD_STATICSTR_LEN_ (prefix_qop) + 3; /* 3 for '", ' */
3641  buf_size += MHD_STATICSTR_LEN_ (MHD_TOKEN_AUTH_);
3642  }
3643  /* 'algorithm="xxxx", ' */
3644  if (((MHD_DIGEST_AUTH_MULT_QOP_NONE) != mqop) ||
3645  (0 == (((unsigned int) s_algo) & MHD_DIGEST_BASE_ALGO_MD5)))
3646  {
3647  buf_size += MHD_STATICSTR_LEN_ (prefix_algo) + 2; /* 2 for ', ' */
3648 #ifdef MHD_MD5_SUPPORT
3649  if (MHD_DIGEST_AUTH_ALGO3_MD5 == s_algo)
3650  buf_size += MHD_STATICSTR_LEN_ (_MHD_MD5_TOKEN);
3651  else
3652 #endif /* MHD_MD5_SUPPORT */
3653 #ifdef MHD_SHA256_SUPPORT
3654  if (MHD_DIGEST_AUTH_ALGO3_SHA256 == s_algo)
3655  buf_size += MHD_STATICSTR_LEN_ (_MHD_SHA256_TOKEN);
3656  else
3657 #endif /* MHD_SHA256_SUPPORT */
3658 #ifdef MHD_SHA512_256_SUPPORT
3659  if (MHD_DIGEST_AUTH_ALGO3_SHA512_256 == s_algo)
3661  else
3662 #endif /* MHD_SHA512_256_SUPPORT */
3663  mhd_assert (0);
3664  }
3665  /* 'nonce="xxxx", ' */
3666  buf_size += MHD_STATICSTR_LEN_ (prefix_nonce) + 3; /* 3 for '", ' */
3667  buf_size += NONCE_STD_LEN (digest_get_size (da)); /* Escaping not needed */
3668  /* 'opaque="xxxx", ' */
3669  if (NULL != opaque)
3670  {
3671  buf_size += MHD_STATICSTR_LEN_ (prefix_opaque) + 3; /* 3 for '", ' */
3672  opaque_len = strlen (opaque);
3673  if ((NULL != memchr (opaque, '\r', opaque_len)) ||
3674  (NULL != memchr (opaque, '\n', opaque_len)))
3675  return MHD_NO;
3676 
3677  buf_size += opaque_len * 2; /* Quoting may double the size */
3678  }
3679  else
3680  opaque_len = 0;
3681  /* 'domain="xxxx", ' */
3682  if (NULL != domain)
3683  {
3684  buf_size += MHD_STATICSTR_LEN_ (prefix_domain) + 3; /* 3 for '", ' */
3685  domain_len = strlen (domain);
3686  if ((NULL != memchr (domain, '\r', domain_len)) ||
3687  (NULL != memchr (domain, '\n', domain_len)))
3688  return MHD_NO;
3689 
3690  buf_size += domain_len * 2; /* Quoting may double the size */
3691  }
3692  else
3693  domain_len = 0;
3694  /* 'charset=UTF-8' */
3695  if (MHD_NO != prefer_utf8)
3696  buf_size += MHD_STATICSTR_LEN_ (str_charset) + 2; /* 2 for ', ' */
3697  /* 'userhash=true' */
3698  if (MHD_NO != userhash_support)
3699  buf_size += MHD_STATICSTR_LEN_ (str_userhash) + 2; /* 2 for ', ' */
3700  /* 'stale=true' */
3701  if (MHD_NO != signal_stale)
3702  buf_size += MHD_STATICSTR_LEN_ (str_stale) + 2; /* 2 for ', ' */
3703 
3704  /* The calculated length is for string ended with ", ". One character will
3705  * be used for zero-termination, the last one will not be used. */
3706 
3707  /* Allocate the buffer */
3708  buf = malloc (buf_size);
3709  if (NULL == buf)
3710  return MHD_NO;
3711  *buf_ptr = buf;
3712 
3713  /* Build the challenge string */
3714  p = 0;
3715  /* 'Digest: ' */
3716  memcpy (buf + p, _MHD_AUTH_DIGEST_BASE,
3719  buf[p++] = ' ';
3720  /* 'realm="xxxx", ' */
3721  memcpy (buf + p, prefix_realm,
3722  MHD_STATICSTR_LEN_ (prefix_realm));
3723  p += MHD_STATICSTR_LEN_ (prefix_realm);
3724  mhd_assert ((buf_size - p) >= (realm_len * 2));
3725  if (1)
3726  {
3727  size_t quoted_size;
3728  quoted_size = MHD_str_quote (realm, realm_len, buf + p, buf_size - p);
3729  if (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < quoted_size)
3730  {
3731 #ifdef HAVE_MESSAGES
3732  MHD_DLOG (connection->daemon,
3733  _ ("The 'realm' is too large after 'quoting'.\n"));
3734 #endif /* HAVE_MESSAGES */
3735  return MHD_NO;
3736  }
3737  p += quoted_size;
3738  }
3739  buf[p++] = '\"';
3740  buf[p++] = ',';
3741  buf[p++] = ' ';
3742  /* 'qop="xxxx", ' */
3743  if (MHD_DIGEST_AUTH_MULT_QOP_NONE != mqop)
3744  {
3745  memcpy (buf + p, prefix_qop,
3746  MHD_STATICSTR_LEN_ (prefix_qop));
3747  p += MHD_STATICSTR_LEN_ (prefix_qop);
3748  memcpy (buf + p, MHD_TOKEN_AUTH_,
3751  buf[p++] = '\"';
3752  buf[p++] = ',';
3753  buf[p++] = ' ';
3754  }
3755  /* 'algorithm="xxxx", ' */
3756  if (((MHD_DIGEST_AUTH_MULT_QOP_NONE) != mqop) ||
3757  (0 == (((unsigned int) s_algo) & MHD_DIGEST_BASE_ALGO_MD5)))
3758  {
3759  memcpy (buf + p, prefix_algo,
3760  MHD_STATICSTR_LEN_ (prefix_algo));
3761  p += MHD_STATICSTR_LEN_ (prefix_algo);
3762 #ifdef MHD_MD5_SUPPORT
3763  if (MHD_DIGEST_AUTH_ALGO3_MD5 == s_algo)
3764  {
3765  memcpy (buf + p, _MHD_MD5_TOKEN,
3768  }
3769  else
3770 #endif /* MHD_MD5_SUPPORT */
3771 #ifdef MHD_SHA256_SUPPORT
3772  if (MHD_DIGEST_AUTH_ALGO3_SHA256 == s_algo)
3773  {
3774  memcpy (buf + p, _MHD_SHA256_TOKEN,
3777  }
3778  else
3779 #endif /* MHD_SHA256_SUPPORT */
3780 #ifdef MHD_SHA512_256_SUPPORT
3781  if (MHD_DIGEST_AUTH_ALGO3_SHA512_256 == s_algo)
3782  {
3783  memcpy (buf + p, _MHD_SHA512_256_TOKEN,
3786  }
3787  else
3788 #endif /* MHD_SHA512_256_SUPPORT */
3789  mhd_assert (0);
3790  buf[p++] = ',';
3791  buf[p++] = ' ';
3792  }
3793  /* 'nonce="xxxx", ' */
3794  memcpy (buf + p, prefix_nonce,
3795  MHD_STATICSTR_LEN_ (prefix_nonce));
3796  p += MHD_STATICSTR_LEN_ (prefix_nonce);
3797  mhd_assert ((buf_size - p) >= (NONCE_STD_LEN (digest_get_size (da))));
3798  if (! calculate_add_nonce_with_retry (connection, realm, da, buf + p))
3799  {
3800 #ifdef MHD_DIGEST_HAS_EXT_ERROR
3801  if (digest_ext_error (da))
3802  {
3803 #ifdef HAVE_MESSAGES
3804  MHD_DLOG (connection->daemon,
3805  _ ("TLS library reported hash calculation error, nonce could "
3806  "not be generated.\n"));
3807 #endif /* HAVE_MESSAGES */
3808  return MHD_NO;
3809  }
3810 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
3811 #ifdef HAVE_MESSAGES
3812  MHD_DLOG (connection->daemon,
3813  _ ("Could not register nonce. Client's requests with this "
3814  "nonce will be always 'stale'. Probably clients' requests "
3815  "are too intensive.\n"));
3816 #endif /* HAVE_MESSAGES */
3817  (void) 0; /* Mute compiler warning for builds without messages */
3818  }
3819  p += NONCE_STD_LEN (digest_get_size (da));
3820  buf[p++] = '\"';
3821  buf[p++] = ',';
3822  buf[p++] = ' ';
3823  /* 'opaque="xxxx", ' */
3824  if (NULL != opaque)
3825  {
3826  memcpy (buf + p, prefix_opaque,
3827  MHD_STATICSTR_LEN_ (prefix_opaque));
3828  p += MHD_STATICSTR_LEN_ (prefix_opaque);
3829  mhd_assert ((buf_size - p) >= (opaque_len * 2));
3830  p += MHD_str_quote (opaque, opaque_len, buf + p, buf_size - p);
3831  buf[p++] = '\"';
3832  buf[p++] = ',';
3833  buf[p++] = ' ';
3834  }
3835  /* 'domain="xxxx", ' */
3836  if (NULL != domain)
3837  {
3838  memcpy (buf + p, prefix_domain,
3839  MHD_STATICSTR_LEN_ (prefix_domain));
3840  p += MHD_STATICSTR_LEN_ (prefix_domain);
3841  mhd_assert ((buf_size - p) >= (domain_len * 2));
3842  p += MHD_str_quote (domain, domain_len, buf + p, buf_size - p);
3843  buf[p++] = '\"';
3844  buf[p++] = ',';
3845  buf[p++] = ' ';
3846  }
3847  /* 'charset=UTF-8' */
3848  if (MHD_NO != prefer_utf8)
3849  {
3850  memcpy (buf + p, str_charset,
3851  MHD_STATICSTR_LEN_ (str_charset));
3852  p += MHD_STATICSTR_LEN_ (str_charset);
3853  buf[p++] = ',';
3854  buf[p++] = ' ';
3855  }
3856  /* 'userhash=true' */
3857  if (MHD_NO != userhash_support)
3858  {
3859  memcpy (buf + p, str_userhash,
3860  MHD_STATICSTR_LEN_ (str_userhash));
3861  p += MHD_STATICSTR_LEN_ (str_userhash);
3862  buf[p++] = ',';
3863  buf[p++] = ' ';
3864  }
3865  /* 'stale=true' */
3866  if (MHD_NO != signal_stale)
3867  {
3868  memcpy (buf + p, str_stale,
3869  MHD_STATICSTR_LEN_ (str_stale));
3870  p += MHD_STATICSTR_LEN_ (str_stale);
3871  buf[p++] = ',';
3872  buf[p++] = ' ';
3873  }
3874  mhd_assert (buf_size >= p);
3875  /* The built string ends with ", ". Replace comma with zero-termination. */
3876  --p;
3877  buf[--p] = 0;
3878 
3879  hdr_name = malloc (MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_WWW_AUTHENTICATE) + 1);
3880  if (NULL != hdr_name)
3881  {
3882  memcpy (hdr_name, MHD_HTTP_HEADER_WWW_AUTHENTICATE,
3885  hdr_name,
3886  MHD_STATICSTR_LEN_ ( \
3888  buf, p))
3889  {
3890  *buf_ptr = NULL; /* The buffer will be free()ed when the response is destroyed */
3891  return MHD_queue_response (connection, MHD_HTTP_UNAUTHORIZED, response);
3892  }
3893 #ifdef HAVE_MESSAGES
3894  else
3895  {
3896  MHD_DLOG (connection->daemon,
3897  _ ("Failed to add Digest auth header.\n"));
3898  }
3899 #endif /* HAVE_MESSAGES */
3900  free (hdr_name);
3901  }
3902  return MHD_NO;
3903 }
3904 
3905 
3970  const char *realm,
3971  const char *opaque,
3972  const char *domain,
3973  struct MHD_Response *response,
3974  int signal_stale,
3975  enum MHD_DigestAuthMultiQOP mqop,
3976  enum MHD_DigestAuthMultiAlgo3 malgo3,
3977  int userhash_support,
3978  int prefer_utf8)
3979 {
3980  struct DigestAlgorithm da;
3981  char *buf_ptr;
3982  enum MHD_Result ret;
3983 
3984  buf_ptr = NULL;
3985  digest_setup_zero (&da);
3986  ret = queue_auth_required_response3_inner (connection,
3987  realm,
3988  opaque,
3989  domain,
3990  response,
3991  signal_stale,
3992  mqop,
3993  malgo3,
3994  userhash_support,
3995  prefer_utf8,
3996  &buf_ptr,
3997  &da);
3998  digest_deinit (&da);
3999  if (NULL != buf_ptr)
4000  free (buf_ptr);
4001  return ret;
4002 }
4003 
4004 
4022 MHD_queue_auth_fail_response2 (struct MHD_Connection *connection,
4023  const char *realm,
4024  const char *opaque,
4025  struct MHD_Response *response,
4026  int signal_stale,
4027  enum MHD_DigestAuthAlgorithm algo)
4028 {
4029  enum MHD_DigestAuthMultiAlgo3 algo3;
4030 
4031  if (MHD_DIGEST_ALG_MD5 == algo)
4033  else if (MHD_DIGEST_ALG_SHA256 == algo)
4035  else if (MHD_DIGEST_ALG_AUTO == algo)
4037  else
4038  MHD_PANIC (_ ("Wrong algo value.\n")); /* API violation! */
4039 
4040  return MHD_queue_auth_required_response3 (connection, realm, opaque,
4041  NULL, response, signal_stale,
4043  algo3,
4044  0, 0);
4045 }
4046 
4047 
4066 MHD_queue_auth_fail_response (struct MHD_Connection *connection,
4067  const char *realm,
4068  const char *opaque,
4069  struct MHD_Response *response,
4070  int signal_stale)
4071 {
4072  return MHD_queue_auth_fail_response2 (connection,
4073  realm,
4074  opaque,
4075  response,
4076  signal_stale,
4078 }
4079 
4080 
4081 /* end of digestauth.c */
_MHD_static_inline enum MHD_DigestBaseAlgo get_base_digest_algo(enum MHD_DigestAuthAlgo3 algo3)
Definition: digestauth.c:210
#define digest_deinit(da)
Definition: digestauth.c:430
_MHD_static_inline void calc_userhash(struct DigestAlgorithm *da, const char *username, const size_t username_len, const char *realm, const size_t realm_len, uint8_t *digest_bin)
Definition: digestauth.c:1987
MHD_CheckNonceNC_
Definition: digestauth.c:184
@ MHD_CHECK_NONCENC_OK
Definition: digestauth.c:188
@ MHD_CHECK_NONCENC_STALE
Definition: digestauth.c:195
@ MHD_CHECK_NONCENC_WRONG
Definition: digestauth.c:200
#define TRIM_TO_TIMESTAMP(value)
Definition: digestauth.c:77
static enum MHD_Result test_header(void *cls, const char *key, size_t key_size, const char *value, size_t value_size, enum MHD_ValueKind kind)
Definition: digestauth.c:2158
static bool check_uri_match(struct MHD_Connection *connection, char *uri, size_t uri_len)
Definition: digestauth.c:2266
#define TIMESTAMP_CHARS_LEN
Definition: digestauth.c:84
static enum MHD_GetRqNCResult get_rq_nc(const struct MHD_RqDAuth *params, uint32_t *nc)
Definition: digestauth.c:1204
static MHD_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE_ bool calculate_add_nonce_with_retry(struct MHD_Connection *const connection, const char *realm, struct DigestAlgorithm *da, char *nonce)
Definition: digestauth.c:1777
static MHD_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE_ size_t get_nonce_nc_idx(size_t arr_size, const char *nonce, size_t noncelen)
Definition: digestauth.c:807
_MHD_static_inline void digest_update_with_colon(struct DigestAlgorithm *da)
Definition: digestauth.c:562
#define NONCE_STD_LEN(digest_size)
Definition: digestauth.c:92
static char * get_buffer_for_size(char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE], char **ptmp2, size_t *ptmp2_size, size_t required_size)
Definition: digestauth.c:2324
_MHD_static_inline void digest_reset(struct DigestAlgorithm *da)
Definition: digestauth.c:638
#define TIMESTAMP_BIN_SIZE
Definition: digestauth.c:71
MHD_GetRqNCResult
Definition: digestauth.c:1188
@ MHD_GET_RQ_NC_NONE
Definition: digestauth.c:1189
@ MHD_GET_RQ_NC_BROKEN
Definition: digestauth.c:1193
@ MHD_GET_RQ_NC_VALID
Definition: digestauth.c:1190
@ MHD_GET_RQ_NC_TOO_LONG
Definition: digestauth.c:1191
@ MHD_GET_RQ_NC_TOO_LARGE
Definition: digestauth.c:1192
static size_t get_rq_param_unquoted_copy_z(const struct MHD_RqDAuthParam *param, char *buf)
Definition: digestauth.c:1022
static ssize_t get_rq_extended_uname_copy_z(const char *uname_ext, size_t uname_ext_len, char *buf, size_t buf_size)
Definition: digestauth.c:1052
_MHD_GetUnqResult
Definition: digestauth.c:2357
@ _MHD_UNQ_TOO_LARGE
Definition: digestauth.c:2359
@ _MHD_UNQ_OUT_OF_MEM
Definition: digestauth.c:2360
@ _MHD_UNQ_OK
Definition: digestauth.c:2358
#define digest_ext_error(da)
Definition: digestauth.c:728
_MHD_static_inline bool is_param_equal(const struct MHD_RqDAuthParam *param, const char *const str, const size_t str_len)
Definition: digestauth.c:2458
static void calculate_nonce(uint64_t nonce_time, enum MHD_HTTP_Method mthd_e, const char *method, const char *rnd, size_t rnd_size, const struct sockaddr_storage *saddr, size_t saddr_size, const char *uri, size_t uri_len, const struct MHD_HTTP_Req_Header *first_header, const char *realm, size_t realm_len, unsigned int bind_options, struct DigestAlgorithm *da, char *nonce)
Definition: digestauth.c:1485
static size_t get_rq_uname(const struct MHD_RqDAuth *params, enum MHD_DigestAuthUsernameType uname_type, struct MHD_DigestAuthUsernameInfo *uname_info, uint8_t *buf, size_t buf_size)
Definition: digestauth.c:1102
static enum _MHD_GetUnqResult get_unquoted_param_copy(const struct MHD_RqDAuthParam *param, char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE], char **ptmp2, size_t *ptmp2_size, struct _MHD_mstr_w_len *unquoted)
Definition: digestauth.c:2416
static bool calculate_add_nonce(struct MHD_Connection *const connection, uint64_t timestamp, const char *realm, size_t realm_len, struct DigestAlgorithm *da, char *nonce)
Definition: digestauth.c:1697
_MHD_static_inline size_t digest_get_hash_size(enum MHD_DigestAuthAlgo3 algo3)
Definition: digestauth.c:232
#define MHD_DAUTH_EXT_PARAM_PREFIX
Definition: digestauth.c:172
static enum _MHD_GetUnqResult get_unquoted_param(const struct MHD_RqDAuthParam *param, char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE], char **ptmp2, size_t *ptmp2_size, struct _MHD_str_w_len *unquoted)
Definition: digestauth.c:2373
static enum MHD_CheckNonceNC_ check_nonce_nc(struct MHD_Connection *connection, const char *nonce, size_t noncelen, uint64_t nonce_time, uint64_t nc)
Definition: digestauth.c:832
_MHD_static_inline size_t get_rq_unames_size(const struct MHD_RqDAuth *params, enum MHD_DigestAuthUsernameType uname_type)
Definition: digestauth.c:992
#define REUSE_TIMEOUT
Definition: digestauth.c:59
#define DAUTH_JUMPBACK_MAX
Definition: digestauth.c:65
_MHD_static_inline enum MHD_DigestAuthUsernameType get_rq_uname_type(const struct MHD_RqDAuth *params)
Definition: digestauth.c:960
#define _MHD_STATIC_UNQ_BUFFER_SIZE
Definition: digestauth.c:2311
MHD_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE_ _MHD_static_inline void calc_userdigest(struct DigestAlgorithm *da, const char *username, const size_t username_len, const char *realm, const size_t realm_len, const char *password, uint8_t *ha1_bin)
Definition: digestauth.c:1887
_MHD_static_inline void digest_update(struct DigestAlgorithm *da, const void *data, size_t length)
Definition: digestauth.c:512
_MHD_static_inline bool is_param_equal_caseless(const struct MHD_RqDAuthParam *param, const char *const str, const size_t str_len)
Definition: digestauth.c:2482
static bool get_nonce_timestamp(const char *const nonce, size_t noncelen, uint64_t *const ptimestamp)
Definition: digestauth.c:741
_MHD_static_inline void digest_calc_hash(struct DigestAlgorithm *da, uint8_t *digest)
Definition: digestauth.c:576
_MHD_static_inline void digest_update_str(struct DigestAlgorithm *da, const char *str)
Definition: digestauth.c:548
static MHD_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE_ uint32_t fast_simple_hash(const uint8_t *data, size_t data_size)
Definition: digestauth.c:777
_MHD_static_inline bool digest_init_one_time(struct DigestAlgorithm *da, enum MHD_DigestBaseAlgo algo)
Definition: digestauth.c:448
_MHD_static_inline unsigned int digest_get_size(struct DigestAlgorithm *da)
Definition: digestauth.c:351
static bool check_argument_match(struct MHD_Connection *connection, char *args)
Definition: digestauth.c:2219
#define digest_setup_zero(da)
Definition: digestauth.c:429
#define MHD_DAUTH_EXT_PARAM_MIN_LEN
Definition: digestauth.c:177
static bool is_slot_available(const struct MHD_NonceNc *const nn, const uint64_t now, const char *const new_nonce, size_t new_nonce_len)
Definition: digestauth.c:1641
#define _MHD_SHA256_TOKEN
Definition: digestauth.h:60
#define _MHD_MD5_TOKEN
Definition: digestauth.h:55
#define _MHD_SHA512_256_TOKEN
Definition: digestauth.h:65
#define MHD_TOKEN_AUTH_
Definition: digestauth.h:75
#define _MHD_AUTH_DIGEST_BASE
Definition: digestauth.h:50
#define _MHD_AUTH_DIGEST_MAX_PARAM_SIZE
Definition: digestauth.h:45
Declarations for HTTP authorisation general functions.
_MHD_EXTERN enum MHD_Result MHD_digest_auth_calc_userdigest(enum MHD_DigestAuthAlgo3 algo3, const char *username, const char *realm, const char *password, void *userdigest_bin, size_t bin_buf_size)
Definition: digestauth.c:1937
static enum MHD_DigestAuthResult digest_auth_check_all_inner(struct MHD_Connection *connection, const char *realm, const char *username, const char *password, const uint8_t *userdigest, unsigned int nonce_timeout, uint32_t max_nc, enum MHD_DigestAuthMultiQOP mqop, enum MHD_DigestAuthMultiAlgo3 malgo3, char **pbuf, struct DigestAlgorithm *da)
Definition: digestauth.c:2534
#define MHD_SHA512_256_DIGEST_SIZE
Definition: microhttpd.h:4700
static enum MHD_DigestAuthResult digest_auth_check_all(struct MHD_Connection *connection, const char *realm, const char *username, const char *password, const uint8_t *userdigest, unsigned int nonce_timeout, uint32_t max_nc, enum MHD_DigestAuthMultiQOP mqop, enum MHD_DigestAuthMultiAlgo3 malgo3)
Definition: digestauth.c:3081
_MHD_EXTERN enum MHD_Result MHD_queue_auth_fail_response(struct MHD_Connection *connection, const char *realm, const char *opaque, struct MHD_Response *response, int signal_stale)
Definition: digestauth.c:4066
_MHD_EXTERN int MHD_digest_auth_check2(struct MHD_Connection *connection, const char *realm, const char *username, const char *password, unsigned int nonce_timeout, enum MHD_DigestAuthAlgorithm algo)
Definition: digestauth.c:3330
_MHD_EXTERN enum MHD_Result MHD_queue_auth_required_response3(struct MHD_Connection *connection, const char *realm, const char *opaque, const char *domain, struct MHD_Response *response, int signal_stale, enum MHD_DigestAuthMultiQOP mqop, enum MHD_DigestAuthMultiAlgo3 algo, int userhash_support, int prefer_utf8)
Definition: digestauth.c:3969
_MHD_EXTERN int MHD_digest_auth_check_digest2(struct MHD_Connection *connection, const char *realm, const char *username, const uint8_t *digest, size_t digest_size, unsigned int nonce_timeout, enum MHD_DigestAuthAlgorithm algo)
Definition: digestauth.c:3386
_MHD_EXTERN enum MHD_Result MHD_digest_auth_calc_userhash_hex(enum MHD_DigestAuthAlgo3 algo3, const char *username, const char *realm, char *userhash_hex, size_t hex_buf_size)
Definition: digestauth.c:2117
_MHD_EXTERN enum MHD_DigestAuthResult MHD_digest_auth_check_digest3(struct MHD_Connection *connection, const char *realm, const char *username, const void *userdigest, size_t userdigest_size, unsigned int nonce_timeout, uint32_t max_nc, enum MHD_DigestAuthMultiQOP mqop, enum MHD_DigestAuthMultiAlgo3 malgo3)
Definition: digestauth.c:3246
_MHD_EXTERN enum MHD_Result MHD_queue_auth_fail_response2(struct MHD_Connection *connection, const char *realm, const char *opaque, struct MHD_Response *response, int signal_stale, enum MHD_DigestAuthAlgorithm algo)
Definition: digestauth.c:4022
_MHD_EXTERN struct MHD_DigestAuthInfo * MHD_digest_auth_get_request_info3(struct MHD_Connection *connection)
Definition: digestauth.c:1268
_MHD_EXTERN size_t MHD_digest_get_hash_size(enum MHD_DigestAuthAlgo3 algo3)
Definition: digestauth.c:295
_MHD_EXTERN int MHD_digest_auth_check_digest(struct MHD_Connection *connection, const char *realm, const char *username, const uint8_t digest[MHD_MD5_DIGEST_SIZE], unsigned int nonce_timeout)
Definition: digestauth.c:3443
_MHD_EXTERN char * MHD_digest_auth_get_username(struct MHD_Connection *connection)
Definition: digestauth.c:1414
_MHD_EXTERN int MHD_digest_auth_check(struct MHD_Connection *connection, const char *realm, const char *username, const char *password, unsigned int nonce_timeout)
Definition: digestauth.c:3133
#define MHD_INVALID_NONCE
Definition: microhttpd.h:5751
static enum MHD_Result queue_auth_required_response3_inner(struct MHD_Connection *connection, const char *realm, const char *opaque, const char *domain, struct MHD_Response *response, int signal_stale, enum MHD_DigestAuthMultiQOP mqop, enum MHD_DigestAuthMultiAlgo3 malgo3, int userhash_support, int prefer_utf8, char **buf_ptr, struct DigestAlgorithm *da)
Definition: digestauth.c:3509
#define MHD_SHA256_DIGEST_SIZE
Definition: microhttpd.h:4690
_MHD_EXTERN enum MHD_DigestAuthResult MHD_digest_auth_check3(struct MHD_Connection *connection, const char *realm, const char *username, const char *password, unsigned int nonce_timeout, uint32_t max_nc, enum MHD_DigestAuthMultiQOP mqop, enum MHD_DigestAuthMultiAlgo3 malgo3)
Definition: digestauth.c:3180
_MHD_EXTERN enum MHD_Result MHD_digest_auth_calc_userhash(enum MHD_DigestAuthAlgo3 algo3, const char *username, const char *realm, void *userhash_bin, size_t bin_buf_size)
Definition: digestauth.c:2042
_MHD_EXTERN struct MHD_DigestAuthUsernameInfo * MHD_digest_auth_get_username3(struct MHD_Connection *connection)
Definition: digestauth.c:1356
#define MHD_MD5_DIGEST_SIZE
Definition: microhttpd.h:4683
#define MHD_HTTP_HEADER_WWW_AUTHENTICATE
Definition: microhttpd.h:658
#define MHD_HTTP_UNAUTHORIZED
Definition: microhttpd.h:387
_MHD_EXTERN enum MHD_Result MHD_queue_response(struct MHD_Connection *connection, unsigned int status_code, struct MHD_Response *response)
Definition: connection.c:7850
bool MHD_parse_arguments_(struct MHD_Request *request, enum MHD_ValueKind kind, char *args, MHD_ArgumentIterator_ cb, unsigned int *num_headers)
Definition: internal.c:190
#define MHD_PANIC(msg)
Definition: internal.h:69
#define mhd_assert(CHK)
Definition: mhd_assert.h:39
void * MHD_calloc_(size_t nelem, size_t elsize)
Definition: mhd_compat.c:98
#define UINT64_MAX
Definition: mhd_limits.h:81
#define UINT32_MAX
Definition: mhd_limits.h:73
#define MHD_mutex_unlock_chk_(pmutex)
Definition: mhd_locks.h:180
#define MHD_mutex_lock_chk_(pmutex)
Definition: mhd_locks.h:154
size_t MHD_strx_to_uint64_n_(const char *str, size_t maxlen, uint64_t *out_val)
Definition: mhd_str.c:692
#define MHD_STATICSTR_LEN_(macro)
Definition: mhd_str.h:45
#define NULL
Definition: reason_phrase.c:30
void MHD_MD5_finish(struct Md5Ctx *ctx, uint8_t digest[MD5_DIGEST_SIZE])
Definition: md5.c:461
void MHD_MD5_update(struct Md5Ctx *ctx, const uint8_t *data, size_t length)
Definition: md5.c:393
#define MD5_DIGEST_SIZE
Definition: md5.h:61
macros for bits manipulations
_MHD_static_inline uint32_t _MHD_ROTR32(uint32_t value32, int bits)
_MHD_static_inline uint32_t _MHD_ROTL32(uint32_t value32, int bits)
Simple wrapper for selection of built-in/external MD5 implementation.
#define MHD_MD5_finish_reset(ctx, digest)
Definition: mhd_md5_wrap.h:81
#define MHD_MD5_deinit(ignore)
Definition: mhd_md5_wrap.h:89
#define Md5CtxWr
Definition: mhd_md5_wrap.h:58
#define MHD_MD5_reset(ctx)
Definition: mhd_md5_wrap.h:77
#define MHD_MD5_init_one_time(ctx)
Definition: mhd_md5_wrap.h:70
#define _(String)
Definition: mhd_options.h:42
#define MHD_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE_
Definition: mhd_options.h:176
#define _MHD_EXTERN
Definition: mhd_options.h:53
#define MHD_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE_
Definition: mhd_options.h:177
Simple wrapper for selection of built-in/external SHA-256 implementation.
#define Sha256CtxWr
#define MHD_SHA256_deinit(ignore)
#define MHD_SHA256_init_one_time(ctx)
#define MHD_SHA256_reset(ctx)
#define MHD_SHA256_finish_reset(ctx, digest)
MHD internal shared structures.
_MHD_static_inline struct MHD_Daemon * MHD_get_master(struct MHD_Daemon *const daemon)
Definition: internal.h:2900
#define MAX_DIGEST_NONCE_LENGTH
Definition: internal.h:269
MHD_HTTP_Method
Definition: internal.h:899
@ MHD_HTTP_MTHD_GET
Definition: internal.h:907
@ MHD_HTTP_MTHD_HEAD
Definition: internal.h:911
@ MHD_HTTP_MTHD_OTHER
Definition: internal.h:939
macros for mhd_assert()
Header for platform missing functions.
limits values definitions
#define SSIZE_MAX
Definition: mhd_limits.h:121
Header for platform-independent locks abstraction.
uint64_t MHD_monotonic_msec_counter(void)
internal monotonic clock functions implementations
size_t MHD_bin_to_hex(const void *bin, size_t size, char *hex)
Definition: mhd_str.c:1676
size_t MHD_str_pct_decode_strict_n_(const char *pct_encoded, size_t pct_encoded_len, char *decoded, size_t buf_size)
Definition: mhd_str.c:1746
size_t MHD_bin_to_hex_z(const void *bin, size_t size, char *hex)
Definition: mhd_str.c:1696
bool MHD_str_equal_caseless_bin_n_(const char *const str1, const char *const str2, size_t len)
Definition: mhd_str.c:749
size_t MHD_hex_to_bin(const char *hex, size_t len, void *bin)
Definition: mhd_str.c:1710
Header for string manipulating helpers.
bool MHD_add_response_entry_no_alloc_(struct MHD_Response *response, enum MHD_ValueKind kind, char *header, size_t header_len, char *content, size_t content_len)
Definition: response.c:167
MHD_DigestAuthResult
Definition: microhttpd.h:5446
@ MHD_DAUTH_NONCE_WRONG
Definition: microhttpd.h:5521
@ MHD_DAUTH_RESPONSE_WRONG
Definition: microhttpd.h:5527
@ MHD_DAUTH_WRONG_HEADER
Definition: microhttpd.h:5462
@ MHD_DAUTH_NONCE_STALE
Definition: microhttpd.h:5502
@ MHD_DAUTH_ERROR
Definition: microhttpd.h:5455
@ MHD_DAUTH_WRONG_QOP
Definition: microhttpd.h:5482
@ MHD_DAUTH_OK
Definition: microhttpd.h:5450
@ MHD_DAUTH_NONCE_OTHER_COND
Definition: microhttpd.h:5516
@ MHD_DAUTH_WRONG_REALM
Definition: microhttpd.h:5472
@ MHD_DAUTH_WRONG_URI
Definition: microhttpd.h:5477
@ MHD_DAUTH_WRONG_ALGO
Definition: microhttpd.h:5487
@ MHD_DAUTH_TOO_LARGE
Definition: microhttpd.h:5492
@ MHD_DAUTH_WRONG_USERNAME
Definition: microhttpd.h:5467
MHD_Result
Definition: microhttpd.h:158
@ MHD_YES
Definition: microhttpd.h:167
@ MHD_NO
Definition: microhttpd.h:162
#define MHD_DIGEST_AUTH_ALGO3_SESSION
Definition: microhttpd.h:4747
#define MHD_DIGEST_AUTH_ALGO3_NON_SESSION
Definition: microhttpd.h:4740
MHD_DigestAuthMultiQOP
Definition: microhttpd.h:5138
@ MHD_DIGEST_AUTH_MULT_QOP_AUTH_INT
Definition: microhttpd.h:5164
@ MHD_DIGEST_AUTH_MULT_QOP_AUTH
Definition: microhttpd.h:5157
@ MHD_DIGEST_AUTH_MULT_QOP_NONE
Definition: microhttpd.h:5152
MHD_DigestBaseAlgo
Definition: microhttpd.h:4710
@ MHD_DIGEST_BASE_ALGO_INVALID
Definition: microhttpd.h:4714
@ MHD_DIGEST_BASE_ALGO_SHA256
Definition: microhttpd.h:4726
@ MHD_DIGEST_BASE_ALGO_SHA512_256
Definition: microhttpd.h:4732
@ MHD_DIGEST_BASE_ALGO_MD5
Definition: microhttpd.h:4720
MHD_DigestAuthAlgo3
Definition: microhttpd.h:4756
@ MHD_DIGEST_AUTH_ALGO3_MD5
Definition: microhttpd.h:4767
@ MHD_DIGEST_AUTH_ALGO3_SHA256
Definition: microhttpd.h:4780
@ MHD_DIGEST_AUTH_ALGO3_SHA512_256
Definition: microhttpd.h:4793
MHD_DigestAuthQOP
Definition: microhttpd.h:5099
@ MHD_DIGEST_AUTH_QOP_NONE
Definition: microhttpd.h:5115
@ MHD_DIGEST_AUTH_QOP_AUTH_INT
Definition: microhttpd.h:5126
void * data
Definition: microhttpd.h:3968
MHD_DigestAuthUsernameType
Definition: microhttpd.h:5056
@ MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD
Definition: microhttpd.h:5066
@ MHD_DIGEST_AUTH_UNAME_TYPE_MISSING
Definition: microhttpd.h:5061
@ MHD_DIGEST_AUTH_UNAME_TYPE_INVALID
Definition: microhttpd.h:5091
@ MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED
Definition: microhttpd.h:5074
@ MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH
Definition: microhttpd.h:5081
MHD_ValueKind
Definition: microhttpd.h:2245
@ MHD_HEADER_KIND
Definition: microhttpd.h:2260
@ MHD_GET_ARGUMENT_KIND
Definition: microhttpd.h:2281
#define MHD_DIGEST_AUTH_INVALID_NC_VALUE
Definition: microhttpd.h:5187
MHD_DigestAuthMultiAlgo3
Definition: microhttpd.h:4831
@ MHD_DIGEST_AUTH_MULT_ALGO3_SHA256
Definition: microhttpd.h:4852
@ MHD_DIGEST_AUTH_MULT_ALGO3_ANY_NON_SESSION
Definition: microhttpd.h:4886
@ MHD_DIGEST_AUTH_MULT_ALGO3_MD5
Definition: microhttpd.h:4840
MHD_DigestAuthAlgorithm
Definition: microhttpd.h:5779
@ MHD_DIGEST_ALG_AUTO
Definition: microhttpd.h:5784
@ MHD_DIGEST_ALG_MD5
Definition: microhttpd.h:5789
@ MHD_DIGEST_ALG_SHA256
Definition: microhttpd.h:5794
@ MHD_DAUTH_BIND_NONCE_NONE
Definition: microhttpd.h:1612
@ MHD_DAUTH_BIND_NONCE_URI
Definition: microhttpd.h:1629
@ MHD_DAUTH_BIND_NONCE_URI_PARAMS
Definition: microhttpd.h:1637
@ MHD_DAUTH_BIND_NONCE_REALM
Definition: microhttpd.h:1617
@ MHD_DAUTH_BIND_NONCE_CLIENT_IP
Definition: microhttpd.h:1646
platform-specific includes for libmicrohttpd
Methods for managing response objects.
void MHD_SHA256_update(struct Sha256Ctx *ctx, const uint8_t *data, size_t length)
Definition: sha256.c:410
void MHD_SHA256_finish(struct Sha256Ctx *ctx, uint8_t digest[SHA256_DIGEST_SIZE])
Definition: sha256.c:473
#define SHA256_DIGEST_SIZE
Definition: sha256.h:55
void MHD_SHA512_256_finish(struct Sha512_256Ctx *ctx, uint8_t digest[SHA512_256_DIGEST_SIZE])
Definition: sha512_256.c:539
void MHD_SHA512_256_init(struct Sha512_256Ctx *ctx)
Definition: sha512_256.c:41
void MHD_SHA512_256_update(struct Sha512_256Ctx *ctx, const uint8_t *data, size_t length)
Definition: sha512_256.c:460
Calculation of SHA-512/256 digest.
#define SHA512_256_DIGEST_SIZE
Definition: sha512_256.h:62
socklen_t addr_len
Definition: internal.h:733
struct MHD_Request rq
Definition: internal.h:1365
struct sockaddr_storage addr
Definition: internal.h:728
struct MHD_Daemon * daemon
Definition: internal.h:675
void * unescape_callback_cls
Definition: internal.h:2072
UnescapeCallback unescape_callback
Definition: internal.h:2067
enum MHD_DigestAuthQOP qop
Definition: microhttpd.h:5298
enum MHD_DigestAuthUsernameType uname_type
Definition: microhttpd.h:5212
enum MHD_DigestAuthAlgo3 algo3
Definition: microhttpd.h:5207
enum MHD_DigestAuthAlgo3 algo3
Definition: microhttpd.h:5356
enum MHD_DigestAuthUsernameType uname_type
Definition: microhttpd.h:5363
enum MHD_ValueKind kind
Definition: internal.h:396
const char * value
Definition: internal.h:386
struct MHD_HTTP_Req_Header * next
Definition: internal.h:366
const char * header
Definition: internal.h:376
uint32_t nc
Definition: internal.h:285
uint64_t nmask
Definition: internal.h:293
char nonce[MAX_DIGEST_NONCE_LENGTH+1]
Definition: internal.h:298
struct MHD_HTTP_Header * headers_received
Definition: internal.h:388
enum MHD_Method method
Definition: internal.h:554
size_t url_len
Definition: internal.h:1101
const char * url
Definition: internal.h:413
enum MHD_HTTP_Method http_mthd
Definition: internal.h:1090
const char * str
Definition: mhd_str_types.h:50