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 @@ /* This file is part of libmicrohttpd - Copyright (C) 2007, 2010, 2016 Christian Grothoff + Copyright (C) 2007, 2016 Christian Grothoff + Copyright (C) 2016-2022 Evgeny Grin (Karlson2k) libmicrohttpd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -16,66 +17,408 @@ along with libmicrohttpd; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ + */ /** - * @file tls_daemon_options_test.c - * @brief Testcase for libmicrohttpd HTTPS GET operations + * @file test_tls_options.c + * @brief Testcase for libmicrohttpd HTTPS TLS version match/mismatch * @author Sagie Amir + * @author Karlson2k (Evgeny Grin) */ #include "platform.h" #include "microhttpd.h" -#include -#include +#include #ifdef MHD_HTTPS_REQUIRE_GCRYPT #include #endif /* MHD_HTTPS_REQUIRE_GCRYPT */ #include "tls_test_common.h" #include "tls_test_keys.h" -/** - * test server refuses to negotiate connections with unsupported protocol versions - * +/* + * HTTP access handler call back + * used to query negotiated security parameters */ -static unsigned int -test_unmatching_ssl_version (void *cls, uint16_t port, const char *cipher_suite, - int curl_req_ssl_version) +static enum MHD_Result +simple_ahc (void *cls, struct MHD_Connection *connection, + const char *url, const char *method, + const char *version, const char *upload_data, + size_t *upload_data_size, void **req_cls) { - struct CBC cbc; - char url[255]; - (void) cls; /* Unused. Silent compiler warning. */ - if (NULL == (cbc.buf = malloc (sizeof (char) * 256))) + struct MHD_Response *response; + enum MHD_Result ret; + (void) cls; (void) url; (void) method; (void) version; /* Unused. Silent compiler warning. */ + (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */ + + if (NULL == *req_cls) { - fprintf (stderr, "Error: failed to allocate: %s\n", - strerror (errno)); - return 1; + *req_cls = (void *) &simple_ahc; + return MHD_YES; } - cbc.size = 256; + + response = + MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (EMPTY_PAGE), + EMPTY_PAGE); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; +} + + +enum check_result +{ + CHECK_RES_OK = 0, + CHECK_RES_ERR = 1, + + CHECK_RES_MHD_START_FAILED = 17, + CHECK_RES_CURL_TLS_INIT_FAIL = 18, + CHECK_RES_CURL_TLS_CONN_FAIL = 19, + + CHECK_RES_HARD_ERROR = 99 +}; + +static enum check_result +check_tls_match_inner (enum know_gnutls_tls_id tls_ver_mhd, + enum know_gnutls_tls_id tls_ver_libcurl, + uint16_t *pport, + struct MHD_Daemon **d_ptr, + struct CBC *pcbc, + CURL **c_ptr) +{ + CURLcode errornum; + char url[256]; + int libcurl_tls_set; + CURL *c; + struct MHD_Daemon *d; + + /* setup test */ + d = + MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION + | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_TLS + | MHD_USE_ERROR_LOG, *pport, + NULL, NULL, + &simple_ahc, NULL, + MHD_OPTION_HTTPS_PRIORITIES, priorities_map[tls_ver_mhd], + MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, + MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, + MHD_OPTION_END); + fflush (stderr); + fflush (stdout); + *d_ptr = d; + + if (d == NULL) + { + fprintf (stderr, "MHD_start_daemon() with %s failed.\n", + tls_names[tls_ver_mhd]); + return CHECK_RES_MHD_START_FAILED; + } + if (0 == *pport) + { + const union MHD_DaemonInfo *dinfo; + dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); + if ((NULL == dinfo) || (0 == dinfo->port) ) + { + fprintf (stderr, "MHD_get_daemon_info() failed.\n"); + return CHECK_RES_ERR; + } + *pport = dinfo->port; /* Use the same port for rest of the checks */ + } + + if (0 != gen_test_uri (url, + sizeof (url), + *pport)) + { + fprintf (stderr, "failed to generate URI.\n"); + return CHECK_RES_CURL_TLS_INIT_FAIL; + } + c = curl_easy_init (); + fflush (stderr); + fflush (stdout); + *c_ptr = c; + if (NULL == c) + { + fprintf (stderr, "curl_easy_init() failed.\n"); + return CHECK_RES_HARD_ERROR; + } +#ifdef _DEBUG + curl_easy_setopt (c, CURLOPT_VERBOSE, 1L); +#endif + + if ((CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_URL, url))) || + (CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_HTTP_VERSION, + CURL_HTTP_VERSION_1_1))) || + (CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_TIMEOUT, 10L))) || + (CURLE_OK != + (errornum = curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 10L))) || + (CURLE_OK != + (errornum = curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer))) || + (CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_WRITEDATA, + pcbc))) || + /* TLS options */ + /* currently skip any peer authentication */ + (CURLE_OK != + (errornum = curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0L))) || + (CURLE_OK != + (errornum = curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0L))) || + (CURLE_OK != + (errornum = curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L))) || + (CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)))) + { + fflush (stderr); + fflush (stdout); + fprintf (stderr, "Error setting libcurl option: %s.\n", + curl_easy_strerror (errornum)); + return CHECK_RES_HARD_ERROR; + } + libcurl_tls_set = 0; +#if CURL_AT_LEAST_VERSION (7,54,0) + if (CURL_SSLVERSION_MAX_DEFAULT != + libcurl_tls_max_vers_map[tls_ver_libcurl]) + { + errornum = curl_easy_setopt (c, CURLOPT_SSLVERSION, + libcurl_tls_vers_map[tls_ver_libcurl] + | libcurl_tls_max_vers_map[tls_ver_libcurl]); + if (CURLE_OK == errornum) + libcurl_tls_set = 1; + else + { + fprintf (stderr, "Error setting libcurl TLS version range: " + "%s.\nRetrying with minimum TLS version only.\n", + curl_easy_strerror (errornum)); + } + } +#endif /* CURL_AT_LEAST_VERSION(7,54,0) */ + if (! libcurl_tls_set && + (CURLE_OK != + (errornum = curl_easy_setopt (c, CURLOPT_SSLVERSION, + libcurl_tls_vers_map[tls_ver_libcurl])))) + { + fprintf (stderr, "Error setting libcurl minimum TLS version: %s.\n", + curl_easy_strerror (errornum)); + return CHECK_RES_CURL_TLS_INIT_FAIL; + } + + errornum = curl_easy_perform (c); + fflush (stderr); + fflush (stdout); + if (CURLE_OK != errornum) + { + if ((CURLE_SSL_CONNECT_ERROR == errornum) || + (CURLE_SSL_CIPHER == errornum)) + { + fprintf (stderr, "libcurl request failed due to TLS error: '%s'\n", + curl_easy_strerror (errornum)); + return CHECK_RES_CURL_TLS_CONN_FAIL; + + } + else + { + fprintf (stderr, "curl_easy_perform failed: '%s'\n", + curl_easy_strerror (errornum)); + return CHECK_RES_ERR; + } + } + return CHECK_RES_OK; +} + + +/** + * negotiate a secure connection with server with specific TLS versions + * set for MHD and for libcurl + */ +static enum check_result +check_tls_match (enum know_gnutls_tls_id tls_ver_mhd, + enum know_gnutls_tls_id tls_ver_libcurl, + uint16_t *pport) +{ + CURL *c; + struct CBC cbc; + enum check_result ret; + struct MHD_Daemon *d; + + if (NULL == (cbc.buf = malloc (sizeof (char) * 255))) + return CHECK_RES_HARD_ERROR; + cbc.size = 255; cbc.pos = 0; - if (gen_test_uri (url, - sizeof (url), - port)) - { - free (cbc.buf); - fprintf (stderr, - "Internal error in gen_test_file_url\n"); - return 1; - } - - /* assert daemon *rejected* request */ - if (CURLE_OK == - send_curl_req (url, &cbc, cipher_suite, curl_req_ssl_version)) - { - free (cbc.buf); - fprintf (stderr, - "cURL failed to reject request despite SSL version mismatch!\n"); - return 1; - } - + d = NULL; + c = NULL; + ret = check_tls_match_inner (tls_ver_mhd, tls_ver_libcurl, pport, + &d, &cbc, &c); + fflush (stderr); + fflush (stdout); + if (NULL != d) + MHD_stop_daemon (d); + if (NULL != c) + curl_easy_cleanup (c); free (cbc.buf); - return 0; + + return ret; +} + + +static unsigned int +test_first_supported_versions (void) +{ + enum know_gnutls_tls_id ver_for_check; /**< TLS version used for test */ + const gnutls_protocol_t *vers_list; /**< The list of GnuTLS supported TLS versions */ + uint16_t port; + + if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) + port = 0; /* Use system automatic assignment */ + else + port = 3060; /* Use predefined port, may break parallel testing of another MHD build */ + + vers_list = gnutls_protocol_list (); + if (NULL == vers_list) + { + fprintf (stderr, "Error getting GnuTLS supported TLS versions"); + return 99; + } + + for (ver_for_check = KNOWN_TLS_MIN; KNOWN_TLS_MAX >= ver_for_check; + ++ver_for_check) + { + const gnutls_protocol_t *ver_ptr; /**< The pointer to the position on the @a vers_list */ + enum check_result res; + for (ver_ptr = vers_list; 0 != *ver_ptr; ++ver_ptr) + { + if (ver_for_check == (enum know_gnutls_tls_id) *ver_ptr) + break; + } + if (0 == *ver_ptr) + { + printf ("%s is not supported by GnuTLS, skipping.\n\n", + tls_names[ver_for_check]); + fflush (stdout); + continue; + } + if (CURL_SSLVERSION_LAST == libcurl_tls_vers_map[ver_for_check]) + { + printf ("%s is not supported by libcurl, skipping.\n\n", + tls_names[ver_for_check]); + fflush (stdout); + continue; + } + /* Found some TLS version that supported by GnuTLS and should be supported + by libcurl (but in practice support depends on used TLS library) */ + + if (KNOWN_TLS_MIN != ver_for_check) + printf ("\n"); + printf ("Starting check with MHD set to '%s' and " + "libcurl set to '%s' (successful connection is expected)...\n", + tls_names[ver_for_check], tls_names[ver_for_check]); + fflush (stdout); + + /* Check with MHD and libcurl set to the same TLS version */ + res = check_tls_match (ver_for_check, ver_for_check, &port); + if (CHECK_RES_HARD_ERROR == res) + { + fprintf (stderr, "Hard error. Test stopped.\n"); + fflush (stderr); + return 99; + } + else if (CHECK_RES_ERR == res) + { + printf ("Test failed.\n"); + fflush (stdout); + return 2; + } + else if (CHECK_RES_MHD_START_FAILED == res) + { + printf ("Skipping '%s' as MHD cannot be started with this setting.\n", + tls_names[ver_for_check]); + fflush (stdout); + continue; + } + else if (CHECK_RES_CURL_TLS_INIT_FAIL == res) + { + printf ("Skipping '%s' as libcurl rejected this setting.\n", + tls_names[ver_for_check]); + fflush (stdout); + continue; + } + else if (CHECK_RES_CURL_TLS_CONN_FAIL == res) + { + printf ("Skipping '%s' as it is not supported by current libcurl " + "and GnuTLS combination.\n", + tls_names[ver_for_check]); + fflush (stdout); + continue; + } + printf ("Connection succeeded for MHD set to '%s' and " + "libcurl set to '%s'.\n\n", + tls_names[ver_for_check], tls_names[ver_for_check]); + + /* Check with libcurl set to the next TLS version relative to MHD setting */ + if (KNOWN_TLS_MAX == ver_for_check) + { + printf ("Test is incomplete as the latest known TLS version ('%s') " + "was found as minimum working version.\nThere is no space to " + "advance to the next version.\nAssuming that test is fine.\n", + tls_names[ver_for_check]); + fflush (stdout); + return 0; + } + if (CURL_SSLVERSION_LAST == libcurl_tls_vers_map[ver_for_check + 1]) + { + printf ("Test is incomplete as '%s' is the latest version supported " + "by libcurl.\nThere is no space to " + "advance to the next version.\nAssuming that test is fine.\n", + tls_names[ver_for_check]); + fflush (stdout); + return 0; + } + printf ("Starting check with MHD set to '%s' and " + "minimum libcurl TLS version set to '%s' " + "(failed connection is expected)...\n", + tls_names[ver_for_check], tls_names[ver_for_check + 1]); + fflush (stdout); + res = check_tls_match (ver_for_check, ver_for_check + 1, + &port); + if (CHECK_RES_HARD_ERROR == res) + { + fprintf (stderr, "Hard error. Test stopped.\n"); + fflush (stderr); + return 99; + } + else if (CHECK_RES_ERR == res) + { + printf ("Test failed.\n"); + fflush (stdout); + return 2; + } + else if (CHECK_RES_MHD_START_FAILED == res) + { + printf ("MHD cannot be started for the second time with " + "the same setting.\n"); + fflush (stdout); + return 4; + } + else if (CHECK_RES_CURL_TLS_INIT_FAIL == res) + { + printf ("'%s' has been rejected by libcurl.\n" + "Assuming that test is fine.\n", + tls_names[ver_for_check + 1]); + fflush (stdout); + return 0; + } + else if (CHECK_RES_CURL_TLS_CONN_FAIL == res) + { + printf ("As expected, libcurl cannot connect to MHD when libcurl " + "minimum TLS version is set to '%s' while MHD TLS version set " + "to '%s'.\n" + "Test succeeded.\n", + tls_names[ver_for_check + 1], tls_names[ver_for_check]); + fflush (stdout); + return 0; + } + } + + fprintf (stderr, "The test skipped: No know TLS version is supported by " + "both MHD and libcurl.\n"); + fflush (stderr); + return 77; } @@ -84,19 +427,9 @@ main (int argc, char *const *argv) { unsigned int errorCount = 0; const char *ssl_version; - unsigned int daemon_flags = - MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD - | MHD_USE_TLS | MHD_USE_ERROR_LOG; - uint16_t port; - (void) argc; (void) argv; /* Unused. Silent compiler warning. */ - - if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) - port = 0; - else - port = 3010; + (void) argc; /* Unused. Silent compiler warning. */ #ifdef MHD_HTTPS_REQUIRE_GCRYPT - gcry_control (GCRYCTL_DISABLE_SECMEM, 0); gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); #ifdef GCRYCTL_INITIALIZATION_FINISHED gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); @@ -106,66 +439,20 @@ main (int argc, char *const *argv) return 99; ssl_version = curl_version_info (CURLVERSION_NOW)->ssl_version; - if (0 == strncmp (ssl_version, "OpenSSL/", 8)) + if (NULL == ssl_version) { - if (0 == strncmp (ssl_version, "OpenSSL/0.", 10)) - { - fprintf (stderr, "Curl uses too old library: %s\n", ssl_version); - curl_global_cleanup (); - return 77; - } - } - else if ((0 == strncmp (ssl_version, "GnuTLS/", 7))) - { -#if GNUTLS_VERSION_NUMBER <= 0x020806 - fprintf (stderr, "Curl uses too old library: %s\n", ssl_version); - curl_global_cleanup (); - return 77; -#else - (void) 0; -#endif - } - else - { - if (NULL == ssl_version) - fprintf (stderr, "Curl does not support TLS.\n"); - else - fprintf (stderr, "Curl uses too old library: %s\n", ssl_version); + fprintf (stderr, "Curl does not support SSL. Cannot run the test.\n"); curl_global_cleanup (); return 77; } - - if (0 != - test_wrap ("TLS1.0", - &test_https_transfer, NULL, port, daemon_flags, - NULL, - CURL_SSLVERSION_TLSv1, - MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, - MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, - MHD_OPTION_HTTPS_PRIORITIES, - "NONE:+VERS-TLS1.0:+AES-128-CBC:+SHA1:+RSA:+COMP-NULL", - MHD_OPTION_END)) - { - fprintf (stderr, "TLS1.0 test failed\n"); - errorCount++; - } - fprintf (stderr, - "The following handshake should fail (and print an error message)...\n"); - if (0 != - test_wrap ("TLS1.1 vs TLS1.0", - &test_unmatching_ssl_version, NULL, port, daemon_flags, - NULL, - CURL_SSLVERSION_TLSv1_1, - MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, - MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, - MHD_OPTION_HTTPS_PRIORITIES, - "NONE:+VERS-TLS1.0:+AES-256-CBC:+SHA1:+RSA:+COMP-NULL", - MHD_OPTION_END)) - { - fprintf (stderr, "TLS1.1 vs TLS1.0 test failed\n"); - errorCount++; - } + errorCount = test_first_supported_versions (); + fflush (stderr); + fflush (stdout); curl_global_cleanup (); - + if (77 == errorCount) + return 77; + else if (99 == errorCount) + return 99; + print_test_result (errorCount, argv[0]); return errorCount != 0 ? 1 : 0; } diff --git a/src/testcurl/https/tls_test_common.c b/src/testcurl/https/tls_test_common.c index d2c7b14e..6d7daa02 100644 --- a/src/testcurl/https/tls_test_common.c +++ b/src/testcurl/https/tls_test_common.c @@ -29,7 +29,7 @@ /** * Map @a know_gnutls_tls_ids values to printable names. */ -const char *tls_names[6] = { +const char *tls_names[KNOW_TLS_IDS_COUNT] = { "Bad value", "SSL version 3", "TLS version 1.0", @@ -41,7 +41,7 @@ const char *tls_names[6] = { /** * Map @a know_gnutls_tls_ids values to GnuTLS priorities strings. */ -const char *priorities_map[6] = { +const char *priorities_map[KNOW_TLS_IDS_COUNT] = { "NONE", "NORMAL:!VERS-ALL:+VERS-SSL3.0", "NORMAL:!VERS-ALL:+VERS-TLS1.0", @@ -50,6 +50,50 @@ const char *priorities_map[6] = { "NORMAL:!VERS-ALL:+VERS-TLS1.3" }; + +/** + * Map @a know_gnutls_tls_ids values to libcurl @a CURLOPT_SSLVERSION value. + */ +const long libcurl_tls_vers_map[KNOW_TLS_IDS_COUNT] = { + CURL_SSLVERSION_LAST, /* bad value */ + CURL_SSLVERSION_SSLv3, +#if CURL_AT_LEAST_VERSION (7,34,0) + CURL_SSLVERSION_TLSv1_0, +#else /* CURL VER < 7.34.0 */ + CURL_SSLVERSION_TLSv1, /* TLS 1.0 or later */ +#endif /* CURL VER < 7.34.0 */ +#if CURL_AT_LEAST_VERSION (7,34,0) + CURL_SSLVERSION_TLSv1_1, +#else /* CURL VER < 7.34.0 */ + CURL_SSLVERSION_LAST, /* bad value, not supported by this libcurl version */ +#endif /* CURL VER < 7.34.0 */ +#if CURL_AT_LEAST_VERSION (7,34,0) + CURL_SSLVERSION_TLSv1_2, +#else /* CURL VER < 7.34.0 */ + CURL_SSLVERSION_LAST, /* bad value, not supported by this libcurl version */ +#endif /* CURL VER < 7.34.0 */ +#if CURL_AT_LEAST_VERSION (7,52,0) + CURL_SSLVERSION_TLSv1_3 +#else /* CURL VER < 7.34.0 */ + CURL_SSLVERSION_LAST /* bad value, not supported by this libcurl version */ +#endif /* CURL VER < 7.34.0 */ +}; + +#if CURL_AT_LEAST_VERSION (7,54,0) +/** + * Map @a know_gnutls_tls_ids values to libcurl @a CURLOPT_SSLVERSION value + * for maximum supported TLS version. + */ +const long libcurl_tls_max_vers_map[KNOW_TLS_IDS_COUNT] = { + CURL_SSLVERSION_MAX_DEFAULT, /* bad value */ + CURL_SSLVERSION_MAX_DEFAULT, /* SSLv3 */ + CURL_SSLVERSION_MAX_TLSv1_0, + CURL_SSLVERSION_MAX_TLSv1_1, + CURL_SSLVERSION_MAX_TLSv1_2, + CURL_SSLVERSION_MAX_TLSv1_3 +}; +#endif /* CURL_AT_LEAST_VERSION(7,54,0) */ + /* * test HTTPS transfer */ diff --git a/src/testcurl/https/tls_test_common.h b/src/testcurl/https/tls_test_common.h index 784ab173..074f5345 100644 --- a/src/testcurl/https/tls_test_common.h +++ b/src/testcurl/https/tls_test_common.h @@ -28,6 +28,14 @@ #include #include +#ifndef CURL_VERSION_BITS +#define CURL_VERSION_BITS(x,y,z) ((x) << 16 | (y) << 8 | (z)) +#endif /* ! CURL_VERSION_BITS */ +#ifndef CURL_AT_LEAST_VERSION +#define CURL_AT_LEAST_VERSION(x,y,z) \ + (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS (x, y, z)) +#endif /* ! CURL_AT_LEAST_VERSION */ + #define test_data "Hello World\n" #define ca_cert_file_name SRCDIR "/test-ca.crt" @@ -44,6 +52,13 @@ #define MHD_E_FAILED_TO_CONNECT \ "Error: server connection could not be established\n" +#ifndef MHD_STATICSTR_LEN_ +/** + * Determine length of static string / macro strings at compile time. + */ +#define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1) +#endif /* ! MHD_STATICSTR_LEN_ */ + /* The local copy if GnuTLS IDs to avoid long #ifdefs list with various * GnuTLS versions */ @@ -63,15 +78,29 @@ enum know_gnutls_tls_id KNOWN_TLS_MAX = KNOWN_TLS_V1_3 /**< Maximum valid value */ }; +#define KNOW_TLS_IDS_COUNT 6 /* KNOWN_TLS_MAX + 1 */ /** * Map @a know_gnutls_tls_ids values to printable names. */ -extern const char *tls_names[6]; +extern const char *tls_names[KNOW_TLS_IDS_COUNT]; /** * Map @a know_gnutls_tls_ids values to GnuTLS priorities strings. */ -extern const char *priorities_map[6]; +extern const char *priorities_map[KNOW_TLS_IDS_COUNT]; + +/** + * Map @a know_gnutls_tls_ids values to libcurl @a CURLOPT_SSLVERSION value. + */ +extern const long libcurl_tls_vers_map[KNOW_TLS_IDS_COUNT]; + +#if CURL_AT_LEAST_VERSION (7,54,0) +/** + * Map @a know_gnutls_tls_ids values to libcurl @a CURLOPT_SSLVERSION value + * for maximum supported TLS version. + */ +extern const long libcurl_tls_max_vers_map[KNOW_TLS_IDS_COUNT]; +#endif /* CURL_AT_LEAST_VERSION(7,54,0) */ struct https_test_data {