GNU libmicrohttpd 1.0.6
Loading...
Searching...
No Matches
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
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)))
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
304union 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
320struct 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
351digest_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)
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
388digest_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 */
397}
398
399
409_MHD_static_inline void
410digest_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;
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
448digest_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 {
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
501 return false; /* Unsupported or bad algorithm */
502}
503
504
511_MHD_static_inline void
512digest_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
548digest_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
562digest_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
576digest_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
638digest_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
711digest_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
740static bool
741get_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
759 MHD_strx_to_uint64_n_ (nonce + noncelen - TIMESTAMP_CHARS_LEN,
761 ptimestamp))
762 return false;
763 return true;
764}
765
766
768
776static uint32_t
777fast_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
806static size_t
807get_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
831static enum MHD_CheckNonceNC_
832check_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;
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));
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
960get_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
992get_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
1021static size_t
1022get_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
1051static ssize_t
1052get_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
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
1101static size_t
1102get_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
1195
1196
1203static enum MHD_GetRqNCResult
1204get_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)
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)) )
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)
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 if (NULL == info)
1295 return NULL;
1296 unif_buf_ptr = (uint8_t *) (info + 1);
1297 unif_buf_used = 0;
1298
1299 info->algo3 = params->algo3;
1300
1303 unif_buf_used +=
1304 get_rq_uname (params, uname_type,
1305 (struct MHD_DigestAuthUsernameInfo *) info,
1306 unif_buf_ptr + unif_buf_used,
1307 unif_buf_size - unif_buf_used);
1308 else
1309 info->uname_type = uname_type;
1310
1311 if (NULL != params->opaque.value.str)
1312 {
1313 info->opaque = (char *) (unif_buf_ptr + unif_buf_used);
1314 info->opaque_len = get_rq_param_unquoted_copy_z (&params->opaque,
1315 info->opaque);
1316 unif_buf_used += info->opaque_len + 1;
1317 }
1318 if (NULL != params->realm.value.str)
1319 {
1320 info->realm = (char *) (unif_buf_ptr + unif_buf_used);
1321 info->realm_len = get_rq_param_unquoted_copy_z (&params->realm,
1322 info->realm);
1323 unif_buf_used += info->realm_len + 1;
1324 }
1325
1326 mhd_assert (unif_buf_size >= unif_buf_used);
1327
1328 info->qop = params->qop;
1329
1330 if (NULL != params->cnonce.value.str)
1331 info->cnonce_len = params->cnonce.value.len;
1332 else
1333 info->cnonce_len = 0;
1334
1335 nc_res = get_rq_nc (params, &info->nc);
1336 if (MHD_GET_RQ_NC_VALID != nc_res)
1338
1339 return info;
1340}
1341
1342
1359{
1360 const struct MHD_RqDAuth *params;
1361 struct MHD_DigestAuthUsernameInfo *uname_info;
1363 size_t unif_buf_size;
1364 uint8_t *unif_buf_ptr;
1365 size_t unif_buf_used;
1366
1367 params = MHD_get_rq_dauth_params_ (connection);
1368 if (NULL == params)
1369 return NULL;
1370
1371 uname_type = get_rq_uname_type (params);
1374 return NULL;
1375
1376 unif_buf_size = get_rq_unames_size (params, uname_type);
1377
1378 uname_info = (struct MHD_DigestAuthUsernameInfo *)
1379 MHD_calloc_ (1, (sizeof(struct MHD_DigestAuthUsernameInfo))
1380 + unif_buf_size);
1381 if (NULL == uname_info)
1382 return NULL;
1383 unif_buf_ptr = (uint8_t *) (uname_info + 1);
1384 unif_buf_used = get_rq_uname (params, uname_type, uname_info, unif_buf_ptr,
1385 unif_buf_size);
1386 mhd_assert (unif_buf_size >= unif_buf_used);
1387 (void) unif_buf_used; /* Mute compiler warning on non-debug builds */
1389
1391 {
1392 free (uname_info);
1393 return NULL;
1394 }
1395 mhd_assert (uname_type == uname_info->uname_type);
1396 uname_info->algo3 = params->algo3;
1397
1398 return uname_info;
1399}
1400
1401
1417_MHD_EXTERN char *
1419{
1420 const struct MHD_RqDAuth *params;
1421 char *username;
1422 size_t buf_size;
1423 enum MHD_DigestAuthUsernameType uname_type;
1424
1425 params = MHD_get_rq_dauth_params_ (connection);
1426 if (NULL == params)
1427 return NULL;
1428
1429 uname_type = get_rq_uname_type (params);
1430
1431 if ( (MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD != uname_type) &&
1432 (MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED != uname_type) )
1433 return NULL;
1434
1435 buf_size = get_rq_unames_size (params, uname_type);
1436
1437 mhd_assert (0 != buf_size);
1438
1439 username = (char *) MHD_calloc_ (1, buf_size);
1440 if (NULL == username)
1441 return NULL;
1442
1443 if (1)
1444 {
1445 struct MHD_DigestAuthUsernameInfo uname_strct;
1446 size_t used;
1447
1448 memset (&uname_strct, 0, sizeof(uname_strct));
1449
1450 used = get_rq_uname (params, uname_type, &uname_strct,
1451 (uint8_t *) username, buf_size);
1452 if (uname_type != uname_strct.uname_type)
1453 { /* Broken encoding for extended notation */
1454 free (username);
1455 return NULL;
1456 }
1457 (void) used; /* Mute compiler warning for non-debug builds */
1458 mhd_assert (buf_size >= used);
1459 }
1460
1461 return username;
1462}
1463
1464
1488static void
1489calculate_nonce (uint64_t nonce_time,
1490 enum MHD_HTTP_Method mthd_e,
1491 const char *method,
1492 const char *rnd,
1493 size_t rnd_size,
1494 const struct sockaddr_storage *saddr,
1495 size_t saddr_size,
1496 const char *uri,
1497 size_t uri_len,
1498 const struct MHD_HTTP_Req_Header *first_header,
1499 const char *realm,
1500 size_t realm_len,
1501 unsigned int bind_options,
1502 struct DigestAlgorithm *da,
1503 char *nonce)
1504{
1505 mhd_assert (! da->hashing);
1506 if (1)
1507 {
1508 /* Add the timestamp to the hash calculation */
1509 uint8_t timestamp[TIMESTAMP_BIN_SIZE];
1510 /* If the nonce_time is milliseconds, then the same 48 bit value will repeat
1511 * every 8 919 years, which is more than enough to mitigate a replay attack */
1512#if TIMESTAMP_BIN_SIZE != 6
1513#error The code needs to be updated here
1514#endif
1515 timestamp[0] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 0)));
1516 timestamp[1] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 1)));
1517 timestamp[2] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 2)));
1518 timestamp[3] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 3)));
1519 timestamp[4] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 4)));
1520 timestamp[5] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 5)));
1521 MHD_bin_to_hex (timestamp,
1522 sizeof (timestamp),
1523 nonce + digest_get_size (da) * 2);
1524 digest_update (da,
1525 timestamp,
1526 sizeof (timestamp));
1527 }
1528 if (rnd_size > 0)
1529 {
1530 /* Add the unique random value to the hash calculation */
1532 digest_update (da,
1533 rnd,
1534 rnd_size);
1535 }
1536 if ( (MHD_DAUTH_BIND_NONCE_NONE == bind_options) &&
1537 (0 != saddr_size) )
1538 {
1539 /* Add full client address including source port to make unique nonces
1540 * for requests received exactly at the same time */
1542 digest_update (da,
1543 saddr,
1544 saddr_size);
1545 }
1546 if ( (0 != (bind_options & MHD_DAUTH_BIND_NONCE_CLIENT_IP)) &&
1547 (0 != saddr_size) )
1548 {
1549 /* Add the client's IP address to the hash calculation */
1551 if (AF_INET == saddr->ss_family)
1552 digest_update (da,
1553 &((const struct sockaddr_in *) saddr)->sin_addr,
1554 sizeof(((const struct sockaddr_in *) saddr)->sin_addr));
1555#ifdef HAVE_INET6
1556 else if (AF_INET6 == saddr->ss_family)
1557 digest_update (da,
1558 &((const struct sockaddr_in6 *) saddr)->sin6_addr,
1559 sizeof(((const struct sockaddr_in6 *) saddr)->sin6_addr));
1560#endif /* HAVE_INET6 */
1561 }
1562 if ( (MHD_DAUTH_BIND_NONCE_NONE == bind_options) ||
1563 (0 != (bind_options & MHD_DAUTH_BIND_NONCE_URI)))
1564 {
1565 /* Add the request method to the hash calculation */
1567 if (MHD_HTTP_MTHD_OTHER != mthd_e)
1568 {
1569 uint8_t mthd_for_hash;
1570 if (MHD_HTTP_MTHD_HEAD != mthd_e)
1571 mthd_for_hash = (uint8_t) mthd_e;
1572 else /* Treat HEAD method in the same way as GET method */
1573 mthd_for_hash = (uint8_t) MHD_HTTP_MTHD_GET;
1574 digest_update (da,
1575 &mthd_for_hash,
1576 sizeof(mthd_for_hash));
1577 }
1578 else
1579 digest_update_str (da, method);
1580 }
1581
1582 if (0 != (bind_options & MHD_DAUTH_BIND_NONCE_URI))
1583 {
1584 /* Add the request URI to the hash calculation */
1586
1587 digest_update (da,
1588 uri,
1589 uri_len);
1590 }
1591 if (0 != (bind_options & MHD_DAUTH_BIND_NONCE_URI_PARAMS))
1592 {
1593 /* Add the request URI parameters to the hash calculation */
1594 const struct MHD_HTTP_Req_Header *h;
1595
1597 for (h = first_header; NULL != h; h = h->next)
1598 {
1599 if (MHD_GET_ARGUMENT_KIND != h->kind)
1600 continue;
1601 digest_update (da, "\0", 2);
1602 if (0 != h->header_size)
1603 digest_update (da, h->header, h->header_size);
1604 digest_update (da, "", 1);
1605 if (0 != h->value_size)
1606 digest_update (da, h->value, h->value_size);
1607 }
1608 }
1609 if ( (MHD_DAUTH_BIND_NONCE_NONE == bind_options) ||
1610 (0 != (bind_options & MHD_DAUTH_BIND_NONCE_REALM)))
1611 {
1612 /* Add the realm to the hash calculation */
1614 digest_update (da,
1615 realm,
1616 realm_len);
1617 }
1618 if (1)
1619 {
1620 uint8_t hash[MAX_DIGEST];
1621 digest_calc_hash (da, hash);
1622 MHD_bin_to_hex (hash,
1623 digest_get_size (da),
1624 nonce);
1625 }
1626}
1627
1628
1644static bool
1645is_slot_available (const struct MHD_NonceNc *const nn,
1646 const uint64_t now,
1647 const char *const new_nonce,
1648 size_t new_nonce_len)
1649{
1650 uint64_t timestamp;
1651 bool timestamp_valid;
1652 mhd_assert (new_nonce_len <= NONCE_STD_LEN (MAX_DIGEST));
1654 if (0 == nn->nonce[0])
1655 return true; /* The slot is empty */
1656
1657 if (0 == memcmp (nn->nonce, new_nonce, new_nonce_len))
1658 {
1659 /* The slot has the same nonce already. This nonce cannot be registered
1660 * again as it would just clear 'nc' usage history. */
1661 return false;
1662 }
1663
1664 if (0 != nn->nc)
1665 return true; /* Client already used the nonce in this slot at least
1666 one time, re-use the slot */
1667
1668 /* The nonce must be zero-terminated */
1669 mhd_assert (0 == nn->nonce[sizeof(nn->nonce) - 1]);
1670 if (0 != nn->nonce[sizeof(nn->nonce) - 1])
1671 return true; /* Wrong nonce format in the slot */
1672
1673 timestamp_valid = get_nonce_timestamp (nn->nonce, 0, &timestamp);
1674 mhd_assert (timestamp_valid);
1675 if (! timestamp_valid)
1676 return true; /* Invalid timestamp in nonce-nc, should not be possible */
1677
1678 if ((REUSE_TIMEOUT * 1000) < TRIM_TO_TIMESTAMP (now - timestamp))
1679 return true;
1680
1681 return false;
1682}
1683
1684
1700static bool
1701calculate_add_nonce (struct MHD_Connection *const connection,
1702 uint64_t timestamp,
1703 const char *realm,
1704 size_t realm_len,
1705 struct DigestAlgorithm *da,
1706 char *nonce)
1707{
1708 struct MHD_Daemon *const daemon = MHD_get_master (connection->daemon);
1709 struct MHD_NonceNc *nn;
1710 const size_t nonce_size = NONCE_STD_LEN (digest_get_size (da));
1711 bool ret;
1712
1713 mhd_assert (! da->hashing);
1714 mhd_assert (MAX_DIGEST_NONCE_LENGTH >= nonce_size);
1715 mhd_assert (0 != nonce_size);
1716
1717 calculate_nonce (timestamp,
1718 connection->rq.http_mthd,
1719 connection->rq.method,
1720 daemon->digest_auth_random,
1721 daemon->digest_auth_rand_size,
1722 connection->addr,
1723 (size_t) connection->addr_len,
1724 connection->rq.url,
1725 connection->rq.url_len,
1726 connection->rq.headers_received,
1727 realm,
1728 realm_len,
1729 daemon->dauth_bind_type,
1730 da,
1731 nonce);
1732
1733#ifdef MHD_DIGEST_HAS_EXT_ERROR
1734 if (digest_ext_error (da))
1735 return false;
1736#endif /* MHD_DIGEST_HAS_EXT_ERROR */
1737
1738 if (0 == daemon->nonce_nc_size)
1739 return false;
1740
1741 /* Sanity check for values */
1743
1744 nn = daemon->nnc + get_nonce_nc_idx (daemon->nonce_nc_size,
1745 nonce,
1746 nonce_size);
1747
1748 MHD_mutex_lock_chk_ (&daemon->nnc_lock);
1749 if (is_slot_available (nn, timestamp, nonce, nonce_size))
1750 {
1751 memcpy (nn->nonce,
1752 nonce,
1753 nonce_size);
1754 nn->nonce[nonce_size] = 0; /* With terminating zero */
1755 nn->nc = 0;
1756 nn->nmask = 0;
1757 ret = true;
1758 }
1759 else
1760 ret = false;
1761 MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
1762
1763 return ret;
1764}
1765
1766
1768
1780static bool
1782 const char *realm,
1783 struct DigestAlgorithm *da,
1784 char *nonce)
1785{
1786 const uint64_t timestamp1 = MHD_monotonic_msec_counter ();
1787 const size_t realm_len = strlen (realm);
1788 mhd_assert (! da->hashing);
1789
1790#ifdef HAVE_MESSAGES
1791 if (0 == MHD_get_master (connection->daemon)->digest_auth_rand_size)
1792 MHD_DLOG (connection->daemon,
1793 _ ("Random value was not initialised by " \
1794 "MHD_OPTION_DIGEST_AUTH_RANDOM or " \
1795 "MHD_OPTION_DIGEST_AUTH_RANDOM_COPY, generated nonces " \
1796 "are predictable.\n"));
1797#endif
1798
1799 if (! calculate_add_nonce (connection, timestamp1, realm, realm_len, da,
1800 nonce))
1801 {
1802 /* Either:
1803 * 1. The same nonce was already generated. If it will be used then one
1804 * of the clients will fail (as no initial 'nc' value could be given to
1805 * the client, the second client which will use 'nc=00000001' will fail).
1806 * 2. Another nonce uses the same slot, and this nonce never has been
1807 * used by the client and this nonce is still fresh enough.
1808 */
1809 const size_t digest_size = digest_get_size (da);
1810 char nonce2[NONCE_STD_LEN (MAX_DIGEST) + 1];
1811 uint64_t timestamp2;
1812#ifdef MHD_DIGEST_HAS_EXT_ERROR
1813 if (digest_ext_error (da))
1814 return false; /* No need to re-try */
1815#endif /* MHD_DIGEST_HAS_EXT_ERROR */
1816 if (0 == MHD_get_master (connection->daemon)->nonce_nc_size)
1817 return false; /* No need to re-try */
1818
1819 timestamp2 = MHD_monotonic_msec_counter ();
1820 if (timestamp1 == timestamp2)
1821 {
1822 /* The timestamps are equal, need to generate some arbitrary
1823 * difference for nonce. */
1824 /* As the number is needed only to differentiate clients, weak
1825 * pseudo-random generators could be used. Seeding is not needed. */
1826 uint64_t base1;
1827 uint32_t base2;
1828 uint16_t base3;
1829 uint8_t base4;
1830#ifdef HAVE_RANDOM
1831 base1 = ((uint64_t) random ()) ^ UINT64_C (0x54a5acff5be47e63);
1832 base4 = 0xb8;
1833#elif defined(HAVE_RAND)
1834 base1 = ((uint64_t) rand ()) ^ UINT64_C (0xc4bcf553b12f3965);
1835 base4 = 0x92;
1836#else
1837 /* Monotonic msec counter alone does not really help here as it is already
1838 known that this value is not unique. */
1839 base1 = ((uint64_t) (uintptr_t) nonce2) ^ UINT64_C (0xf2e1b21bc6c92655);
1840 base2 = ((uint32_t) (base1 >> 32)) ^ ((uint32_t) base1);
1841 base2 = _MHD_ROTR32 (base2, 4);
1842 base3 = ((uint16_t) (base2 >> 16)) ^ ((uint16_t) base2);
1843 base4 = ((uint8_t) (base3 >> 8)) ^ ((uint8_t) base3);
1844 base1 = ((uint64_t) MHD_monotonic_msec_counter ())
1845 ^ UINT64_C (0xccab93f72cf5b15);
1846#endif
1847 base2 = ((uint32_t) (base1 >> 32)) ^ ((uint32_t) base1);
1848 base2 = _MHD_ROTL32 (base2, (((base4 >> 4) ^ base4) % 32));
1849 base3 = ((uint16_t) (base2 >> 16)) ^ ((uint16_t) base2);
1850 base4 = ((uint8_t) (base3 >> 8)) ^ ((uint8_t) base3);
1851 /* Use up to 127 ms difference */
1852 timestamp2 -= (base4 & DAUTH_JUMPBACK_MAX);
1853 if (timestamp1 == timestamp2)
1854 timestamp2 -= 2; /* Fallback value */
1855 }
1856 digest_reset (da);
1857 if (! calculate_add_nonce (connection, timestamp2, realm, realm_len, da,
1858 nonce2))
1859 {
1860 /* No free slot has been found. Re-tries are expensive, just use
1861 * the generated nonce. As it is not stored in nonce-nc map array,
1862 * the next request of the client will be recognized as valid, but 'stale'
1863 * so client should re-try automatically. */
1864 return false;
1865 }
1866 memcpy (nonce, nonce2, NONCE_STD_LEN (digest_size));
1867 }
1868 return true;
1869}
1870
1871
1873
1890_MHD_static_inline void
1891calc_userdigest (struct DigestAlgorithm *da,
1892 const char *username, const size_t username_len,
1893 const char *realm, const size_t realm_len,
1894 const char *password,
1895 uint8_t *ha1_bin)
1896{
1897 mhd_assert (! da->hashing);
1898 digest_update (da, username, username_len);
1900 digest_update (da, realm, realm_len);
1902 digest_update_str (da, password);
1903 digest_calc_hash (da, ha1_bin);
1904}
1905
1906
1942 const char *username,
1943 const char *realm,
1944 const char *password,
1945 void *userdigest_bin,
1946 size_t bin_buf_size)
1947{
1948 struct DigestAlgorithm da;
1949 enum MHD_Result ret;
1950 if (! digest_init_one_time (&da, get_base_digest_algo (algo3)))
1951 return MHD_NO;
1952
1953 if (digest_get_size (&da) > bin_buf_size)
1954 ret = MHD_NO;
1955 else
1956 {
1957 calc_userdigest (&da,
1958 username,
1959 strlen (username),
1960 realm,
1961 strlen (realm),
1962 password,
1963 userdigest_bin);
1964 ret = MHD_YES;
1965
1966#ifdef MHD_DIGEST_HAS_EXT_ERROR
1967 if (digest_ext_error (&da))
1968 ret = MHD_NO;
1969#endif /* MHD_DIGEST_HAS_EXT_ERROR */
1970 }
1971 digest_deinit (&da);
1972
1973 return ret;
1974}
1975
1976
1990_MHD_static_inline void
1991calc_userhash (struct DigestAlgorithm *da,
1992 const char *username, const size_t username_len,
1993 const char *realm, const size_t realm_len,
1994 uint8_t *digest_bin)
1995{
1996 mhd_assert (NULL != username);
1997 mhd_assert (! da->hashing);
1998 digest_update (da, username, username_len);
2000 digest_update (da, realm, realm_len);
2001 digest_calc_hash (da, digest_bin);
2002}
2003
2004
2047 const char *username,
2048 const char *realm,
2049 void *userhash_bin,
2050 size_t bin_buf_size)
2051{
2052 struct DigestAlgorithm da;
2053 enum MHD_Result ret;
2054
2055 if (! digest_init_one_time (&da, get_base_digest_algo (algo3)))
2056 return MHD_NO;
2057 if (digest_get_size (&da) > bin_buf_size)
2058 ret = MHD_NO;
2059 else
2060 {
2061 calc_userhash (&da,
2062 username,
2063 strlen (username),
2064 realm,
2065 strlen (realm),
2066 userhash_bin);
2067 ret = MHD_YES;
2068
2069#ifdef MHD_DIGEST_HAS_EXT_ERROR
2070 if (digest_ext_error (&da))
2071 ret = MHD_NO;
2072#endif /* MHD_DIGEST_HAS_EXT_ERROR */
2073 }
2074 digest_deinit (&da);
2075
2076 return ret;
2077}
2078
2079
2122 const char *username,
2123 const char *realm,
2124 char *userhash_hex,
2125 size_t hex_buf_size)
2126{
2127 uint8_t userhash_bin[MAX_DIGEST];
2128 size_t digest_size;
2129
2130 digest_size = digest_get_hash_size (algo3);
2131 if (digest_size * 2 + 1 > hex_buf_size)
2132 return MHD_NO;
2133 if (MHD_NO == MHD_digest_auth_calc_userhash (algo3, username, realm,
2134 userhash_bin, MAX_DIGEST))
2135 return MHD_NO;
2136
2137 MHD_bin_to_hex_z (userhash_bin, digest_size, userhash_hex);
2138 return MHD_YES;
2139}
2140
2141
2142struct test_header_param
2143{
2144 struct MHD_Connection *connection;
2145 size_t num_headers;
2146};
2147
2161static enum MHD_Result
2162test_header (void *cls,
2163 const char *key,
2164 size_t key_size,
2165 const char *value,
2166 size_t value_size,
2167 enum MHD_ValueKind kind)
2168{
2169 struct test_header_param *const param = (struct test_header_param *) cls;
2170 struct MHD_Connection *connection = param->connection;
2171 struct MHD_HTTP_Req_Header *pos;
2172 size_t i;
2173
2174 param->num_headers++;
2175 i = 0;
2176 for (pos = connection->rq.headers_received; NULL != pos; pos = pos->next)
2177 {
2178 if (kind != pos->kind)
2179 continue;
2180 if (++i == param->num_headers)
2181 {
2182 if (key_size != pos->header_size)
2183 return MHD_NO;
2184 if (value_size != pos->value_size)
2185 return MHD_NO;
2186 if (0 != key_size)
2187 {
2188 mhd_assert (NULL != key);
2189 mhd_assert (NULL != pos->header);
2190 if (0 != memcmp (key,
2191 pos->header,
2192 key_size))
2193 return MHD_NO;
2194 }
2195 if (0 != value_size)
2196 {
2197 mhd_assert (NULL != value);
2198 mhd_assert (NULL != pos->value);
2199 if (0 != memcmp (value,
2200 pos->value,
2201 value_size))
2202 return MHD_NO;
2203 }
2204 return MHD_YES;
2205 }
2206 }
2207 return MHD_NO;
2208}
2209
2210
2222static bool
2224 char *args)
2225{
2226 struct MHD_HTTP_Req_Header *pos;
2227 enum MHD_Result ret;
2228 struct test_header_param param;
2229
2230 param.connection = connection;
2231 param.num_headers = 0;
2232 ret = MHD_parse_arguments_ (connection,
2234 args,
2235 &test_header,
2236 &param);
2237 if (MHD_NO == ret)
2238 {
2239 return false;
2240 }
2241 /* also check that the number of headers matches */
2242 for (pos = connection->rq.headers_received; NULL != pos; pos = pos->next)
2243 {
2244 if (MHD_GET_ARGUMENT_KIND != pos->kind)
2245 continue;
2246 param.num_headers--;
2247 }
2248 if (0 != param.num_headers)
2249 {
2250 /* argument count mismatch */
2251 return false;
2252 }
2253 return true;
2254}
2255
2256
2269static bool
2270check_uri_match (struct MHD_Connection *connection, char *uri, size_t uri_len)
2271{
2272 char *qmark;
2273 char *args;
2274 struct MHD_Daemon *const daemon = connection->daemon;
2275
2276 uri[uri_len] = 0;
2277 qmark = memchr (uri,
2278 '?',
2279 uri_len);
2280 if (NULL != qmark)
2281 *qmark = '\0';
2282
2283 /* Need to unescape URI before comparing with connection->url */
2284 uri_len = daemon->unescape_callback (daemon->unescape_callback_cls,
2285 connection,
2286 uri);
2287 if ((uri_len != connection->rq.url_len) ||
2288 (0 != memcmp (uri, connection->rq.url, uri_len)))
2289 {
2290#ifdef HAVE_MESSAGES
2291 MHD_DLOG (daemon,
2292 _ ("Authentication failed, URI does not match.\n"));
2293#endif
2294 return false;
2295 }
2296
2297 args = (NULL != qmark) ? (qmark + 1) : uri + uri_len;
2298
2299 if (! check_argument_match (connection,
2300 args) )
2301 {
2302#ifdef HAVE_MESSAGES
2303 MHD_DLOG (daemon,
2304 _ ("Authentication failed, arguments do not match.\n"));
2305#endif
2306 return false;
2307 }
2308 return true;
2309}
2310
2311
2315#define _MHD_STATIC_UNQ_BUFFER_SIZE 128
2316
2317
2327static char *
2329 char **ptmp2,
2330 size_t *ptmp2_size,
2331 size_t required_size)
2332{
2333 mhd_assert ((0 == *ptmp2_size) || (NULL != *ptmp2));
2334 mhd_assert ((NULL != *ptmp2) || (0 == *ptmp2_size));
2335 mhd_assert ((0 == *ptmp2_size) || \
2336 (_MHD_STATIC_UNQ_BUFFER_SIZE < *ptmp2_size));
2337
2338 if (required_size <= _MHD_STATIC_UNQ_BUFFER_SIZE)
2339 return tmp1;
2340
2341 if (required_size <= *ptmp2_size)
2342 return *ptmp2;
2343
2344 if (required_size > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE)
2345 return NULL;
2346 if (NULL != *ptmp2)
2347 free (*ptmp2);
2348 *ptmp2 = (char *) malloc (required_size);
2349 if (NULL == *ptmp2)
2350 *ptmp2_size = 0;
2351 else
2352 *ptmp2_size = required_size;
2353 return *ptmp2;
2354}
2355
2356
2366
2376static enum _MHD_GetUnqResult
2377get_unquoted_param (const struct MHD_RqDAuthParam *param,
2378 char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE],
2379 char **ptmp2,
2380 size_t *ptmp2_size,
2381 struct _MHD_str_w_len *unquoted)
2382{
2383 char *str;
2384 size_t len;
2385 mhd_assert (NULL != param->value.str);
2386 mhd_assert (0 != param->value.len);
2387
2388 if (! param->quoted)
2389 {
2390 unquoted->str = param->value.str;
2391 unquoted->len = param->value.len;
2392 return _MHD_UNQ_OK;
2393 }
2394 /* The value is present and is quoted, needs to be copied and unquoted */
2395 str = get_buffer_for_size (tmp1, ptmp2, ptmp2_size, param->value.len);
2396 if (NULL == str)
2397 return (param->value.len > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE) ?
2399
2400 len = MHD_str_unquote (param->value.str, param->value.len, str);
2401 unquoted->str = str;
2402 unquoted->len = len;
2403 mhd_assert (0 != unquoted->len);
2404 mhd_assert (unquoted->len < param->value.len);
2405 return _MHD_UNQ_OK;
2406}
2407
2408
2419static enum _MHD_GetUnqResult
2420get_unquoted_param_copy (const struct MHD_RqDAuthParam *param,
2421 char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE],
2422 char **ptmp2,
2423 size_t *ptmp2_size,
2424 struct _MHD_mstr_w_len *unquoted)
2425{
2426 mhd_assert (NULL != param->value.str);
2427 mhd_assert (0 != param->value.len);
2428
2429 /* The value is present and is quoted, needs to be copied and unquoted */
2430 /* Allocate buffer with one more additional byte for zero-termination */
2431 unquoted->str =
2432 get_buffer_for_size (tmp1, ptmp2, ptmp2_size, param->value.len + 1);
2433
2434 if (NULL == unquoted->str)
2435 return (param->value.len + 1 > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE) ?
2437
2438 if (! param->quoted)
2439 {
2440 memcpy (unquoted->str, param->value.str, param->value.len);
2441 unquoted->len = param->value.len;
2442 return _MHD_UNQ_OK;
2443 }
2444
2445 unquoted->len =
2446 MHD_str_unquote (param->value.str, param->value.len, unquoted->str);
2447 mhd_assert (0 != unquoted->len);
2448 mhd_assert (unquoted->len < param->value.len);
2449 return _MHD_UNQ_OK;
2450}
2451
2452
2461_MHD_static_inline bool
2462is_param_equal (const struct MHD_RqDAuthParam *param,
2463 const char *const str,
2464 const size_t str_len)
2465{
2466 mhd_assert (NULL != param->value.str);
2467 mhd_assert (0 != param->value.len);
2468 if (param->quoted)
2469 return MHD_str_equal_quoted_bin_n (param->value.str, param->value.len,
2470 str, str_len);
2471 return (str_len == param->value.len) &&
2472 (0 == memcmp (str, param->value.str, str_len));
2473
2474}
2475
2476
2485_MHD_static_inline bool
2486is_param_equal_caseless (const struct MHD_RqDAuthParam *param,
2487 const char *const str,
2488 const size_t str_len)
2489{
2490 mhd_assert (NULL != param->value.str);
2491 mhd_assert (0 != param->value.len);
2492 if (param->quoted)
2493 return MHD_str_equal_caseless_quoted_bin_n (param->value.str,
2494 param->value.len,
2495 str,
2496 str_len);
2497 return (str_len == param->value.len) &&
2499 param->value.str,
2500 str_len));
2501}
2502
2503
2540static enum MHD_DigestAuthResult
2542 const char *realm,
2543 const char *username,
2544 const char *password,
2545 const uint8_t *userdigest,
2546 unsigned int nonce_timeout,
2547 uint32_t max_nc,
2548 enum MHD_DigestAuthMultiQOP mqop,
2549 enum MHD_DigestAuthMultiAlgo3 malgo3,
2550 char **pbuf,
2551 struct DigestAlgorithm *da)
2552{
2553 struct MHD_Daemon *daemon = MHD_get_master (connection->daemon);
2554 enum MHD_DigestAuthAlgo3 c_algo;
2555 enum MHD_DigestAuthQOP c_qop;
2556 unsigned int digest_size;
2557 uint8_t hash1_bin[MAX_DIGEST];
2558 uint8_t hash2_bin[MAX_DIGEST];
2559#if 0
2560 const char *hentity = NULL; /* "auth-int" is not supported */
2561#endif
2562 uint64_t nonce_time;
2563 uint64_t nci;
2564 const struct MHD_RqDAuth *params;
2568 char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE];
2569 char **const ptmp2 = pbuf;
2570 size_t tmp2_size;
2571 struct _MHD_str_w_len unquoted;
2572 struct _MHD_mstr_w_len unq_copy;
2573 enum _MHD_GetUnqResult unq_res;
2574 size_t username_len;
2575 size_t realm_len;
2576
2577 mhd_assert ((NULL != password) || (NULL != userdigest));
2578 mhd_assert (! ((NULL != userdigest) && (NULL != password)));
2579
2580 tmp2_size = 0;
2581
2582 params = MHD_get_rq_dauth_params_ (connection);
2583 if (NULL == params)
2585
2586 /* ** Initial parameters checks and setup ** */
2587 /* Get client's algorithm */
2588 c_algo = params->algo3;
2589 /* Check whether client's algorithm is allowed by function parameter */
2590 if (((unsigned int) c_algo) !=
2591 (((unsigned int) c_algo) & ((unsigned int) malgo3)))
2592 return MHD_DAUTH_WRONG_ALGO;
2593 /* Check whether client's algorithm is supported */
2594 if (0 != (((unsigned int) c_algo) & MHD_DIGEST_AUTH_ALGO3_SESSION))
2595 {
2596#ifdef HAVE_MESSAGES
2597 MHD_DLOG (connection->daemon,
2598 _ ("The 'session' algorithms are not supported.\n"));
2599#endif /* HAVE_MESSAGES */
2600 return MHD_DAUTH_WRONG_ALGO;
2601 }
2602#ifndef MHD_MD5_SUPPORT
2603 if (0 != (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_MD5))
2604 {
2605#ifdef HAVE_MESSAGES
2606 MHD_DLOG (connection->daemon,
2607 _ ("The MD5 algorithm is not supported by this MHD build.\n"));
2608#endif /* HAVE_MESSAGES */
2609 return MHD_DAUTH_WRONG_ALGO;
2610 }
2611#endif /* ! MHD_MD5_SUPPORT */
2612#ifndef MHD_SHA256_SUPPORT
2613 if (0 != (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_SHA256))
2614 {
2615#ifdef HAVE_MESSAGES
2616 MHD_DLOG (connection->daemon,
2617 _ ("The SHA-256 algorithm is not supported by "
2618 "this MHD build.\n"));
2619#endif /* HAVE_MESSAGES */
2620 return MHD_DAUTH_WRONG_ALGO;
2621 }
2622#endif /* ! MHD_SHA256_SUPPORT */
2623#ifndef MHD_SHA512_256_SUPPORT
2624 if (0 != (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_SHA512_256))
2625 {
2626#ifdef HAVE_MESSAGES
2627 MHD_DLOG (connection->daemon,
2628 _ ("The SHA-512/256 algorithm is not supported by "
2629 "this MHD build.\n"));
2630#endif /* HAVE_MESSAGES */
2631 return MHD_DAUTH_WRONG_ALGO;
2632 }
2633#endif /* ! MHD_SHA512_256_SUPPORT */
2634 if (! digest_init_one_time (da, get_base_digest_algo (c_algo)))
2635 MHD_PANIC (_ ("Wrong 'malgo3' value, API violation"));
2636 /* Check 'mqop' value */
2637 c_qop = params->qop;
2638 /* Check whether client's QOP is allowed by function parameter */
2639 if (((unsigned int) c_qop) !=
2640 (((unsigned int) c_qop) & ((unsigned int) mqop)))
2641 return MHD_DAUTH_WRONG_QOP;
2642 if (0 != (((unsigned int) c_qop) & MHD_DIGEST_AUTH_QOP_AUTH_INT))
2643 {
2644#ifdef HAVE_MESSAGES
2645 MHD_DLOG (connection->daemon,
2646 _ ("The 'auth-int' QOP is not supported.\n"));
2647#endif /* HAVE_MESSAGES */
2648 return MHD_DAUTH_WRONG_QOP;
2649 }
2650#ifdef HAVE_MESSAGES
2651 if ((MHD_DIGEST_AUTH_QOP_NONE == c_qop) &&
2652 (0 == (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_MD5)))
2653 MHD_DLOG (connection->daemon,
2654 _ ("RFC2069 with SHA-256 or SHA-512/256 algorithm is " \
2655 "non-standard extension.\n"));
2656#endif /* HAVE_MESSAGES */
2657
2658 digest_size = digest_get_size (da);
2659
2660 /* ** A quick check for presence of all required parameters ** */
2661
2662 if ((NULL == params->username.value.str) &&
2663 (NULL == params->username_ext.value.str))
2665 else if ((NULL != params->username.value.str) &&
2666 (NULL != params->username_ext.value.str))
2667 return MHD_DAUTH_WRONG_USERNAME; /* Parameters cannot be used together */
2668 else if ((NULL != params->username_ext.value.str) &&
2669 (MHD_DAUTH_EXT_PARAM_MIN_LEN > params->username_ext.value.len))
2670 return MHD_DAUTH_WRONG_USERNAME; /* Broken extended notation */
2671 else if (params->userhash && (NULL == params->username.value.str))
2672 return MHD_DAUTH_WRONG_USERNAME; /* Userhash cannot be used with extended notation */
2673 else if (params->userhash && (digest_size * 2 > params->username.value.len))
2674 return MHD_DAUTH_WRONG_USERNAME; /* Too few chars for correct userhash */
2675 else if (params->userhash && (digest_size * 4 < params->username.value.len))
2676 return MHD_DAUTH_WRONG_USERNAME; /* Too many chars for correct userhash */
2677
2678 if (NULL == params->realm.value.str)
2679 return MHD_DAUTH_WRONG_REALM;
2680 else if (((NULL == userdigest) || params->userhash) &&
2682 return MHD_DAUTH_TOO_LARGE; /* Realm is too large and should be used in hash calculations */
2683
2684 if (MHD_DIGEST_AUTH_QOP_NONE != c_qop)
2685 {
2686 if (NULL == params->nc.value.str)
2688 else if (0 == params->nc.value.len)
2690 else if (4 * 8 < params->nc.value.len) /* Four times more than needed */
2692
2693 if (NULL == params->cnonce.value.str)
2695 else if (0 == params->cnonce.value.len)
2697 else if (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < params->cnonce.value.len)
2698 return MHD_DAUTH_TOO_LARGE;
2699 }
2700
2701 /* The QOP parameter was checked already */
2702
2703 if (NULL == params->uri.value.str)
2704 return MHD_DAUTH_WRONG_URI;
2705 else if (0 == params->uri.value.len)
2706 return MHD_DAUTH_WRONG_URI;
2707 else if (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < params->uri.value.len)
2708 return MHD_DAUTH_TOO_LARGE;
2709
2710 if (NULL == params->nonce.value.str)
2711 return MHD_DAUTH_NONCE_WRONG;
2712 else if (0 == params->nonce.value.len)
2713 return MHD_DAUTH_NONCE_WRONG;
2714 else if (NONCE_STD_LEN (digest_size) * 2 < params->nonce.value.len)
2715 return MHD_DAUTH_NONCE_WRONG;
2716
2717 if (NULL == params->response.value.str)
2719 else if (0 == params->response.value.len)
2721 else if (digest_size * 4 < params->response.value.len)
2723
2724 /* ** Check simple parameters match ** */
2725
2726 /* Check 'algorithm' */
2727 /* The 'algorithm' was checked at the start of the function */
2728 /* 'algorithm' valid */
2729
2730 /* Check 'qop' */
2731 /* The 'qop' was checked at the start of the function */
2732 /* 'qop' valid */
2733
2734 /* Check 'realm' */
2735 realm_len = strlen (realm);
2736 if (! is_param_equal (&params->realm, realm, realm_len))
2737 return MHD_DAUTH_WRONG_REALM;
2738 /* 'realm' valid */
2739
2740 /* Check 'username' */
2741 username_len = strlen (username);
2742 if (! params->userhash)
2743 {
2744 if (NULL != params->username.value.str)
2745 { /* Username in standard notation */
2746 if (! is_param_equal (&params->username, username, username_len))
2748 }
2749 else
2750 { /* Username in extended notation */
2751 char *r_uname;
2752 size_t buf_size = params->username_ext.value.len;
2753 ssize_t res;
2754
2755 mhd_assert (NULL != params->username_ext.value.str);
2756 mhd_assert (MHD_DAUTH_EXT_PARAM_MIN_LEN <= buf_size); /* It was checked already */
2757 buf_size += 1; /* For zero-termination */
2758 buf_size -= MHD_DAUTH_EXT_PARAM_MIN_LEN;
2759 r_uname = get_buffer_for_size (tmp1, ptmp2, &tmp2_size, buf_size);
2760 if (NULL == r_uname)
2761 return (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < buf_size) ?
2763 res = get_rq_extended_uname_copy_z (params->username_ext.value.str,
2764 params->username_ext.value.len,
2765 r_uname, buf_size);
2766 if (0 > res)
2767 return MHD_DAUTH_WRONG_HEADER; /* Broken extended notation */
2768 if ((username_len != (size_t) res) ||
2769 (0 != memcmp (username, r_uname, username_len)))
2771 }
2772 }
2773 else
2774 { /* Userhash */
2775 mhd_assert (NULL != params->username.value.str);
2776 calc_userhash (da, username, username_len, realm, realm_len, hash1_bin);
2777#ifdef MHD_DIGEST_HAS_EXT_ERROR
2778 if (digest_ext_error (da))
2779 return MHD_DAUTH_ERROR;
2780#endif /* MHD_DIGEST_HAS_EXT_ERROR */
2781 mhd_assert (sizeof (tmp1) >= (2 * digest_size));
2782 MHD_bin_to_hex (hash1_bin, digest_size, tmp1);
2783 if (! is_param_equal_caseless (&params->username, tmp1, 2 * digest_size))
2785 /* To simplify the logic, the digest is reset here instead of resetting
2786 before the next hash calculation. */
2787 digest_reset (da);
2788 }
2789 /* 'username' valid */
2790
2791 /* ** Do basic nonce and nonce-counter checks (size, timestamp) ** */
2792
2793 /* Get 'nc' digital value */
2794 if (MHD_DIGEST_AUTH_QOP_NONE != c_qop)
2795 {
2796
2797 unq_res = get_unquoted_param (&params->nc, tmp1, ptmp2, &tmp2_size,
2798 &unquoted);
2799 if (_MHD_UNQ_OK != unq_res)
2800 return MHD_DAUTH_ERROR;
2801
2802 if (unquoted.len != MHD_strx_to_uint64_n_ (unquoted.str,
2803 unquoted.len,
2804 &nci))
2805 {
2806#ifdef HAVE_MESSAGES
2807 MHD_DLOG (daemon,
2808 _ ("Authentication failed, invalid nc format.\n"));
2809#endif
2810 return MHD_DAUTH_WRONG_HEADER; /* invalid nonce format */
2811 }
2812 if (0 == nci)
2813 {
2814#ifdef HAVE_MESSAGES
2815 MHD_DLOG (daemon,
2816 _ ("Authentication failed, invalid 'nc' value.\n"));
2817#endif
2818 return MHD_DAUTH_WRONG_HEADER; /* invalid nc value */
2819 }
2820 if ((0 != max_nc) && (max_nc < nci))
2821 return MHD_DAUTH_NONCE_STALE; /* Too large 'nc' value */
2822 }
2823 else
2824 nci = 1; /* Force 'nc' value */
2825 /* Got 'nc' digital value */
2826
2827 /* Get 'nonce' with basic checks */
2828 unq_res = get_unquoted_param (&params->nonce, tmp1, ptmp2, &tmp2_size,
2829 &unquoted);
2830 if (_MHD_UNQ_OK != unq_res)
2831 return MHD_DAUTH_ERROR;
2832
2833 if ((NONCE_STD_LEN (digest_size) != unquoted.len) ||
2834 (! get_nonce_timestamp (unquoted.str, unquoted.len, &nonce_time)))
2835 {
2836#ifdef HAVE_MESSAGES
2837 MHD_DLOG (daemon,
2838 _ ("Authentication failed, invalid nonce format.\n"));
2839#endif
2840 return MHD_DAUTH_NONCE_WRONG;
2841 }
2842
2843 if (1)
2844 {
2845 uint64_t t;
2846
2848 /*
2849 * First level vetting for the nonce validity: if the timestamp
2850 * attached to the nonce exceeds `nonce_timeout', then the nonce is
2851 * stale.
2852 */
2853 if (TRIM_TO_TIMESTAMP (t - nonce_time) > (nonce_timeout * 1000))
2854 return MHD_DAUTH_NONCE_STALE; /* too old */
2855 }
2856 if (1)
2857 {
2858 enum MHD_CheckNonceNC_ nonce_nc_check;
2859 /*
2860 * Checking if that combination of nonce and nc is sound
2861 * and not a replay attack attempt. Refuse if nonce was not
2862 * generated previously.
2863 */
2864 nonce_nc_check = check_nonce_nc (connection,
2865 unquoted.str,
2866 NONCE_STD_LEN (digest_size),
2867 nonce_time,
2868 nci);
2869 if (MHD_CHECK_NONCENC_STALE == nonce_nc_check)
2870 {
2871#ifdef HAVE_MESSAGES
2872 if (MHD_DIGEST_AUTH_QOP_NONE != c_qop)
2873 MHD_DLOG (daemon,
2874 _ ("Stale nonce received. If this happens a lot, you should "
2875 "probably increase the size of the nonce array.\n"));
2876 else
2877 MHD_DLOG (daemon,
2878 _ ("Stale nonce received. This is expected when client " \
2879 "uses RFC2069-compatible mode and makes more than one " \
2880 "request.\n"));
2881#endif
2882 return MHD_DAUTH_NONCE_STALE;
2883 }
2884 else if (MHD_CHECK_NONCENC_WRONG == nonce_nc_check)
2885 {
2886#ifdef HAVE_MESSAGES
2887 MHD_DLOG (daemon,
2888 _ ("Received nonce that was not "
2889 "generated by MHD. This may indicate an attack attempt.\n"));
2890#endif
2891 return MHD_DAUTH_NONCE_WRONG;
2892 }
2893 mhd_assert (MHD_CHECK_NONCENC_OK == nonce_nc_check);
2894 }
2895 /* The nonce was generated by MHD, is not stale and nonce-nc combination was
2896 not used before */
2897
2898 /* ** Build H(A2) and check URI match in the header and in the request ** */
2899
2900 /* Get 'uri' */
2901 mhd_assert (! da->hashing);
2902 digest_update_str (da, connection->rq.method);
2904#if 0
2905 /* TODO: add support for "auth-int" */
2906 digest_update_str (da, hentity);
2908#endif
2909 unq_res = get_unquoted_param_copy (&params->uri, tmp1, ptmp2, &tmp2_size,
2910 &unq_copy);
2911 if (_MHD_UNQ_OK != unq_res)
2912 return MHD_DAUTH_ERROR;
2913
2914 digest_update (da, unq_copy.str, unq_copy.len);
2915 /* The next check will modify copied URI string */
2916 if (! check_uri_match (connection, unq_copy.str, unq_copy.len))
2917 return MHD_DAUTH_WRONG_URI;
2918 digest_calc_hash (da, hash2_bin);
2919#ifdef MHD_DIGEST_HAS_EXT_ERROR
2920 /* Skip digest calculation external error check, the next one checks both */
2921#endif /* MHD_DIGEST_HAS_EXT_ERROR */
2922 /* Got H(A2) */
2923
2924 /* ** Build H(A1) ** */
2925 if (NULL == userdigest)
2926 {
2927 mhd_assert (! da->hashing);
2928 digest_reset (da);
2929 calc_userdigest (da,
2930 username, username_len,
2931 realm, realm_len,
2932 password,
2933 hash1_bin);
2934 }
2935 /* TODO: support '-sess' versions */
2936#ifdef MHD_DIGEST_HAS_EXT_ERROR
2937 if (digest_ext_error (da))
2938 return MHD_DAUTH_ERROR;
2939#endif /* MHD_DIGEST_HAS_EXT_ERROR */
2940 /* Got H(A1) */
2941
2942 /* ** Check 'response' ** */
2943
2944 mhd_assert (! da->hashing);
2945 digest_reset (da);
2946 /* Update digest with H(A1) */
2947 mhd_assert (sizeof (tmp1) >= (digest_size * 2));
2948 if (NULL == userdigest)
2949 MHD_bin_to_hex (hash1_bin, digest_size, tmp1);
2950 else
2951 MHD_bin_to_hex (userdigest, digest_size, tmp1);
2952 digest_update (da, (const uint8_t *) tmp1, digest_size * 2);
2953
2954 /* H(A1) is not needed anymore, reuse the buffer.
2955 * Use hash1_bin for the client's 'response' decoded to binary form. */
2956 unq_res = get_unquoted_param (&params->response, tmp1, ptmp2, &tmp2_size,
2957 &unquoted);
2958 if (_MHD_UNQ_OK != unq_res)
2959 return MHD_DAUTH_ERROR;
2960 if (digest_size != MHD_hex_to_bin (unquoted.str, unquoted.len, hash1_bin))
2962
2963 /* Update digest with ':' */
2965 /* Update digest with 'nonce' text value */
2966 unq_res = get_unquoted_param (&params->nonce, tmp1, ptmp2, &tmp2_size,
2967 &unquoted);
2968 if (_MHD_UNQ_OK != unq_res)
2969 return MHD_DAUTH_ERROR;
2970 digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
2971 /* Update digest with ':' */
2973 if (MHD_DIGEST_AUTH_QOP_NONE != c_qop)
2974 {
2975 /* Update digest with 'nc' text value */
2976 unq_res = get_unquoted_param (&params->nc, tmp1, ptmp2, &tmp2_size,
2977 &unquoted);
2978 if (_MHD_UNQ_OK != unq_res)
2979 return MHD_DAUTH_ERROR;
2980 digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
2981 /* Update digest with ':' */
2983 /* Update digest with 'cnonce' value */
2984 unq_res = get_unquoted_param (&params->cnonce, tmp1, ptmp2, &tmp2_size,
2985 &unquoted);
2986 if (_MHD_UNQ_OK != unq_res)
2987 return MHD_DAUTH_ERROR;
2988 digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
2989 /* Update digest with ':' */
2991 /* Update digest with 'qop' value */
2992 unq_res = get_unquoted_param (&params->qop_raw, tmp1, ptmp2, &tmp2_size,
2993 &unquoted);
2994 if (_MHD_UNQ_OK != unq_res)
2995 return MHD_DAUTH_ERROR;
2996 digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
2997 /* Update digest with ':' */
2999 }
3000 /* Update digest with H(A2) */
3001 MHD_bin_to_hex (hash2_bin,
3002 digest_size,
3003 tmp1);
3004 digest_update (da,
3005 (const uint8_t *) tmp1,
3006 digest_size * 2);
3007
3008 /* H(A2) is not needed anymore, reuse the buffer.
3009 * Use hash2_bin for the calculated response in binary form */
3010 digest_calc_hash (da, hash2_bin);
3011#ifdef MHD_DIGEST_HAS_EXT_ERROR
3012 if (digest_ext_error (da))
3013 return MHD_DAUTH_ERROR;
3014#endif /* MHD_DIGEST_HAS_EXT_ERROR */
3015
3016 if (0 != memcmp (hash1_bin,
3017 hash2_bin,
3018 digest_size))
3020
3021 if (MHD_DAUTH_BIND_NONCE_NONE != daemon->dauth_bind_type)
3022 {
3023 mhd_assert (sizeof(tmp1) >= (NONCE_STD_LEN (digest_size) + 1));
3024 /* It was already checked that 'nonce' (including timestamp) was generated
3025 by MHD. */
3026 mhd_assert (! da->hashing);
3027 digest_reset (da);
3028 calculate_nonce (nonce_time,
3029 connection->rq.http_mthd,
3030 connection->rq.method,
3031 daemon->digest_auth_random,
3032 daemon->digest_auth_rand_size,
3033 connection->addr,
3034 (size_t) connection->addr_len,
3035 connection->rq.url,
3036 connection->rq.url_len,
3037 connection->rq.headers_received,
3038 realm,
3039 realm_len,
3040 daemon->dauth_bind_type,
3041 da,
3042 tmp1);
3043
3044#ifdef MHD_DIGEST_HAS_EXT_ERROR
3045 if (digest_ext_error (da))
3046 return MHD_DAUTH_ERROR;
3047#endif /* MHD_DIGEST_HAS_EXT_ERROR */
3048
3049 if (! is_param_equal (&params->nonce, tmp1,
3050 NONCE_STD_LEN (digest_size)))
3052 /* The 'nonce' was generated in the same conditions */
3053 }
3054
3055 return MHD_DAUTH_OK;
3056}
3057
3058
3093static enum MHD_DigestAuthResult
3095 const char *realm,
3096 const char *username,
3097 const char *password,
3098 const uint8_t *userdigest,
3099 unsigned int nonce_timeout,
3100 uint32_t max_nc,
3101 enum MHD_DigestAuthMultiQOP mqop,
3102 enum MHD_DigestAuthMultiAlgo3 malgo3)
3103{
3104 enum MHD_DigestAuthResult res;
3105 char *buf;
3106 struct DigestAlgorithm da;
3107
3108 buf = NULL;
3109 digest_setup_zero (&da);
3110 if (0 == nonce_timeout)
3111 nonce_timeout = connection->daemon->dauth_def_nonce_timeout;
3112 if (0 == max_nc)
3113 max_nc = connection->daemon->dauth_def_max_nc;
3114 res = digest_auth_check_all_inner (connection, realm, username, password,
3115 userdigest,
3116 nonce_timeout,
3117 max_nc, mqop, malgo3,
3118 &buf, &da);
3119 digest_deinit (&da);
3120 if (NULL != buf)
3121 free (buf);
3122
3123 return res;
3124}
3125
3126
3145_MHD_EXTERN int
3147 const char *realm,
3148 const char *username,
3149 const char *password,
3150 unsigned int nonce_timeout)
3151{
3152 return MHD_digest_auth_check2 (connection,
3153 realm,
3154 username,
3155 password,
3156 nonce_timeout,
3158}
3159
3160
3194 const char *realm,
3195 const char *username,
3196 const char *password,
3197 unsigned int nonce_timeout,
3198 uint32_t max_nc,
3199 enum MHD_DigestAuthMultiQOP mqop,
3200 enum MHD_DigestAuthMultiAlgo3 malgo3)
3201{
3202 mhd_assert (NULL != password);
3203
3204 return digest_auth_check_all (connection,
3205 realm,
3206 username,
3207 password,
3208 NULL,
3209 nonce_timeout,
3210 max_nc,
3211 mqop,
3212 malgo3);
3213}
3214
3215
3260 const char *realm,
3261 const char *username,
3262 const void *userdigest,
3263 size_t userdigest_size,
3264 unsigned int nonce_timeout,
3265 uint32_t max_nc,
3266 enum MHD_DigestAuthMultiQOP mqop,
3267 enum MHD_DigestAuthMultiAlgo3 malgo3)
3268{
3269 if (1 != (((0 != (malgo3 & MHD_DIGEST_BASE_ALGO_MD5)) ? 1 : 0)
3270 + ((0 != (malgo3 & MHD_DIGEST_BASE_ALGO_SHA256)) ? 1 : 0)
3271 + ((0 != (malgo3 & MHD_DIGEST_BASE_ALGO_SHA512_256)) ? 1 : 0)))
3272 MHD_PANIC (_ ("Wrong 'malgo3' value, only one base hashing algorithm " \
3273 "(MD5, SHA-256 or SHA-512/256) must be specified, " \
3274 "API violation"));
3275
3276#ifndef MHD_MD5_SUPPORT
3277 if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_MD5))
3278 {
3279#ifdef HAVE_MESSAGES
3280 MHD_DLOG (connection->daemon,
3281 _ ("The MD5 algorithm is not supported by this MHD build.\n"));
3282#endif /* HAVE_MESSAGES */
3283 return MHD_DAUTH_WRONG_ALGO;
3284 }
3285#endif /* ! MHD_MD5_SUPPORT */
3286#ifndef MHD_SHA256_SUPPORT
3287 if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA256))
3288 {
3289#ifdef HAVE_MESSAGES
3290 MHD_DLOG (connection->daemon,
3291 _ ("The SHA-256 algorithm is not supported by "
3292 "this MHD build.\n"));
3293#endif /* HAVE_MESSAGES */
3294 return MHD_DAUTH_WRONG_ALGO;
3295 }
3296#endif /* ! MHD_SHA256_SUPPORT */
3297#ifndef MHD_SHA512_256_SUPPORT
3298 if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA512_256))
3299 {
3300#ifdef HAVE_MESSAGES
3301 MHD_DLOG (connection->daemon,
3302 _ ("The SHA-512/256 algorithm is not supported by "
3303 "this MHD build.\n"));
3304#endif /* HAVE_MESSAGES */
3305 return MHD_DAUTH_WRONG_ALGO;
3306 }
3307#endif /* ! MHD_SHA512_256_SUPPORT */
3308
3309 if (digest_get_hash_size ((enum MHD_DigestAuthAlgo3) malgo3) !=
3310 userdigest_size)
3311 MHD_PANIC (_ ("Wrong 'userdigest_size' value, does not match 'malgo3', "
3312 "API violation"));
3313
3314 return digest_auth_check_all (connection,
3315 realm,
3316 username,
3317 NULL,
3318 (const uint8_t *) userdigest,
3319 nonce_timeout,
3320 max_nc,
3321 mqop,
3322 malgo3);
3323}
3324
3325
3342_MHD_EXTERN int
3344 const char *realm,
3345 const char *username,
3346 const char *password,
3347 unsigned int nonce_timeout,
3348 enum MHD_DigestAuthAlgorithm algo)
3349{
3350 enum MHD_DigestAuthResult res;
3351 enum MHD_DigestAuthMultiAlgo3 malgo3;
3352
3353 if (MHD_DIGEST_ALG_AUTO == algo)
3355 else if (MHD_DIGEST_ALG_MD5 == algo)
3357 else if (MHD_DIGEST_ALG_SHA256 == algo)
3359 else
3360 MHD_PANIC (_ ("Wrong 'algo' value, API violation"));
3361
3362 res = MHD_digest_auth_check3 (connection,
3363 realm,
3364 username,
3365 password,
3366 nonce_timeout,
3368 malgo3);
3369 if (MHD_DAUTH_OK == res)
3370 return MHD_YES;
3371 else if ((MHD_DAUTH_NONCE_STALE == res) || (MHD_DAUTH_NONCE_WRONG == res) ||
3373 return MHD_INVALID_NONCE;
3374 return MHD_NO;
3375
3376}
3377
3378
3398_MHD_EXTERN int
3399MHD_digest_auth_check_digest2 (struct MHD_Connection *connection,
3400 const char *realm,
3401 const char *username,
3402 const uint8_t *digest,
3403 size_t digest_size,
3404 unsigned int nonce_timeout,
3405 enum MHD_DigestAuthAlgorithm algo)
3406{
3407 enum MHD_DigestAuthResult res;
3408 enum MHD_DigestAuthMultiAlgo3 malgo3;
3409
3410 if (MHD_DIGEST_ALG_AUTO == algo)
3412 else if (MHD_DIGEST_ALG_MD5 == algo)
3414 else if (MHD_DIGEST_ALG_SHA256 == algo)
3416 else
3417 MHD_PANIC (_ ("Wrong 'algo' value, API violation"));
3418
3419 res = MHD_digest_auth_check_digest3 (connection,
3420 realm,
3421 username,
3422 digest,
3423 digest_size,
3424 nonce_timeout,
3426 malgo3);
3427 if (MHD_DAUTH_OK == res)
3428 return MHD_YES;
3429 else if ((MHD_DAUTH_NONCE_STALE == res) || (MHD_DAUTH_NONCE_WRONG == res) ||
3431 return MHD_INVALID_NONCE;
3432 return MHD_NO;
3433}
3434
3435
3455_MHD_EXTERN int
3456MHD_digest_auth_check_digest (struct MHD_Connection *connection,
3457 const char *realm,
3458 const char *username,
3459 const uint8_t digest[MHD_MD5_DIGEST_SIZE],
3460 unsigned int nonce_timeout)
3461{
3462 return MHD_digest_auth_check_digest2 (connection,
3463 realm,
3464 username,
3465 digest,
3467 nonce_timeout,
3469}
3470
3471
3521static enum MHD_Result
3523 const char *realm,
3524 const char *opaque,
3525 const char *domain,
3526 struct MHD_Response *response,
3527 int signal_stale,
3528 enum MHD_DigestAuthMultiQOP mqop,
3529 enum MHD_DigestAuthMultiAlgo3 malgo3,
3530 int userhash_support,
3531 int prefer_utf8,
3532 char **buf_ptr,
3533 struct DigestAlgorithm *da)
3534{
3535 static const char prefix_realm[] = "realm=\"";
3536 static const char prefix_qop[] = "qop=\"";
3537 static const char prefix_algo[] = "algorithm=";
3538 static const char prefix_nonce[] = "nonce=\"";
3539 static const char prefix_opaque[] = "opaque=\"";
3540 static const char prefix_domain[] = "domain=\"";
3541 static const char str_charset[] = "charset=UTF-8";
3542 static const char str_userhash[] = "userhash=true";
3543 static const char str_stale[] = "stale=true";
3544 enum MHD_DigestAuthAlgo3 s_algo;
3545 size_t realm_len;
3546 size_t opaque_len;
3547 size_t domain_len;
3548 size_t buf_size;
3549 char *buf;
3550 size_t p; /* The position in the buffer */
3551 char *hdr_name;
3552
3553 if ((0 == (((unsigned int) malgo3) & MHD_DIGEST_AUTH_ALGO3_NON_SESSION)) ||
3554 (0 != (((unsigned int) malgo3) & MHD_DIGEST_AUTH_ALGO3_SESSION)))
3555 {
3556#ifdef HAVE_MESSAGES
3557 MHD_DLOG (connection->daemon,
3558 _ ("Only non-'session' algorithms are supported.\n"));
3559#endif /* HAVE_MESSAGES */
3560 return MHD_NO;
3561 }
3562 malgo3 =
3564 (malgo3
3566#ifdef MHD_MD5_SUPPORT
3567 if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_MD5))
3569 else
3570#endif /* MHD_MD5_SUPPORT */
3571#ifdef MHD_SHA256_SUPPORT
3572 if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA256))
3574 else
3575#endif /* MHD_SHA256_SUPPORT */
3576#ifdef MHD_SHA512_256_SUPPORT
3577 if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA512_256))
3579 else
3580#endif /* MHD_SHA512_256_SUPPORT */
3581 {
3582 if (0 == (((unsigned int) malgo3)
3585 MHD_PANIC (_ ("Wrong 'malgo3' value, API violation"));
3586 else
3587 {
3588#ifdef HAVE_MESSAGES
3589 MHD_DLOG (connection->daemon,
3590 _ ("No requested algorithm is supported by this MHD build.\n"));
3591#endif /* HAVE_MESSAGES */
3592 }
3593 return MHD_NO;
3594 }
3595
3597 MHD_PANIC (_ ("Wrong 'mqop' value, API violation"));
3598
3599 mqop = (enum MHD_DigestAuthMultiQOP)
3600 (mqop
3602
3603 if (! digest_init_one_time (da, get_base_digest_algo (s_algo)))
3604 MHD_PANIC (_ ("Wrong 'algo' value, API violation"));
3605
3607 {
3608#ifdef HAVE_MESSAGES
3609 if ((0 != userhash_support) || (0 != prefer_utf8))
3610 MHD_DLOG (connection->daemon,
3611 _ ("The 'userhash' and 'charset' ('prefer_utf8') parameters " \
3612 "are not compatible with RFC2069 and ignored.\n"));
3613 if (0 == (((unsigned int) s_algo) & MHD_DIGEST_BASE_ALGO_MD5))
3614 MHD_DLOG (connection->daemon,
3615 _ ("RFC2069 with SHA-256 or SHA-512/256 algorithm is " \
3616 "non-standard extension.\n"));
3617#endif
3618 userhash_support = 0;
3619 prefer_utf8 = 0;
3620 }
3621
3622 if (0 == MHD_get_master (connection->daemon)->nonce_nc_size)
3623 {
3624#ifdef HAVE_MESSAGES
3625 MHD_DLOG (connection->daemon,
3626 _ ("The nonce array size is zero.\n"));
3627#endif /* HAVE_MESSAGES */
3628 return MHD_NO;
3629 }
3630
3631 /* Calculate required size */
3632 buf_size = 0;
3633 /* 'Digest ' */
3634 buf_size += MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE) + 1; /* 1 for ' ' */
3635 buf_size += MHD_STATICSTR_LEN_ (prefix_realm) + 3; /* 3 for '", ' */
3636 /* 'realm="xxxx", ' */
3637 realm_len = strlen (realm);
3638 if (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < realm_len)
3639 {
3640#ifdef HAVE_MESSAGES
3641 MHD_DLOG (connection->daemon,
3642 _ ("The 'realm' is too large.\n"));
3643#endif /* HAVE_MESSAGES */
3644 return MHD_NO;
3645 }
3646 if ((NULL != memchr (realm, '\r', realm_len)) ||
3647 (NULL != memchr (realm, '\n', realm_len)))
3648 return MHD_NO;
3649
3650 buf_size += realm_len * 2; /* Quoting may double the size */
3651 /* 'qop="xxxx", ' */
3653 {
3654 buf_size += MHD_STATICSTR_LEN_ (prefix_qop) + 3; /* 3 for '", ' */
3655 buf_size += MHD_STATICSTR_LEN_ (MHD_TOKEN_AUTH_);
3656 }
3657 /* 'algorithm="xxxx", ' */
3658 if (((MHD_DIGEST_AUTH_MULT_QOP_NONE) != mqop) ||
3659 (0 == (((unsigned int) s_algo) & MHD_DIGEST_BASE_ALGO_MD5)))
3660 {
3661 buf_size += MHD_STATICSTR_LEN_ (prefix_algo) + 2; /* 2 for ', ' */
3662#ifdef MHD_MD5_SUPPORT
3663 if (MHD_DIGEST_AUTH_ALGO3_MD5 == s_algo)
3664 buf_size += MHD_STATICSTR_LEN_ (_MHD_MD5_TOKEN);
3665 else
3666#endif /* MHD_MD5_SUPPORT */
3667#ifdef MHD_SHA256_SUPPORT
3668 if (MHD_DIGEST_AUTH_ALGO3_SHA256 == s_algo)
3670 else
3671#endif /* MHD_SHA256_SUPPORT */
3672#ifdef MHD_SHA512_256_SUPPORT
3675 else
3676#endif /* MHD_SHA512_256_SUPPORT */
3677 mhd_assert (0);
3678 }
3679 /* 'nonce="xxxx", ' */
3680 buf_size += MHD_STATICSTR_LEN_ (prefix_nonce) + 3; /* 3 for '", ' */
3681 buf_size += NONCE_STD_LEN (digest_get_size (da)); /* Escaping not needed */
3682 /* 'opaque="xxxx", ' */
3683 if (NULL != opaque)
3684 {
3685 buf_size += MHD_STATICSTR_LEN_ (prefix_opaque) + 3; /* 3 for '", ' */
3686 opaque_len = strlen (opaque);
3687 if ((NULL != memchr (opaque, '\r', opaque_len)) ||
3688 (NULL != memchr (opaque, '\n', opaque_len)))
3689 return MHD_NO;
3690
3691 buf_size += opaque_len * 2; /* Quoting may double the size */
3692 }
3693 else
3694 opaque_len = 0;
3695 /* 'domain="xxxx", ' */
3696 if (NULL != domain)
3697 {
3698 buf_size += MHD_STATICSTR_LEN_ (prefix_domain) + 3; /* 3 for '", ' */
3699 domain_len = strlen (domain);
3700 if ((NULL != memchr (domain, '\r', domain_len)) ||
3701 (NULL != memchr (domain, '\n', domain_len)))
3702 return MHD_NO;
3703
3704 buf_size += domain_len * 2; /* Quoting may double the size */
3705 }
3706 else
3707 domain_len = 0;
3708 /* 'charset=UTF-8' */
3709 if (MHD_NO != prefer_utf8)
3710 buf_size += MHD_STATICSTR_LEN_ (str_charset) + 2; /* 2 for ', ' */
3711 /* 'userhash=true' */
3712 if (MHD_NO != userhash_support)
3713 buf_size += MHD_STATICSTR_LEN_ (str_userhash) + 2; /* 2 for ', ' */
3714 /* 'stale=true' */
3715 if (MHD_NO != signal_stale)
3716 buf_size += MHD_STATICSTR_LEN_ (str_stale) + 2; /* 2 for ', ' */
3717
3718 /* The calculated length is for string ended with ", ". One character will
3719 * be used for zero-termination, the last one will not be used. */
3720
3721 /* Allocate the buffer */
3722 buf = malloc (buf_size);
3723 if (NULL == buf)
3724 return MHD_NO;
3725 *buf_ptr = buf;
3726
3727 /* Build the challenge string */
3728 p = 0;
3729 /* 'Digest: ' */
3730 memcpy (buf + p, _MHD_AUTH_DIGEST_BASE,
3733 buf[p++] = ' ';
3734 /* 'realm="xxxx", ' */
3735 memcpy (buf + p, prefix_realm,
3736 MHD_STATICSTR_LEN_ (prefix_realm));
3737 p += MHD_STATICSTR_LEN_ (prefix_realm);
3738 mhd_assert ((buf_size - p) >= (realm_len * 2));
3739 if (1)
3740 {
3741 size_t quoted_size;
3742 quoted_size = MHD_str_quote (realm, realm_len, buf + p, buf_size - p);
3743 if (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < quoted_size)
3744 {
3745#ifdef HAVE_MESSAGES
3746 MHD_DLOG (connection->daemon,
3747 _ ("The 'realm' is too large after 'quoting'.\n"));
3748#endif /* HAVE_MESSAGES */
3749 return MHD_NO;
3750 }
3751 p += quoted_size;
3752 }
3753 buf[p++] = '\"';
3754 buf[p++] = ',';
3755 buf[p++] = ' ';
3756 /* 'qop="xxxx", ' */
3758 {
3759 memcpy (buf + p, prefix_qop,
3760 MHD_STATICSTR_LEN_ (prefix_qop));
3761 p += MHD_STATICSTR_LEN_ (prefix_qop);
3762 memcpy (buf + p, MHD_TOKEN_AUTH_,
3765 buf[p++] = '\"';
3766 buf[p++] = ',';
3767 buf[p++] = ' ';
3768 }
3769 /* 'algorithm="xxxx", ' */
3770 if (((MHD_DIGEST_AUTH_MULT_QOP_NONE) != mqop) ||
3771 (0 == (((unsigned int) s_algo) & MHD_DIGEST_BASE_ALGO_MD5)))
3772 {
3773 memcpy (buf + p, prefix_algo,
3774 MHD_STATICSTR_LEN_ (prefix_algo));
3775 p += MHD_STATICSTR_LEN_ (prefix_algo);
3776#ifdef MHD_MD5_SUPPORT
3777 if (MHD_DIGEST_AUTH_ALGO3_MD5 == s_algo)
3778 {
3779 memcpy (buf + p, _MHD_MD5_TOKEN,
3782 }
3783 else
3784#endif /* MHD_MD5_SUPPORT */
3785#ifdef MHD_SHA256_SUPPORT
3786 if (MHD_DIGEST_AUTH_ALGO3_SHA256 == s_algo)
3787 {
3788 memcpy (buf + p, _MHD_SHA256_TOKEN,
3791 }
3792 else
3793#endif /* MHD_SHA256_SUPPORT */
3794#ifdef MHD_SHA512_256_SUPPORT
3796 {
3797 memcpy (buf + p, _MHD_SHA512_256_TOKEN,
3800 }
3801 else
3802#endif /* MHD_SHA512_256_SUPPORT */
3803 mhd_assert (0);
3804 buf[p++] = ',';
3805 buf[p++] = ' ';
3806 }
3807 /* 'nonce="xxxx", ' */
3808 memcpy (buf + p, prefix_nonce,
3809 MHD_STATICSTR_LEN_ (prefix_nonce));
3810 p += MHD_STATICSTR_LEN_ (prefix_nonce);
3811 mhd_assert ((buf_size - p) >= (NONCE_STD_LEN (digest_get_size (da))));
3812 if (! calculate_add_nonce_with_retry (connection, realm, da, buf + p))
3813 {
3814#ifdef MHD_DIGEST_HAS_EXT_ERROR
3815 if (digest_ext_error (da))
3816 {
3817#ifdef HAVE_MESSAGES
3818 MHD_DLOG (connection->daemon,
3819 _ ("TLS library reported hash calculation error, nonce could "
3820 "not be generated.\n"));
3821#endif /* HAVE_MESSAGES */
3822 return MHD_NO;
3823 }
3824#endif /* MHD_DIGEST_HAS_EXT_ERROR */
3825#ifdef HAVE_MESSAGES
3826 MHD_DLOG (connection->daemon,
3827 _ ("Could not register nonce. Client's requests with this "
3828 "nonce will be always 'stale'. Probably clients' requests "
3829 "are too intensive.\n"));
3830#endif /* HAVE_MESSAGES */
3831 (void) 0; /* Mute compiler warning for builds without messages */
3832 }
3833 p += NONCE_STD_LEN (digest_get_size (da));
3834 buf[p++] = '\"';
3835 buf[p++] = ',';
3836 buf[p++] = ' ';
3837 /* 'opaque="xxxx", ' */
3838 if (NULL != opaque)
3839 {
3840 memcpy (buf + p, prefix_opaque,
3841 MHD_STATICSTR_LEN_ (prefix_opaque));
3842 p += MHD_STATICSTR_LEN_ (prefix_opaque);
3843 mhd_assert ((buf_size - p) >= (opaque_len * 2));
3844 p += MHD_str_quote (opaque, opaque_len, buf + p, buf_size - p);
3845 buf[p++] = '\"';
3846 buf[p++] = ',';
3847 buf[p++] = ' ';
3848 }
3849 /* 'domain="xxxx", ' */
3850 if (NULL != domain)
3851 {
3852 memcpy (buf + p, prefix_domain,
3853 MHD_STATICSTR_LEN_ (prefix_domain));
3854 p += MHD_STATICSTR_LEN_ (prefix_domain);
3855 mhd_assert ((buf_size - p) >= (domain_len * 2));
3856 p += MHD_str_quote (domain, domain_len, buf + p, buf_size - p);
3857 buf[p++] = '\"';
3858 buf[p++] = ',';
3859 buf[p++] = ' ';
3860 }
3861 /* 'charset=UTF-8' */
3862 if (MHD_NO != prefer_utf8)
3863 {
3864 memcpy (buf + p, str_charset,
3865 MHD_STATICSTR_LEN_ (str_charset));
3866 p += MHD_STATICSTR_LEN_ (str_charset);
3867 buf[p++] = ',';
3868 buf[p++] = ' ';
3869 }
3870 /* 'userhash=true' */
3871 if (MHD_NO != userhash_support)
3872 {
3873 memcpy (buf + p, str_userhash,
3874 MHD_STATICSTR_LEN_ (str_userhash));
3875 p += MHD_STATICSTR_LEN_ (str_userhash);
3876 buf[p++] = ',';
3877 buf[p++] = ' ';
3878 }
3879 /* 'stale=true' */
3880 if (MHD_NO != signal_stale)
3881 {
3882 memcpy (buf + p, str_stale,
3883 MHD_STATICSTR_LEN_ (str_stale));
3884 p += MHD_STATICSTR_LEN_ (str_stale);
3885 buf[p++] = ',';
3886 buf[p++] = ' ';
3887 }
3888 mhd_assert (buf_size >= p);
3889 /* The built string ends with ", ". Replace comma with zero-termination. */
3890 --p;
3891 buf[--p] = 0;
3892
3893 hdr_name = malloc (MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_WWW_AUTHENTICATE) + 1);
3894 if (NULL != hdr_name)
3895 {
3896 memcpy (hdr_name, MHD_HTTP_HEADER_WWW_AUTHENTICATE,
3899 hdr_name,
3902 buf, p))
3903 {
3904 *buf_ptr = NULL; /* The buffer will be free()ed when the response is destroyed */
3905 return MHD_queue_response (connection, MHD_HTTP_UNAUTHORIZED, response);
3906 }
3907#ifdef HAVE_MESSAGES
3908 else
3909 {
3910 MHD_DLOG (connection->daemon,
3911 _ ("Failed to add Digest auth header.\n"));
3912 }
3913#endif /* HAVE_MESSAGES */
3914 free (hdr_name);
3915 }
3916 return MHD_NO;
3917}
3918
3919
3984 const char *realm,
3985 const char *opaque,
3986 const char *domain,
3987 struct MHD_Response *response,
3988 int signal_stale,
3989 enum MHD_DigestAuthMultiQOP mqop,
3990 enum MHD_DigestAuthMultiAlgo3 malgo3,
3991 int userhash_support,
3992 int prefer_utf8)
3993{
3994 struct DigestAlgorithm da;
3995 char *buf_ptr;
3996 enum MHD_Result ret;
3997
3998 buf_ptr = NULL;
3999 digest_setup_zero (&da);
4000 ret = queue_auth_required_response3_inner (connection,
4001 realm,
4002 opaque,
4003 domain,
4004 response,
4005 signal_stale,
4006 mqop,
4007 malgo3,
4008 userhash_support,
4009 prefer_utf8,
4010 &buf_ptr,
4011 &da);
4012 digest_deinit (&da);
4013 if (NULL != buf_ptr)
4014 free (buf_ptr);
4015 return ret;
4016}
4017
4018
4037 const char *realm,
4038 const char *opaque,
4039 struct MHD_Response *response,
4040 int signal_stale,
4041 enum MHD_DigestAuthAlgorithm algo)
4042{
4043 enum MHD_DigestAuthMultiAlgo3 algo3;
4044
4045 if (MHD_DIGEST_ALG_MD5 == algo)
4047 else if (MHD_DIGEST_ALG_SHA256 == algo)
4049 else if (MHD_DIGEST_ALG_AUTO == algo)
4051 else
4052 MHD_PANIC (_ ("Wrong algo value.\n")); /* API violation! */
4053
4054 return MHD_queue_auth_required_response3 (connection, realm, opaque,
4055 NULL, response, signal_stale,
4057 algo3,
4058 0, 0);
4059}
4060
4061
4081 const char *realm,
4082 const char *opaque,
4083 struct MHD_Response *response,
4084 int signal_stale)
4085{
4086 return MHD_queue_auth_fail_response2 (connection,
4087 realm,
4088 opaque,
4089 response,
4090 signal_stale,
4092}
4093
4094
4095/* 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)
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)
static bool check_uri_match(struct MHD_Connection *connection, char *uri, size_t uri_len)
#define TIMESTAMP_CHARS_LEN
Definition digestauth.c:84
static enum MHD_GetRqNCResult get_rq_nc(const struct MHD_RqDAuth *params, uint32_t *nc)
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)
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
_MHD_static_inline void digest_reset(struct DigestAlgorithm *da)
Definition digestauth.c:638
#define TIMESTAMP_BIN_SIZE
Definition digestauth.c:71
MHD_GetRqNCResult
@ MHD_GET_RQ_NC_NONE
@ MHD_GET_RQ_NC_BROKEN
@ MHD_GET_RQ_NC_VALID
@ MHD_GET_RQ_NC_TOO_LONG
@ MHD_GET_RQ_NC_TOO_LARGE
static size_t get_rq_param_unquoted_copy_z(const struct MHD_RqDAuthParam *param, char *buf)
static ssize_t get_rq_extended_uname_copy_z(const char *uname_ext, size_t uname_ext_len, char *buf, size_t buf_size)
_MHD_GetUnqResult
@ _MHD_UNQ_TOO_LARGE
@ _MHD_UNQ_OUT_OF_MEM
@ _MHD_UNQ_OK
#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)
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)
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)
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)
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)
_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)
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
static char * get_buffer_for_size(char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE], char **ptmp2, size_t *ptmp2_size, size_t required_size)
_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
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)
_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)
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)
#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)
#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)
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)
#define MHD_SHA512_256_DIGEST_SIZE
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)
_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)
_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)
_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)
_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)
_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)
_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)
_MHD_EXTERN struct MHD_DigestAuthInfo * MHD_digest_auth_get_request_info3(struct MHD_Connection *connection)
_MHD_EXTERN size_t MHD_digest_get_hash_size(enum MHD_DigestAuthAlgo3 algo3)
Definition digestauth.c:295
_MHD_EXTERN char * MHD_digest_auth_get_username(struct MHD_Connection *connection)
_MHD_EXTERN int MHD_digest_auth_check(struct MHD_Connection *connection, const char *realm, const char *username, const char *password, unsigned int nonce_timeout)
#define MHD_INVALID_NONCE
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)
#define MHD_SHA256_DIGEST_SIZE
_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)
_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)
_MHD_EXTERN struct MHD_DigestAuthUsernameInfo * MHD_digest_auth_get_username3(struct MHD_Connection *connection)
#define MHD_MD5_DIGEST_SIZE
#define MHD_HTTP_HEADER_WWW_AUTHENTICATE
Definition microhttpd.h:664
#define MHD_HTTP_UNAUTHORIZED
Definition microhttpd.h:393
_MHD_EXTERN enum MHD_Result MHD_queue_response(struct MHD_Connection *connection, unsigned int status_code, struct MHD_Response *response)
enum MHD_Result MHD_parse_arguments_(struct MHD_Connection *connection, enum MHD_ValueKind kind, char *args, MHD_ArgumentIterator_ cb, void *cls)
Definition internal.c:169
MHD internal shared structures.
#define MAX_DIGEST_NONCE_LENGTH
Definition internal.h:269
_MHD_static_inline struct MHD_Daemon * MHD_get_master(struct MHD_Daemon *const daemon)
Definition internal.h:2913
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
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 mhd_assert()
#define mhd_assert(ignore)
Definition mhd_assert.h:45
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)
void * MHD_calloc_(size_t nelem, size_t elsize)
Definition mhd_compat.c:98
Header for platform missing functions.
#define MHD_PANIC(msg)
Definition mhd_itc.h:45
limits values definitions
#define SSIZE_MAX
Definition mhd_limits.h:121
#define UINT64_MAX
Definition mhd_limits.h:93
#define UINT32_MAX
Definition mhd_limits.h:85
Header for platform-independent locks abstraction.
#define MHD_mutex_unlock_chk_(ignore)
Definition mhd_locks.h:198
#define MHD_mutex_lock_chk_(ignore)
Definition mhd_locks.h:196
Simple wrapper for selection of built-in/external MD5 implementation.
#define MHD_MD5_finish_reset(ctx, digest)
#define MHD_MD5_deinit(ignore)
#define Md5CtxWr
#define MHD_MD5_reset(ctx)
#define MHD_MD5_init_one_time(ctx)
#define NULL
uint64_t MHD_monotonic_msec_counter(void)
internal monotonic clock functions implementations
#define _(String)
Definition mhd_options.h:42
#define MHD_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE_
#define _MHD_EXTERN
Definition mhd_options.h:53
#define MHD_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE_
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)
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:1749
size_t MHD_bin_to_hex_z(const void *bin, size_t size, char *hex)
Definition mhd_str.c:1696
size_t MHD_strx_to_uint64_n_(const char *str, size_t maxlen, uint64_t *out_val)
Definition mhd_str.c:1415
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.
#define MHD_STATICSTR_LEN_(macro)
MHD_DigestAuthResult
@ MHD_DAUTH_NONCE_WRONG
@ MHD_DAUTH_RESPONSE_WRONG
@ MHD_DAUTH_WRONG_HEADER
@ MHD_DAUTH_NONCE_STALE
@ MHD_DAUTH_ERROR
@ MHD_DAUTH_WRONG_QOP
@ MHD_DAUTH_OK
@ MHD_DAUTH_NONCE_OTHER_COND
@ MHD_DAUTH_WRONG_REALM
@ MHD_DAUTH_WRONG_URI
@ MHD_DAUTH_WRONG_ALGO
@ MHD_DAUTH_TOO_LARGE
@ MHD_DAUTH_WRONG_USERNAME
MHD_Result
Definition microhttpd.h:163
@ MHD_YES
Definition microhttpd.h:172
@ MHD_NO
Definition microhttpd.h:167
#define MHD_DIGEST_AUTH_ALGO3_SESSION
#define MHD_DIGEST_AUTH_ALGO3_NON_SESSION
MHD_DigestAuthMultiQOP
@ MHD_DIGEST_AUTH_MULT_QOP_AUTH_INT
@ MHD_DIGEST_AUTH_MULT_QOP_AUTH
@ MHD_DIGEST_AUTH_MULT_QOP_NONE
MHD_DigestBaseAlgo
@ MHD_DIGEST_BASE_ALGO_INVALID
@ MHD_DIGEST_BASE_ALGO_SHA256
@ MHD_DIGEST_BASE_ALGO_SHA512_256
@ MHD_DIGEST_BASE_ALGO_MD5
MHD_DigestAuthAlgo3
@ MHD_DIGEST_AUTH_ALGO3_MD5
@ MHD_DIGEST_AUTH_ALGO3_SHA256
@ MHD_DIGEST_AUTH_ALGO3_SHA512_256
MHD_DigestAuthQOP
@ MHD_DIGEST_AUTH_QOP_NONE
@ MHD_DIGEST_AUTH_QOP_AUTH_INT
void * data
MHD_DigestAuthUsernameType
@ MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD
@ MHD_DIGEST_AUTH_UNAME_TYPE_MISSING
@ MHD_DIGEST_AUTH_UNAME_TYPE_INVALID
@ MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED
@ MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH
MHD_ValueKind
@ MHD_HEADER_KIND
@ MHD_GET_ARGUMENT_KIND
#define MHD_DIGEST_AUTH_INVALID_NC_VALUE
MHD_DigestAuthMultiAlgo3
@ MHD_DIGEST_AUTH_MULT_ALGO3_SHA256
@ MHD_DIGEST_AUTH_MULT_ALGO3_ANY_NON_SESSION
@ MHD_DIGEST_AUTH_MULT_ALGO3_MD5
MHD_DigestAuthAlgorithm
@ MHD_DIGEST_ALG_AUTO
@ MHD_DIGEST_ALG_MD5
@ MHD_DIGEST_ALG_SHA256
@ MHD_DAUTH_BIND_NONCE_NONE
@ MHD_DAUTH_BIND_NONCE_URI
@ MHD_DAUTH_BIND_NONCE_URI_PARAMS
@ MHD_DAUTH_BIND_NONCE_REALM
@ MHD_DAUTH_BIND_NONCE_CLIENT_IP
platform-specific includes for libmicrohttpd
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
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:1469
struct MHD_Request rq
Definition internal.h:1371
struct MHD_Daemon * daemon
Definition internal.h:1366
struct sockaddr_storage * addr
Definition internal.h:1421
void * unescape_callback_cls
Definition internal.h:2078
UnescapeCallback unescape_callback
Definition internal.h:2073
enum MHD_DigestAuthQOP qop
enum MHD_DigestAuthUsernameType uname_type
enum MHD_DigestAuthAlgo3 algo3
enum MHD_DigestAuthAlgo3 algo3
enum MHD_DigestAuthUsernameType uname_type
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_Req_Header * headers_received
Definition internal.h:1117
const char * url
Definition internal.h:1096
size_t url_len
Definition internal.h:1101
const char * method
Definition internal.h:1085
enum MHD_HTTP_Method http_mthd
Definition internal.h:1090
const char * str