diff options
author | Christian Grothoff <christian@grothoff.org> | 2018-12-08 22:54:33 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2018-12-08 22:54:33 +0100 |
commit | 2897bd23e57cf016a713876e551cd20b8a28427d (patch) | |
tree | 835d3e5972f83fd55eca47af047acdf3ce4eac23 | |
parent | bcba3f58c5fc9b4a3776494d3edddceb244ab110 (diff) | |
download | libmicrohttpd-2897bd23e57cf016a713876e551cd20b8a28427d.tar.gz libmicrohttpd-2897bd23e57cf016a713876e551cd20b8a28427d.zip |
add test for RFC 7616 and document new API
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | doc/libmicrohttpd.texi | 126 | ||||
-rw-r--r-- | src/include/microhttpd.h | 2 | ||||
-rw-r--r-- | src/testcurl/.gitignore | 2 | ||||
-rw-r--r-- | src/testcurl/Makefile.am | 9 | ||||
-rw-r--r-- | src/testcurl/test_digestauth_sha256.c | 314 |
6 files changed, 438 insertions, 18 deletions
@@ -1,3 +1,6 @@ | |||
1 | Sat Dec 8 22:53:56 CET 2018 | ||
2 | Added test for RFC 7616 and documented new API. -CG | ||
3 | |||
1 | Sat Dec 8 17:34:58 CET 2018 | 4 | Sat Dec 8 17:34:58 CET 2018 |
2 | Adding support for RFC 7616, experimental, needs | 5 | Adding support for RFC 7616, experimental, needs |
3 | testing and documentation still! -CG | 6 | 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. | |||
2440 | @node microhttpd-dauth digest | 2440 | @node microhttpd-dauth digest |
2441 | @section Using Digest Authentication | 2441 | @section Using Digest Authentication |
2442 | 2442 | ||
2443 | MHD supports MD5 (deprecated by IETF) and SHA-256 hash algorithms | ||
2444 | for digest authentication. The @code{MHD_DigestAuthAlgorithm} enumeration | ||
2445 | is used to specify which algorithm should be used. | ||
2446 | |||
2447 | @deftp {Enumeration} MHD_DigestAuthAlgorithm | ||
2448 | Which digest algorithm should be used. Must be used consistently. | ||
2449 | |||
2450 | @table @code | ||
2451 | @item MHD_DIGEST_ALG_AUTO | ||
2452 | Have MHD pick an algorithm currently considered secure. For now defaults to SHA-256. | ||
2453 | |||
2454 | @item MHD_DIGEST_ALG_MD5 | ||
2455 | Force use of (deprecated, ancient, insecure) MD5. | ||
2456 | |||
2457 | @item MHD_DIGEST_ALG_SHA256 | ||
2458 | Force use of SHA-256. | ||
2459 | |||
2460 | @end table | ||
2461 | @end deftp | ||
2462 | |||
2463 | |||
2443 | @deftypefun {char *} MHD_digest_auth_get_username (struct MHD_Connection *connection) | 2464 | @deftypefun {char *} MHD_digest_auth_get_username (struct MHD_Connection *connection) |
2444 | Find and return a pointer to the username value from the request header. | 2465 | Find and return a pointer to the username value from the request header. |
2445 | Return @code{NULL} if the value is not found or header does not exist. | 2466 | Return @code{NULL} if the value is not found or header does not exist. |
2446 | If returned value is not @code{NULL}, the value must be @code{MHD_free()}'ed. | 2467 | If returned value is not @code{NULL}, the value must be @code{MHD_free()}'ed. |
2447 | @end deftypefun | 2468 | @end deftypefun |
2448 | 2469 | ||
2470 | @deftypefun 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) | ||
2471 | Checks if the provided values in the WWW-Authenticate header are valid | ||
2472 | and sound according to RFC2716. If valid return @code{MHD_YES}, otherwise return @code{MHD_NO}. | ||
2473 | |||
2474 | @var{realm} must reference to a zero-terminated string representing the realm. | ||
2475 | |||
2476 | @var{username} must reference to a zero-terminated string representing the username, | ||
2477 | it is usually the returned value from MHD_digest_auth_get_username. | ||
2478 | |||
2479 | @var{password} must reference to a zero-terminated string representing the password, | ||
2480 | most probably it will be the result of a lookup of the username against a local database. | ||
2481 | |||
2482 | @var{nonce_timeout} is the amount of time in seconds for a nonce to be invalid. | ||
2483 | Most of the time it is sound to specify 300 seconds as its values. | ||
2484 | |||
2485 | @var{algo} which digest algorithm should we use. | ||
2486 | @end deftypefun | ||
2487 | |||
2488 | |||
2449 | @deftypefun int MHD_digest_auth_check (struct MHD_Connection *connection, const char *realm, const char *username, const char *password, unsigned int nonce_timeout) | 2489 | @deftypefun int MHD_digest_auth_check (struct MHD_Connection *connection, const char *realm, const char *username, const char *password, unsigned int nonce_timeout) |
2450 | Checks if the provided values in the WWW-Authenticate header are valid | 2490 | Checks if the provided values in the WWW-Authenticate header are valid |
2451 | and sound according to RFC2716. If valid return @code{MHD_YES}, otherwise return @code{MHD_NO}. | 2491 | and sound according to RFC2716. If valid return @code{MHD_YES}, otherwise return @code{MHD_NO}. |
2492 | Deprecated, use @code{MHD_digest_auth_check2} instead. | ||
2493 | |||
2452 | 2494 | ||
2453 | @var{realm} must reference to a zero-terminated string representing the realm. | 2495 | @var{realm} must reference to a zero-terminated string representing the realm. |
2454 | 2496 | ||
@@ -2462,9 +2504,29 @@ most probably it will be the result of a lookup of the username against a local | |||
2462 | Most of the time it is sound to specify 300 seconds as its values. | 2504 | Most of the time it is sound to specify 300 seconds as its values. |
2463 | @end deftypefun | 2505 | @end deftypefun |
2464 | 2506 | ||
2507 | |||
2508 | |||
2509 | @deftypefun 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) | ||
2510 | Checks if the provided values in the WWW-Authenticate header are valid | ||
2511 | and sound according to RFC2716. If valid return @code{MHD_YES}, otherwise return @code{MHD_NO}. | ||
2512 | |||
2513 | @var{realm} must reference to a zero-terminated string representing the realm. | ||
2514 | |||
2515 | @var{username} must reference to a zero-terminated string representing the username, | ||
2516 | it is usually the returned value from MHD_digest_auth_get_username. | ||
2517 | |||
2518 | @var{digest} pointer to the binary MD5 sum for the precalculated hash value ``userame:realm:password''. The size must match the selected @var{algo}! | ||
2519 | |||
2520 | @var{nonce_timeout} is the amount of time in seconds for a nonce to be invalid. | ||
2521 | Most of the time it is sound to specify 300 seconds as its values. | ||
2522 | |||
2523 | @var{algo} digest authentication algorithm to use. | ||
2524 | @end deftypefun | ||
2525 | |||
2465 | @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) | 2526 | @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) |
2466 | Checks if the provided values in the WWW-Authenticate header are valid | 2527 | Checks if the provided values in the WWW-Authenticate header are valid |
2467 | and sound according to RFC2716. If valid return @code{MHD_YES}, otherwise return @code{MHD_NO}. | 2528 | and sound according to RFC2716. If valid return @code{MHD_YES}, otherwise return @code{MHD_NO}. |
2529 | Deprecated, use @code{MHD_digest_auth_check_digest2} instead. | ||
2468 | 2530 | ||
2469 | @var{realm} must reference to a zero-terminated string representing the realm. | 2531 | @var{realm} must reference to a zero-terminated string representing the realm. |
2470 | 2532 | ||
@@ -2477,6 +2539,31 @@ it is usually the returned value from MHD_digest_auth_get_username. | |||
2477 | Most of the time it is sound to specify 300 seconds as its values. | 2539 | Most of the time it is sound to specify 300 seconds as its values. |
2478 | @end deftypefun | 2540 | @end deftypefun |
2479 | 2541 | ||
2542 | |||
2543 | @deftypefun 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) | ||
2544 | Queues a response to request authentication from the client, | ||
2545 | return @code{MHD_YES} if successful, otherwise @code{MHD_NO}. | ||
2546 | |||
2547 | @var{realm} must reference to a zero-terminated string representing the realm. | ||
2548 | |||
2549 | @var{opaque} must reference to a zero-terminated string representing a value | ||
2550 | that gets passed to the client and expected to be passed again to the server | ||
2551 | as-is. This value can be a hexadecimal or base64 string. | ||
2552 | |||
2553 | @var{response} a response structure to specify what shall be presented to the | ||
2554 | client with a 401 HTTP status. | ||
2555 | |||
2556 | @var{signal_stale} a value that signals "stale=true" in the response header to | ||
2557 | indicate the invalidity of the nonce and no need to ask for authentication | ||
2558 | parameters and only a new nonce gets generated. @code{MHD_YES} to generate a new | ||
2559 | nonce, @code{MHD_NO} to ask for authentication parameters. | ||
2560 | |||
2561 | @var{algo} which digest algorithm should we use. The same algorithm | ||
2562 | must then be selected when checking digests received from clients! | ||
2563 | |||
2564 | @end deftypefun | ||
2565 | |||
2566 | |||
2480 | @deftypefun int MHD_queue_auth_fail_response (struct MHD_Connection *connection, const char *realm, const char *opaque, struct MHD_Response *response, int signal_stale) | 2567 | @deftypefun int MHD_queue_auth_fail_response (struct MHD_Connection *connection, const char *realm, const char *opaque, struct MHD_Response *response, int signal_stale) |
2481 | Queues a response to request authentication from the client, | 2568 | Queues a response to request authentication from the client, |
2482 | return @code{MHD_YES} if successful, otherwise @code{MHD_NO}. | 2569 | return @code{MHD_YES} if successful, otherwise @code{MHD_NO}. |
@@ -2517,23 +2604,27 @@ ahc_echo (void *cls, | |||
2517 | const char *realm = "test@@example.com"; | 2604 | const char *realm = "test@@example.com"; |
2518 | int ret; | 2605 | int ret; |
2519 | 2606 | ||
2520 | username = MHD_digest_auth_get_username(connection); | 2607 | username = MHD_digest_auth_get_username (connection); |
2521 | if (username == NULL) | 2608 | if (username == NULL) |
2522 | @{ | 2609 | @{ |
2523 | response = MHD_create_response_from_buffer(strlen (DENIED), | 2610 | response = MHD_create_response_from_buffer(strlen (DENIED), |
2524 | DENIED, | 2611 | DENIED, |
2525 | MHD_RESPMEM_PERSISTENT); | 2612 | MHD_RESPMEM_PERSISTENT); |
2526 | ret = MHD_queue_auth_fail_response(connection, realm, | 2613 | ret = MHD_queue_auth_fail_response2 (connection, |
2527 | OPAQUE, | 2614 | realm, |
2528 | response, | 2615 | OPAQUE, |
2529 | MHD_NO); | 2616 | response, |
2617 | MHD_NO, | ||
2618 | MHD_DIGEST_ALG_SHA256); | ||
2530 | MHD_destroy_response(response); | 2619 | MHD_destroy_response(response); |
2531 | return ret; | 2620 | return ret; |
2532 | @} | 2621 | @} |
2533 | ret = MHD_digest_auth_check(connection, realm, | 2622 | ret = MHD_digest_auth_check2 (connection, |
2534 | username, | 2623 | realm, |
2535 | password, | 2624 | username, |
2536 | 300); | 2625 | password, |
2626 | 300, | ||
2627 | MHD_DIGEST_ALG_SHA256); | ||
2537 | free(username); | 2628 | free(username); |
2538 | if ( (ret == MHD_INVALID_NONCE) || | 2629 | if ( (ret == MHD_INVALID_NONCE) || |
2539 | (ret == MHD_NO) ) | 2630 | (ret == MHD_NO) ) |
@@ -2543,16 +2634,21 @@ ahc_echo (void *cls, | |||
2543 | MHD_RESPMEM_PERSISTENT); | 2634 | MHD_RESPMEM_PERSISTENT); |
2544 | if (NULL == response) | 2635 | if (NULL == response) |
2545 | return MHD_NO; | 2636 | return MHD_NO; |
2546 | ret = MHD_queue_auth_fail_response(connection, realm, | 2637 | ret = MHD_queue_auth_fail_response2 (connection, |
2547 | OPAQUE, | 2638 | realm, |
2548 | response, | 2639 | OPAQUE, |
2549 | (ret == MHD_INVALID_NONCE) ? MHD_YES : MHD_NO); | 2640 | response, |
2641 | (ret == MHD_INVALID_NONCE) ? MHD_YES : MHD_NO, | ||
2642 | MHD_DIGEST_ALG_SHA256); | ||
2550 | MHD_destroy_response(response); | 2643 | MHD_destroy_response(response); |
2551 | return ret; | 2644 | return ret; |
2552 | @} | 2645 | @} |
2553 | response = MHD_create_response_from_buffer (strlen(PAGE), PAGE, | 2646 | response = MHD_create_response_from_buffer (strlen(PAGE), |
2647 | PAGE, | ||
2554 | MHD_RESPMEM_PERSISTENT); | 2648 | MHD_RESPMEM_PERSISTENT); |
2555 | ret = MHD_queue_response(connection, MHD_HTTP_OK, response); | 2649 | ret = MHD_queue_response (connection, |
2650 | MHD_HTTP_OK, | ||
2651 | response); | ||
2556 | MHD_destroy_response(response); | 2652 | MHD_destroy_response(response); |
2557 | return ret; | 2653 | return ret; |
2558 | @} | 2654 | @} |
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, | |||
3331 | * @return #MHD_YES on success, #MHD_NO otherwise | 3331 | * @return #MHD_YES on success, #MHD_NO otherwise |
3332 | * @ingroup authentication | 3332 | * @ingroup authentication |
3333 | */ | 3333 | */ |
3334 | int | 3334 | _MHD_EXTERN int |
3335 | MHD_queue_auth_fail_response2 (struct MHD_Connection *connection, | 3335 | MHD_queue_auth_fail_response2 (struct MHD_Connection *connection, |
3336 | const char *realm, | 3336 | const char *realm, |
3337 | const char *opaque, | 3337 | 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 @@ | |||
104 | *.exe | 104 | *.exe |
105 | test_quiesce_stream | 105 | test_quiesce_stream |
106 | test_large_put_inc11 | 106 | test_large_put_inc11 |
107 | /test_delete \ No newline at end of file | 107 | /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 = \ | |||
23 | test_long_header11 \ | 23 | test_long_header11 \ |
24 | test_iplimit11 \ | 24 | test_iplimit11 \ |
25 | test_termination \ | 25 | test_termination \ |
26 | test_timeout | 26 | test_timeout |
27 | 27 | ||
28 | 28 | ||
29 | 29 | ||
@@ -42,6 +42,7 @@ endif | |||
42 | if ENABLE_DAUTH | 42 | if ENABLE_DAUTH |
43 | THREAD_ONLY_TESTS += \ | 43 | THREAD_ONLY_TESTS += \ |
44 | test_digestauth \ | 44 | test_digestauth \ |
45 | test_digestauth_sha256 \ | ||
45 | test_digestauth_with_arguments | 46 | test_digestauth_with_arguments |
46 | endif | 47 | endif |
47 | 48 | ||
@@ -156,6 +157,12 @@ test_digestauth_LDADD = \ | |||
156 | $(top_builddir)/src/microhttpd/libmicrohttpd.la \ | 157 | $(top_builddir)/src/microhttpd/libmicrohttpd.la \ |
157 | @LIBGCRYPT_LIBS@ @LIBCURL@ | 158 | @LIBGCRYPT_LIBS@ @LIBCURL@ |
158 | 159 | ||
160 | test_digestauth_sha256_SOURCES = \ | ||
161 | test_digestauth_sha256.c | ||
162 | test_digestauth_sha256_LDADD = \ | ||
163 | $(top_builddir)/src/microhttpd/libmicrohttpd.la \ | ||
164 | @LIBGCRYPT_LIBS@ @LIBCURL@ | ||
165 | |||
159 | test_digestauth_with_arguments_SOURCES = \ | 166 | test_digestauth_with_arguments_SOURCES = \ |
160 | test_digestauth_with_arguments.c | 167 | test_digestauth_with_arguments.c |
161 | test_digestauth_with_arguments_LDADD = \ | 168 | 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 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | Copyright (C) 2010, 2018 Christian Grothoff | ||
4 | |||
5 | libmicrohttpd is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | libmicrohttpd is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with libmicrohttpd; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file daemontest_digestauth_sha256.c | ||
23 | * @brief Testcase for libmicrohttpd Digest Auth with SHA256 | ||
24 | * @author Amr Ali | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | |||
28 | #include "MHD_config.h" | ||
29 | #include "platform.h" | ||
30 | #include <curl/curl.h> | ||
31 | #include <microhttpd.h> | ||
32 | #include <stdlib.h> | ||
33 | #include <string.h> | ||
34 | #include <time.h> | ||
35 | #ifdef MHD_HTTPS_REQUIRE_GRYPT | ||
36 | #ifdef HAVE_GCRYPT_H | ||
37 | #include <gcrypt.h> | ||
38 | #endif | ||
39 | #endif /* MHD_HTTPS_REQUIRE_GRYPT */ | ||
40 | |||
41 | #ifndef WINDOWS | ||
42 | #include <sys/socket.h> | ||
43 | #include <unistd.h> | ||
44 | #else | ||
45 | #include <wincrypt.h> | ||
46 | #endif | ||
47 | |||
48 | #define PAGE "<html><head><title>libmicrohttpd demo</title></head><body>Access granted</body></html>" | ||
49 | |||
50 | #define DENIED "<html><head><title>libmicrohttpd demo</title></head><body>Access denied</body></html>" | ||
51 | |||
52 | #define MY_OPAQUE "11733b200778ce33060f31c9af70a870ba96ddd4" | ||
53 | |||
54 | struct CBC | ||
55 | { | ||
56 | char *buf; | ||
57 | size_t pos; | ||
58 | size_t size; | ||
59 | }; | ||
60 | |||
61 | |||
62 | static size_t | ||
63 | copyBuffer (void *ptr, | ||
64 | size_t size, | ||
65 | size_t nmemb, | ||
66 | void *ctx) | ||
67 | { | ||
68 | struct CBC *cbc = ctx; | ||
69 | |||
70 | if (cbc->pos + size * nmemb > cbc->size) | ||
71 | return 0; /* overflow */ | ||
72 | memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); | ||
73 | cbc->pos += size * nmemb; | ||
74 | return size * nmemb; | ||
75 | } | ||
76 | |||
77 | |||
78 | static int | ||
79 | ahc_echo (void *cls, | ||
80 | struct MHD_Connection *connection, | ||
81 | const char *url, | ||
82 | const char *method, | ||
83 | const char *version, | ||
84 | const char *upload_data, | ||
85 | size_t *upload_data_size, | ||
86 | void **unused) | ||
87 | { | ||
88 | struct MHD_Response *response; | ||
89 | char *username; | ||
90 | const char *password = "testpass"; | ||
91 | const char *realm = "test@example.com"; | ||
92 | int ret; | ||
93 | (void)cls;(void)url; /* Unused. Silent compiler warning. */ | ||
94 | (void)method;(void)version;(void)upload_data; /* Unused. Silent compiler warning. */ | ||
95 | (void)upload_data_size;(void)unused; /* Unused. Silent compiler warning. */ | ||
96 | |||
97 | username = MHD_digest_auth_get_username (connection); | ||
98 | if ( (username == NULL) || | ||
99 | (0 != strcmp (username, "testuser")) ) | ||
100 | { | ||
101 | response = MHD_create_response_from_buffer (strlen (DENIED), | ||
102 | DENIED, | ||
103 | MHD_RESPMEM_PERSISTENT); | ||
104 | ret = MHD_queue_auth_fail_response2 (connection, | ||
105 | realm, | ||
106 | MY_OPAQUE, | ||
107 | response, | ||
108 | MHD_NO, | ||
109 | MHD_DIGEST_ALG_SHA256); | ||
110 | MHD_destroy_response(response); | ||
111 | return ret; | ||
112 | } | ||
113 | ret = MHD_digest_auth_check2 (connection, | ||
114 | realm, | ||
115 | username, | ||
116 | password, | ||
117 | 300, | ||
118 | MHD_DIGEST_ALG_SHA256); | ||
119 | free (username); | ||
120 | if ( (ret == MHD_INVALID_NONCE) || | ||
121 | (ret == MHD_NO) ) | ||
122 | { | ||
123 | response = MHD_create_response_from_buffer (strlen (DENIED), | ||
124 | DENIED, | ||
125 | MHD_RESPMEM_PERSISTENT); | ||
126 | if (NULL == response) | ||
127 | return MHD_NO; | ||
128 | ret = MHD_queue_auth_fail_response2 (connection, | ||
129 | realm, | ||
130 | MY_OPAQUE, | ||
131 | response, | ||
132 | (MHD_INVALID_NONCE == ret) ? MHD_YES : MHD_NO, | ||
133 | MHD_DIGEST_ALG_SHA256); | ||
134 | MHD_destroy_response(response); | ||
135 | return ret; | ||
136 | } | ||
137 | response = MHD_create_response_from_buffer (strlen(PAGE), | ||
138 | PAGE, | ||
139 | MHD_RESPMEM_PERSISTENT); | ||
140 | ret = MHD_queue_response (connection, | ||
141 | MHD_HTTP_OK, | ||
142 | response); | ||
143 | MHD_destroy_response (response); | ||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | |||
148 | static int | ||
149 | testDigestAuth () | ||
150 | { | ||
151 | CURL *c; | ||
152 | CURLcode errornum; | ||
153 | struct MHD_Daemon *d; | ||
154 | struct CBC cbc; | ||
155 | char buf[2048]; | ||
156 | char rnd[8]; | ||
157 | int port; | ||
158 | char url[128]; | ||
159 | #ifndef WINDOWS | ||
160 | int fd; | ||
161 | size_t len; | ||
162 | size_t off = 0; | ||
163 | #endif /* ! WINDOWS */ | ||
164 | |||
165 | if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) | ||
166 | port = 0; | ||
167 | else | ||
168 | port = 1165; | ||
169 | |||
170 | cbc.buf = buf; | ||
171 | cbc.size = 2048; | ||
172 | cbc.pos = 0; | ||
173 | #ifndef WINDOWS | ||
174 | fd = open ("/dev/urandom", | ||
175 | O_RDONLY); | ||
176 | if (-1 == fd) | ||
177 | { | ||
178 | fprintf (stderr, | ||
179 | "Failed to open `%s': %s\n", | ||
180 | "/dev/urandom", | ||
181 | strerror(errno)); | ||
182 | return 1; | ||
183 | } | ||
184 | while (off < 8) | ||
185 | { | ||
186 | len = read (fd, | ||
187 | rnd, | ||
188 | 8); | ||
189 | if (len == (size_t)-1) | ||
190 | { | ||
191 | fprintf (stderr, | ||
192 | "Failed to read `%s': %s\n", | ||
193 | "/dev/urandom", | ||
194 | strerror(errno)); | ||
195 | (void) close(fd); | ||
196 | return 1; | ||
197 | } | ||
198 | off += len; | ||
199 | } | ||
200 | (void) close(fd); | ||
201 | #else | ||
202 | { | ||
203 | HCRYPTPROV cc; | ||
204 | BOOL b; | ||
205 | |||
206 | b = CryptAcquireContext (&cc, | ||
207 | NULL, | ||
208 | NULL, | ||
209 | PROV_RSA_FULL, | ||
210 | CRYPT_VERIFYCONTEXT); | ||
211 | if (b == 0) | ||
212 | { | ||
213 | fprintf (stderr, | ||
214 | "Failed to acquire crypto provider context: %lu\n", | ||
215 | GetLastError ()); | ||
216 | return 1; | ||
217 | } | ||
218 | b = CryptGenRandom (cc, 8, (BYTE*)rnd); | ||
219 | if (b == 0) | ||
220 | { | ||
221 | fprintf (stderr, | ||
222 | "Failed to generate 8 random bytes: %lu\n", | ||
223 | GetLastError ()); | ||
224 | } | ||
225 | CryptReleaseContext (cc, 0); | ||
226 | if (b == 0) | ||
227 | return 1; | ||
228 | } | ||
229 | #endif | ||
230 | d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, | ||
231 | port, NULL, NULL, | ||
232 | &ahc_echo, PAGE, | ||
233 | MHD_OPTION_DIGEST_AUTH_RANDOM, sizeof (rnd), rnd, | ||
234 | MHD_OPTION_NONCE_NC_SIZE, 300, | ||
235 | MHD_OPTION_END); | ||
236 | if (d == NULL) | ||
237 | return 1; | ||
238 | if (0 == port) | ||
239 | { | ||
240 | const union MHD_DaemonInfo *dinfo; | ||
241 | |||
242 | dinfo = MHD_get_daemon_info (d, | ||
243 | MHD_DAEMON_INFO_BIND_PORT); | ||
244 | if ( (NULL == dinfo) || | ||
245 | (0 == dinfo->port) ) | ||
246 | { | ||
247 | MHD_stop_daemon (d); | ||
248 | return 32; | ||
249 | } | ||
250 | port = (int)dinfo->port; | ||
251 | } | ||
252 | snprintf (url, | ||
253 | sizeof (url), | ||
254 | "http://127.0.0.1:%d/bar%%20foo%%3Fkey%%3Dvalue", | ||
255 | port); | ||
256 | c = curl_easy_init (); | ||
257 | curl_easy_setopt (c, CURLOPT_URL, url); | ||
258 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
259 | curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); | ||
260 | curl_easy_setopt (c, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); | ||
261 | curl_easy_setopt (c, CURLOPT_USERPWD, "testuser:testpass"); | ||
262 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
263 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); | ||
264 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); | ||
265 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
266 | /* NOTE: use of CONNECTTIMEOUT without also | ||
267 | setting NOSIGNAL results in really weird | ||
268 | crashes on my system!*/ | ||
269 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
270 | if (CURLE_OK != (errornum = curl_easy_perform (c))) | ||
271 | { | ||
272 | fprintf (stderr, | ||
273 | "curl_easy_perform failed: `%s'\n", | ||
274 | curl_easy_strerror (errornum)); | ||
275 | curl_easy_cleanup (c); | ||
276 | MHD_stop_daemon (d); | ||
277 | return 2; | ||
278 | } | ||
279 | curl_easy_cleanup (c); | ||
280 | MHD_stop_daemon (d); | ||
281 | if (cbc.pos != strlen (PAGE)) | ||
282 | return 4; | ||
283 | if (0 != strncmp (PAGE, cbc.buf, strlen (PAGE))) | ||
284 | return 8; | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | |||
289 | int | ||
290 | main (int argc, char *const *argv) | ||
291 | { | ||
292 | unsigned int errorCount = 0; | ||
293 | curl_version_info_data *d = curl_version_info (CURLVERSION_NOW); | ||
294 | (void)argc; (void)argv; /* Unused. Silent compiler warning. */ | ||
295 | |||
296 | /* curl added SHA256 support in 7.57 = 7.0x39 */ | ||
297 | if (d->version_num < 0x073900) | ||
298 | return 77; /* skip test, curl is too old */ | ||
299 | #ifdef MHD_HTTPS_REQUIRE_GRYPT | ||
300 | #ifdef HAVE_GCRYPT_H | ||
301 | gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); | ||
302 | #ifdef GCRYCTL_INITIALIZATION_FINISHED | ||
303 | gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); | ||
304 | #endif | ||
305 | #endif | ||
306 | #endif /* MHD_HTTPS_REQUIRE_GRYPT */ | ||
307 | if (0 != curl_global_init (CURL_GLOBAL_WIN32)) | ||
308 | return 2; | ||
309 | errorCount += testDigestAuth (); | ||
310 | if (errorCount != 0) | ||
311 | fprintf (stderr, "Error (code: %u)\n", errorCount); | ||
312 | curl_global_cleanup (); | ||
313 | return errorCount != 0; /* 0 == pass */ | ||
314 | } | ||