libmicrohttpd

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

commit a0026eb09eb0b6687ca55a6bf6a019b54f55d330
parent d7f21bfb62c60566d20b35ea555bf7c6803d9b7b
Author: lv-426 <oxcafebaby@yahoo.com>
Date:   Tue, 29 Jul 2008 03:13:11 +0000

added debug state dictionary
added secure connection request termination codes
secure connections start at MHD_TLS_CONNECTION_INIT

Diffstat:
Msrc/daemon/connection.c | 20+++++++++++---------
Msrc/daemon/connection_https.c | 180++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/daemon/daemon.c | 5++++-
Msrc/daemon/https/tls/gnutls_handshake.c | 7+++----
Msrc/daemon/internal.c | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/daemon/internal.h | 26++++++++++++++++++++++++--
Msrc/include/microhttpd.h | 16+++++++++++++++-
Msrc/testcurl/curl_version_check.c | 29+++++++++++++++--------------
Msrc/testcurl/https/Makefile.am | 17+++++++++++++++--
Msrc/testcurl/https/mhds_get_test.c | 5++---
Msrc/testcurl/https/mhds_multi_daemon_test.c | 5+++--
Msrc/testcurl/https/mhds_session_info_test.c | 4++--
Msrc/testcurl/https/tls_alert_test.c | 20++++++++++++--------
Msrc/testcurl/https/tls_authentication_test.c | 6+++---
Asrc/testcurl/https/tls_cipher_change_test.c | 199+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/testcurl/https/tls_session_time_out_test.c | 182+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16 files changed, 664 insertions(+), 116 deletions(-)

