[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, ©Buffer);
+ 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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] [libmicrohttpd] branch master updated: add test for RFC 7616 and document new API,
gnunet <=