GNU libmicrohttpd  0.9.61
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 */
25 #include "platform.h"
26 #include "mhd_limits.h"
27 #include "internal.h"
28 #include "md5.h"
29 #include "mhd_mono_clock.h"
30 #include "mhd_str.h"
31 #include "mhd_compat.h"
32 
33 #if defined(MHD_W32_MUTEX_)
34 #ifndef WIN32_LEAN_AND_MEAN
35 #define WIN32_LEAN_AND_MEAN 1
36 #endif /* !WIN32_LEAN_AND_MEAN */
37 #include <windows.h>
38 #endif /* MHD_W32_MUTEX_ */
39 
40 #define HASH_MD5_HEX_LEN (2 * MHD_MD5_DIGEST_SIZE)
41 /* 32 bit value is 4 bytes */
42 #define TIMESTAMP_BIN_SIZE 4
43 #define TIMESTAMP_HEX_LEN (2 * TIMESTAMP_BIN_SIZE)
44 
45 /* Standard server nonce length, not including terminating null */
46 #define NONCE_STD_LEN (HASH_MD5_HEX_LEN + TIMESTAMP_HEX_LEN)
47 
51 #define _BASE "Digest "
52 
56 #define MAX_USERNAME_LENGTH 128
57 
61 #define MAX_REALM_LENGTH 256
62 
66 #define MAX_AUTH_RESPONSE_LENGTH 128
67 
68 
76 static void
77 cvthex (const unsigned char *bin,
78  size_t len,
79  char *hex)
80 {
81  size_t i;
82  unsigned int j;
83 
84  for (i = 0; i < len; ++i)
85  {
86  j = (bin[i] >> 4) & 0x0f;
87  hex[i * 2] = (char)((j <= 9) ? (j + '0') : (j - 10 + 'a'));
88  j = bin[i] & 0x0f;
89  hex[i * 2 + 1] = (char)((j <= 9) ? (j + '0') : (j - 10 + 'a'));
90  }
91  hex[len * 2] = '\0';
92 }
93 
94 
107 static void
109  const uint8_t digest[MHD_MD5_DIGEST_SIZE],
110  const char *nonce,
111  const char *cnonce,
112  char sessionkey[HASH_MD5_HEX_LEN + 1])
113 {
114  struct MD5Context md5;
115 
116  if (MHD_str_equal_caseless_(alg,
117  "md5-sess"))
118  {
119  unsigned char ha1[MHD_MD5_DIGEST_SIZE];
120 
121  MD5Init (&md5);
122  MD5Update (&md5,
123  digest,
125  MD5Update (&md5,
126  (const unsigned char *) ":",
127  1);
128  MD5Update (&md5,
129  (const unsigned char *) nonce,
130  strlen (nonce));
131  MD5Update (&md5,
132  (const unsigned char *) ":",
133  1);
134  MD5Update (&md5,
135  (const unsigned char *) cnonce,
136  strlen (cnonce));
137  MD5Final (ha1,
138  &md5);
139  cvthex (ha1,
140  sizeof (ha1),
141  sessionkey);
142  }
143  else
144  {
145  cvthex (digest,
147  sessionkey);
148  }
149 }
150 
151 
164 static void
165 digest_calc_ha1_from_user (const char *alg,
166  const char *username,
167  const char *realm,
168  const char *password,
169  const char *nonce,
170  const char *cnonce,
171  char sessionkey[HASH_MD5_HEX_LEN + 1])
172 {
173  struct MD5Context md5;
174  unsigned char ha1[MHD_MD5_DIGEST_SIZE];
175 
176  MD5Init (&md5);
177  MD5Update (&md5,
178  (const unsigned char *) username,
179  strlen (username));
180  MD5Update (&md5,
181  (const unsigned char *) ":",
182  1);
183  MD5Update (&md5,
184  (const unsigned char *) realm,
185  strlen (realm));
186  MD5Update (&md5,
187  (const unsigned char *) ":",
188  1);
189  MD5Update (&md5,
190  (const unsigned char *) password,
191  strlen (password));
192  MD5Final (ha1,
193  &md5);
195  ha1,
196  nonce,
197  cnonce,
198  sessionkey);
199 }
200 
201 
215 static void
217  const char *nonce,
218  const char *noncecount,
219  const char *cnonce,
220  const char *qop,
221  const char *method,
222  const char *uri,
223  const char *hentity,
224  char response[HASH_MD5_HEX_LEN + 1])
225 {
226  struct MD5Context md5;
227  unsigned char ha2[MHD_MD5_DIGEST_SIZE];
228  unsigned char resphash[MHD_MD5_DIGEST_SIZE];
229  char ha2hex[HASH_MD5_HEX_LEN + 1];
230  (void)hentity; /* Unused. Silent compiler warning. */
231 
232  MD5Init (&md5);
233  MD5Update (&md5,
234  (const unsigned char *) method,
235  strlen (method));
236  MD5Update (&md5,
237  (const unsigned char *) ":",
238  1);
239  MD5Update (&md5,
240  (const unsigned char *) uri,
241  strlen (uri));
242 #if 0
243  if (0 == strcasecmp(qop,
244  "auth-int"))
245  {
246  /* This is dead code since the rest of this module does
247  not support auth-int. */
248  MD5Update (&md5,
249  ":",
250  1);
251  if (NULL != hentity)
252  MD5Update (&md5,
253  hentity,
254  strlen (hentity));
255  }
256 #endif
257  MD5Final (ha2,
258  &md5);
259  cvthex (ha2,
261  ha2hex);
262  MD5Init (&md5);
263  /* calculate response */
264  MD5Update (&md5,
265  (const unsigned char *) ha1,
267  MD5Update (&md5,
268  (const unsigned char *) ":",
269  1);
270  MD5Update (&md5,
271  (const unsigned char *) nonce,
272  strlen (nonce));
273  MD5Update (&md5,
274  (const unsigned char*) ":",
275  1);
276  if ('\0' != *qop)
277  {
278  MD5Update (&md5,
279  (const unsigned char *) noncecount,
280  strlen (noncecount));
281  MD5Update (&md5,
282  (const unsigned char *) ":",
283  1);
284  MD5Update (&md5,
285  (const unsigned char *) cnonce,
286  strlen (cnonce));
287  MD5Update (&md5,
288  (const unsigned char *) ":",
289  1);
290  MD5Update (&md5,
291  (const unsigned char *) qop,
292  strlen (qop));
293  MD5Update (&md5,
294  (const unsigned char *) ":",
295  1);
296  }
297  MD5Update (&md5,
298  (const unsigned char *) ha2hex,
300  MD5Final (resphash,
301  &md5);
302  cvthex (resphash,
303  sizeof(resphash),
304  response);
305 }
306 
307 
322 static size_t
323 lookup_sub_value (char *dest,
324  size_t size,
325  const char *data,
326  const char *key)
327 {
328  size_t keylen;
329  size_t len;
330  const char *ptr;
331  const char *eq;
332  const char *q1;
333  const char *q2;
334  const char *qn;
335 
336  if (0 == size)
337  return 0;
338  keylen = strlen (key);
339  ptr = data;
340  while ('\0' != *ptr)
341  {
342  if (NULL == (eq = strchr (ptr,
343  '=')))
344  return 0;
345  q1 = eq + 1;
346  while (' ' == *q1)
347  q1++;
348  if ('\"' != *q1)
349  {
350  q2 = strchr (q1,
351  ',');
352  qn = q2;
353  }
354  else
355  {
356  q1++;
357  q2 = strchr (q1,
358  '\"');
359  if (NULL == q2)
360  return 0; /* end quote not found */
361  qn = q2 + 1;
362  }
363  if ( (MHD_str_equal_caseless_n_(ptr,
364  key,
365  keylen)) &&
366  (eq == &ptr[keylen]) )
367  {
368  if (NULL == q2)
369  {
370  len = strlen (q1) + 1;
371  if (size > len)
372  size = len;
373  size--;
374  strncpy (dest,
375  q1,
376  size);
377  dest[size] = '\0';
378  return size;
379  }
380  else
381  {
382  if (size > (size_t) ((q2 - q1) + 1))
383  size = (q2 - q1) + 1;
384  size--;
385  memcpy (dest,
386  q1,
387  size);
388  dest[size] = '\0';
389  return size;
390  }
391  }
392  if (NULL == qn)
393  return 0;
394  ptr = strchr (qn,
395  ',');
396  if (NULL == ptr)
397  return 0;
398  ptr++;
399  while (' ' == *ptr)
400  ptr++;
401  }
402  return 0;
403 }
404 
405 
415 static int
416 check_nonce_nc (struct MHD_Connection *connection,
417  const char *nonce,
418  uint64_t nc)
419 {
420  struct MHD_Daemon *daemon = connection->daemon;
421  struct MHD_NonceNc *nn;
422  uint32_t off;
423  uint32_t mod;
424  const char *np;
425  size_t noncelen;
426 
427  noncelen = strlen (nonce) + 1;
428  if (MAX_NONCE_LENGTH < noncelen)
429  return MHD_NO; /* This should be impossible, but static analysis
430  tools have a hard time with it *and* this also
431  protects against unsafe modifications that may
432  happen in the future... */
433  mod = daemon->nonce_nc_size;
434  if (0 == mod)
435  return MHD_NO; /* no array! */
436  /* super-fast xor-based "hash" function for HT lookup in nonce array */
437  off = 0;
438  np = nonce;
439  while ('\0' != *np)
440  {
441  off = (off << 8) | (*np ^ (off >> 24));
442  np++;
443  }
444  off = off % mod;
445  /*
446  * Look for the nonce, if it does exist and its corresponding
447  * nonce counter is less than the current nonce counter by 1,
448  * then only increase the nonce counter by one.
449  */
450  nn = &daemon->nnc[off];
451  MHD_mutex_lock_chk_ (&daemon->nnc_lock);
452  if (0 == nc)
453  {
454  /* Fresh nonce, reinitialize array */
455  memcpy (nn->nonce,
456  nonce,
457  noncelen);
458  nn->nc = 0;
459  nn->nmask = 0;
460  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
461  return MHD_YES;
462  }
463  /* Note that we use 64 here, as we do not store the
464  bit for 'nn->nc' itself in 'nn->nmask' */
465  if ( (nc < nn->nc) &&
466  (nc + 64 > nc /* checking for overflow */) &&
467  (nc + 64 >= nn->nc) &&
468  (0 == ((1LLU << (nn->nc - nc - 1)) & nn->nmask)) )
469  {
470  /* Out-of-order nonce, but within 64-bit bitmask, set bit */
471  nn->nmask |= (1LLU << (nn->nc - nc - 1));
472  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
473  return MHD_YES;
474  }
475 
476  if ( (nc <= nn->nc) ||
477  (0 != strcmp (nn->nonce,
478  nonce)) )
479  {
480  /* Nonce does not match, fail */
481  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
482 #ifdef HAVE_MESSAGES
483  MHD_DLOG (daemon,
484  _("Stale nonce received. If this happens a lot, you should probably increase the size of the nonce array.\n"));
485 #endif
486  return MHD_NO;
487  }
488  /* Nonce is larger, shift bitmask and bump limit */
489  if (64 > nc - nn->nc)
490  nn->nmask <<= (nc - nn->nc); /* small jump, less than mask width */
491  else
492  nn->nmask = 0; /* big jump, unset all bits in the mask */
493  nn->nc = nc;
494  MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
495  return MHD_YES;
496 }
497 
498 
508 char *
510 {
511  size_t len;
512  char user[MAX_USERNAME_LENGTH];
513  const char *header;
514 
515  if (NULL == (header =
516  MHD_lookup_connection_value (connection,
519  return NULL;
520  if (0 != strncmp (header,
521  _BASE,
523  return NULL;
524  header += MHD_STATICSTR_LEN_ (_BASE);
525  if (0 == (len = lookup_sub_value (user,
526  sizeof (user),
527  header,
528  "username")))
529  return NULL;
530  return strdup (user);
531 }
532 
533 
547 static void
548 calculate_nonce (uint32_t nonce_time,
549  const char *method,
550  const char *rnd,
551  size_t rnd_size,
552  const char *uri,
553  const char *realm,
554  char nonce[NONCE_STD_LEN + 1])
555 {
556  struct MD5Context md5;
557  unsigned char timestamp[TIMESTAMP_BIN_SIZE];
558  unsigned char tmpnonce[MHD_MD5_DIGEST_SIZE];
559  char timestamphex[TIMESTAMP_HEX_LEN + 1];
560 
561  MD5Init (&md5);
562  timestamp[0] = (unsigned char)((nonce_time & 0xff000000) >> 0x18);
563  timestamp[1] = (unsigned char)((nonce_time & 0x00ff0000) >> 0x10);
564  timestamp[2] = (unsigned char)((nonce_time & 0x0000ff00) >> 0x08);
565  timestamp[3] = (unsigned char)((nonce_time & 0x000000ff));
566  MD5Update (&md5,
567  timestamp,
568  sizeof (timestamp));
569  MD5Update (&md5,
570  (const unsigned char *) ":",
571  1);
572  MD5Update (&md5,
573  (const unsigned char *) method,
574  strlen (method));
575  MD5Update (&md5,
576  (const unsigned char *) ":",
577  1);
578  if (rnd_size > 0)
579  MD5Update (&md5,
580  (const unsigned char *) rnd,
581  rnd_size);
582  MD5Update (&md5,
583  (const unsigned char *) ":",
584  1);
585  MD5Update (&md5,
586  (const unsigned char *) uri,
587  strlen (uri));
588  MD5Update (&md5,
589  (const unsigned char *) ":",
590  1);
591  MD5Update (&md5,
592  (const unsigned char *) realm,
593  strlen (realm));
594  MD5Final (tmpnonce,
595  &md5);
596  cvthex (tmpnonce,
597  sizeof (tmpnonce),
598  nonce);
599  cvthex (timestamp,
600  sizeof (timestamp),
601  timestamphex);
602  strncat (nonce,
603  timestamphex,
604  8);
605 }
606 
607 
619 static int
620 test_header (struct MHD_Connection *connection,
621  const char *key,
622  const char *value,
623  enum MHD_ValueKind kind)
624 {
625  struct MHD_HTTP_Header *pos;
626 
627  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
628  {
629  if (kind != pos->kind)
630  continue;
631  if (0 != strcmp (key,
632  pos->header))
633  continue;
634  if ( (NULL == value) &&
635  (NULL == pos->value) )
636  return MHD_YES;
637  if ( (NULL == value) ||
638  (NULL == pos->value) ||
639  (0 != strcmp (value,
640  pos->value)) )
641  continue;
642  return MHD_YES;
643  }
644  return MHD_NO;
645 }
646 
647 
658 static int
660  const char *args)
661 {
662  struct MHD_HTTP_Header *pos;
663  char *argb;
664  unsigned int num_headers;
665  int ret;
666 
667  argb = strdup (args);
668  if (NULL == argb)
669  {
670 #ifdef HAVE_MESSAGES
671  MHD_DLOG (connection->daemon,
672  _("Failed to allocate memory for copy of URI arguments\n"));
673 #endif /* HAVE_MESSAGES */
674  return MHD_NO;
675  }
676  ret = MHD_parse_arguments_ (connection,
678  argb,
679  &test_header,
680  &num_headers);
681  free (argb);
682  if (MHD_YES != ret)
683  {
684  return MHD_NO;
685  }
686  /* also check that the number of headers matches */
687  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
688  {
689  if (MHD_GET_ARGUMENT_KIND != pos->kind)
690  continue;
691  num_headers--;
692  }
693  if (0 != num_headers)
694  {
695  /* argument count missmatch */
696  return MHD_NO;
697  }
698  return MHD_YES;
699 }
700 
701 
718 static int
720  const char *realm,
721  const char *username,
722  const char *password,
723  const uint8_t digest[MHD_MD5_DIGEST_SIZE],
724  unsigned int nonce_timeout)
725 {
726  struct MHD_Daemon *daemon = connection->daemon;
727  size_t len;
728  const char *header;
729  char nonce[MAX_NONCE_LENGTH];
730  char cnonce[MAX_NONCE_LENGTH];
731  char qop[15]; /* auth,auth-int */
732  char nc[20];
733  char response[MAX_AUTH_RESPONSE_LENGTH];
734  const char *hentity = NULL; /* "auth-int" is not supported */
735  char ha1[HASH_MD5_HEX_LEN + 1];
736  char respexp[HASH_MD5_HEX_LEN + 1];
737  char noncehashexp[NONCE_STD_LEN + 1];
738  uint32_t nonce_time;
739  uint32_t t;
740  size_t left; /* number of characters left in 'header' for 'uri' */
741  uint64_t nci;
742 
743  header = MHD_lookup_connection_value (connection,
746  if (NULL == header)
747  return MHD_NO;
748  if (0 != strncmp (header,
749  _BASE,
751  return MHD_NO;
752  header += MHD_STATICSTR_LEN_ (_BASE);
753  left = strlen (header);
754 
755  {
756  char un[MAX_USERNAME_LENGTH];
757 
758  len = lookup_sub_value (un,
759  sizeof (un),
760  header,
761  "username");
762  if ( (0 == len) ||
763  (0 != strcmp (username,
764  un)) )
765  return MHD_NO;
766  left -= strlen ("username") + len;
767  }
768 
769  {
770  char r[MAX_REALM_LENGTH];
771 
772  len = lookup_sub_value (r,
773  sizeof (r),
774  header,
775  "realm");
776  if ( (0 == len) ||
777  (0 != strcmp (realm,
778  r)) )
779  return MHD_NO;
780  left -= strlen ("realm") + len;
781  }
782 
783  if (0 == (len = lookup_sub_value (nonce,
784  sizeof (nonce),
785  header,
786  "nonce")))
787  return MHD_NO;
788  left -= strlen ("nonce") + len;
789  if (left > 32 * 1024)
790  {
791  /* we do not permit URIs longer than 32k, as we want to
792  make sure to not blow our stack (or per-connection
793  heap memory limit). Besides, 32k is already insanely
794  large, but of course in theory the
795  #MHD_OPTION_CONNECTION_MEMORY_LIMIT might be very large
796  and would thus permit sending a >32k authorization
797  header value. */
798  return MHD_NO;
799  }
800  if (TIMESTAMP_HEX_LEN !=
803  &nonce_time))
804  {
805 #ifdef HAVE_MESSAGES
806  MHD_DLOG (daemon,
807  _("Authentication failed, invalid timestamp format.\n"));
808 #endif
809  return MHD_NO;
810  }
811  t = (uint32_t) MHD_monotonic_sec_counter();
812  /*
813  * First level vetting for the nonce validity: if the timestamp
814  * attached to the nonce exceeds `nonce_timeout', then the nonce is
815  * invalid.
816  */
817  if ( (t > nonce_time + nonce_timeout) ||
818  (nonce_time + nonce_timeout < nonce_time) )
819  {
820  /* too old */
821  return MHD_INVALID_NONCE;
822  }
823 
824  calculate_nonce (nonce_time,
825  connection->method,
826  daemon->digest_auth_random,
827  daemon->digest_auth_rand_size,
828  connection->url,
829  realm,
830  noncehashexp);
831  /*
832  * Second level vetting for the nonce validity
833  * if the timestamp attached to the nonce is valid
834  * and possibly fabricated (in case of an attack)
835  * the attacker must also know the random seed to be
836  * able to generate a "sane" nonce, which if he does
837  * not, the nonce fabrication process going to be
838  * very hard to achieve.
839  */
840 
841  if (0 != strcmp (nonce, noncehashexp))
842  {
843  return MHD_INVALID_NONCE;
844  }
845  if ( (0 == lookup_sub_value (cnonce,
846  sizeof (cnonce),
847  header,
848  "cnonce")) ||
849  (0 == lookup_sub_value (qop,
850  sizeof (qop),
851  header,
852  "qop")) ||
853  ( (0 != strcmp (qop,
854  "auth")) &&
855  (0 != strcmp (qop,
856  "")) ) ||
857  (0 == (len = lookup_sub_value (nc,
858  sizeof (nc),
859  header,
860  "nc")) ) ||
861  (0 == lookup_sub_value (response,
862  sizeof (response),
863  header,
864  "response")) )
865  {
866 #ifdef HAVE_MESSAGES
867  MHD_DLOG (daemon,
868  _("Authentication failed, invalid format.\n"));
869 #endif
870  return MHD_NO;
871  }
872  if (len != MHD_strx_to_uint64_n_ (nc,
873  len,
874  &nci))
875  {
876 #ifdef HAVE_MESSAGES
877  MHD_DLOG (daemon,
878  _("Authentication failed, invalid nc format.\n"));
879 #endif
880  return MHD_NO; /* invalid nonce format */
881  }
882 
883  /*
884  * Checking if that combination of nonce and nc is sound
885  * and not a replay attack attempt. Also adds the nonce
886  * to the nonce-nc map if it does not exist there.
887  */
888  if (MHD_YES !=
889  check_nonce_nc (connection,
890  nonce,
891  nci))
892  {
893  return MHD_NO;
894  }
895 
896  {
897  char *uri;
898 
899  uri = malloc (left + 1);
900  if (NULL == uri)
901  {
902 #ifdef HAVE_MESSAGES
903  MHD_DLOG(daemon,
904  _("Failed to allocate memory for auth header processing\n"));
905 #endif /* HAVE_MESSAGES */
906  return MHD_NO;
907  }
908  if (0 == lookup_sub_value (uri,
909  left + 1,
910  header,
911  "uri"))
912  {
913  free (uri);
914  return MHD_NO;
915  }
916 
917  if (NULL != digest)
918  {
920  digest,
921  nonce,
922  cnonce,
923  ha1);
924  }
925  else
926  {
928  username,
929  realm,
930  password,
931  nonce,
932  cnonce,
933  ha1);
934  }
936  nonce,
937  nc,
938  cnonce,
939  qop,
940  connection->method,
941  uri,
942  hentity,
943  respexp);
944 
945 
946  /* Need to unescape URI before comparing with connection->url */
947  daemon->unescape_callback (daemon->unescape_callback_cls,
948  connection,
949  uri);
950  if (0 != strncmp (uri,
951  connection->url,
952  strlen (connection->url)))
953  {
954 #ifdef HAVE_MESSAGES
955  MHD_DLOG (daemon,
956  _("Authentication failed, URI does not match.\n"));
957 #endif
958  free (uri);
959  return MHD_NO;
960  }
961 
962  {
963  const char *args = strchr (uri,
964  '?');
965 
966  if (NULL == args)
967  args = "";
968  else
969  args++;
970  if (MHD_YES !=
971  check_argument_match (connection,
972  args) )
973  {
974 #ifdef HAVE_MESSAGES
975  MHD_DLOG (daemon,
976  _("Authentication failed, arguments do not match.\n"));
977 #endif
978  free (uri);
979  return MHD_NO;
980  }
981  }
982  free (uri);
983  return (0 == strcmp (response,
984  respexp))
985  ? MHD_YES
986  : MHD_NO;
987  }
988 }
989 
990 
1004 _MHD_EXTERN int
1006  const char *realm,
1007  const char *username,
1008  const char *password,
1009  unsigned int nonce_timeout)
1010 {
1011  return digest_auth_check_all (connection,
1012  realm,
1013  username,
1014  password,
1015  NULL,
1016  nonce_timeout);
1017 }
1018 
1019 
1035 _MHD_EXTERN int
1037  const char *realm,
1038  const char *username,
1039  const uint8_t digest[MD5_DIGEST_SIZE],
1040  unsigned int nonce_timeout)
1041 {
1042  return digest_auth_check_all (connection,
1043  realm,
1044  username,
1045  NULL,
1046  digest,
1047  nonce_timeout);
1048 }
1049 
1050 
1065 int
1067  const char *realm,
1068  const char *opaque,
1069  struct MHD_Response *response,
1070  int signal_stale)
1071 {
1072  int ret;
1073  int hlen;
1074  char nonce[NONCE_STD_LEN + 1];
1075 
1076  /* Generating the server nonce */
1078  connection->method,
1079  connection->daemon->digest_auth_random,
1080  connection->daemon->digest_auth_rand_size,
1081  connection->url,
1082  realm,
1083  nonce);
1084  if (MHD_YES !=
1085  check_nonce_nc (connection,
1086  nonce,
1087  0))
1088  {
1089 #ifdef HAVE_MESSAGES
1090  MHD_DLOG (connection->daemon,
1091  _("Could not register nonce (is the nonce array size zero?).\n"));
1092 #endif
1093  return MHD_NO;
1094  }
1095  /* Building the authentication header */
1096  hlen = MHD_snprintf_ (NULL,
1097  0,
1098  "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s",
1099  realm,
1100  nonce,
1101  opaque,
1102  signal_stale
1103  ? ",stale=\"true\""
1104  : "");
1105  if (hlen > 0)
1106  {
1107  char *header;
1108 
1109  header = MHD_calloc_ (1, hlen + 1);
1110  if (NULL == header)
1111  {
1112 #ifdef HAVE_MESSAGES
1113  MHD_DLOG(connection->daemon,
1114  _("Failed to allocate memory for auth response header\n"));
1115 #endif /* HAVE_MESSAGES */
1116  return MHD_NO;
1117  }
1118 
1119  if (MHD_snprintf_ (header,
1120  hlen + 1,
1121  "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s",
1122  realm,
1123  nonce,
1124  opaque,
1125  signal_stale
1126  ? ",stale=\"true\""
1127  : "") == hlen)
1128  ret = MHD_add_response_header(response,
1130  header);
1131  else
1132  ret = MHD_NO;
1133  free (header);
1134  }
1135  else
1136  ret = MHD_NO;
1137 
1138  if (MHD_YES == ret)
1139  {
1140  ret = MHD_queue_response (connection,
1142  response);
1143  }
1144  else
1145  {
1146 #ifdef HAVE_MESSAGES
1147  MHD_DLOG (connection->daemon,
1148  _("Failed to add Digest auth header\n"));
1149 #endif /* HAVE_MESSAGES */
1150  }
1151  return ret;
1152 }
1153 
1154 
1155 /* end of digestauth.c */
void * unescape_callback_cls
Definition: internal.h:1387
int MHD_str_equal_caseless_n_(const char *const str1, const char *const str2, size_t maxlen)
Definition: mhd_str.c:359
Header for platform missing functions.
#define MAX_AUTH_RESPONSE_LENGTH
Definition: digestauth.c:66
_MHD_EXTERN const char * MHD_lookup_connection_value(struct MHD_Connection *connection, enum MHD_ValueKind kind, const char *key)
Definition: connection.c:795
static void digest_calc_response(const char ha1[HASH_MD5_HEX_LEN+1], const char *nonce, const char *noncecount, const char *cnonce, const char *qop, const char *method, const char *uri, const char *hentity, char response[HASH_MD5_HEX_LEN+1])
Definition: digestauth.c:216
void * data
Definition: microhttpd.h:2709
_MHD_EXTERN int MHD_add_response_header(struct MHD_Response *response, const char *header, const char *content)
Definition: response.c:118
static void cvthex(const unsigned char *bin, size_t len, char *hex)
Definition: digestauth.c:77
#define MHD_mutex_unlock_chk_(pmutex)
Definition: mhd_locks.h:177
static size_t lookup_sub_value(char *dest, size_t size, const char *data, const char *key)
Definition: digestauth.c:323
internal monotonic clock functions implementations
#define TIMESTAMP_BIN_SIZE
Definition: digestauth.c:42
void * MHD_calloc_(size_t nelem, size_t elsize)
Definition: mhd_compat.c:96
#define MHD_YES
Definition: microhttpd.h: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:186
int MHD_str_equal_caseless_(const char *str1, const char *str2)
Definition: mhd_str.c:329
time_t MHD_monotonic_sec_counter(void)
char * value
Definition: internal.h:349
#define MHD_INVALID_NONCE
Definition: microhttpd.h:3167
enum MHD_ValueKind kind
Definition: internal.h:355
#define NONCE_STD_LEN
Definition: digestauth.c:46
_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:1005
platform-specific includes for libmicrohttpd
char * header
Definition: internal.h:344
struct MHD_Daemon * daemon
Definition: internal.h:672
void MD5Update(struct MD5Context *ctx, const unsigned char *input, size_t len)
Definition: md5.c:67
#define HASH_MD5_HEX_LEN
Definition: digestauth.c:40
#define MHD_MD5_DIGEST_SIZE
Definition: microhttpd.h:299
uint64_t nmask
Definition: internal.h:235
#define MHD_HTTP_HEADER_AUTHORIZATION
Definition: microhttpd.h:440
const char * url
Definition: internal.h:698
_MHD_EXTERN int 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:1066
size_t MHD_strx_to_uint64_n_(const char *str, size_t maxlen, uint64_t *out_val)
Definition: mhd_str.c:666
internal shared structures
char * method
Definition: internal.h:692
static int test_header(struct MHD_Connection *connection, const char *key, const char *value, enum MHD_ValueKind kind)
Definition: digestauth.c:620
char nonce[MAX_NONCE_LENGTH]
Definition: internal.h:240
#define MHD_HTTP_HEADER_WWW_AUTHENTICATE
Definition: microhttpd.h:518
_MHD_EXTERN char * MHD_digest_auth_get_username(struct MHD_Connection *connection)
Definition: digestauth.c:509
#define _MHD_EXTERN
Definition: mhd_options.h:51
#define MAX_NONCE_LENGTH
Definition: internal.h:215
static int check_argument_match(struct MHD_Connection *connection, const char *args)
Definition: digestauth.c:659
#define NULL
Definition: reason_phrase.c:30
MHD_ValueKind
Definition: microhttpd.h:1554
Header for string manipulating helpers.
#define MHD_STATICSTR_LEN_(macro)
Definition: mhd_str.h:45
UnescapeCallback unescape_callback
Definition: internal.h:1382
_MHD_EXTERN int MHD_digest_auth_check_digest(struct MHD_Connection *connection, const char *realm, const char *username, const uint8_t digest[MD5_DIGEST_SIZE], unsigned int nonce_timeout)
Definition: digestauth.c:1036
_MHD_EXTERN int MHD_queue_response(struct MHD_Connection *connection, unsigned int status_code, struct MHD_Response *response)
Definition: connection.c:3994
#define MHD_HTTP_UNAUTHORIZED
Definition: microhttpd.h:336
#define _BASE
Definition: digestauth.c:51
void MD5Final(unsigned char digest[MD5_DIGEST_SIZE], struct MD5Context *ctx)
Definition: md5.c:135
static void calculate_nonce(uint32_t nonce_time, const char *method, const char *rnd, size_t rnd_size, const char *uri, const char *realm, char nonce[NONCE_STD_LEN+1])
Definition: digestauth.c:548
void MD5Init(struct MD5Context *ctx)
Definition: md5.c:50
uint64_t nc
Definition: internal.h:229
struct MHD_HTTP_Header * next
Definition: internal.h:339
Definition: md5.h:27
static void digest_calc_ha1_from_digest(const char *alg, const uint8_t digest[MHD_MD5_DIGEST_SIZE], const char *nonce, const char *cnonce, char sessionkey[HASH_MD5_HEX_LEN+1])
Definition: digestauth.c:108
#define MHD_mutex_lock_chk_(pmutex)
Definition: mhd_locks.h:151
static int digest_auth_check_all(struct MHD_Connection *connection, const char *realm, const char *username, const char *password, const uint8_t digest[MHD_MD5_DIGEST_SIZE], unsigned int nonce_timeout)
Definition: digestauth.c:719
static int check_nonce_nc(struct MHD_Connection *connection, const char *nonce, uint64_t nc)
Definition: digestauth.c:416
#define MD5_DIGEST_SIZE
Definition: md5.h:24
#define MAX_USERNAME_LENGTH
Definition: digestauth.c:56
#define _(String)
Definition: mhd_options.h:42
#define MAX_REALM_LENGTH
Definition: digestauth.c:61
#define MHD_NO
Definition: microhttpd.h:139
#define TIMESTAMP_HEX_LEN
Definition: digestauth.c:43
struct MHD_HTTP_Header * headers_received
Definition: internal.h:650
limits values definitions
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, char sessionkey[HASH_MD5_HEX_LEN+1])
Definition: digestauth.c:165
size_t MHD_strx_to_uint32_n_(const char *str, size_t maxlen, uint32_t *out_val)
Definition: mhd_str.c:581