libmicrohttpd

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

commit ae588bb3c84708b17d75d3ab2ccaf5e972c28fde
parent a0026eb09eb0b6687ca55a6bf6a019b54f55d330
Author: lv-426 <oxcafebaby@yahoo.com>
Date:   Sat,  2 Aug 2008 22:17:12 +0000

added MHD_daemon_start_va
better daemon option testing through tls_option_test
other misc fixes

Diffstat:
Msrc/daemon/daemon.c | 66++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Msrc/daemon/https/tls/gnutls_alert.c | 4++--
Msrc/include/microhttpd.h | 21+++++++++++++++++++++
Msrc/testcurl/Makefile.am | 1-
Msrc/testcurl/curl_version_check.c | 6+++---
Msrc/testcurl/https/Makefile.am | 16++++++++--------
Dsrc/testcurl/https/mhds_get_test.c | 457-------------------------------------------------------------------------------
Asrc/testcurl/https/tls_daemon_options_test.c | 461+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/testcurl/https/tls_session_time_out_test.c | 1-
9 files changed, 547 insertions(+), 486 deletions(-)

diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c @@ -59,7 +59,7 @@ #if HTTPS_SUPPORT /* initialize security aspects of the HTTPS daemon */ static int -MHDS_init (struct MHD_Daemon *daemon) +MHD_TLS_init (struct MHD_Daemon *daemon) { int i; priority_st st; @@ -305,7 +305,7 @@ gnutls_push_param_adapter (void *connection, */ #if HTTPS_SUPPORT static void * -MHDS_handle_connection (void *data) +MHD_TLS_handle_connection (void *data) { struct MHD_Connection *con = data; @@ -489,7 +489,7 @@ MHD_accept_connection (struct MHD_Daemon *daemon) #if HTTPS_SUPPORT if (daemon->options & MHD_USE_SSL) res_thread_create = pthread_create (&connection->pid, NULL, - &MHDS_handle_connection, + &MHD_TLS_handle_connection, connection); else #endif @@ -767,11 +767,11 @@ MHD_select_thread (void *cls) * @return NULL on error, handle to daemon on success */ struct MHD_Daemon * -MHD_start_daemon (unsigned int options, - unsigned short port, - MHD_AcceptPolicyCallback apc, - void *apc_cls, - MHD_AccessHandlerCallback dh, void *dh_cls, ...) +MHD_start_daemon_va (unsigned int options, + unsigned short port, + MHD_AcceptPolicyCallback apc, + void *apc_cls, + MHD_AccessHandlerCallback dh, void *dh_cls, va_list ap) { const int on = 1; struct MHD_Daemon *retVal; @@ -783,7 +783,6 @@ MHD_start_daemon (unsigned int options, struct sockaddr_in6 servaddr6; const struct sockaddr *servaddr; socklen_t addrlen; - va_list ap; enum MHD_OPTION opt; if ((port == 0) || (dh == NULL)) @@ -879,7 +878,7 @@ MHD_start_daemon (unsigned int options, } #endif /* initializes the argument pointer variable */ - va_start (ap, dh_cls); + /* * loop through daemon options */ @@ -905,6 +904,10 @@ MHD_start_daemon (unsigned int options, retVal->per_ip_connection_limit = va_arg (ap, unsigned int); break; #if HTTPS_SUPPORT + case MHD_OPTION_PROTOCOL_VERSION: + _set_priority (&retVal->priority_cache->protocol, + va_arg (ap, const int *)); + break; case MHD_OPTION_HTTPS_KEY_PATH: retVal->https_key_path = va_arg (ap, const char *); break; @@ -925,13 +928,17 @@ MHD_start_daemon (unsigned int options, _set_priority (&retVal->priority_cache->cipher, va_arg (ap, const int *)); break; + case MHD_OPTION_MAC_ALGO: + _set_priority (&retVal->priority_cache->mac, + va_arg (ap, const int *)); + break; #endif default: #if HAVE_MESSAGES if (opt > MHD_HTTPS_OPTION_START && opt < MHD_HTTPS_OPTION_END) { fprintf (stderr, - "Error: HTTPS option given while compiling without HTTPS support\n"); + "Error: HTTPS option %d passed to non HTTPS daemon\n", opt); } else { @@ -942,18 +949,19 @@ MHD_start_daemon (unsigned int options, abort (); } } + #if HTTPS_SUPPORT /* initialize HTTPS daemon certificate aspects & send / recv functions */ - if (options & MHD_USE_SSL && MHD_NO == MHDS_init (retVal)) + if (options & MHD_USE_SSL && MHD_NO == MHD_TLS_init (retVal)) { #if HAVE_MESSAGES - MHD_DLOG (retVal, "Failed to initialize MHDS\n", STRERROR (errno)); + MHD_DLOG (retVal, "Failed to initialize HTTPS daemon\n"); #endif free (retVal); return NULL; } #endif - va_end (ap); + if (((0 != (options & MHD_USE_THREAD_PER_CONNECTION)) || (0 != (options & MHD_USE_SELECT_INTERNALLY))) @@ -972,6 +980,36 @@ MHD_start_daemon (unsigned int options, return retVal; } +struct MHD_Daemon * +MHD_start_daemon (unsigned int options, + unsigned short port, + MHD_AcceptPolicyCallback apc, + void *apc_cls, + MHD_AccessHandlerCallback dh, void *dh_cls, ...){ + + int ret; + va_list ap; + va_start (ap, dh_cls); + ret = MHD_start_daemon_va (options, + port, + apc, + apc_cls, + dh, dh_cls, ap); + va_end (ap); + return ret; +} + +/** + * Start a webserver on the given port. + * + * @param port port to bind to + * @param apc callback to call to check which clients + * will be allowed to connect + * @param apc_cls extra argument to apc + * @param dh default handler for all URIs + * @param dh_cls extra argument to dh + * @return NULL on error, handle to daemon on success + */ /** * Shutdown an http daemon. */ diff --git a/src/daemon/https/tls/gnutls_alert.c b/src/daemon/https/tls/gnutls_alert.c @@ -144,8 +144,8 @@ gnutls_alert_send (gnutls_session_t session, gnutls_alert_level_t level, * * Returns an alert depending on the error code returned by a gnutls * function. All alerts sent by this function should be considered fatal. - * The only exception is when err == GNUTLS_E_REHANDSHAKE, where a warning - * alert should be sent to the peer indicating that no renegotiation will + * The only exception is when err == GNUTLS_E_REHANDSHAKE, where a warning + * alert should be sent to the peer indicating that no renegotiation will * be performed. * * If there is no mapping to a valid alert the alert to indicate internal error diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h @@ -380,6 +380,15 @@ enum MHD_OPTION MHD_OPTION_HTTPS_MEM_CERT, /* + * SSL/TLS protocol version + * + * Memory pointer to a zero terminated int array representing the + * protocol versions to this server should support. Unsupported + * requests will be droped by the server. + */ + MHD_OPTION_PROTOCOL_VERSION, + + /* * Memory pointer to a zero terminated int array representing the * cipher priority order to which the HTTPS daemon should adhere. * "const int *" argument. @@ -703,6 +712,18 @@ typedef int * terminated with MHD_OPTION_END). * @return NULL on error, handle to daemon on success */ +struct MHD_Daemon * +MHD_start_daemon_va (unsigned int options, + unsigned short port, + MHD_AcceptPolicyCallback apc, + void *apc_cls, + MHD_AccessHandlerCallback dh, void *dh_cls, va_list ap); + + +/* + * Variadic version of MHD_start_daemon_va. This function will delegate calls + * to MHD_start_daemon_va() once argument list is analyzed. + */ struct MHD_Daemon *MHD_start_daemon (unsigned int flags, unsigned short port, MHD_AcceptPolicyCallback apc, diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am @@ -38,7 +38,6 @@ libcurl_version_check_a_CPPFLAGS = \ -I$(top_srcdir)/src/daemon/https \ $(LIBCURL_CPPFLAGS) - daemontest_get_SOURCES = \ daemontest_get.c daemontest_get_LDADD = \ diff --git a/src/testcurl/curl_version_check.c b/src/testcurl/curl_version_check.c @@ -89,7 +89,7 @@ curl_check_version (const char *req_version) fprintf (stderr, "curl version: %s\n", ver); #endif /* - * this call relies on the cURL string to be of the format : + * this call relies on the cURL string to be of the exact following format : * 'libcurl/7.16.4 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/0.6.5' OR * 'libcurl/7.18.2 GnuTLS/2.4.0 zlib/1.2.3.3 libidn/0.6.5' */ @@ -118,7 +118,7 @@ curl_check_version (const char *req_version) * TODO use curl version string to assert use of gnutls */ #if HTTPS_SUPPORT - ssl_ver = strchr (curl_ver, '\ ') + 1; + ssl_ver = strchr (curl_ver, ' ') + 1; if (strncmp ("GnuTLS", ssl_ver, strlen ("GNUtls")) == 0) { @@ -132,7 +132,7 @@ curl_check_version (const char *req_version) } else { - fprintf (stderr, "Error: unrecognized curl ssl library\n", req_ssl_ver); + fprintf (stderr, "Error: unrecognized curl ssl library\n"); return -1; } diff --git a/src/testcurl/https/Makefile.am b/src/testcurl/https/Makefile.am @@ -12,7 +12,7 @@ $(LIBCURL_CPPFLAGS) check_PROGRAMS = \ tls_session_time_out_test \ tls_cipher_change_test \ -mhds_get_test \ +tls_daemon_options_test \ tls_alert_test \ tls_authentication_test \ mhds_multi_daemon_test \ @@ -20,6 +20,13 @@ mhds_session_info_test TESTS = $(check_PROGRAMS) +tls_daemon_options_test_SOURCES = \ + tls_daemon_options_test.c +tls_daemon_options_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + tls_session_time_out_test_SOURCES = \ tls_session_time_out_test.c tls_session_time_out_test_LDADD = \ @@ -45,13 +52,6 @@ tls_authentication_test_LDADD = \ $(top_builddir)/src/daemon/libmicrohttpd.la \ @LIBCURL@ -mhds_get_test_SOURCES = \ - mhds_get_test.c -mhds_get_test_LDADD = \ - $(top_builddir)/src/testcurl/libcurl_version_check.a \ - $(top_builddir)/src/daemon/libmicrohttpd.la \ - @LIBCURL@ - mhds_session_info_test_SOURCES = \ mhds_session_info_test.c mhds_session_info_test_LDADD = \ diff --git a/src/testcurl/https/mhds_get_test.c b/src/testcurl/https/mhds_get_test.c @@ -1,457 +0,0 @@ -/* - This file is part of libmicrohttpd - (C) 2007 Christian Grothoff - - 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., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - */ - -/** - * @file mhds_get_test.c - * @brief Testcase for libmicrohttpd HTTPS GET operations - * @author Sagie Amir - */ - -#include "platform.h" -#include "microhttpd.h" - -#include <sys/stat.h> - -#include "gnutls.h" -#include <curl/curl.h> - -#define PAGE_NOT_FOUND "<html><head><title>File not found</title></head><body>File not found</body></html>" - -#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" - -#include "tls_test_keys.h" - -const char *test_file_name = "https_test_file"; -const char test_file_data[] = "Hello World\n"; - -int curl_check_version (const char *req_version, ...); - -struct CBC -{ - char *buf; - size_t pos; - size_t size; -}; - -static size_t -copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) -{ - struct CBC *cbc = ctx; - - if (cbc->pos + size * nmemb > cbc->size) - return 0; /* overflow */ - memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); - cbc->pos += size * nmemb; - return size * nmemb; -} - -static int -file_reader (void *cls, size_t pos, char *buf, int max) -{ - FILE *file = cls; - fseek (file, pos, SEEK_SET); - return fread (buf, 1, max, file); -} - -/* HTTP access handler call back */ -static int -http_ahc (void *cls, struct MHD_Connection *connection, - const char *url, const char *method, const char *upload_data, - const char *version, unsigned int *upload_data_size, void **ptr) -{ - static int aptr; - struct MHD_Response *response; - int ret; - FILE *file; - struct stat buf; - - if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) - return MHD_NO; /* unexpected method */ - if (&aptr != *ptr) - { - /* do never respond on first call */ - *ptr = &aptr; - return MHD_YES; - } - *ptr = NULL; /* reset when done */ - - file = fopen (url, "r"); - if (file == NULL) - { - response = MHD_create_response_from_data (strlen (PAGE_NOT_FOUND), - (void *) PAGE_NOT_FOUND, - MHD_NO, MHD_NO); - ret = MHD_queue_response (connection, MHD_HTTP_NOT_FOUND, response); - MHD_destroy_response (response); - } - else - { - stat (url, &buf); - response = MHD_create_response_from_callback (buf.st_size, 32 * 1024, /* 32k PAGE_NOT_FOUND size */ - &file_reader, file, - (MHD_ContentReaderFreeCallback) - & fclose); - ret = MHD_queue_response (connection, MHD_HTTP_OK, response); - MHD_destroy_response (response); - } - return ret; -} - -/* - * test HTTPS transfer - * @param test_fd: file to attempt transfering - */ -static int -test_daemon_get (FILE * test_fd, char *cipher_suite, int proto_version) -{ - CURL *c; - struct CBC cbc; - CURLcode errornum; - char *doc_path; - char url[255]; - struct stat statb; - - stat (test_file_name, &statb); - - int len = statb.st_size; - - /* used to memcmp local copy & deamon supplied copy */ - unsigned char *mem_test_file_local; - - /* setup test file path, url */ - doc_path = get_current_dir_name (); - - if (NULL == (mem_test_file_local = malloc (len))) - { - fclose (test_fd); - fprintf (stderr, MHD_E_MEM); - return -1; - } - - fseek (test_fd, 0, SEEK_SET); - if (fread (mem_test_file_local, sizeof (char), len, test_fd) != len) - { - fclose (test_fd); - fprintf (stderr, "Error: failed to read test file. %s\n", - strerror (errno)); - return -1; - } - - if (NULL == (cbc.buf = malloc (sizeof (char) * len))) - { - fclose (test_fd); - fprintf (stderr, MHD_E_MEM); - return -1; - } - cbc.size = len; - cbc.pos = 0; - - /* construct url - this might use doc_path */ - sprintf (url, "%s%s/%s", "https://localhost:42433", - doc_path, test_file_name); - - c = curl_easy_init (); -#ifdef DEBUG - curl_easy_setopt (c, CURLOPT_VERBOSE, 1); -#endif - curl_easy_setopt (c, CURLOPT_URL, url); - curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); - curl_easy_setopt (c, CURLOPT_TIMEOUT, 2L); - curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 2L); - curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); - curl_easy_setopt (c, CURLOPT_FILE, &cbc); - - /* TLS options */ - curl_easy_setopt (c, CURLOPT_SSLVERSION, proto_version); - curl_easy_setopt (c, CURLOPT_SSL_CIPHER_LIST, cipher_suite); - - /* currently skip any peer authentication */ - curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0); - curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0); - - curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); - - /* NOTE: use of CONNECTTIMEOUT without also - setting NOSIGNAL results in really weird - crashes on my system! */ - curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); - 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); - - if (memcmp (cbc.buf, mem_test_file_local, len) != 0) - { - fprintf (stderr, "Error: local file & received file differ.\n"); - free (cbc.buf); - free (mem_test_file_local); - return -1; - } - - free (mem_test_file_local); - free (cbc.buf); - free (doc_path); - return 0; -} - -/* perform a HTTP GET request via SSL/TLS */ -int -test_secure_get (FILE * test_fd, char *cipher_suite, int proto_version) -{ - int ret; - struct MHD_Daemon *d; - d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | - MHD_USE_DEBUG, 42433, - NULL, NULL, &http_ahc, NULL, - MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, - MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, - MHD_OPTION_END); - - if (d == NULL) - { - fprintf (stderr, MHD_E_SERVER_INIT); - return -1; - } - - ret = test_daemon_get (test_fd, cipher_suite, proto_version); - MHD_stop_daemon (d); - return ret; -} - -/* test loading of key & certificate files */ -int -test_file_certificates (FILE * test_fd, char *cipher_suite, int proto_version) -{ - int ret; - struct MHD_Daemon *d; - FILE *cert_fd, *key_fd; - char cert_path[255], key_path[255], *cur_dir; - - cur_dir = get_current_dir_name (); - - sprintf (cert_path, "%s/%s", cur_dir, "cert.pem"); - sprintf (key_path, "%s/%s", cur_dir, "key.pem"); - - if (NULL == (key_fd = fopen (key_path, "w+"))) - { - fprintf (stderr, MHD_E_KEY_FILE_CREAT); - return -1; - } - if (NULL == (cert_fd = fopen (cert_path, "w+"))) - { - fprintf (stderr, MHD_E_CERT_FILE_CREAT); - return -1; - } - - fwrite (srv_key_pem, strlen (srv_key_pem), sizeof (char), key_fd); - fwrite (srv_self_signed_cert_pem, strlen (srv_self_signed_cert_pem), - sizeof (char), cert_fd); - fclose (key_fd); - fclose (cert_fd); - - d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | - MHD_USE_DEBUG, 42433, - NULL, NULL, &http_ahc, NULL, - MHD_OPTION_HTTPS_KEY_PATH, key_path, - MHD_OPTION_HTTPS_CERT_PATH, cert_path, - MHD_OPTION_END); - - if (d == NULL) - { - fprintf (stderr, MHD_E_SERVER_INIT); - return -1; - } - - ret = test_daemon_get (test_fd, cipher_suite, proto_version); - MHD_stop_daemon (d); - - free (cur_dir); - remove (cert_path); - remove (key_path); - return ret; -} - -int -test_cipher_option (FILE * test_fd, char *cipher_suite, int proto_version) -{ - - int ret; - int ciper[] = { MHD_GNUTLS_CIPHER_3DES_CBC, 0 }; - struct MHD_Daemon *d; - d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | - MHD_USE_DEBUG, 42433, - NULL, NULL, &http_ahc, NULL, - MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, - MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, - MHD_OPTION_CIPHER_ALGORITHM, ciper, MHD_OPTION_END); - - if (d == NULL) - { - fprintf (stderr, MHD_E_SERVER_INIT); - return -1; - } - - ret = test_daemon_get (test_fd, cipher_suite, proto_version); - - MHD_stop_daemon (d); - return ret; -} - -int -test_kx_option (FILE * test_fd, char *cipher_suite, int proto_version) -{ - - int ret; - int ciper[] = { MHD_GNUTLS_CIPHER_3DES_CBC, 0 }; - int kx[] = { MHD_GNUTLS_KX_DHE_RSA, 0 }; - struct MHD_Daemon *d; - - d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | - MHD_USE_DEBUG, 42433, - NULL, NULL, &http_ahc, NULL, - MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, - MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, - MHD_OPTION_KX_PRIORITY, kx, - MHD_OPTION_CIPHER_ALGORITHM, ciper, MHD_OPTION_END); - - if (d == NULL) - { - fprintf (stderr, MHD_E_SERVER_INIT); - return -1; - } - - ret = test_daemon_get (test_fd, cipher_suite, proto_version); - - MHD_stop_daemon (d); - return ret; -} - -int -test_mac_option (FILE * test_fd, char *cipher_suite, int proto_version) -{ - - int ret; - int mac[] = { MHD_GNUTLS_MAC_SHA1, 0 }; - struct MHD_Daemon *d; - - d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | - MHD_USE_DEBUG, 42433, - NULL, NULL, &http_ahc, NULL, - MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, - MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, - MHD_OPTION_MAC_ALGO, mac, MHD_OPTION_END); - - if (d == NULL) - { - fprintf (stderr, MHD_E_SERVER_INIT); - return -1; - } - - ret = test_daemon_get (test_fd, cipher_suite, proto_version); - - MHD_stop_daemon (d); - return ret; -} - -/* setup a temporary transfer test file */ -FILE * -setupTestFile () -{ - FILE *test_fd; - - if (NULL == (test_fd = fopen (test_file_name, "w+"))) - { - fprintf (stderr, "Error: failed to open `%s': %s\n", - test_file_name, strerror (errno)); - return NULL; - } - if (fwrite (test_file_data, sizeof (char), strlen (test_file_data), test_fd) - != strlen (test_file_data)) - { - fprintf (stderr, "Error: failed to write `%s. %s'\n", - test_file_name, strerror (errno)); - return NULL; - } - if (fflush (test_fd)) - { - fprintf (stderr, "Error: failed to flush test file stream. %s\n", - strerror (errno)); - return NULL; - } - - return test_fd; -} - -int -main (int argc, char *const *argv) -{ - FILE *test_fd; - unsigned int errorCount = 0; - - /* gnutls_global_set_log_level(11); */ - - if (curl_check_version (MHD_REQ_CURL_VERSION)) - { - return -1; - } - - if ((test_fd = setupTestFile ()) == NULL) - { - fprintf (stderr, MHD_E_TEST_FILE_CREAT); - return -1; - } - - if (0 != curl_global_init (CURL_GLOBAL_ALL)) - { - fprintf (stderr, "Error: %s\n", strerror (errno)); - return -1; - } - - errorCount += - test_secure_get (test_fd, "AES256-SHA", CURL_SSLVERSION_TLSv1); - errorCount += - test_secure_get (test_fd, "AES256-SHA", CURL_SSLVERSION_SSLv3); - errorCount += - test_file_certificates (test_fd, "AES256-SHA", CURL_SSLVERSION_SSLv3); - /* TODO resolve cipher setting issue when compiling against GNU TLS */ -// errorCount += -// test_cipher_option (test_fd, "DES-CBC3-SHA", CURL_SSLVERSION_TLSv1); -// errorCount += -// test_kx_option (test_fd, "EDH-RSA-DES-CBC3-SHA", CURL_SSLVERSION_TLSv1); - - if (errorCount != 0) - fprintf (stderr, "Failed test: %s.\n", argv[0]); - - curl_global_cleanup (); - fclose (test_fd); - - remove (test_file_name); - - return errorCount != 0; -} diff --git a/src/testcurl/https/tls_daemon_options_test.c b/src/testcurl/https/tls_daemon_options_test.c @@ -0,0 +1,461 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file mhds_get_test.c + * @brief Testcase for libmicrohttpd HTTPS GET operations + * @author Sagie Amir + */ + +#include "platform.h" +#include "microhttpd.h" + +#include <sys/stat.h> + +#include "gnutls.h" +#include <curl/curl.h> + +#define PAGE_NOT_FOUND "<html><head><title>File not found</title></head><body>File not found</body></html>" + +#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" + +#include "tls_test_keys.h" + +const char *test_file_name = "https_test_file"; +const char test_file_data[] = "Hello World\n"; + +int curl_check_version (const char *req_version, ...); + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +static int +file_reader (void *cls, size_t pos, char *buf, int max) +{ + FILE *file = cls; + fseek (file, pos, SEEK_SET); + return fread (buf, 1, max, file); +} + +/* HTTP access handler call back */ +static int +http_ahc (void *cls, struct MHD_Connection *connection, + const char *url, const char *method, const char *upload_data, + const char *version, unsigned int *upload_data_size, void **ptr) +{ + static int aptr; + struct MHD_Response *response; + int ret; + FILE *file; + struct stat buf; + + if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) + return MHD_NO; /* unexpected method */ + if (&aptr != *ptr) + { + /* do never respond on first call */ + *ptr = &aptr; + return MHD_YES; + } + *ptr = NULL; /* reset when done */ + + file = fopen (url, "r"); + if (file == NULL) + { + response = MHD_create_response_from_data (strlen (PAGE_NOT_FOUND), + (void *) PAGE_NOT_FOUND, + MHD_NO, MHD_NO); + ret = MHD_queue_response (connection, MHD_HTTP_NOT_FOUND, response); + MHD_destroy_response (response); + } + else + { + stat (url, &buf); + response = MHD_create_response_from_callback (buf.st_size, 32 * 1024, /* 32k PAGE_NOT_FOUND size */ + &file_reader, file, + (MHD_ContentReaderFreeCallback) + & fclose); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + } + return ret; +} + +/* + * test HTTPS transfer + * @param test_fd: file to attempt transfering + */ +static int +test_https_transfer (FILE * test_fd, char * cipher_suite, int proto_version) +{ + CURL *c; + CURLcode errornum; + struct CBC cbc; + char *doc_path; + char url[255]; + struct stat statb; + + stat (test_file_name, &statb); + + int len = statb.st_size; + + /* used to memcmp local copy & deamon supplied copy */ + unsigned char *mem_test_file_local; + + /* setup test file path, url */ + doc_path = get_current_dir_name (); + + if (NULL == (mem_test_file_local = malloc (len))) + { + fclose (test_fd); + fprintf (stderr, MHD_E_MEM); + return -1; + } + + fseek (test_fd, 0, SEEK_SET); + if (fread (mem_test_file_local, sizeof (char), len, test_fd) != len) + { + fclose (test_fd); + fprintf (stderr, "Error: failed to read test file. %s\n", + strerror (errno)); + return -1; + } + + if (NULL == (cbc.buf = malloc (sizeof (char) * len))) + { + fclose (test_fd); + fprintf (stderr, MHD_E_MEM); + return -1; + } + cbc.size = len; + cbc.pos = 0; + + /* construct url - this might use doc_path */ + sprintf (url, "%s%s/%s", "https://localhost:42433", + doc_path, test_file_name); + + c = curl_easy_init (); +#ifdef DEBUG + curl_easy_setopt (c, CURLOPT_VERBOSE, 1); +#endif + curl_easy_setopt (c, CURLOPT_URL, url); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 5L); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 5L); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); + curl_easy_setopt (c, CURLOPT_FILE, &cbc); + + /* TLS options */ + curl_easy_setopt (c, CURLOPT_SSLVERSION, proto_version); + curl_easy_setopt (c, CURLOPT_SSL_CIPHER_LIST, cipher_suite); + + /* currently skip any peer authentication */ + curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0); + + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + + /* NOTE: use of CONNECTTIMEOUT without also + setting NOSIGNAL results in really weird + crashes on my system! */ + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + 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); + + if (memcmp (cbc.buf, mem_test_file_local, len) != 0) + { + fprintf (stderr, "Error: local file & received file differ.\n"); + free (cbc.buf); + free (mem_test_file_local); + return -1; + } + + free (mem_test_file_local); + free (cbc.buf); + free (doc_path); + return 0; +} + +FILE * +setupTestFile () +{ + FILE *test_fd; + + if (NULL == (test_fd = fopen (test_file_name, "w+"))) + { + fprintf (stderr, "Error: failed to open `%s': %s\n", + test_file_name, strerror (errno)); + return NULL; + } + if (fwrite (test_file_data, sizeof (char), strlen (test_file_data), test_fd) + != strlen (test_file_data)) + { + fprintf (stderr, "Error: failed to write `%s. %s'\n", + test_file_name, strerror (errno)); + return NULL; + } + if (fflush (test_fd)) + { + fprintf (stderr, "Error: failed to flush test file stream. %s\n", + strerror (errno)); + return NULL; + } + + return test_fd; +} + +static int +setup (struct MHD_Daemon **d, enum MHD_OPTION option, void * value ) +{ + *d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | + MHD_USE_DEBUG, 42433, + NULL, NULL, &http_ahc, NULL, + MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, + MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, + option, value, MHD_OPTION_END); + + if (*d == NULL) + { + fprintf (stderr, MHD_E_SERVER_INIT); + return -1; + } + + return 0; +} + +static void +teardown (struct MHD_Daemon *d) +{ + MHD_stop_daemon (d); +} + +int +test_wrap (int + (*test) (FILE * test_fd, char *cipher_suite, int proto_version), + FILE * test_fd, char *cipher_suite, int proto_version, + enum MHD_OPTION option, void * value) +{ + int ret; + struct MHD_Daemon *d; + + if (setup (&d, option, value) != 0) + return -1; + ret = test (test_fd, cipher_suite, proto_version); + teardown (d); + return ret; +} + +/* perform a HTTP GET request via SSL/TLS */ + +/* test loading of key & certificate files */ +int +test_file_certificates (FILE * test_fd, char *cipher_suite, int proto_version) +{ + int ret; + struct MHD_Daemon *d; + FILE *cert_fd, *key_fd; + char cert_path[255], key_path[255], *cur_dir; + + cur_dir = get_current_dir_name (); + + sprintf (cert_path, "%s/%s", cur_dir, "cert.pem"); + sprintf (key_path, "%s/%s", cur_dir, "key.pem"); + + if (NULL == (key_fd = fopen (key_path, "w+"))) + { + fprintf (stderr, MHD_E_KEY_FILE_CREAT); + return -1; + } + if (NULL == (cert_fd = fopen (cert_path, "w+"))) + { + fprintf (stderr, MHD_E_CERT_FILE_CREAT); + return -1; + } + + fwrite (srv_key_pem, strlen (srv_key_pem), sizeof (char), key_fd); + fwrite (srv_self_signed_cert_pem, strlen (srv_self_signed_cert_pem), + sizeof (char), cert_fd); + fclose (key_fd); + fclose (cert_fd); + + if (d == NULL) + { + fprintf (stderr, MHD_E_SERVER_INIT); + return -1; + } + + ret = test_https_transfer (test_fd, cipher_suite, proto_version); + + free (cur_dir); + remove (cert_path); + remove (key_path); + return ret; +} + +int +test_protocol_version (FILE * test_fd, char *cipher_suite, + int curl_proto_version) +{ + CURL *c; + CURLcode errornum; + + c = curl_easy_init (); +#ifdef DEBUG + curl_easy_setopt (c, CURLOPT_VERBOSE, 1); +#endif + curl_easy_setopt (c, CURLOPT_URL, "https://localhost:42433/"); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 5L); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 5L); + + /* TLS options */ + curl_easy_setopt (c, CURLOPT_SSLVERSION, curl_proto_version); + curl_easy_setopt (c, CURLOPT_SSL_CIPHER_LIST, cipher_suite); + + curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + + /* NOTE: use of CONNECTTIMEOUT without also + setting NOSIGNAL results in really weird + crashes on my system! */ + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + /* assert daemon rejected request */ + 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 -1; + } + + return 0; +} + +/* setup a temporary transfer test file */ +int +main (int argc, char *const *argv) +{ + FILE *test_fd; + unsigned int errorCount = 0; + + gnutls_global_set_log_level(11); + + if (curl_check_version (MHD_REQ_CURL_VERSION)) + { + return -1; + } + + if ((test_fd = setupTestFile ()) == NULL) + { + fprintf (stderr, MHD_E_TEST_FILE_CREAT); + return -1; + } + + if (0 != curl_global_init (CURL_GLOBAL_ALL)) + { + fprintf (stderr, "Error: %s\n", strerror (errno)); + return -1; + } + + int mac[] = {MHD_GNUTLS_MAC_SHA1, 0}; + int p [] = {MHD_GNUTLS_SSL3, 0}; + int cipher[] = { MHD_GNUTLS_CIPHER_3DES_CBC, 0 }; + int kx[] = { MHD_GNUTLS_KX_DHE_RSA, 0 }; + + +// errorCount += +// test_wrap (&test_https_transfer, test_fd, "AES256-SHA", +// CURL_SSLVERSION_TLSv1, MHD_OPTION_END, 0); +// errorCount += +// test_wrap (&test_file_certificates, test_fd, "AES256-SHA", +// CURL_SSLVERSION_TLSv1, MHD_OPTION_END, 0); +// +// errorCount += +// test_wrap (&test_protocol_version, test_fd, "AES256-SHA", +// CURL_SSLVERSION_TLSv1, MHD_OPTION_PROTOCOL_VERSION, p); +// +// errorCount += +// test_wrap (&test_https_transfer, test_fd, "DES-CBC3-SHA", +// CURL_SSLVERSION_TLSv1, MHD_OPTION_CIPHER_ALGORITHM, cipher); + + errorCount += + test_wrap (&test_https_transfer, test_fd, "AES256-SHA", + CURL_SSLVERSION_TLSv1, MHD_OPTION_MAC_ALGO, mac); + + // errorCount += + // test_wrap (&test_https_transfer, test_fd, "EDH-RSA-DES-CBC3-SHA", + // CURL_SSLVERSION_TLSv1, MHD_OPTION_KX_PRIORITY, kx); + + /*gnutls_mac_algorithm_t mac[] = { + {MHD_GNUTLS_MAC_MD5, 0}, 0}; + gnutls_mac_algorithm_t * cur_mac; + + for ( cur_mac = &mac[0]; (*cur_mac) != 0; cur_mac++ ){ + option[0] = MHD_GNUTLS_MAC_SHA1; + errorCount += + test_wrap (&test_https_transfer, test_fd, "AES256-SHA", + CURL_SSLVERSION_TLSv1, MHD_OPTION_MAC_ALGO, option); + }*/ + + + + if (errorCount != 0) + fprintf (stderr, "Failed test: %s.\n", argv[0]); + else + { + fprintf (stderr, "ok\n"); + } + + curl_global_cleanup (); + fclose (test_fd); + + remove (test_file_name); + + return errorCount != 0; +} diff --git a/src/testcurl/https/tls_session_time_out_test.c b/src/testcurl/https/tls_session_time_out_test.c @@ -128,7 +128,6 @@ test_tls_session_time_out (gnutls_session_t session) sleep (TIME_OUT + 1); - /* check that server has closed the connection */ /* TODO better RST trigger */ if (send (sd, "", 1, 0) == 0)