gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [libmicrohttpd] branch master updated: add test for RFC 761


From: gnunet
Subject: [GNUnet-SVN] [libmicrohttpd] branch master updated: add test for RFC 7616 and document new API
Date: Sat, 08 Dec 2018 22:54:34 +0100

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

grothoff pushed a commit to branch master
in repository libmicrohttpd.

The following commit(s) were added to refs/heads/master by this push:
     new 2897bd23 add test for RFC 7616 and document new API
2897bd23 is described below

commit 2897bd23e57cf016a713876e551cd20b8a28427d
Author: Christian Grothoff <address@hidden>
AuthorDate: Sat Dec 8 22:54:33 2018 +0100

    add test for RFC 7616 and document new API
---
 ChangeLog                             |   3 +
 doc/libmicrohttpd.texi                | 126 ++++++++++++--
 src/include/microhttpd.h              |   2 +-
 src/testcurl/.gitignore               |   2 +-
 src/testcurl/Makefile.am              |   9 +-
 src/testcurl/test_digestauth_sha256.c | 314 ++++++++++++++++++++++++++++++++++
 6 files changed, 438 insertions(+), 18 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 352cdc8e..c482a6a2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,6 @@
+Sat Dec  8 22:53:56 CET 2018
+       Added test for RFC 7616 and documented new API. -CG
+
 Sat Dec  8 17:34:58 CET 2018
        Adding support for RFC 7616, experimental, needs
        testing and documentation still! -CG
diff --git a/doc/libmicrohttpd.texi b/doc/libmicrohttpd.texi
index 851f23cc..f2e3576c 100644
--- a/doc/libmicrohttpd.texi
+++ b/doc/libmicrohttpd.texi
@@ -2440,15 +2440,57 @@ client with a 401 HTTP status.
 @node microhttpd-dauth digest
 @section Using Digest Authentication
 
+MHD supports MD5 (deprecated by IETF) and SHA-256 hash algorithms
+for digest authentication. The @code{MHD_DigestAuthAlgorithm} enumeration
+is used to specify which algorithm should be used.
+
address@hidden {Enumeration} MHD_DigestAuthAlgorithm
+Which digest algorithm should be used. Must be used consistently.
+
address@hidden @code
address@hidden MHD_DIGEST_ALG_AUTO
+Have MHD pick an algorithm currently considered secure.  For now defaults to 
SHA-256.
+
address@hidden MHD_DIGEST_ALG_MD5
+Force use of (deprecated, ancient, insecure) MD5.
+
address@hidden MHD_DIGEST_ALG_SHA256
+Force use of SHA-256.
+
address@hidden table
address@hidden deftp
+
+
 @deftypefun {char *} MHD_digest_auth_get_username (struct MHD_Connection 
*connection)
 Find and return a pointer to the username value from the request header.
 Return @code{NULL} if the value is not found or header does not exist.
 If returned value is not @code{NULL}, the value must be @code{MHD_free()}'ed.
 @end deftypefun
 
address@hidden int MHD_digest_auth_check2 (struct MHD_Connection *connection, 
const char *realm, const char *username, const char *password, unsigned int 
nonce_timeout, enum MHD_DigestAuthAlgorithm algo)
+Checks if the provided values in the WWW-Authenticate header are valid
+and sound according to RFC2716. If valid return @code{MHD_YES}, otherwise 
return @code{MHD_NO}.
+
address@hidden must reference to a zero-terminated string representing the 
realm.
+
address@hidden must reference to a zero-terminated string representing the 
username,
+it is usually the returned value from MHD_digest_auth_get_username.
+
address@hidden must reference to a zero-terminated string representing the 
password,
+most probably it will be the result of a lookup of the username against a 
local database.
+
address@hidden is the amount of time in seconds for a nonce to be invalid.
+Most of the time it is sound to specify 300 seconds as its values.
+
address@hidden which digest algorithm should we use.
address@hidden deftypefun
+
+
 @deftypefun int MHD_digest_auth_check (struct MHD_Connection *connection, 
const char *realm, const char *username, const char *password, unsigned int 
nonce_timeout)
 Checks if the provided values in the WWW-Authenticate header are valid
 and sound according to RFC2716. If valid return @code{MHD_YES}, otherwise 