diff --git a/src/daemon/connection.c b/src/daemon/connection.c @@ -113,11 +113,6 @@ #define DEBUG_SEND_DATA MHD_NO /** - * Should all state transitions be printed to stderr? - */ -#define DEBUG_STATES MHD_NO - -/** * Get all of the headers from the request. * * @param iterator callback to call on each header; @@ -649,13 +644,17 @@ MHD_connection_get_fdset (struct MHD_Connection *connection, while (1) { #if DEBUG_STATES - fprintf (stderr, "`%s' in state %u\n", __FUNCTION__, connection->state); + MHD_DLOG (connection->daemon, "%s: state: %s\n", + __FUNCTION__, MHD_state_to_string (connection->state)); #endif switch (connection->state) { case MHD_CONNECTION_INIT: case MHD_CONNECTION_URL_RECEIVED: case MHD_CONNECTION_HEADER_PART_RECEIVED: +#if HTTPS_SUPPORT + case MHD_TLS_CONNECTION_INIT: +#endif /* while reading headers, we always grow the read buffer if needed, no size-check required */ if ((connection->read_closed) && @@ -1465,7 +1464,8 @@ MHD_connection_handle_read (struct MHD_Connection *connection) while (1) { #if DEBUG_STATES - fprintf (stderr, "`%s' in state %u\n", __FUNCTION__, connection->state); + MHD_DLOG (connection->daemon, "%s: state: %s\n", + __FUNCTION__, MHD_state_to_string (connection->state)); #endif switch (connection->state) { @@ -1530,7 +1530,8 @@ MHD_connection_handle_write (struct MHD_Connection *connection) while (1) { #if DEBUG_STATES - fprintf (stderr, "`%s' in state %u\n", __FUNCTION__, connection->state); + MHD_DLOG (connection->daemon, "%s: state: %s\n", + __FUNCTION__, MHD_state_to_string (connection->state)); #endif switch (connection->state) { @@ -1694,7 +1695,8 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) while (1) { #if DEBUG_STATES - fprintf (stderr, "`%s' in state %u\n", __FUNCTION__, connection->state); + MHD_DLOG (connection->daemon, "%s: state: %s\n", + __FUNCTION__, MHD_state_to_string (connection->state)); #endif switch (connection->state) { diff --git a/src/daemon/connection_https.c b/src/daemon/connection_https.c @@ -45,37 +45,50 @@ int MHD_connection_handle_read (struct MHD_Connection *connection); int MHD_connection_handle_write (struct MHD_Connection *connection); int MHD_connection_handle_idle (struct MHD_Connection *connection); +/* + * This function is called once a secure connection has been marked + * for closure. + * + * @param : + * @return: + */ static void MHD_tls_connection_close (struct MHD_Connection *connection) { gnutls_bye (connection->tls_session, GNUTLS_SHUT_WR); connection->tls_session->internals.read_eof = 1; - connection->socket_fd = -1; SHUTDOWN (connection->socket_fd, SHUT_RDWR); CLOSE (connection->socket_fd); + connection->socket_fd = -1; + connection->state = MHD_CONNECTION_CLOSED; + + /* call notify_completed callback if one was registered */ if (connection->daemon->notify_completed != NULL) connection->daemon->notify_completed (connection->daemon-> notify_completed_cls, connection, &connection->client_context, - MHD_REQUEST_TERMINATED_COMPLETED_OK); + MHD_TLS_REQUEST_TERMINATED_COMPLETED_OK); } +/* TODO - we might want to send raw RST packets here... */ static void -MHD_tls_connection_close_err (struct MHD_Connection *connection) +MHD_tls_connection_close_err (struct MHD_Connection *connection, + enum MHD_RequestTerminationCode + termination_code) { connection->tls_session->internals.read_eof = 1; - connection->socket_fd = -1; - SHUTDOWN (connection->socket_fd, SHUT_RDWR); CLOSE (connection->socket_fd); + connection->socket_fd = -1; + connection->state = MHD_CONNECTION_CLOSED; if (connection->daemon->notify_completed != NULL) connection->daemon->notify_completed (connection->daemon-> notify_completed_cls, connection, &connection->client_context, - MHD_REQUEST_TERMINATED_WITH_ERROR); + termination_code); } union MHD_SessionInfo @@ -110,6 +123,7 @@ MHD_get_session_info (struct MHD_Connection *con, enum MHD_InfoType infoType) return (union MHD_SessionInfo) con->tls_session->security_parameters. cert_type; }; + return (union MHD_SessionInfo) 0; } static ssize_t @@ -138,34 +152,33 @@ MHD_tls_connection_handle_idle (struct MHD_Connection *connection) { unsigned int timeout; - while (1) - { -#if HAVE_MESSAGES - MHD_DLOG (connection->daemon, "MHDS idle: %d, l: %d, f: %s\n", - connection->state, __LINE__, __FUNCTION__); +#if DEBUG_STATES + MHD_DLOG (connection->daemon, "%s: state: %s\n", + __FUNCTION__, MHD_state_to_string (connection->state)); #endif - switch (connection->state) - { - case MHD_CONNECTION_CLOSED: - MHD_tls_connection_close (connection); - return MHD_NO; - case MHD_TLS_HANDSHAKE_FAILED: - MHD_tls_connection_close (connection); - return MHD_NO; - /* some http state */ - default: - return MHD_connection_handle_idle (connection); - } - break; - } timeout = connection->daemon->connection_timeout; - if ((connection->socket_fd != -1) && (timeout != 0) && (time (NULL) - timeout > connection->last_activity)) { + MHD_tls_connection_close_err (connection, + MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); + return MHD_NO; + } + + switch (connection->state) + { + /* close connection if necessary */ + case MHD_CONNECTION_CLOSED: MHD_tls_connection_close (connection); return MHD_NO; + case MHD_TLS_HANDSHAKE_FAILED: + MHD_tls_connection_close_err (connection, + MHD_TLS_REQUEST_TERMINATED_WITH_ERROR); + return MHD_NO; + /* some HTTP state */ + default: + return MHD_connection_handle_idle (connection); } return MHD_YES; } @@ -173,9 +186,17 @@ MHD_tls_connection_handle_idle (struct MHD_Connection *connection) /** * This function handles a particular SSL/TLS connection when * it has been determined that there is data to be read off a - * socket. All application_data is forwarded to - * MHD_connection_handle_read(). + * socket. Message processing is done by message type which is + * determined by peeking into the first message type byte of the + * stream. + * + * Error message handling : all fatal level messages cause the + * connection to be terminated. + * + * Application data is forwarded to the underlying daemon for + * processing. * + * @param connection : the source connection * @return MHD_YES if we should continue to process the * connection (not dead yet), MHD_NO if it died */ @@ -186,13 +207,15 @@ MHD_tls_connection_handle_read (struct MHD_Connection *connection) unsigned char msg_type; connection->last_activity = time (NULL); - if (connection->state == MHD_CONNECTION_CLOSED) - return MHD_NO; + if (connection->state == MHD_CONNECTION_CLOSED || + connection->state == MHD_TLS_HANDSHAKE_FAILED) + return MHD_NO; -#if HAVE_MESSAGES - MHD_DLOG (connection->daemon, "MHD read: %d, l: %d, f: %s\n", - connection->state, __LINE__, __FUNCTION__); +#if DEBUG_STATES + MHD_DLOG (connection->daemon, "%s: state: %s\n", + __FUNCTION__, MHD_state_to_string (connection->state)); #endif + /* discover content type */ if (recv (connection->socket_fd, &msg_type, 1, MSG_PEEK) == -1) { @@ -204,9 +227,48 @@ MHD_tls_connection_handle_read (struct MHD_Connection *connection) switch (msg_type) { + /* check for handshake messages first */ + case GNUTLS_HANDSHAKE: + /* negotiate handshake only while in INIT & HELLO_REQUEST states */ + if (connection->state == MHD_TLS_CONNECTION_INIT || + connection->state == MHD_TLS_HELLO_REQUEST) + { + ret = gnutls_handshake (connection->tls_session); + if (ret == 0) + { + /* set connection state to enable HTTP processing */ + connection->state = MHD_CONNECTION_INIT; + } + /* set connection as closed */ + else + { +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Error: Handshake has failed (%d)\n", ret); +#endif + connection->state = MHD_TLS_HANDSHAKE_FAILED; + return MHD_NO; + } + break; + } + /* a handshake message has been received out of bound */ + else + { +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Error: received handshake message out of context\n"); +#endif + MHD_tls_connection_close_err (connection, + MHD_TLS_REQUEST_TERMINATED_WITH_ERROR); + return MHD_NO; + } + + /* ignore any out of bound change chiper spec messages */ case GNUTLS_CHANGE_CIPHER_SPEC: + MHD_tls_connection_close_err (connection, + MHD_TLS_REQUEST_TERMINATED_WITH_ERROR); + return MHD_NO; - break; case GNUTLS_ALERT: /* * this call of _gnutls_recv_int expects 0 bytes read. @@ -219,7 +281,7 @@ MHD_tls_connection_handle_read (struct MHD_Connection *connection) if (connection->tls_session->internals.last_alert == GNUTLS_A_CLOSE_NOTIFY) { - MHD_tls_connection_close (connection); + connection->state = MHD_CONNECTION_CLOSED; return MHD_YES; } /* non FATAL or WARNING */ @@ -238,7 +300,8 @@ MHD_tls_connection_handle_read (struct MHD_Connection *connection) else if (connection->tls_session->internals.last_alert_level == GNUTLS_AL_FATAL) { - MHD_tls_connection_close_err (connection); + MHD_tls_connection_close_err (connection, + MHD_TLS_REQUEST_TERMINATED_WITH_FATAL_ALERT); return MHD_NO; } /* this should never execut */ @@ -257,25 +320,6 @@ MHD_tls_connection_handle_read (struct MHD_Connection *connection) case GNUTLS_APPLICATION_DATA: return MHD_connection_handle_read (connection); - case GNUTLS_HANDSHAKE: - ret = gnutls_handshake (connection->tls_session); - if (ret == 0) - { - connection->state = MHD_CONNECTION_INIT; - // connection->state = MHD_CONNECTION_INIT; - } - /* set connection as closed */ - else - { -#if HAVE_MESSAGES - MHD_DLOG (connection->daemon, - "Error: Handshake has failed (%d)\n", ret); -#endif - connection->state = MHD_TLS_HANDSHAKE_FAILED; - MHD_tls_connection_close (connection); - return MHD_NO; - } - break; case GNUTLS_INNER_APPLICATION: break; default: @@ -292,34 +336,40 @@ MHD_tls_connection_handle_read (struct MHD_Connection *connection) /** * This function was created to handle writes to sockets when it has - * been determined that the socket can be written to. + * been determined that the socket can be written to. This function + * will forward all write requests to the underlying daemon unless + * the connection has been marked for closing. * - * @return MHD_YES if we should continue to process the - * connection (not dead yet), MHD_NO if it died + * @return MHD_connection_handle_write() if we should continue to + * process the connection (not dead yet), MHD_NO if it died */ int MHD_tls_connection_handle_write (struct MHD_Connection *connection) { connection->last_activity = time (NULL); -#if HAVE_MESSAGES - MHD_DLOG (connection->daemon, "MHD write: %d. f: %s, l: %d\n", - connection->state, __FUNCTION__, __LINE__); +#if DEBUG_STATES + MHD_DLOG (connection->daemon, "%s: state: %s\n", + __FUNCTION__, MHD_state_to_string (connection->state)); #endif + switch (connection->state) { case MHD_CONNECTION_CLOSED: - MHD_tls_connection_close (connection); - return MHD_NO; case MHD_TLS_HANDSHAKE_FAILED: - MHD_tls_connection_close (connection); return MHD_NO; - /* some HTTP state */ + /* some HTTP connection state */ default: return MHD_connection_handle_write (connection); } + return MHD_NO; } +/* + * set connection callback function to be used through out + * the processing of this secure connection. + * + */ void MHD_set_https_calbacks (struct MHD_Connection *connection) { diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c @@ -312,6 +312,9 @@ MHDS_handle_connection (void *data) if (con == NULL) abort (); + /* initialize connection state */ + con->state = MHD_TLS_CONNECTION_INIT; + gnutls_init (&con->tls_session, GNUTLS_SERVER); /* sets cipher priorities */ @@ -872,7 +875,7 @@ MHD_start_daemon (unsigned int options, gnutls_global_init (); pthread_mutex_unlock (&gnutls_init_mutex); /* set default priorities */ - gnutls_priority_init (&retVal->priority_cache,"", NULL); + gnutls_priority_init (&retVal->priority_cache, "", NULL); } #endif /* initializes the argument pointer variable */ diff --git a/src/daemon/https/tls/gnutls_handshake.c b/src/daemon/https/tls/gnutls_handshake.c @@ -940,10 +940,6 @@ _gnutls_send_handshake (gnutls_session_t session, void *i_data, if (i_datasize > 0) memcpy (&data[pos], i_data, i_datasize); - _gnutls_handshake_log ("HSK[%x]: %s was send [%ld bytes]\n", - session, _gnutls_handshake2str (type), datasize); - - /* Here we keep the handshake messages in order to hash them... */ if (type != GNUTLS_HANDSHAKE_HELLO_REQUEST) @@ -961,6 +957,9 @@ _gnutls_send_handshake (gnutls_session_t session, void *i_data, _gnutls_handshake_io_send_int (session, GNUTLS_HANDSHAKE, type, data, datasize); + _gnutls_handshake_log ("HSK[%x]: %s was sent [%ld bytes]\n", + session, _gnutls_handshake2str (type), datasize); + gnutls_afree (data); return ret; diff --git a/src/daemon/internal.c b/src/daemon/internal.c @@ -26,6 +26,65 @@ #include "internal.h" +#if DEBUG_STATES +char * +MHD_state_to_string (enum MHD_CONNECTION_STATE state) +{ + switch (state) + { + case MHD_CONNECTION_INIT: + return "connection init"; + case MHD_CONNECTION_URL_RECEIVED: + return "connection url received"; + case MHD_CONNECTION_HEADER_PART_RECEIVED: + return "header partially received"; + case MHD_CONNECTION_HEADERS_RECEIVED: + return "headers received"; + case MHD_CONNECTION_HEADERS_PROCESSED: + return "headers processed"; + case MHD_CONNECTION_CONTINUE_SENDING: + return "continue sending"; + case MHD_CONNECTION_CONTINUE_SENT: + return "continue sent"; + case MHD_CONNECTION_BODY_RECEIVED: + return "body received"; + case MHD_CONNECTION_FOOTER_PART_RECEIVED: + return "footer partially received"; + case MHD_CONNECTION_FOOTERS_RECEIVED: + return "footers received"; + case MHD_CONNECTION_HEADERS_SENDING: + return "headers sending"; + case MHD_CONNECTION_HEADERS_SENT: + return "headers sent"; + case MHD_CONNECTION_NORMAL_BODY_READY: + return "normal body ready"; + case MHD_CONNECTION_NORMAL_BODY_UNREADY: + return "normal body unready"; + case MHD_CONNECTION_CHUNKED_BODY_READY: + return "chunked body ready"; + case MHD_CONNECTION_CHUNKED_BODY_UNREADY: + return "chunked body unready"; + case MHD_CONNECTION_BODY_SENT: + return "body sent"; + case MHD_CONNECTION_FOOTERS_SENDING: + return "footers sending"; + case MHD_CONNECTION_FOOTERS_SENT: + return "footers sent"; + case MHD_CONNECTION_CLOSED: + return "closed"; + case MHD_TLS_CONNECTION_INIT: + return "secure connection init"; + case MHD_TLS_HELLO_REQUEST: + return "secure hello request"; + case MHD_TLS_HANDSHAKE_FAILED: + return "secure handshake failed"; + case MHD_TLS_HANDSHAKE_COMPLETE: + return "secure handshake _complete"; + } + return "unrecognized connection state"; +} +#endif + #if HAVE_MESSAGES /** * fprintf-like helper function for logging debug diff --git a/src/daemon/internal.h b/src/daemon/internal.h @@ -273,15 +273,37 @@ enum MHD_CONNECTION_STATE /* * SSL/TLS connection states */ - MHD_TLS_HANDSHAKE_FAILED = MHD_CONNECTION_CLOSED +1, + + /* + * The initial connection state for all secure connectoins + * Handshake messages will be processed in this state & while + * in the 'MHD_TLS_HELLO_REQUEST' state + */ + MHD_TLS_CONNECTION_INIT = MHD_CONNECTION_CLOSED +1, + + /* + * This state indicates the server has send a 'Hello Request' to + * the client & a renegotiation of the handshake is in progress. + * + * Handshake messages will processed in this state & while + * in the 'MHD_TLS_CONNECTION_INIT' state + */ + MHD_TLS_HELLO_REQUEST, + + MHD_TLS_HANDSHAKE_FAILED, MHD_TLS_HANDSHAKE_COMPLETE, + #endif }; +/** + * Should all state transitions be printed to stderr? + */ +#define DEBUG_STATES MHD_NO #if DEBUG_STATES - /* TODO add state dictionary */ +char * MHD_state_to_string(enum MHD_CONNECTION_STATE state); #endif struct MHD_Connection diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h @@ -486,8 +486,22 @@ enum MHD_RequestTerminationCode * We had to close the session since MHD was being * shut down. */ - MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN = 3 + MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN = 3, +#if HTTPS_SUPPORT + /* + * this is the final state of a successfully processed secure connection + */ + MHD_TLS_REQUEST_TERMINATED_COMPLETED_OK, + + /* + * processing of this secure connection encountered an error + */ + /* TODO consider elaborating error cause & registering a error callback */ + MHD_TLS_REQUEST_TERMINATED_WITH_ERROR, + + MHD_TLS_REQUEST_TERMINATED_WITH_FATAL_ALERT, +#endif }; /** diff --git a/src/testcurl/curl_version_check.c b/src/testcurl/curl_version_check.c @@ -76,7 +76,6 @@ parse_version_string (const char *s, int *major, int *minor, int *micro) int curl_check_version (const char *req_version) { - va_list ap; const char *ver; const char *curl_ver; const char *ssl_ver; @@ -121,19 +120,21 @@ curl_check_version (const char *req_version) #if HTTPS_SUPPORT ssl_ver = strchr (curl_ver, '\ ') + 1; - if (strncmp("GnuTLS",ssl_ver,strlen("GNUtls")) == 0){ - ssl_ver = strchr (ssl_ver, '/') + 1; - req_ssl_ver = MHD_REQ_CURL_GNUTLS_VERSION; - } - else if(strncmp("OpenSSL",ssl_ver,strlen("OpenSSL")) == 0){ - ssl_ver = strchr (ssl_ver, '/') + 1; - req_ssl_ver = MHD_REQ_CURL_OPENSSL_VERSION; - } - else{ - fprintf (stderr, - "Error: unrecognized curl ssl library\n",req_ssl_ver); - return -1; - } + if (strncmp ("GnuTLS", ssl_ver, strlen ("GNUtls")) == 0) + { + ssl_ver = strchr (ssl_ver, '/') + 1; + req_ssl_ver = MHD_REQ_CURL_GNUTLS_VERSION; + } + else if (strncmp ("OpenSSL", ssl_ver, strlen ("OpenSSL")) == 0) + { + ssl_ver = strchr (ssl_ver, '/') + 1; + req_ssl_ver = MHD_REQ_CURL_OPENSSL_VERSION; + } + else + { + fprintf (stderr, "Error: unrecognized curl ssl library\n", req_ssl_ver); + return -1; + } parse_version_string (req_ssl_ver, &rq_major, &rq_minor, &rq_micro); parse_version_string (ssl_ver, &loc_major, &loc_minor, &loc_micro); diff --git a/src/testcurl/https/Makefile.am b/src/testcurl/https/Makefile.am @@ -10,6 +10,8 @@ AM_CPPFLAGS = \ $(LIBCURL_CPPFLAGS) check_PROGRAMS = \ +tls_session_time_out_test \ +tls_cipher_change_test \ mhds_get_test \ tls_alert_test \ tls_authentication_test \ @@ -18,12 +20,23 @@ mhds_session_info_test TESTS = $(check_PROGRAMS) +tls_session_time_out_test_SOURCES = \ + tls_session_time_out_test.c +tls_session_time_out_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +tls_cipher_change_test_SOURCES = \ + tls_cipher_change_test.c +tls_cipher_change_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la + tls_alert_test_SOURCES = \ tls_alert_test.c tls_alert_test_LDADD = \ $(top_builddir)/src/testcurl/libcurl_version_check.a \ - $(top_builddir)/src/daemon/libmicrohttpd.la \ - @LIBCURL@ + $(top_builddir)/src/daemon/libmicrohttpd.la tls_authentication_test_SOURCES = \ tls_authentication_test.c diff --git a/src/testcurl/https/mhds_get_test.c b/src/testcurl/https/mhds_get_test.c @@ -338,8 +338,7 @@ test_kx_option (FILE * test_fd, char *cipher_suite, int proto_version) 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); + MHD_OPTION_CIPHER_ALGORITHM, ciper, MHD_OPTION_END); if (d == NULL) { @@ -447,7 +446,7 @@ main (int argc, char *const *argv) // test_kx_option (test_fd, "EDH-RSA-DES-CBC3-SHA", CURL_SSLVERSION_TLSv1); if (errorCount != 0) - fprintf(stderr, "Failed test: %s.\n", argv[0]); + fprintf (stderr, "Failed test: %s.\n", argv[0]); curl_global_cleanup (); fclose (test_fd); diff --git a/src/testcurl/https/mhds_multi_daemon_test.c b/src/testcurl/https/mhds_multi_daemon_test.c @@ -306,7 +306,8 @@ main (int argc, char *const *argv) if (0 != curl_global_init (CURL_GLOBAL_ALL)) { - fprintf (stderr, "Error (code: %u). l:%d f:%s\n", errorCount, __LINE__, __FUNCTION__); + fprintf (stderr, "Error (code: %u). l:%d f:%s\n", errorCount, __LINE__, + __FUNCTION__); return -1; } @@ -314,7 +315,7 @@ main (int argc, char *const *argv) test_concurent_daemon_pair (test_fd, "AES256-SHA", CURL_SSLVERSION_SSLv3); if (errorCount != 0) - fprintf(stderr, "Failed test: %s.\n", __FILE__); + fprintf (stderr, "Failed test: %s.\n", __FILE__); curl_global_cleanup (); fclose (test_fd); diff --git a/src/testcurl/https/mhds_session_info_test.c b/src/testcurl/https/mhds_session_info_test.c @@ -215,13 +215,13 @@ main (int argc, char *const *argv) if (0 != curl_global_init (CURL_GLOBAL_ALL)) { fprintf (stderr, "Error (code: %u)\n", errorCount); - return 8; + return -1; } errorCount += test_query_session (test_fd); if (errorCount != 0) - fprintf(stderr, "Failed test: %s.\n", argv[0]); + fprintf (stderr, "Failed test: %s.\n", argv[0]); curl_global_cleanup (); diff --git a/src/testcurl/https/tls_alert_test.c b/src/testcurl/https/tls_alert_test.c @@ -27,7 +27,6 @@ #include "platform.h" #include "microhttpd.h" -#include <curl/curl.h> #include "gnutls_int.h" #include "gnutls_datum.h" #include "gnutls_record.h" @@ -37,8 +36,6 @@ #define MHD_E_SERVER_INIT "Error: failed to start server\n" #define MHD_E_FAILED_TO_CONNECT "Error: server connection could not be established\n" -extern int curl_check_version (const char *req_version, ...); - const char *ca_cert_file_name = "ca_cert_pem"; const char *test_file_name = "https_test_file"; const char test_file_data[] = "Hello World\n"; @@ -102,6 +99,12 @@ teardown (gnutls_session_t session, return 0; } +/* + * assert server closes connection upon receiving a + * close notify alert message. + * + * @param session: an initialized TLS session + */ static int test_alert_close_notify (gnutls_session_t session) { @@ -145,6 +148,12 @@ test_alert_close_notify (gnutls_session_t session) return 0; } +/* + * assert server closes connection upon receiving a + * fatal unexpected_message alert. + * + * @param session: an initialized TLS session + */ static int test_alert_unexpected_message (gnutls_session_t session) { @@ -196,11 +205,6 @@ main (int argc, char *const *argv) gnutls_datum_t cert; gnutls_certificate_credentials_t xcred; - if (curl_check_version (MHD_REQ_CURL_VERSION)) - { - return -1; - } - gnutls_global_init (); gnutls_global_set_log_level (11); diff --git a/src/testcurl/https/tls_authentication_test.c b/src/testcurl/https/tls_authentication_test.c @@ -308,9 +308,9 @@ main (int argc, char *const *argv) FILE *test_fd; unsigned int errorCount = 0; - gnutls_global_set_log_level(11); + /* gnutls_global_set_log_level (11); */ - if (curl_check_version (MHD_REQ_CURL_VERSION)) + if (curl_check_version (MHD_REQ_CURL_VERSION)) { return -1; } @@ -333,7 +333,7 @@ main (int argc, char *const *argv) test_secure_get (test_fd, "AES256-SHA", CURL_SSLVERSION_SSLv3); if (errorCount != 0) - fprintf(stderr, "Failed test: %s.\n", argv[0]); + fprintf (stderr, "Failed test: %s.\n", argv[0]); curl_global_cleanup (); fclose (test_fd); diff --git a/src/testcurl/https/tls_cipher_change_test.c b/src/testcurl/https/tls_cipher_change_test.c @@ -0,0 +1,199 @@ +/* + 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: daemon TLS cipher change message test-case + * + * @author Sagie Amir + */ + +#include "platform.h" +#include "microhttpd.h" +#include "internal.h" +#include "gnutls_int.h" +#include "gnutls_datum.h" +#include "gnutls_record.h" +#include "tls_test_keys.h" + +#define MHD_E_SERVER_INIT "Error: failed to start server\n" +#define MHD_E_FAILED_TO_CONNECT "Error: server connection could not be established\n" + +char *http_get_req = "GET / HTTP/1.1\r\n\r\n"; + +/* HTTP access handler call back */ +static int +rehandshake_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) +{ + int ret; + /* server side re-handshake request */ + ret = gnutls_rehandshake (connection->tls_session); + + if (ret < 0) + { + fprintf (stderr, "Error: %s. f: %s, l: %d\n", + "server failed to send Hello Request", __FUNCTION__, __LINE__); + } + + return 0; +} + +static int +setup (gnutls_session_t * session, + gnutls_datum_t * key, + gnutls_datum_t * cert, gnutls_certificate_credentials_t * xcred) +{ + int ret; + const char **err_pos; + + gnutls_certificate_allocate_credentials (xcred); + + _gnutls_set_datum_m (key, srv_key_pem, strlen (srv_key_pem), &malloc); + _gnutls_set_datum_m (cert, srv_self_signed_cert_pem, + strlen (srv_self_signed_cert_pem), &malloc); + + gnutls_certificate_set_x509_key_mem (*xcred, cert, key, + GNUTLS_X509_FMT_PEM); + + gnutls_init (session, GNUTLS_CLIENT); + ret = gnutls_priority_set_direct (*session, "PERFORMANCE", err_pos); + if (ret < 0) + { + return -1; + } + + gnutls_credentials_set (*session, MHD_GNUTLS_CRD_CERTIFICATE, xcred); + return 0; +} + +static int +teardown (gnutls_session_t session, + gnutls_datum_t * key, + gnutls_datum_t * cert, gnutls_certificate_credentials_t xcred) +{ + + _gnutls_free_datum_m (key, free); + _gnutls_free_datum_m (cert, free); + + gnutls_deinit (session); + + gnutls_certificate_free_credentials (xcred); + return 0; +} + +/* + * Cipher change message should only occur while negotiating + * the SSL/TLS handshake. + * Test server disconnects upon receiving an out of context + * message. + * + * @param session: initiallized TLS session + */ +static int +test_out_of_context_cipher_change (gnutls_session_t session) +{ + int sd, ret; + struct sockaddr_in sa; + + sd = socket (AF_INET, SOCK_STREAM, 0); + memset (&sa, '\0', sizeof (struct sockaddr_in)); + sa.sin_family = AF_INET; + sa.sin_port = htons (42433); + inet_pton (AF_INET, "127.0.0.1", &sa.sin_addr); + + gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd); + + ret = connect (sd, &sa, sizeof (struct sockaddr_in)); + + if (ret < 0) + { + fprintf (stderr, "Error: %s)\n", MHD_E_FAILED_TO_CONNECT); + return -1; + } + + ret = gnutls_handshake (session); + if (ret < 0) + { + return -1; + } + + /* send an out of context cipher change spec */ + _gnutls_send_change_cipher_spec (session, 0); + + + /* assert server has closed connection */ + /* TODO better RST trigger */ + if (send (sd, "", 1, 0) == 0) + { + return -1; + } + + close (sd); + return 0; +} + +static int +test_rehandshake (gnutls_session_t session) +{ + /* TODO impl */ + return 0; +} + +int +main (int argc, char *const *argv) +{ + int errorCount = 0;; + struct MHD_Daemon *d; + gnutls_session_t session; + gnutls_datum_t key; + gnutls_datum_t cert; + gnutls_certificate_credentials_t xcred; + + gnutls_global_init (); + gnutls_global_set_log_level (11); + + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | + MHD_USE_DEBUG, 42433, + NULL, NULL, &rehandshake_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; + } + + setup (&session, &key, &cert, &xcred); + errorCount += test_out_of_context_cipher_change (session); + teardown (session, &key, &cert, xcred); + + if (errorCount != 0) + fprintf (stderr, "Failed test: %s.\n", argv[0]); + + MHD_stop_daemon (d); + gnutls_global_deinit (); + + 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 @@ -0,0 +1,182 @@ +/* + 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: daemon TLS alert response test-case + * + * @author Sagie Amir + */ + +#include "platform.h" +#include "microhttpd.h" +#include "internal.h" +#include "gnutls_int.h" +#include "gnutls_datum.h" +#include "gnutls_record.h" +#include "tls_test_keys.h" + +#define MHD_E_MEM "Error: memory error\n" +#define MHD_E_SERVER_INIT "Error: failed to start server\n" +#define MHD_E_FAILED_TO_CONNECT "Error: server connection could not be established\n" + +const char *ca_cert_file_name = "ca_cert_pem"; +const char *test_file_name = "https_test_file"; +const char test_file_data[] = "Hello World\n"; + +static const int TIME_OUT = 3; + +char *http_get_req = "GET / HTTP/1.1\r\n\r\n"; + +/* 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) +{ + return 0; +} + +static int +setup (gnutls_session_t * session, + gnutls_datum_t * key, + gnutls_datum_t * cert, gnutls_certificate_credentials_t * xcred) +{ + int ret; + const char **err_pos; + + gnutls_certificate_allocate_credentials (xcred); + + _gnutls_set_datum_m (key, srv_key_pem, strlen (srv_key_pem), &malloc); + _gnutls_set_datum_m (cert, srv_self_signed_cert_pem, + strlen (srv_self_signed_cert_pem), &malloc); + + gnutls_certificate_set_x509_key_mem (*xcred, cert, key, + GNUTLS_X509_FMT_PEM); + + gnutls_init (session, GNUTLS_CLIENT); + ret = gnutls_priority_set_direct (*session, "PERFORMANCE", err_pos); + if (ret < 0) + { + return -1; + } + + gnutls_credentials_set (*session, MHD_GNUTLS_CRD_CERTIFICATE, xcred); + return 0; +} + +static int +teardown (gnutls_session_t session, + gnutls_datum_t * key, + gnutls_datum_t * cert, gnutls_certificate_credentials_t xcred) +{ + + _gnutls_free_datum_m (key, free); + _gnutls_free_datum_m (cert, free); + + gnutls_deinit (session); + + gnutls_certificate_free_credentials (xcred); + return 0; +} + +static int +test_tls_session_time_out (gnutls_session_t session) +{ + int sd, ret; + char *url = "https://localhost:42433/"; + struct sockaddr_in sa; + + sd = socket (AF_INET, SOCK_STREAM, 0); + memset (&sa, '\0', sizeof (struct sockaddr_in)); + sa.sin_family = AF_INET; + sa.sin_port = htons (42433); + inet_pton (AF_INET, "127.0.0.1", &sa.sin_addr); + + gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd); + + ret = connect (sd, &sa, sizeof (struct sockaddr_in)); + + if (ret < 0) + { + fprintf (stderr, "Error: %s)\n", MHD_E_FAILED_TO_CONNECT); + return -1; + } + + ret = gnutls_handshake (session); + if (ret < 0) + { + return -1; + } + + sleep (TIME_OUT + 1); + + + /* check that server has closed the connection */ + /* TODO better RST trigger */ + if (send (sd, "", 1, 0) == 0) + { + return -1; + } + + close (sd); + fprintf (stderr, "%s. f: %s, l: %d\n", "ok", __FUNCTION__, __LINE__); + return 0; +} + +int +main (int argc, char *const *argv) +{ + int errorCount = 0;; + struct MHD_Daemon *d; + gnutls_session_t session; + gnutls_datum_t key; + gnutls_datum_t cert; + gnutls_certificate_credentials_t xcred; + + gnutls_global_init (); + gnutls_global_set_log_level (11); + + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | + MHD_USE_DEBUG, 42433, + NULL, NULL, &http_ahc, NULL, + MHD_OPTION_CONNECTION_TIMEOUT, TIME_OUT, + 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; + } + + setup (&session, &key, &cert, &xcred); + errorCount += test_tls_session_time_out (session); + teardown (session, &key, &cert, xcred); + + if (errorCount != 0) + fprintf (stderr, "Failed test: %s.\n", argv[0]); + + MHD_stop_daemon (d); + gnutls_global_deinit (); + + return errorCount != 0; +}