diff --git a/src/microhttpd/connection_https_openssl.c b/src/microhttpd/connection_https_openssl.c index 60497728..fd2e3d8c 100644 --- a/src/microhttpd/connection_https_openssl.c +++ b/src/microhttpd/connection_https_openssl.c @@ -41,8 +41,11 @@ FILE *err_file; void init_openssl () { - SSL_load_error_strings (); + #if OPENSSL_API_LEVEL < 3000 + // deprecated since OpenSSL 3.0 ERR_load_BIO_strings (); + #endif + SSL_load_error_strings (); OpenSSL_add_all_algorithms (); } @@ -103,8 +106,8 @@ create_secure_connection (SSL_CTX *ctx, const char *hostnname, const char *port, BIO_set_conn_hostname (bio, hostnname); // Set the BIO in a non blocking mode BIO_set_nbio (bio, 1); - if ((MHD_TLS_CONN_INIT == connection->tls.openssl.tls_session) || - (MHD_TLS_CONN_HANDSHAKING == connection->tls.openssl.tls_state)) + if ((1 == SSL_is_init_finished (ssl)) || + (1 == SSL_in_init (ssl))) { ret = BIO_do_handshake (bio); if (1 == ret) diff --git a/src/testcurl/https/tls_test_common_openssl.c b/src/testcurl/https/tls_test_common_openssl.c new file mode 100644 index 00000000..1e6ab948 --- /dev/null +++ b/src/testcurl/https/tls_test_common_openssl.c @@ -0,0 +1,799 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007 Christian Grothoff + Copyright (C) 2017-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 + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + 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_test_common.c + * @brief Common tls test functions + * @author Sagie Amir + * @author Karlson2k (Evgeny Grin) + * @author Édouard LEFIZELIER + */ +#include +#include "tls_test_common_openssl.h" +#include "tls_test_keys.h" + +/** + * Map @a know_gnutls_tls_ids values to printable names. + */ +const char *tls_names[KNOW_TLS_IDS_COUNT] = { + "Bad value", + "SSL version 3", + "TLS version 1.0", + "TLS version 1.1", + "TLS version 1.2", + "TLS version 1.3" +}; + +/** + * Map @a know_gnutls_tls_ids values to GnuTLS priorities strings. + */ +const char *priorities_map[KNOW_TLS_IDS_COUNT] = { + "NONE", + "NORMAL:!VERS-ALL:+VERS-SSL3.0", + "NORMAL:!VERS-ALL:+VERS-TLS1.0", + "NORMAL:!VERS-ALL:+VERS-TLS1.1", + "NORMAL:!VERS-ALL:+VERS-TLS1.2", + "NORMAL:!VERS-ALL:+VERS-TLS1.3" +}; + +/** + * Map @a know_gnutls_tls_ids values to GnuTLS priorities append strings. + */ +const char *priorities_append_map[KNOW_TLS_IDS_COUNT] = { + "NONE", + "!VERS-ALL:+VERS-SSL3.0", + "!VERS-ALL:+VERS-TLS1.0", + "!VERS-ALL:+VERS-TLS1.1", + "!VERS-ALL:+VERS-TLS1.2", + "!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 + */ +enum test_get_result +test_daemon_get (void *cls, + const char *cipher_suite, + int proto_version, + uint16_t port, + int ver_peer) +{ + CURL *c; + struct CBC cbc; + CURLcode errornum; + CURLcode e; + char url[255]; + size_t len; + (void) cls; /* Unused. Silence compiler warning. */ + + len = strlen (test_data); + if (NULL == (cbc.buf = malloc (sizeof (char) * len))) + { + fprintf (stderr, MHD_E_MEM); + return TEST_GET_HARD_ERROR; + } + cbc.size = len; + cbc.pos = 0; + + /* construct url - this might use doc_path */ + gen_test_uri (url, + sizeof (url), + port); + + c = curl_easy_init (); +#ifdef _DEBUG + curl_easy_setopt (c, CURLOPT_VERBOSE, 1L); +#endif + if ((CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_URL, url))) || + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_HTTP_VERSION, + CURL_HTTP_VERSION_1_1))) || + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_TIMEOUT, 10L))) || + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 10L))) || + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, + ©Buffer))) || + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc))) || + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L))) || + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)))) + { + fprintf (stderr, "curl_easy_setopt failed: `%s'\n", + curl_easy_strerror (e)); + curl_easy_cleanup (c); + free (cbc.buf); + return TEST_GET_CURL_GEN_ERROR; + } + + /* TLS options */ + if ((CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_SSLVERSION, + proto_version))) || + ((NULL != cipher_suite) && + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_SSL_CIPHER_LIST, + cipher_suite)))) || + + /* perform peer authentication */ + /* TODO merge into send_curl_req */ + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, + ver_peer))) || + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0L)))) + { + fprintf (stderr, "HTTPS curl_easy_setopt failed: `%s'\n", + curl_easy_strerror (e)); + curl_easy_cleanup (c); + free (cbc.buf); + return TEST_GET_CURL_GEN_ERROR; + } + if (ver_peer && + (CURLE_OK != + (e = curl_easy_setopt (c, CURLOPT_CAINFO, ca_cert_file_name)))) + { + fprintf (stderr, "HTTPS curl_easy_setopt failed: `%s'\n", + curl_easy_strerror (e)); + curl_easy_cleanup (c); + free (cbc.buf); + return TEST_GET_CURL_CA_ERROR; + } + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + free (cbc.buf); + if ((CURLE_SSL_CACERT_BADFILE == errornum) +#if CURL_AT_LEAST_VERSION (7,21,5) + || (CURLE_NOT_BUILT_IN == errornum) +#endif /* CURL_AT_LEAST_VERSION (7,21,5) */ + ) + return TEST_GET_CURL_CA_ERROR; + if (CURLE_OUT_OF_MEMORY == errornum) + return TEST_GET_HARD_ERROR; + return TEST_GET_ERROR; + } + + curl_easy_cleanup (c); + + if (memcmp (cbc.buf, test_data, len) != 0) + { + fprintf (stderr, "Error: local data & received data differ.\n"); + free (cbc.buf); + return TEST_GET_TRANSFER_ERROR; + } + + free (cbc.buf); + return TEST_GET_OK; +} + + +void +print_test_result (unsigned int test_outcome, + const char *test_name) +{ + if (test_outcome != 0) + fprintf (stderr, + "running test: %s [fail: %u]\n", + test_name, test_outcome); +#if 0 + else + fprintf (stdout, + "running test: %s [pass]\n", + test_name); +#endif +} + + +size_t +copyBuffer (void *ptr, + size_t size, + size_t nmemb, + void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + { + fprintf (stderr, "Server data does not fit buffer.\n"); + return 0; /* overflow */ + } + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + + +/** + * HTTP access handler call back + */ +enum MHD_Result +http_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) +{ + static int aptr; + struct MHD_Response *response; + enum MHD_Result ret; + (void) cls; (void) url; (void) version; /* Unused. Silent compiler warning. */ + (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */ + + if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) + return MHD_NO; /* unexpected method */ + if (&aptr != *req_cls) + { + /* do never respond on first call */ + *req_cls = &aptr; + return MHD_YES; + } + *req_cls = NULL; /* reset when done */ + response = MHD_create_response_from_buffer_static (strlen (test_data), + test_data); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; +} + + +/* HTTP access handler call back */ +enum MHD_Result +http_dummy_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) +{ + (void) cls; + (void) connection; + (void) url; + (void) method; + (void) version; /* Unused. Silent compiler warning. */ + (void) upload_data; + (void) upload_data_size; + (void) req_cls; /* Unused. Silent compiler warning. */ + return 0; +} + + +/** + * send a test http request to the daemon + * @param url + * @param cbc - may be null + * @param cipher_suite + * @param proto_version + * @return + */ +/* TODO have test wrap consider a NULL cbc */ +CURLcode +send_curl_req (char *url, + struct CBC *cbc, + const char *cipher_suite, + int proto_version) +{ + CURL *c; + CURLcode errornum; + CURLcode e; + c = curl_easy_init (); +#ifdef _DEBUG + curl_easy_setopt (c, CURLOPT_VERBOSE, 1L); +#endif + if ((CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_URL, url))) || + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_HTTP_VERSION, + CURL_HTTP_VERSION_1_1))) || + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_TIMEOUT, 60L))) || + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 60L))) || + + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L))) || + + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)))) + { + fprintf (stderr, "curl_easy_setopt failed: `%s'\n", + curl_easy_strerror (e)); + curl_easy_cleanup (c); + return e; + } + if (cbc != NULL) + { + if ((CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, + ©Buffer))) || + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc)))) + { + fprintf (stderr, "curl_easy_setopt failed: `%s'\n", + curl_easy_strerror (e)); + curl_easy_cleanup (c); + return e; + } + } + + /* TLS options */ + if ((CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_SSLVERSION, + proto_version))) || + ((NULL != cipher_suite) && + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_SSL_CIPHER_LIST, + cipher_suite)))) || + /* currently skip any peer authentication */ + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0L))) || + (CURLE_OK != (e = curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0L)))) + { + fprintf (stderr, "HTTPS curl_easy_setopt failed: `%s'\n", + curl_easy_strerror (e)); + curl_easy_cleanup (c); + return e; + } + + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + return errornum; + } + curl_easy_cleanup (c); + + return CURLE_OK; +} + + +/** + * compile test URI + * + * @param[out] uri - char buffer into which the url is compiled + * @param uri_len number of bytes available in @a url + * @param port port to use for the test + * @return 1 on error + */ +unsigned int +gen_test_uri (char *uri, + size_t uri_len, + uint16_t port) +{ + int res; + + res = snprintf (uri, + uri_len, + "https://127.0.0.1:%u/urlpath", + (unsigned int) port); + if (res <= 0) + return 1; + if ((size_t) res >= uri_len) + return 1; + + return 0; +} + + +/** + * test HTTPS data transfer + */ +unsigned int +test_https_transfer (void *cls, + uint16_t port, + const char *cipher_suite, + int proto_version) +{ + size_t len; + unsigned int ret = 0; + struct CBC cbc; + char url[255]; + (void) cls; /* Unused. Silent compiler warning. */ + + len = strlen (test_data); + if (NULL == (cbc.buf = malloc (sizeof (char) * len))) + { + fprintf (stderr, MHD_E_MEM); + return 1; + } + cbc.size = len; + cbc.pos = 0; + + if (gen_test_uri (url, + sizeof (url), + port)) + { + ret = 1; + goto cleanup; + } + + if (CURLE_OK != + send_curl_req (url, &cbc, cipher_suite, proto_version)) + { + ret = 1; + goto cleanup; + } + + /* compare test data & daemon response */ + if ( (len != strlen (test_data)) || + (memcmp (cbc.buf, + test_data, + len) != 0) ) + { + fprintf (stderr, "Error: original data & received data differ.\n"); + ret = 1; + } +cleanup: + free (cbc.buf); + return ret; +} + + +/** + * setup test case + * + * @param d + * @param daemon_flags + * @param arg_list + * @return port number on success or zero on failure + */ +static uint16_t +setup_testcase (struct MHD_Daemon **d, uint16_t port, unsigned int daemon_flags, + va_list arg_list) +{ + *d = MHD_start_daemon_va (daemon_flags, port, + NULL, NULL, &http_ahc, NULL, arg_list); + + if (*d == NULL) + { + fprintf (stderr, MHD_E_SERVER_INIT); + return 0; + } + + if (0 == port) + { + const union MHD_DaemonInfo *dinfo; + dinfo = MHD_get_daemon_info (*d, MHD_DAEMON_INFO_BIND_PORT); + if ((NULL == dinfo) || (0 == dinfo->port) ) + { + MHD_stop_daemon (*d); + return 0; + } + port = dinfo->port; + } + + return port; +} + + +static void +teardown_testcase (struct MHD_Daemon *d) +{ + MHD_stop_daemon (d); +} + + +unsigned int +setup_session (gnutls_session_t *session, + gnutls_certificate_credentials_t *xcred) +{ + if (GNUTLS_E_SUCCESS == gnutls_init (session, GNUTLS_CLIENT)) + { + if (GNUTLS_E_SUCCESS == gnutls_set_default_priority (*session)) + { + if (GNUTLS_E_SUCCESS == gnutls_certificate_allocate_credentials (xcred)) + { + if (GNUTLS_E_SUCCESS == gnutls_credentials_set (*session, + GNUTLS_CRD_CERTIFICATE, + *xcred)) + { + return 0; + } + gnutls_certificate_free_credentials (*xcred); + } + } + gnutls_deinit (*session); + } + return 1; +} + + +unsigned int +setup_session_openssl (const char *PATH) +{ + init_openssl (); + SSL_CTX *ctx = create_context (); + set_context (ctx, PATH); +} + + +unsigned int +teardown_session (gnutls_session_t session, + gnutls_certificate_credentials_t xcred) +{ + gnutls_deinit (session); + gnutls_certificate_free_credentials (xcred); + return 0; +} + + +unsigned int +teardown_session_openssl (BIO *bio, struct MHD_Connection *connection) +{ + return close_connection (bio, connection); +} + + +/* TODO test_wrap: change sig to (setup_func, test, va_list test_arg) */ +unsigned int +test_wrap (const char *test_name, unsigned int + (*test_function)(void *cls, uint16_t port, const char *cipher_suite, + int proto_version), void *cls, + uint16_t port, + unsigned int daemon_flags, const char *cipher_suite, + int proto_version, ...) +{ + unsigned int ret; + va_list arg_list; + struct MHD_Daemon *d; + (void) cls; /* Unused. Silent compiler warning. */ + + va_start (arg_list, proto_version); + port = setup_testcase (&d, port, daemon_flags, arg_list); + if (0 == port) + { + va_end (arg_list); + fprintf (stderr, "Failed to setup testcase %s\n", test_name); + return 1; + } +#if 0 + fprintf (stdout, "running test: %s ", test_name); +#endif + ret = test_function (NULL, port, cipher_suite, proto_version); +#if 0 + if (ret == 0) + { + fprintf (stdout, "[pass]\n"); + } + else + { + fprintf (stdout, "[fail]\n"); + } +#endif + teardown_testcase (d); + va_end (arg_list); + return ret; +} + + +static int inited_tls_is_gnutls = 0; +static int inited_tls_is_openssl = 0; + +int +curl_tls_is_gnutls (void) +{ + const char *tlslib; + if (inited_tls_is_gnutls) + return 1; + if (inited_tls_is_openssl) + return 0; + + tlslib = curl_version_info (CURLVERSION_NOW)->ssl_version; + if (NULL == tlslib) + return 0; + if (0 == strncmp (tlslib, "GnuTLS/", 7)) + return 1; + + /* Multi-backends handled during initialization by setting variable */ + return 0; +} + + +int +curl_tls_is_openssl (void) +{ + const char *tlslib; + if (inited_tls_is_gnutls) + return 0; + if (inited_tls_is_openssl) + return 1; + + tlslib = curl_version_info (CURLVERSION_NOW)->ssl_version; + if (NULL == tlslib) + return 0; + if (0 == strncmp (tlslib, "OpenSSL/", 8)) + return 1; + + /* Multi-backends handled during initialization by setting variable */ + return 0; +} + + +int +curl_tls_is_nss (void) +{ + const char *tlslib; + if (inited_tls_is_gnutls) + return 0; + if (inited_tls_is_openssl) + return 0; + + tlslib = curl_version_info (CURLVERSION_NOW)->ssl_version; + if (NULL == tlslib) + return 0; + if (0 == strncmp (tlslib, "NSS/", 4)) + return 1; + + /* Handle multi-backends with selected backend */ + if (NULL != strstr (tlslib," NSS/")) + return 1; + + return 0; +} + + +int +curl_tls_is_schannel (void) +{ + const char *tlslib; + if (inited_tls_is_gnutls) + return 0; + if (inited_tls_is_openssl) + return 0; + + tlslib = curl_version_info (CURLVERSION_NOW)->ssl_version; + if (NULL == tlslib) + return 0; + if ((0 == strncmp (tlslib, "Schannel", 8)) || (0 == strncmp (tlslib, "WinSSL", + 6))) + return 1; + + /* Handle multi-backends with selected backend */ + if ((NULL != strstr (tlslib," Schannel")) || (NULL != strstr (tlslib, + " WinSSL"))) + return 1; + + return 0; +} + + +int +curl_tls_is_sectransport (void) +{ + const char *tlslib; + if (inited_tls_is_gnutls) + return 0; + if (inited_tls_is_openssl) + return 0; + + tlslib = curl_version_info (CURLVERSION_NOW)->ssl_version; + if (NULL == tlslib) + return 0; + if (0 == strncmp (tlslib, "SecureTransport", 15)) + return 1; + + /* Handle multi-backends with selected backend */ + if (NULL != strstr (tlslib," SecureTransport")) + return 1; + + return 0; +} + + +int +testsuite_curl_global_init (void) +{ + CURLcode res; +#if LIBCURL_VERSION_NUM >= 0x073800 + if (CURLSSLSET_OK != curl_global_sslset (CURLSSLBACKEND_GNUTLS, NULL, NULL)) + { + CURLsslset e; + e = curl_global_sslset (CURLSSLBACKEND_OPENSSL, NULL, NULL); + if (CURLSSLSET_TOO_LATE == e) + fprintf (stderr, "WARNING: libcurl was already initialised.\n"); + else if (CURLSSLSET_OK == e) + inited_tls_is_openssl = 1; + } + else + inited_tls_is_gnutls = 1; +#endif /* LIBCURL_VERSION_NUM >= 0x07380 */ + res = curl_global_init (CURL_GLOBAL_ALL); + if (CURLE_OK != res) + { + fprintf (stderr, "libcurl initialisation error: %s\n", + curl_easy_strerror (res)); + return 0; + } + return 1; +} + + +/** + * Check whether program name contains specific @a marker string. + * Only last component in pathname is checked for marker presence, + * all leading directories names (if any) are ignored. Directories + * separators are handled correctly on both non-W32 and W32 + * platforms. + * @param prog_name program name, may include path + * @param marker marker to look for. + * @return zero if any parameter is NULL or empty string or + * @prog_name ends with slash or @marker is not found in + * program name, non-zero if @maker is found in program + * name. + */ +int +has_in_name (const char *prog_name, const char *marker) +{ + size_t name_pos; + size_t pos; + + if (! prog_name || ! marker || ! prog_name[0] || ! marker[0]) + return 0; + + pos = 0; + name_pos = 0; + while (prog_name[pos]) + { + if ('/' == prog_name[pos]) + name_pos = pos + 1; +#if defined(_WIN32) || defined(__CYGWIN__) + else if ('\\' == prog_name[pos]) + name_pos = pos + 1; +#endif /* _WIN32 || __CYGWIN__ */ + pos++; + } + if (name_pos == pos) + return 0; + return strstr (prog_name + name_pos, marker) != (char *) 0; +} diff --git a/src/testcurl/https/tls_test_common_openssl.h b/src/testcurl/https/tls_test_common_openssl.h new file mode 100644 index 00000000..788bc723 --- /dev/null +++ b/src/testcurl/https/tls_test_common_openssl.h @@ -0,0 +1,244 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007 Christian Grothoff + Copyright (C) 2017-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 + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + 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. + */ + +#ifndef TLS_TEST_COMMON_H_ +#define TLS_TEST_COMMON_H_ + +#include "platform.h" +#include "microhttpd.h" +#include +#include +#include +#include "openssl/bio.h" +#include "openssl/ssl.h" +#include "openssl/err.h" + +#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" + +#define EMPTY_PAGE \ + "Empty pageEmpty page" +#define PAGE_NOT_FOUND \ + "File not foundFile not found" + +#define MHD_E_MEM "Error: memory error\n" +#define MHD_E_SERVER_INIT "Error: failed to start server\n" +#define MHD_E_TEST_FILE_CREAT "Error: failed to setup test file\n" +#define MHD_E_CERT_FILE_CREAT "Error: failed to setup test certificate\n" +#define MHD_E_KEY_FILE_CREAT "Error: failed to setup test certificate\n" +#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 */ +/** + * The list of know (at the moment of writing) GnuTLS IDs of TLS versions. + * Can be safely casted to/from @a gnutls_protocol_t. + */ +enum know_gnutls_tls_id +{ + KNOWN_BAD = 0, /**< No TLS */ + KNOWN_TLS_SSLv3 = 1, /**< GNUTLS_SSL3 */ + KNOWN_TLS_V1_0 = 2, /**< GNUTLS_TLS1_0 */ + KNOWN_TLS_V1_1 = 3, /**< GNUTLS_TLS1_1 */ + KNOWN_TLS_V1_2 = 4, /**< GNUTLS_TLS1_2 */ + KNOWN_TLS_V1_3 = 5, /**< GNUTLS_TLS1_3 */ + KNOWN_TLS_MIN = KNOWN_TLS_SSLv3, /**< Minimum valid value */ + 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[KNOW_TLS_IDS_COUNT]; + +/** + * Map @a know_gnutls_tls_ids values to GnuTLS priorities strings. + */ +extern const char *priorities_map[KNOW_TLS_IDS_COUNT]; + +/** + * Map @a know_gnutls_tls_ids values to GnuTLS priorities append strings. + */ +extern const char *priorities_append_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 +{ + void *cls; + uint16_t port; + const char *cipher_suite; + int proto_version; +}; + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +int +curl_tls_is_gnutls (void); + +int +curl_tls_is_openssl (void); + +int +curl_tls_is_nss (void); + +int +curl_tls_is_schannel (void); + +int +curl_tls_is_sectransport (void); + + +enum test_get_result +{ + TEST_GET_OK = 0, + TEST_GET_ERROR = 1, + + TEST_GET_MHD_ERROR = 16, + TEST_GET_TRANSFER_ERROR = 17, + + TEST_GET_CURL_GEN_ERROR = 32, + TEST_GET_CURL_CA_ERROR = 33, + TEST_GET_CURL_NOT_IMPLT = 34, + + TEST_GET_HARD_ERROR = 999 +}; +/** + * perform cURL request for file + */ +enum test_get_result +test_daemon_get (void *cls, + const char *cipher_suite, int proto_version, + uint16_t port, int ver_peer); + +void +print_test_result (unsigned int test_outcome, + const char *test_name); + +size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx); + +enum MHD_Result +http_ahc (void *cls, struct MHD_Connection *connection, + const char *url, const char *method, const char *upload_data, + const char *version, size_t *upload_data_size, void **req_cls); + +enum MHD_Result +http_dummy_ahc (void *cls, struct MHD_Connection *connection, + const char *url, const char *method, const char *upload_data, + const char *version, size_t *upload_data_size, + void **req_cls); + + +/** + * compile test URI + * + * @param[out] uri - char buffer into which the url is compiled + * @param uri_len number of bytes available in @a url + * @param port port to use for the test + * @return 1 on error + */ +unsigned int +gen_test_uri (char *uri, + size_t uri_len, + uint16_t port); + +CURLcode +send_curl_req (char *url, + struct CBC *cbc, + const char *cipher_suite, + int proto_version); + +unsigned int +test_https_transfer (void *cls, + uint16_t port, + const char *cipher_suite, + int proto_version); + +unsigned int +setup_session (gnutls_session_t *session, + gnutls_certificate_credentials_t *xcred); + +unsigned int +teardown_session (gnutls_session_t session, + gnutls_certificate_credentials_t xcred); + +unsigned int +test_wrap (const char *test_name, unsigned int + (*test_function)(void *cls, uint16_t port, const char *cipher_suite, + int proto_version), void *cls, + uint16_t port, + unsigned int daemon_flags, const char *cipher_suite, + int proto_version, ...); + +int testsuite_curl_global_init (void); + +/** + * Check whether program name contains specific @a marker string. + * Only last component in pathname is checked for marker presence, + * all leading directories names (if any) are ignored. Directories + * separators are handled correctly on both non-W32 and W32 + * platforms. + * @param prog_name program name, may include path + * @param marker marker to look for. + * @return zero if any parameter is NULL or empty string or + * @prog_name ends with slash or @marker is not found in + * program name, non-zero if @maker is found in program + * name. + */ +int +has_in_name (const char *prog_name, const char *marker); + +#endif /* TLS_TEST_COMMON_H_ */