GNU libmicrohttpd 1.0.0
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
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
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
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
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
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
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
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 {
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
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
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
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
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
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
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
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
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
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
751#endif /* MHD_MD5_SUPPORT */
754#endif /* MHD_SHA256_SUPPORT */
755 )
756 return false;
757
761 ptimestamp))
762 return false;
763 return true;
764}
765
766
768
776static uint32_t
778 size_t data_size)
779{
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
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,
836 uint64_t nc)
837{
838 struct MHD_Daemon *daemon = MHD_get_master (connection->daemon);
839 struct MHD_NonceNc *nn;
842
843 mhd_assert (0 != noncelen);
844 mhd_assert (0 != nc);
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 {
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 */
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
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 &&
976 else
978 }
979
981}
982
983
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
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
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
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
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 */
1088 return (ssize_t) w;
1089}
1090
1091
1101static size_t
1103 enum MHD_DigestAuthUsernameType uname_type,
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 =
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 =
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 }
1180 return buf_used;
1181}
1182
1183
1195
1196
1203static enum MHD_GetRqNCResult
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;
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
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;
1275 size_t unif_buf_used;
1277
1278 params = MHD_get_rq_dauth_params_ (connection);
1279 if (NULL == params)
1280 return NULL;
1281
1282 unif_buf_size = 0;
1283
1285
1287
1288 if (NULL != params->opaque.value.str)
1289 unif_buf_size += params->opaque.value.len + 1; /* Add one for zero-termination */
1290 if (NULL != params->realm.value.str)
1291 unif_buf_size += params->realm.value.len + 1; /* Add one for zero-termination */
1292 info = (struct MHD_DigestAuthInfo *)
1293 MHD_calloc_ (1, (sizeof(struct MHD_DigestAuthInfo)) + unif_buf_size);
1294 unif_buf_ptr = (uint8_t *) (info + 1);
1295 unif_buf_used = 0;
1296
1297 info->algo3 = params->algo3;
1298
1301 unif_buf_used +=
1306 else
1307 info->uname_type = uname_type;
1308
1309 if (NULL != params->opaque.value.str)
1310 {
1311 info->opaque = (char *) (unif_buf_ptr + unif_buf_used);
1312 info->opaque_len = get_rq_param_unquoted_copy_z (&params->opaque,
1313 info->opaque);
1314 unif_buf_used += info->opaque_len + 1;
1315 }
1316 if (NULL != params->realm.value.str)
1317 {
1318 info->realm = (char *) (unif_buf_ptr + unif_buf_used);
1319 info->realm_len = get_rq_param_unquoted_copy_z (&params->realm,
1320 info->realm);
1321 unif_buf_used += info->realm_len + 1;
1322 }
1323
1325
1326 info->qop = params->qop;
1327
1328 if (NULL != params->cnonce.value.str)
1329 info->cnonce_len = params->cnonce.value.len;
1330 else
1331 info->cnonce_len = 0;
1332
1333 nc_res = get_rq_nc (params, &info->nc);
1336
1337 return info;
1338}
1339
1340
1357{
1358 const struct MHD_RqDAuth *params;
1361 size_t unif_buf_size;
1363 size_t unif_buf_used;
1364
1365 params = MHD_get_rq_dauth_params_ (connection);
1366 if (NULL == params)
1367 return NULL;
1368
1372 return NULL;
1373
1375
1377 MHD_calloc_ (1, (sizeof(struct MHD_DigestAuthUsernameInfo))
1378 + unif_buf_size);
1379 unif_buf_ptr = (uint8_t *) (uname_info + 1);
1383 (void) unif_buf_used; /* Mute compiler warning on non-debug builds */
1385
1387 {
1388 free (uname_info);
1389 return NULL;
1390 }
1391 mhd_assert (uname_type == uname_info->uname_type);
1392 uname_info->algo3 = params->algo3;
1393
1394 return uname_info;
1395}
1396
1397
1413_MHD_EXTERN char *
1415{
1416 const struct MHD_RqDAuth *params;
1417 char *username;
1418 size_t buf_size;
1419 enum MHD_DigestAuthUsernameType uname_type;
1420
1421 params = MHD_get_rq_dauth_params_ (connection);
1422 if (NULL == params)
1423 return NULL;
1424
1425 uname_type = get_rq_uname_type (params);
1426
1427 if ( (MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD != uname_type) &&
1428 (MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED != uname_type) )
1429 return NULL;
1430
1431 buf_size = get_rq_unames_size (params, uname_type);
1432
1433 mhd_assert (0 != buf_size);
1434
1435 username = (char *) MHD_calloc_ (1, buf_size);
1436 if (NULL == username)
1437 return NULL;
1438
1439 if (1)
1440 {
1442 size_t used;
1443
1444 memset (&uname_strct, 0, sizeof(uname_strct));
1445
1448 if (uname_type != uname_strct.uname_type)
1449 { /* Broken encoding for extended notation */
1450 free (username);
1451 return NULL;
1452 }
1453 (void) used; /* Mute compiler warning for non-debug builds */
1455 }
1456
1457 return username;
1458}
1459
1460
1484static void
1487 const char *method,
1488 const char *rnd,
1489 size_t rnd_size,
1490 const struct sockaddr_storage *saddr,
1491 size_t saddr_size,
1492 const char *uri,
1493 size_t uri_len,
1494 const struct MHD_HTTP_Req_Header *first_header,
1495 const char *realm,
1496 size_t realm_len,
1497 unsigned int bind_options,
1498 struct DigestAlgorithm *da,
1499 char *nonce)
1500{
1501 mhd_assert (! da->hashing);
1502 if (1)
1503 {
1504 /* Add the timestamp to the hash calculation */
1506 /* If the nonce_time is milliseconds, then the same 48 bit value will repeat
1507 * every 8 919 years, which is more than enough to mitigate a replay attack */
1508#if TIMESTAMP_BIN_SIZE != 6
1509#error The code needs to be updated here
1510#endif
1511 timestamp[0] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 0)));
1512 timestamp[1] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 1)));
1513 timestamp[2] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 2)));
1514 timestamp[3] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 3)));
1515 timestamp[4] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 4)));
1516 timestamp[5] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 5)));
1518 sizeof (timestamp),
1519 nonce + digest_get_size (da) * 2);
1521 timestamp,
1522 sizeof (timestamp));
1523 }
1524 if (rnd_size > 0)
1525 {
1526 /* Add the unique random value to the hash calculation */
1529 rnd,
1530 rnd_size);
1531 }
1533 (0 != saddr_size) )
1534 {
1535 /* Add full client address including source port to make unique nonces
1536 * for requests received exactly at the same time */
1539 saddr,
1540 saddr_size);
1541 }
1543 (0 != saddr_size) )
1544 {
1545 /* Add the client's IP address to the hash calculation */
1547 if (AF_INET == saddr->ss_family)
1549 &((const struct sockaddr_in *) saddr)->sin_addr,
1550 sizeof(((const struct sockaddr_in *) saddr)->sin_addr));
1551#ifdef HAVE_INET6
1552 else if (AF_INET6 == saddr->ss_family)
1554 &((const struct sockaddr_in6 *) saddr)->sin6_addr,
1555 sizeof(((const struct sockaddr_in6 *) saddr)->sin6_addr));
1556#endif /* HAVE_INET6 */
1557 }
1560 {
1561 /* Add the request method to the hash calculation */
1564 {
1568 else /* Treat HEAD method in the same way as GET method */
1572 sizeof(mthd_for_hash));
1573 }
1574 else
1575 digest_update_str (da, method);
1576 }
1577
1579 {
1580 /* Add the request URI to the hash calculation */
1582
1584 uri,
1585 uri_len);
1586 }
1588 {
1589 /* Add the request URI parameters to the hash calculation */
1590 const struct MHD_HTTP_Req_Header *h;
1591
1593 for (h = first_header; NULL != h; h = h->next)
1594 {
1595 if (MHD_GET_ARGUMENT_KIND != h->kind)
1596 continue;
1597 digest_update (da, "\0", 2);
1598 if (0 != h->header_size)
1599 digest_update (da, h->header, h->header_size);
1600 digest_update (da, "", 1);
1601 if (0 != h->value_size)
1602 digest_update (da, h->value, h->value_size);
1603 }
1604 }
1607 {
1608 /* Add the realm to the hash calculation */
1611 realm,
1612 realm_len);
1613 }
1614 if (1)
1615 {
1620 nonce);
1621 }
1622}
1623
1624
1640static bool
1641is_slot_available (const struct MHD_NonceNc *const nn,
1642 const uint64_t now,
1643 const char *const new_nonce,
1644 size_t new_nonce_len)
1645{
1647 bool timestamp_valid;
1650 if (0 == nn->nonce[0])
1651 return true; /* The slot is empty */
1652
1653 if (0 == memcmp (nn->nonce, new_nonce, new_nonce_len))
1654 {
1655 /* The slot has the same nonce already. This nonce cannot be registered
1656 * again as it would just clear 'nc' usage history. */
1657 return false;
1658 }
1659
1660 if (0 != nn->nc)
1661 return true; /* Client already used the nonce in this slot at least
1662 one time, re-use the slot */
1663
1664 /* The nonce must be zero-terminated */
1665 mhd_assert (0 == nn->nonce[sizeof(nn->nonce) - 1]);
1666 if (0 != nn->nonce[sizeof(nn->nonce) - 1])
1667 return true; /* Wrong nonce format in the slot */
1668
1671 if (! timestamp_valid)
1672 return true; /* Invalid timestamp in nonce-nc, should not be possible */
1673
1674 if ((REUSE_TIMEOUT * 1000) < TRIM_TO_TIMESTAMP (now - timestamp))
1675 return true;
1676
1677 return false;
1678}
1679
1680
1696static bool
1697calculate_add_nonce (struct MHD_Connection *const connection,
1699 const char *realm,
1700 size_t realm_len,
1701 struct DigestAlgorithm *da,
1702 char *nonce)
1703{
1704 struct MHD_Daemon *const daemon = MHD_get_master (connection->daemon);
1705 struct MHD_NonceNc *nn;
1706 const size_t nonce_size = NONCE_STD_LEN (digest_get_size (da));
1707 bool ret;
1708
1709 mhd_assert (! da->hashing);
1711 mhd_assert (0 != nonce_size);
1712
1714 connection->rq.http_mthd,
1715 connection->rq.method,
1716 daemon->digest_auth_random,
1717 daemon->digest_auth_rand_size,
1718 connection->addr,
1719 (size_t) connection->addr_len,
1720 connection->rq.url,
1721 connection->rq.url_len,
1722 connection->rq.headers_received,
1723 realm,
1724 realm_len,
1725 daemon->dauth_bind_type,
1726 da,
1727 nonce);
1728
1729#ifdef MHD_DIGEST_HAS_EXT_ERROR
1730 if (digest_ext_error (da))
1731 return false;
1732#endif /* MHD_DIGEST_HAS_EXT_ERROR */
1733
1734 if (0 == daemon->nonce_nc_size)
1735 return false;
1736
1737 /* Sanity check for values */
1739
1740 nn = daemon->nnc + get_nonce_nc_idx (daemon->nonce_nc_size,
1741 nonce,
1742 nonce_size);
1743
1744 MHD_mutex_lock_chk_ (&daemon->nnc_lock);
1746 {
1747 memcpy (nn->nonce,
1748 nonce,
1749 nonce_size);
1750 nn->nonce[nonce_size] = 0; /* With terminating zero */
1751 nn->nc = 0;
1752 nn->nmask = 0;
1753 ret = true;
1754 }
1755 else
1756 ret = false;
1757 MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
1758
1759 return ret;
1760}
1761
1762
1764
1776static bool
1778 const char *realm,
1779 struct DigestAlgorithm *da,
1780 char *nonce)
1781{
1783 const size_t realm_len = strlen (realm);
1784 mhd_assert (! da->hashing);
1785
1786#ifdef HAVE_MESSAGES
1787 if (0 == MHD_get_master (connection->daemon)->digest_auth_rand_size)
1788 MHD_DLOG (connection->daemon,
1789 _ ("Random value was not initialised by " \
1790 "MHD_OPTION_DIGEST_AUTH_RANDOM or " \
1791 "MHD_OPTION_DIGEST_AUTH_RANDOM_COPY, generated nonces " \
1792 "are predictable.\n"));
1793#endif
1794
1795 if (! calculate_add_nonce (connection, timestamp1, realm, realm_len, da,
1796 nonce))
1797 {
1798 /* Either:
1799 * 1. The same nonce was already generated. If it will be used then one
1800 * of the clients will fail (as no initial 'nc' value could be given to
1801 * the client, the second client which will use 'nc=00000001' will fail).
1802 * 2. Another nonce uses the same slot, and this nonce never has been
1803 * used by the client and this nonce is still fresh enough.
1804 */
1805 const size_t digest_size = digest_get_size (da);
1806 char nonce2[NONCE_STD_LEN (MAX_DIGEST) + 1];
1808#ifdef MHD_DIGEST_HAS_EXT_ERROR
1809 if (digest_ext_error (da))
1810 return false; /* No need to re-try */
1811#endif /* MHD_DIGEST_HAS_EXT_ERROR */
1812 if (0 == MHD_get_master (connection->daemon)->nonce_nc_size)
1813 return false; /* No need to re-try */
1814
1816 if (timestamp1 == timestamp2)
1817 {
1818 /* The timestamps are equal, need to generate some arbitrary
1819 * difference for nonce. */
1820 /* As the number is needed only to differentiate clients, weak
1821 * pseudo-random generators could be used. Seeding is not needed. */
1825 uint8_t base4;
1826#ifdef HAVE_RANDOM
1827 base1 = ((uint64_t) random ()) ^ UINT64_C (0x54a5acff5be47e63);
1828 base4 = 0xb8;
1829#elif defined(HAVE_RAND)
1830 base1 = ((uint64_t) rand ()) ^ UINT64_C (0xc4bcf553b12f3965);
1831 base4 = 0x92;
1832#else
1833 /* Monotonic msec counter alone does not really help here as it is already
1834 known that this value is not unique. */
1835 base1 = ((uint64_t) (uintptr_t) nonce2) ^ UINT64_C (0xf2e1b21bc6c92655);
1836 base2 = ((uint32_t) (base1 >> 32)) ^ ((uint32_t) base1);
1837 base2 = _MHD_ROTR32 (base2, 4);
1838 base3 = ((uint16_t) (base2 >> 16)) ^ ((uint16_t) base2);
1839 base4 = ((uint8_t) (base3 >> 8)) ^ ((uint8_t) base3);
1841 ^ UINT64_C (0xccab93f72cf5b15);
1842#endif
1843 base2 = ((uint32_t) (base1 >> 32)) ^ ((uint32_t) base1);
1844 base2 = _MHD_ROTL32 (base2, (((base4 >> 4) ^ base4) % 32));
1845 base3 = ((uint16_t) (base2 >> 16)) ^ ((uint16_t) base2);
1846 base4 = ((uint8_t) (base3 >> 8)) ^ ((uint8_t) base3);
1847 /* Use up to 127 ms difference */
1849 if (timestamp1 == timestamp2)
1850 timestamp2 -= 2; /* Fallback value */
1851 }
1852 digest_reset (da);
1853 if (! calculate_add_nonce (connection, timestamp2, realm, realm_len, da,
1854 nonce2))
1855 {
1856 /* No free slot has been found. Re-tries are expensive, just use
1857 * the generated nonce. As it is not stored in nonce-nc map array,
1858 * the next request of the client will be recognized as valid, but 'stale'
1859 * so client should re-try automatically. */
1860 return false;
1861 }
1863 }
1864 return true;
1865}
1866
1867
1869
1887calc_userdigest (struct DigestAlgorithm *da,
1888 const char *username, const size_t username_len,
1889 const char *realm, const size_t realm_len,
1890 const char *password,
1892{
1893 mhd_assert (! da->hashing);
1894 digest_update (da, username, username_len);
1896 digest_update (da, realm, realm_len);
1898 digest_update_str (da, password);
1900}
1901
1902
1938 const char *username,
1939 const char *realm,
1940 const char *password,
1941 void *userdigest_bin,
1942 size_t bin_buf_size)
1943{
1944 struct DigestAlgorithm da;
1945 enum MHD_Result ret;
1947 return MHD_NO;
1948
1950 ret = MHD_NO;
1951 else
1952 {
1954 username,
1955 strlen (username),
1956 realm,
1957 strlen (realm),
1958 password,
1960 ret = MHD_YES;
1961
1962#ifdef MHD_DIGEST_HAS_EXT_ERROR
1963 if (digest_ext_error (&da))
1964 ret = MHD_NO;
1965#endif /* MHD_DIGEST_HAS_EXT_ERROR */
1966 }
1967 digest_deinit (&da);
1968
1969 return ret;
1970}
1971
1972
1987calc_userhash (struct DigestAlgorithm *da,
1988 const char *username, const size_t username_len,
1989 const char *realm, const size_t realm_len,
1991{
1992 mhd_assert (NULL != username);
1993 mhd_assert (! da->hashing);
1994 digest_update (da, username, username_len);
1996 digest_update (da, realm, realm_len);
1998}
1999
2000
2043 const char *username,
2044 const char *realm,
2045 void *userhash_bin,
2046 size_t bin_buf_size)
2047{
2048 struct DigestAlgorithm da;
2049 enum MHD_Result ret;
2050
2052 return MHD_NO;
2054 ret = MHD_NO;
2055 else
2056 {
2057 calc_userhash (&da,
2058 username,
2059 strlen (username),
2060 realm,
2061 strlen (realm),
2062 userhash_bin);
2063 ret = MHD_YES;
2064
2065#ifdef MHD_DIGEST_HAS_EXT_ERROR
2066 if (digest_ext_error (&da))
2067 ret = MHD_NO;
2068#endif /* MHD_DIGEST_HAS_EXT_ERROR */
2069 }
2070 digest_deinit (&da);
2071
2072 return ret;
2073}
2074
2075
2118 const char *username,
2119 const char *realm,
2120 char *userhash_hex,
2121 size_t hex_buf_size)
2122{
2123 uint8_t userhash_bin[MAX_DIGEST];
2124 size_t digest_size;
2125
2127 if (digest_size * 2 + 1 > hex_buf_size)
2128 return MHD_NO;
2129 if (MHD_NO == MHD_digest_auth_calc_userhash (algo3, username, realm,
2130 userhash_bin, MAX_DIGEST))
2131 return MHD_NO;
2132
2133 MHD_bin_to_hex_z (userhash_bin, digest_size, userhash_hex);
2134 return MHD_YES;
2135}
2136
2137
2138struct test_header_param
2139{
2140 struct MHD_Connection *connection;
2141 size_t num_headers;
2142};
2143
2157static enum MHD_Result
2158test_header (void *cls,
2159 const char *key,
2160 size_t key_size,
2161 const char *value,
2162 size_t value_size,
2163 enum MHD_ValueKind kind)
2164{
2165 struct test_header_param *const param = (struct test_header_param *) cls;
2166 struct MHD_Connection *connection = param->connection;
2167 struct MHD_HTTP_Req_Header *pos;
2168 size_t i;
2169
2170 param->num_headers++;
2171 i = 0;
2172 for (pos = connection->rq.headers_received; NULL != pos; pos = pos->next)
2173 {
2174 if (kind != pos->kind)
2175 continue;
2176 if (++i == param->num_headers)
2177 {
2178 if (key_size != pos->header_size)
2179 return MHD_NO;
2180 if (value_size != pos->value_size)
2181 return MHD_NO;
2182 if (0 != key_size)
2183 {
2184 mhd_assert (NULL != key);
2185 mhd_assert (NULL != pos->header);
2186 if (0 != memcmp (key,
2187 pos->header,
2188 key_size))
2189 return MHD_NO;
2190 }
2191 if (0 != value_size)
2192 {
2193 mhd_assert (NULL != value);
2194 mhd_assert (NULL != pos->value);
2195 if (0 != memcmp (value,
2196 pos->value,
2197 value_size))
2198 return MHD_NO;
2199 }
2200 return MHD_YES;
2201 }
2202 }
2203 return MHD_NO;
2204}
2205
2206
2218static bool
2220 char *args)
2221{
2222 struct MHD_HTTP_Req_Header *pos;
2223 enum MHD_Result ret;
2224 struct test_header_param param;
2225
2226 param.connection = connection;
2227 param.num_headers = 0;
2228 ret = MHD_parse_arguments_ (connection,
2230 args,
2231 &test_header,
2232 &param);
2233 if (MHD_NO == ret)
2234 {
2235 return false;
2236 }
2237 /* also check that the number of headers matches */
2238 for (pos = connection->rq.headers_received; NULL != pos; pos = pos->next)
2239 {
2240 if (MHD_GET_ARGUMENT_KIND != pos->kind)
2241 continue;
2242 param.num_headers--;
2243 }
2244 if (0 != param.num_headers)
2245 {
2246 /* argument count mismatch */
2247 return false;
2248 }
2249 return true;
2250}
2251
2252
2265static bool
2266check_uri_match (struct MHD_Connection *connection, char *uri, size_t uri_len)
2267{
2268 char *qmark;
2269 char *args;
2270 struct MHD_Daemon *const daemon = connection->daemon;
2271
2272 uri[uri_len] = 0;
2273 qmark = memchr (uri,
2274 '?',
2275 uri_len);
2276 if (NULL != qmark)
2277 *qmark = '\0';
2278
2279 /* Need to unescape URI before comparing with connection->url */
2281 connection,
2282 uri);
2283 if ((uri_len != connection->rq.url_len) ||
2284 (0 != memcmp (uri, connection->rq.url, uri_len)))
2285 {
2286#ifdef HAVE_MESSAGES
2287 MHD_DLOG (daemon,
2288 _ ("Authentication failed, URI does not match.\n"));
2289#endif
2290 return false;
2291 }
2292
2293 args = (NULL != qmark) ? (qmark + 1) : uri + uri_len;
2294
2295 if (! check_argument_match (connection,
2296 args) )
2297 {
2298#ifdef HAVE_MESSAGES
2299 MHD_DLOG (daemon,
2300 _ ("Authentication failed, arguments do not match.\n"));
2301#endif
2302 return false;
2303 }
2304 return true;
2305}
2306
2307
2311#define _MHD_STATIC_UNQ_BUFFER_SIZE 128
2312
2313
2323static char *
2325 char **ptmp2,
2326 size_t *ptmp2_size,
2327 size_t required_size)
2328{
2329 mhd_assert ((0 == *ptmp2_size) || (NULL != *ptmp2));
2330 mhd_assert ((NULL != *ptmp2) || (0 == *ptmp2_size));
2331 mhd_assert ((0 == *ptmp2_size) || \
2333
2335 return tmp1;
2336
2337 if (required_size <= *ptmp2_size)
2338 return *ptmp2;
2339
2341 return NULL;
2342 if (NULL != *ptmp2)
2343 free (*ptmp2);
2344 *ptmp2 = (char *) malloc (required_size);
2345 if (NULL == *ptmp2)
2346 *ptmp2_size = 0;
2347 else
2349 return *ptmp2;
2350}
2351
2352
2362
2372static enum _MHD_GetUnqResult
2375 char **ptmp2,
2376 size_t *ptmp2_size,
2377 struct _MHD_str_w_len *unquoted)
2378{
2379 char *str;
2380 size_t len;
2381 mhd_assert (NULL != param->value.str);
2382 mhd_assert (0 != param->value.len);
2383
2384 if (! param->quoted)
2385 {
2386 unquoted->str = param->value.str;
2387 unquoted->len = param->value.len;
2388 return _MHD_UNQ_OK;
2389 }
2390 /* The value is present and is quoted, needs to be copied and unquoted */
2391 str = get_buffer_for_size (tmp1, ptmp2, ptmp2_size, param->value.len);
2392 if (NULL == str)
2393 return (param->value.len > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE) ?
2395
2396 len = MHD_str_unquote (param->value.str, param->value.len, str);
2397 unquoted->str = str;
2398 unquoted->len = len;
2399 mhd_assert (0 != unquoted->len);
2400 mhd_assert (unquoted->len < param->value.len);
2401 return _MHD_UNQ_OK;
2402}
2403
2404
2415static enum _MHD_GetUnqResult
2418 char **ptmp2,
2419 size_t *ptmp2_size,
2420 struct _MHD_mstr_w_len *unquoted)
2421{
2422 mhd_assert (NULL != param->value.str);
2423 mhd_assert (0 != param->value.len);
2424
2425 /* The value is present and is quoted, needs to be copied and unquoted */
2426 /* Allocate buffer with one more additional byte for zero-termination */
2427 unquoted->str =
2428 get_buffer_for_size (tmp1, ptmp2, ptmp2_size, param->value.len + 1);
2429
2430 if (NULL == unquoted->str)
2431 return (param->value.len + 1 > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE) ?
2433
2434 if (! param->quoted)
2435 {
2436 memcpy (unquoted->str, param->value.str, param->value.len);
2437 unquoted->len = param->value.len;
2438 return _MHD_UNQ_OK;
2439 }
2440
2441 unquoted->len =
2442 MHD_str_unquote (param->value.str, param->value.len, unquoted->str);
2443 mhd_assert (0 != unquoted->len);
2444 mhd_assert (unquoted->len < param->value.len);
2445 return _MHD_UNQ_OK;
2446}
2447
2448
2459 const char *const str,
2460 const size_t str_len)
2461{
2462 mhd_assert (NULL != param->value.str);
2463 mhd_assert (0 != param->value.len);
2464 if (param->quoted)
2465 return MHD_str_equal_quoted_bin_n (param->value.str, param->value.len,
2466 str, str_len);
2467 return (str_len == param->value.len) &&
2468 (0 == memcmp (str, param->value.str, str_len));
2469
2470}
2471
2472
2483 const char *const str,
2484 const size_t str_len)
2485{
2486 mhd_assert (NULL != param->value.str);
2487 mhd_assert (0 != param->value.len);
2488 if (param->quoted)
2489 return MHD_str_equal_quoted_bin_n (param->value.str, param->value.len,
2490 str, str_len);
2491 return (str_len == param->value.len) &&
2492 (0 == memcmp (str, param->value.str, str_len));
2493
2494}
2495
2496
2533static enum MHD_DigestAuthResult
2535 const char *realm,
2536 const char *username,
2537 const char *password,
2538 const uint8_t *userdigest,
2539 unsigned int nonce_timeout,
2543 char **pbuf,
2544 struct DigestAlgorithm *da)
2545{
2546 struct MHD_Daemon *daemon = MHD_get_master (connection->daemon);
2549 unsigned int digest_size;
2552#if 0
2553 const char *hentity = NULL; /* "auth-int" is not supported */
2554#endif
2556 uint64_t nci;
2557 const struct MHD_RqDAuth *params;
2562 char **const ptmp2 = pbuf;
2563 size_t tmp2_size;
2564 struct _MHD_str_w_len unquoted;
2567 size_t username_len;
2568 size_t realm_len;
2569
2570 mhd_assert ((NULL != password) || (NULL != userdigest));
2571 mhd_assert (! ((NULL != userdigest) && (NULL != password)));
2572
2573 tmp2_size = 0;
2574
2575 params = MHD_get_rq_dauth_params_ (connection);
2576 if (NULL == params)
2578
2579 /* ** Initial parameters checks and setup ** */
2580 /* Get client's algorithm */
2581 c_algo = params->algo3;
2582 /* Check whether client's algorithm is allowed by function parameter */
2583 if (((unsigned int) c_algo) !=
2584 (((unsigned int) c_algo) & ((unsigned int) malgo3)))
2585 return MHD_DAUTH_WRONG_ALGO;
2586 /* Check whether client's algorithm is supported */
2587 if (0 != (((unsigned int) c_algo) & MHD_DIGEST_AUTH_ALGO3_SESSION))
2588 {
2589#ifdef HAVE_MESSAGES
2590 MHD_DLOG (connection->daemon,
2591 _ ("The 'session' algorithms are not supported.\n"));
2592#endif /* HAVE_MESSAGES */
2593 return MHD_DAUTH_WRONG_ALGO;
2594 }
2595#ifndef MHD_MD5_SUPPORT
2596 if (0 != (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_MD5))
2597 {
2598#ifdef HAVE_MESSAGES
2599 MHD_DLOG (connection->daemon,
2600 _ ("The MD5 algorithm is not supported by this MHD build.\n"));
2601#endif /* HAVE_MESSAGES */
2602 return MHD_DAUTH_WRONG_ALGO;
2603 }
2604#endif /* ! MHD_MD5_SUPPORT */
2605#ifndef MHD_SHA256_SUPPORT
2606 if (0 != (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_SHA256))
2607 {
2608#ifdef HAVE_MESSAGES
2609 MHD_DLOG (connection->daemon,
2610 _ ("The SHA-256 algorithm is not supported by "
2611 "this MHD build.\n"));
2612#endif /* HAVE_MESSAGES */
2613 return MHD_DAUTH_WRONG_ALGO;
2614 }
2615#endif /* ! MHD_SHA256_SUPPORT */
2616#ifndef MHD_SHA512_256_SUPPORT
2617 if (0 != (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_SHA512_256))
2618 {
2619#ifdef HAVE_MESSAGES
2620 MHD_DLOG (connection->daemon,
2621 _ ("The SHA-512/256 algorithm is not supported by "
2622 "this MHD build.\n"));
2623#endif /* HAVE_MESSAGES */
2624 return MHD_DAUTH_WRONG_ALGO;
2625 }
2626#endif /* ! MHD_SHA512_256_SUPPORT */
2628 MHD_PANIC (_ ("Wrong 'malgo3' value, API violation"));
2629 /* Check 'mqop' value */
2630 c_qop = params->qop;
2631 /* Check whether client's QOP is allowed by function parameter */
2632 if (((unsigned int) c_qop) !=
2633 (((unsigned int) c_qop) & ((unsigned int) mqop)))
2634 return MHD_DAUTH_WRONG_QOP;
2635 if (0 != (((unsigned int) c_qop) & MHD_DIGEST_AUTH_QOP_AUTH_INT))
2636 {
2637#ifdef HAVE_MESSAGES
2638 MHD_DLOG (connection->daemon,
2639 _ ("The 'auth-int' QOP is not supported.\n"));
2640#endif /* HAVE_MESSAGES */
2641 return MHD_DAUTH_WRONG_QOP;
2642 }
2643#ifdef HAVE_MESSAGES
2645 (0 == (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_MD5)))
2646 MHD_DLOG (connection->daemon,
2647 _ ("RFC2069 with SHA-256 or SHA-512/256 algorithm is " \
2648 "non-standard extension.\n"));
2649#endif /* HAVE_MESSAGES */
2650
2652
2653 /* ** A quick check for presence of all required parameters ** */
2654
2655 if ((NULL == params->username.value.str) &&
2656 (NULL == params->username_ext.value.str))
2658 else if ((NULL != params->username.value.str) &&
2659 (NULL != params->username_ext.value.str))
2660 return MHD_DAUTH_WRONG_USERNAME; /* Parameters cannot be used together */
2661 else if ((NULL != params->username_ext.value.str) &&
2662 (MHD_DAUTH_EXT_PARAM_MIN_LEN > params->username_ext.value.len))
2663 return MHD_DAUTH_WRONG_USERNAME; /* Broken extended notation */
2664 else if (params->userhash && (NULL == params->username.value.str))
2665 return MHD_DAUTH_WRONG_USERNAME; /* Userhash cannot be used with extended notation */
2666 else if (params->userhash && (digest_size * 2 > params->username.value.len))
2667 return MHD_DAUTH_WRONG_USERNAME; /* Too few chars for correct userhash */
2668 else if (params->userhash && (digest_size * 4 < params->username.value.len))
2669 return MHD_DAUTH_WRONG_USERNAME; /* Too many chars for correct userhash */
2670
2671 if (NULL == params->realm.value.str)
2672 return MHD_DAUTH_WRONG_REALM;
2673 else if (((NULL == userdigest) || params->userhash) &&
2675 return MHD_DAUTH_TOO_LARGE; /* Realm is too large and should be used in hash calculations */
2676
2678 {
2679 if (NULL == params->nc.value.str)
2681 else if (0 == params->nc.value.len)
2683 else if (4 * 8 < params->nc.value.len) /* Four times more than needed */
2685
2686 if (NULL == params->cnonce.value.str)
2688 else if (0 == params->cnonce.value.len)
2691 return MHD_DAUTH_TOO_LARGE;
2692 }
2693
2694 /* The QOP parameter was checked already */
2695
2696 if (NULL == params->uri.value.str)
2697 return MHD_DAUTH_WRONG_URI;
2698 else if (0 == params->uri.value.len)
2699 return MHD_DAUTH_WRONG_URI;
2701 return MHD_DAUTH_TOO_LARGE;
2702
2703 if (NULL == params->nonce.value.str)
2704 return MHD_DAUTH_NONCE_WRONG;
2705 else if (0 == params->nonce.value.len)
2706 return MHD_DAUTH_NONCE_WRONG;
2707 else if (NONCE_STD_LEN (digest_size) * 2 < params->nonce.value.len)
2708 return MHD_DAUTH_NONCE_WRONG;
2709
2710 if (NULL == params->response.value.str)
2712 else if (0 == params->response.value.len)
2714 else if (digest_size * 4 < params->response.value.len)
2716
2717 /* ** Check simple parameters match ** */
2718
2719 /* Check 'algorithm' */
2720 /* The 'algorithm' was checked at the start of the function */
2721 /* 'algorithm' valid */
2722
2723 /* Check 'qop' */
2724 /* The 'qop' was checked at the start of the function */
2725 /* 'qop' valid */
2726
2727 /* Check 'realm' */
2728 realm_len = strlen (realm);
2729 if (! is_param_equal (&params->realm, realm, realm_len))
2730 return MHD_DAUTH_WRONG_REALM;
2731 /* 'realm' valid */
2732
2733 /* Check 'username' */
2734 username_len = strlen (username);
2735 if (! params->userhash)
2736 {
2737 if (NULL != params->username.value.str)
2738 { /* Username in standard notation */
2739 if (! is_param_equal (&params->username, username, username_len))
2741 }
2742 else
2743 { /* Username in extended notation */
2744 char *r_uname;
2745 size_t buf_size = params->username_ext.value.len;
2746 ssize_t res;
2747
2748 mhd_assert (NULL != params->username_ext.value.str);
2749 mhd_assert (MHD_DAUTH_EXT_PARAM_MIN_LEN <= buf_size); /* It was checked already */
2750 buf_size += 1; /* For zero-termination */
2753 if (NULL == r_uname)
2756 res = get_rq_extended_uname_copy_z (params->username_ext.value.str,
2757 params->username_ext.value.len,
2758 r_uname, buf_size);
2759 if (0 > res)
2760 return MHD_DAUTH_WRONG_HEADER; /* Broken extended notation */
2761 if ((username_len != (size_t) res) ||
2762 (0 != memcmp (username, r_uname, username_len)))
2764 }
2765 }
2766 else
2767 { /* Userhash */
2768 mhd_assert (NULL != params->username.value.str);
2769 calc_userhash (da, username, username_len, realm, realm_len, hash1_bin);
2770#ifdef MHD_DIGEST_HAS_EXT_ERROR
2771 if (digest_ext_error (da))
2772 return MHD_DAUTH_ERROR;
2773#endif /* MHD_DIGEST_HAS_EXT_ERROR */
2774 mhd_assert (sizeof (tmp1) >= (2 * digest_size));
2776 if (! is_param_equal_caseless (&params->username, tmp1, 2 * digest_size))
2778 /* To simplify the logic, the digest is reset here instead of resetting
2779 before the next hash calculation. */
2780 digest_reset (da);
2781 }
2782 /* 'username' valid */
2783
2784 /* ** Do basic nonce and nonce-counter checks (size, timestamp) ** */
2785
2786 /* Get 'nc' digital value */
2788 {
2789
2791 &unquoted);
2792 if (_MHD_UNQ_OK != unq_res)
2793 return MHD_DAUTH_ERROR;
2794
2795 if (unquoted.len != MHD_strx_to_uint64_n_ (unquoted.str,
2796 unquoted.len,
2797 &nci))
2798 {
2799#ifdef HAVE_MESSAGES
2800 MHD_DLOG (daemon,
2801 _ ("Authentication failed, invalid nc format.\n"));
2802#endif
2803 return MHD_DAUTH_WRONG_HEADER; /* invalid nonce format */
2804 }
2805 if (0 == nci)
2806 {
2807#ifdef HAVE_MESSAGES
2808 MHD_DLOG (daemon,
2809 _ ("Authentication failed, invalid 'nc' value.\n"));
2810#endif
2811 return MHD_DAUTH_WRONG_HEADER; /* invalid nc value */
2812 }
2813 if ((0 != max_nc) && (max_nc < nci))
2814 return MHD_DAUTH_NONCE_STALE; /* Too large 'nc' value */
2815 }
2816 else
2817 nci = 1; /* Force 'nc' value */
2818 /* Got 'nc' digital value */
2819
2820 /* Get 'nonce' with basic checks */
2822 &unquoted);
2823 if (_MHD_UNQ_OK != unq_res)
2824 return MHD_DAUTH_ERROR;
2825
2826 if ((NONCE_STD_LEN (digest_size) != unquoted.len) ||
2828 {
2829#ifdef HAVE_MESSAGES
2830 MHD_DLOG (daemon,
2831 _ ("Authentication failed, invalid nonce format.\n"));
2832#endif
2833 return MHD_DAUTH_NONCE_WRONG;
2834 }
2835
2836 if (1)
2837 {
2838 uint64_t t;
2839
2841 /*
2842 * First level vetting for the nonce validity: if the timestamp
2843 * attached to the nonce exceeds `nonce_timeout', then the nonce is
2844 * stale.
2845 */
2846 if (TRIM_TO_TIMESTAMP (t - nonce_time) > (nonce_timeout * 1000))
2847 return MHD_DAUTH_NONCE_STALE; /* too old */
2848 }
2849 if (1)
2850 {
2852 /*
2853 * Checking if that combination of nonce and nc is sound
2854 * and not a replay attack attempt. Refuse if nonce was not
2855 * generated previously.
2856 */
2857 nonce_nc_check = check_nonce_nc (connection,
2858 unquoted.str,
2860 nonce_time,
2861 nci);
2863 {
2864#ifdef HAVE_MESSAGES
2866 MHD_DLOG (daemon,
2867 _ ("Stale nonce received. If this happens a lot, you should "
2868 "probably increase the size of the nonce array.\n"));
2869 else
2870 MHD_DLOG (daemon,
2871 _ ("Stale nonce received. This is expected when client " \
2872 "uses RFC2069-compatible mode and makes more than one " \
2873 "request.\n"));
2874#endif
2875 return MHD_DAUTH_NONCE_STALE;
2876 }
2878 {
2879#ifdef HAVE_MESSAGES
2880 MHD_DLOG (daemon,
2881 _ ("Received nonce that was not "
2882 "generated by MHD. This may indicate an attack attempt.\n"));
2883#endif
2884 return MHD_DAUTH_NONCE_WRONG;
2885 }
2887 }
2888 /* The nonce was generated by MHD, is not stale and nonce-nc combination was
2889 not used before */
2890
2891 /* ** Build H(A2) and check URI match in the header and in the request ** */
2892
2893 /* Get 'uri' */
2894 mhd_assert (! da->hashing);
2895 digest_update_str (da, connection->rq.method);
2897#if 0
2898 /* TODO: add support for "auth-int" */
2901#endif
2903 &unq_copy);
2904 if (_MHD_UNQ_OK != unq_res)
2905 return MHD_DAUTH_ERROR;
2906
2907 digest_update (da, unq_copy.str, unq_copy.len);
2908 /* The next check will modify copied URI string */
2909 if (! check_uri_match (connection, unq_copy.str, unq_copy.len))
2910 return MHD_DAUTH_WRONG_URI;
2912#ifdef MHD_DIGEST_HAS_EXT_ERROR
2913 /* Skip digest calculation external error check, the next one checks both */
2914#endif /* MHD_DIGEST_HAS_EXT_ERROR */
2915 /* Got H(A2) */
2916
2917 /* ** Build H(A1) ** */
2918 if (NULL == userdigest)
2919 {
2920 mhd_assert (! da->hashing);
2921 digest_reset (da);
2923 username, username_len,
2924 realm, realm_len,
2925 password,
2926 hash1_bin);
2927 }
2928 /* TODO: support '-sess' versions */
2929#ifdef MHD_DIGEST_HAS_EXT_ERROR
2930 if (digest_ext_error (da))
2931 return MHD_DAUTH_ERROR;
2932#endif /* MHD_DIGEST_HAS_EXT_ERROR */
2933 /* Got H(A1) */
2934
2935 /* ** Check 'response' ** */
2936
2937 mhd_assert (! da->hashing);
2938 digest_reset (da);
2939 /* Update digest with H(A1) */
2940 mhd_assert (sizeof (tmp1) >= (digest_size * 2));
2941 if (NULL == userdigest)
2943 else
2945 digest_update (da, (const uint8_t *) tmp1, digest_size * 2);
2946
2947 /* H(A1) is not needed anymore, reuse the buffer.
2948 * Use hash1_bin for the client's 'response' decoded to binary form. */
2950 &unquoted);
2951 if (_MHD_UNQ_OK != unq_res)
2952 return MHD_DAUTH_ERROR;
2955
2956 /* Update digest with ':' */
2958 /* Update digest with 'nonce' text value */
2960 &unquoted);
2961 if (_MHD_UNQ_OK != unq_res)
2962 return MHD_DAUTH_ERROR;
2963 digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
2964 /* Update digest with ':' */
2967 {
2968 /* Update digest with 'nc' text value */
2970 &unquoted);
2971 if (_MHD_UNQ_OK != unq_res)
2972 return MHD_DAUTH_ERROR;
2973 digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
2974 /* Update digest with ':' */
2976 /* Update digest with 'cnonce' value */
2978 &unquoted);
2979 if (_MHD_UNQ_OK != unq_res)
2980 return MHD_DAUTH_ERROR;
2981 digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
2982 /* Update digest with ':' */
2984 /* Update digest with 'qop' value */
2986 &unquoted);
2987 if (_MHD_UNQ_OK != unq_res)
2988 return MHD_DAUTH_ERROR;
2989 digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
2990 /* Update digest with ':' */
2992 }
2993 /* Update digest with H(A2) */
2995 digest_update (da, (const uint8_t *) tmp1, digest_size * 2);
2996
2997 /* H(A2) is not needed anymore, reuse the buffer.
2998 * Use hash2_bin for the calculated response in binary form */
3000#ifdef MHD_DIGEST_HAS_EXT_ERROR
3001 if (digest_ext_error (da))
3002 return MHD_DAUTH_ERROR;
3003#endif /* MHD_DIGEST_HAS_EXT_ERROR */
3004
3007
3008 if (MHD_DAUTH_BIND_NONCE_NONE != daemon->dauth_bind_type)
3009 {
3010 mhd_assert (sizeof(tmp1) >= (NONCE_STD_LEN (digest_size) + 1));
3011 /* It was already checked that 'nonce' (including timestamp) was generated
3012 by MHD. */
3013 mhd_assert (! da->hashing);
3014 digest_reset (da);
3016 connection->rq.http_mthd,
3017 connection->rq.method,
3018 daemon->digest_auth_random,
3019 daemon->digest_auth_rand_size,
3020 connection->addr,
3021 (size_t) connection->addr_len,
3022 connection->rq.url,
3023 connection->rq.url_len,
3024 connection->rq.headers_received,
3025 realm,
3026 realm_len,
3027 daemon->dauth_bind_type,
3028 da,
3029 tmp1);
3030
3031#ifdef MHD_DIGEST_HAS_EXT_ERROR
3032 if (digest_ext_error (da))
3033 return MHD_DAUTH_ERROR;
3034#endif /* MHD_DIGEST_HAS_EXT_ERROR */
3035
3036 if (! is_param_equal (&params->nonce, tmp1,
3039 /* The 'nonce' was generated in the same conditions */
3040 }
3041
3042 return MHD_DAUTH_OK;
3043}
3044
3045
3080static enum MHD_DigestAuthResult
3082 const char *realm,
3083 const char *username,
3084 const char *password,
3085 const uint8_t *userdigest,
3086 unsigned int nonce_timeout,
3090{
3092 char *buf;
3093 struct DigestAlgorithm da;
3094
3095 buf = NULL;
3097 if (0 == nonce_timeout)
3098 nonce_timeout = connection->daemon->dauth_def_nonce_timeout;
3099 if (0 == max_nc)
3100 max_nc = connection->daemon->dauth_def_max_nc;
3101 res = digest_auth_check_all_inner (connection, realm, username, password,
3102 userdigest,
3104 max_nc, mqop, malgo3,
3105 &buf, &da);
3106 digest_deinit (&da);
3107 if (NULL != buf)
3108 free (buf);
3109
3110 return res;
3111}
3112
3113
3132_MHD_EXTERN int
3134 const char *realm,
3135 const char *username,
3136 const char *password,
3137 unsigned int nonce_timeout)
3138{
3139 return MHD_digest_auth_check2 (connection,
3140 realm,
3141 username,
3142 password,
3145}
3146
3147
3181 const char *realm,
3182 const char *username,
3183 const char *password,
3184 unsigned int nonce_timeout,
3188{
3189 mhd_assert (NULL != password);
3190
3191 return digest_auth_check_all (connection,
3192 realm,
3193 username,
3194 password,
3195 NULL,
3197 max_nc,
3198 mqop,
3199 malgo3);
3200}
3201
3202
3247 const char *realm,
3248 const char *username,
3249 const void *userdigest,
3250 size_t userdigest_size,
3251 unsigned int nonce_timeout,
3255{
3256 if (1 != (((0 != (malgo3 & MHD_DIGEST_BASE_ALGO_MD5)) ? 1 : 0)
3257 + ((0 != (malgo3 & MHD_DIGEST_BASE_ALGO_SHA256)) ? 1 : 0)
3258 + ((0 != (malgo3 & MHD_DIGEST_BASE_ALGO_SHA512_256)) ? 1 : 0)))
3259 MHD_PANIC (_ ("Wrong 'malgo3' value, only one base hashing algorithm " \
3260 "(MD5, SHA-256 or SHA-512/256) must be specified, " \
3261 "API violation"));
3262
3263#ifndef MHD_MD5_SUPPORT
3264 if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_MD5))
3265 {
3266#ifdef HAVE_MESSAGES
3267 MHD_DLOG (connection->daemon,
3268 _ ("The MD5 algorithm is not supported by this MHD build.\n"));
3269#endif /* HAVE_MESSAGES */
3270 return MHD_DAUTH_WRONG_ALGO;
3271 }
3272#endif /* ! MHD_MD5_SUPPORT */
3273#ifndef MHD_SHA256_SUPPORT
3274 if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA256))
3275 {
3276#ifdef HAVE_MESSAGES
3277 MHD_DLOG (connection->daemon,
3278 _ ("The SHA-256 algorithm is not supported by "
3279 "this MHD build.\n"));
3280#endif /* HAVE_MESSAGES */
3281 return MHD_DAUTH_WRONG_ALGO;
3282 }
3283#endif /* ! MHD_SHA256_SUPPORT */
3284#ifndef MHD_SHA512_256_SUPPORT
3285 if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA512_256))
3286 {
3287#ifdef HAVE_MESSAGES
3288 MHD_DLOG (connection->daemon,
3289 _ ("The SHA-512/256 algorithm is not supported by "
3290 "this MHD build.\n"));
3291#endif /* HAVE_MESSAGES */
3292 return MHD_DAUTH_WRONG_ALGO;
3293 }
3294#endif /* ! MHD_SHA512_256_SUPPORT */
3295
3298 MHD_PANIC (_ ("Wrong 'userdigest_size' value, does not match 'malgo3', "
3299 "API violation"));
3300
3301 return digest_auth_check_all (connection,
3302 realm,
3303 username,
3304 NULL,
3305 (const uint8_t *) userdigest,
3307 max_nc,
3308 mqop,
3309 malgo3);
3310}
3311
3312
3329_MHD_EXTERN int
3331 const char *realm,
3332 const char *username,
3333 const char *password,
3334 unsigned int nonce_timeout,
3335 enum MHD_DigestAuthAlgorithm algo)
3336{
3339
3340 if (MHD_DIGEST_ALG_AUTO == algo)
3342 else if (MHD_DIGEST_ALG_MD5 == algo)
3344 else if (MHD_DIGEST_ALG_SHA256 == algo)
3346 else
3347 MHD_PANIC (_ ("Wrong 'algo' value, API violation"));
3348
3349 res = MHD_digest_auth_check3 (connection,
3350 realm,
3351 username,
3352 password,
3355 malgo3);
3356 if (MHD_DAUTH_OK == res)
3357 return MHD_YES;
3358 else if ((MHD_DAUTH_NONCE_STALE == res) || (MHD_DAUTH_NONCE_WRONG == res) ||
3360 return MHD_INVALID_NONCE;
3361 return MHD_NO;
3362
3363}
3364
3365
3385_MHD_EXTERN int
3387 const char *realm,
3388 const char *username,
3389 const uint8_t *digest,
3390 size_t digest_size,
3391 unsigned int nonce_timeout,
3392 enum MHD_DigestAuthAlgorithm algo)
3393{
3396
3397 if (MHD_DIGEST_ALG_AUTO == algo)
3399 else if (MHD_DIGEST_ALG_MD5 == algo)
3401 else if (MHD_DIGEST_ALG_SHA256 == algo)
3403 else
3404 MHD_PANIC (_ ("Wrong 'algo' value, API violation"));
3405
3406 res = MHD_digest_auth_check_digest3 (connection,
3407 realm,
3408 username,
3409 digest,
3413 malgo3);
3414 if (MHD_DAUTH_OK == res)
3415 return MHD_YES;
3416 else if ((MHD_DAUTH_NONCE_STALE == res) || (MHD_DAUTH_NONCE_WRONG == res) ||
3418 return MHD_INVALID_NONCE;
3419 return MHD_NO;
3420}
3421
3422
3442_MHD_EXTERN int
3444 const char *realm,
3445 const char *username,
3447 unsigned int nonce_timeout)
3448{
3449 return MHD_digest_auth_check_digest2 (connection,
3450 realm,
3451 username,
3452 digest,
3456}
3457
3458
3508static enum MHD_Result
3510 const char *realm,
3511 const char *opaque,
3512 const char *domain,
3513 struct MHD_Response *response,
3514 int signal_stale,
3517 int userhash_support,
3518 int prefer_utf8,
3519 char **buf_ptr,
3520 struct DigestAlgorithm *da)
3521{
3522 static const char prefix_realm[] = "realm=\"";
3523 static const char prefix_qop[] = "qop=\"";
3524 static const char prefix_algo[] = "algorithm=";
3525 static const char prefix_nonce[] = "nonce=\"";
3526 static const char prefix_opaque[] = "opaque=\"";
3527 static const char prefix_domain[] = "domain=\"";
3528 static const char str_charset[] = "charset=UTF-8";
3529 static const char str_userhash[] = "userhash=true";
3530 static const char str_stale[] = "stale=true";
3532 size_t realm_len;
3533 size_t opaque_len;
3534 size_t domain_len;
3535 size_t buf_size;
3536 char *buf;
3537 size_t p; /* The position in the buffer */
3538 char *hdr_name;
3539
3540 if (0 == (((unsigned int) malgo3) & MHD_DIGEST_AUTH_ALGO3_NON_SESSION))
3541 {
3542#ifdef HAVE_MESSAGES
3543 MHD_DLOG (connection->daemon,
3544 _ ("Only non-'session' algorithms are supported.\n"));
3545#endif /* HAVE_MESSAGES */
3546 return MHD_NO;
3547 }
3548 malgo3 &=
3551#ifdef MHD_MD5_SUPPORT
3552 if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_MD5))
3554 else
3555#endif /* MHD_MD5_SUPPORT */
3556#ifdef MHD_SHA256_SUPPORT
3557 if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA256))
3559 else
3560#endif /* MHD_SHA256_SUPPORT */
3561#ifdef MHD_SHA512_256_SUPPORT
3562 if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA512_256))
3564 else
3565#endif /* MHD_SHA512_256_SUPPORT */
3566 {
3567 if (0 == (((unsigned int) malgo3)
3570 MHD_PANIC (_ ("Wrong 'malgo3' value, API violation"));
3571 else
3572 {
3573#ifdef HAVE_MESSAGES
3574 MHD_DLOG (connection->daemon,
3575 _ ("No requested algorithm is supported by this MHD build.\n"));
3576#endif /* HAVE_MESSAGES */
3577 }
3578 return MHD_NO;
3579 }
3580
3582 MHD_PANIC (_ ("Wrong 'mqop' value, API violation"));
3585
3587 MHD_PANIC (_ ("Wrong 'algo' value, API violation"));
3588
3590 {
3591#ifdef HAVE_MESSAGES
3592 if ((0 != userhash_support) || (0 != prefer_utf8))
3593 MHD_DLOG (connection->daemon,
3594 _ ("The 'userhash' and 'charset' ('prefer_utf8') parameters " \
3595 "are not compatible with RFC2069 and ignored.\n"));
3596 if (0 == (((unsigned int) s_algo) & MHD_DIGEST_BASE_ALGO_MD5))
3597 MHD_DLOG (connection->daemon,
3598 _ ("RFC2069 with SHA-256 or SHA-512/256 algorithm is " \
3599 "non-standard extension.\n"));
3600#endif
3601 userhash_support = 0;
3602 prefer_utf8 = 0;
3603 }
3604
3605 if (0 == MHD_get_master (connection->daemon)->nonce_nc_size)
3606 {
3607#ifdef HAVE_MESSAGES
3608 MHD_DLOG (connection->daemon,
3609 _ ("The nonce array size is zero.\n"));
3610#endif /* HAVE_MESSAGES */
3611 return MHD_NO;
3612 }
3613
3614 /* Calculate required size */
3615 buf_size = 0;
3616 /* 'Digest ' */
3617 buf_size += MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE) + 1; /* 1 for ' ' */
3618 buf_size += MHD_STATICSTR_LEN_ (prefix_realm) + 3; /* 3 for '", ' */
3619 /* 'realm="xxxx", ' */
3620 realm_len = strlen (realm);
3621 if (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < realm_len)
3622 {
3623#ifdef HAVE_MESSAGES
3624 MHD_DLOG (connection->daemon,
3625 _ ("The 'realm' is too large.\n"));
3626#endif /* HAVE_MESSAGES */
3627 return MHD_NO;
3628 }
3629 if ((NULL != memchr (realm, '\r', realm_len)) ||
3630 (NULL != memchr (realm, '\n', realm_len)))
3631 return MHD_NO;
3632
3633 buf_size += realm_len * 2; /* Quoting may double the size */
3634 /* 'qop="xxxx", ' */
3636 {
3637 buf_size += MHD_STATICSTR_LEN_ (prefix_qop) + 3; /* 3 for '", ' */
3639 }
3640 /* 'algorithm="xxxx", ' */
3642 (0 == (((unsigned int) s_algo) & MHD_DIGEST_BASE_ALGO_MD5)))
3643 {
3644 buf_size += MHD_STATICSTR_LEN_ (prefix_algo) + 2; /* 2 for ', ' */
3645#ifdef MHD_MD5_SUPPORT
3648 else
3649#endif /* MHD_MD5_SUPPORT */
3650#ifdef MHD_SHA256_SUPPORT
3653 else
3654#endif /* MHD_SHA256_SUPPORT */
3655#ifdef MHD_SHA512_256_SUPPORT
3658 else
3659#endif /* MHD_SHA512_256_SUPPORT */
3660 mhd_assert (0);
3661 }
3662 /* 'nonce="xxxx", ' */
3663 buf_size += MHD_STATICSTR_LEN_ (prefix_nonce) + 3; /* 3 for '", ' */
3664 buf_size += NONCE_STD_LEN (digest_get_size (da)); /* Escaping not needed */
3665 /* 'opaque="xxxx", ' */
3666 if (NULL != opaque)
3667 {
3668 buf_size += MHD_STATICSTR_LEN_ (prefix_opaque) + 3; /* 3 for '", ' */
3669 opaque_len = strlen (opaque);
3670 if ((NULL != memchr (opaque, '\r', opaque_len)) ||
3671 (NULL != memchr (opaque, '\n', opaque_len)))
3672 return MHD_NO;
3673
3674 buf_size += opaque_len * 2; /* Quoting may double the size */
3675 }
3676 else
3677 opaque_len = 0;
3678 /* 'domain="xxxx", ' */
3679 if (NULL != domain)
3680 {
3681 buf_size += MHD_STATICSTR_LEN_ (prefix_domain) + 3; /* 3 for '", ' */
3683 if ((NULL != memchr (domain, '\r', domain_len)) ||
3684 (NULL != memchr (domain, '\n', domain_len)))
3685 return MHD_NO;
3686
3687 buf_size += domain_len * 2; /* Quoting may double the size */
3688 }
3689 else
3690 domain_len = 0;
3691 /* 'charset=UTF-8' */
3692 if (MHD_NO != prefer_utf8)
3693 buf_size += MHD_STATICSTR_LEN_ (str_charset) + 2; /* 2 for ', ' */
3694 /* 'userhash=true' */
3695 if (MHD_NO != userhash_support)
3696 buf_size += MHD_STATICSTR_LEN_ (str_userhash) + 2; /* 2 for ', ' */
3697 /* 'stale=true' */
3698 if (MHD_NO != signal_stale)
3699 buf_size += MHD_STATICSTR_LEN_ (str_stale) + 2; /* 2 for ', ' */
3700
3701 /* The calculated length is for string ended with ", ". One character will
3702 * be used for zero-termination, the last one will not be used. */
3703
3704 /* Allocate the buffer */
3705 buf = malloc (buf_size);
3706 if (NULL == buf)
3707 return MHD_NO;
3708 *buf_ptr = buf;
3709
3710 /* Build the challenge string */
3711 p = 0;
3712 /* 'Digest: ' */
3716 buf[p++] = ' ';
3717 /* 'realm="xxxx", ' */
3721 mhd_assert ((buf_size - p) >= (realm_len * 2));
3722 if (1)
3723 {
3724 size_t quoted_size;
3725 quoted_size = MHD_str_quote (realm, realm_len, buf + p, buf_size - p);
3727 {
3728#ifdef HAVE_MESSAGES
3729 MHD_DLOG (connection->daemon,
3730 _ ("The 'realm' is too large after 'quoting'.\n"));
3731#endif /* HAVE_MESSAGES */
3732 return MHD_NO;
3733 }
3734 p += quoted_size;
3735 }
3736 buf[p++] = '\"';
3737 buf[p++] = ',';
3738 buf[p++] = ' ';
3739 /* 'qop="xxxx", ' */
3741 {
3742 memcpy (buf + p, prefix_qop,
3748 buf[p++] = '\"';
3749 buf[p++] = ',';
3750 buf[p++] = ' ';
3751 }
3752 /* 'algorithm="xxxx", ' */
3754 (0 == (((unsigned int) s_algo) & MHD_DIGEST_BASE_ALGO_MD5)))
3755 {
3756 memcpy (buf + p, prefix_algo,
3759#ifdef MHD_MD5_SUPPORT
3761 {
3765 }
3766 else
3767#endif /* MHD_MD5_SUPPORT */
3768#ifdef MHD_SHA256_SUPPORT
3770 {
3774 }
3775 else
3776#endif /* MHD_SHA256_SUPPORT */
3777#ifdef MHD_SHA512_256_SUPPORT
3779 {
3783 }
3784 else
3785#endif /* MHD_SHA512_256_SUPPORT */
3786 mhd_assert (0);
3787 buf[p++] = ',';
3788 buf[p++] = ' ';
3789 }
3790 /* 'nonce="xxxx", ' */
3795 if (! calculate_add_nonce_with_retry (connection, realm, da, buf + p))
3796 {
3797#ifdef MHD_DIGEST_HAS_EXT_ERROR
3798 if (digest_ext_error (da))
3799 {
3800#ifdef HAVE_MESSAGES
3801 MHD_DLOG (connection->daemon,
3802 _ ("TLS library reported hash calculation error, nonce could "
3803 "not be generated.\n"));
3804#endif /* HAVE_MESSAGES */
3805 return MHD_NO;
3806 }
3807#endif /* MHD_DIGEST_HAS_EXT_ERROR */
3808#ifdef HAVE_MESSAGES
3809 MHD_DLOG (connection->daemon,
3810 _ ("Could not register nonce. Client's requests with this "
3811 "nonce will be always 'stale'. Probably clients' requests "
3812 "are too intensive.\n"));
3813#endif /* HAVE_MESSAGES */
3814 (void) 0; /* Mute compiler warning for builds without messages */
3815 }
3817 buf[p++] = '\"';
3818 buf[p++] = ',';
3819 buf[p++] = ' ';
3820 /* 'opaque="xxxx", ' */
3821 if (NULL != opaque)
3822 {
3826 mhd_assert ((buf_size - p) >= (opaque_len * 2));
3827 p += MHD_str_quote (opaque, opaque_len, buf + p, buf_size - p);
3828 buf[p++] = '\"';
3829 buf[p++] = ',';
3830 buf[p++] = ' ';
3831 }
3832 /* 'domain="xxxx", ' */
3833 if (NULL != domain)
3834 {
3838 mhd_assert ((buf_size - p) >= (domain_len * 2));
3840 buf[p++] = '\"';
3841 buf[p++] = ',';
3842 buf[p++] = ' ';
3843 }
3844 /* 'charset=UTF-8' */
3845 if (MHD_NO != prefer_utf8)
3846 {
3847 memcpy (buf + p, str_charset,
3850 buf[p++] = ',';
3851 buf[p++] = ' ';
3852 }
3853 /* 'userhash=true' */
3854 if (MHD_NO != userhash_support)
3855 {
3859 buf[p++] = ',';
3860 buf[p++] = ' ';
3861 }
3862 /* 'stale=true' */
3863 if (MHD_NO != signal_stale)
3864 {
3865 memcpy (buf + p, str_stale,
3868 buf[p++] = ',';
3869 buf[p++] = ' ';
3870 }
3871 mhd_assert (buf_size >= p);
3872 /* The built string ends with ", ". Replace comma with zero-termination. */
3873 --p;
3874 buf[--p] = 0;
3875
3877 if (NULL != hdr_name)
3878 {
3882 hdr_name,
3885 buf, p))
3886 {
3887 *buf_ptr = NULL; /* The buffer will be free()ed when the response is destroyed */
3888 return MHD_queue_response (connection, MHD_HTTP_UNAUTHORIZED, response);
3889 }
3890#ifdef HAVE_MESSAGES
3891 else
3892 {
3893 MHD_DLOG (connection->daemon,
3894 _ ("Failed to add Digest auth header.\n"));
3895 }
3896#endif /* HAVE_MESSAGES */
3897 free (hdr_name);
3898 }
3899 return MHD_NO;
3900}
3901
3902
3967 const char *realm,
3968 const char *opaque,
3969 const char *domain,
3970 struct MHD_Response *response,
3971 int signal_stale,
3974 int userhash_support,
3975 int prefer_utf8)
3976{
3977 struct DigestAlgorithm da;
3978 char *buf_ptr;
3979 enum MHD_Result ret;
3980
3981 buf_ptr = NULL;
3984 realm,
3985 opaque,
3986 domain,
3987 response,
3989 mqop,
3990 malgo3,
3993 &buf_ptr,
3994 &da);
3995 digest_deinit (&da);
3996 if (NULL != buf_ptr)
3997 free (buf_ptr);
3998 return ret;
3999}
4000
4001
4020 const char *realm,
4021 const char *opaque,
4022 struct MHD_Response *response,
4023 int signal_stale,
4024 enum MHD_DigestAuthAlgorithm algo)
4025{
4026 enum MHD_DigestAuthMultiAlgo3 algo3;
4027
4028 if (MHD_DIGEST_ALG_MD5 == algo)
4030 else if (MHD_DIGEST_ALG_SHA256 == algo)
4032 else if (MHD_DIGEST_ALG_AUTO == algo)
4034 else
4035 MHD_PANIC (_ ("Wrong algo value.\n")); /* API violation! */
4036
4037 return MHD_queue_auth_required_response3 (connection, realm, opaque,
4038 NULL, response, signal_stale,
4040 algo3,
4041 0, 0);
4042}
4043
4044
4064 const char *realm,
4065 const char *opaque,
4066 struct MHD_Response *response,
4067 int signal_stale)
4068{
4069 return MHD_queue_auth_fail_response2 (connection,
4070 realm,
4071 opaque,
4072 response,
4075}
4076
4077
4078/* 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 int MHD_digest_auth_check_digest2(struct MHD_Connection *connection, const char *realm, const char *username, const uint8_t *digest, size_t digest_size, unsigned int nonce_timeout, enum MHD_DigestAuthAlgorithm algo)
_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 int MHD_digest_auth_check_digest(struct MHD_Connection *connection, const char *realm, const char *username, const uint8_t digest[MHD_MD5_DIGEST_SIZE], unsigned int nonce_timeout)
_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:658
#define MHD_HTTP_OK
Definition microhttpd.h:344
#define MHD_HTTP_UNAUTHORIZED
Definition microhttpd.h:387
_MHD_EXTERN enum MHD_Result MHD_queue_response(struct MHD_Connection *connection, unsigned int status_code, struct MHD_Response *response)
bool MHD_parse_arguments_(struct MHD_Request *request, enum MHD_ValueKind kind, char *args, MHD_ArgumentIterator_ cb, unsigned int *num_headers)
Definition internal.c:190
#define MHD_PANIC(msg)
Definition internal.h:69
#define mhd_assert(CHK)
Definition mhd_assert.h:39
void * MHD_calloc_(size_t nelem, size_t elsize)
Definition mhd_compat.c:98
#define UINT64_MAX
Definition mhd_limits.h:81
#define UINT32_MAX
Definition mhd_limits.h:73
#define MHD_mutex_unlock_chk_(pmutex)
Definition mhd_locks.h:180
#define MHD_mutex_lock_chk_(pmutex)
Definition mhd_locks.h:154
size_t MHD_strx_to_uint64_n_(const char *str, size_t maxlen, uint64_t *out_val)
Definition mhd_str.c:692
#define MHD_STATICSTR_LEN_(macro)
Definition mhd_str.h:45
#define NULL
void MHD_MD5_finish(struct Md5Ctx *ctx, uint8_t digest[MD5_DIGEST_SIZE])
Definition md5.c:461
void MHD_MD5_update(struct Md5Ctx *ctx, const uint8_t *data, size_t length)
Definition md5.c:393
#define MD5_DIGEST_SIZE
Definition md5.h:61
macros for bits manipulations
_MHD_static_inline uint32_t _MHD_ROTR32(uint32_t value32, int bits)
_MHD_static_inline uint32_t _MHD_ROTL32(uint32_t value32, int bits)
Simple wrapper for selection of built-in/external MD5 implementation.
#define MHD_MD5_finish_reset(ctx, digest)
#define MHD_MD5_deinit(ignore)
#define Md5CtxWr
#define MHD_MD5_reset(ctx)
#define MHD_MD5_init_one_time(ctx)
#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)
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:2900
MHD_HTTP_Method
Definition internal.h:899
@ MHD_HTTP_MTHD_GET
Definition internal.h:907
@ MHD_HTTP_MTHD_HEAD
Definition internal.h:911
@ MHD_HTTP_MTHD_OTHER
Definition internal.h:939
macros for mhd_assert()
Header for platform missing functions.
limits values definitions
#define SSIZE_MAX
Definition mhd_limits.h:121
Header for platform-independent locks abstraction.
uint64_t MHD_monotonic_msec_counter(void)
internal monotonic clock functions implementations
size_t MHD_bin_to_hex(const void *bin, size_t size, char *hex)
Definition mhd_str.c:1676
size_t MHD_str_pct_decode_strict_n_(const char *pct_encoded, size_t pct_encoded_len, char *decoded, size_t buf_size)
Definition mhd_str.c:1746
size_t MHD_bin_to_hex_z(const void *bin, size_t size, char *hex)
Definition mhd_str.c:1696
bool MHD_str_equal_caseless_bin_n_(const char *const str1, const char *const str2, size_t len)
Definition mhd_str.c:749
size_t MHD_hex_to_bin(const char *hex, size_t len, void *bin)
Definition mhd_str.c:1710
Header for string manipulating helpers.
bool MHD_add_response_entry_no_alloc_(struct MHD_Response *response, enum MHD_ValueKind kind, char *header, size_t header_len, char *content, size_t content_len)
Definition response.c:167
MHD_DigestAuthResult
@ 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:158
@ MHD_YES
Definition microhttpd.h:167
@ MHD_NO
Definition microhttpd.h:162
#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
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:535
void MHD_SHA512_256_init(struct Sha512_256Ctx *ctx)
Definition sha512_256.c:41
void MHD_SHA512_256_update(struct Sha512_256Ctx *ctx, const uint8_t *data, size_t length)
Definition sha512_256.c:460
Calculation of SHA-512/256 digest.
#define SHA512_256_DIGEST_SIZE
Definition sha512_256.h:62
socklen_t addr_len
Definition internal.h:733
struct MHD_Request rq
Definition internal.h:1365
struct sockaddr_storage addr
Definition internal.h:728
struct MHD_Daemon * daemon
Definition internal.h:675
void * unescape_callback_cls
Definition internal.h:2072
UnescapeCallback unescape_callback
Definition internal.h:2067
enum MHD_DigestAuthUsernameType uname_type
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
char nonce[MAX_DIGEST_NONCE_LENGTH+1]
Definition internal.h:298
struct MHD_HTTP_Header * headers_received
Definition internal.h:388
enum MHD_Method method
Definition internal.h:554
size_t url_len
Definition internal.h:1101
const char * url
Definition internal.h:413
enum MHD_HTTP_Method http_mthd
Definition internal.h:1090