return @code{MHD_NO}.
+Deprecated, use @code{MHD_digest_auth_check2} instead.
+
 
 @var{realm} must reference to a zero-terminated string representing the realm.
 
@@ -2462,9 +2504,29 @@ most probably it will be the result of a lookup of the 
username against a local
 Most of the time it is sound to specify 300 seconds as its values.
 @end deftypefun
 
+
+
address@hidden int MHD_digest_auth_check_digest2 (struct MHD_Connection 
*connection, const char *realm, const char *username, const uint8_t *digest, 
unsigned int nonce_timeout, enum MHD_DigestAuthAlgorithm algo)
+Checks if the provided values in the WWW-Authenticate header are valid
+and sound according to RFC2716. If valid return @code{MHD_YES}, otherwise 
return @code{MHD_NO}.
+
address@hidden must reference to a zero-terminated string representing the 
realm.
+
address@hidden must reference to a zero-terminated string representing the 
username,
+it is usually the returned value from MHD_digest_auth_get_username.
+
address@hidden pointer to the binary MD5 sum for the precalculated hash value 
``userame:realm:password''. The size must match the selected @var{algo}!
+
address@hidden is the amount of time in seconds for a nonce to be invalid.
+Most of the time it is sound to specify 300 seconds as its values.
+
address@hidden digest authentication algorithm to use.
address@hidden deftypefun
+
 @deftypefun int MHD_digest_auth_check_digest (struct MHD_Connection 
*connection, const char *realm, const char *username, const unsigned char 
digest[MHD_MD5_DIGEST_SIZE], unsigned int nonce_timeout)
 Checks if the provided values in the WWW-Authenticate header are valid
 and sound according to RFC2716. If valid return @code{MHD_YES}, otherwise 
return @code{MHD_NO}.
+Deprecated, use @code{MHD_digest_auth_check_digest2} instead.
 
 @var{realm} must reference to a zero-terminated string representing the realm.
 
@@ -2477,6 +2539,31 @@ it is usually the returned value from 
MHD_digest_auth_get_username.
 Most of the time it is sound to specify 300 seconds as its values.
 @end deftypefun
 
+
address@hidden int MHD_queue_auth_fail_response2 (struct MHD_Connection 
*connection, const char *realm, const char *opaque, struct MHD_Response 
*response, int signal_stale, enum MHD_DigestAuthAlgorithm algo)
+Queues a response to request authentication from the client,
+return @code{MHD_YES} if successful, otherwise @code{MHD_NO}.
+
address@hidden must reference to a zero-terminated string representing the 
realm.
+
address@hidden must reference to a zero-terminated string representing a value
+that gets passed to the client and expected to be passed again to the server
+as-is. This value can be a hexadecimal or base64 string.
+
address@hidden a response structure to specify what shall be presented to the
+client with a 401 HTTP status.
+
address@hidden a value that signals "stale=true" in the response header to
+indicate the invalidity of the nonce and no need to ask for authentication
+parameters and only a new nonce gets generated. @code{MHD_YES} to generate a 
new
+nonce, @code{MHD_NO} to ask for authentication parameters.
+
address@hidden which digest algorithm should we use.  The same algorithm
+must then be selected when checking digests received from clients!
+
address@hidden deftypefun
+
+
 @deftypefun int MHD_queue_auth_fail_response (struct MHD_Connection 
*connection, const char *realm, const char *opaque, struct MHD_Response 
*response, int signal_stale)
 Queues a response to request authentication from the client,
 return @code{MHD_YES} if successful, otherwise @code{MHD_NO}.
