GNU libmicrohttpd  0.9.73
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 = &sha256_finish; \
1216  break; \
1217  default: \
1218  mhd_assert (false); \
1219  break; \
1220  } \
1221  } while (0)
1222 
1223 
1238 _MHD_EXTERN int
1240  const char *realm,
1241  const char *username,
1242  const char *password,
1243  unsigned int nonce_timeout,
1244  enum MHD_DigestAuthAlgorithm algo)
1245 {
1246  SETUP_DA (algo, da);
1247 
1248  mhd_assert (NULL != password);
1249  return digest_auth_check_all (connection,
1250  &da,
1251  realm,
1252  username,
1253  password,
1254  NULL,
1255  nonce_timeout);
1256 }
1257 
1258 
1276 _MHD_EXTERN int
1278  const char *realm,
1279  const char *username,
1280  const uint8_t *digest,
1281  size_t digest_size,
1282  unsigned int nonce_timeout,
1283  enum MHD_DigestAuthAlgorithm algo)
1284 {
1285  SETUP_DA (algo, da);
1286 
1287  mhd_assert (NULL != digest);
1288  if (da.digest_size != digest_size)
1289  MHD_PANIC (_ ("Digest size mismatch.\n")); /* API violation! */
1290  return digest_auth_check_all (connection,
1291  &da,
1292  realm,
1293  username,
1294  NULL,
1295  digest,
1296  nonce_timeout);
1297 }
1298 
1299 
1317 _MHD_EXTERN int
1319  const char *realm,
1320  const char *username,
1321  const uint8_t digest[MHD_MD5_DIGEST_SIZE],
1322  unsigned int nonce_timeout)
1323 {
1324  return MHD_digest_auth_check_digest2 (connection,
1325  realm,
1326  username,
1327  digest,
1329  nonce_timeout,
1331 }
1332 
1333 
1349 enum MHD_Result
1350 MHD_queue_auth_fail_response2 (struct MHD_Connection *connection,
1351  const char *realm,
1352  const char *opaque,
1353  struct MHD_Response *response,
1354  int signal_stale,
1355  enum MHD_DigestAuthAlgorithm algo)
1356 {
1357  int ret;
1358  int hlen;
1359  SETUP_DA (algo, da);
1360 
1361  {
1362  char nonce[NONCE_STD_LEN (VLA_ARRAY_LEN_DIGEST (da.digest_size)) + 1];
1363 
1364  VLA_CHECK_LEN_DIGEST (da.digest_size);
1365  /* Generating the server nonce */
1367  connection->method,
1368  connection->daemon->digest_auth_random,
1369  connection->daemon->digest_auth_rand_size,
1370  connection->url,
1371  realm,
1372  &da,
1373  nonce);
1374  if (MHD_NO ==
1375  check_nonce_nc (connection,
1376  nonce,
1377  0))
1378  {
1379 #ifdef HAVE_MESSAGES
1380  MHD_DLOG (connection->daemon,
1381  _ (
1382  "Could not register nonce (is the nonce array size zero?).\n"));
1383 #endif
1384  return MHD_NO;
1385  }
1386  /* Building the authentication header */
1387  hlen = MHD_snprintf_ (NULL,
1388  0,
1389  "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\",algorithm=%s%s",
1390  realm,
1391  nonce,
1392  opaque,
1393  da.alg,
1394  signal_stale
1395  ? ",stale=\"true\""
1396  : "");
1397  if (hlen > 0)
1398  {
1399  char *header;
1400 
1401  header = MHD_calloc_ (1,
1402  hlen + 1);
1403  if (NULL == header)
1404  {
1405 #ifdef HAVE_MESSAGES
1406  MHD_DLOG (connection->daemon,
1407  _ ("Failed to allocate memory for auth response header.\n"));
1408 #endif /* HAVE_MESSAGES */
1409  return MHD_NO;
1410  }
1411 
1412  if (MHD_snprintf_ (header,
1413  hlen + 1,
1414  "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\",algorithm=%s%s",
1415  realm,
1416  nonce,
1417  opaque,
1418  da.alg,
1419  signal_stale
1420  ? ",stale=\"true\""
1421  : "") == hlen)
1422  ret = MHD_add_response_header (response,
1424  header);
1425  else
1426  ret = MHD_NO;
1427 #if 0
1428  if ( (MHD_NO != ret) && (AND in state : 100 continue aborting ...))
1429  ret = MHD_add_response_header (response,
1431  "close");
1432 #endif
1433  free (header);
1434  }
1435  else
1436  ret = MHD_NO;
1437  }
1438 
1439  if (MHD_NO != ret)
1440  {
1441  ret = MHD_queue_response (connection,
1443  response);
1444  }
1445  else
1446  {
1447 #ifdef HAVE_MESSAGES
1448  MHD_DLOG (connection->daemon,
1449  _ ("Failed to add Digest auth header.\n"));
1450 #endif /* HAVE_MESSAGES */
1451  }
1452  return ret;
1453 }
1454 
1455 
1472 enum MHD_Result
1473 MHD_queue_auth_fail_response (struct MHD_Connection *connection,
1474  const char *realm,
1475  const char *opaque,
1476  struct MHD_Response *response,
1477  int signal_stale)
1478 {
1479  return MHD_queue_auth_fail_response2 (connection,
1480  realm,
1481  opaque,
1482  response,
1483  signal_stale,
1485 }
1486 
1487 
1488 /* 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:1239
_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:1350
_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:1277
_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:1473
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:1318
_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:3634
#define MHD_HTTP_HEADER_CONNECTION
Definition: microhttpd.h:566
#define MHD_HTTP_HEADER_AUTHORIZATION
Definition: microhttpd.h:560
#define MHD_HTTP_HEADER_WWW_AUTHENTICATE
Definition: microhttpd.h:638
#define MHD_HTTP_UNAUTHORIZED
Definition: microhttpd.h:384
_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:512
_MHD_EXTERN enum MHD_Result MHD_queue_response(struct MHD_Connection *connection, unsigned int status_code, struct MHD_Response *response)
Definition: connection.c:4035
_MHD_EXTERN enum MHD_Result MHD_add_response_header(struct MHD_Response *response, const char *header, const char *content)
Definition: response.c:134
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:268
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:139
@ MHD_YES
Definition: microhttpd.h:148
@ MHD_NO
Definition: microhttpd.h:143
void * data
Definition: microhttpd.h:3125
MHD_ValueKind
Definition: microhttpd.h:1800
@ MHD_HEADER_KIND
Definition: microhttpd.h:1815
@ MHD_GET_ARGUMENT_KIND
Definition: microhttpd.h:1836
MHD_DigestAuthAlgorithm
Definition: microhttpd.h:3665
@ MHD_DIGEST_ALG_MD5
Definition: microhttpd.h:3675
#define MHD_MD5_DIGEST_SIZE
Definition: microhttpd.h:320
platform-specific includes for libmicrohttpd
Calculation of SHA-256 digest.
const char * url
Definition: internal.h:834
struct MHD_HTTP_Header * headers_received
Definition: internal.h:786
char * method
Definition: internal.h:828
struct MHD_Daemon * daemon
Definition: internal.h:675
void * unescape_callback_cls
Definition: internal.h:1603
UnescapeCallback unescape_callback
Definition: internal.h:1598
size_t value_size
Definition: internal.h:338
char * header
Definition: internal.h:347
enum MHD_ValueKind kind
Definition: internal.h:358
size_t header_size
Definition: internal.h:328
struct MHD_HTTP_Header * next
Definition: internal.h:342
char * value
Definition: internal.h:352
uint64_t nc
Definition: internal.h:282
uint64_t nmask
Definition: internal.h:288
char nonce[MAX_NONCE_LENGTH]
Definition: internal.h:293