aboutsummaryrefslogtreecommitdiff
path: root/src/testcurl
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2022-07-25 10:17:53 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2022-07-28 07:21:36 +0300
commit2fd1a01fe010ea47654fd6b3053af619fb96dc37 (patch)
tree47122c5924ea59a1c01847915fe63c91d04717bd /src/testcurl
parentc03c57c9d2d95bd739ab8a149597658d1ec95478 (diff)
downloadlibmicrohttpd-2fd1a01fe010ea47654fd6b3053af619fb96dc37.tar.gz
libmicrohttpd-2fd1a01fe010ea47654fd6b3053af619fb96dc37.zip
test_digestauth2: added new group of tests for Digest Auth checking
Diffstat (limited to 'src/testcurl')
-rw-r--r--src/testcurl/.gitignore5
-rw-r--r--src/testcurl/Makefile.am22
-rw-r--r--src/testcurl/test_digestauth2.c1159
3 files changed, 1185 insertions, 1 deletions
diff --git a/src/testcurl/.gitignore b/src/testcurl/.gitignore
index e23f52c9..26e59bfc 100644
--- a/src/testcurl/.gitignore
+++ b/src/testcurl/.gitignore
@@ -157,3 +157,8 @@ core
157/test_basicauth_preauth_oldapi 157/test_basicauth_preauth_oldapi
158/test_digestauth_emu_ext 158/test_digestauth_emu_ext
159/test_digestauth_emu_ext_oldapi 159/test_digestauth_emu_ext_oldapi
160/test_digestauth2
161/test_digestauth2_oldapi
162/test_digestauth2_userhash
163/test_digestauth2_sha256
164/test_digestauth2_sha256_userhash
diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am
index e46bbb2d..749e31e2 100644
--- a/src/testcurl/Makefile.am
+++ b/src/testcurl/Makefile.am
@@ -169,7 +169,12 @@ THREAD_ONLY_TESTS += \
169 169
170check_PROGRAMS += \ 170check_PROGRAMS += \
171 test_digestauth_emu_ext \ 171 test_digestauth_emu_ext \
172 test_digestauth_emu_ext_oldapi 172 test_digestauth_emu_ext_oldapi \
173 test_digestauth2 \
174 test_digestauth2_oldapi \
175 test_digestauth2_userhash \
176 test_digestauth2_sha256 \
177 test_digestauth2_sha256_userhash
173endif 178endif
174 179
175if HEAVY_TESTS 180if HEAVY_TESTS
@@ -279,6 +284,21 @@ test_digestauth_emu_ext_SOURCES = \
279test_digestauth_emu_ext_oldapi_SOURCES = \ 284test_digestauth_emu_ext_oldapi_SOURCES = \
280 test_digestauth_emu_ext.c 285 test_digestauth_emu_ext.c
281 286
287test_digestauth2_SOURCES = \
288 test_digestauth2.c mhd_has_param.h mhd_has_in_name.h
289
290test_digestauth2_oldapi_SOURCES = \
291 test_digestauth2.c mhd_has_param.h mhd_has_in_name.h
292
293test_digestauth2_userhash_SOURCES = \
294 test_digestauth2.c mhd_has_param.h mhd_has_in_name.h
295
296test_digestauth2_sha256_SOURCES = \
297 test_digestauth2.c mhd_has_param.h mhd_has_in_name.h
298
299test_digestauth2_sha256_userhash_SOURCES = \
300 test_digestauth2.c mhd_has_param.h mhd_has_in_name.h
301
282test_get_iovec_SOURCES = \ 302test_get_iovec_SOURCES = \
283 test_get_iovec.c mhd_has_in_name.h 303 test_get_iovec.c mhd_has_in_name.h
284 304
diff --git a/src/testcurl/test_digestauth2.c b/src/testcurl/test_digestauth2.c
new file mode 100644
index 00000000..0d6b844a
--- /dev/null
+++ b/src/testcurl/test_digestauth2.c
@@ -0,0 +1,1159 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2010 Christian Grothoff
4 Copyright (C) 2016-2022 Evgeny Grin (Karlson2k)
5
6 libmicrohttpd is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 2, or (at your
9 option) any later version.
10
11 libmicrohttpd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with libmicrohttpd; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22/**
23 * @file test_digest2.c
24 * @brief Testcase for MHD Digest Authorisation
25 * @author Karlson2k (Evgeny Grin)
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
36#ifndef _WIN32
37#include <sys/socket.h>
38#include <unistd.h>
39#else
40#include <wincrypt.h>
41#endif
42
43#include "mhd_has_param.h"
44#include "mhd_has_in_name.h"
45
46#ifndef MHD_STATICSTR_LEN_
47/**
48 * Determine length of static string / macro strings at compile time.
49 */
50#define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1)
51#endif /* ! MHD_STATICSTR_LEN_ */
52
53#ifndef CURL_VERSION_BITS
54#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z))
55#endif /* ! CURL_VERSION_BITS */
56#ifndef CURL_AT_LEAST_VERSION
57#define CURL_AT_LEAST_VERSION(x,y,z) \
58 (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z))
59#endif /* ! CURL_AT_LEAST_VERSION */
60
61#ifndef _MHD_INSTRMACRO
62/* Quoted macro parameter */
63#define _MHD_INSTRMACRO(a) #a
64#endif /* ! _MHD_INSTRMACRO */
65#ifndef _MHD_STRMACRO
66/* Quoted expanded macro parameter */
67#define _MHD_STRMACRO(a) _MHD_INSTRMACRO (a)
68#endif /* ! _MHD_STRMACRO */
69
70#if defined(HAVE___FUNC__)
71#define externalErrorExit(ignore) \
72 _externalErrorExit_func(NULL, __func__, __LINE__)
73#define externalErrorExitDesc(errDesc) \
74 _externalErrorExit_func(errDesc, __func__, __LINE__)
75#define libcurlErrorExit(ignore) \
76 _libcurlErrorExit_func(NULL, __func__, __LINE__)
77#define libcurlErrorExitDesc(errDesc) \
78 _libcurlErrorExit_func(errDesc, __func__, __LINE__)
79#define mhdErrorExit(ignore) \
80 _mhdErrorExit_func(NULL, __func__, __LINE__)
81#define mhdErrorExitDesc(errDesc) \
82 _mhdErrorExit_func(errDesc, __func__, __LINE__)
83#define checkCURLE_OK(libcurlcall) \
84 _checkCURLE_OK_func((libcurlcall), _MHD_STRMACRO(libcurlcall), \
85 __func__, __LINE__)
86#elif defined(HAVE___FUNCTION__)
87#define externalErrorExit(ignore) \
88 _externalErrorExit_func(NULL, __FUNCTION__, __LINE__)
89#define externalErrorExitDesc(errDesc) \
90 _externalErrorExit_func(errDesc, __FUNCTION__, __LINE__)
91#define libcurlErrorExit(ignore) \
92 _libcurlErrorExit_func(NULL, __FUNCTION__, __LINE__)
93#define libcurlErrorExitDesc(errDesc) \
94 _libcurlErrorExit_func(errDesc, __FUNCTION__, __LINE__)
95#define mhdErrorExit(ignore) \
96 _mhdErrorExit_func(NULL, __FUNCTION__, __LINE__)
97#define mhdErrorExitDesc(errDesc) \
98 _mhdErrorExit_func(errDesc, __FUNCTION__, __LINE__)
99#define checkCURLE_OK(libcurlcall) \
100 _checkCURLE_OK_func((libcurlcall), _MHD_STRMACRO(libcurlcall), \
101 __FUNCTION__, __LINE__)
102#else
103#define externalErrorExit(ignore) _externalErrorExit_func(NULL, NULL, __LINE__)
104#define externalErrorExitDesc(errDesc) \
105 _externalErrorExit_func(errDesc, NULL, __LINE__)
106#define libcurlErrorExit(ignore) _libcurlErrorExit_func(NULL, NULL, __LINE__)
107#define libcurlErrorExitDesc(errDesc) \
108 _libcurlErrorExit_func(errDesc, NULL, __LINE__)
109#define mhdErrorExit(ignore) _mhdErrorExit_func(NULL, NULL, __LINE__)
110#define mhdErrorExitDesc(errDesc) _mhdErrorExit_func(errDesc, NULL, __LINE__)
111#define checkCURLE_OK(libcurlcall) \
112 _checkCURLE_OK_func((libcurlcall), _MHD_STRMACRO(libcurlcall), NULL, __LINE__)
113#endif
114
115
116_MHD_NORETURN static void
117_externalErrorExit_func (const char *errDesc, const char *funcName, int lineNum)
118{
119 fflush (stdout);
120 if ((NULL != errDesc) && (0 != errDesc[0]))
121 fprintf (stderr, "%s", errDesc);
122 else
123 fprintf (stderr, "System or external library call failed");
124 if ((NULL != funcName) && (0 != funcName[0]))
125 fprintf (stderr, " in %s", funcName);
126 if (0 < lineNum)
127 fprintf (stderr, " at line %d", lineNum);
128
129 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno,
130 strerror (errno));
131#ifdef MHD_WINSOCK_SOCKETS
132 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ());
133#endif /* MHD_WINSOCK_SOCKETS */
134 fflush (stderr);
135 exit (99);
136}
137
138
139/* Not actually used in this test */
140static char libcurl_errbuf[CURL_ERROR_SIZE] = "";
141
142_MHD_NORETURN static void
143_libcurlErrorExit_func (const char *errDesc, const char *funcName, int lineNum)
144{
145 fflush (stdout);
146 if ((NULL != errDesc) && (0 != errDesc[0]))
147 fprintf (stderr, "%s", errDesc);
148 else
149 fprintf (stderr, "CURL library call failed");
150 if ((NULL != funcName) && (0 != funcName[0]))
151 fprintf (stderr, " in %s", funcName);
152 if (0 < lineNum)
153 fprintf (stderr, " at line %d", lineNum);
154
155 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno,
156 strerror (errno));
157#ifdef MHD_WINSOCK_SOCKETS
158 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ());
159#endif /* MHD_WINSOCK_SOCKETS */
160 if (0 != libcurl_errbuf[0])
161 fprintf (stderr, "Last libcurl error description: %s\n", libcurl_errbuf);
162
163 fflush (stderr);
164 exit (99);
165}
166
167
168_MHD_NORETURN static void
169_mhdErrorExit_func (const char *errDesc, const char *funcName, int lineNum)
170{
171 fflush (stdout);
172 if ((NULL != errDesc) && (0 != errDesc[0]))
173 fprintf (stderr, "%s", errDesc);
174 else
175 fprintf (stderr, "MHD unexpected error");
176 if ((NULL != funcName) && (0 != funcName[0]))
177 fprintf (stderr, " in %s", funcName);
178 if (0 < lineNum)
179 fprintf (stderr, " at line %d", lineNum);
180
181 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno,
182 strerror (errno));
183#ifdef MHD_WINSOCK_SOCKETS
184 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ());
185#endif /* MHD_WINSOCK_SOCKETS */
186
187 fflush (stderr);
188 exit (8);
189}
190
191
192#if 0
193/* Function unused in this test */
194static void
195_checkCURLE_OK_func (CURLcode code, const char *curlFunc,
196 const char *funcName, int lineNum)
197{
198 if (CURLE_OK == code)
199 return;
200
201 fflush (stdout);
202 if ((NULL != curlFunc) && (0 != curlFunc[0]))
203 fprintf (stderr, "'%s' resulted in '%s'", curlFunc,
204 curl_easy_strerror (code));
205 else
206 fprintf (stderr, "libcurl function call resulted in '%s'",
207 curl_easy_strerror (code));
208 if ((NULL != funcName) && (0 != funcName[0]))
209 fprintf (stderr, " in %s", funcName);
210 if (0 < lineNum)
211 fprintf (stderr, " at line %d", lineNum);
212
213 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno,
214 strerror (errno));
215 if (0 != libcurl_errbuf[0])
216 fprintf (stderr, "Last libcurl error description: %s\n", libcurl_errbuf);
217
218 fflush (stderr);
219 exit (9);
220}
221
222
223#endif
224
225
226/* Could be increased to facilitate debugging */
227#define TIMEOUTS_VAL 10
228
229#define MHD_URI_BASE_PATH "/bar%20foo?key=value"
230
231#define REALM "TestRealm"
232#define USERNAME1 "test_user"
233/* The hex form of MD5("test_user:TestRealm") */
234#define USERHASH1_MD5_HEX "c53c601503ff176f18f623725fba4281"
235#define USERHASH1_MD5_BIN 0xc5, 0x3c, 0x60, 0x15, 0x03, 0xff, 0x17, 0x6f, \
236 0x18, 0xf6, 0x23, 0x72, 0x5f, 0xba, 0x42, 0x81
237/* The hex form of SHA-256("test_user:TestRealm") */
238#define USERHASH1_SHA256_HEX \
239 "090c7e06b77d6614cf5fe6cafa004d2e5f8fb36ba45a0e35eacb2eb7728f34de"
240/* The binary form of SHA-256("test_user:TestRealm") */
241#define USERHASH1_SHA256_BIN 0x09, 0x0c, 0x7e, 0x06, 0xb7, 0x7d, 0x66, 0x14, \
242 0xcf, 0x5f, 0xe6, 0xca, 0xfa, 0x00, 0x4d, 0x2e, 0x5f, 0x8f, 0xb3, 0x6b, \
243 0xa4, 0x5a, 0x0e, 0x35, 0xea, 0xcb, 0x2e, 0xb7, 0x72, 0x8f, 0x34, 0xde
244/* "titkos szuperügynök" in UTF-8 */
245#define USERNAME2 "titkos szuper" "\xC3\xBC" "gyn" "\xC3\xB6" "k"
246/* percent-encoded username */
247#define USERNAME2_PCTENC "titkos%20szuper%C3%BCgyn%C3%B6k"
248#define PASSWORD_VALUE "test pass"
249#define OPAQUE_VALUE "opaque+content" /* Base64 character set */
250
251
252#define PAGE \
253 "<html><head><title>libmicrohttpd demo page</title>" \
254 "</head><body>Access granted</body></html>"
255
256#define DENIED \
257 "<html><head><title>libmicrohttpd - Access denied</title>" \
258 "</head><body>Access denied</body></html>"
259
260/* Global parameters */
261static int verbose;
262static int test_oldapi;
263static int test_userhash;
264static int test_sha256;
265static int curl_uses_usehash;
266
267/* Static helper variables */
268static const char userhash1_md5_hex[] = USERHASH1_MD5_HEX;
269static const uint8_t userhash1_md5_bin[] = { USERHASH1_MD5_BIN };
270static const char userhash1_sha256_hex[] = USERHASH1_SHA256_HEX;
271static const uint8_t userhash1_sha256_bin[] = { USERHASH1_SHA256_BIN };
272static const char *userhash1_hex;
273static size_t userhash1_hex_len;
274static const uint8_t *userhash1_bin;
275static const char *username_ptr;
276
277static void
278test_global_init (void)
279{
280 libcurl_errbuf[0] = 0;
281
282 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
283 externalErrorExit ();
284
285 username_ptr = USERNAME1;
286 if (! test_sha256)
287 {
288 userhash1_hex = userhash1_md5_hex;
289 userhash1_hex_len = MHD_STATICSTR_LEN_ (userhash1_md5_hex);
290 userhash1_bin = userhash1_md5_bin;
291 if ((userhash1_hex_len / 2) != \
292 (sizeof(userhash1_md5_bin) / sizeof(userhash1_md5_bin[0])))
293 externalErrorExitDesc ("Wrong size of the 'userhash1_md5_bin' array");
294 }
295 else
296 {
297 userhash1_hex = userhash1_sha256_hex;
298 userhash1_hex_len = MHD_STATICSTR_LEN_ (userhash1_sha256_hex);
299 userhash1_bin = userhash1_sha256_bin;
300 if ((userhash1_hex_len / 2) != \
301 (sizeof(userhash1_sha256_bin) \
302 / sizeof(userhash1_sha256_bin[0])))
303 externalErrorExitDesc ("Wrong size of the 'userhash1_sha256_bin' array");
304 }
305}
306
307
308static void
309test_global_cleanup (void)
310{
311 curl_global_cleanup ();
312}
313
314
315static int
316gen_good_rnd (void *rnd_buf, size_t rnd_buf_size)
317{
318 if (1024 < rnd_buf_size)
319 externalErrorExitDesc ("Too large amount of random data " \
320 "is requested");
321#ifndef _WIN32
322 if (1)
323 {
324 const int urand_fd = open ("/dev/urandom", O_RDONLY);
325 if (0 < urand_fd)
326 {
327 size_t pos = 0;
328 do
329 {
330 ssize_t res = read (urand_fd,
331 ((uint8_t *) rnd_buf) + pos, rnd_buf_size - pos);
332 if (0 > res)
333 break;
334 pos += (size_t) res;
335 } while (rnd_buf_size > pos);
336 (void) close (urand_fd);
337
338 if (rnd_buf_size == pos)
339 return ! 0; /* Success */
340 }
341 }
342#else /* _WIN32 */
343 if (1)
344 {
345 HCRYPTPROV cpr_hndl;
346 if (CryptAcquireContextW (&cpr_hndl, NULL, NULL, PROV_RSA_FULL,
347 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
348 {
349 if (CryptGenRandom (cpr_hndl, (DWORD) rnd_buf_size, (BYTE *) rnd_buf))
350 {
351 (void) CryptReleaseContext (cpr_hndl, 0);
352 return ! 0; /* Success */
353 }
354 (void) CryptReleaseContext (cpr_hndl, 0);
355 }
356 }
357#endif /* _WIN32 */
358 return 0; /* Failure */
359}
360
361
362struct CBC
363{
364 char *buf;
365 size_t pos;
366 size_t size;
367};
368
369
370static size_t
371copyBuffer (void *ptr,
372 size_t size,
373 size_t nmemb,
374 void *ctx)
375{
376 struct CBC *cbc = ctx;
377
378 if (cbc->pos + size * nmemb > cbc->size)
379 mhdErrorExitDesc ("Wrong too large data"); /* overflow */
380 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
381 cbc->pos += size * nmemb;
382 return size * nmemb;
383}
384
385
386static enum MHD_Result
387ahc_echo (void *cls,
388 struct MHD_Connection *connection,
389 const char *url,
390 const char *method,
391 const char *version,
392 const char *upload_data,
393 size_t *upload_data_size,
394 void **req_cls)
395{
396 struct MHD_Response *response;
397 enum MHD_Result res;
398 static int already_called_marker;
399 (void) cls; (void) url; /* Unused. Silent compiler warning. */
400 (void) method; (void) version; (void) upload_data; /* Unused. Silent compiler warning. */
401 (void) upload_data_size; /* Unused. Silent compiler warning. */
402
403 if (&already_called_marker != *req_cls)
404 { /* Called for the first time, request not fully read yet */
405 *req_cls = &already_called_marker;
406 /* Wait for complete request */
407 return MHD_YES;
408 }
409
410 if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
411 mhdErrorExitDesc ("Unexpected HTTP method");
412
413 response = NULL;
414 if (! test_oldapi)
415 {
416 struct MHD_DigestAuthInfo *dinfo;
417 const enum MHD_DigestAuthAlgo3 algo3 =
418 test_sha256 ? MHD_DIGEST_AUTH_ALGO3_SHA256 : MHD_DIGEST_AUTH_ALGO3_MD5;
419
420 dinfo = MHD_digest_auth_get_request_info3 (connection);
421 if (NULL != dinfo)
422 {
423 /* Got any kind of Digest response. Check it, it must be valid */
424 struct MHD_DigestAuthUsernameInfo *uname;
425 enum MHD_DigestAuthResult check_res;
426
427 if (NULL == dinfo->username)
428 mhdErrorExitDesc ("'username' is NULL");
429 if (curl_uses_usehash)
430 {
431 if (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH != dinfo->uname_type)
432 {
433 fprintf (stderr, "Unexpected 'uname_type'.\n"
434 "Expected: %d\tRecieved: %d. ",
435 (int) MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH,
436 (int) dinfo->uname_type);
437 mhdErrorExitDesc ("Wrong 'uname_type'");
438 }
439 else if (dinfo->username_len != userhash1_hex_len)
440 {
441 fprintf (stderr, "'username_len' does not match.\n"
442 "Expected: %u\tRecieved: %u. ",
443 (unsigned) userhash1_hex_len,
444 (unsigned) dinfo->username_len);
445 mhdErrorExitDesc ("Wrong 'username_len'");
446 }
447 else if (0 != memcmp (dinfo->username, userhash1_hex,
448 dinfo->username_len))
449 {
450 fprintf (stderr, "'username' does not match.\n"
451 "Expected: '%s'\tRecieved: '%.*s'. ",
452 userhash1_hex,
453 (int) dinfo->username_len,
454 dinfo->username);
455 mhdErrorExitDesc ("Wrong 'username'");
456 }
457 else if (NULL == dinfo->userhash_bin)
458 mhdErrorExitDesc ("'userhash_bin' is NULL");
459 else if (0 != memcmp (dinfo->userhash_bin, userhash1_bin,
460 dinfo->username_len / 2))
461 mhdErrorExitDesc ("Wrong 'userhash_bin'");
462 }
463 else
464 {
465 if (MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD != dinfo->uname_type)
466 {
467 fprintf (stderr, "Unexpected 'uname_type'.\n"
468 "Expected: %d\tRecieved: %d. ",
469 (int) MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD,
470 (int) dinfo->uname_type);
471 mhdErrorExitDesc ("Wrong 'uname_type'");
472 }
473 else if (dinfo->username_len != strlen (username_ptr))
474 {
475 fprintf (stderr, "'username_len' does not match.\n"
476 "Expected: %u\tRecieved: %u. ",
477 (unsigned) strlen (username_ptr),
478 (unsigned) dinfo->username_len);
479 mhdErrorExitDesc ("Wrong 'username_len'");
480 }
481 else if (0 != memcmp (dinfo->username, username_ptr,
482 dinfo->username_len))
483 {
484 fprintf (stderr, "'username' does not match.\n"
485 "Expected: '%s'\tRecieved: '%.*s'. ",
486 username_ptr,
487 (int) dinfo->username_len,
488 dinfo->username);
489 mhdErrorExitDesc ("Wrong 'username'");
490 }
491 else if (NULL != dinfo->userhash_bin)
492 mhdErrorExitDesc ("'userhash_bin' is NOT NULL");
493 }
494 if (algo3 != dinfo->algo)
495 {
496 fprintf (stderr, "Unexpected 'algo'.\n"
497 "Expected: %d\tRecieved: %d. ",
498 (int) algo3,
499 (int) dinfo->algo);
500 mhdErrorExitDesc ("Wrong 'algo'");
501 }
502 else if (10 >= dinfo->cnonce_len)
503 {
504 fprintf (stderr, "Unexpected small 'cnonce_len': %ld. ",
505 (long) dinfo->cnonce_len);
506 mhdErrorExitDesc ("Wrong 'cnonce_len'");
507 }
508 else if (NULL == dinfo->opaque)
509 mhdErrorExitDesc ("'opaque' is NULL");
510 else if (dinfo->opaque_len != MHD_STATICSTR_LEN_ (OPAQUE_VALUE))
511 {
512 fprintf (stderr, "'opaque_len' does not match.\n"
513 "Expected: %u\tRecieved: %u. ",
514 (unsigned) MHD_STATICSTR_LEN_ (OPAQUE_VALUE),
515 (unsigned) dinfo->opaque_len);
516 mhdErrorExitDesc ("Wrong 'opaque_len'");
517 }
518 else if (0 != memcmp (dinfo->opaque, OPAQUE_VALUE, dinfo->opaque_len))
519 {
520 fprintf (stderr, "'opaque' does not match.\n"
521 "Expected: '%s'\tRecieved: '%.*s'. ",
522 OPAQUE_VALUE,
523 (int) dinfo->opaque_len,
524 dinfo->opaque);
525 mhdErrorExitDesc ("Wrong 'opaque'");
526 }
527 else if (MHD_DIGEST_AUTH_QOP_AUTH != dinfo->qop)
528 {
529 fprintf (stderr, "Unexpected 'qop'.\n"
530 "Expected: %d\tRecieved: %d. ",
531 (int) MHD_DIGEST_AUTH_QOP_AUTH,
532 (int) dinfo->qop);
533 mhdErrorExitDesc ("Wrong 'qop'");
534 }
535 else if (NULL == dinfo->realm)
536 mhdErrorExitDesc ("'realm' is NULL");
537 else if (dinfo->realm_len != MHD_STATICSTR_LEN_ (REALM))
538 {
539 fprintf (stderr, "'realm_len' does not match.\n"
540 "Expected: %u\tRecieved: %u. ",
541 (unsigned) MHD_STATICSTR_LEN_ (REALM),
542 (unsigned) dinfo->realm_len);
543 mhdErrorExitDesc ("Wrong 'realm_len'");
544 }
545 else if (0 != memcmp (dinfo->realm, REALM, dinfo->realm_len))
546 {
547 fprintf (stderr, "'realm' does not match.\n"
548 "Expected: '%s'\tRecieved: '%.*s'. ",
549 OPAQUE_VALUE,
550 (int) dinfo->realm_len,
551 dinfo->realm);
552 mhdErrorExitDesc ("Wrong 'realm'");
553 }
554 MHD_free (dinfo);
555
556 uname = MHD_digest_auth_get_username3 (connection);
557 if (NULL == uname)
558 mhdErrorExitDesc ("MHD_digest_auth_get_username3() returned NULL");
559 else if (NULL == uname->username)
560 mhdErrorExitDesc ("'username' is NULL");
561 if (curl_uses_usehash)
562 {
563 if (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH != uname->uname_type)
564 {
565 fprintf (stderr, "Unexpected 'uname_type'.\n"
566 "Expected: %d\tRecieved: %d. ",
567 (int) MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH,
568 (int) uname->uname_type);
569 mhdErrorExitDesc ("Wrong 'uname_type'");
570 }
571 else if (uname->username_len != userhash1_hex_len)
572 {
573 fprintf (stderr, "'username_len' does not match.\n"
574 "Expected: %u\tRecieved: %u. ",
575 (unsigned) userhash1_hex_len,
576 (unsigned) uname->username_len);
577 mhdErrorExitDesc ("Wrong 'username_len'");
578 }
579 else if (0 != memcmp (uname->username, userhash1_hex,
580 uname->username_len))
581 {
582 fprintf (stderr, "'username' does not match.\n"
583 "Expected: '%s'\tRecieved: '%.*s'. ",
584 userhash1_hex,
585 (int) uname->username_len,
586 uname->username);
587 mhdErrorExitDesc ("Wrong 'username'");
588 }
589 else if (NULL == uname->userhash_bin)
590 mhdErrorExitDesc ("'userhash_bin' is NULL");
591 else if (0 != memcmp (uname->userhash_bin, userhash1_bin,
592 uname->username_len / 2))
593 mhdErrorExitDesc ("Wrong 'userhash_bin'");
594 }
595 else
596 {
597 if (MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD != uname->uname_type)
598 {
599 fprintf (stderr, "Unexpected 'uname_type'.\n"
600 "Expected: %d\tRecieved: %d. ",
601 (int) MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD,
602 (int) uname->uname_type);
603 mhdErrorExitDesc ("Wrong 'uname_type'");
604 }
605 else if (uname->username_len != strlen (username_ptr))
606 {
607 fprintf (stderr, "'username_len' does not match.\n"
608 "Expected: %u\tRecieved: %u. ",
609 (unsigned) strlen (username_ptr),
610 (unsigned) uname->username_len);
611 mhdErrorExitDesc ("Wrong 'username_len'");
612 }
613 else if (0 != memcmp (uname->username, username_ptr,
614 uname->username_len))
615 {
616 fprintf (stderr, "'username' does not match.\n"
617 "Expected: '%s'\tRecieved: '%.*s'. ",
618 username_ptr,
619 (int) uname->username_len,
620 uname->username);
621 mhdErrorExitDesc ("Wrong 'username'");
622 }
623 else if (NULL != uname->userhash_bin)
624 mhdErrorExitDesc ("'userhash_bin' is NOT NULL");
625 }
626 MHD_free (uname);
627
628 check_res =
629 MHD_digest_auth_check3 (connection, REALM, username_ptr,
630 PASSWORD_VALUE, 50 * TIMEOUTS_VAL,
631 0, MHD_DIGEST_AUTH_MULT_QOP_AUTH,
632 (enum MHD_DigestAuthMultiAlgo3) algo3);
633
634 switch (check_res)
635 {
636 /* Valid result */
637 case MHD_DAUTH_OK:
638 if (verbose)
639 printf ("Got valid auth check result: MHD_DAUTH_OK.\n");
640 break;
641 /* Invalid results */
642 case MHD_DAUTH_NONCE_STALE:
643 mhdErrorExitDesc ("MHD_digest_auth_check3()' returned " \
644 "MHD_DAUTH_NONCE_STALE");
645 break;
646 case MHD_DAUTH_NONCE_WRONG:
647 mhdErrorExitDesc ("MHD_digest_auth_check3()' returned " \
648 "MHD_DAUTH_NONCE_WRONG");
649 break;
650 case MHD_DAUTH_ERROR:
651 externalErrorExitDesc ("General error returned " \
652 "by 'MHD_digest_auth_check3()'");
653 break;
654 case MHD_DAUTH_WRONG_USERNAME:
655 mhdErrorExitDesc ("MHD_digest_auth_check3()' returned " \
656 "MHD_DAUTH_WRONG_USERNAME");
657 break;
658 case MHD_DAUTH_RESPONSE_WRONG:
659 mhdErrorExitDesc ("MHD_digest_auth_check3()' returned " \
660 "MHD_DAUTH_RESPONSE_WRONG");
661 break;
662 case MHD_DAUTH_WRONG_HEADER:
663 case MHD_DAUTH_WRONG_REALM:
664 case MHD_DAUTH_WRONG_URI:
665 case MHD_DAUTH_WRONG_QOP:
666 case MHD_DAUTH_WRONG_ALGO:
667 case MHD_DAUTH_TOO_LARGE:
668 fprintf (stderr, "'MHD_digest_auth_check3()' returned "
669 "unexpected result: %d. ",
670 check_res);
671 mhdErrorExitDesc ("Wrong returned code");
672 break;
673 default:
674 fprintf (stderr, "'MHD_digest_auth_check3()' returned "
675 "impossible result code: %d. ",
676 check_res);
677 mhdErrorExitDesc ("Impossible returned code");
678 }
679
680 response =
681 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE),
682 (const void *) PAGE);
683 if (NULL == response)
684 mhdErrorExitDesc ("Response creation failed");
685
686 if (MHD_YES !=
687 MHD_queue_response (connection, MHD_HTTP_OK, response))
688 mhdErrorExitDesc ("'MHD_queue_response()' failed");
689 }
690 else
691 {
692 /* No Digest auth header */
693 response =
694 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (DENIED),
695 (const void *) DENIED);
696 if (NULL == response)
697 mhdErrorExitDesc ("Response creation failed");
698 res =
699 MHD_queue_auth_required_response3 (connection, REALM, OPAQUE_VALUE,
700 "/", response, 0,
701 MHD_DIGEST_AUTH_MULT_QOP_AUTH,
702 (enum MHD_DigestAuthMultiAlgo3) algo3,
703 test_userhash, 0);
704 if (MHD_YES != res)
705 mhdErrorExitDesc ("'MHD_queue_auth_required_response3()' failed");
706 }
707 }
708 else
709 {
710 /* Use old API */
711 char *username;
712 int check_res;
713
714 username = MHD_digest_auth_get_username (connection);
715 if (NULL != username)
716 { /* Has a valid username in header */
717 if (0 != strcmp (username, username_ptr))
718 {
719 fprintf (stderr, "'username' does not match.\n"
720 "Expected: '%s'\tRecieved: '%s'. ",
721 username_ptr,
722 username);
723 mhdErrorExitDesc ("Wrong 'username'");
724 }
725 MHD_free (username);
726
727 check_res = MHD_digest_auth_check (connection, REALM, username_ptr,
728 PASSWORD_VALUE, 50 * TIMEOUTS_VAL);
729
730 if (MHD_YES != check_res)
731 {
732 fprintf (stderr, "'MHD_digest_auth_check()' returned unexpected"
733 " result: %d. ", check_res);
734 mhdErrorExitDesc ("Wrong 'MHD_digest_auth_check()' result");
735 }
736 response =
737 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE),
738 (const void *) PAGE);
739 if (NULL == response)
740 mhdErrorExitDesc ("Response creation failed");
741
742 if (MHD_YES !=
743 MHD_queue_response (connection, MHD_HTTP_OK, response))
744 mhdErrorExitDesc ("'MHD_queue_response()' failed");
745 }
746 else
747 {
748 /* Has no valid username in header */
749 response =
750 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (DENIED),
751 (const void *) DENIED);
752 if (NULL == response)
753 mhdErrorExitDesc ("Response creation failed");
754
755 res = MHD_queue_auth_fail_response (connection, REALM, OPAQUE_VALUE,
756 response, 0);
757 if (MHD_YES != res)
758 mhdErrorExitDesc ("'MHD_queue_auth_fail_response()' failed");
759 }
760 }
761 MHD_destroy_response (response);
762 return MHD_YES;
763}
764
765
766static CURL *
767setupCURL (void *cbc, int port)
768{
769 CURL *c;
770 char url[512];
771
772 if (1)
773 {
774 int res;
775 /* A workaround for some old libcurl versions, which ignore the specified
776 * port by CURLOPT_PORT when authorisation is used. */
777 res = snprintf (url, (sizeof(url) / sizeof(url[0])),
778 "http://127.0.0.1:%d%s", port, MHD_URI_BASE_PATH);
779 if ((0 >= res) || ((sizeof(url) / sizeof(url[0])) <= (size_t) res))
780 externalErrorExitDesc ("Cannot form request URL");
781 }
782
783 c = curl_easy_init ();
784 if (NULL == c)
785 libcurlErrorExitDesc ("curl_easy_init() failed");
786
787 if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) ||
788 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION,
789 &copyBuffer)) ||
790 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc)) ||
791 (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT,
792 ((long) TIMEOUTS_VAL))) ||
793 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION,
794 CURL_HTTP_VERSION_1_1)) ||
795 (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT,
796 ((long) TIMEOUTS_VAL))) ||
797 (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER,
798 libcurl_errbuf)) ||
799 (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 0L)) ||
800 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTPAUTH,
801 (long) CURLAUTH_DIGEST)) ||
802#if CURL_AT_LEAST_VERSION (7,19,1)
803 /* Need version 7.19.1 for separate username and password */
804 (CURLE_OK != curl_easy_setopt (c, CURLOPT_USERNAME, username_ptr)) ||
805 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PASSWORD, PASSWORD_VALUE)) ||
806#endif /* CURL_AT_LEAST_VERSION(7,19,1) */
807#ifdef _DEBUG
808 (CURLE_OK != curl_easy_setopt (c, CURLOPT_VERBOSE, 1L)) ||
809#endif /* _DEBUG */
810#if CURL_AT_LEAST_VERSION (7, 19, 4)
811 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PROTOCOLS, CURLPROTO_HTTP)) ||
812#endif /* CURL_AT_LEAST_VERSION (7, 19, 4) */
813#if CURL_AT_LEAST_VERSION (7, 45, 0)
814 (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEFAULT_PROTOCOL, "http")) ||
815#endif /* CURL_AT_LEAST_VERSION (7, 45, 0) */
816 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, ((long) port))) ||
817 (CURLE_OK != curl_easy_setopt (c, CURLOPT_URL, url)))
818 libcurlErrorExitDesc ("curl_easy_setopt() failed");
819 return c;
820}
821
822
823static CURLcode
824performQueryExternal (struct MHD_Daemon *d, CURL *c)
825{
826 CURLM *multi;
827 time_t start;
828 struct timeval tv;
829 CURLcode ret;
830
831 ret = CURLE_FAILED_INIT; /* will be replaced with real result */
832 multi = NULL;
833 multi = curl_multi_init ();
834 if (multi == NULL)
835 libcurlErrorExitDesc ("curl_multi_init() failed");
836 if (CURLM_OK != curl_multi_add_handle (multi, c))
837 libcurlErrorExitDesc ("curl_multi_add_handle() failed");
838
839 start = time (NULL);
840 while (time (NULL) - start <= TIMEOUTS_VAL)
841 {
842 fd_set rs;
843 fd_set ws;
844 fd_set es;
845 MHD_socket maxMhdSk;
846 int maxCurlSk;
847 int running;
848
849 maxMhdSk = MHD_INVALID_SOCKET;
850 maxCurlSk = -1;
851 FD_ZERO (&rs);
852 FD_ZERO (&ws);
853 FD_ZERO (&es);
854 if (NULL != multi)
855 {
856 curl_multi_perform (multi, &running);
857 if (0 == running)
858 {
859 struct CURLMsg *msg;
860 int msgLeft;
861 int totalMsgs = 0;
862 do
863 {
864 msg = curl_multi_info_read (multi, &msgLeft);
865 if (NULL == msg)
866 libcurlErrorExitDesc ("curl_multi_info_read() failed");
867 totalMsgs++;
868 if (CURLMSG_DONE == msg->msg)
869 ret = msg->data.result;
870 } while (msgLeft > 0);
871 if (1 != totalMsgs)
872 {
873 fprintf (stderr,
874 "curl_multi_info_read returned wrong "
875 "number of results (%d).\n",
876 totalMsgs);
877 externalErrorExit ();
878 }
879 curl_multi_remove_handle (multi, c);
880 curl_multi_cleanup (multi);
881 multi = NULL;
882 }
883 else
884 {
885 if (CURLM_OK != curl_multi_fdset (multi, &rs, &ws, &es, &maxCurlSk))
886 libcurlErrorExitDesc ("curl_multi_fdset() failed");
887 }
888 }
889 if (NULL == multi)
890 { /* libcurl has finished, check whether MHD still needs to perform cleanup */
891 if (0 != MHD_get_timeout64s (d))
892 break; /* MHD finished as well */
893 }
894 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxMhdSk))
895 mhdErrorExitDesc ("MHD_get_fdset() failed");
896 tv.tv_sec = 0;
897 tv.tv_usec = 200000;
898#ifdef MHD_POSIX_SOCKETS
899 if (maxMhdSk > maxCurlSk)
900 maxCurlSk = maxMhdSk;
901#endif /* MHD_POSIX_SOCKETS */
902 if (-1 == select (maxCurlSk + 1, &rs, &ws, &es, &tv))
903 {
904#ifdef MHD_POSIX_SOCKETS
905 if (EINTR != errno)
906 externalErrorExitDesc ("Unexpected select() error");
907#else
908 if ((WSAEINVAL != WSAGetLastError ()) ||
909 (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) )
910 externalErrorExitDesc ("Unexpected select() error");
911 Sleep (200);
912#endif
913 }
914 if (MHD_YES != MHD_run_from_select (d, &rs, &ws, &es))
915 mhdErrorExitDesc ("MHD_run_from_select() failed");
916 }
917
918 return ret;
919}
920
921
922/**
923 * Check request result
924 * @param curl_code the CURL easy return code
925 * @param pcbc the pointer struct CBC
926 * @return non-zero if success, zero if failed
927 */
928static unsigned int
929check_result (CURLcode curl_code, CURL *c, struct CBC *pcbc)
930{
931 long code;
932 if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code))
933 libcurlErrorExit ();
934
935 if (MHD_HTTP_OK != code)
936 {
937 fprintf (stderr, "Request returned wrong code: %ld.\n",
938 code);
939 return 0;
940 }
941
942 if (CURLE_OK != curl_code)
943 {
944 fflush (stdout);
945 if (0 != libcurl_errbuf[0])
946 fprintf (stderr, "Request failed. "
947 "libcurl error: '%s'.\n"
948 "libcurl error description: '%s'.\n",
949 curl_easy_strerror (curl_code),
950 libcurl_errbuf);
951 else
952 fprintf (stderr, "Request failed. "
953 "libcurl error: '%s'.\n",
954 curl_easy_strerror (curl_code));
955 fflush (stderr);
956 return 0;
957 }
958
959 if (pcbc->pos != MHD_STATICSTR_LEN_ (PAGE))
960 {
961 fprintf (stderr, "Got %u bytes ('%.*s'), expected %u bytes. ",
962 (unsigned) pcbc->pos, (int) pcbc->pos, pcbc->buf,
963 (unsigned) MHD_STATICSTR_LEN_ (PAGE));
964 mhdErrorExitDesc ("Wrong returned data length");
965 }
966 if (0 != memcmp (PAGE, pcbc->buf, pcbc->pos))
967 {
968 fprintf (stderr, "Got invalid response '%.*s'. ",
969 (int) pcbc->pos, pcbc->buf);
970 mhdErrorExitDesc ("Wrong returned data");
971 }
972 return 1;
973}
974
975
976static unsigned int
977testDigestAuth (void)
978{
979 struct MHD_Daemon *d;
980 uint16_t port;
981 uint8_t salt[8];
982 struct CBC cbc;
983 char buf[2048];
984 CURL *c;
985 int failed = 0;
986
987 if (! gen_good_rnd (salt, sizeof(salt)))
988 {
989 fprintf (stderr, "WARNING: the random buffer (used as salt value) is not "
990 "initialised completely, nonce generation may be "
991 "predictable in this test.\n");
992 fflush (stderr);
993 }
994
995 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
996 port = 0;
997 else
998 port = 4210;
999
1000 d = MHD_start_daemon (MHD_USE_ERROR_LOG,
1001 port, NULL, NULL,
1002 &ahc_echo, NULL,
1003 MHD_OPTION_DIGEST_AUTH_RANDOM, sizeof (salt), salt,
1004 MHD_OPTION_NONCE_NC_SIZE, 300,
1005 MHD_OPTION_END);
1006 if (d == NULL)
1007 return 1;
1008 if (0 == port)
1009 {
1010 const union MHD_DaemonInfo *dinfo;
1011
1012 dinfo = MHD_get_daemon_info (d,
1013 MHD_DAEMON_INFO_BIND_PORT);
1014 if ( (NULL == dinfo) ||
1015 (0 == dinfo->port) )
1016 mhdErrorExitDesc ("MHD_get_daemon_info() failed");
1017 port = dinfo->port;
1018 }
1019
1020 /* First request */
1021 cbc.buf = buf;
1022 cbc.size = sizeof (buf);
1023 cbc.pos = 0;
1024 memset (cbc.buf, 0, cbc.size);
1025 c = setupCURL (&cbc, port);
1026 if (check_result (performQueryExternal (d, c), c, &cbc))
1027 {
1028 if (verbose)
1029 printf ("Got expected response.\n");
1030 }
1031 else
1032 {
1033 fprintf (stderr, "Request FAILED.\n");
1034 failed = 1;
1035 }
1036 curl_easy_cleanup (c);
1037
1038 MHD_stop_daemon (d);
1039 return failed ? 1 : 0;
1040}
1041
1042
1043int
1044main (int argc, char *const *argv)
1045{
1046#if ! CURL_AT_LEAST_VERSION (7,19,1)
1047 (void) argc; (void) argv; /* Unused. Silent compiler warning. */
1048 /* Need version 7.19.1 for separate username and password */
1049 fprintf (stderr, "Required libcurl version 7.19.1 at least"
1050 " to run this test.\n");
1051 return 77;
1052#else /* CURL_AT_LEAST_VERSION(7,19,1) */
1053 unsigned int errorCount = 0;
1054 const curl_version_info_data *const curl_info =
1055 curl_version_info (CURLVERSION_NOW);
1056 int curl_sspi;
1057 (void) argc; (void) argv; /* Unused. Silent compiler warning. */
1058
1059 /* Test type and test parameters */
1060 verbose = ! (has_param (argc, argv, "-q") ||
1061 has_param (argc, argv, "--quiet") ||
1062 has_param (argc, argv, "-s") ||
1063 has_param (argc, argv, "--silent"));
1064 test_oldapi = has_in_name (argv[0], "_oldapi");
1065 test_userhash = has_in_name (argv[0], "_userhash");
1066 test_sha256 = has_in_name (argv[0], "_sha256");
1067
1068 if (test_oldapi)
1069 { /* Wrong test types combination */
1070 if (test_userhash || test_sha256)
1071 return 99;
1072 }
1073
1074 /* Curl version and known bugs checks */
1075 curl_sspi = 0;
1076#ifdef CURL_VERSION_SSPI
1077 if (0 != (curl_info->features & CURL_VERSION_SSPI))
1078 curl_sspi = 1;
1079#endif /* CURL_VERSION_SSPI */
1080
1081 if ((CURL_VERSION_BITS (7,63,0) > curl_info->version_num) &&
1082 (CURL_VERSION_BITS (7,62,0) <= curl_info->version_num) )
1083 {
1084 fprintf (stderr, "libcurl version 7.62.x has bug in processing"
1085 "URI with GET argements for Digest Auth.\n");
1086 fprintf (stderr, "This test with libcurl %u.%u.%u cannot be performed.\n",
1087 0xFF & (curl_info->version_num >> 16),
1088 0xFF & (curl_info->version_num >> 8),
1089 0xFF & (curl_info->version_num >> 0));
1090 return 77;
1091 }
1092 if (test_userhash)
1093 {
1094 if (curl_sspi)
1095 {
1096 printf ("WARNING: Windows SSPI API does not support 'userhash'.\n");
1097 printf ("This test just checks Digest Auth compatibility with "
1098 "the clients without 'userhash' support "
1099 "when 'userhash=true' is specified by MHD.\n");
1100 curl_uses_usehash = 0;
1101 }
1102 else if (CURL_VERSION_BITS (7,57,0) > curl_info->version_num)
1103 {
1104 printf ("WARNING: libcurl before version 7.57.0 does not "
1105 "support 'userhash'.\n");
1106 printf ("This test just checks Digest Auth compatibility with "
1107 "libcurl version %u.%u.%u without 'userhash' support "
1108 "when 'userhash=true' is specified by MHD.\n",
1109 0xFF & (curl_info->version_num >> 16),
1110 0xFF & (curl_info->version_num >> 8),
1111 0xFF & (curl_info->version_num >> 0));
1112 curl_uses_usehash = 0;
1113 }
1114 else if (CURL_VERSION_BITS (7,81,0) > curl_info->version_num)
1115 {
1116 fprintf (stderr, "Required libcurl version 7.81.0 at least"
1117 " to run this test with userhash.\n");
1118 fprintf (stderr, "This libcurl version %u.%u.%u has broken digest"
1119 "calculation when userhash is used.\n",
1120 0xFF & (curl_info->version_num >> 16),
1121 0xFF & (curl_info->version_num >> 8),
1122 0xFF & (curl_info->version_num >> 0));
1123 return 77;
1124 }
1125 else
1126 curl_uses_usehash = ! 0;
1127 }
1128 else
1129 curl_uses_usehash = 0;
1130
1131 if (test_sha256)
1132 {
1133 if (curl_sspi)
1134 {
1135 fprintf (stderr, "Windows SSPI API does not support SHA-256 digests.\n");
1136 return 77;
1137 }
1138 else if (CURL_VERSION_BITS (7,57,0) > curl_info->version_num)
1139 {
1140 fprintf (stderr, "Required libcurl version 7.57.0 at least"
1141 " to run this test with SHA-256.\n");
1142 fprintf (stderr, "This libcurl version %u.%u.%u "
1143 "does not support SHA-256.\n",
1144 0xFF & (curl_info->version_num >> 16),
1145 0xFF & (curl_info->version_num >> 8),
1146 0xFF & (curl_info->version_num >> 0));
1147 return 77;
1148 }
1149 }
1150
1151 test_global_init ();
1152
1153 errorCount += testDigestAuth ();
1154 if (errorCount != 0)
1155 fprintf (stderr, "Error (code: %u)\n", errorCount);
1156 test_global_cleanup ();
1157 return (0 == errorCount) ? 0 : 1; /* 0 == pass */
1158#endif /* CURL_AT_LEAST_VERSION(7,19,1) */
1159}