@@ -2517,23 +2604,27 @@ ahc_echo (void *cls,
   const char *realm = "test@@example.com";
   int ret;
 
-  username = MHD_digest_auth_get_username(connection);
+  username = MHD_digest_auth_get_username (connection);
   if (username == NULL)
     @{
       response = MHD_create_response_from_buffer(strlen (DENIED),
                                                 DENIED,
                                                 MHD_RESPMEM_PERSISTENT);
-      ret = MHD_queue_auth_fail_response(connection, realm,
-                                        OPAQUE,
-                                        response,
-                                        MHD_NO);
+      ret = MHD_queue_auth_fail_response2 (connection,
+                                           realm,
+                                          OPAQUE,
+                                          response,
+                                          MHD_NO,
+                                           MHD_DIGEST_ALG_SHA256);
       MHD_destroy_response(response);
       return ret;
     @}
-  ret = MHD_digest_auth_check(connection, realm,
-                             username,
-                             password,
-                             300);
+  ret = MHD_digest_auth_check2 (connection,
+                                realm,
+                               username,
+                               password,
+                               300,
+                                MHD_DIGEST_ALG_SHA256);
   free(username);
   if ( (ret == MHD_INVALID_NONCE) ||
        (ret == MHD_NO) )
@@ -2543,16 +2634,21 @@ ahc_echo (void *cls,
                                                 MHD_RESPMEM_PERSISTENT);
       if (NULL == response)
        return MHD_NO;
-      ret = MHD_queue_auth_fail_response(connection, realm,
-                                        OPAQUE,
-                                        response,
-                                        (ret == MHD_INVALID_NONCE) ? MHD_YES : 
MHD_NO);
+      ret = MHD_queue_auth_fail_response2 (connection,
+                                           realm,
+                                          OPAQUE,
+                                          response,
+                                          (ret == MHD_INVALID_NONCE) ? MHD_YES 
: MHD_NO,
+                                           MHD_DIGEST_ALG_SHA256);
       MHD_destroy_response(response);
       return ret;
     @}
