gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r12805 - libmicrohttpd/src/daemon


From: gnunet
Subject: [GNUnet-SVN] r12805 - libmicrohttpd/src/daemon
Date: Wed, 1 Sep 2010 21:20:01 +0200

Author: grothoff
Date: 2010-09-01 21:20:01 +0200 (Wed, 01 Sep 2010)
New Revision: 12805

Modified:
   libmicrohttpd/src/daemon/digestauth.c
Log:
fixing authentication header parser

Modified: libmicrohttpd/src/daemon/digestauth.c
===================================================================
--- libmicrohttpd/src/daemon/digestauth.c       2010-09-01 15:49:33 UTC (rev 
12804)
+++ libmicrohttpd/src/daemon/digestauth.c       2010-09-01 19:20:01 UTC (rev 
12805)
@@ -28,9 +28,32 @@
 
 #define HASH_MD5_HEX_LEN (2 * MD5_DIGEST_SIZE)
 
+/**
+ * Beginning string for any valid Digest authentication header.
+ */
 #define _BASE          "Digest "
 
 /**
+ * Maximum length of a username for digest authentication.
+ */
+#define MAX_USERNAME_LENGTH 128
+
+/**
+ * Maximum length of a realm for digest authentication.
+ */
+#define MAX_REALM_LENGTH 256
+
+/**
+ * Maximum length of a nonce in digest authentication.
+ */
+#define MAX_NONCE_LENGTH 128
+
+/**
+ * Maximum length of the response in digest authentication.
+ */
+#define MAX_AUTH_RESPONSE_LENGTH 128
+
+/**
  * convert bin to hex 
  *
  * @param bin binary data
@@ -59,6 +82,12 @@
  * calculate H(A1) as per RFC2617 spec and store the
  * result in 'sessionkey'.
  *
+ * @param alg FIXME: document
+ * @param username FIXME: document
+ * @param realm FIXME: document
+ * @param password FIXME: document
+ * @param nonce FIXME: document
+ * @param cnonce FIXME: document
  * @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes
  */
 static void
@@ -156,49 +185,81 @@
 
 
 /**
- * Lookup subvalue off of the HTTP Authorization header
+ * Lookup subvalue off of the HTTP Authorization header.
  *
- * @param dest A pointer to char * to store the result
- * @param size The size of dst
- * @param data A pointer to char * of the Authorization header
- * @param key A pointer to char * of the key in the header
+ * A description of the input format for 'data' is at
+ * http://en.wikipedia.org/wiki/Digest_access_authentication
+ *
+ *
+ * @param dest where to store the result (possibly truncated if
+ *             the buffer is not big enough).
+ * @param size size of dest
+ * @param data pointer to the Authorization header
+ * @param key key to look up in data
  * @return size of the located value, 0 if otherwise
  */
 static int
 lookup_sub_value(char *dest,
-               size_t size,
-               const char *data,
-               const char *key)
+                size_t size,
+                const char *data,
+                const char *key)
 {
   size_t keylen = strlen(key);
   const char *ptr = data;
-  char field[size];
-  char fmt[24 + keylen + 1];
-  int items_read;
-  
-  ptr += strstr(ptr, key) - ptr;
-  
-  if (*(ptr + keylen) != ' ' && *(ptr + keylen) != '=') 
-    {
-      ++ptr;
-      ptr += strstr(ptr, key) - ptr;
-    }  
-  if (!ptr)
+  const char *eq;
+  const char *q1;
+  const char *q2;
+
+  if (0 == size)
     return 0;
-  
-  snprintf(fmt, 
-          sizeof (fmt),
-          "%s%%*[ =\"]%%%u[^, \"]",
-          key, 
-          (unsigned int) size - 1);
-  
-  items_read = sscanf(ptr, fmt, field);
-  
-  if (items_read == 1) 
+  while ('\0' != *ptr)
     {
-      strcpy(dest, field);
-      return strlen(dest);
-    }  
+      if (NULL == (eq = strstr (ptr, "=")))
+       return 0;
+      q1 = strstr (eq, "\"");
+      if (q1 == NULL)
+       {
+         q1 = eq + 1;
+         q2 = strstr (q1, ",");
+       }
+      else
+       {
+         q2 = strstr (q1 + 1, "\"");
+         if (NULL == q2)
+           return 0; /* end quote not found */
+       }      
+      if (0 == strncasecmp (ptr,
+                           key,
+                           keylen))
+       {
+         if (q2 == NULL)
+           {
+             strncpy (dest,
+                      q1 + 1,
+                      size - 1);
+             dest[size-1] = '\0';
+             return strlen (dest);
+           }
+         else
+           {
+             if (size >= q2 - q1)
+               size = (q2 - q1) - 1;
+             memcpy (dest, 
+                     q1 + 1,
+                     size);
+             dest[size] = '\0';
+             return size;
+           }
+       }
+      if (NULL == q2)
+       return 0;
+      ptr = strstr (q2, ",");
+      if (NULL == ptr)
+       return 0;
+      ptr++;
+      while (' ' == *ptr)
+       ptr++;
+    }
   return 0;
 }
 
