GNU libmicrohttpd  0.9.76
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 #ifndef HAVE_C_VARARRAYS
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  const unsigned int digest_size = da->digest_size;
220  if ( (MHD_str_equal_caseless_ (alg,
221  "md5-sess")) ||
223  "sha-256-sess")) )
224  {
225  uint8_t dig[VLA_ARRAY_LEN_DIGEST (digest_size)];
226 
227  VLA_CHECK_LEN_DIGEST (digest_size);
228  da->init (da->ctx);
229  da->update (da->ctx,
230  digest,
232  da->update (da->ctx,
233  (const unsigned char *) ":",
234  1);
235  da->update (da->ctx,
236  (const unsigned char *) nonce,
237  strlen (nonce));
238  da->update (da->ctx,
239  (const unsigned char *) ":",
240  1);
241  da->update (da->ctx,
242  (const unsigned char *) cnonce,
243  strlen (cnonce));
244  da->digest (da->ctx,
245  dig);
246  cvthex (dig,
247  digest_size,
248  da->sessionkey);
249  }
250  else
251  {
252  cvthex (digest,
253  digest_size,
254  da->sessionkey);
255  }
256 }
257 
258 
273 static void
274 digest_calc_ha1_from_user (const char *alg,
275  const char *username,
276  const char *realm,
277  const char *password,
278  const char *nonce,
279  const char *cnonce,
280  struct DigestAlgorithm *da)
281 {
282  unsigned char ha1[VLA_ARRAY_LEN_DIGEST (da->digest_size)];
283 
284  VLA_CHECK_LEN_DIGEST (da->digest_size);
285  da->init (da->ctx);
286  da->update (da->ctx,
287  (const unsigned char *) username,
288  strlen (username));
289  da->update (da->ctx,
290  (const unsigned char *) ":",
291  1);
292  da->update (da->ctx,
293  (const unsigned char *) realm,
294  strlen (realm));
295  da->update (da->ctx,
296  (const unsigned char *) ":",
297  1);
298  da->update (da->ctx,
299  (const unsigned char *) password,
300  strlen (password));
301  da->digest (da->ctx,
302  ha1);
304  da,
305  ha1,
306  nonce,
307  cnonce);
308 }
309 
310 
327 static void
328 digest_calc_response (const char *ha1,
329  const char *nonce,
330  const char *noncecount,
331  const char *cnonce,
332  const char *qop,
333  const char *method,
334  const char *uri,
335  const char *hentity,
336  struct DigestAlgorithm *da)
337 {
338  const unsigned int digest_size = da->digest_size;
339  unsigned char ha2[VLA_ARRAY_LEN_DIGEST (digest_size)];
340  unsigned char resphash[VLA_ARRAY_LEN_DIGEST (digest_size)];
341  (void) hentity; /* Unused. Silence compiler warning. */
342 
343  VLA_CHECK_LEN_DIGEST (digest_size);
344  da->init (da->ctx);
345  da->update (da->ctx,
346  (const unsigned char *) method,
347  strlen (method));
348  da->update (da->ctx,
349  (const unsigned char *) ":",
350  1);
351  da->update (da->ctx,
352  (const unsigned char *) uri,
353  strlen (uri));
354 #if 0
355  if (0 == strcasecmp (qop,
356  "auth-int"))
357  {
358  /* This is dead code since the rest of this module does
359  not support auth-int. */
360  da->update (da->ctx,
361  ":",
362  1);
363  if (NULL != hentity)
364  da->update (da->ctx,
365  hentity,
366  strlen (hentity));
367  }
368 #endif
369  da->digest (da->ctx,
370  ha2);
371  cvthex (ha2,
372  digest_size,
373  da->sessionkey);
374  da->init (da->ctx);
375  /* calculate response */
376  da->update (da->ctx,
377  (const unsigned char *) ha1,
378  digest_size * 2);
379  da->update (da->ctx,
380  (const unsigned char *) ":",
381  1);
382  da->update (da->ctx,
383  (const unsigned char *) nonce,
384  strlen (nonce));
385  da->update (da->ctx,
386  (const unsigned char*) ":",
387  1);
388  if ('\0' != *qop)
389  {
390  da->update (da->ctx,
391  (const unsigned char *) noncecount,
392  strlen (noncecount));
393  da->update (da->ctx,
394  (const unsigned char *) ":",
395  1);
396  da->update (da->ctx,
397  (const unsigned char *) cnonce,
398  strlen (cnonce));
399  da->update (da->ctx,
400  (const unsigned char *) ":",
401  1);
402  da->update (da->ctx,
403  (const unsigned char *) qop,
404  strlen (qop));
405  da->update (da->ctx,
406  (const unsigned char *) ":",
407  1);
408  }
409  da->update (da->ctx,
410  (const unsigned char *) da->sessionkey,
411  digest_size * 2);
412  da->digest (da->ctx,
413  resphash);
414  cvthex (resphash,
415  digest_size,
416  da->sessionkey);
417 }
418 
419 
434 static size_t
435 lookup_sub_value (char *dest,
436  size_t size,
437  const char *data,
438  const char *key)
439 {
440  size_t keylen;
441  size_t len;
442  const char *ptr;
443  const char *eq;
444  const char *q1;
445  const char *q2;
446  const char *qn;
447 
448  if (0 == size)
449  return 0;
450  keylen = strlen (key);
451  ptr = data;
452  while ('\0' != *ptr)
453  {
454  if (NULL == (eq = strchr (ptr,
455  '=')))
456  return 0;
457  q1 = eq + 1;
458  while (' ' == *q1)
459  q1++;
460  if ('\"' != *q1)
461  {
462  q2 = strchr (q1,
463  ',');
464  qn = q2;
465  }
466  else
467  {
468  q1++;
469  q2 = strchr (q1,
470  '\"');
471  if (NULL == q2)
472  return 0; /* end quote not found */
473  qn = q2 + 1;
474  }
475  if ( (MHD_str_equal_caseless_n_ (ptr,
476  key,
477  keylen)) &&
478  (eq == &ptr[keylen]) )
479  {
480  if (NULL == q2)
481  {
482  len = strlen (q1) + 1;
483  if (size > len)
484  size = len;
485  size--;
486  memcpy (dest,
487  q1,
488  size);
489  dest[size] = '\0';
490  return size;
491  }
492  else
493  {
494  if (size > (size_t) ((q2 - q1) + 1))
495  size = (q2 - q1) + 1;
496  size--;
497  memcpy (dest,
498  q1,
499  size);
500  dest[size] = '\0';
501  return size;
502  }
503  }
504  if (NULL == qn)
505  return 0;
506  ptr = strchr (qn,
507  ',');
508  if (NULL == ptr)
509  return 0;
510  ptr++;
511  while (' ' == *ptr)
512  ptr++;
513  }
514  return 0;
515 }
516 
517 
527 static enum MHD_Result
528 check_nonce_nc (struct MHD_Connection *connection,
529  const char *nonce,
530  uint64_t nc)
531 {
532  struct MHD_Daemon *daemon = connection->daemon;
533  struct MHD_NonceNc *nn;
534  uint32_t off;
535  uint32_t mod;
536  const char *np;
537  size_t noncelen;
538 
539  noncelen = strlen (nonce) + 1;
540  if (MAX_NONCE_LENGTH < noncelen)
541  return MHD_NO; /* This should be impossible, but static analysis
542  tools have a hard time with it *and* this also
543  protects against unsafe modifications that may
544  happen in the future... */
545  mod = daemon->nonce_nc_size;
546  if (0 == mod)
547  return MHD_NO; /* no array! */
548  /* super-fast xor-based "hash" function for HT lookup in nonce array */
549  off = 0;
550  np = nonce;
551  while ('\0' != *np)
552  {
553  off = (off << 8) | (*np ^ (off >> 24));
554  np++;
555  }
556  off = off % mod;
557  /*
558  * Look for the nonce, if it does exist and its corresponding
559  * nonce counter is less than the current nonce counter by 1,
560  * then only increase the nonce counter by one.
561  */
562  nn = &daemon->nnc[off];
563 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
564  MHD_mutex_lock_chk_ (&daemon->nnc_lock);
565 #endif
566  if (0 == nc)
567  {
568  /* Fresh nonce, reinitialize array */
569  memcpy (nn->nonce,
570  nonce,
571  noncelen);
572  nn->nc = 0;
573  nn->nmask = 0;
574 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
575  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
576 #endif
577  return MHD_YES;
578  }
579  /* Note that we use 64 here, as we do not store the
580  bit for 'nn->nc' itself in 'nn->nmask' */
581  if ( (nc < nn->nc) &&
582  (nc + 64 > nc /* checking for overflow */) &&
583  (nc + 64 >= nn->nc) &&
584  (0 == ((1LLU << (nn->nc - nc - 1)) & nn->nmask)) )
585  {
586  /* Out-of-order nonce, but within 64-bit bitmask, set bit */
587  nn->nmask |= (1LLU << (nn->nc - nc - 1));
588 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
589  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
590 #endif
591  return MHD_YES;
592  }
593 
594  if ( (nc <= nn->nc) ||
595  (0 != strcmp (nn->nonce,
596  nonce)) )
597  {
598  /* Nonce does not match, fail */
599 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
600  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
601 #endif
602 #ifdef HAVE_MESSAGES
603  MHD_DLOG (daemon,
604  _ (
605  "Stale nonce received. If this happens a lot, you should probably increase the size of the nonce array.\n"));
606 #endif
607  return MHD_NO;
608  }
609  /* Nonce is larger, shift bitmask and bump limit */
610  if (64 > nc - nn->nc)
611  nn->nmask <<= (nc - nn->nc); /* small jump, less than mask width */
612  else
613  nn->nmask = 0; /* big jump, unset all bits in the mask */
614  nn->nc = nc;
615 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
616  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
617 #endif
618  return MHD_YES;
619 }
620 
621 
631 char *
633 {
634  char user[MAX_USERNAME_LENGTH];
635  const char *header;
636 
637  if (MHD_NO == MHD_lookup_connection_value_n (connection,
642  &header,
643  NULL))
644  return NULL;
645  if (0 != strncmp (header,
646  _BASE,
648  return NULL;
649  header += MHD_STATICSTR_LEN_ (_BASE);
650  if (0 == lookup_sub_value (user,
651  sizeof (user),
652  header,
653  "username"))
654  return NULL;
655  return strdup (user);
656 }
657 
658 
674 static void
675 calculate_nonce (uint32_t nonce_time,
676  const char *method,
677  const char *rnd,
678  size_t rnd_size,
679  const char *uri,
680  const char *realm,
681  struct DigestAlgorithm *da,
682  char *nonce)
683 {
684  unsigned char timestamp[TIMESTAMP_BIN_SIZE];
685  const unsigned int digest_size = da->digest_size;
686  unsigned char tmpnonce[VLA_ARRAY_LEN_DIGEST (digest_size)];
687 
688  VLA_CHECK_LEN_DIGEST (digest_size);
689  da->init (da->ctx);
690  timestamp[0] = (unsigned char) ((nonce_time & 0xff000000) >> 0x18);
691  timestamp[1] = (unsigned char) ((nonce_time & 0x00ff0000) >> 0x10);
692  timestamp[2] = (unsigned char) ((nonce_time & 0x0000ff00) >> 0x08);
693  timestamp[3] = (unsigned char) ((nonce_time & 0x000000ff));
694  da->update (da->ctx,
695  timestamp,
696  sizeof (timestamp));
697  da->update (da->ctx,
698  (const unsigned char *) ":",
699  1);
700  da->update (da->ctx,
701  (const unsigned char *) method,
702  strlen (method));
703  da->update (da->ctx,
704  (const unsigned char *) ":",
705  1);
706  if (rnd_size > 0)
707  da->update (da->ctx,
708  (const unsigned char *) rnd,
709  rnd_size);
710  da->update (da->ctx,
711  (const unsigned char *) ":",
712  1);
713  da->update (da->ctx,
714  (const unsigned char *) uri,
715  strlen (uri));
716  da->update (da->ctx,
717  (const unsigned char *) ":",
718  1);
719  da->update (da->ctx,
720  (const unsigned char *) realm,
721  strlen (realm));
722  da->digest (da->ctx,
723  tmpnonce);
724  cvthex (tmpnonce,
725  digest_size,
726  nonce);
727  cvthex (timestamp,
728  sizeof (timestamp),
729  nonce + digest_size * 2);
730 }
731 
732 
746 static enum MHD_Result
747 test_header (struct MHD_Connection *connection,
748  const char *key,
749  size_t key_size,
750  const char *value,
751  size_t value_size,
752  enum MHD_ValueKind kind)
753 {
754  struct MHD_HTTP_Header *pos;
755 
756  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
757  {
758  if (kind != pos->kind)
759  continue;
760  if (key_size != pos->header_size)
761  continue;
762  if (value_size != pos->value_size)
763  continue;
764  if (0 != memcmp (key,
765  pos->header,
766  key_size))
767  continue;
768  if ( (NULL == value) &&
769  (NULL == pos->value) )
770  return MHD_YES;
771  if ( (NULL == value) ||
772  (NULL == pos->value) ||
773  (0 != memcmp (value,
774  pos->value,
775  value_size)) )
776  continue;
777  return MHD_YES;
778  }
779  return MHD_NO;
780 }
781 
782 
793 static enum MHD_Result
794 check_argument_match (struct MHD_Connection *connection,
795  const char *args)
796 {
797  struct MHD_HTTP_Header *pos;
798  char *argb;
799  unsigned int num_headers;
800  enum MHD_Result ret;
801 
802  argb = strdup (args);
803  if (NULL == argb)
804  {
805 #ifdef HAVE_MESSAGES
806  MHD_DLOG (connection->daemon,
807  _ ("Failed to allocate memory for copy of URI arguments.\n"));
808 #endif /* HAVE_MESSAGES */
809  return MHD_NO;
810  }
811  ret = MHD_parse_arguments_ (connection,
813  argb,
814  &test_header,
815  &num_headers);
816  free (argb);
817  if (MHD_NO == ret)
818  {
819  return MHD_NO;
820  }
821  /* also check that the number of headers matches */
822  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
823  {
824  if (MHD_GET_ARGUMENT_KIND != pos->kind)
825  continue;
826  num_headers--;
827  }
828  if (0 != num_headers)
829  {
830  /* argument count mismatch */
831  return MHD_NO;
832  }
833  return MHD_YES;
834 }
835 
836 
856 static int
858  struct DigestAlgorithm *da,
859  const char *realm,
860  const char *username,
861  const char *password,
862  const uint8_t *digest,
863  unsigned int nonce_timeout)
864 {
865  struct MHD_Daemon *daemon = connection->daemon;
866  size_t len;
867  const char *header;
868  char nonce[MAX_NONCE_LENGTH];
869  char cnonce[MAX_NONCE_LENGTH];
870  const unsigned int digest_size = da->digest_size;
871  char ha1[VLA_ARRAY_LEN_DIGEST (digest_size) * 2 + 1];
872  char qop[15]; /* auth,auth-int */
873  char nc[20];
874  char response[MAX_AUTH_RESPONSE_LENGTH];
875  const char *hentity = NULL; /* "auth-int" is not supported */
876  char noncehashexp[NONCE_STD_LEN (VLA_ARRAY_LEN_DIGEST (digest_size)) + 1];
877  uint32_t nonce_time;
878  uint32_t t;
879  size_t left; /* number of characters left in 'header' for 'uri' */
880  uint64_t nci;
881  char *qmark;
882 
883  VLA_CHECK_LEN_DIGEST (digest_size);
884  if (MHD_NO == MHD_lookup_connection_value_n (connection,
889  &header,
890  NULL))
891  return MHD_NO;
892  if (0 != strncmp (header,
893  _BASE,
895  return MHD_NO;
896  header += MHD_STATICSTR_LEN_ (_BASE);
897  left = strlen (header);
898 
899  {
900  char un[MAX_USERNAME_LENGTH];
901 
902  len = lookup_sub_value (un,
903  sizeof (un),
904  header,
905  "username");
906  if ( (0 == len) ||
907  (0 != strcmp (username,
908  un)) )
909  return MHD_NO;
910  left -= strlen ("username") + len;
911  }
912 
913  {
914  char r[MAX_REALM_LENGTH];
915 
916  len = lookup_sub_value (r,
917  sizeof (r),
918  header,
919  "realm");
920  if ( (0 == len) ||
921  (0 != strcmp (realm,
922  r)) )
923  return MHD_NO;
924  left -= strlen ("realm") + len;
925  }
926 
927  if (0 == (len = lookup_sub_value (nonce,
928  sizeof (nonce),
929  header,
930  "nonce")))
931  return MHD_NO;
932  left -= strlen ("nonce") + len;
933  if (left > 32 * 1024)
934  {
935  /* we do not permit URIs longer than 32k, as we want to
936  make sure to not blow our stack (or per-connection
937  heap memory limit). Besides, 32k is already insanely
938  large, but of course in theory the
939  #MHD_OPTION_CONNECTION_MEMORY_LIMIT might be very large
940  and would thus permit sending a >32k authorization
941  header value. */
942  return MHD_NO;
943  }
944  if (TIMESTAMP_BIN_SIZE * 2 !=
945  MHD_strx_to_uint32_n_ (nonce + len - TIMESTAMP_BIN_SIZE * 2,
946  TIMESTAMP_BIN_SIZE * 2,
947  &nonce_time))
948  {
949 #ifdef HAVE_MESSAGES
950  MHD_DLOG (daemon,
951  _ ("Authentication failed, invalid timestamp format.\n"));
952 #endif
953  return MHD_NO;
954  }
955  t = (uint32_t) MHD_monotonic_sec_counter ();
956  /*
957  * First level vetting for the nonce validity: if the timestamp
958  * attached to the nonce exceeds `nonce_timeout', then the nonce is
959  * invalid.
960  */
961  if ( (t > nonce_time + nonce_timeout) ||
962  (nonce_time + nonce_timeout < nonce_time) )
963  {
964  /* too old */
965  return MHD_INVALID_NONCE;
966  }
967 
968  calculate_nonce (nonce_time,
969  connection->method,
970  daemon->digest_auth_random,
971  daemon->digest_auth_rand_size,
972  connection->url,
973  realm,
974  da,
975  noncehashexp);
976  /*
977  * Second level vetting for the nonce validity
978  * if the timestamp attached to the nonce is valid
979  * and possibly fabricated (in case of an attack)
980  * the attacker must also know the random seed to be
981  * able to generate a "sane" nonce, which if he does
982  * not, the nonce fabrication process going to be
983  * very hard to achieve.
984  */
985  if (0 != strcmp (nonce,
986  noncehashexp))
987  {
988  return MHD_INVALID_NONCE;
989  }
990  if ( (0 == lookup_sub_value (cnonce,
991  sizeof (cnonce),
992  header,
993  "cnonce")) ||
994  (0 == lookup_sub_value (qop,
995  sizeof (qop),
996  header,
997  "qop")) ||
998  ( (0 != strcmp (qop,
999  "auth")) &&
1000  (0 != strcmp (qop,
1001  "")) ) ||
1002  (0 == (len = lookup_sub_value (nc,
1003  sizeof (nc),
1004  header,
1005  "nc")) ) ||
1006  (0 == lookup_sub_value (response,
1007  sizeof (response),
1008  header,
1009  "response")) )
1010  {
1011 #ifdef HAVE_MESSAGES
1012  MHD_DLOG (daemon,
1013  _ ("Authentication failed, invalid format.\n"));
1014 #endif
1015  return MHD_NO;
1016  }
1017  if (len != MHD_strx_to_uint64_n_ (nc,
1018  len,
1019  &nci))
1020  {
1021 #ifdef HAVE_MESSAGES
1022  MHD_DLOG (daemon,
1023  _ ("Authentication failed, invalid nc format.\n"));
1024 #endif
1025  return MHD_NO; /* invalid nonce format */
1026  }
1027 
1028  /*
1029  * Checking if that combination of nonce and nc is sound
1030  * and not a replay attack attempt. Also adds the nonce
1031  * to the nonce-nc map if it does not exist there.
1032  */
1033  if (MHD_NO ==
1034  check_nonce_nc (connection,
1035  nonce,
1036  nci))
1037  {
1038  return MHD_NO;
1039  }
1040 
1041  {
1042  char *uri;
1043 
1044  uri = malloc (left + 1);
1045  if (NULL == uri)
1046  {
1047 #ifdef HAVE_MESSAGES
1048  MHD_DLOG (daemon,
1049  _ ("Failed to allocate memory for auth header processing.\n"));
1050 #endif /* HAVE_MESSAGES */
1051  return MHD_NO;
1052  }
1053  if (0 == lookup_sub_value (uri,
1054  left + 1,
1055  header,
1056  "uri"))
1057  {
1058  free (uri);
1059  return MHD_NO;
1060  }
1061  if (NULL != digest)
1062  {
1063  /* This will initialize da->sessionkey (ha1) */
1064  digest_calc_ha1_from_digest (da->alg,
1065  da,
1066  digest,
1067  nonce,
1068  cnonce);
1069  }
1070  else
1071  {
1072  /* This will initialize da->sessionkey (ha1) */
1073  mhd_assert (NULL != password); /* NULL == digest => password != NULL */
1074  digest_calc_ha1_from_user (da->alg,
1075  username,
1076  realm,
1077  password,
1078  nonce,
1079  cnonce,
1080  da);
1081  }
1082  memcpy (ha1,
1083  da->sessionkey,
1084  digest_size * 2 + 1);
1085  /* This will initialize da->sessionkey (respexp) */
1086  digest_calc_response (ha1,
1087  nonce,
1088  nc,
1089  cnonce,
1090  qop,
1091  connection->method,
1092  uri,
1093  hentity,
1094  da);
1095  qmark = strchr (uri,
1096  '?');
1097  if (NULL != qmark)
1098  *qmark = '\0';
1099 
1100  /* Need to unescape URI before comparing with connection->url */
1101  daemon->unescape_callback (daemon->unescape_callback_cls,
1102  connection,
1103  uri);
1104  if (0 != strcmp (uri,
1105  connection->url))
1106  {
1107 #ifdef HAVE_MESSAGES
1108  MHD_DLOG (daemon,
1109  _ ("Authentication failed, URI does not match.\n"));
1110 #endif
1111  free (uri);
1112  return MHD_NO;
1113  }
1114 
1115  {
1116  const char *args = qmark;
1117 
1118  if (NULL == args)
1119  args = "";
1120  else
1121  args++;
1122  if (MHD_NO ==
1123  check_argument_match (connection,
1124  args) )
1125  {
1126 #ifdef HAVE_MESSAGES
1127  MHD_DLOG (daemon,
1128  _ ("Authentication failed, arguments do not match.\n"));
1129 #endif
1130  free (uri);
1131  return MHD_NO;
1132  }
1133  }
1134  free (uri);
1135  return (0 == strcmp (response,
1136  da->sessionkey))
1137  ? MHD_YES
1138  : MHD_NO;
1139  }
1140 }
1141 
1142 
1160 _MHD_EXTERN int
1162  const char *realm,
1163  const char *username,
1164  const char *password,
1165  unsigned int nonce_timeout)
1166 {
1167  return MHD_digest_auth_check2 (connection,
1168  realm,
1169  username,
1170  password,
1171  nonce_timeout,
1173 }
1174 
1175 
1184 #define SETUP_DA(algo,da) \
1185  union { \
1186  struct MD5Context md5; \
1187  struct sha256_ctx sha256; \
1188  } ctx; \
1189  union { \
1190  char md5[MD5_DIGEST_SIZE * 2 + 1]; \
1191  char sha256[SHA256_DIGEST_SIZE * 2 + 1]; \
1192  } skey; \
1193  struct DigestAlgorithm da; \
1194  \
1195  do { \
1196  switch (algo) { \
1197  case MHD_DIGEST_ALG_MD5: \
1198  da.digest_size = MD5_DIGEST_SIZE; \
1199  da.ctx = &ctx.md5; \
1200  da.alg = "md5"; \
1201  da.sessionkey = skey.md5; \
1202  da.init = &MHD_MD5Init; \
1203  da.update = &MHD_MD5Update; \
1204  da.digest = &MHD_MD5Final; \
1205  break; \
1206  case MHD_DIGEST_ALG_AUTO: \
1207  /* auto == SHA256, fall-though thus intentional! */ \
1208  case MHD_DIGEST_ALG_SHA256: \
1209  da.digest_size = SHA256_DIGEST_SIZE; \
1210  da.ctx = &ctx.sha256; \
1211  da.alg = "sha-256"; \
1212  da.sessionkey = skey.sha256; \
1213  da.init = &MHD_SHA256_init; \
1214  da.update = &MHD_SHA256_update; \
1215  da.digest = &MHD_SHA256_finish; \
1216  break; \
1217  default: \
1218  da.digest_size = 0; \
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:1184
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:328
#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:794
#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:274
static size_t lookup_sub_value(char *dest, size_t size, const char *data, const char *key)
Definition: digestauth.c:435
#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:528
#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:675
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:747
#define VLA_ARRAY_LEN_DIGEST(n)
Definition: digestauth.c:72
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:632
_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:857
_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:1161
#define MHD_INVALID_NONCE
Definition: microhttpd.h:4064
#define MHD_HTTP_HEADER_CONNECTION
Definition: microhttpd.h:606
#define MHD_HTTP_HEADER_AUTHORIZATION
Definition: microhttpd.h:598
#define MHD_HTTP_HEADER_WWW_AUTHENTICATE
Definition: microhttpd.h:686
#define MHD_HTTP_UNAUTHORIZED
Definition: microhttpd.h:399
_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:649
_MHD_EXTERN enum MHD_Result MHD_queue_response(struct MHD_Connection *connection, unsigned int status_code, struct MHD_Response *response)
Definition: connection.c:5099
_MHD_EXTERN enum MHD_Result MHD_add_response_header(struct MHD_Response *response, const char *header, const char *content)
Definition: response.c:493
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
MHD internal shared structures.
#define MAX_NONCE_LENGTH
Definition: internal.h:277
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:158
@ MHD_YES
Definition: microhttpd.h:167
@ MHD_NO
Definition: microhttpd.h:162
void * data
Definition: microhttpd.h:3428
MHD_ValueKind
Definition: microhttpd.h:1978
@ MHD_HEADER_KIND
Definition: microhttpd.h:1993
@ MHD_GET_ARGUMENT_KIND
Definition: microhttpd.h:2014
MHD_DigestAuthAlgorithm
Definition: microhttpd.h:4095
@ MHD_DIGEST_ALG_MD5
Definition: microhttpd.h:4105
#define MHD_MD5_DIGEST_SIZE
Definition: microhttpd.h:335
platform-specific includes for libmicrohttpd
Calculation of SHA-256 digest.
const char * url
Definition: internal.h:1011
struct MHD_HTTP_Header * headers_received
Definition: internal.h:958
char * method
Definition: internal.h:1000
struct MHD_Daemon * daemon
Definition: internal.h:675
void * unescape_callback_cls
Definition: internal.h:1811
UnescapeCallback unescape_callback
Definition: internal.h:1806
size_t value_size
Definition: internal.h:352
char * header
Definition: internal.h:347
enum MHD_ValueKind kind
Definition: internal.h:358
size_t header_size
Definition: internal.h:342
struct MHD_HTTP_Header * next
Definition: internal.h:342
char * value
Definition: internal.h:352
uint64_t nc
Definition: internal.h:291
uint64_t nmask
Definition: internal.h:297
char nonce[MAX_NONCE_LENGTH]
Definition: internal.h:302