GNU libmicrohttpd  0.9.72
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 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public
7  License as published by the Free Software Foundation; either
8  version 2.1 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
26 #include "platform.h"
27 #include "mhd_limits.h"
28 #include "internal.h"
29 #include "md5.h"
30 #include "sha256.h"
31 #include "mhd_mono_clock.h"
32 #include "mhd_str.h"
33 #include "mhd_compat.h"
34 #include "mhd_assert.h"
35 
36 #if defined(MHD_W32_MUTEX_)
37 #ifndef WIN32_LEAN_AND_MEAN
38 #define WIN32_LEAN_AND_MEAN 1
39 #endif /* !WIN32_LEAN_AND_MEAN */
40 #include <windows.h>
41 #endif /* MHD_W32_MUTEX_ */
42 
46 #define TIMESTAMP_BIN_SIZE 4
47 
53 #define NONCE_STD_LEN(digest_size) \
54  ((digest_size) * 2 + TIMESTAMP_BIN_SIZE * 2)
55 
56 
61 #define MAX_DIGEST SHA256_DIGEST_SIZE
62 
66 #if __STDC_NO_VLA__
72 #define VLA_ARRAY_LEN_DIGEST(n) (MAX_DIGEST)
73 
74 #else
80 #define VLA_ARRAY_LEN_DIGEST(n) (n)
81 #endif
82 
86 #define VLA_CHECK_LEN_DIGEST(n) do { if ((n) > MAX_DIGEST) mhd_panic ( \
87  mhd_panic_cls, __FILE__, __LINE__, \
88  "VLA too big.\n"); } while (0)
89 
90 
94 #define _BASE "Digest "
95 
99 #define MAX_USERNAME_LENGTH 128
100 
104 #define MAX_REALM_LENGTH 256
105 
109 #define MAX_AUTH_RESPONSE_LENGTH 256
110 
111 
117 struct DigestAlgorithm
118 {
122  unsigned int digest_size;
123 
128  void *ctx;
129 
133  const char *alg;
134 
138  char *sessionkey;
139 
143  void
144  (*init)(void *ctx);
145 
153  void
154  (*update)(void *ctx,
155  const uint8_t *data,
156  size_t length);
157 
165  void
166  (*digest)(void *ctx,
167  uint8_t *digest);
168 };
169 
170 
178 static void
179 cvthex (const unsigned char *bin,
180  size_t len,
181  char *hex)
182 {
183  size_t i;
184  unsigned int j;
185 
186  for (i = 0; i < len; ++i)
187  {
188  j = (bin[i] >> 4) & 0x0f;
189  hex[i * 2] = (char) ((j <= 9) ? (j + '0') : (j - 10 + 'a'));
190  j = bin[i] & 0x0f;
191  hex[i * 2 + 1] = (char) ((j <= 9) ? (j + '0') : (j - 10 + 'a'));
192  }
193  hex[len * 2] = '\0';
194 }
195 
196 
212 static void
214  struct DigestAlgorithm *da,
215  const uint8_t *digest,
216  const char *nonce,
217  const char *cnonce)
218 {
219  if ( (MHD_str_equal_caseless_ (alg,
220  "md5-sess")) ||
222  "sha-256-sess")) )
223  {
224  uint8_t dig[VLA_ARRAY_LEN_DIGEST (da->digest_size)];
225 
226  VLA_CHECK_LEN_DIGEST (da->digest_size);
227  da->init (da->ctx);
228  da->update (da->ctx,
229  digest,
231  da->update (da->ctx,
232  (const unsigned char *) ":",
233  1);
234  da->update (da->ctx,
235  (const unsigned char *) nonce,
236  strlen (nonce));
237  da->update (da->ctx,
238  (const unsigned char *) ":",
239  1);
240  da->update (da->ctx,
241  (const unsigned char *) cnonce,
242  strlen (cnonce));
243  da->digest (da->ctx,
244  dig);
245  cvthex (dig,
246  sizeof (dig),
247  da->sessionkey);
248  }
249  else
250  {
251  cvthex (digest,
252  da->digest_size,
253  da->sessionkey);
254  }
255 }
256 
257 
272 static void
273 digest_calc_ha1_from_user (const char *alg,
274  const char *username,
275  const char *realm,
276  const char *password,
277  const char *nonce,
278  const char *cnonce,
279  struct DigestAlgorithm *da)
280 {
281  unsigned char ha1[VLA_ARRAY_LEN_DIGEST (da->digest_size)];
282 
283  VLA_CHECK_LEN_DIGEST (da->digest_size);
284  da->init (da->ctx);
285  da->update (da->ctx,
286  (const unsigned char *) username,
287  strlen (username));
288  da->update (da->ctx,
289  (const unsigned char *) ":",
290  1);
291  da->update (da->ctx,
292  (const unsigned char *) realm,
293  strlen (realm));
294  da->update (da->ctx,
295  (const unsigned char *) ":",
296  1);
297  da->update (da->ctx,
298  (const unsigned char *) password,
299  strlen (password));
300  da->digest (da->ctx,
301  ha1);
303  da,
304  ha1,
305  nonce,
306  cnonce);
307 }
308 
309 
326 static void
327 digest_calc_response (const char *ha1,
328  const char *nonce,
329  const char *noncecount,
330  const char *cnonce,
331  const char *qop,
332  const char *method,
333  const char *uri,
334  const char *hentity,
335  struct DigestAlgorithm *da)
336 {
337  unsigned char ha2[VLA_ARRAY_LEN_DIGEST (da->digest_size)];
338  unsigned char resphash[VLA_ARRAY_LEN_DIGEST (da->digest_size)];
339  (void) hentity; /* Unused. Silence compiler warning. */
340 
341  VLA_CHECK_LEN_DIGEST (da->digest_size);
342  da->init (da->ctx);
343  da->update (da->ctx,
344  (const unsigned char *) method,
345  strlen (method));
346  da->update (da->ctx,
347  (const unsigned char *) ":",
348  1);
349  da->update (da->ctx,
350  (const unsigned char *) uri,
351  strlen (uri));
352 #if 0
353  if (0 == strcasecmp (qop,
354  "auth-int"))
355  {
356  /* This is dead code since the rest of this module does
357  not support auth-int. */
358  da->update (da->ctx,
359  ":",
360  1);
361  if (NULL != hentity)
362  da->update (da->ctx,
363  hentity,
364  strlen (hentity));
365  }
366 #endif
367  da->digest (da->ctx,
368  ha2);
369  cvthex (ha2,
370  da->digest_size,
371  da->sessionkey);
372  da->init (da->ctx);
373  /* calculate response */
374  da->update (da->ctx,
375  (const unsigned char *) ha1,
376  da->digest_size * 2);
377  da->update (da->ctx,
378  (const unsigned char *) ":",
379  1);
380  da->update (da->ctx,
381  (const unsigned char *) nonce,
382  strlen (nonce));
383  da->update (da->ctx,
384  (const unsigned char*) ":",
385  1);
386  if ('\0' != *qop)
387  {
388  da->update (da->ctx,
389  (const unsigned char *) noncecount,
390  strlen (noncecount));
391  da->update (da->ctx,
392  (const unsigned char *) ":",
393  1);
394  da->update (da->ctx,
395  (const unsigned char *) cnonce,
396  strlen (cnonce));
397  da->update (da->ctx,
398  (const unsigned char *) ":",
399  1);
400  da->update (da->ctx,
401  (const unsigned char *) qop,
402  strlen (qop));
403  da->update (da->ctx,
404  (const unsigned char *) ":",
405  1);
406  }
407  da->update (da->ctx,
408  (const unsigned char *) da->sessionkey,
409  da->digest_size * 2);
410  da->digest (da->ctx,
411  resphash);
412  cvthex (resphash,
413  sizeof(resphash),
414  da->sessionkey);
415 }
416 
417 
432 static size_t
433 lookup_sub_value (char *dest,
434  size_t size,
435  const char *data,
436  const char *key)
437 {
438  size_t keylen;
439  size_t len;
440  const char *ptr;
441  const char *eq;
442  const char *q1;
443  const char *q2;
444  const char *qn;
445 
446  if (0 == size)
447  return 0;
448  keylen = strlen (key);
449  ptr = data;
450  while ('\0' != *ptr)
451  {
452  if (NULL == (eq = strchr (ptr,
453  '=')))
454  return 0;
455  q1 = eq + 1;
456  while (' ' == *q1)
457  q1++;
458  if ('\"' != *q1)
459  {
460  q2 = strchr (q1,
461  ',');
462  qn = q2;
463  }
464  else
465  {
466  q1++;
467  q2 = strchr (q1,
468  '\"');
469  if (NULL == q2)
470  return 0; /* end quote not found */
471  qn = q2 + 1;
472  }
473  if ( (MHD_str_equal_caseless_n_ (ptr,
474  key,
475  keylen)) &&
476  (eq == &ptr[keylen]) )
477  {
478  if (NULL == q2)
479  {
480  len = strlen (q1) + 1;
481  if (size > len)
482  size = len;
483  size--;
484  memcpy (dest,
485  q1,
486  size);
487  dest[size] = '\0';
488  return size;
489  }
490  else
491  {
492  if (size > (size_t) ((q2 - q1) + 1))
493  size = (q2 - q1) + 1;
494  size--;
495  memcpy (dest,
496  q1,
497  size);
498  dest[size] = '\0';
499  return size;
500  }
501  }
502  if (NULL == qn)
503  return 0;
504  ptr = strchr (qn,
505  ',');
506  if (NULL == ptr)
507  return 0;
508  ptr++;
509  while (' ' == *ptr)
510  ptr++;
511  }
512  return 0;
513 }
514 
515 
525 static enum MHD_Result
526 check_nonce_nc (struct MHD_Connection *connection,
527  const char *nonce,
528  uint64_t nc)
529 {
530  struct MHD_Daemon *daemon = connection->daemon;
531  struct MHD_NonceNc *nn;
532  uint32_t off;
533  uint32_t mod;
534  const char *np;
535  size_t noncelen;
536 
537  noncelen = strlen (nonce) + 1;
538  if (MAX_NONCE_LENGTH < noncelen)
539  return MHD_NO; /* This should be impossible, but static analysis
540  tools have a hard time with it *and* this also
541  protects against unsafe modifications that may
542  happen in the future... */
543  mod = daemon->nonce_nc_size;
544  if (0 == mod)
545  return MHD_NO; /* no array! */
546  /* super-fast xor-based "hash" function for HT lookup in nonce array */
547  off = 0;
548  np = nonce;
549  while ('\0' != *np)
550  {
551  off = (off << 8) | (*np ^ (off >> 24));
552  np++;
553  }
554  off = off % mod;
555  /*
556  * Look for the nonce, if it does exist and its corresponding
557  * nonce counter is less than the current nonce counter by 1,
558  * then only increase the nonce counter by one.
559  */
560  nn = &daemon->nnc[off];
561 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
562  MHD_mutex_lock_chk_ (&daemon->nnc_lock);
563 #endif
564  if (0 == nc)
565  {
566  /* Fresh nonce, reinitialize array */
567  memcpy (nn->nonce,
568  nonce,
569  noncelen);
570  nn->nc = 0;
571  nn->nmask = 0;
572 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
573  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
574 #endif
575  return MHD_YES;
576  }
577  /* Note that we use 64 here, as we do not store the
578  bit for 'nn->nc' itself in 'nn->nmask' */
579  if ( (nc < nn->nc) &&
580  (nc + 64 > nc /* checking for overflow */) &&
581  (nc + 64 >= nn->nc) &&
582  (0 == ((1LLU << (nn->nc - nc - 1)) & nn->nmask)) )
583  {
584  /* Out-of-order nonce, but within 64-bit bitmask, set bit */
585  nn->nmask |= (1LLU << (nn->nc - nc - 1));
586 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
587  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
588 #endif
589  return MHD_YES;
590  }
591 
592  if ( (nc <= nn->nc) ||
593  (0 != strcmp (nn->nonce,
594  nonce)) )
595  {
596  /* Nonce does not match, fail */
597 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
598  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
599 #endif
600 #ifdef HAVE_MESSAGES
601  MHD_DLOG (daemon,
602  _ (
603  "Stale nonce received. If this happens a lot, you should probably increase the size of the nonce array.\n"));
604 #endif
605  return MHD_NO;
606  }
607  /* Nonce is larger, shift bitmask and bump limit */
608  if (64 > nc - nn->nc)
609  nn->nmask <<= (nc - nn->nc); /* small jump, less than mask width */
610  else
611  nn->nmask = 0; /* big jump, unset all bits in the mask */
612  nn->nc = nc;
613 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
614  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
615 #endif
616  return MHD_YES;
617 }
618 
619 
629 char *
631 {
632  size_t len;
633  char user[MAX_USERNAME_LENGTH];
634  const char *header;
635 
636  if (MHD_NO == MHD_lookup_connection_value_n (connection,
641  &header,
642  NULL))
643  return NULL;
644  if (0 != strncmp (header,
645  _BASE,
647  return NULL;
648  header += MHD_STATICSTR_LEN_ (_BASE);
649  if (0 == (len = lookup_sub_value (user,
650  sizeof (user),
651  header,
652  "username")))
653  return NULL;
654  return strdup (user);
655 }
656 
657 
673 static void
674 calculate_nonce (uint32_t nonce_time,
675  const char *method,
676  const char *rnd,
677  size_t rnd_size,
678  const char *uri,
679  const char *realm,
680  struct DigestAlgorithm *da,
681  char *nonce)
682 {
683  unsigned char timestamp[TIMESTAMP_BIN_SIZE];
684  unsigned char tmpnonce[VLA_ARRAY_LEN_DIGEST (da->digest_size)];
685  char timestamphex[TIMESTAMP_BIN_SIZE * 2 + 1];
686 
687  VLA_CHECK_LEN_DIGEST (da->digest_size);
688  da->init (da->ctx);
689  timestamp[0] = (unsigned char) ((nonce_time & 0xff000000) >> 0x18);
690  timestamp[1] = (unsigned char) ((nonce_time & 0x00ff0000) >> 0x10);
691  timestamp[2] = (unsigned char) ((nonce_time & 0x0000ff00) >> 0x08);
692  timestamp[3] = (unsigned char) ((nonce_time & 0x000000ff));
693  da->update (da->ctx,
694  timestamp,
695  sizeof (timestamp));
696  da->update (da->ctx,
697  (const unsigned char *) ":",
698  1);
699  da->update (da->ctx,
700  (const unsigned char *) method,
701  strlen (method));
702  da->update (da->ctx,
703  (const unsigned char *) ":",
704  1);
705  if (rnd_size > 0)
706  da->update (da->ctx,
707  (const unsigned char *) rnd,
708  rnd_size);
709  da->update (da->ctx,
710  (const unsigned char *) ":",
711  1);
712  da->update (da->ctx,
713  (const unsigned char *) uri,
714  strlen (uri));
715  da->update (da->ctx,
716  (const unsigned char *) ":",
717  1);
718  da->update (da->ctx,
719  (const unsigned char *) realm,
720  strlen (realm));
721  da->digest (da->ctx,
722  tmpnonce);
723  cvthex (tmpnonce,
724  sizeof (tmpnonce),
725  nonce);
726  cvthex (timestamp,
727  sizeof (timestamp),
728  timestamphex);
729  strncat (nonce,
730  timestamphex,
731  8);
732 }
733 
734 
748 static enum MHD_Result
749 test_header (struct MHD_Connection *connection,
750  const char *key,
751  size_t key_size,
752  const char *value,
753  size_t value_size,
754  enum MHD_ValueKind kind)
755 {
756  struct MHD_HTTP_Header *pos;
757 
758  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
759  {
760  if (kind != pos->kind)
761  continue;
762  if (key_size != pos->header_size)
763  continue;
764  if (value_size != pos->value_size)
765  continue;
766  if (0 != memcmp (key,
767  pos->header,
768  key_size))
769  continue;
770  if ( (NULL == value) &&
771  (NULL == pos->value) )
772  return MHD_YES;
773  if ( (NULL == value) ||
774  (NULL == pos->value) ||
775  (0 != memcmp (value,
776  pos->value,
777  value_size)) )
778  continue;
779  return MHD_YES;
780  }
781  return MHD_NO;
782 }
783 
784 
795 static enum MHD_Result
796 check_argument_match (struct MHD_Connection *connection,
797  const char *args)
798 {
799  struct MHD_HTTP_Header *pos;
800  char *argb;
801  unsigned int num_headers;
802  enum MHD_Result ret;
803 
804  argb = strdup (args);
805  if (NULL == argb)
806  {
807 #ifdef HAVE_MESSAGES
808  MHD_DLOG (connection->daemon,
809  _ ("Failed to allocate memory for copy of URI arguments.\n"));
810 #endif /* HAVE_MESSAGES */
811  return MHD_NO;
812  }
813  ret = MHD_parse_arguments_ (connection,
815  argb,
816  &test_header,
817  &num_headers);
818  free (argb);
819  if (MHD_NO == ret)
820  {
821  return MHD_NO;
822  }
823  /* also check that the number of headers matches */
824  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
825  {
826  if (MHD_GET_ARGUMENT_KIND != pos->kind)
827  continue;
828  num_headers--;
829  }
830  if (0 != num_headers)
831  {
832  /* argument count mismatch */
833  return MHD_NO;
834  }
835  return MHD_YES;
836 }
837 
838 
858 static int
860  struct DigestAlgorithm *da,
861  const char *realm,
862  const char *username,
863  const char *password,
864  const uint8_t *digest,
865  unsigned int nonce_timeout)
866 {
867  struct MHD_Daemon *daemon = connection->daemon;
868  size_t len;
869  const char *header;
870  char nonce[MAX_NONCE_LENGTH];
871  char cnonce[MAX_NONCE_LENGTH];
872  char ha1[VLA_ARRAY_LEN_DIGEST (da->digest_size) * 2 + 1];
873  char qop[15]; /* auth,auth-int */
874  char nc[20];
875  char response[MAX_AUTH_RESPONSE_LENGTH];
876  const char *hentity = NULL; /* "auth-int" is not supported */
877  char noncehashexp[NONCE_STD_LEN (VLA_ARRAY_LEN_DIGEST (da->digest_size)) + 1];
878  uint32_t nonce_time;
879  uint32_t t;
880  size_t left; /* number of characters left in 'header' for 'uri' */
881  uint64_t nci;
882  char *qmark;
883 
884  VLA_CHECK_LEN_DIGEST (da->digest_size);
885  if (MHD_NO == MHD_lookup_connection_value_n (connection,
890  &header,
891  NULL))
892  return MHD_NO;
893  if (0 != strncmp (header,
894  _BASE,
896  return MHD_NO;
897  header += MHD_STATICSTR_LEN_ (_BASE);
898  left = strlen (header);
899 
900  {
901  char un[MAX_USERNAME_LENGTH];
902 
903  len = lookup_sub_value (un,
904  sizeof (un),
905  header,
906  "username");
907  if ( (0 == len) ||
908  (0 != strcmp (username,
909  un)) )
910  return MHD_NO;
911  left -= strlen ("username") + len;
912  }
913 
914  {
915  char r[MAX_REALM_LENGTH];
916 
917  len = lookup_sub_value (r,
918  sizeof (r),
919  header,
920  "realm");
921  if ( (0 == len) ||
922  (0 != strcmp (realm,
923  r)) )
924  return MHD_NO;
925  left -= strlen ("realm") + len;
926  }
927 
928  if (0 == (len = lookup_sub_value (nonce,
929  sizeof (nonce),
930  header,
931  "nonce")))
932  return MHD_NO;
933  left -= strlen ("nonce") + len;
934  if (left > 32 * 1024)
935  {
936  /* we do not permit URIs longer than 32k, as we want to
937  make sure to not blow our stack (or per-connection
938  heap memory limit). Besides, 32k is already insanely
939  large, but of course in theory the
940  #MHD_OPTION_CONNECTION_MEMORY_LIMIT might be very large
941  and would thus permit sending a >32k authorization
942  header value. */
943  return MHD_NO;
944  }
945  if (TIMESTAMP_BIN_SIZE * 2 !=
946  MHD_strx_to_uint32_n_ (nonce + len - TIMESTAMP_BIN_SIZE * 2,
947  TIMESTAMP_BIN_SIZE * 2,
948  &nonce_time))
949  {
950 #ifdef HAVE_MESSAGES
951  MHD_DLOG (daemon,
952  _ ("Authentication failed, invalid timestamp format.\n"));
953 #endif
954  return MHD_NO;
955  }
956  t = (uint32_t) MHD_monotonic_sec_counter ();
957  /*
958  * First level vetting for the nonce validity: if the timestamp
959  * attached to the nonce exceeds `nonce_timeout', then the nonce is
960  * invalid.
961  */
962  if ( (t > nonce_time + nonce_timeout) ||
963  (nonce_time + nonce_timeout < nonce_time) )
964  {
965  /* too old */
966  return MHD_INVALID_NONCE;
967  }
968 
969  calculate_nonce (nonce_time,
970  connection->method,
971  daemon->digest_auth_random,
972  daemon->digest_auth_rand_size,
973  connection->url,
974  realm,
975  da,
976  noncehashexp);
977  /*
978  * Second level vetting for the nonce validity
979  * if the timestamp attached to the nonce is valid
980  * and possibly fabricated (in case of an attack)
981  * the attacker must also know the random seed to be
982  * able to generate a "sane" nonce, which if he does
983  * not, the nonce fabrication process going to be
984  * very hard to achieve.
985  */
986  if (0 != strcmp (nonce,
987  noncehashexp))
988  {
989  return MHD_INVALID_NONCE;
990  }
991  if ( (0 == lookup_sub_value (cnonce,
992  sizeof (cnonce),
993  header,
994  "cnonce")) ||
995  (0 == lookup_sub_value (qop,
996  sizeof (qop),
997  header,
998  "qop")) ||
999  ( (0 != strcmp (qop,
1000  "auth")) &&
1001  (0 != strcmp (qop,
1002  "")) ) ||
1003  (0 == (len = lookup_sub_value (nc,
1004  sizeof (nc),
1005  header,
1006  "nc")) ) ||
1007  (0 == lookup_sub_value (response,
1008  sizeof (response),
1009  header,
1010  "response")) )
1011  {
1012 #ifdef HAVE_MESSAGES
1013  MHD_DLOG (daemon,
1014  _ ("Authentication failed, invalid format.\n"));
1015 #endif
1016  return MHD_NO;
1017  }
1018  if (len != MHD_strx_to_uint64_n_ (nc,
1019  len,
1020  &nci))
1021  {
1022 #ifdef HAVE_MESSAGES
1023  MHD_DLOG (daemon,
1024  _ ("Authentication failed, invalid nc format.\n"));
1025 #endif
1026  return MHD_NO; /* invalid nonce format */
1027  }
1028 
1029  /*
1030  * Checking if that combination of nonce and nc is sound
1031  * and not a replay attack attempt. Also adds the nonce
1032  * to the nonce-nc map if it does not exist there.
1033  */
1034  if (MHD_NO ==
1035  check_nonce_nc (connection,
1036  nonce,
1037  nci))
1038  {
1039  return MHD_NO;
1040  }
1041 
1042  {
1043  char *uri;
1044 
1045  uri = malloc (left + 1);
1046  if (NULL == uri)
1047  {
1048 #ifdef HAVE_MESSAGES
1049  MHD_DLOG (daemon,
1050  _ ("Failed to allocate memory for auth header processing.\n"));
1051 #endif /* HAVE_MESSAGES */
1052  return MHD_NO;
1053  }
1054  if (0 == lookup_sub_value (uri,
1055  left + 1,
1056  header,
1057  "uri"))
1058  {
1059  free (uri);
1060  return MHD_NO;
1061  }
1062  if (NULL != digest)
1063  {
1064  /* This will initialize da->sessionkey (ha1) */
1065  digest_calc_ha1_from_digest (da->alg,
1066  da,
1067  digest,
1068  nonce,
1069  cnonce);
1070  }
1071  else
1072  {
1073  /* This will initialize da->sessionkey (ha1) */
1074  mhd_assert (NULL != password); /* NULL == digest => password != NULL */
1075  digest_calc_ha1_from_user (da->alg,
1076  username,
1077  realm,
1078  password,
1079  nonce,
1080  cnonce,
1081  da);
1082  }
1083  memcpy (ha1,
1084  da->sessionkey,
1085  sizeof (ha1));
1086  /* This will initialize da->sessionkey (respexp) */
1087  digest_calc_response (ha1,
1088  nonce,
1089  nc,
1090  cnonce,
1091  qop,
1092  connection->method,
1093  uri,
1094  hentity,
1095  da);
1096  qmark = strchr (uri,
1097  '?');
1098  if (NULL != qmark)
1099  *qmark = '\0';
1100 
1101  /* Need to unescape URI before comparing with connection->url */
1102  daemon->unescape_callback (daemon->unescape_callback_cls,
1103  connection,
1104  uri);
1105  if (0 != strcmp (uri,
1106  connection->url))
1107  {
1108 #ifdef HAVE_MESSAGES
1109  MHD_DLOG (daemon,
1110  _ ("Authentication failed, URI does not match.\n"));
1111 #endif
1112  free (uri);
1113  return MHD_NO;
1114  }
1115 
1116  {
1117  const char *args = qmark;
1118 
1119  if (NULL == args)
1120  args = "";
1121  else
1122  args++;
1123  if (MHD_NO ==
1124  check_argument_match (connection,
1125  args) )
1126  {
1127 #ifdef HAVE_MESSAGES
1128  MHD_DLOG (daemon,
1129  _ ("Authentication failed, arguments do not match.\n"));
1130 #endif
1131  free (uri);
1132  return MHD_NO;
1133  }
1134  }
1135  free (uri);
1136  return (0 == strcmp (response,
1137  da->sessionkey))
1138  ? MHD_YES
1139  : MHD_NO;
1140  }
1141 }
1142 
1143 
1161 _MHD_EXTERN int
1163  const char *realm,
1164  const char *username,
1165  const char *password,
1166  unsigned int nonce_timeout)
1167 {
1168  return MHD_digest_auth_check2 (connection,
1169  realm,
1170  username,
1171  password,
1172  nonce_timeout,
1174 }
1175 
1176 
1185 #define SETUP_DA(algo,da) \
1186  union { \
1187  struct MD5Context md5; \
1188  struct sha256_ctx sha256; \
1189  } ctx; \
1190  union { \
1191  char md5[MD5_DIGEST_SIZE * 2 + 1]; \
1192  char sha256[SHA256_DIGEST_SIZE * 2 + 1]; \
1193  } skey; \
1194  struct DigestAlgorithm da; \
1195  \
1196  do { \
1197  switch (algo) { \
1198  case MHD_DIGEST_ALG_MD5: \
1199  da.digest_size = MD5_DIGEST_SIZE; \
1200  da.ctx = &ctx.md5; \
1201  da.alg = "md5"; \
1202  da.sessionkey = skey.md5; \
1203  da.init = &MHD_MD5Init; \
1204  da.update = &MHD_MD5Update; \
1205  da.digest = &MHD_MD5Final; \
1206  break; \
1207  case MHD_DIGEST_ALG_AUTO: \
1208  /* auto == SHA256, fall-though thus intentional! */ \
1209  case MHD_DIGEST_ALG_SHA256: \
1210  da.digest_size = SHA256_DIGEST_SIZE; \
1211  da.ctx = &ctx.sha256; \
1212  da.alg = "sha-256"; \
1213  da.sessionkey = skey.sha256; \
1214  da.init = &MHD_SHA256_init; \
1215  da.update = &MHD_SHA256_update; \
1216  da.digest = &sha256_finish; \
1217  break; \
1218  default: \
1219  mhd_assert (false); \
1220  break; \
1221  } \
1222  } while (0)
1223 
1224 
1239 _MHD_EXTERN int
1241  const char *realm,
1242  const char *username,
1243  const char *password,
1244  unsigned int nonce_timeout,
1245  enum MHD_DigestAuthAlgorithm algo)
1246 {
1247  SETUP_DA (algo, da);
1248 
1249  mhd_assert (NULL != password);
1250  return digest_auth_check_all (connection,
1251  &da,
1252  realm,
1253  username,
1254  password,
1255  NULL,
1256  nonce_timeout);
1257 }
1258 
1259 
1277 _MHD_EXTERN int
1279  const char *realm,
1280  const char *username,
1281  const uint8_t *digest,
1282  size_t digest_size,
1283  unsigned int nonce_timeout,
1284  enum MHD_DigestAuthAlgorithm algo)
1285 {
1286  SETUP_DA (algo, da);
1287 
1288  mhd_assert (NULL != digest);
1289  if (da.digest_size != digest_size)
1290  MHD_PANIC (_ ("Digest size mismatch.\n")); /* API violation! */
1291  return digest_auth_check_all (connection,
1292  &da,
1293  realm,
1294  username,
1295  NULL,
1296  digest,
1297  nonce_timeout);
1298 }
1299 
1300 
1318 _MHD_EXTERN int
1320  const char *realm,
1321  const char *username,
1322  const uint8_t digest[MHD_MD5_DIGEST_SIZE],
1323  unsigned int nonce_timeout)
1324 {
1325  return MHD_digest_auth_check_digest2 (connection,
1326  realm,
1327  username,
1328  digest,
1330  nonce_timeout,
1332 }
1333 
1334 
1350 enum MHD_Result
1351 MHD_queue_auth_fail_response2 (struct MHD_Connection *connection,
1352  const char *realm,
1353  const char *opaque,
1354  struct MHD_Response *response,
1355  int signal_stale,
1356  enum MHD_DigestAuthAlgorithm algo)
1357 {
1358  int ret;
1359  int hlen;
1360  SETUP_DA (algo, da);
1361 
1362  {
1363  char nonce[NONCE_STD_LEN (VLA_ARRAY_LEN_DIGEST (da.digest_size)) + 1];
1364 
1365  VLA_CHECK_LEN_DIGEST (da.digest_size);
1366  /* Generating the server nonce */
1368  connection->method,
1369  connection->daemon->digest_auth_random,
1370  connection->daemon->digest_auth_rand_size,
1371  connection->url,
1372  realm,
1373  &da,
1374  nonce);
1375  if (MHD_NO ==
1376  check_nonce_nc (connection,
1377  nonce,
1378  0))
1379  {
1380 #ifdef HAVE_MESSAGES
1381  MHD_DLOG (connection->daemon,
1382  _ (
1383  "Could not register nonce (is the nonce array size zero?).\n"));
1384 #endif
1385  return MHD_NO;
1386  }
1387  /* Building the authentication header */
1388  hlen = MHD_snprintf_ (NULL,
1389  0,
1390  "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\",algorithm=%s%s",
1391  realm,
1392  nonce,
1393  opaque,
1394  da.alg,
1395  signal_stale
1396  ? ",stale=\"true\""
1397  : "");
1398  if (hlen > 0)
1399  {
1400  char *header;
1401 
1402  header = MHD_calloc_ (1,
1403  hlen + 1);
1404  if (NULL == header)
1405  {
1406 #ifdef HAVE_MESSAGES
1407  MHD_DLOG (connection->daemon,
1408  _ ("Failed to allocate memory for auth response header.\n"));
1409 #endif /* HAVE_MESSAGES */
1410  return MHD_NO;
1411  }
1412 
1413  if (MHD_snprintf_ (header,
1414  hlen + 1,
1415  "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\",algorithm=%s%s",
1416  realm,
1417  nonce,
1418  opaque,
1419  da.alg,
1420  signal_stale
1421  ? ",stale=\"true\""
1422  : "") == hlen)
1423  ret = MHD_add_response_header (response,
1425  header);
1426  else
1427  ret = MHD_NO;
1428 #if 0
1429  if ( (MHD_NO != ret) && (AND in state : 100 continue aborting ...))
1430  ret = MHD_add_response_header (response,
1432  "close");
1433 #endif
1434  free (header);
1435  }
1436  else
1437  ret = MHD_NO;
1438  }
1439 
1440  if (MHD_NO != ret)
1441  {
1442  ret = MHD_queue_response (connection,
1444  response);
1445  }
1446  else
1447  {
1448 #ifdef HAVE_MESSAGES
1449  MHD_DLOG (connection->daemon,
1450  _ ("Failed to add Digest auth header.\n"));
1451 #endif /* HAVE_MESSAGES */
1452  }
1453  return ret;
1454 }
1455 
1456 
1473 enum MHD_Result
1474 MHD_queue_auth_fail_response (struct MHD_Connection *connection,
1475  const char *realm,
1476  const char *opaque,
1477  struct MHD_Response *response,
1478  int signal_stale)
1479 {
1480  return MHD_queue_auth_fail_response2 (connection,
1481  realm,
1482  opaque,
1483  response,
1484  signal_stale,
1486 }
1487 
1488 
1489 /* end of digestauth.c */
#define VLA_CHECK_LEN_DIGEST(n)
Definition: digestauth.c:86
#define SETUP_DA(algo, da)
Definition: digestauth.c:1185
static void digest_calc_response(const char *ha1, const char *nonce, const char *noncecount, const char *cnonce, const char *qop, const char *method, const char *uri, const char *hentity, struct DigestAlgorithm *da)
Definition: digestauth.c:327
#define MAX_REALM_LENGTH
Definition: digestauth.c:104
#define NONCE_STD_LEN(digest_size)
Definition: digestauth.c:53
static enum MHD_Result check_argument_match(struct MHD_Connection *connection, const char *args)
Definition: digestauth.c:796
#define MAX_AUTH_RESPONSE_LENGTH
Definition: digestauth.c:109
#define TIMESTAMP_BIN_SIZE
Definition: digestauth.c:46
static void digest_calc_ha1_from_user(const char *alg, const char *username, const char *realm, const char *password, const char *nonce, const char *cnonce, struct DigestAlgorithm *da)
Definition: digestauth.c:273
static size_t lookup_sub_value(char *dest, size_t size, const char *data, const char *key)
Definition: digestauth.c:433
#define _BASE
Definition: digestauth.c:94
static enum MHD_Result check_nonce_nc(struct MHD_Connection *connection, const char *nonce, uint64_t nc)
Definition: digestauth.c:526
#define MAX_USERNAME_LENGTH
Definition: digestauth.c:99
static void calculate_nonce(uint32_t nonce_time, const char *method, const char *rnd, size_t rnd_size, const char *uri, const char *realm, struct DigestAlgorithm *da, char *nonce)
Definition: digestauth.c:674
static enum MHD_Result test_header(struct MHD_Connection *connection, const char *key, size_t key_size, const char *value, size_t value_size, enum MHD_ValueKind kind)
Definition: digestauth.c:749
#define VLA_ARRAY_LEN_DIGEST(n)
Definition: digestauth.c:80
static void digest_calc_ha1_from_digest(const char *alg, struct DigestAlgorithm *da, const uint8_t *digest, const char *nonce, const char *cnonce)
Definition: digestauth.c:213
static void cvthex(const unsigned char *bin, size_t len, char *hex)
Definition: digestauth.c:179
_MHD_EXTERN char * MHD_digest_auth_get_username(struct MHD_Connection *connection)
Definition: digestauth.c:630
_MHD_EXTERN int MHD_digest_auth_check2(struct MHD_Connection *connection, const char *realm, const char *username, const char *password, unsigned int nonce_timeout, enum MHD_DigestAuthAlgorithm algo)
Definition: digestauth.c:1240
_MHD_EXTERN enum MHD_Result MHD_queue_auth_fail_response2(struct MHD_Connection *connection, const char *realm, const char *opaque, struct MHD_Response *response, int signal_stale, enum MHD_DigestAuthAlgorithm algo)
Definition: digestauth.c:1351
_MHD_EXTERN int MHD_digest_auth_check_digest2(struct MHD_Connection *connection, const char *realm, const char *username, const uint8_t *digest, size_t digest_size, unsigned int nonce_timeout, enum MHD_DigestAuthAlgorithm algo)
Definition: digestauth.c:1278
_MHD_EXTERN enum MHD_Result MHD_queue_auth_fail_response(struct MHD_Connection *connection, const char *realm, const char *opaque, struct MHD_Response *response, int signal_stale)
Definition: digestauth.c:1474
static int digest_auth_check_all(struct MHD_Connection *connection, struct DigestAlgorithm *da, const char *realm, const char *username, const char *password, const uint8_t *digest, unsigned int nonce_timeout)
Definition: digestauth.c:859
_MHD_EXTERN int MHD_digest_auth_check_digest(struct MHD_Connection *connection, const char *realm, const char *username, const uint8_t digest[MHD_MD5_DIGEST_SIZE], unsigned int nonce_timeout)
Definition: digestauth.c:1319
_MHD_EXTERN int MHD_digest_auth_check(struct MHD_Connection *connection, const char *realm, const char *username, const char *password, unsigned int nonce_timeout)
Definition: digestauth.c:1162
#define MHD_INVALID_NONCE
Definition: microhttpd.h:3537
#define MHD_HTTP_HEADER_CONNECTION
Definition: microhttpd.h:569
#define MHD_HTTP_HEADER_AUTHORIZATION
Definition: microhttpd.h:563
#define MHD_HTTP_HEADER_WWW_AUTHENTICATE
Definition: microhttpd.h:641
#define MHD_HTTP_UNAUTHORIZED
Definition: microhttpd.h:387
_MHD_EXTERN enum MHD_Result MHD_lookup_connection_value_n(struct MHD_Connection *connection, enum MHD_ValueKind kind, const char *key, size_t key_size, const char **value_ptr, size_t *value_size_ptr)
Definition: connection.c:460
_MHD_EXTERN enum MHD_Result MHD_queue_response(struct MHD_Connection *connection, unsigned int status_code, struct MHD_Response *response)
Definition: connection.c:3919
_MHD_EXTERN enum MHD_Result MHD_add_response_header(struct MHD_Response *response, const char *header, const char *content)
Definition: response.c:133
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 MHD_mutex_unlock_chk_(pmutex)
Definition: mhd_locks.h:180
#define MHD_mutex_lock_chk_(pmutex)
Definition: mhd_locks.h:154
time_t MHD_monotonic_sec_counter(void)
int MHD_str_equal_caseless_(const char *str1, const char *str2)
Definition: mhd_str.c:346
size_t MHD_strx_to_uint64_n_(const char *str, size_t maxlen, uint64_t *out_val)
Definition: mhd_str.c:692
int MHD_str_equal_caseless_n_(const char *const str1, const char *const str2, size_t maxlen)
Definition: mhd_str.c:378
size_t MHD_strx_to_uint32_n_(const char *str, size_t maxlen, uint32_t *out_val)
Definition: mhd_str.c:605
#define MHD_STATICSTR_LEN_(macro)
Definition: mhd_str.h:45
#define NULL
Definition: reason_phrase.c:30
#define _(String)
Definition: mhd_options.h:42
#define _MHD_EXTERN
Definition: mhd_options.h:50
internal shared structures
#define MAX_NONCE_LENGTH
Definition: internal.h:265
macros for mhd_assert()
Header for platform missing functions.
limits values definitions
internal monotonic clock functions implementations
Header for string manipulating helpers.
MHD_Result
Definition: microhttpd.h:142
@ MHD_YES
Definition: microhttpd.h:151
@ MHD_NO
Definition: microhttpd.h:146
void * data
Definition: microhttpd.h:3053
MHD_ValueKind
Definition: microhttpd.h:1781
@ MHD_HEADER_KIND
Definition: microhttpd.h:1796
@ MHD_GET_ARGUMENT_KIND
Definition: microhttpd.h:1817
MHD_DigestAuthAlgorithm
Definition: microhttpd.h:3568
@ MHD_DIGEST_ALG_MD5
Definition: microhttpd.h:3578
#define MHD_MD5_DIGEST_SIZE
Definition: microhttpd.h:323
platform-specific includes for libmicrohttpd
Calculation of SHA-256 digest.
const char * url
Definition: internal.h:768
struct MHD_HTTP_Header * headers_received
Definition: internal.h:720
char * method
Definition: internal.h:762
struct MHD_Daemon * daemon
Definition: internal.h:675
void * unescape_callback_cls
Definition: internal.h:1517
UnescapeCallback unescape_callback
Definition: internal.h:1512
size_t value_size
Definition: internal.h:335
char * header
Definition: internal.h:347
enum MHD_ValueKind kind
Definition: internal.h:358
size_t header_size
Definition: internal.h:325
struct MHD_HTTP_Header * next
Definition: internal.h:342
char * value
Definition: internal.h:352
uint64_t nc
Definition: internal.h:279
uint64_t nmask
Definition: internal.h:285
char nonce[MAX_NONCE_LENGTH]
Definition: internal.h:290