test_https_session_info.c (11254B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007, 2016 Christian Grothoff 4 Copyright (C) 2016-2021 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_https_session_info.c 24 * @brief Testcase for libmicrohttpd HTTPS connection querying operations 25 * @author Sagie Amir 26 * @author Karlson2k (Evgeny Grin) 27 */ 28 29 #include "platform.h" 30 #include "microhttpd.h" 31 #include <curl/curl.h> 32 #ifdef MHD_HTTPS_REQUIRE_GCRYPT 33 #include <gcrypt.h> 34 #endif /* MHD_HTTPS_REQUIRE_GCRYPT */ 35 #include "tls_test_common.h" 36 #include "tls_test_keys.h" 37 38 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this 39 test into a marked, classifiable test error (TESTING.md, P5). */ 40 #include "mhd_panic_tripwire.h" 41 42 43 static int test_append_prio; 44 45 /* 46 * HTTP access handler call back 47 * used to query negotiated security parameters 48 */ 49 static enum MHD_Result 50 query_info_ahc (void *cls, struct MHD_Connection *connection, 51 const char *url, const char *method, 52 const char *version, const char *upload_data, 53 size_t *upload_data_size, void **req_cls) 54 { 55 struct MHD_Response *response; 56 enum MHD_Result ret; 57 const union MHD_ConnectionInfo *conn_info; 58 enum know_gnutls_tls_id *used_tls_ver; 59 (void) url; (void) method; (void) version; /* Unused. Silent compiler warning. */ 60 (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */ 61 used_tls_ver = (enum know_gnutls_tls_id *) cls; 62 63 if (NULL == *req_cls) 64 { 65 *req_cls = (void *) &query_info_ahc; 66 return MHD_YES; 67 } 68 69 conn_info = MHD_get_connection_info (connection, 70 MHD_CONNECTION_INFO_PROTOCOL); 71 if (NULL == conn_info) 72 { 73 fflush (stderr); 74 fflush (stdout); 75 fprintf (stderr, "MHD_get_connection_info() failed.\n"); 76 fflush (stderr); 77 return MHD_NO; 78 } 79 if (0 == (unsigned int) conn_info->protocol) 80 { 81 fflush (stderr); 82 fflush (stdout); 83 fprintf (stderr, "MHD_get_connection_info()->protocol has " 84 "wrong zero value.\n"); 85 fflush (stderr); 86 return MHD_NO; 87 } 88 *used_tls_ver = (enum know_gnutls_tls_id) conn_info->protocol; 89 90 response = MHD_create_response_from_buffer_static (strlen (EMPTY_PAGE), 91 EMPTY_PAGE); 92 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 93 MHD_destroy_response (response); 94 return ret; 95 } 96 97 98 /** 99 * negotiate a secure connection with server & query negotiated security parameters 100 */ 101 static unsigned int 102 test_query_session (enum know_gnutls_tls_id tls_ver, uint16_t *pport) 103 { 104 CURL *c; 105 struct CBC cbc; 106 CURLcode errornum; 107 char url[256]; 108 enum know_gnutls_tls_id found_tls_ver; 109 struct MHD_Daemon *d; 110 111 if (NULL == (cbc.buf = malloc (sizeof (char) * 255))) 112 return 99; 113 cbc.size = 255; 114 cbc.pos = 0; 115 116 /* setup test */ 117 found_tls_ver = KNOWN_BAD; 118 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION 119 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_TLS 120 | MHD_USE_ERROR_LOG, *pport, 121 NULL, NULL, 122 &query_info_ahc, &found_tls_ver, 123 test_append_prio ? 124 MHD_OPTION_HTTPS_PRIORITIES_APPEND : 125 MHD_OPTION_HTTPS_PRIORITIES, 126 test_append_prio ? 127 priorities_append_map[tls_ver] : 128 priorities_map[tls_ver], 129 MHD_OPTION_HTTPS_MEM_KEY, srv_self_signed_key_pem, 130 MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, 131 MHD_OPTION_END); 132 133 if (d == NULL) 134 { 135 free (cbc.buf); 136 fprintf (stderr, "MHD_start_daemon() with %s failed.\n", 137 tls_names[tls_ver]); 138 fflush (stderr); 139 return 77; 140 } 141 if (0 == *pport) 142 { 143 const union MHD_DaemonInfo *dinfo; 144 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 145 if ((NULL == dinfo) || (0 == dinfo->port) ) 146 { 147 MHD_stop_daemon (d); 148 free (cbc.buf); 149 fprintf (stderr, "MHD_get_daemon_info() failed.\n"); 150 fflush (stderr); 151 return 10; 152 } 153 *pport = dinfo->port; /* Use the same port for rest of the checks */ 154 } 155 156 gen_test_uri (url, 157 sizeof (url), 158 *pport); 159 c = curl_easy_init (); 160 fflush (stderr); 161 if (NULL == c) 162 { 163 fprintf (stderr, "curl_easy_init() failed.\n"); 164 fflush (stderr); 165 MHD_stop_daemon (d); 166 free (cbc.buf); 167 return 99; 168 } 169 #ifdef _DEBUG 170 curl_easy_setopt (c, CURLOPT_VERBOSE, 1L); 171 #endif 172 173 if ((CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_URL, url))) || 174 (CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_HTTP_VERSION, 175 CURL_HTTP_VERSION_1_1))) || 176 (CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_TIMEOUT, 10L))) || 177 (CURLE_OK != 178 (errornum = curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 10L))) || 179 (CURLE_OK != 180 (errornum = curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer))) || 181 (CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_WRITEDATA, 182 &cbc))) || 183 /* TLS options */ 184 /* currently skip any peer authentication */ 185 (CURLE_OK != 186 (errornum = curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0L))) || 187 (CURLE_OK != 188 (errornum = curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0L))) || 189 (CURLE_OK != 190 (errornum = curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L))) || 191 (CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)))) 192 { 193 curl_easy_cleanup (c); 194 free (cbc.buf); 195 MHD_stop_daemon (d); 196 fflush (stderr); 197 fflush (stdout); 198 fprintf (stderr, "Error setting libcurl option: %s.\n", 199 curl_easy_strerror (errornum)); 200 fflush (stderr); 201 return 99; 202 } 203 204 if (CURLE_OK != (errornum = curl_easy_perform (c))) 205 { 206 unsigned int ret; 207 curl_easy_cleanup (c); 208 free (cbc.buf); 209 MHD_stop_daemon (d); 210 211 fflush (stderr); 212 fflush (stdout); 213 if ((CURLE_SSL_CONNECT_ERROR == errornum) || 214 (CURLE_SSL_CIPHER == errornum)) 215 { 216 ret = 77; 217 fprintf (stderr, "libcurl request failed due to TLS error: '%s'\n", 218 curl_easy_strerror (errornum)); 219 220 } 221 else 222 { 223 ret = 1; 224 fprintf (stderr, "curl_easy_perform failed: '%s'\n", 225 curl_easy_strerror (errornum)); 226 } 227 fflush (stderr); 228 229 return ret; 230 } 231 232 curl_easy_cleanup (c); 233 free (cbc.buf); 234 MHD_stop_daemon (d); 235 236 if (tls_ver != found_tls_ver) 237 { 238 fflush (stderr); 239 fflush (stdout); 240 fprintf (stderr, "MHD_get_connection_info (conn, " 241 "MHD_CONNECTION_INFO_PROTOCOL) returned unexpected " 242 "protocol version.\n" 243 "\tReturned: %s (%u)\tExpected: %s (%u)\n", 244 ((unsigned int) found_tls_ver) > KNOWN_TLS_MAX ? 245 "[wrong value]" : tls_names[found_tls_ver], 246 (unsigned int) found_tls_ver, 247 tls_names[tls_ver], (unsigned int) tls_ver); 248 fflush (stderr); 249 return 2; 250 } 251 return 0; 252 } 253 254 255 static unsigned int 256 test_all_supported_versions (void) 257 { 258 enum know_gnutls_tls_id ver_for_test; /**< TLS version used for test */ 259 const gnutls_protocol_t *vers_list; /**< The list of GnuTLS supported TLS versions */ 260 uint16_t port; 261 unsigned int num_success; /**< Number of tests succeeded */ 262 unsigned int num_failed; /**< Number of tests failed */ 263 264 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 265 port = 0; /* Use system automatic assignment */ 266 else 267 port = 3060; /* Use predefined port, may break parallel testing of another MHD build */ 268 269 vers_list = gnutls_protocol_list (); 270 if (NULL == vers_list) 271 { 272 fprintf (stderr, "Error getting GnuTLS supported TLS versions"); 273 return 99; 274 } 275 num_success = 0; 276 num_failed = 0; 277 278 for (ver_for_test = KNOWN_TLS_MIN; KNOWN_TLS_MAX >= ver_for_test; 279 ++ver_for_test) 280 { 281 const gnutls_protocol_t *ver_ptr; /**< The pointer to the position on the @a vers_list */ 282 unsigned int res; 283 for (ver_ptr = vers_list; 0 != *ver_ptr; ++ver_ptr) 284 { 285 if (ver_for_test == (enum know_gnutls_tls_id) *ver_ptr) 286 break; 287 } 288 if (0 == *ver_ptr) 289 { 290 printf ("%s is not supported by GnuTLS, skipping.\n\n", 291 tls_names[ver_for_test]); 292 fflush (stdout); 293 continue; 294 } 295 printf ("Starting check for %s...\n", 296 tls_names[ver_for_test]); 297 fflush (stdout); 298 res = test_query_session (ver_for_test, &port); 299 fflush (stderr); 300 fflush (stdout); 301 if (99 == res) 302 { 303 fprintf (stderr, "Hard error. Test stopped.\n"); 304 fflush (stderr); 305 return 99; 306 } 307 else if (77 == res) 308 { 309 printf ("%s does not work with libcurl client and GnuTLS " 310 "server combination, skipping.\n", 311 tls_names[ver_for_test]); 312 fflush (stdout); 313 } 314 else if (0 != res) 315 { 316 fprintf (stderr, "Check failed for %s.\n", 317 tls_names[ver_for_test]); 318 fflush (stderr); 319 num_failed++; 320 } 321 else 322 { 323 printf ("Check succeeded for %s.\n", 324 tls_names[ver_for_test]); 325 fflush (stdout); 326 num_success++; 327 } 328 printf ("\n"); 329 fflush (stdout); 330 } 331 332 if (0 == num_failed) 333 { 334 if (0 == num_success) 335 { 336 fprintf (stderr, "No supported TLS version was found.\n"); 337 fflush (stderr); 338 return 77; 339 } 340 return 0; 341 } 342 return num_failed; 343 } 344 345 346 int 347 main (int argc, char *const *argv) 348 { 349 unsigned int errorCount = 0; 350 const char *ssl_version; 351 (void) argc; /* Unused. Silent compiler warning. */ 352 353 #ifdef MHD_HTTPS_REQUIRE_GCRYPT 354 gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); 355 #ifdef GCRYCTL_INITIALIZATION_FINISHED 356 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); 357 #endif 358 #endif /* MHD_HTTPS_REQUIRE_GCRYPT */ 359 test_append_prio = has_in_name (argv[0], "_append"); 360 if (! testsuite_curl_global_init ()) 361 return 99; 362 363 ssl_version = curl_version_info (CURLVERSION_NOW)->ssl_version; 364 if (NULL == ssl_version) 365 { 366 fprintf (stderr, "Curl does not support SSL. Cannot run the test.\n"); 367 curl_global_cleanup (); 368 return 77; 369 } 370 errorCount = test_all_supported_versions (); 371 fflush (stderr); 372 fflush (stdout); 373 curl_global_cleanup (); 374 if (77 == errorCount) 375 return 77; 376 else if (99 == errorCount) 377 return 99; 378 print_test_result (errorCount, argv[0]); 379 return errorCount != 0 ? 1 : 0; 380 }