libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit cfe614ca375d068b203db10207c97930936f779b
parent a781ffa5834f0ed4a496cf854d374a0e958e293f
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
Date:   Sat,  8 Oct 2022 18:46:15 +0300

test_https_session_info: removed hardcoded TLS version

Test rewritten to use several known TLS versions. If all known TLS
version fail, test is skipped instead of error.
This way MHD is forward-compatible with TLS libraries versions, as
TLS versions are phased out from time to time.

Diffstat:
Msrc/testcurl/https/test_https_session_info.c | 311+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Msrc/testcurl/https/tls_test_common.c | 23+++++++++++++++++++++++
Msrc/testcurl/https/tls_test_common.h | 29+++++++++++++++++++++++++++++
3 files changed, 276 insertions(+), 87 deletions(-)

diff --git a/src/testcurl/https/test_https_session_info.c b/src/testcurl/https/test_https_session_info.c @@ -35,7 +35,6 @@ #include "tls_test_common.h" #include "tls_test_keys.h" -#if LIBCURL_VERSION_NUM >= 0x072200 static struct MHD_Daemon *d; /* @@ -43,45 +42,45 @@ static struct MHD_Daemon *d; * used to query negotiated security parameters */ static enum MHD_Result -query_session_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) +query_info_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 MHD_Response *response; enum MHD_Result ret; - int gret; - (void) cls; (void) url; (void) method; (void) version; /* Unused. Silent compiler warning. */ - (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */ + const union MHD_ConnectionInfo *conn_info; + enum know_gnutls_tls_id *used_tls_ver; + (void) url; (void) method; (void) version; /* Unused. Silent compiler warning. */ + (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */ + used_tls_ver = (enum know_gnutls_tls_id *) cls; if (NULL == *req_cls) { - *req_cls = (void *) &query_session_ahc; + *req_cls = (void *) &query_info_ahc; return MHD_YES; } - if (GNUTLS_TLS1_1 != - (gret = MHD_get_connection_info - (connection, - MHD_CONNECTION_INFO_PROTOCOL)->protocol)) + conn_info = MHD_get_connection_info (connection, + MHD_CONNECTION_INFO_PROTOCOL); + if (NULL == conn_info) { - if (GNUTLS_TLS1_2 == gret) - { - /* as usual, TLS implementations sometimes don't - quite do what was asked, just mildly complain... */ - fprintf (stderr, - "Warning: requested TLS 1.1, got TLS 1.2\n"); - } - else - { - /* really different version... */ - fprintf (stderr, - "Error: requested protocol mismatch (wanted %d, got %d)\n", - GNUTLS_TLS1_1, - gret); - return MHD_NO; - } + fflush (stderr); + fflush (stdout); + fprintf (stderr, "MHD_get_connection_info() failed.\n"); + fflush (stderr); + return MHD_NO; } + if (0 == (unsigned int) conn_info->protocol) + { + fflush (stderr); + fflush (stdout); + fprintf (stderr, "MHD_get_connection_info()->protocol has " + "wrong zero value.\n"); + fflush (stderr); + return MHD_NO; + } + *used_tls_ver = (enum know_gnutls_tls_id) conn_info->protocol; response = MHD_create_response_from_buffer_static (strlen (EMPTY_PAGE), EMPTY_PAGE); @@ -95,30 +94,27 @@ query_session_ahc (void *cls, struct MHD_Connection *connection, * negotiate a secure connection with server & query negotiated security parameters */ static unsigned int -test_query_session (void) +test_query_session (enum know_gnutls_tls_id tls_ver, uint16_t *pport) { CURL *c; struct CBC cbc; CURLcode errornum; char url[256]; - uint16_t port; - - if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) - port = 0; - else - port = 3060; + enum know_gnutls_tls_id found_tls_ver; if (NULL == (cbc.buf = malloc (sizeof (char) * 255))) - return 16; + return 99; cbc.size = 255; cbc.pos = 0; /* setup test */ + found_tls_ver = KNOWN_BAD; d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_TLS - | MHD_USE_ERROR_LOG, port, - NULL, NULL, &query_session_ahc, NULL, - MHD_OPTION_HTTPS_PRIORITIES, "NORMAL:+ARCFOUR-128", + | MHD_USE_ERROR_LOG, *pport, + NULL, NULL, + &query_info_ahc, &found_tls_ver, + MHD_OPTION_HTTPS_PRIORITIES, priorities_map[tls_ver], MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, MHD_OPTION_END); @@ -126,63 +122,219 @@ test_query_session (void) if (d == NULL) { free (cbc.buf); - return 2; + fflush (stderr); + fflush (stdout); + fprintf (stderr, "MHD_start_daemon() with %s failed.\n", + tls_names[tls_ver]); + fflush (stderr); + return 77; } - if (0 == port) + 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) ) { MHD_stop_daemon (d); + fflush (stderr); + fflush (stdout); + fprintf (stderr, "MHD_get_daemon_info() failed.\n"); + fflush (stderr); free (cbc.buf); - return 32; + return 10; } - port = dinfo->port; + *pport = dinfo->port; /* Use the same port for rest of the checks */ } gen_test_uri (url, sizeof (url), - port); + *pport); c = curl_easy_init (); #ifdef _DEBUG curl_easy_setopt (c, CURLOPT_VERBOSE, 1L); #endif - curl_easy_setopt (c, CURLOPT_URL, url); - curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); - curl_easy_setopt (c, CURLOPT_TIMEOUT, 10L); - curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 10L); - curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); - curl_easy_setopt (c, CURLOPT_FILE, &cbc); - /* TLS options */ - curl_easy_setopt (c, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1); - /* currently skip any peer authentication */ - curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0L); - curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); - - /* NOTE: use of CONNECTTIMEOUT without also - * setting NOSIGNAL results in really weird - * crashes on my system! */ - curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); - if (CURLE_OK != (errornum = curl_easy_perform (c))) + + 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, &copyBuffer))) || + (CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_WRITEDATA, + &cbc))) || + /* 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)))) { - fprintf (stderr, "curl_easy_perform failed: `%s'\n", + fflush (stderr); + fflush (stdout); + fprintf (stderr, "Error setting libcurl option: %s.\n", curl_easy_strerror (errornum)); + fflush (stderr); + return 99; + } + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + unsigned int ret; MHD_stop_daemon (d); curl_easy_cleanup (c); free (cbc.buf); - return 1; + + fflush (stderr); + fflush (stdout); + if ((CURLE_SSL_CONNECT_ERROR == errornum) || + (CURLE_SSL_CIPHER == errornum)) + { + ret = 77; + fprintf (stderr, "libcurl request failed due to TLS error: '%s'\n", + curl_easy_strerror (errornum)); + + } + else + { + ret = 1; + fprintf (stderr, "curl_easy_perform failed: '%s'\n", + curl_easy_strerror (errornum)); + } + fflush (stderr); + + return ret; } curl_easy_cleanup (c); MHD_stop_daemon (d); free (cbc.buf); + + if (tls_ver != found_tls_ver) + { + fflush (stderr); + fflush (stdout); + fprintf (stderr, "MHD_get_connection_info (conn, " + "MHD_CONNECTION_INFO_PROTOCOL) returned unexpected " + "protocol version.\n" + "\tReturned: %s (%u)\tExpected: %s (%u)\n", + ((unsigned int) found_tls_ver) > KNOWN_TLS_MAX ? + "[wrong value]" : tls_names[found_tls_ver], + (unsigned int) found_tls_ver, + tls_names[tls_ver], (unsigned int) tls_ver); + fflush (stderr); + return 2; + } return 0; } +static unsigned int +test_all_supported_versions (void) +{ + enum know_gnutls_tls_id ver_for_test; /**< TLS version used for test */ + const gnutls_protocol_t *vers_list; /**< The list of GnuTLS supported TLS versions */ + uint16_t port; + unsigned int num_success; /**< Number of tests succeeded */ + unsigned int num_failed; /**< Number of tests failed */ + + 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) + { + fflush (stderr); + fflush (stdout); + fprintf (stderr, "Error getting GnuTLS supported TLS versions"); + fflush (stdout); + return 99; + } + num_success = 0; + num_failed = 0; + + for (ver_for_test = KNOWN_TLS_MIN; KNOWN_TLS_MAX >= ver_for_test; + ++ver_for_test) + { + const gnutls_protocol_t *ver_ptr; /**< The pointer to the position on the @a vers_list */ + unsigned int res; + for (ver_ptr = vers_list; 0 != *ver_ptr; ++ver_ptr) + { + if (ver_for_test == (enum know_gnutls_tls_id) *ver_ptr) + break; + } + if (0 == *ver_ptr) + { + fflush (stderr); + printf ("%s is not supported by GnuTLS, skipping.\n\n", + tls_names[ver_for_test]); + fflush (stdout); + continue; + } + fflush (stderr); + printf ("Starting check for %s...\n", + tls_names[ver_for_test]); + fflush (stdout); + res = test_query_session (ver_for_test, &port); + if (99 == res) + { + fflush (stderr); + fflush (stdout); + fprintf (stderr, "Hard error. Test stopped.\n"); + fflush (stderr); + return 99; + } + else if (77 == res) + { + fflush (stderr); + printf ("%s does not work with libcurl client and GnuTLS " + "server combination, skipping.\n", + tls_names[ver_for_test]); + fflush (stdout); + } + else if (0 != res) + { + fflush (stderr); + fflush (stdout); + fprintf (stderr, "Check failed for %s.\n", + tls_names[ver_for_test]); + fflush (stderr); + num_failed++; + } + else + { + fflush (stderr); + printf ("Check succeeded for %s.\n", + tls_names[ver_for_test]); + fflush (stdout); + num_success++; + } + printf ("\n"); + fflush (stdout); + } + + if (0 == num_failed) + { + if (0 == num_success) + { + fflush (stderr); + fflush (stdout); + fprintf (stderr, "No supported TLS version was found.\n"); + fflush (stderr); + return 77; + } + return 0; + } + return num_failed; +} + + int main (int argc, char *const *argv) { @@ -206,29 +358,14 @@ main (int argc, char *const *argv) curl_global_cleanup (); return 77; } - if (! curl_tls_is_gnutls ()) - { - fprintf (stderr, "This test can be run only with libcurl-gnutls.\n"); - curl_global_cleanup (); + errorCount = test_all_supported_versions (); + fflush (stderr); + fflush (stdout); + curl_global_cleanup (); + if (77 == errorCount) return 77; - } - errorCount += test_query_session (); + else if (99 == errorCount) + return 99; print_test_result (errorCount, argv[0]); - curl_global_cleanup (); return errorCount != 0 ? 1 : 0; } - - -#else /* LIBCURL_VERSION_NUM < 0x072200 */ - -int -main (int argc, char *const *argv) -{ - (void) argc; (void) argv; /* Unused. Silent compiler warning. */ - fprintf (stderr, "libcurl version 7.34.0 or later is required.\n" \ - "Cannot run the test.\n"); - return 77; -} - - -#endif /* LIBCURL_VERSION_NUM < 0x072200 */ diff --git a/src/testcurl/https/tls_test_common.c b/src/testcurl/https/tls_test_common.c @@ -26,6 +26,29 @@ #include "tls_test_common.h" #include "tls_test_keys.h" +/** + * Map @a know_gnutls_tls_ids values to printable names. + */ +const char *tls_names[6] = { + "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[6] = { + "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" +}; /* * test HTTPS transfer diff --git a/src/testcurl/https/tls_test_common.h b/src/testcurl/https/tls_test_common.h @@ -44,6 +44,35 @@ #define MHD_E_FAILED_TO_CONNECT \ "Error: server connection could not be established\n" + +/* 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 */ +}; + +/** + * Map @a know_gnutls_tls_ids values to printable names. + */ +extern const char *tls_names[6]; + +/** + * Map @a know_gnutls_tls_ids values to GnuTLS priorities strings. + */ +extern const char *priorities_map[6]; + struct https_test_data { void *cls;