-  response = MHD_create_response_from_buffer (strlen(PAGE), PAGE,
+  response = MHD_create_response_from_buffer (strlen(PAGE),
+                                              PAGE,
                                              MHD_RESPMEM_PERSISTENT);
-  ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
+  ret = MHD_queue_response (connection,
+                            MHD_HTTP_OK,
+                            response);
   MHD_destroy_response(response);
   return ret;
 @}
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index 7591bdc4..2362d2bc 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -3331,7 +3331,7 @@ MHD_digest_auth_check_digest (struct MHD_Connection 
*connection,
  * @return #MHD_YES on success, #MHD_NO otherwise
  * @ingroup authentication
  */
-int
+_MHD_EXTERN int
 MHD_queue_auth_fail_response2 (struct MHD_Connection *connection,
                               const char *realm,
                               const char *opaque,
diff --git a/src/testcurl/.gitignore b/src/testcurl/.gitignore
index 5f2e7da2..747b4b9d 100644
--- a/src/testcurl/.gitignore
+++ b/src/testcurl/.gitignore
@@ -104,4 +104,4 @@
 *.exe
 test_quiesce_stream
 test_large_put_inc11
-/test_delete
\ No newline at end of file
+/test_deletetest_digestauth_sha256
diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am
index e564241c..fde060c5 100644
--- a/src/testcurl/Makefile.am
+++ b/src/testcurl/Makefile.am
@@ -23,7 +23,7 @@ THREAD_ONLY_TESTS = \
   test_long_header11 \
   test_iplimit11 \
   test_termination \
-  test_timeout 
+  test_timeout
 
 
 
@@ -42,6 +42,7 @@ endif
 if ENABLE_DAUTH
   THREAD_ONLY_TESTS += \
     test_digestauth \
+    test_digestauth_sha256 \
     test_digestauth_with_arguments
 endif
 
@@ -156,6 +157,12 @@ test_digestauth_LDADD = \
   $(top_builddir)/src/microhttpd/libmicrohttpd.la \
   @LIBGCRYPT_LIBS@ @LIBCURL@
 
+test_digestauth_sha256_SOURCES = \
+  test_digestauth_sha256.c
+test_digestauth_sha256_LDADD = \
+  $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+  @LIBGCRYPT_LIBS@ @LIBCURL@
+
 test_digestauth_with_arguments_SOURCES = \
   test_digestauth_with_arguments.c
 test_digestauth_with_arguments_LDADD = \
diff --git a/src/testcurl/test_digestauth_sha256.c 
b/src/testcurl/test_digestauth_sha256.c
new file mode 100644
index 00000000..aaa57bbe
--- /dev/null
+++ b/src/testcurl/test_digestauth_sha256.c
@@ -0,0 +1,314 @@
+/*
+     This file is part of libmicrohttpd
+     Copyright (C) 2010, 2018 Christian Grothoff
+
+     libmicrohttpd is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 2, or (at your
+     option) any later version.
+
+     libmicrohttpd is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with libmicrohttpd; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file daemontest_digestauth_sha256.c
+ * @brief  Testcase for libmicrohttpd Digest Auth with SHA256
+ * @author Amr Ali
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef HAVE_GCRYPT_H
+#include <gcrypt.h>
+#endif
+#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+
+#ifndef WINDOWS
+#include <sys/socket.h>
+#include <unistd.h>
+#else
+#include <wincrypt.h>
+#endif
+
+#define PAGE "<html><head><title>libmicrohttpd demo</title></head><body>Access 
granted</body></html>"
+
+#define DENIED "<html><head><title>libmicrohttpd 
demo</title></head><body>Access denied</body></html>"
+
+#define MY_OPAQUE "11733b200778ce33060f31c9af70a870ba96ddd4"
+
+struct CBC
+{
+  char *buf;
+  size_t pos;
+  size_t size;
+};
+
+
+static size_t
+copyBuffer (void *ptr,
+            size_t size,
+            size_t nmemb,
+            void *ctx)
+{
+  struct CBC *cbc = ctx;
+
+  if (cbc->pos + size * nmemb > cbc->size)
+    return 0;                   /* overflow */
+  memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+  cbc->pos += size * nmemb;
+  return size * nmemb;
+}
+
+
+static int
+ahc_echo (void *cls,
+          struct MHD_Connection *connection,
+          const char *url,
+          const char *method,
+          const char *version,
+          const char *upload_data,
+          size_t *upload_data_size,
+          void **unused)
+{
+  struct MHD_Response *response;
+  char *username;
+  const char *password = "testpass";
+  const char *realm = "address@hidden";
+  int ret;
+  (void)cls;(void)url;                          /* Unused. Silent compiler 
warning. */
+  (void)method;(void)version;(void)upload_data; /* Unused. Silent compiler 
warning. */
+  (void)upload_data_size;(void)unused;         /* Unused. Silent compiler 
warning. */
+
+  username = MHD_digest_auth_get_username (connection);
+  if ( (username == NULL) ||
+       (0 != strcmp (username, "testuser")) )
+    {
+      response = MHD_create_response_from_buffer (strlen (DENIED),
+                                                  DENIED,
+                                                  MHD_RESPMEM_PERSISTENT);
+      ret = MHD_queue_auth_fail_response2 (connection,
+                                           realm,
+                                           MY_OPAQUE,
+                                           response,
+                                           MHD_NO,
+                                           MHD_DIGEST_ALG_SHA256);
+      MHD_destroy_response(response);
+      return ret;
+    }
+  ret = MHD_digest_auth_check2 (connection,
+                                realm,
+                                username,
+                                password,
+                                300,
+                                MHD_DIGEST_ALG_SHA256);
+  free (username);
+  if ( (ret == MHD_INVALID_NONCE) ||
+       (ret == MHD_NO) )
+    {
+      response = MHD_create_response_from_buffer (strlen (DENIED),
+                                                  DENIED,
+                                                  MHD_RESPMEM_PERSISTENT);
+      if (NULL == response)
+       return MHD_NO;
+      ret = MHD_queue_auth_fail_response2 (connection,
+                                           realm,
+                                           MY_OPAQUE,
+                                           response,
+                                           (MHD_INVALID_NONCE == ret) ? 
MHD_YES : MHD_NO,
+                                           MHD_DIGEST_ALG_SHA256);
+      MHD_destroy_response(response);
+      return ret;
+    }
+  response = MHD_create_response_from_buffer (strlen(PAGE),
+                                              PAGE,
+                                              MHD_RESPMEM_PERSISTENT);
+  ret = MHD_queue_response (connection,
+                            MHD_HTTP_OK,
+                            response);
+  MHD_destroy_response (response);
+  return ret;
+}
+
+
+static int
+testDigestAuth ()
+{
+  CURL *c;
+  CURLcode errornum;
+  struct MHD_Daemon *d;
+  struct CBC cbc;
+  char buf[2048];
+  char rnd[8];
+  int port;
+  char url[128];
+#ifndef WINDOWS
+  int fd;
+  size_t len;
+  size_t off = 0;
+#endif /* ! WINDOWS */
+
+  if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
+    port = 0;
+  else
+    port = 1165;
+
+  cbc.buf = buf;
+  cbc.size = 2048;
+  cbc.pos = 0;
+#ifndef WINDOWS
+  fd = open ("/dev/urandom",
+             O_RDONLY);
+  if (-1 == fd)
+    {
+      fprintf (stderr,
+               "Failed to open `%s': %s\n",
+               "/dev/urandom",
+               strerror(errno));
+      return 1;
+    }
+  while (off < 8)
+    {
+      len = read (fd,
+                  rnd,
+                  8);
+      if (len == (size_t)-1)
+        {
+          fprintf (stderr,
+                   "Failed to read `%s': %s\n",
+                   "/dev/urandom",
+                   strerror(errno));
+          (void) close(fd);
+          return 1;
+        }
+      off += len;
+    }
+  (void) close(fd);
+#else
+  {
+    HCRYPTPROV cc;
+    BOOL b;
+
+    b = CryptAcquireContext (&cc,
+                             NULL,
+                             NULL,
+                             PROV_RSA_FULL,
+                             CRYPT_VERIFYCONTEXT);
+    if (b == 0)
+    {
+      fprintf (stderr,
+               "Failed to acquire crypto provider context: %lu\n",
+               GetLastError ());
+      return 1;
+    }
+    b = CryptGenRandom (cc, 8, (BYTE*)rnd);
+    if (b == 0)
+    {
+      fprintf (stderr,
+               "Failed to generate 8 random bytes: %lu\n",
+               GetLastError ());
+    }
+    CryptReleaseContext (cc, 0);
+    if (b == 0)
+      return 1;
+  }
+#endif
+  d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
+                        port, NULL, NULL,
+                        &ahc_echo, PAGE,
+                       MHD_OPTION_DIGEST_AUTH_RANDOM, sizeof (rnd), rnd,
+                       MHD_OPTION_NONCE_NC_SIZE, 300,
+                       MHD_OPTION_END);
+  if (d == NULL)
+    return 1;
+  if (0 == port)
+    {
+      const union MHD_DaemonInfo *dinfo;
+
+      dinfo = MHD_get_daemon_info (d,
+                                   MHD_DAEMON_INFO_BIND_PORT);
+      if ( (NULL == dinfo) ||
+           (0 == dinfo->port) )
+        {
+          MHD_stop_daemon (d);
+          return 32;
+        }
+      port = (int)dinfo->port;
+    }
+  snprintf (url,
+            sizeof (url),
+            "http://127.0.0.1:%d/bar%%20foo%%3Fkey%%3Dvalue";,
+            port);
+  c = curl_easy_init ();
+  curl_easy_setopt (c, CURLOPT_URL, url);
+  curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
+  curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+  curl_easy_setopt (c, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
+  curl_easy_setopt (c, CURLOPT_USERPWD, "testuser:testpass");
+  curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+  curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+  curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+  curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+  /* NOTE: use of CONNECTTIMEOUT without also
+     setting NOSIGNAL results in really weird
+     crashes on my system!*/
+  curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+  if (CURLE_OK != (errornum = curl_easy_perform (c)))
+    {
+      fprintf (stderr,
+               "curl_easy_perform failed: `%s'\n",
+               curl_easy_strerror (errornum));
+      curl_easy_cleanup (c);
+      MHD_stop_daemon (d);
+      return 2;
+    }
+  curl_easy_cleanup (c);
+  MHD_stop_daemon (d);
+  if (cbc.pos != strlen (PAGE))
+    return 4;
+  if (0 != strncmp (PAGE, cbc.buf, strlen (PAGE)))
+    return 8;
+  return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+  unsigned int errorCount = 0;
+  curl_version_info_data *d = curl_version_info (CURLVERSION_NOW);
+  (void)argc; (void)argv; /* Unused. Silent compiler warning. */
+
+  /* curl added SHA256 support in 7.57 = 7.0x39 */
+  if (d->version_num < 0x073900)
+    return 77; /* skip test, curl is too old */
+#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 */
+if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+    return 2;
+  errorCount += testDigestAuth ();
+  if (errorCount != 0)
+    fprintf (stderr, "Error (code: %u)\n", errorCount);
+  curl_global_cleanup ();
+  return errorCount != 0;       /* 0 == pass */
+}

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

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