aboutsummaryrefslogtreecommitdiff
path: root/src/testcurl/https/test_tls_options.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/testcurl/https/test_tls_options.c')
-rw-r--r--src/testcurl/https/test_tls_options.c493
1 files changed, 390 insertions, 103 deletions
diff --git a/src/testcurl/https/test_tls_options.c b/src/testcurl/https/test_tls_options.c
index f6fa477a..196aebf5 100644
--- a/src/testcurl/https/test_tls_options.c
+++ b/src/testcurl/https/test_tls_options.c
@@ -1,6 +1,7 @@
1/* 1/*
2 This file is part of libmicrohttpd 2 This file is part of libmicrohttpd
3 Copyright (C) 2007, 2010, 2016 Christian Grothoff 3 Copyright (C) 2007, 2016 Christian Grothoff
4 Copyright (C) 2016-2022 Evgeny Grin (Karlson2k)
4 5
5 libmicrohttpd is free software; you can redistribute it and/or modify 6 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 it under the terms of the GNU General Public License as published
@@ -16,87 +17,419 @@
16 along with libmicrohttpd; see the file COPYING. If not, write to the 17 along with libmicrohttpd; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA. 19 Boston, MA 02110-1301, USA.
19*/ 20 */
20 21
21/** 22/**
22 * @file tls_daemon_options_test.c 23 * @file test_tls_options.c
23 * @brief Testcase for libmicrohttpd HTTPS GET operations 24 * @brief Testcase for libmicrohttpd HTTPS TLS version match/mismatch
24 * @author Sagie Amir 25 * @author Sagie Amir
26 * @author Karlson2k (Evgeny Grin)
25 */ 27 */
26 28
27#include "platform.h" 29#include "platform.h"
28#include "microhttpd.h" 30#include "microhttpd.h"
29#include <sys/stat.h> 31#include <curl/curl.h>
30#include <limits.h>
31#ifdef MHD_HTTPS_REQUIRE_GCRYPT 32#ifdef MHD_HTTPS_REQUIRE_GCRYPT
32#include <gcrypt.h> 33#include <gcrypt.h>
33#endif /* MHD_HTTPS_REQUIRE_GCRYPT */ 34#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
34#include "tls_test_common.h" 35#include "tls_test_common.h"
35#include "tls_test_keys.h" 36#include "tls_test_keys.h"
36 37
37/** 38/*
38 * test server refuses to negotiate connections with unsupported protocol versions 39 * HTTP access handler call back
39 * 40 * used to query negotiated security parameters
40 */ 41 */
41static unsigned int 42static enum MHD_Result
42test_unmatching_ssl_version (void *cls, uint16_t port, const char *cipher_suite, 43simple_ahc (void *cls, struct MHD_Connection *connection,
43 int curl_req_ssl_version) 44 const char *url, const char *method,
45 const char *version, const char *upload_data,
46 size_t *upload_data_size, void **req_cls)
44{ 47{
45 struct CBC cbc; 48 struct MHD_Response *response;
46 char url[255]; 49 enum MHD_Result ret;
47 (void) cls; /* Unused. Silent compiler warning. */ 50 (void) cls; (void) url; (void) method; (void) version; /* Unused. Silent compiler warning. */
48 if (NULL == (cbc.buf = malloc (sizeof (char) * 256))) 51 (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */
52
53 if (NULL == *req_cls)
49 { 54 {
50 fprintf (stderr, "Error: failed to allocate: %s\n", 55 *req_cls = (void *) &simple_ahc;
51 strerror (errno)); 56 return MHD_YES;
52 return 1;
53 } 57 }
54 cbc.size = 256;
55 cbc.pos = 0;
56 58
57 if (gen_test_uri (url, 59 response =
58 sizeof (url), 60 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (EMPTY_PAGE),
59 port)) 61 EMPTY_PAGE);
62 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
63 MHD_destroy_response (response);
64 return ret;
65}
66
67
68enum check_result
69{
70 CHECK_RES_OK = 0,
71 CHECK_RES_ERR = 1,
72
73 CHECK_RES_MHD_START_FAILED = 17,
74 CHECK_RES_CURL_TLS_INIT_FAIL = 18,
75 CHECK_RES_CURL_TLS_CONN_FAIL = 19,
76
77 CHECK_RES_HARD_ERROR = 99
78};
79
80static enum check_result
81check_tls_match_inner (enum know_gnutls_tls_id tls_ver_mhd,
82 enum know_gnutls_tls_id tls_ver_libcurl,
83 uint16_t *pport,
84 struct MHD_Daemon **d_ptr,
85 struct CBC *pcbc,
86 CURL **c_ptr)
87{
88 CURLcode errornum;
89 char url[256];
90 int libcurl_tls_set;
91 CURL *c;
92 struct MHD_Daemon *d;
93
94 /* setup test */
95 d =
96 MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
97 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_TLS
98 | MHD_USE_ERROR_LOG, *pport,
99 NULL, NULL,
100 &simple_ahc, NULL,
101 MHD_OPTION_HTTPS_PRIORITIES, priorities_map[tls_ver_mhd],
102 MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem,
103 MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
104 MHD_OPTION_END);
105 fflush (stderr);
106 fflush (stdout);
107 *d_ptr = d;
108
109 if (d == NULL)
110 {
111 fprintf (stderr, "MHD_start_daemon() with %s failed.\n",
112 tls_names[tls_ver_mhd]);
113 return CHECK_RES_MHD_START_FAILED;
114 }
115 if (0 == *pport)
60 { 116 {
61 free (cbc.buf); 117 const union MHD_DaemonInfo *dinfo;
62 fprintf (stderr, 118 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
63 "Internal error in gen_test_file_url\n"); 119 if ((NULL == dinfo) || (0 == dinfo->port) )
64 return 1; 120 {
121 fprintf (stderr, "MHD_get_daemon_info() failed.\n");
122 return CHECK_RES_ERR;
123 }
124 *pport = dinfo->port; /* Use the same port for rest of the checks */
65 } 125 }
66 126
67 /* assert daemon *rejected* request */ 127 if (0 != gen_test_uri (url,
68 if (CURLE_OK == 128 sizeof (url),
69 send_curl_req (url, &cbc, cipher_suite, curl_req_ssl_version)) 129 *pport))
130 {
131 fprintf (stderr, "failed to generate URI.\n");
132 return CHECK_RES_CURL_TLS_INIT_FAIL;
133 }
134 c = curl_easy_init ();
135 fflush (stderr);
136 fflush (stdout);
137 *c_ptr = c;
138 if (NULL == c)
70 { 139 {
71 free (cbc.buf); 140 fprintf (stderr, "curl_easy_init() failed.\n");
72 fprintf (stderr, 141 return CHECK_RES_HARD_ERROR;
73 "cURL failed to reject request despite SSL version mismatch!\n");
74 return 1;
75 } 142 }
143#ifdef _DEBUG
144 curl_easy_setopt (c, CURLOPT_VERBOSE, 1L);
145#endif
76 146
147 if ((CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_URL, url))) ||
148 (CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_HTTP_VERSION,
149 CURL_HTTP_VERSION_1_1))) ||
150 (CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_TIMEOUT, 10L))) ||
151 (CURLE_OK !=
152 (errornum = curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 10L))) ||
153 (CURLE_OK !=
154 (errornum = curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer))) ||
155 (CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_WRITEDATA,
156 pcbc))) ||
157 /* TLS options */
158 /* currently skip any peer authentication */
159 (CURLE_OK !=
160 (errornum = curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0L))) ||
161 (CURLE_OK !=
162 (errornum = curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0L))) ||
163 (CURLE_OK !=
164 (errornum = curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L))) ||
165 (CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L))))
166 {
167 fflush (stderr);
168 fflush (stdout);
169 fprintf (stderr, "Error setting libcurl option: %s.\n",
170 curl_easy_strerror (errornum));
171 return CHECK_RES_HARD_ERROR;
172 }
173 libcurl_tls_set = 0;
174#if CURL_AT_LEAST_VERSION (7,54,0)
175 if (CURL_SSLVERSION_MAX_DEFAULT !=
176 libcurl_tls_max_vers_map[tls_ver_libcurl])
177 {
178 errornum = curl_easy_setopt (c, CURLOPT_SSLVERSION,
179 libcurl_tls_vers_map[tls_ver_libcurl]
180 | libcurl_tls_max_vers_map[tls_ver_libcurl]);
181 if (CURLE_OK == errornum)
182 libcurl_tls_set = 1;
183 else
184 {
185 fprintf (stderr, "Error setting libcurl TLS version range: "
186 "%s.\nRetrying with minimum TLS version only.\n",
187 curl_easy_strerror (errornum));
188 }
189 }
190#endif /* CURL_AT_LEAST_VERSION(7,54,0) */
191 if (! libcurl_tls_set &&
192 (CURLE_OK !=
193 (errornum = curl_easy_setopt (c, CURLOPT_SSLVERSION,
194 libcurl_tls_vers_map[tls_ver_libcurl]))))
195 {
196 fprintf (stderr, "Error setting libcurl minimum TLS version: %s.\n",
197 curl_easy_strerror (errornum));
198 return CHECK_RES_CURL_TLS_INIT_FAIL;
199 }
200
201 errornum = curl_easy_perform (c);
202 fflush (stderr);
203 fflush (stdout);
204 if (CURLE_OK != errornum)
205 {
206 if ((CURLE_SSL_CONNECT_ERROR == errornum) ||
207 (CURLE_SSL_CIPHER == errornum))
208 {
209 fprintf (stderr, "libcurl request failed due to TLS error: '%s'\n",
210 curl_easy_strerror (errornum));
211 return CHECK_RES_CURL_TLS_CONN_FAIL;
212
213 }
214 else
215 {
216 fprintf (stderr, "curl_easy_perform failed: '%s'\n",
217 curl_easy_strerror (errornum));
218 return CHECK_RES_ERR;
219 }
220 }
221 return CHECK_RES_OK;
222}
223
224
225/**
226 * negotiate a secure connection with server with specific TLS versions
227 * set for MHD and for libcurl
228 */
229static enum check_result
230check_tls_match (enum know_gnutls_tls_id tls_ver_mhd,
231 enum know_gnutls_tls_id tls_ver_libcurl,
232 uint16_t *pport)
233{
234 CURL *c;
235 struct CBC cbc;
236 enum check_result ret;
237 struct MHD_Daemon *d;
238
239 if (NULL == (cbc.buf = malloc (sizeof (char) * 255)))
240 return CHECK_RES_HARD_ERROR;
241 cbc.size = 255;
242 cbc.pos = 0;
243
244 d = NULL;
245 c = NULL;
246 ret = check_tls_match_inner (tls_ver_mhd, tls_ver_libcurl, pport,
247 &d, &cbc, &c);
248 fflush (stderr);
249 fflush (stdout);
250 if (NULL != d)
251 MHD_stop_daemon (d);
252 if (NULL != c)
253 curl_easy_cleanup (c);
77 free (cbc.buf); 254 free (cbc.buf);
78 return 0; 255
256 return ret;
79} 257}
80 258
81 259
82int 260static unsigned int
83main (int argc, char *const *argv) 261test_first_supported_versions (void)
84{ 262{
85 unsigned int errorCount = 0; 263 enum know_gnutls_tls_id ver_for_check; /**< TLS version used for test */
86 const char *ssl_version; 264 const gnutls_protocol_t *vers_list; /**< The list of GnuTLS supported TLS versions */
87 unsigned int daemon_flags =
88 MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD
89 | MHD_USE_TLS | MHD_USE_ERROR_LOG;
90 uint16_t port; 265 uint16_t port;
91 (void) argc; (void) argv; /* Unused. Silent compiler warning. */
92 266
93 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 267 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
94 port = 0; 268 port = 0; /* Use system automatic assignment */
95 else 269 else
96 port = 3010; 270 port = 3060; /* Use predefined port, may break parallel testing of another MHD build */
271
272 vers_list = gnutls_protocol_list ();
273 if (NULL == vers_list)
274 {
275 fprintf (stderr, "Error getting GnuTLS supported TLS versions");
276 return 99;
277 }
278
279 for (ver_for_check = KNOWN_TLS_MIN; KNOWN_TLS_MAX >= ver_for_check;
280 ++ver_for_check)
281 {
282 const gnutls_protocol_t *ver_ptr; /**< The pointer to the position on the @a vers_list */
283 enum check_result res;
284 for (ver_ptr = vers_list; 0 != *ver_ptr; ++ver_ptr)
285 {
286 if (ver_for_check == (enum know_gnutls_tls_id) *ver_ptr)
287 break;
288 }
289 if (0 == *ver_ptr)
290 {
291 printf ("%s is not supported by GnuTLS, skipping.\n\n",
292 tls_names[ver_for_check]);
293 fflush (stdout);
294 continue;
295 }
296 if (CURL_SSLVERSION_LAST == libcurl_tls_vers_map[ver_for_check])
297 {
298 printf ("%s is not supported by libcurl, skipping.\n\n",
299 tls_names[ver_for_check]);
300 fflush (stdout);
301 continue;
302 }
303 /* Found some TLS version that supported by GnuTLS and should be supported
304 by libcurl (but in practice support depends on used TLS library) */
305
306 if (KNOWN_TLS_MIN != ver_for_check)
307 printf ("\n");
308 printf ("Starting check with MHD set to '%s' and "
309 "libcurl set to '%s' (successful connection is expected)...\n",
310 tls_names[ver_for_check], tls_names[ver_for_check]);
311 fflush (stdout);
312
313 /* Check with MHD and libcurl set to the same TLS version */
314 res = check_tls_match (ver_for_check, ver_for_check, &port);
315 if (CHECK_RES_HARD_ERROR == res)
316 {
317 fprintf (stderr, "Hard error. Test stopped.\n");
318 fflush (stderr);
319 return 99;
320 }
321 else if (CHECK_RES_ERR == res)
322 {
323 printf ("Test failed.\n");
324 fflush (stdout);
325 return 2;
326 }
327 else if (CHECK_RES_MHD_START_FAILED == res)
328 {
329 printf ("Skipping '%s' as MHD cannot be started with this setting.\n",
330 tls_names[ver_for_check]);
331 fflush (stdout);
332 continue;
333 }
334 else if (CHECK_RES_CURL_TLS_INIT_FAIL == res)
335 {
336 printf ("Skipping '%s' as libcurl rejected this setting.\n",
337 tls_names[ver_for_check]);
338 fflush (stdout);
339 continue;
340 }
341 else if (CHECK_RES_CURL_TLS_CONN_FAIL == res)
342 {
343 printf ("Skipping '%s' as it is not supported by current libcurl "
344 "and GnuTLS combination.\n",
345 tls_names[ver_for_check]);
346 fflush (stdout);
347 continue;
348 }
349 printf ("Connection succeeded for MHD set to '%s' and "
350 "libcurl set to '%s'.\n\n",
351 tls_names[ver_for_check], tls_names[ver_for_check]);
352
353 /* Check with libcurl set to the next TLS version relative to MHD setting */
354 if (KNOWN_TLS_MAX == ver_for_check)
355 {
356 printf ("Test is incomplete as the latest known TLS version ('%s') "
357 "was found as minimum working version.\nThere is no space to "
358 "advance to the next version.\nAssuming that test is fine.\n",
359 tls_names[ver_for_check]);
360 fflush (stdout);
361 return 0;
362 }
363 if (CURL_SSLVERSION_LAST == libcurl_tls_vers_map[ver_for_check + 1])
364 {
365 printf ("Test is incomplete as '%s' is the latest version supported "
366 "by libcurl.\nThere is no space to "
367 "advance to the next version.\nAssuming that test is fine.\n",
368 tls_names[ver_for_check]);
369 fflush (stdout);
370 return 0;
371 }
372 printf ("Starting check with MHD set to '%s' and "
373 "minimum libcurl TLS version set to '%s' "
374 "(failed connection is expected)...\n",
375 tls_names[ver_for_check], tls_names[ver_for_check + 1]);
376 fflush (stdout);
377 res = check_tls_match (ver_for_check, ver_for_check + 1,
378 &port);
379 if (CHECK_RES_HARD_ERROR == res)
380 {
381 fprintf (stderr, "Hard error. Test stopped.\n");
382 fflush (stderr);
383 return 99;
384 }
385 else if (CHECK_RES_ERR == res)
386 {
387 printf ("Test failed.\n");
388 fflush (stdout);
389 return 2;
390 }
391 else if (CHECK_RES_MHD_START_FAILED == res)
392 {
393 printf ("MHD cannot be started for the second time with "
394 "the same setting.\n");
395 fflush (stdout);
396 return 4;
397 }
398 else if (CHECK_RES_CURL_TLS_INIT_FAIL == res)
399 {
400 printf ("'%s' has been rejected by libcurl.\n"
401 "Assuming that test is fine.\n",
402 tls_names[ver_for_check + 1]);
403 fflush (stdout);
404 return 0;
405 }
406 else if (CHECK_RES_CURL_TLS_CONN_FAIL == res)
407 {
408 printf ("As expected, libcurl cannot connect to MHD when libcurl "
409 "minimum TLS version is set to '%s' while MHD TLS version set "
410 "to '%s'.\n"
411 "Test succeeded.\n",
412 tls_names[ver_for_check + 1], tls_names[ver_for_check]);
413 fflush (stdout);
414 return 0;
415 }
416 }
417
418 fprintf (stderr, "The test skipped: No know TLS version is supported by "
419 "both MHD and libcurl.\n");
420 fflush (stderr);
421 return 77;
422}
423
424
425int
426main (int argc, char *const *argv)
427{
428 unsigned int errorCount = 0;
429 const char *ssl_version;
430 (void) argc; /* Unused. Silent compiler warning. */
97 431
98#ifdef MHD_HTTPS_REQUIRE_GCRYPT 432#ifdef MHD_HTTPS_REQUIRE_GCRYPT
99 gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
100 gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); 433 gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
101#ifdef GCRYCTL_INITIALIZATION_FINISHED 434#ifdef GCRYCTL_INITIALIZATION_FINISHED
102 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); 435 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
@@ -106,66 +439,20 @@ main (int argc, char *const *argv)
106 return 99; 439 return 99;
107 440
108 ssl_version = curl_version_info (CURLVERSION_NOW)->ssl_version; 441 ssl_version = curl_version_info (CURLVERSION_NOW)->ssl_version;
109 if (0 == strncmp (ssl_version, "OpenSSL/", 8)) 442 if (NULL == ssl_version)
110 {
111 if (0 == strncmp (ssl_version, "OpenSSL/0.", 10))
112 {
113 fprintf (stderr, "Curl uses too old library: %s\n", ssl_version);
114 curl_global_cleanup ();
115 return 77;
116 }
117 }
118 else if ((0 == strncmp (ssl_version, "GnuTLS/", 7)))
119 { 443 {
120#if GNUTLS_VERSION_NUMBER <= 0x020806 444 fprintf (stderr, "Curl does not support SSL. Cannot run the test.\n");
121 fprintf (stderr, "Curl uses too old library: %s\n", ssl_version);
122 curl_global_cleanup ();
123 return 77;
124#else
125 (void) 0;
126#endif
127 }
128 else
129 {
130 if (NULL == ssl_version)
131 fprintf (stderr, "Curl does not support TLS.\n");
132 else
133 fprintf (stderr, "Curl uses too old library: %s\n", ssl_version);
134 curl_global_cleanup (); 445 curl_global_cleanup ();
135 return 77; 446 return 77;
136 } 447 }
137 448 errorCount = test_first_supported_versions ();
138 if (0 != 449 fflush (stderr);
139 test_wrap ("TLS1.0", 450 fflush (stdout);
140 &test_https_transfer, NULL, port, daemon_flags,
141 NULL,
142 CURL_SSLVERSION_TLSv1,
143 MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem,
144 MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
145 MHD_OPTION_HTTPS_PRIORITIES,
146 "NONE:+VERS-TLS1.0:+AES-128-CBC:+SHA1:+RSA:+COMP-NULL",
147 MHD_OPTION_END))
148 {
149 fprintf (stderr, "TLS1.0 test failed\n");
150 errorCount++;
151 }
152 fprintf (stderr,
153 "The following handshake should fail (and print an error message)...\n");
154 if (0 !=
155 test_wrap ("TLS1.1 vs TLS1.0",
156 &test_unmatching_ssl_version, NULL, port, daemon_flags,
157 NULL,
158 CURL_SSLVERSION_TLSv1_1,
159 MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem,
160 MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
161 MHD_OPTION_HTTPS_PRIORITIES,
162 "NONE:+VERS-TLS1.0:+AES-256-CBC:+SHA1:+RSA:+COMP-NULL",
163 MHD_OPTION_END))
164 {
165 fprintf (stderr, "TLS1.1 vs TLS1.0 test failed\n");
166 errorCount++;
167 }
168 curl_global_cleanup (); 451 curl_global_cleanup ();
169 452 if (77 == errorCount)
453 return 77;
454 else if (99 == errorCount)
455 return 99;
456 print_test_result (errorCount, argv[0]);
170 return errorCount != 0 ? 1 : 0; 457 return errorCount != 0 ? 1 : 0;
171} 458}