gnunet-svn
[Top][All Lists]
Advanced

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

[libmicrohttpd] branch master updated (bd88a19e -> 22796735)


From: gnunet
Subject: [libmicrohttpd] branch master updated (bd88a19e -> 22796735)
Date: Thu, 21 Jul 2022 14:07:58 +0200

This is an automated email from the git hooks/post-receive script.

karlson2k pushed a change to branch master
in repository libmicrohttpd.

    from bd88a19e -typo
     new 755b338b test_basicauth: Fixed doxy
     new e9166209 test_digest: improved test URI
     new 348da88b digestauth: added small helper function to simplify the code
     new 984f72a2 digestauth: simplified internal function call
     new 98ade6e6 digestauth: added sanity check for digest macros
     new 76813be7 digest_auth_check(): removed one more large local variable
     new c63e7544 digest calculations: further simplified code, removed some 
local variables
     new e1e5a395 digestauth: removed usage of variable-length arrays
     new b528bec9 digest_auth_check(): added support for username in extended 
notation
     new 69aec9dc digest_auth_check(): updated the order of parameters check
     new 57a5fcfa digestauth: fixed username extraction with the new API
     new c7ac9d80 digestauth: do not allocate extra space for extended notation
     new aac0cc55 digestauth: added support for extended notation for old API
     new 22796735 Added test for Digest Auth with username in extended notation

The 14 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/microhttpd/digestauth.c                        | 380 +++++++++-------
 src/testcurl/.gitignore                            |   4 +-
 src/testcurl/Makefile.am                           |  29 +-
 src/testcurl/test_basicauth.c                      |   2 +-
 src/testcurl/test_digestauth_concurrent.c          |   2 +-
 ...{test_basicauth.c => test_digestauth_emu_ext.c} | 494 +++++++++++++--------
 src/testcurl/test_digestauth_sha256.c              |   2 +-
 7 files changed, 547 insertions(+), 366 deletions(-)
 copy src/testcurl/{test_basicauth.c => test_digestauth_emu_ext.c} (58%)

diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c
index 71561332..fe80bf0d 100644
--- a/src/microhttpd/digestauth.c
+++ b/src/microhttpd/digestauth.c
@@ -201,24 +201,6 @@ union DigestCtx
   struct Sha256Ctx sha256_ctx;
 };
 
-/**
- * Digest printed as hex digits.
- */
-union DigestHex
-{
-  char md5[MD5_DIGEST_STRING_LENGTH];
-  char sha256[SHA256_DIGEST_STRING_SIZE];
-};
-
-/**
- * Digest in binary form.
- */
-union DigestBin
-{
-  uint8_t md5[MD5_DIGEST_SIZE];
-  uint8_t sha256[SHA256_DIGEST_SIZE];
-};
-
 /**
  * The digest calculation structure.
  */
@@ -230,11 +212,6 @@ struct DigestAlgorithm
    */
   union DigestCtx ctx;
 
-  /**
-   * Digest in binary form.
-   */
-  union DigestBin digest;
-
   /**
    * The hash calculation algorithm.
    */
@@ -360,15 +337,15 @@ digest_init (struct DigestAlgorithm *da)
  */
 _MHD_static_inline void
 digest_update (struct DigestAlgorithm *da,
-               const uint8_t *data,
+               const void *data,
                size_t length)
 {
   mhd_assert (da->inited);
   mhd_assert (! da->digest_calculated);
   if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
-    MHD_MD5Update (&da->ctx.md5_ctx, data, length);
+    MHD_MD5Update (&da->ctx.md5_ctx, (const uint8_t *) data, length);
   else if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
-    MHD_SHA256_update (&da->ctx.sha256_ctx, data, length);
+    MHD_SHA256_update (&da->ctx.sha256_ctx, (const uint8_t *) data, length);
   else
     mhd_assert (0); /* May not happen */
 }
@@ -388,19 +365,34 @@ digest_update_str (struct DigestAlgorithm *da,
 }
 
 
+/**
+ * Feed digest calculation with single colon ':' character.
+ * @param da the digest calculation
+ * @param str the zero-terminated string to process
+ */
+_MHD_static_inline void
+digest_update_with_colon (struct DigestAlgorithm *da)
+{
+  static const uint8_t colon = (uint8_t) ':';
+  digest_update (da, &colon, 1);
+}
+
+
 /**
  * Finally calculate hash (the digest).
  * @param da the digest calculation
+ * @param[out] digest the pointer to the buffer to put calculated digest,
+ *                    must be at least digest_get_size(da) bytes large
  */
 _MHD_static_inline void
-digest_calc_hash (struct DigestAlgorithm *da)
+digest_calc_hash (struct DigestAlgorithm *da, uint8_t *digest)
 {
   mhd_assert (da->inited);
   mhd_assert (! da->digest_calculated);
   if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
-    MHD_MD5Final (&da->ctx.md5_ctx, da->digest.md5);
+    MHD_MD5Final (&da->ctx.md5_ctx, digest);
   else if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
-    MHD_SHA256_finish (&da->ctx.sha256_ctx, da->digest.sha256);
+    MHD_SHA256_finish (&da->ctx.sha256_ctx, digest);
   else
     mhd_assert (0); /* May not happen */
 #ifdef _DEBUG
@@ -409,21 +401,6 @@ digest_calc_hash (struct DigestAlgorithm *da)
 }
 
 
-/**
- * Get pointer to the calculated digest in binary form.
- * @param da the digest calculation
- * @return the pointer to the calculated digest
- */
-_MHD_static_inline const uint8_t *
-digest_get_bin (struct DigestAlgorithm *da)
-{
-  mhd_assert (da->inited);
-  mhd_assert (da->digest_calculated);
-  mhd_assert (da->digest.md5 == da->digest.sha256);
-  return da->digest.sha256;
-}
-
-
 static const struct MHD_RqDAuth *
 get_rq_dauth_params (struct MHD_Connection *connection)
 {
@@ -703,7 +680,8 @@ get_rq_unames_size (const struct MHD_RqDAuth *params,
       s += (params->username.value.len + 1) / 2;
   }
   else if (MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED == uname_type)
-    s += params->username_ext.value.len + 1; /* Add one byte for 
zero-termination */
+    s += params->username_ext.value.len
+         - MHD_DAUTH_EXT_PARAM_MIN_LEN + 1; /* Add one byte for 
zero-termination */
   return s;
 }
 
@@ -915,9 +893,12 @@ get_rq_uname (const struct MHD_RqDAuth *params,
       else
       {
         uname_info->userhash_bin = (uint8_t *) (buf + buf_used);
+        uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH;
         buf_used += uname_info->userhash_bin_size;
       }
     }
+    else
+      uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD;
   }
   else if (MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED == uname_type)
   {
@@ -932,9 +913,15 @@ get_rq_uname (const struct MHD_RqDAuth *params,
     {
       uname_info->username = (char *) (buf + buf_used);
       uname_info->username_len = (size_t) res;
+      uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED;
       buf_used += uname_info->username_len + 1;
     }
   }
+  else
+  {
+    mhd_assert (0);
+    uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_INVALID;
+  }
   mhd_assert (buf_size >= buf_used);
   return buf_used;
 }
