diff options
Diffstat (limited to 'src/microhttpd/test_dauth_userdigest.c')
-rw-r--r-- | src/microhttpd/test_dauth_userdigest.c | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/src/microhttpd/test_dauth_userdigest.c b/src/microhttpd/test_dauth_userdigest.c new file mode 100644 index 00000000..3af45156 --- /dev/null +++ b/src/microhttpd/test_dauth_userdigest.c | |||
@@ -0,0 +1,432 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | Copyright (C) 2022 Evgeny Grin (Karlson2) | ||
4 | |||
5 | This test tool is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU General Public License as | ||
7 | published by the Free Software Foundation; either version 2, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This test tool is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | */ | ||
19 | |||
20 | /** | ||
21 | * @file microhttpd/test_dauth_userdigest.c | ||
22 | * @brief Tests for Digest Auth calculations of userdigest | ||
23 | * @author Karlson2k (Evgeny Grin) | ||
24 | */ | ||
25 | |||
26 | #include <stdio.h> | ||
27 | #include <stdlib.h> | ||
28 | #include <string.h> | ||
29 | #include "microhttpd.h" | ||
30 | #include "test_helpers.h" | ||
31 | |||
32 | static int verbose = 1; /* verbose level (0-1)*/ | ||
33 | |||
34 | /* Declarations and data */ | ||
35 | |||
36 | struct data_md5 | ||
37 | { | ||
38 | unsigned int line_num; | ||
39 | const char *const username; | ||
40 | const char *const realm; | ||
41 | const char *const password; | ||
42 | const uint8_t hash[MHD_MD5_DIGEST_SIZE]; | ||
43 | }; | ||
44 | |||
45 | |||
46 | static const struct data_md5 md5_tests[] = { | ||
47 | {__LINE__, | ||
48 | "u", "r", "p", | ||
49 | {0x44, 0xad, 0xd2, 0x2b, 0x6f, 0x31, 0x79, 0xb7, 0x51, 0xea, 0xfd, 0x68, | ||
50 | 0xee, 0x37, 0x0f, 0x7d}}, | ||
51 | {__LINE__, | ||
52 | "testuser", "testrealm", "testpass", | ||
53 | {0xeb, 0xff, 0x22, 0x5e, 0x1c, 0xeb, 0x73, 0xe0, 0x26, 0xfc, 0xc6, 0x45, | ||
54 | 0xaf, 0x3e, 0x84, 0xf6}}, | ||
55 | {__LINE__, /* Values from testcurl/test_digestauth2.c */ | ||
56 | "test_user", "TestRealm", "test pass", | ||
57 | {0xd8, 0xb4, 0xa6, 0xd0, 0x01, 0x13, 0x07, 0xb7, 0x67, 0x94, 0xea, 0x66, | ||
58 | 0x86, 0x03, 0x6b, 0x43}}, | ||
59 | {__LINE__, | ||
60 | "Mufasa", "myhost@testrealm.com", "CircleOfLife", | ||
61 | {0x7e, 0xbe, 0xcc, 0x07, 0x18, 0xa5, 0x4a, 0xb4, 0x7e, 0x21, 0x65, 0x69, | ||
62 | 0x07, 0x66, 0x41, 0x6a}}, | ||
63 | {__LINE__, | ||
64 | "Mufasa", "myhost@example.com", "Circle Of Life", | ||
65 | {0x6a, 0x6d, 0x4e, 0x7c, 0xd7, 0x15, 0x18, 0x68, 0xf9, 0xb8, 0xc7, 0xc8, | ||
66 | 0xd1, 0xcd, 0xd4, 0xe0}}, | ||
67 | {__LINE__, | ||
68 | "Mufasa", "http-auth@example.org", "Circle of Life", | ||
69 | {0x3d, 0x78, 0x80, 0x7d, 0xef, 0xe7, 0xde, 0x21, 0x57, 0xe2, 0xb0, 0xb6, | ||
70 | 0x57, 0x3a, 0x85, 0x5f}}, | ||
71 | {__LINE__, | ||
72 | "J" "\xC3\xA4" "s" "\xC3\xB8" "n Doe" /* "Jäsøn Doe" */, | ||
73 | "api@example.org", "Secret, or not?", | ||
74 | {0x83, 0xa3, 0xf7, 0xf6, 0xb8, 0x3f, 0x71, 0xc5, 0xc2, 0xeb, 0x7c, 0x6d, | ||
75 | 0xd2, 0xdd, 0x4c, 0x4b}} | ||
76 | }; | ||
77 | |||
78 | struct data_sha256 | ||
79 | { | ||
80 | unsigned int line_num; | ||
81 | const char *const username; | ||
82 | const char *const realm; | ||
83 | const char *const password; | ||
84 | const uint8_t hash[MHD_SHA256_DIGEST_SIZE]; | ||
85 | }; | ||
86 | |||
87 | static const struct data_sha256 sha256_tests[] = { | ||
88 | {__LINE__, | ||
89 | "u", "r", "p", | ||
90 | {0xdc, 0xb0, 0x21, 0x10, 0x2e, 0x49, 0x1e, 0x70, 0x1a, 0x4a, 0x23, 0x6d, | ||
91 | 0xaa, 0x89, 0x23, 0xaf, 0x21, 0x61, 0x44, 0x7b, 0xce, 0x7b, 0xb7, 0x26, | ||
92 | 0x0a, 0x35, 0x1e, 0xe8, 0x3e, 0x9f, 0x81, 0x54}}, | ||
93 | {__LINE__, | ||
94 | "testuser", "testrealm", "testpass", | ||
95 | {0xa9, 0x2e, 0xf6, 0x3b, 0x3d, 0xec, 0x38, 0x95, 0xb0, 0x8f, 0x3d, 0x4d, | ||
96 | 0x67, 0x33, 0xf0, 0x70, 0x74, 0xcb, 0xe6, 0xd4, 0xa0, 0x01, 0x27, 0xf5, | ||
97 | 0x74, 0x1a, 0x77, 0x4f, 0x05, 0xf9, 0xd4, 0x99}}, | ||
98 | {__LINE__, /* Values from testcurl/test_digestauth2.c */ | ||
99 | "test_user", "TestRealm", "test pass", | ||
100 | {0xc3, 0x4e, 0x16, 0x5a, 0x17, 0x0f, 0xe5, 0xac, 0x04, 0xf1, 0x6e, 0x46, | ||
101 | 0x48, 0x2b, 0xa0, 0xc6, 0x56, 0xc1, 0xfb, 0x8f, 0x66, 0xa6, 0xd6, 0x3f, | ||
102 | 0x91, 0x12, 0xf8, 0x56, 0xa5, 0xec, 0x6d, 0x6d}}, | ||
103 | {__LINE__, | ||
104 | "Mufasa", "myhost@testrealm.com", "CircleOfLife", | ||
105 | {0x8e, 0x64, 0x1f, 0xaa, 0x71, 0x7d, 0x20, 0x70, 0x5a, 0xd7, 0x3c, 0x54, | ||
106 | 0xfb, 0x04, 0x9e, 0x32, 0x6a, 0xe1, 0x1c, 0x80, 0xd6, 0x05, 0x9f, 0xc3, | ||
107 | 0x7e, 0xbb, 0x2d, 0x7b, 0x60, 0x6c, 0x11, 0xb9}}, | ||
108 | {__LINE__, | ||
109 | "Mufasa", "myhost@example.com", "Circle Of Life", | ||
110 | {0x8b, 0xc5, 0xa8, 0xed, 0xe3, 0x02, 0x15, 0x6b, 0x9f, 0x51, 0xce, 0x97, | ||
111 | 0x81, 0xb5, 0x26, 0xff, 0x99, 0x29, 0x0b, 0xb2, 0xc3, 0xe4, 0x41, 0x71, | ||
112 | 0x8e, 0xa3, 0xa1, 0x7e, 0x5a, 0xd9, 0xd6, 0x49}}, | ||
113 | {__LINE__, | ||
114 | "Mufasa", "http-auth@example.org", "Circle of Life", | ||
115 | {0x79, 0x87, 0xc6, 0x4c, 0x30, 0xe2, 0x5f, 0x1b, 0x74, 0xbe, 0x53, 0xf9, | ||
116 | 0x66, 0xb4, 0x9b, 0x90, 0xf2, 0x80, 0x8a, 0xa9, 0x2f, 0xaf, 0x9a, 0x00, | ||
117 | 0x26, 0x23, 0x92, 0xd7, 0xb4, 0x79, 0x42, 0x32}}, | ||
118 | {__LINE__, | ||
119 | "J" "\xC3\xA4" "s" "\xC3\xB8" "n Doe" /* "Jäsøn Doe" */, | ||
120 | "api@example.org", "Secret, or not?", | ||
121 | {0xfd, 0x0b, 0xe3, 0x93, 0x9d, 0xca, 0x4b, 0x5c, 0x2d, 0x46, 0xe8, 0xfa, | ||
122 | 0x6a, 0x3d, 0x16, 0xdb, 0xea, 0x82, 0x47, 0x4c, 0xb9, 0xa5, 0x88, 0xd4, | ||
123 | 0xcb, 0x14, 0x9c, 0x54, 0xf3, 0x7c, 0xff, 0x37}} | ||
124 | }; | ||
125 | |||
126 | |||
127 | /* | ||
128 | * Helper functions | ||
129 | */ | ||
130 | |||
131 | /** | ||
132 | * Print bin as lower case hex | ||
133 | * | ||
134 | * @param bin binary data | ||
135 | * @param len number of bytes in bin | ||
136 | * @param hex pointer to len*2+1 bytes buffer | ||
137 | */ | ||
138 | static void | ||
139 | bin2hex (const uint8_t *bin, | ||
140 | size_t len, | ||
141 | char *hex) | ||
142 | { | ||
143 | while (len-- > 0) | ||
144 | { | ||
145 | unsigned int b1, b2; | ||
146 | b1 = (*bin >> 4) & 0xf; | ||
147 | *hex++ = (char) ((b1 > 9) ? (b1 + 'a' - 10) : (b1 + '0')); | ||
148 | b2 = *bin++ & 0xf; | ||
149 | *hex++ = (char) ((b2 > 9) ? (b2 + 'a' - 10) : (b2 + '0')); | ||
150 | } | ||
151 | *hex = 0; | ||
152 | } | ||
153 | |||
154 | |||
155 | /* Tests */ | ||
156 | |||
157 | static unsigned int | ||
158 | check_md5 (const struct data_md5 *const data) | ||
159 | { | ||
160 | static const enum MHD_DigestAuthAlgo3 algo3 = MHD_DIGEST_AUTH_ALGO3_MD5; | ||
161 | uint8_t hash_bin[MHD_MD5_DIGEST_SIZE]; | ||
162 | char hash_hex[MHD_MD5_DIGEST_SIZE * 2 + 1]; | ||
163 | char expected_hex[MHD_MD5_DIGEST_SIZE * 2 + 1]; | ||
164 | const char *func_name; | ||
165 | unsigned int failed = 0; | ||
166 | |||
167 | func_name = "MHD_digest_auth_calc_userdigest"; | ||
168 | if (MHD_YES != MHD_digest_auth_calc_userdigest (algo3, | ||
169 | data->username, | ||
170 | data->realm, | ||
171 | data->password, | ||
172 | hash_bin, sizeof(hash_bin))) | ||
173 | { | ||
174 | failed++; | ||
175 | fprintf (stderr, | ||
176 | "FAILED: %s() has not returned MHD_YES.\n", | ||
177 | func_name); | ||
178 | } | ||
179 | else if (0 != memcmp (hash_bin, data->hash, sizeof(data->hash))) | ||
180 | { | ||
181 | failed++; | ||
182 | bin2hex (hash_bin, sizeof(hash_bin), hash_hex); | ||
183 | bin2hex (data->hash, sizeof(data->hash), expected_hex); | ||
184 | fprintf (stderr, | ||
185 | "FAILED: %s() produced wrong hash. " | ||
186 | "Calculated digest %s, expected digest %s.\n", | ||
187 | func_name, | ||
188 | hash_hex, expected_hex); | ||
189 | } | ||
190 | |||
191 | if (failed) | ||
192 | { | ||
193 | fprintf (stderr, | ||
194 | "The check failed for data located at line: %u.\n", | ||
195 | data->line_num); | ||
196 | fflush (stderr); | ||
197 | } | ||
198 | else if (verbose) | ||
199 | { | ||
200 | printf ("PASSED: check for data at line: %u.\n", | ||
201 | data->line_num); | ||
202 | } | ||
203 | return failed ? 1 : 0; | ||
204 | } | ||
205 | |||
206 | |||
207 | static unsigned int | ||
208 | test_md5 (void) | ||
209 | { | ||
210 | unsigned int num_failed = 0; | ||
211 | size_t i; | ||
212 | |||
213 | for (i = 0; i < sizeof(md5_tests) / sizeof(md5_tests[0]); i++) | ||
214 | num_failed += check_md5 (md5_tests + i); | ||
215 | return num_failed; | ||
216 | } | ||
217 | |||
218 | |||
219 | static unsigned int | ||
220 | test_md5_failure (void) | ||
221 | { | ||
222 | static const enum MHD_DigestAuthAlgo3 algo3 = MHD_DIGEST_AUTH_ALGO3_MD5; | ||
223 | uint8_t hash_bin[MHD_MD5_DIGEST_SIZE]; | ||
224 | const char *func_name; | ||
225 | unsigned int failed = 0; | ||
226 | |||
227 | func_name = "MHD_digest_auth_calc_userdigest"; | ||
228 | if (MHD_NO != MHD_digest_auth_calc_userdigest (algo3, | ||
229 | "u", "r", "p", | ||
230 | hash_bin, sizeof(hash_bin) | ||
231 | - 1)) | ||
232 | { | ||
233 | failed++; | ||
234 | fprintf (stderr, | ||
235 | "FAILED: %s() has not returned MHD_NO at line: %u.\n", | ||
236 | func_name, (unsigned) __LINE__); | ||
237 | } | ||
238 | if (MHD_NO != MHD_digest_auth_calc_userdigest (algo3, | ||
239 | "u", "r", "p", | ||
240 | hash_bin, 0)) | ||
241 | { | ||
242 | failed++; | ||
243 | fprintf (stderr, | ||
244 | "FAILED: %s() has not returned MHD_NO at line: %u.\n", | ||
245 | func_name, (unsigned) __LINE__); | ||
246 | } | ||
247 | if (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_DIGEST_AUTH_MD5)) | ||
248 | { | ||
249 | if (MHD_NO != MHD_digest_auth_calc_userdigest (algo3, | ||
250 | "u", "r", "p", | ||
251 | hash_bin, sizeof(hash_bin))) | ||
252 | { | ||
253 | failed++; | ||
254 | fprintf (stderr, | ||
255 | "FAILED: %s() has not returned MHD_NO at line: %u.\n", | ||
256 | func_name, (unsigned) __LINE__); | ||
257 | } | ||
258 | } | ||
259 | |||
260 | if (! failed && verbose) | ||
261 | { | ||
262 | printf ("PASSED: all checks with expected MHD_NO result near line: %u.\n", | ||
263 | (unsigned) __LINE__); | ||
264 | } | ||
265 | return failed ? 1 : 0; | ||
266 | } | ||
267 | |||
268 | |||
269 | static unsigned int | ||
270 | check_sha256 (const struct data_sha256 *const data) | ||
271 | { | ||
272 | static const enum MHD_DigestAuthAlgo3 algo3 = MHD_DIGEST_AUTH_ALGO3_SHA256; | ||
273 | uint8_t hash_bin[MHD_SHA256_DIGEST_SIZE]; | ||
274 | char hash_hex[MHD_SHA256_DIGEST_SIZE * 2 + 1]; | ||
275 | char expected_hex[MHD_SHA256_DIGEST_SIZE * 2 + 1]; | ||
276 | const char *func_name; | ||
277 | unsigned int failed = 0; | ||
278 | |||
279 | func_name = "MHD_digest_auth_calc_userdigest"; | ||
280 | if (MHD_YES != MHD_digest_auth_calc_userdigest (algo3, | ||
281 | data->username, | ||
282 | data->realm, | ||
283 | data->password, | ||
284 | hash_bin, sizeof(hash_bin))) | ||
285 | { | ||
286 | failed++; | ||
287 | fprintf (stderr, | ||
288 | "FAILED: %s() has not returned MHD_YES.\n", | ||
289 | func_name); | ||
290 | } | ||
291 | else if (0 != memcmp (hash_bin, data->hash, sizeof(data->hash))) | ||
292 | { | ||
293 | failed++; | ||
294 | bin2hex (hash_bin, sizeof(hash_bin), hash_hex); | ||
295 | bin2hex (data->hash, sizeof(data->hash), expected_hex); | ||
296 | fprintf (stderr, | ||
297 | "FAILED: %s() produced wrong hash. " | ||
298 | "Calculated digest %s, expected digest %s.\n", | ||
299 | func_name, | ||
300 | hash_hex, expected_hex); | ||
301 | } | ||
302 | |||
303 | if (failed) | ||
304 | { | ||
305 | fprintf (stderr, | ||
306 | "The check failed for data located at line: %u.\n", | ||
307 | data->line_num); | ||
308 | fflush (stderr); | ||
309 | } | ||
310 | else if (verbose) | ||
311 | { | ||
312 | printf ("PASSED: check for data at line: %u.\n", | ||
313 | data->line_num); | ||
314 | } | ||
315 | return failed ? 1 : 0; | ||
316 | } | ||
317 | |||
318 | |||
319 | static unsigned int | ||
320 | test_sha256 (void) | ||
321 | { | ||
322 | unsigned int num_failed = 0; | ||
323 | size_t i; | ||
324 | |||
325 | for (i = 0; i < sizeof(sha256_tests) / sizeof(sha256_tests[0]); i++) | ||
326 | num_failed += check_sha256 (sha256_tests + i); | ||
327 | return num_failed; | ||
328 | } | ||
329 | |||
330 | |||
331 | static unsigned int | ||
332 | test_sha256_failure (void) | ||
333 | { | ||
334 | static const enum MHD_DigestAuthAlgo3 algo3 = MHD_DIGEST_AUTH_ALGO3_SHA256; | ||
335 | uint8_t hash_bin[MHD_SHA256_DIGEST_SIZE]; | ||
336 | char hash_hex[MHD_SHA256_DIGEST_SIZE * 2 + 1]; | ||
337 | const char *func_name; | ||
338 | unsigned int failed = 0; | ||
339 | |||
340 | func_name = "MHD_digest_auth_calc_userhash"; | ||
341 | if (MHD_NO != MHD_digest_auth_calc_userhash (algo3, | ||
342 | "u", "r", | ||
343 | hash_bin, sizeof(hash_bin) - 1)) | ||
344 | { | ||
345 | failed++; | ||
346 | fprintf (stderr, | ||
347 | "FAILED: %s() has not returned MHD_NO at line: %u.\n", | ||
348 | func_name, (unsigned) __LINE__); | ||
349 | } | ||
350 | if (MHD_NO != MHD_digest_auth_calc_userhash (algo3, | ||
351 | "u", "r", | ||
352 | hash_bin, 0)) | ||
353 | { | ||
354 | failed++; | ||
355 | fprintf (stderr, | ||
356 | "FAILED: %s() has not returned MHD_NO at line: %u.\n", | ||
357 | func_name, (unsigned) __LINE__); | ||
358 | } | ||
359 | if (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_DIGEST_AUTH_MD5)) | ||
360 | { | ||
361 | if (MHD_NO != MHD_digest_auth_calc_userhash (algo3, | ||
362 | "u", "r", | ||
363 | hash_bin, sizeof(hash_bin))) | ||
364 | { | ||
365 | failed++; | ||
366 | fprintf (stderr, | ||
367 | "FAILED: %s() has not returned MHD_NO at line: %u.\n", | ||
368 | func_name, (unsigned) __LINE__); | ||
369 | } | ||
370 | } | ||
371 | |||
372 | func_name = "MHD_digest_auth_calc_userhash_hex"; | ||
373 | if (MHD_NO != | ||
374 | MHD_digest_auth_calc_userhash_hex (algo3, | ||
375 | "u", "r", | ||
376 | hash_hex, sizeof(hash_hex) - 1)) | ||
377 | { | ||
378 | failed++; | ||
379 | fprintf (stderr, | ||
380 | "FAILED: %s() has not returned MHD_NO at line: %u.\n", | ||
381 | func_name, (unsigned) __LINE__); | ||
382 | } | ||
383 | if (MHD_NO != | ||
384 | MHD_digest_auth_calc_userhash_hex (algo3, | ||
385 | "u", "r", | ||
386 | hash_hex, 0)) | ||
387 | { | ||
388 | failed++; | ||
389 | fprintf (stderr, | ||
390 | "FAILED: %s() has not returned MHD_NO at line: %u.\n", | ||
391 | func_name, (unsigned) __LINE__); | ||
392 | } | ||
393 | if (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_DIGEST_AUTH_MD5)) | ||
394 | { | ||
395 | if (MHD_NO != | ||
396 | MHD_digest_auth_calc_userhash_hex (algo3, | ||
397 | "u", "r", | ||
398 | hash_hex, sizeof(hash_hex))) | ||
399 | { | ||
400 | failed++; | ||
401 | fprintf (stderr, | ||
402 | "FAILED: %s() has not returned MHD_NO at line: %u.\n", | ||
403 | func_name, (unsigned) __LINE__); | ||
404 | } | ||
405 | } | ||
406 | |||
407 | if (! failed && verbose) | ||
408 | { | ||
409 | printf ("PASSED: all checks with expected MHD_NO result near line: %u.\n", | ||
410 | (unsigned) __LINE__); | ||
411 | } | ||
412 | return failed ? 1 : 0; | ||
413 | } | ||
414 | |||
415 | |||
416 | int | ||
417 | main (int argc, char *argv[]) | ||
418 | { | ||
419 | unsigned int num_failed = 0; | ||
420 | (void) has_in_name; /* Mute compiler warning. */ | ||
421 | if (has_param (argc, argv, "-s") || has_param (argc, argv, "--silent")) | ||
422 | verbose = 0; | ||
423 | |||
424 | if (MHD_is_feature_supported (MHD_FEATURE_DIGEST_AUTH_MD5)) | ||
425 | num_failed += test_md5 (); | ||
426 | num_failed += test_md5_failure (); | ||
427 | if (MHD_is_feature_supported (MHD_FEATURE_DIGEST_AUTH_SHA256)) | ||
428 | num_failed += test_sha256 (); | ||
429 | num_failed += test_sha256_failure (); | ||
430 | |||
431 | return num_failed ? 1 : 0; | ||
432 | } | ||