@@ -214,7 +275,7 @@
 MHD_digest_auth_get_username(struct MHD_Connection *connection)
 {
   size_t len;
-  char user[50];
+  char user[MAX_USERNAME_LENGTH];
   const char *header;
   
   header = MHD_lookup_connection_value(connection,
@@ -234,6 +295,17 @@
   return strdup(user);
 }
 
+
+/**
+ * FIXME: document
+ *
+ * @param nonce_time  FIXME: document
+ * @param method  FIXME: document
+ * @param rnd  FIXME: document
+ * @param uri  FIXME: document
+ * @param realm  FIXME: document
+ * @param nonce  FIXME: document
+ */
 static void
 calculate_nonce (uint32_t nonce_time,
                 const char *method,
@@ -287,24 +359,21 @@
                      const char *password,
                      unsigned int nonce_timeout)
 {
-  int auth;
   size_t len;
   const char *header;
-  const char *rnd;
-  char ret[60];
-  char nonce[50];
-  char cnonce[50];
-  char uri[100];
-/*char qop[15]; // Uncomment when supporting "auth-int" */  
-  char qop[] = "auth"; /* "auth-int" is not supported */
-  char nc[10];
-  char response[35];
-  char *hentity = NULL; /* "auth-int" is not supported */
+  char nonce[MAX_NONCE_LENGTH];
+  char cnonce[MAX_NONCE_LENGTH];
+  /* char qop[15]; // Uncomment when supporting "auth-int" */  
+  const char * qop = "auth"; /* "auth-int" is not supported */
+  char nc[20];
+  char response[MAX_AUTH_RESPONSE_LENGTH];
+  const char *hentity = NULL; /* "auth-int" is not supported */
   char ha1[HASH_MD5_HEX_LEN + 1];
   char respexp[HASH_MD5_HEX_LEN + 1];
   char noncehashexp[HASH_MD5_HEX_LEN + 9];
   uint32_t nonce_time;
   uint32_t t;
+  size_t left; /* number of characters left in 'header' for 'uri' */
 
   header = MHD_lookup_connection_value(connection,
                                       MHD_HEADER_KIND,
@@ -313,86 +382,100 @@
     return MHD_NO;
   if (strncmp(header, _BASE, strlen(_BASE)) != 0) 
     return MHD_NO;
+  header += strlen (_BASE);
+  left = strlen (header);
 
-  rnd = connection->daemon->digest_auth_random;
-  
-  len = lookup_sub_value(ret,
-                        sizeof (ret),
-                        header, "username");
-  if ( (!len) ||
-       (strcmp(username, ret) != 0) ) 
+  {
+    char un[MAX_USERNAME_LENGTH];
+    len = lookup_sub_value(un,
+                          sizeof (un),
+                          header, "username");
+    if ( (!len) ||
+        (strcmp(username, un) != 0) ) 
+      return MHD_NO;
+    left -= strlen ("username") + len;
+  }
+
+  {
+    char r[MAX_REALM_LENGTH];
+    len = lookup_sub_value(r, 
+                          sizeof (r),
+                          header, "realm");  
+    if ( (!len) || 
+        (strcmp(realm, r) != 0) )
+      return MHD_NO;
+    left -= strlen ("realm") + len;
+  }
+
+  if (0 == (len = lookup_sub_value(nonce, 
+                                  sizeof (nonce),
+                                  header, "nonce")))
     return MHD_NO;
-  len = lookup_sub_value(ret, 
-                        sizeof (ret),
-                        header, "realm");  
-  if ( (!len) || 
-       (strcmp(realm, ret) != 0) )
-    return MHD_NO;
-  if ( (0 == lookup_sub_value(uri,
-                             sizeof (uri),
-                             header, "uri")) ||
-       (0 == (len = lookup_sub_value(nonce, 
-                                    sizeof (nonce),
-                                    header, "nonce"))) )
-    return MHD_NO;
-  
-  /* 8 = 4 hexadecimal numbers for the timestamp */  
-  nonce_time = strtoul(nonce + len - 8, 0, 16);  
-  t = (uint32_t) time(NULL);    
-  /*
-   * First level vetting for the nonce validity
-   * if the timestamp attached to the nonce
-   * exceeds `nonce_timeout' then the nonce is
-   * invalid.
-   */
-  if (t > nonce_time + nonce_timeout) 
-    return MHD_INVALID_NONCE;    
-  calculate_nonce (nonce_time,
-                  connection->method,
-                  rnd,
-                  uri,
-                  realm,
-                  noncehashexp);
-  /*
-   * Second level vetting for the nonce validity
-   * if the timestamp attached to the nonce is valid
-   * and possibility fabricated (in case of an attack)
-   * the attacker must also know the password to be
-   * able to generate a "sane" nonce, which if he does
-   * not, the nonce fabrication process going to be
-   * very hard to achieve.
-   */
-  
-  if (0 != strcmp(nonce, noncehashexp))
-    return MHD_INVALID_NONCE;
-  if ( (0 == lookup_sub_value(cnonce,
-                             sizeof (cnonce), 
-                             header, "cnonce")) ||
-       /*       (0 == lookup_sub_value(qop, sizeof (qop), header, "qop")) || 
// Uncomment when supporting "auth-int" */
-       (0 == lookup_sub_value(nc, sizeof (nc), header, "nc"))  ||
-       (0 == lookup_sub_value(response, sizeof (response), header, 
"response")) )
-    return MHD_NO;
+  left -= strlen ("nonce") + len;
 
-  digest_calc_ha1("md5",
-                 username,
-                 realm,
-                 password,
-                 nonce,
-                 cnonce,
-                 ha1);
-  digest_calc_response(ha1,
-                      nonce,
-                      nc,
-                      cnonce,
-                      qop,
-                      connection->method,
-                      uri,
-                      hentity,
-                      respexp);  
+  {
+    char uri[left];  
   
-  auth = strcmp(response, respexp) == 0 ? MHD_YES : MHD_NO;
-  
-  return auth;
+    if (0 == lookup_sub_value(uri,
+                             sizeof (uri),
+                             header, "uri")) 
+      return MHD_NO;
+      
+    /* 8 = 4 hexadecimal numbers for the timestamp */  
+    nonce_time = strtoul(nonce + len - 8, 0, 16);  
+    t = (uint32_t) time(NULL);    
+    /*
+     * First level vetting for the nonce validity
+     * if the timestamp attached to the nonce
+     * exceeds `nonce_timeout' then the nonce is
+     * invalid.
+     */
+    if (t > nonce_time + nonce_timeout) 
+      return MHD_INVALID_NONCE;    
+    calculate_nonce (nonce_time,
+                    connection->method,
+                    connection->daemon->digest_auth_random,
+                    uri,
+                    realm,
+                    noncehashexp);
+    /*
+     * Second level vetting for the nonce validity
+     * if the timestamp attached to the nonce is valid
+     * and possibility fabricated (in case of an attack)
+     * the attacker must also know the password to be
+     * able to generate a "sane" nonce, which if he does
+     * not, the nonce fabrication process going to be
+     * very hard to achieve.
+     */
+    
+    if (0 != strcmp(nonce, noncehashexp))
+      return MHD_INVALID_NONCE;
+    if ( (0 == lookup_sub_value(cnonce,
+                               sizeof (cnonce), 
+                               header, "cnonce")) ||
+        /*      (0 == lookup_sub_value(qop, sizeof (qop), header, "qop")) || 
// Uncomment when supporting "auth-int" */
+        (0 == lookup_sub_value(nc, sizeof (nc), header, "nc"))  ||
+        (0 == lookup_sub_value(response, sizeof (response), header, 
"response")) )
+      return MHD_NO;
+    
+    digest_calc_ha1("md5",
+                   username,
+                   realm,
+                   password,
+                   nonce,
+                   cnonce,
+                   ha1);
+    digest_calc_response(ha1,
+                        nonce,
+                        nc,
+                        cnonce,
+                        qop,
+                        connection->method,
+                        uri,
+                        hentity,
+                        respexp);  
+    return strcmp(response, respexp) == 0 ? MHD_YES : MHD_NO;
+  }
 }
 
 
@@ -414,20 +497,17 @@
 {
   int ret;
   size_t hlen;
-  const char *rnd;
   char nonce[HASH_MD5_HEX_LEN + 9];
   struct MHD_Response *response;
 
   response = MHD_create_response_from_data(0, NULL, MHD_NO, MHD_NO);  
   if (NULL == response) 
     return MHD_NO;
-
-  rnd = connection->daemon->digest_auth_random;
   
   /* Generating the server nonce */  
   calculate_nonce ((uint32_t) time(NULL),
                   connection->method,
-                  rnd,
+                  connection->daemon->digest_auth_random,
                   connection->url,
                   realm,
                   nonce);
@@ -439,7 +519,7 @@
                  realm, 
                  nonce,
                  opaque,
-                 signal_stale ? ",stale=true" : "");
+                 signal_stale ? ",stale=\"true\"" : "");
   {
     char header[hlen + 1];
     snprintf(header,
@@ -448,7 +528,7 @@
             realm, 
             nonce,
             opaque,
-            signal_stale ? ",stale=true" : "");
+            signal_stale ? ",stale=\"true\"" : "");
     ret = MHD_add_response_header(response,
                                  MHD_HTTP_HEADER_WWW_AUTHENTICATE, 
                                  header);




reply via email to

[Prev in Thread] Current Thread [Next in Thread]