@@ -1213,35 +1200,43 @@ MHD_digest_auth_get_username (struct MHD_Connection 
*connection)
 {
   const struct MHD_RqDAuth *params;
   char *username;
-  size_t username_len;
+  size_t buf_size;
+  enum MHD_DigestAuthUsernameType uname_type;
 
   params = get_rq_dauth_params (connection);
   if (NULL == params)
     return NULL;
 
-  if (NULL == params->username.value.str)
+  uname_type = get_rq_uname_type (params);
+
+  if ( (MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD != uname_type) &&
+       (MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED != uname_type) )
     return NULL;
 
-  username_len = params->username.value.len;
-  username = malloc (username_len + 1);
+  buf_size = get_rq_unames_size (params, uname_type);
+
+  mhd_assert (0 != buf_size);
+
+  username = (char *) MHD_calloc_ (1, buf_size);
   if (NULL == username)
     return NULL;
 
-  if (! params->username.quoted)
-  {
-    /* The username is not quoted, no need to unquote */
-    if (0 != username_len)
-      memcpy (username, params->username.value.str, username_len);
-    username[username_len] = 0; /* Zero-terminate */
-  }
-  else
+  if (1)
   {
-    /* Need to properly unquote the username */
-    mhd_assert (0 != username_len); /* Quoted string may not be zero-legth */
-    username_len = MHD_str_unquote (params->username.value.str, username_len,
-                                    username);
-    mhd_assert (0 != username_len); /* The unquoted string cannot be empty */
-    username[username_len] = 0; /* Zero-terminate */
+    struct MHD_DigestAuthUsernameInfo uname_strct;
+    size_t used;
+
+    memset (&uname_strct, 0, sizeof(uname_strct));
+
+    used = get_rq_uname (params, uname_type, &uname_strct,
+                         (uint8_t *) username, buf_size);
+    if (uname_type != uname_strct.uname_type)
+    { /* Broken encoding for extended notation */
+      free (username);
+      return NULL;
+    }
+    (void) used; /* Mute compiler warning for non-debug builds */
+    mhd_assert (buf_size >= used);
   }
 
   return username;
@@ -1262,7 +1257,7 @@ MHD_digest_auth_get_username (struct MHD_Connection 
*connection)
  * @param realm_len the length of the @a realm.
  * @param da digest algorithm to use
  * @param[out] nonce A pointer to a character array for the nonce to put in,
- *        must provide NONCE_STD_LEN(da->digest_size)+1 bytes
+ *        must provide NONCE_STD_LEN(digest_get_size(da))+1 bytes
  */
 static void
 calculate_nonce (uint64_t nonce_time,
@@ -1295,46 +1290,41 @@ calculate_nonce (uint64_t nonce_time,
   digest_update (da,
                  timestamp,
                  sizeof (timestamp));
-  digest_update (da,
-                 (const unsigned char *) ":",
-                 1);
-  digest_update (da,
-                 (const unsigned char *) method,
-                 strlen (method));
-  digest_update (da,
-                 (const unsigned char *) ":",
-                 1);
+  digest_update_with_colon (da);
+  digest_update_str (da, method);
+  digest_update_with_colon (da);
   if (rnd_size > 0)
     digest_update (da,
-                   (const unsigned char *) rnd,
+                   rnd,
                    rnd_size);
+  digest_update_with_colon (da);
   digest_update (da,
-                 (const unsigned char *) ":",
-                 1);
-  digest_update (da,
-                 (const unsigned char *) uri,
+                 uri,
                  uri_len);
   for (h = first_header; NULL != h; h = h->next)
   {
     if (MHD_GET_ARGUMENT_KIND != h->kind)
       continue;
-    digest_update (da, (const uint8_t *) "\0", 2);
+    digest_update (da, "\0", 2);
     if (0 != h->header_size)
-      digest_update (da, (const uint8_t *) h->header, h->header_size);
-    digest_update (da, (const uint8_t *) "", 1);
+      digest_update (da, h->header, h->header_size);
+    digest_update (da, "", 1);
     if (0 != h->value_size)
-      digest_update (da, (const uint8_t *) h->value, h->value_size);
+      digest_update (da, h->value, h->value_size);
   }
+  digest_update_with_colon (da);
   digest_update (da,
-                 (const unsigned char *) ":",
-                 1);
-  digest_update (da,
-                 (const unsigned char *) realm,
+                 realm,
                  realm_len);
-  digest_calc_hash (da);
-  MHD_bin_to_hex (digest_get_bin (da),
-                  digest_get_size (da),
-                  nonce);
+  if (1)
+  {
+    const unsigned int digest_size = digest_get_size (da);
+    uint8_t hash[MAX_DIGEST];
+    digest_calc_hash (da, hash);
+    MHD_bin_to_hex (hash,
+                    digest_size,
+                    nonce);
+  }
   MHD_bin_to_hex (timestamp,
                   sizeof (timestamp),
                   nonce + digest_get_size (da) * 2);
@@ -1409,7 +1399,7 @@ is_slot_available (const struct MHD_NonceNc *const nn,
  * @param realm_len the length of the @a realm
  * @param da the digest algorithm to use
  * @param[out] nonce the pointer to a character array for the nonce to put in,
- *        must provide NONCE_STD_LEN(da->digest_size)+1 bytes
+ *        must provide NONCE_STD_LEN(digest_get_size(da))+1 bytes
  * @return true if the new nonce has been added to the nonce-nc map array,
  *         false otherwise.
  */
@@ -1444,6 +1434,9 @@ calculate_add_nonce (struct MHD_Connection *const 
connection,
   if (0 == daemon->nonce_nc_size)
     return false;
 
+  /* Sanity check for values */
+  mhd_assert (MAX_DIGEST_NONCE_LENGTH == NONCE_STD_LEN (MAX_DIGEST));
+
   nn = daemon->nnc + get_nonce_nc_idx (daemon->nonce_nc_size,
                                        nonce,
                                        nonce_size);
@@ -1475,7 +1468,7 @@ calculate_add_nonce (struct MHD_Connection *const 
connection,
  * @param realm A string of characters that describes the realm of auth.
  * @param da digest algorithm to use
  * @param[out] nonce A pointer to a character array for the nonce to put in,
- *        must provide NONCE_STD_LEN(da->digest_size)+1 bytes
+ *        must provide NONCE_STD_LEN(digest_get_size(da))+1 bytes
  */
 static bool
 calculate_add_nonce_with_retry (struct MHD_Connection *const connection,
@@ -1497,7 +1490,7 @@ calculate_add_nonce_with_retry (struct MHD_Connection 
*const connection,
      * used by the client and this nonce is still fresh enough.
      */
     const size_t digest_size = digest_get_size (da);
-    char nonce2[NONCE_STD_LEN (VLA_ARRAY_LEN_DIGEST (digest_size)) + 1];
+    char nonce2[NONCE_STD_LEN (MAX_DIGEST) + 1];
     uint64_t timestamp2;
     if (0 == MHD_get_master (connection->daemon)->nonce_nc_size)
       return false; /* No need to re-try */
@@ -1913,7 +1906,7 @@ is_param_equal_caseless (const struct MHD_RqDAuthParam 
*param,
  * @param password The password used in the authentication
  * @param digest An optional binary hash
  *     of the precalculated hash value "username:realm:password"
- *     (must contain "da->digest_size" bytes or be NULL)
+ *     (must contain "digest_get_size(da)" bytes or be NULL)
  * @param nonce_timeout The amount of time for a nonce to be
  *      invalid in seconds
  * @param[out] pbuf the pointer to pointer to internally malloc'ed buffer,
@@ -1933,22 +1926,20 @@ digest_auth_check_all_inner (struct MHD_Connection 
*connection,
                              char **pbuf)
 {
   struct MHD_Daemon *daemon = MHD_get_master (connection->daemon);
-  static const uint8_t colon = (uint8_t) ':';
   const unsigned int digest_size = digest_get_size (da);
-  char hdigest1[VLA_ARRAY_LEN_DIGEST (digest_size) * 2 + 1];
-  char hdigest2[VLA_ARRAY_LEN_DIGEST (digest_size) * 2 + 1];
-  char *ha1;
-  char *ha2;
-  uint8_t *response_bin;
+  uint8_t hash1_bin[MAX_DIGEST];
+  uint8_t hash2_bin[MAX_DIGEST];
 #if 0
   const char *hentity = NULL; /* "auth-int" is not supported */
 #endif
-  char noncehashexp[NONCE_STD_LEN (VLA_ARRAY_LEN_DIGEST (digest_size)) + 1];
   uint64_t nonce_time;
   uint64_t t;
   uint64_t nci;
   const struct MHD_RqDAuth *params;
-  char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE]; /**< Temporal buffer in stack for 
unquoting */
+  /**
+   * Temporal buffer in stack for unquoting and other needs
+   */
+  char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE];
   char **const ptmp2 = pbuf;     /**< Temporal malloc'ed buffer for unquoting 
*/
   size_t tmp2_size; /**< The size of @a tmp2 buffer */
   struct _MHD_str_w_len unquoted;
@@ -1958,26 +1949,25 @@ digest_auth_check_all_inner (struct MHD_Connection 
*connection,
   size_t realm_len;
 
   tmp2_size = 0;
-  ha1 = NULL;
-  ha2 = NULL;
 
   params = get_rq_dauth_params (connection);
   if (NULL == params)
     return MHD_DAUTH_WRONG_HEADER;
 
   /* ** A quick check for presence of all required parameters ** */
-  if (NULL == params->username.value.str)
-    return MHD_DAUTH_WRONG_HEADER;
 
-  if (NULL == params->realm.value.str)
+  if ((NULL == params->username.value.str) &&
+      (NULL == params->username_ext.value.str))
     return MHD_DAUTH_WRONG_HEADER;
+  else if ((NULL != params->username.value.str) &&
+           (NULL != params->username_ext.value.str))
+    return MHD_DAUTH_WRONG_HEADER; /* Parameters cannot be used together */
+  else if ((NULL != params->username_ext.value.str) &&
+           (MHD_DAUTH_EXT_PARAM_MIN_LEN > params->username_ext.value.len))
+    return MHD_DAUTH_WRONG_HEADER; /* Broken extended notation */
 
-  if (NULL == params->nonce.value.str)
+  if (NULL == params->realm.value.str)
     return MHD_DAUTH_WRONG_HEADER;
-  else if (0 == params->nonce.value.len)
-    return MHD_DAUTH_NONCE_WRONG;
-  else if (NONCE_STD_LEN (digest_size) * 2 < params->nonce.value.len)
-    return MHD_DAUTH_NONCE_WRONG;
 
   if (NULL == params->nc.value.str)
     return MHD_DAUTH_WRONG_HEADER;
@@ -2000,13 +1990,6 @@ digest_auth_check_all_inner (struct MHD_Connection 
*connection,
   else if (MHD_STATICSTR_LEN_ ("auth-int") * 2 < params->qop.value.len)
     return MHD_DAUTH_WRONG_QOP;
 
-  if (NULL == params->response.value.str)
-    return MHD_DAUTH_WRONG_HEADER;
-  else if (0 == params->response.value.len)
-    return MHD_DAUTH_RESPONSE_WRONG;
-  else if (digest_size * 4 < params->response.value.len)
-    return MHD_DAUTH_RESPONSE_WRONG;
-
   if (NULL == params->uri.value.str)
     return MHD_DAUTH_WRONG_HEADER;
   else if (0 == params->uri.value.len)
@@ -2014,25 +1997,21 @@ digest_auth_check_all_inner (struct MHD_Connection 
*connection,
   else if (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < params->uri.value.len)
     return MHD_DAUTH_TOO_LARGE;
 
-  /* ** Check simple parameters match ** */
-
-  /* Check 'username' */
-  username_len = strlen (username);
-  if (! is_param_equal (&params->username, username, username_len))
-    return MHD_DAUTH_WRONG_USERNAME;
-  /* 'username' valid */
+  if (NULL == params->nonce.value.str)
+    return MHD_DAUTH_WRONG_HEADER;
+  else if (0 == params->nonce.value.len)
+    return MHD_DAUTH_NONCE_WRONG;
+  else if (NONCE_STD_LEN (digest_size) * 2 < params->nonce.value.len)
+    return MHD_DAUTH_NONCE_WRONG;
 
-  /* Check 'realm' */
-  realm_len = strlen (realm);
-  if (! is_param_equal (&params->realm, realm, realm_len))
-    return MHD_DAUTH_WRONG_REALM;
-  /* 'realm' valid */
+  if (NULL == params->response.value.str)
+    return MHD_DAUTH_WRONG_HEADER;
+  else if (0 == params->response.value.len)
+    return MHD_DAUTH_RESPONSE_WRONG;
+  else if (digest_size * 4 < params->response.value.len)
+    return MHD_DAUTH_RESPONSE_WRONG;
 
-  /* Check 'qop' */
-  /* TODO: support MHD_DIGEST_AUTH_QOP_NONE and MHD_DIGEST_AUTH_QOP_AUTH_INT */
-  if (MHD_DIGEST_AUTH_QOP_AUTH != get_rq_qop (params))
-    return MHD_DAUTH_WRONG_QOP;
-  /* 'qop' valid */
+  /* ** Check simple parameters match ** */
 
   /* Check 'algorithm' */
   if (1)
@@ -2047,7 +2026,52 @@ digest_auth_check_all_inner (struct MHD_Connection 
*connection,
   }
   /* 'algorithm' valid */
 
+  /* Check 'qop' */
+  /* TODO: support MHD_DIGEST_AUTH_QOP_NONE and MHD_DIGEST_AUTH_QOP_AUTH_INT */
+  if (MHD_DIGEST_AUTH_QOP_AUTH != get_rq_qop (params))
+    return MHD_DAUTH_WRONG_QOP;
+  /* 'qop' valid */
+
+  /* Check 'realm' */
+  realm_len = strlen (realm);
+  if (! is_param_equal (&params->realm, realm, realm_len))
+    return MHD_DAUTH_WRONG_REALM;
+  /* 'realm' valid */
+
+  /* Check 'username' */
+  username_len = strlen (username);
+  if (NULL != params->username.value.str)
+  { /* Username in standard notation */
+    if (! is_param_equal (&params->username, username, username_len))
+      return MHD_DAUTH_WRONG_USERNAME;
+  }
+  else
+  { /* Username in extended notation */
+    char *r_uname;
+    size_t buf_size = params->username_ext.value.len;
+    ssize_t res;
+
+    mhd_assert (NULL != params->username_ext.value.str);
+    mhd_assert (MHD_DAUTH_EXT_PARAM_MIN_LEN <= buf_size); /* It was checked 
already */
+    buf_size += 1; /* For zero-termination */
+    buf_size -= MHD_DAUTH_EXT_PARAM_MIN_LEN;
+    r_uname = get_buffer_for_size (tmp1, ptmp2, &tmp2_size, buf_size);
+    if (NULL == r_uname)
+      return (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < buf_size) ?
+             MHD_DAUTH_TOO_LARGE : MHD_DAUTH_ERROR;
+    res = get_rq_extended_uname_copy_z (params->username_ext.value.str,
+                                        params->username_ext.value.len,
+                                        r_uname, buf_size);
+    if (0 > res)
+      return MHD_DAUTH_WRONG_HEADER; /* Broken extended notation */
+    if ((username_len != (size_t) res) ||
+        (0 != memcmp (username, r_uname, username_len)))
+      return MHD_DAUTH_WRONG_USERNAME;
+  }
+  /* 'username' valid */
+
   /* ** Do basic nonce and nonce-counter checks (size, timestamp) ** */
+
   /* Get 'nc' digital value */
   unq_res = get_unquoted_param (&params->nc, tmp1, ptmp2, &tmp2_size,
                                 &unquoted);
@@ -2133,91 +2157,108 @@ digest_auth_check_all_inner (struct MHD_Connection 
*connection,
      not used before */
 
   /* ** Build H(A2) and check URI match in the header and in the request ** */
+
   /* Get 'uri' */
   digest_init (da);
   digest_update_str (da, connection->method);
-  digest_update (da, &colon, 1);
+  digest_update_with_colon (da);
 #if 0
   /* TODO: add support for "auth-int" */
   digest_update_str (da, hentity);
-  digest_update (da, &colon, 1);
+  digest_update_with_colon (da);
 #endif
   unq_res = get_unquoted_param_copy (&params->uri, tmp1, ptmp2, &tmp2_size,
                                      &unq_copy);
   if (_MHD_UNQ_OK != unq_res)
     return MHD_DAUTH_ERROR;
 
-  digest_update (da, (const uint8_t *) unq_copy.str, unq_copy.len);
+  digest_update (da, unq_copy.str, unq_copy.len);
   /* The next check will modify copied URI string */
   if (! check_uri_match (connection, unq_copy.str, unq_copy.len))
     return MHD_DAUTH_WRONG_URI;
-  digest_calc_hash (da);
-  ha2 = hdigest2;
-  MHD_bin_to_hex (digest_get_bin (da), digest_size, ha2);
+  digest_calc_hash (da, hash2_bin);
   /* Got H(A2) */
 
   /* ** Build H(A1) ** */
-  ha1 = hdigest1;
   if (NULL == digest)
   {
     digest_init (da);
     digest_update (da, (const uint8_t *) username, username_len);
-    digest_update (da, &colon, 1);
+    digest_update_with_colon (da);
     digest_update (da, (const uint8_t *) realm, realm_len);
-    digest_update (da, &colon, 1);
+    digest_update_with_colon (da);
     digest_update_str (da, password);
-    digest_calc_hash (da);
-    MHD_bin_to_hex (digest_get_bin (da), digest_size, ha1);
+    digest_calc_hash (da, hash1_bin);
   }
-  else
-    MHD_bin_to_hex (digest, digest_size, ha1);
   /* TODO: support '-sess' versions */
   /* Got H(A1) */
 
   /* **  Check 'response' ** */
+
   digest_init (da);
-  digest_update (da, (const uint8_t *) ha1, digest_size * 2);
-  ha1 = NULL;
-  /* H(A1) is not needed anymore, reuse the buffer */
-  response_bin = (uint8_t *) hdigest1;
+  /* Update digest with H(A1) */
+  mhd_assert (sizeof (tmp1) >= (digest_size * 2 + 1));
+  if (NULL == digest)
+    MHD_bin_to_hex (hash1_bin, digest_size, tmp1);
+  else
+    MHD_bin_to_hex (digest, digest_size, tmp1);
+  digest_update (da, (const uint8_t *) tmp1, digest_size * 2);
+
+  /* H(A1) is not needed anymore, reuse the buffer.
+   * Use hash1_bin for the client's 'response' decoded to binary form. */
   unq_res = get_unquoted_param (&params->response, tmp1, ptmp2, &tmp2_size,
                                 &unquoted);
   if (_MHD_UNQ_OK != unq_res)
     return MHD_DAUTH_ERROR;
-  if (digest_size != MHD_hex_to_bin (unquoted.str, unquoted.len, response_bin))
+  if (digest_size != MHD_hex_to_bin (unquoted.str, unquoted.len, hash1_bin))
     return MHD_DAUTH_RESPONSE_WRONG;
-  digest_update (da, &colon, 1);
+
+  /* Update digest with ':' */
+  digest_update_with_colon (da);
+  /* Update digest with 'nonce' text value */
   unq_res = get_unquoted_param (&params->nonce, tmp1, ptmp2, &tmp2_size,
                                 &unquoted);
   if (_MHD_UNQ_OK != unq_res)
     return MHD_DAUTH_ERROR;
   digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
-  digest_update (da, &colon, 1);
+  /* Update digest with ':' */
+  digest_update_with_colon (da);
+  /* Update digest with 'nc' text value */
   unq_res = get_unquoted_param (&params->nc, tmp1, ptmp2, &tmp2_size,
                                 &unquoted);
   if (_MHD_UNQ_OK != unq_res)
     return MHD_DAUTH_ERROR;
   digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
-  digest_update (da, &colon, 1);
+  /* Update digest with ':' */
+  digest_update_with_colon (da);
+  /* Update digest with 'cnonce' value */
   unq_res = get_unquoted_param (&params->cnonce, tmp1, ptmp2, &tmp2_size,
                                 &unquoted);
   if (_MHD_UNQ_OK != unq_res)
     return MHD_DAUTH_ERROR;
   digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
-  digest_update (da, &colon, 1);
+  /* Update digest with ':' */
+  digest_update_with_colon (da);
+  /* Update digest with 'qop' value */
   unq_res = get_unquoted_param (&params->qop, tmp1, ptmp2, &tmp2_size,
                                 &unquoted);
   if (_MHD_UNQ_OK != unq_res)
     return MHD_DAUTH_ERROR;
   digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
-  digest_update (da, &colon, 1);
-  digest_update (da, (const uint8_t *) ha2, digest_size * 2);
-  ha2 = NULL;
-  digest_calc_hash (da);
-  if (0 != memcmp (digest_get_bin (da), response_bin, digest_size))
+  /* Update digest with ':' */
+  digest_update_with_colon (da);
+  /* Update digest with H(A2) */
+  MHD_bin_to_hex (hash2_bin, digest_size, tmp1);
+  digest_update (da, (const uint8_t *) tmp1, digest_size * 2);
+
+  /* H(A2) is not needed anymore, reuse the buffer.
+   * Use hash2_bin for the calculated response in binary form */
+  digest_calc_hash (da, hash2_bin);
+
+  if (0 != memcmp (hash1_bin, hash2_bin, digest_size))
     return MHD_DAUTH_RESPONSE_WRONG;
-  response_bin = NULL;
 
+  mhd_assert (sizeof(tmp1) >= (NONCE_STD_LEN (digest_size) + 1));
   /* It was already checked that 'nonce' (including timestamp) was generated
      by MHD. The next check is mostly an overcaution. */
   calculate_nonce (nonce_time,
@@ -2230,9 +2271,9 @@ digest_auth_check_all_inner (struct MHD_Connection 
*connection,
                    realm,
                    realm_len,
                    da,
-                   noncehashexp);
+                   tmp1);
 
-  if (! is_param_equal (&params->nonce, noncehashexp,
+  if (! is_param_equal (&params->nonce, tmp1,
                         NONCE_STD_LEN (digest_size)))
     return MHD_DAUTH_NONCE_WRONG;
   /* The 'nonce' was generated in the same conditions */
@@ -2253,7 +2294,7 @@ digest_auth_check_all_inner (struct MHD_Connection 
*connection,
  * @param password The password used in the authentication
  * @param digest An optional binary hash
  *     of the precalculated hash value "username:realm:password"
- *     (must contain "da->digest_size" bytes or be NULL)
+ *     (must contain "digest_get_size(da)" bytes or be NULL)
  * @param nonce_timeout The amount of time for a nonce to be
  *      invalid in seconds
  * @return #MHD_DAUTH_OK if authenticated,
@@ -2597,10 +2638,9 @@ MHD_queue_auth_fail_response2 (struct MHD_Connection 
*connection,
 
   if (1)
   {
-    char nonce[NONCE_STD_LEN (VLA_ARRAY_LEN_DIGEST (digest_get_size (&da)))
-               + 1];
+    char nonce[NONCE_STD_LEN (MAX_DIGEST) + 1];
 
-    VLA_CHECK_LEN_DIGEST (digest_get_size (&da));
+    /* VLA_CHECK_LEN_DIGEST (digest_get_size (&da)); */
     if (! calculate_add_nonce_with_retry (connection, realm, &da, nonce))
     {
 #ifdef HAVE_MESSAGES
diff --git a/src/testcurl/.gitignore b/src/testcurl/.gitignore
index f3ffee14..e23f52c9 100644
--- a/src/testcurl/.gitignore
+++ b/src/testcurl/.gitignore
@@ -154,4 +154,6 @@ core
 /test_parse_cookies_invalid
 /test_basicauth_preauth
 /test_basicauth_oldapi
-/test_basicauth_preauth_oldapi
\ No newline at end of file
+/test_basicauth_preauth_oldapi
+/test_digestauth_emu_ext
+/test_digestauth_emu_ext_oldapi
diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am
index 3bf81e7d..e46bbb2d 100644
--- a/src/testcurl/Makefile.am
+++ b/src/testcurl/Makefile.am
@@ -71,14 +71,6 @@ THREAD_ONLY_TESTS += \
 endif
 endif
 
-if ENABLE_DAUTH
-THREAD_ONLY_TESTS += \
-  test_digestauth \
-  test_digestauth_sha256 \
-  test_digestauth_with_arguments \
-  test_digestauth_concurrent
-endif
-
 if HEAVY_TESTS
 if HAVE_POSIX_THREADS
 THREAD_ONLY_TESTS += \
@@ -158,7 +150,7 @@ check_PROGRAMS += \
 endif
 
 if HAVE_POSTPROCESSOR
- check_PROGRAMS += \
+check_PROGRAMS += \
   test_post \
   test_postform \
   test_post_loop \
@@ -167,6 +159,19 @@ if HAVE_POSTPROCESSOR
   test_post_loop11
 endif
 
+
+if ENABLE_DAUTH
+THREAD_ONLY_TESTS += \
+  test_digestauth \
+  test_digestauth_sha256 \
+  test_digestauth_with_arguments \
+  test_digestauth_concurrent
+
+check_PROGRAMS += \
+  test_digestauth_emu_ext \
+  test_digestauth_emu_ext_oldapi
+endif
+
 if HEAVY_TESTS
 if HAVE_FORK_WAITPID
 if HAVE_CURL_BINARY
@@ -268,6 +273,12 @@ test_digestauth_concurrent_CFLAGS = \
 test_digestauth_concurrent_LDADD = \
   @LIBGCRYPT_LIBS@ $(LDADD) $(PTHREAD_LIBS) $(LDADD)
 
+test_digestauth_emu_ext_SOURCES = \
+  test_digestauth_emu_ext.c
+
+test_digestauth_emu_ext_oldapi_SOURCES = \
+  test_digestauth_emu_ext.c
+
 test_get_iovec_SOURCES = \
   test_get_iovec.c mhd_has_in_name.h
 
diff --git a/src/testcurl/test_basicauth.c b/src/testcurl/test_basicauth.c
index a46e6bd1..ed0406db 100644
--- a/src/testcurl/test_basicauth.c
+++ b/src/testcurl/test_basicauth.c
@@ -21,7 +21,7 @@
 
 /**
  * @file test_basicauth.c
- * @brief  Testcase for libmicrohttpd concurrent Basic Authorisation
+ * @brief  Testcase for libmicrohttpd Basic Authorisation
  * @author Amr Ali
  * @author Karlson2k (Evgeny Grin)
  */
diff --git a/src/testcurl/test_digestauth_concurrent.c 
b/src/testcurl/test_digestauth_concurrent.c
index adfe172d..907f1eae 100644
--- a/src/testcurl/test_digestauth_concurrent.c
+++ b/src/testcurl/test_digestauth_concurrent.c
@@ -226,7 +226,7 @@ _checkCURLE_OK_func (CURLcode code, const char *curlFunc,
 /* Could be increased to facilitate debugging */
 #define TIMEOUTS_VAL 5
 
-#define MHD_URI_BASE_PATH "/bar%20foo%3Fkey%3Dvalue"
+#define MHD_URI_BASE_PATH "/bar%20foo?key=value"
 
 #define PAGE \
   "<html><head><title>libmicrohttpd demo</title></head><body>Access 
granted</body></html>"
diff --git a/src/testcurl/test_basicauth.c 
b/src/testcurl/test_digestauth_emu_ext.c
similarity index 58%
copy from src/testcurl/test_basicauth.c
copy to src/testcurl/test_digestauth_emu_ext.c
index a46e6bd1..740f43eb 100644
--- a/src/testcurl/test_basicauth.c
+++ b/src/testcurl/test_digestauth_emu_ext.c
@@ -20,10 +20,13 @@
 */
 
 /**
- * @file test_basicauth.c
- * @brief  Testcase for libmicrohttpd concurrent Basic Authorisation
- * @author Amr Ali
+ * @file test_digest_emu_ext.c
+ * @brief  Testcase for MHD Digest Authorisation client's header parsing
  * @author Karlson2k (Evgeny Grin)
+ *
+ * libcurl does not support extended notation for username, so this test
+ * "emulates" client request will all valid fields except nonce, cnonce and
+ * response (however syntactically these fields valid as well).
  */
 
 #include "MHD_config.h"
@@ -227,11 +230,18 @@ _checkCURLE_OK_func (CURLcode code, const char *curlFunc,
 /* Could be increased to facilitate debugging */
 #define TIMEOUTS_VAL 10
 
-#define MHD_URI_BASE_PATH "/bar%20foo%3Fkey%3Dvalue"
+#define MHD_URI_BASE_PATH "/bar%20foo?key=value"
 
 #define REALM "TestRealm"
-#define USERNAME "Aladdin"
-#define PASSWORD "open sesame"
+/* "titkos szuperügynök" in UTF-8 */
+#define USERNAME "titkos szuper" "\xC3\xBC" "gyn" "\xC3\xB6" "k"
+/* percent-encoded username */
+#define USERNAME_PCTENC "titkos%20szuper%C3%BCgyn%C3%B6k"
+#define PASSWORD "fake pass"
+#define OPAQUE_VALUE "opaque-content"
+#define NONCE_EMU "badbadbadbadbadbadbadbadbadbadbadbadbadbadba"
+#define CNONCE_EMU "utututututututututututututututututututututs="
+#define RESPONSE_EMU "badbadbadbadbadbadbadbadbadbadba"
 
 
 #define PAGE \
@@ -249,10 +259,49 @@ struct CBC
   size_t size;
 };
 
+/* Global parameters */
 static int verbose;
-static int preauth;
 static int oldapi;
 
+/* Static helper variables */
+struct curl_slist *curl_headers;
+
+static void
+test_global_init (void)
+{
+  libcurl_errbuf[0] = 0;
+
+  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+    externalErrorExit ();
+
+  curl_headers = NULL;
+  curl_headers =
+    curl_slist_append (curl_headers,
+                       "Authorization: "
+                       "Digest username*=UTF-8''" USERNAME_PCTENC ", "
+                       "realm=\"" REALM "\", "
+                       "nonce=\"" NONCE_EMU "\", "
+                       "uri=\"" MHD_URI_BASE_PATH "\", "
+                       "cnonce=\"" CNONCE_EMU "\", "
+                       "nc=00000001, "
+                       "qop=auth, "
+                       "response=\"" RESPONSE_EMU "\", "
+                       "opaque=\"" OPAQUE_VALUE "\", "
+                       "algorithm=MD5");
+  if (NULL == curl_headers)
+    externalErrorExit ();
+}
+
+
+static void
+test_global_cleanup (void)
+{
+  curl_slist_free_all (curl_headers);
+  curl_headers = NULL;
+  curl_global_cleanup ();
+}
+
+
 static size_t
 copyBuffer (void *ptr,
             size_t size,
@@ -296,128 +345,243 @@ ahc_echo (void *cls,
   if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
     mhdErrorExitDesc ("Unexpected HTTP method");
 
-  /* require: USERNAME with password PASSWORD */
   if (! oldapi)
   {
-    struct MHD_BasicAuthInfo *creds;
-
-    creds = MHD_basic_auth_get_username_password3 (connection);
-    if (NULL != creds)
+    struct MHD_DigestAuthUsernameInfo *creds;
+    struct MHD_DigestAuthInfo *dinfo;
+    enum MHD_DigestAuthResult check_res;
+
+    creds = MHD_digest_auth_get_username3 (connection);
+    if (NULL == creds)
+      mhdErrorExitDesc ("MHD_digest_auth_get_username3() returned NULL");
+    else if (NULL == creds->username)
+      mhdErrorExitDesc ("'username' is NULL");
+    else if (creds->username_len != MHD_STATICSTR_LEN_ (USERNAME))
     {
-      if (NULL == creds->username)
-        mhdErrorExitDesc ("'username' is NULL");
-      else if (MHD_STATICSTR_LEN_ (USERNAME) != creds->username_len)
-      {
-        fprintf (stderr, "'username_len' does not match.\n"
-                 "Expected: %u\tRecieved: %u. ",
-                 (unsigned) MHD_STATICSTR_LEN_ (USERNAME),
-                 (unsigned) creds->username_len);
-        mhdErrorExitDesc ("Wrong 'username_len'");
-      }
-      else if (0 != memcmp (creds->username, USERNAME, creds->username_len))
-      {
-        fprintf (stderr, "'username' does not match.\n"
-                 "Expected: '%s'\tRecieved: '%.*s'. ",
-                 USERNAME,
-                 (int) creds->username_len,
-                 creds->username);
-        mhdErrorExitDesc ("Wrong 'username'");
-      }
-      else if (0 != creds->username[creds->username_len])
-        mhdErrorExitDesc ("'username' is not zero-terminated");
-      else if (NULL == creds->password)
-        mhdErrorExitDesc ("'password' is NULL");
-      else if (MHD_STATICSTR_LEN_ (PASSWORD) != creds->password_len)
-      {
-        fprintf (stderr, "'password_len' does not match.\n"
-                 "Expected: %u\tRecieved: %u. ",
-                 (unsigned) MHD_STATICSTR_LEN_ (PASSWORD),
-                 (unsigned) creds->password_len);
-        mhdErrorExitDesc ("Wrong 'password_len'");
-      }
-      else if (0 != memcmp (creds->password, PASSWORD, creds->password_len))
-      {
-        fprintf (stderr, "'password' does not match.\n"
-                 "Expected: '%s'\tRecieved: '%.*s'. ",
-                 PASSWORD,
-                 (int) creds->password_len,
-                 creds->password);
-        mhdErrorExitDesc ("Wrong 'username'");
-      }
-      else if (0 != creds->password[creds->password_len])
-        mhdErrorExitDesc ("'password' is not zero-terminated");
-
-      MHD_free (creds);
-
-      response =
-        MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE),
-                                                (const void *) PAGE);
-      if (NULL == response)
-        mhdErrorExitDesc ("Response creation failed");
-      ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
-      if (MHD_YES != ret)
-        mhdErrorExitDesc ("'MHD_queue_response()' failed");
+      fprintf (stderr, "'username_len' does not match.\n"
+               "Expected: %u\tRecieved: %u. ",
+               (unsigned) MHD_STATICSTR_LEN_ (USERNAME),
+               (unsigned) creds->username_len);
+      mhdErrorExitDesc ("Wrong 'username_len'");
     }
-    else
+    else if (0 != memcmp (creds->username, USERNAME, creds->username_len))
+    {
+      fprintf (stderr, "'username' does not match.\n"
+               "Expected: '%s'\tRecieved: '%.*s'. ",
+               USERNAME,
+               (int) creds->username_len,
+               creds->username);
+      mhdErrorExitDesc ("Wrong 'username'");
+    }
+    else if (NULL != creds->userhash_bin)
+      mhdErrorExitDesc ("'userhash_bin' is NOT NULL");
+    else if (0 != creds->userhash_bin_size)
+      mhdErrorExitDesc ("'userhash_bin_size' is NOT zero");
+    else if (MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED != creds->uname_type)
+    {
+      fprintf (stderr, "Unexpected 'uname_type'.\n"
+               "Expected: %d\tRecieved: %d. ",
+               (int) MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED,
+               (int) creds->uname_type);
+      mhdErrorExitDesc ("Wrong 'uname_type'");
+    }
+    MHD_free (creds);
+
+    dinfo = MHD_digest_auth_get_request_info3 (connection);
+    if (NULL == dinfo)
+      mhdErrorExitDesc ("MHD_digest_auth_get_username3() returned NULL");
+    else if (NULL == dinfo->username)
+      mhdErrorExitDesc ("'username' is NULL");
+    else if (dinfo->username_len != MHD_STATICSTR_LEN_ (USERNAME))
+    {
+      fprintf (stderr, "'username_len' does not match.\n"
+               "Expected: %u\tRecieved: %u. ",
+               (unsigned) MHD_STATICSTR_LEN_ (USERNAME),
+               (unsigned) dinfo->username_len);
+      mhdErrorExitDesc ("Wrong 'username_len'");
+    }
+    else if (0 != memcmp (dinfo->username, USERNAME, dinfo->username_len))
+    {
+      fprintf (stderr, "'username' does not match.\n"
+               "Expected: '%s'\tRecieved: '%.*s'. ",
+               USERNAME,
+               (int) dinfo->username_len,
+               dinfo->username);
+      mhdErrorExitDesc ("Wrong 'username'");
+    }
+    else if (NULL != dinfo->userhash_bin)
+      mhdErrorExitDesc ("'userhash_bin' is NOT NULL");
+    else if (0 != dinfo->userhash_bin_size)
+      mhdErrorExitDesc ("'userhash_bin_size' is NOT zero");
+    else if (MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED != dinfo->uname_type)
+    {
+      fprintf (stderr, "Unexpected 'uname_type'.\n"
+               "Expected: %d\tRecieved: %d. ",
+               (int) MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED,
+               (int) dinfo->uname_type);
+      mhdErrorExitDesc ("Wrong 'uname_type'");
+    }
+    else if (MHD_DIGEST_AUTH_ALGO3_MD5 != dinfo->algo)
+    {
+      fprintf (stderr, "Unexpected 'algo'.\n"
+               "Expected: %d\tRecieved: %d. ",
+               (int) MHD_DIGEST_AUTH_ALGO3_MD5,
+               (int) dinfo->algo);
+      mhdErrorExitDesc ("Wrong 'algo'");
+    }
+    else if (MHD_STATICSTR_LEN_ (CNONCE_EMU) != dinfo->cnonce_len)
+    {
+      fprintf (stderr, "Unexpected 'cnonce_len'.\n"
+               "Expected: %d\tRecieved: %ld. ",
+               (int) MHD_STATICSTR_LEN_ (CNONCE_EMU),
+               (long) dinfo->cnonce_len);
+      mhdErrorExitDesc ("Wrong 'cnonce_len'");
+    }
+    else if (NULL == dinfo->opaque)
+      mhdErrorExitDesc ("'opaque' is NULL");
+    else if (dinfo->opaque_len != MHD_STATICSTR_LEN_ (OPAQUE_VALUE))
+    {
+      fprintf (stderr, "'opaque_len' does not match.\n"
+               "Expected: %u\tRecieved: %u. ",
+               (unsigned) MHD_STATICSTR_LEN_ (OPAQUE_VALUE),
+               (unsigned) dinfo->opaque_len);
+      mhdErrorExitDesc ("Wrong 'opaque_len'");
+    }
+    else if (0 != memcmp (dinfo->opaque, OPAQUE_VALUE, dinfo->opaque_len))
+    {
+      fprintf (stderr, "'opaque' does not match.\n"
+               "Expected: '%s'\tRecieved: '%.*s'. ",
+               OPAQUE_VALUE,
+               (int) dinfo->opaque_len,
+               dinfo->opaque);
+      mhdErrorExitDesc ("Wrong 'opaque'");
+    }
+    else if (MHD_DIGEST_AUTH_QOP_AUTH != dinfo->qop)
+    {
+      fprintf (stderr, "Unexpected 'qop'.\n"
+               "Expected: %d\tRecieved: %d. ",
+               (int) MHD_DIGEST_AUTH_QOP_AUTH,
+               (int) dinfo->qop);
+      mhdErrorExitDesc ("Wrong 'qop'");
+    }
+    else if (NULL == dinfo->realm)
+      mhdErrorExitDesc ("'realm' is NULL");
+    else if (dinfo->realm_len != MHD_STATICSTR_LEN_ (REALM))
     {
-      response =
-        MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (DENIED),
-                                                (const void *) DENIED);
-      if (NULL == response)
-        mhdErrorExitDesc ("Response creation failed");
-      ret = MHD_queue_basic_auth_fail_response3 (connection, REALM, MHD_YES,
-                                                 response);
-      if (MHD_YES != ret)
-        mhdErrorExitDesc ("'MHD_queue_basic_auth_fail_response3()' failed");
+      fprintf (stderr, "'realm_len' does not match.\n"
+               "Expected: %u\tRecieved: %u. ",
+               (unsigned) MHD_STATICSTR_LEN_ (REALM),
+               (unsigned) dinfo->realm_len);
+      mhdErrorExitDesc ("Wrong 'realm_len'");
     }
+    else if (0 != memcmp (dinfo->realm, REALM, dinfo->realm_len))
+    {
+      fprintf (stderr, "'realm' does not match.\n"
+               "Expected: '%s'\tRecieved: '%.*s'. ",
+               OPAQUE_VALUE,
+               (int) dinfo->realm_len,
+               dinfo->realm);
+      mhdErrorExitDesc ("Wrong 'realm'");
+    }
+    MHD_free (dinfo);
+
+    check_res = MHD_digest_auth_check3 (connection, REALM, USERNAME, PASSWORD,
+                                        300, MHD_DIGEST_ALG_MD5);
+
+    switch (check_res)
+    {
+    /* Valid results */
+    case MHD_DAUTH_NONCE_STALE:
+      if (verbose)
+        printf ("Got valid auth check result: MHD_DAUTH_NONCE_STALE.\n");
+      break;
+    case MHD_DAUTH_NONCE_WRONG:
+      if (verbose)
+        printf ("Got valid auth check result: MHD_DAUTH_NONCE_WRONG.\n");
+      break;
+
+    /* Invalid results */
+    case MHD_DAUTH_OK:
+      mhdErrorExitDesc ("'MHD_digest_auth_check3()' succeed, " \
+                        "but it should not");
+      break;
+    case MHD_DAUTH_ERROR:
+      externalErrorExitDesc ("General error returned " \
+                             "by 'MHD_digest_auth_check3()'");
+      break;
+    case MHD_DAUTH_WRONG_USERNAME:
+      mhdErrorExitDesc ("MHD_digest_auth_check3()' returned " \
+                        "MHD_DAUTH_WRONG_USERNAME");
+      break;
+    case MHD_DAUTH_RESPONSE_WRONG:
+      mhdErrorExitDesc ("MHD_digest_auth_check3()' returned " \
+                        "MHD_DAUTH_RESPONSE_WRONG");
+      break;
+    case MHD_DAUTH_WRONG_HEADER:
+    case MHD_DAUTH_WRONG_REALM:
+    case MHD_DAUTH_WRONG_URI:
+    case MHD_DAUTH_WRONG_QOP:
+    case MHD_DAUTH_WRONG_ALGO:
+    case MHD_DAUTH_TOO_LARGE:
+      fprintf (stderr, "'MHD_digest_auth_check3()' returned "
+               "unexpected result: %d. ",
+               check_res);
+      mhdErrorExitDesc ("Wrong returned code");
+      break;
+    default:
+      fprintf (stderr, "'MHD_digest_auth_check3()' returned "
+               "impossible result code: %d. ",
+               check_res);
+      mhdErrorExitDesc ("Impossible returned code");
+    }
+
+    response =
+      MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (DENIED),
+                                              (const void *) DENIED);
+    if (NULL == response)
+      mhdErrorExitDesc ("Response creation failed");
+    ret = MHD_queue_auth_fail_response2 (connection, REALM, OPAQUE_VALUE,
+                                         response, 0, MHD_DIGEST_ALG_MD5);
+    if (MHD_YES != ret)
+      mhdErrorExitDesc ("'MHD_queue_auth_fail_response2()' failed");
   }
   else
   {
     char *username;
-    char *password;
+    int check_res;
 
-    password = NULL;
-    username = MHD_basic_auth_get_username_password (connection,
-                                                     &password);
-    if (NULL != username)
+    username = MHD_digest_auth_get_username (connection);
+    if (NULL == username)
+      mhdErrorExitDesc ("'MHD_digest_auth_get_username()' returned NULL");
+    else if (0 != strcmp (username, USERNAME))
     {
-      if (0 != strcmp (username, USERNAME))
-      {
-        fprintf (stderr, "'username' does not match.\n"
-                 "Expected: '%s'\tRecieved: '%s'. ", USERNAME, username);
-        mhdErrorExitDesc ("Wrong 'username'");
-      }
-      if (NULL == password)
-        mhdErrorExitDesc ("The password pointer is NULL");
-      if (0 != strcmp (password, PASSWORD))
-        fprintf (stderr, "'password' does not match.\n"
-                 "Expected: '%s'\tRecieved: '%s'. ", PASSWORD, password);
-      response =
-        MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE),
-                                                (const void *) PAGE);
-      if (NULL == response)
-        mhdErrorExitDesc ("Response creation failed");
-      ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
-      if (MHD_YES != ret)
-        mhdErrorExitDesc ("'MHD_queue_response()' failed");
+      fprintf (stderr, "'username' does not match.\n"
+               "Expected: '%s'\tRecieved: '%s'. ",
+               USERNAME,
+               username);
+      mhdErrorExitDesc ("Wrong 'username'");
     }
-    else
+    MHD_free (username);
+
+    check_res = MHD_digest_auth_check (connection, REALM, USERNAME, PASSWORD,
+                                       300);
+
+    if (MHD_INVALID_NONCE != check_res)
     {
-      if (NULL != password)
-        mhdErrorExitDesc ("The password pointer is NOT NULL");
-      response =
-        MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (DENIED),
-                                                (const void *) DENIED);
-      if (NULL == response)
-        mhdErrorExitDesc ("Response creation failed");
-      ret = MHD_queue_basic_auth_fail_response (connection, REALM, response);
-      if (MHD_YES != ret)
-        mhdErrorExitDesc ("'MHD_queue_basic_auth_fail_response()' failed");
+      fprintf (stderr, "'MHD_digest_auth_check()' returned unexpected"
+               " result: %d. ", check_res);
+      mhdErrorExitDesc ("Wrong 'MHD_digest_auth_check()' result");
     }
-    if (NULL != username)
-      MHD_free (username);
-    if (NULL != password)
-      MHD_free (password);
+    response =
+      MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (DENIED),
+                                              (const void *) DENIED);
+    if (NULL == response)
+      mhdErrorExitDesc ("Response creation failed");
+
+    ret = MHD_queue_auth_fail_response (connection, REALM, OPAQUE_VALUE,
+                                        response, 0);
+    if (MHD_YES != ret)
+      mhdErrorExitDesc ("'MHD_queue_auth_fail_response()' failed");
   }
 
   MHD_destroy_response (response);
@@ -426,7 +590,7 @@ ahc_echo (void *cls,
 
 
 static CURL *
-setupCURL (void *cbc, int port, char *errbuf)
+setupCURL (void *cbc, int port)
 {
   CURL *c;
   char url[512];
@@ -447,19 +611,20 @@ setupCURL (void *cbc, int port, char *errbuf)
     libcurlErrorExitDesc ("curl_easy_init() failed");
 
   if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) ||
-      (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER,
-                                     errbuf)) ||
       (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION,
                                      &copyBuffer)) ||
       (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc)) ||
       (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT,
                                      ((long) TIMEOUTS_VAL))) ||
-      (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT,
-                                     ((long) TIMEOUTS_VAL))) ||
       (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION,
                                      CURL_HTTP_VERSION_1_1)) ||
+      (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT,
+                                     ((long) TIMEOUTS_VAL))) ||
+      (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER,
+                                     libcurl_errbuf)) ||
       /* (CURLE_OK != curl_easy_setopt (c, CURLOPT_VERBOSE, 1L)) || */
-      (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L)) ||
+      (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 0L)) ||
+      (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTPHEADER, curl_headers)) ||
 #if CURL_AT_LEAST_VERSION (7, 19, 4)
       (CURLE_OK != curl_easy_setopt (c, CURLOPT_PROTOCOLS, CURLPROTO_HTTP)) ||
 #endif /* CURL_AT_LEAST_VERSION (7, 19, 4) */
@@ -469,19 +634,6 @@ setupCURL (void *cbc, int port, char *errbuf)
       (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, ((long) port))) ||
       (CURLE_OK != curl_easy_setopt (c, CURLOPT_URL, url)))
     libcurlErrorExitDesc ("curl_easy_setopt() failed");
-#if CURL_AT_LEAST_VERSION (7,21,3)
-  if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTPAUTH,
-                                     CURLAUTH_BASIC
-                                     | (preauth ? 0 : CURLAUTH_ONLY))) ||
-      (CURLE_OK != curl_easy_setopt (c, CURLOPT_USERPWD,
-                                     USERNAME ":" PASSWORD)))
-    libcurlErrorExitDesc ("curl_easy_setopt() authorization options failed");
-#else  /* libcurl version before 7.21.3 */
-  if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTPAUTH, CURLAUTH_BASIC)) ||
-      (CURLE_OK != curl_easy_setopt (c, CURLOPT_USERPWD,
-                                     USERNAME ":" PASSWORD)))
-    libcurlErrorExitDesc ("curl_easy_setopt() authorization options failed");
-#endif /* libcurl version before 7.21.3 */
   return c;
 }
 
@@ -592,33 +744,44 @@ performQueryExternal (struct MHD_Daemon *d, CURL *c)
  * @return non-zero if success, zero if failed
  */
 static unsigned int
-check_result (CURLcode curl_code, struct CBC *pcbc)
+check_result (CURLcode curl_code, CURL *c, struct CBC *pcbc)
 {
+  long code;
+  if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code))
+    libcurlErrorExit ();
+
+  if (401 != code)
+  {
+    fprintf (stderr, "Request returned wrong code: %ld.\n",
+             code);
+    return 0;
+  }
+
   if (CURLE_OK != curl_code)
   {
     fflush (stdout);
     if (0 != libcurl_errbuf[0])
-      fprintf (stderr, "First request failed. "
+      fprintf (stderr, "Request failed. "
                "libcurl error: '%s'.\n"
                "libcurl error description: '%s'.\n",
                curl_easy_strerror (curl_code),
                libcurl_errbuf);
     else
-      fprintf (stderr, "First request failed. "
+      fprintf (stderr, "Request failed. "
                "libcurl error: '%s'.\n",
                curl_easy_strerror (curl_code));
     fflush (stderr);
     return 0;
   }
 
-  if (pcbc->pos != strlen (PAGE))
+  if (pcbc->pos != strlen (DENIED))
   {
     fprintf (stderr, "Got %u bytes ('%.*s'), expected %u bytes. ",
              (unsigned) pcbc->pos, (int) pcbc->pos, pcbc->buf,
-             (unsigned) strlen (PAGE));
+             (unsigned) strlen (DENIED));
     mhdErrorExitDesc ("Wrong returned data length");
   }
-  if (0 != memcmp (PAGE, pcbc->buf, pcbc->pos))
+  if (0 != memcmp (DENIED, pcbc->buf, pcbc->pos))
   {
     fprintf (stderr, "Got invalid response '%.*s'. ",
              (int) pcbc->pos, pcbc->buf);
@@ -629,7 +792,7 @@ check_result (CURLcode curl_code, struct CBC *pcbc)
 
 
 static unsigned int
-testBasicAuth (void)
+testDigestAuthEmu (void)
 {
   struct MHD_Daemon *d;
   uint16_t port;
@@ -666,36 +829,19 @@ testBasicAuth (void)
   cbc.size = sizeof (buf);
   cbc.pos = 0;
   memset (cbc.buf, 0, cbc.size);
-  c = setupCURL (&cbc, port, libcurl_errbuf);
-  if (check_result (performQueryExternal (d, c), &cbc))
+  c = setupCURL (&cbc, port);
+  if (check_result (performQueryExternal (d, c), c, &cbc))
   {
     if (verbose)
-      printf ("First request successful.\n");
+      printf ("Got expected response.\n");
   }
   else
   {
-    fprintf (stderr, "First request FAILED.\n");
+    fprintf (stderr, "Request FAILED.\n");
     failed = 1;
   }
   curl_easy_cleanup (c);
 
-  /* Second request */
-  cbc.buf = buf;
-  cbc.size = sizeof (buf);
-  cbc.pos = 0;
-  memset (cbc.buf, 0, cbc.size);
-  c = setupCURL (&cbc, port, libcurl_errbuf);
-  if (check_result (performQueryExternal (d, c), &cbc))
-  {
-    if (verbose)
-      printf ("Second request successful.\n");
-  }
-  else
-  {
-    fprintf (stderr, "Second request FAILED.\n");
-    failed = 1;
-  }
-  curl_easy_cleanup (c);
   MHD_stop_daemon (d);
   return failed ? 1 : 0;
 }
@@ -711,30 +857,12 @@ main (int argc, char *const *argv)
                has_param (argc, argv, "--quiet") ||
                has_param (argc, argv, "-s") ||
                has_param (argc, argv, "--silent"));
-  preauth = has_in_name (argv[0], "_preauth");
-#if ! CURL_AT_LEAST_VERSION (7,21,3)
-  if (preauth)
-  {
-    fprintf (stderr, "libcurl version 7.21.3 or later is "
-             "required to run this test.\n");
-    return 77;
-  }
-#endif /* libcurl version before 7.21.3 */
-
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
-#ifdef HAVE_GCRYPT_H
-  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
-#ifdef GCRYCTL_INITIALIZATION_FINISHED
-  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
-#endif
-#endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
   oldapi = has_in_name (argv[0], "_oldapi");
-  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
-    return 2;
-  errorCount += testBasicAuth ();
+  test_global_init ();
+
+  errorCount += testDigestAuthEmu ();
   if (errorCount != 0)
     fprintf (stderr, "Error (code: %u)\n", errorCount);
-  curl_global_cleanup ();
+  test_global_cleanup ();
   return (0 == errorCount) ? 0 : 1;       /* 0 == pass */
 }
diff --git a/src/testcurl/test_digestauth_sha256.c 
b/src/testcurl/test_digestauth_sha256.c
index 90e5ad5f..b34dff9f 100644
--- a/src/testcurl/test_digestauth_sha256.c
+++ b/src/testcurl/test_digestauth_sha256.c
@@ -261,7 +261,7 @@ testDigestAuth ()
   }
   snprintf (url,
             sizeof (url),
-            "http://127.0.0.1:%d/bar%%20foo%%3Fkey%%3Dvalue";,
+            "http://127.0.0.1:%d/bar%%20foo?key=value";,
             port);
   c = curl_easy_init ();
   curl_easy_setopt (c, CURLOPT_URL, url);

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

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