libmicrohttpd

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

commit b9f09651e6217396171d0ee25eb3f1a5087a3ad6
parent eb391a612d2c1a3bea1cbfecfa008079c8a6320c
Author: lv-426 <oxcafebaby@yahoo.com>
Date:   Mon,  7 Jul 2008 02:38:41 +0000

migrated code to connection_https
fixed gcrypt lib initialization to support mt
removed some gnutls psk code
added CIPHER_ALGORITHM & KX_PRIORITY options
added certificate loading test
added TLS GET test

Diffstat:
Msrc/daemon/Makefile.am | 11++++++-----
Msrc/daemon/connection.c | 293+++----------------------------------------------------------------------------
Msrc/daemon/connection.h | 47+++--------------------------------------------
Asrc/daemon/connection_https.c | 309+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/daemon/daemon.c | 220+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/daemon/https/errcodes.c | 41-----------------------------------------
Msrc/daemon/https/includes/gnutls.h | 6++----
Msrc/daemon/https/tls/auth_dh_common.c | 48+++---------------------------------------------
Msrc/daemon/https/tls/gnutls_algorithms.c | 44+++++---------------------------------------
Msrc/daemon/https/tls/gnutls_global.c | 161++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/daemon/https/tls/gnutls_int.h | 17+++++++++--------
Msrc/daemon/https/tls/gnutls_priority.c | 48+++---------------------------------------------
Msrc/daemon/https/tls/gnutls_session_pack.c | 17+----------------
Msrc/daemon/internal.c | 7+++++++
Msrc/daemon/internal.h | 25+++++++------------------
Msrc/include/microhttpd.h | 17+++++++++++++++++
Msrc/testcurl/https/Makefile.am | 2+-
Msrc/testcurl/https/daemon_https_test_get.c | 142++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/testcurl/https/mhds_test_session_info.c | 2+-
19 files changed, 708 insertions(+), 749 deletions(-)

diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am @@ -22,11 +22,6 @@ lib_LTLIBRARIES = \ SUBDIRS = libmicrohttpd_la_LIBADD = -if ENABLE_HTTPS -SUBDIRS += https . -libmicrohttpd_la_LIBADD += https/libhttps.la -endif - libmicrohttpd_la_SOURCES = \ connection.c connection.h \ reason_phrase.c reason_phrase.h \ @@ -38,6 +33,12 @@ postprocessor.c \ response.c response.h libmicrohttpd_la_LDFLAGS = \ -export-dynamic -version-info 4:3:0 $(retaincommand) + +if ENABLE_HTTPS +SUBDIRS += https . +libmicrohttpd_la_SOURCES += connection_https.c +libmicrohttpd_la_LIBADD += https/libhttps.la +endif check_PROGRAMS = \ postprocessor_test \ diff --git a/src/daemon/connection.c b/src/daemon/connection.c @@ -161,33 +161,6 @@ MHD_get_connection_values (struct MHD_Connection *connection, return ret; } -#if HTTPS_SUPPORT -/* get cipher spec for this connection */ -gnutls_cipher_algorithm_t -MHDS_get_session_cipher (struct MHD_Connection * session) -{ - return gnutls_cipher_get (session->tls_session); -} - -gnutls_mac_algorithm_t -MHDS_get_session_mac (struct MHD_Connection * session) -{ - return gnutls_mac_get (session->tls_session); -} - -gnutls_compression_method_t -MHDS_get_session_compression (struct MHD_Connection * session) -{ - return gnutls_compression_get (session->tls_session); -} - -gnutls_certificate_type_t -MHDS_get_session_cert_type (struct MHD_Connection * session) -{ - return gnutls_certificate_type_get (session->tls_session); -} -#endif - /** * Get a particular header value. If multiple * values match the kind, return any one of them. @@ -1276,8 +1249,7 @@ do_write (struct MHD_Connection *connection) return MHD_YES; } - -int +static int MHD_con_read (struct MHD_Connection *connection) { return RECV (connection->socket_fd, @@ -1286,18 +1258,6 @@ MHD_con_read (struct MHD_Connection *connection) connection->read_buffer_offset, MSG_NOSIGNAL); } -#if HTTPS_SUPPORT -ssize_t -MHDS_con_read (struct MHD_Connection * connection) -{ - ssize_t size = gnutls_record_recv (connection->tls_session, - &connection->read_buffer[connection-> - read_buffer_offset], - connection->read_buffer_size); - return size; -} -#endif - /** * Check if we are done sending the write-buffer. * If so, transition into "next_state". @@ -1549,122 +1509,7 @@ MHD_connection_handle_read (struct MHD_Connection *connection) return MHD_YES; } -#if HTTPS_SUPPORT -int -MHDS_connection_handle_read (struct MHD_Connection *connection) -{ - int ret; - - connection->last_activity = time (NULL); - - if (connection->s_state == MHDS_CONNECTION_CLOSED) - return MHD_NO; - - /* discover content type */ - unsigned char msg_type; - if (recv (connection->socket_fd, &msg_type, 1, MSG_PEEK) == -1) - { -#if HAVE_MESSAGES - MHD_DLOG (connection->daemon, "Failed to peek into TLS content type\n"); -#endif - return MHD_NO; - } - - switch (msg_type) - { - case GNUTLS_CHANGE_CIPHER_SPEC: - - break; - case GNUTLS_ALERT: - /* - * this call of _gnutls_recv_int expects 0 bytes read. - * done to decrypt alert message - */ - _gnutls_recv_int (connection->tls_session, GNUTLS_ALERT, - GNUTLS_HANDSHAKE_FINISHED, 0); - - /* CLOSE_NOTIFY */ - if (connection->tls_session->internals.last_alert == - GNUTLS_A_CLOSE_NOTIFY) - { - gnutls_bye (connection->tls_session, GNUTLS_SHUT_WR); - connection->tls_session->internals.read_eof = 1; - connection->socket_fd = -1; - gnutls_deinit (connection->tls_session); - return MHD_YES; - } - /* non FATAL or WARNING */ - else if (connection->tls_session->internals.last_alert != - GNUTLS_AL_FATAL) - { -#if HAVE_MESSAGES - MHD_DLOG (connection->daemon, - "Received TLS alert: %s\n", - gnutls_alert_get_name ((int) connection->tls_session-> - internals.last_alert)); -#endif - return MHD_YES; - } - /* FATAL */ - else if (connection->tls_session->internals.last_alert == - GNUTLS_AL_FATAL) - { - connection->tls_session->internals.resumable = RESUME_FALSE; - connection->tls_session->internals.valid_connection = VALID_FALSE; - connection->socket_fd = -1; - gnutls_deinit (connection->tls_session); - - return MHD_NO; - } - /* this should never execut */ - else - { -#if HAVE_MESSAGES - MHD_DLOG (connection->daemon, - "Received unrecognized alert: %s\n", - connection->tls_session->internals.last_alert); -#endif - return MHD_NO; - } - - - /* forward application level content to MHD */ - case GNUTLS_APPLICATION_DATA: - return MHD_connection_handle_read (connection); - - case GNUTLS_HANDSHAKE: - ret = gnutls_handshake (connection->tls_session); - if (ret == 0) - { - connection->s_state = MHDS_HANDSHAKE_COMPLETE; - connection->state = MHD_CONNECTION_INIT; - } - /* set connection as closed */ - else - { -#if HAVE_MESSAGES - MHD_DLOG (connection->daemon, - "Error: Handshake has failed (%s)\n", - ret); -#endif - connection->s_state = MHDS_HANDSHAKE_FAILED; - gnutls_bye (connection->tls_session, GNUTLS_SHUT_WR); - gnutls_deinit (connection->tls_session); - connection->socket_fd = -1; - return MHD_NO; - - } - break; - case GNUTLS_INNER_APPLICATION: - break; - } - - return MHD_YES; -} -#endif - - -int +static int MHD_con_write (struct MHD_Connection *connection) { return SEND (connection->socket_fd, @@ -1674,19 +1519,6 @@ MHD_con_write (struct MHD_Connection *connection) connection->write_buffer_send_offset, MSG_NOSIGNAL); } -#if HTTPS_SUPPORT -ssize_t -MHDS_con_write (struct MHD_Connection * connection) -{ - ssize_t sent = gnutls_record_send (connection->tls_session, - &connection->write_buffer[connection-> - write_buffer_send_offset], - connection->write_buffer_append_offset - - connection->write_buffer_send_offset); - return sent; -} -#endif - /** * This function was created to handle writes to sockets when it has * been determined that the socket can be written to. All @@ -1849,52 +1681,6 @@ MHD_connection_handle_write (struct MHD_Connection *connection) return MHD_YES; } -#if HTTPS_SUPPORT -int -MHDS_connection_handle_write (struct MHD_Connection *connection) -{ - connection->last_activity = time (NULL); - while (1) - { -#if HAVE_MESSAGES - MHD_DLOG (connection->daemon, "MHDS reached case: %d, l: %d, f: %s\n", - connection->s_state, __LINE__, __FUNCTION__); -#endif - switch (connection->s_state) - { - - /* these cases shouldn't occur */ - case MHDS_CONNECTION_INIT: - // TODO do we have to write back a responce ? - case MHDS_HANDSHAKE_FAILED: - /* we should first exit MHDS_REPLY_SENDING */ - case MHDS_REQUEST_READING: - /* these should go through the idle state at first */ - case MHDS_REQUEST_READ: - connection->s_state = MHDS_REPLY_SENDING; - do_write (connection); - break; - - case MHDS_CONNECTION_CLOSED: - if (connection->socket_fd != -1) - connection_close_error (connection); - return MHD_NO; - case MHDS_HANDSHAKE_COMPLETE: - - case MHDS_REPLY_SENDING: - do_write (connection); - // TODO check write done - break; - - case MHDS_REPLY_READY: - /* switch to MHDS_REPLY_SENDING through idle */ - break; - } - } - return MHD_YES; -} -#endif - /** * This function was created to handle per-connection processing that * has to happen even if the socket cannot be read or written to. All @@ -2223,77 +2009,14 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) } -#if HTTPS_SUPPORT int -MHDS_connection_handle_idle (struct MHD_Connection *connection) +MHD_set_http_calbacks (struct MHD_Connection *connection) { - unsigned int timeout; - const char *end; - char *line; - ssize_t msgLength; - while (1) - { -#if HAVE_MESSAGES - MHD_DLOG (connection->daemon, "MHDS reached case: %d, l: %d, f: %s\n", - connection->s_state, __LINE__, __FUNCTION__); -#endif - switch (connection->s_state) - { - case MHDS_HANDSHAKE_FAILED: - connection->socket_fd = -1; - case MHDS_CONNECTION_INIT: - /* wait for request */ - case MHDS_HANDSHAKE_COMPLETE: - - case MHDS_REPLY_SENDING: - connection->s_state = MHDS_REPLY_SENT; - break; - - case MHDS_REPLY_READY: - /* send data for encryption */ - //memcpy (connection->write_buffer, - //connection->tls_session->internals.application_data_buffer. - // data, connection->write_buffer_size); - //connection->s_state = MHDS_REPLY_SENDING; - break; - - case MHDS_REQUEST_READING: - // TODO mv handshake here - connection->s_state = MHDS_REQUEST_READ; - - case MHDS_REQUEST_READ: - /* pipe data to HTTP state machine */ - - // msgLength = connection->tls_session->internals.application_data_buffer.length; - // memcpy (connection->tls_session->internals.application_data_buffer.data, connection->read_buffer, msgLength); - // connection->read_buffer_offset = msgLength; - /* pass connection to MHD */ - MHD_connection_handle_idle (connection); - - break; - - case MHDS_CONNECTION_CLOSED: - if (connection->socket_fd != -1) - connection_close_error (connection); - break; - - default: - EXTRA_CHECK (0); - break; - } - break; - } - - timeout = connection->daemon->connection_timeout; - - if ((connection->socket_fd != -1) && (timeout != 0) - && (time (NULL) - timeout > connection->last_activity)) - { - connection_close_error (connection); - return MHD_NO; - } - return MHD_YES; + connection->recv_cls = &MHD_con_read; + connection->send_cls = &MHD_con_write; + connection->read_handler = &MHD_connection_handle_read; + connection->write_handler = &MHD_connection_handle_write; + connection->idle_handler = &MHD_connection_handle_idle; } -#endif /* end of connection.c */ diff --git a/src/daemon/connection.h b/src/daemon/connection.h @@ -40,50 +40,9 @@ MHD_connection_get_fdset (struct MHD_Connection *connection, fd_set * write_fd_set, fd_set * except_fd_set, int *max_fd); -/** - * This function handles a particular connection when it has been - * determined that there is data to be read off a socket. All implementations - * (multithreaded, external select, internal select) call this function - * to handle reads. - * - * @return MHD_YES if we should continue to process the - * connection (not dead yet), MHD_NO if it died - */ -int MHD_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. If there is no data - * to be written, however, the function call does nothing. All implementations - * (multithreaded, external select, internal select) call this function - * - * @return MHD_YES if we should continue to process the - * connection (not dead yet), MHD_NO if it died - */ -int MHD_connection_handle_write (struct MHD_Connection *connection); - - -/** - * This function was created to handle per-connection processing that - * has to happen even if the socket cannot be read or written to. All - * implementations (multithreaded, external select, internal select) - * call this function. - * - * @return MHD_YES if we should continue to process the - * connection (not dead yet), MHD_NO if it died - */ -int MHD_connection_handle_idle (struct MHD_Connection *connection); - -int MHD_con_read(struct MHD_Connection *connection); -int MHD_con_write(struct MHD_Connection *connection); - +int MHD_set_http_calbacks (struct MHD_Connection *connection); #if HTTPS_SUPPORT -int MHDS_connection_handle_read(struct MHD_Connection *connection); -int MHDS_connection_handle_write(struct MHD_Connection *connection); -int MHDS_connection_handle_idle(struct MHD_Connection *connection); - -ssize_t MHDS_con_read(struct MHD_Connection *connection); -ssize_t MHDS_con_write(struct MHD_Connection *connection); +int MHD_set_https_calbacks (struct MHD_Connection *connection); #endif + #endif diff --git a/src/daemon/connection_https.c b/src/daemon/connection_https.c @@ -0,0 +1,309 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2008 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +/** + * @file connection.c + * @brief Methods for managing SSL/TLS connections. This file is only + * compiled if ENABLE_HTTPS is set. + * @author Sagie Amir + * @author Christian Grothoff + */ + +#include "internal.h" +#include "connection.h" +#include "memorypool.h" +#include "response.h" +#include "reason_phrase.h" + +// get opaque type +#include "gnutls_int.h" + +// TODO clean +#undef MAX +#define MAX(a,b) ((a)<(b)) ? (b) : (a) +#undef MIN +#define MIN(a,b) ((a)<(b)) ? (a) : (b) + +// TODO rm - appears in a switch default clause +#if EXTRA_CHECKS +#define EXTRA_CHECK(a) if (!(a)) abort(); +#else +#define EXTRA_CHECK(a) +#endif + +/* forward declarations used when setting secure connection callbacks */ +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); + +// TODO rm - appears in a switch default clause +static void +connection_close_error (struct MHD_Connection *connection) +{ + 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); +} + +/* get cipher spec for this connection */ +gnutls_cipher_algorithm_t +MHDS_get_session_cipher (struct MHD_Connection *session) +{ + return gnutls_cipher_get (session->tls_session); +} + +gnutls_mac_algorithm_t +MHDS_get_session_mac (struct MHD_Connection * session) +{ + return gnutls_mac_get (session->tls_session); +} + +gnutls_compression_method_t +MHDS_get_session_compression (struct MHD_Connection * session) +{ + return gnutls_compression_get (session->tls_session); +} + +gnutls_certificate_type_t +MHDS_get_session_cert_type (struct MHD_Connection * session) +{ + return gnutls_certificate_type_get (session->tls_session); +} + +static ssize_t +MHDS_con_read (struct MHD_Connection *connection) +{ + ssize_t size = gnutls_record_recv (connection->tls_session, + &connection->read_buffer[connection-> + read_buffer_offset], + connection->read_buffer_size); + return size; +} + +static ssize_t +MHDS_con_write (struct MHD_Connection *connection) +{ + ssize_t sent = gnutls_record_send (connection->tls_session, + &connection->write_buffer[connection-> + write_buffer_send_offset], + connection->write_buffer_append_offset + - connection->write_buffer_send_offset); + return sent; +} + +int +MHDS_connection_handle_idle (struct MHD_Connection *connection) +{ + unsigned int timeout; + const char *end; + char *line; + ssize_t msgLength; + while (1) + { +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, "MHDS reached case: %d, l: %d, f: %s\n", + connection->s_state, __LINE__, __FUNCTION__); +#endif + switch (connection->s_state) + { + case MHDS_HANDSHAKE_FAILED: + connection->socket_fd = -1; + case MHDS_CONNECTION_INIT: + /* wait for request */ + case MHDS_HANDSHAKE_COMPLETE: + + case MHDS_CONNECTION_CLOSED: + if (connection->socket_fd != -1) + connection_close_error (connection); + break; + + default: + EXTRA_CHECK (0); + break; + } + break; + } + + timeout = connection->daemon->connection_timeout; + + if ((connection->socket_fd != -1) && (timeout != 0) + && (time (NULL) - timeout > connection->last_activity)) + { + connection_close_error (connection); + return MHD_NO; + } + return MHD_YES; +} + +int +MHDS_connection_handle_read (struct MHD_Connection *connection) +{ + int ret; + + connection->last_activity = time (NULL); + + if (connection->s_state == MHDS_CONNECTION_CLOSED) + return MHD_NO; + + /* discover content type */ + unsigned char msg_type; + if (recv (connection->socket_fd, &msg_type, 1, MSG_PEEK) == -1) + { +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, "Failed to peek into TLS content type\n"); +#endif + return MHD_NO; + } + + switch (msg_type) + { + case GNUTLS_CHANGE_CIPHER_SPEC: + + break; + case GNUTLS_ALERT: + /* + * this call of _gnutls_recv_int expects 0 bytes read. + * done to decrypt alert message + */ + _gnutls_recv_int (connection->tls_session, GNUTLS_ALERT, + GNUTLS_HANDSHAKE_FINISHED, 0); + + /* CLOSE_NOTIFY */ + if (connection->tls_session->internals.last_alert == + GNUTLS_A_CLOSE_NOTIFY) + { + gnutls_bye (connection->tls_session, GNUTLS_SHUT_WR); + connection->tls_session->internals.read_eof = 1; + connection->socket_fd = -1; + gnutls_deinit (connection->tls_session); + return MHD_YES; + } + /* non FATAL or WARNING */ + else if (connection->tls_session->internals.last_alert != + GNUTLS_AL_FATAL) + { +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Received TLS alert: %s\n", + gnutls_alert_get_name ((int) connection->tls_session-> + internals.last_alert)); +#endif + return MHD_YES; + } + /* FATAL */ + else if (connection->tls_session->internals.last_alert == + GNUTLS_AL_FATAL) + { + connection->tls_session->internals.resumable = RESUME_FALSE; + connection->tls_session->internals.valid_connection = VALID_FALSE; + connection->socket_fd = -1; + gnutls_deinit (connection->tls_session); + + return MHD_NO; + } + /* this should never execut */ + else + { +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Received unrecognized alert: %s\n", + connection->tls_session->internals.last_alert); +#endif + return MHD_NO; + } + + + /* forward application level content to MHD */ + case GNUTLS_APPLICATION_DATA: + return MHD_connection_handle_read (connection); + + case GNUTLS_HANDSHAKE: + ret = gnutls_handshake (connection->tls_session); + if (ret == 0) + { + connection->s_state = MHDS_HANDSHAKE_COMPLETE; + connection->state = MHD_CONNECTION_INIT; + } + /* set connection as closed */ + else + { +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Error: Handshake has failed (%s)\n", ret); +#endif + connection->s_state = MHDS_HANDSHAKE_FAILED; + gnutls_bye (connection->tls_session, GNUTLS_SHUT_WR); + gnutls_deinit (connection->tls_session); + connection->socket_fd = -1; + return MHD_NO; + + } + break; + case GNUTLS_INNER_APPLICATION: + break; + } + + return MHD_YES; +} + +int +MHDS_connection_handle_write (struct MHD_Connection *connection) +{ + connection->last_activity = time (NULL); + while (1) + { +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, "MHDS reached case: %d, l: %d, f: %s\n", + connection->s_state, __LINE__, __FUNCTION__); +#endif + switch (connection->s_state) + { + + /* these cases shouldn't occur */ + case MHDS_HANDSHAKE_COMPLETE: + case MHDS_CONNECTION_INIT: + // TODO do we have to write back a responce ? + case MHDS_HANDSHAKE_FAILED: + /* we should first exit MHDS_REPLY_SENDING */ + + case MHDS_CONNECTION_CLOSED: + if (connection->socket_fd != -1) + connection_close_error (connection); + return MHD_NO; + } + } + return MHD_YES; +} + +int +MHD_set_https_calbacks (struct MHD_Connection *connection) +{ + connection->recv_cls = &MHDS_con_read; + connection->send_cls = &MHDS_con_write; + connection->read_handler = &MHDS_connection_handle_read; + connection->write_handler = &MHD_connection_handle_write; + connection->idle_handler = &MHD_connection_handle_idle; +} diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c @@ -28,7 +28,9 @@ #include "response.h" #include "connection.h" #include "memorypool.h" -#include "gnutls.h" + +#include "gnutls_int.h" +#include "gnutls_datum.h" /** * Default connection limit. @@ -53,97 +55,86 @@ #define DEBUG_CONNECT MHD_NO #if HTTPS_SUPPORT -// TODO rm -static void -tls_log_func (int level, const char *str) -{ - fprintf (stdout, "|<%d>| %s", level, str); -} - -/** - * Initialize security aspects of the HTTPS daemon - */ +/* initialize security aspects of the HTTPS daemon */ static int -MHDS_init (struct MHD_Daemon *daemon) -{ - // TODO rm - gnutls_global_set_log_level (11); - gnutls_global_set_log_function (tls_log_func); - - gnutls_global_init (); - - /* Generate Diffie Hellman parameters - for use with DHE kx algorithms. */ - // TODO should we be initializing RSA params or DH params ? - gnutls_dh_params_init (&daemon->dh_params); - gnutls_dh_params_generate2 (daemon->dh_params, DH_BITS); - - // TODO rm NONE:+AES-256-CBC:+RSA:+SHA1:+COMP-NULL", NULL); - gnutls_priority_init (&daemon->priority_cache, - "NONE:+AES-256-CBC:+RSA:+SHA1:+COMP-NULL", NULL); - - /* setup server certificate */ - gnutls_certificate_allocate_credentials (&daemon->x509_cret); - - // TODO remove if unused - /* add trusted CAs to certificate */ - // gnutls_certificate_set_x509_trust_file(x509_cret, CAFILE,GNUTLS_X509_FMT_PEM); - - /* add Certificate revocation list to certificate */ - //gnutls_certificate_set_x509_crl_file(x509_cret, CRLFILE, GNUTLS_X509_FMT_PEM); - - /* sets a certificate private key pair */ - if (daemon->https_cert_path && daemon->https_key_path ) - { - /* test for private key & certificate file exsitance */ - FILE *cert_file = fopen (daemon->https_cert_path, "r"); - FILE *key_file = fopen (daemon->https_key_path, "r"); - if (key_file == NULL || cert_file == NULL) - { - printf ("missing cert files"); -#if HAVE_MESSAGES - MHD_DLOG (daemon, "Missing X.509 key or certificate file\n"); -#endif - free (daemon); - CLOSE (daemon->socket_fd); - return MHD_NO; - } - fclose (cert_file); - fclose (key_file); - gnutls_certificate_set_x509_key_file (daemon->x509_cret, - daemon->https_cert_path, - daemon->https_key_path, - GNUTLS_X509_FMT_PEM); - } - else if (daemon->https_mem_cert && daemon->https_mem_key ) - { - // TODO free - gnutls_datum_t * key = ( gnutls_datum_t * ) malloc (sizeof(gnutls_datum_t)); - gnutls_datum_t * cert = ( gnutls_datum_t * ) malloc (sizeof(gnutls_datum_t)); - - _gnutls_set_datum_m(key,daemon->https_mem_key,strlen (daemon->https_mem_key), &malloc); - _gnutls_set_datum_m(cert,daemon->https_mem_cert,strlen (daemon->https_mem_cert), &malloc); - - gnutls_certificate_set_x509_key_mem (daemon->x509_cret, cert, key, - GNUTLS_X509_FMT_PEM); - printf(""); - } - else - { -#if HAVE_MESSAGES - MHD_DLOG (daemon, "Failed to load certificate\n"); -#endif - return MHD_NO; - } +MHDS_init (struct MHD_Daemon *daemon){ + gnutls_global_set_log_function (MHD_tls_log_func); + /* TODO let user access log level */ + + /* setup server certificate */ + gnutls_certificate_allocate_credentials (&daemon->x509_cret); + + /* Generate Diffie Hellman parameters - for use with DHE kx algorithms. */ + // TODO should we be initializing RSA params or DH params ? + + gnutls_dh_params_init (&daemon->dh_params); + gnutls_dh_params_generate2 (daemon->dh_params, 1024); + + // TODO remove if unused + /* add trusted CAs to certificate */ + // gnutls_certificate_set_x509_trust_file(x509_cret, CAFILE,GNUTLS_X509_FMT_PEM); + + /* add Certificate revocation list to certificate */ + //gnutls_certificate_set_x509_crl_file(x509_cret, CRLFILE, GNUTLS_X509_FMT_PEM); + + /* sets a certificate private key pair */ + if (daemon->https_cert_path && daemon->https_key_path) + { + /* test for private key & certificate file exsitance */ + if (access (daemon->https_cert_path, R_OK)) + { + #if HAVE_MESSAGES + MHD_DLOG (daemon, "Missing X.509 certificate file\n"); + #endif + free (daemon); + CLOSE (daemon->socket_fd); + return -1; + } + + if (access (daemon->https_key_path, R_OK)) + { + #if HAVE_MESSAGES + MHD_DLOG (daemon, "Missing X.509 key file\n"); + #endif + free (daemon); + CLOSE (daemon->socket_fd); + return -1; + } + gnutls_certificate_set_x509_key_file (daemon->x509_cret, + daemon->https_cert_path, + daemon->https_key_path, + GNUTLS_X509_FMT_PEM); + } + else if (daemon->https_mem_cert && daemon->https_mem_key) + { + gnutls_datum_t *key = + (gnutls_datum_t *) malloc (sizeof (gnutls_datum_t)); + gnutls_datum_t *cert = + (gnutls_datum_t *) malloc (sizeof (gnutls_datum_t)); + + _gnutls_set_datum_m (key, daemon->https_mem_key, + strlen (daemon->https_mem_key), &malloc); + _gnutls_set_datum_m (cert, daemon->https_mem_cert, + strlen (daemon->https_mem_cert), &malloc); + + gnutls_certificate_set_x509_key_mem (daemon->x509_cret, cert, key, + GNUTLS_X509_FMT_PEM); + } + else + { + #if HAVE_MESSAGES + MHD_DLOG (daemon, "Failed to load certificate\n"); + #endif + return MHD_NO; + } - gnutls_certificate_set_dh_params (daemon->x509_cret, daemon->dh_params); + gnutls_certificate_set_dh_params (daemon->x509_cret, daemon->dh_params); - // TODO address error case return value - return MHD_YES; + // TODO address error case return value + return MHD_YES; } #endif - - /** * Obtain the select sets for this daemon. * @@ -257,7 +248,7 @@ MHD_handle_connection (void *data) #if 0 /* TODO rm if unused - gnutls parameter adapter , used to set gnutls pull function */ -long +static long gnutls_pull_param_adapter (void *connection, void *other, unsigned long i) { ssize_t bytes; @@ -268,7 +259,7 @@ gnutls_pull_param_adapter (void *connection, void *other, unsigned long i) } -long +static long gnutls_push_param_adapter (void *connection, const void *other, unsigned long i) { @@ -311,7 +302,7 @@ MHDS_handle_connection (void *data) gnutls_transport_set_ptr (tls_session, con->socket_fd); - MHD_handle_connection (data); + return MHD_handle_connection (data); } #endif @@ -454,21 +445,12 @@ MHD_accept_connection (struct MHD_Daemon *daemon) connection->daemon = daemon; /* set default connection handlers */ - connection->recv_cls = &MHD_con_read; - connection->send_cls = &MHD_con_write; - connection->read_handler = &MHD_connection_handle_read; - connection->write_handler = &MHD_connection_handle_write; - connection->idle_handler = &MHD_connection_handle_idle; + MHD_set_http_calbacks (connection); #if HTTPS_SUPPORT if (daemon->options & MHD_USE_SSL) { - /* set HTTPS connection handlers */ - connection->recv_cls = &MHDS_con_read; - connection->send_cls = &MHDS_con_write; - connection->read_handler = &MHDS_connection_handle_read; - connection->write_handler = &MHD_connection_handle_write; - connection->idle_handler = &MHD_connection_handle_idle; + MHD_set_https_calbacks (connection); } #endif @@ -739,6 +721,27 @@ MHD_select_thread (void *cls) return NULL; } +/* TODO unite with code in gnutls_priority.c */ +/* this is used to set HTTPS related daemon priorities */ +inline static int +_set_priority (priority_st * st, const int *list) +{ + int num = 0, i; + + while (list[num] != 0) + num++; + if (num > MAX_ALGOS) + num = MAX_ALGOS; + st->algorithms = num; + + for (i = 0; i < num; i++) + { + st->priority[i] = list[i]; + } + + return 0; +} + /** * Start a webserver on the given port. * @@ -758,7 +761,7 @@ MHD_start_daemon (unsigned int options, MHD_AccessHandlerCallback dh, void *dh_cls, ...) { const int on = 1; - struct MHD_Daemon *retVal; + struct MHD_Daemon * retVal; /* listeningss sockets used by the daemon */ int socket_fd; @@ -851,6 +854,13 @@ MHD_start_daemon (unsigned int options, retVal->max_connections = MHD_MAX_CONNECTIONS_DEFAULT; retVal->pool_size = MHD_POOL_SIZE_DEFAULT; retVal->connection_timeout = 0; /* no timeout */ + if (options & MHD_USE_SSL) + { + gnutls_global_init (); + gnutls_priority_init (&retVal->priority_cache, + "NONE:+AES-256-CBC:+RSA:+SHA1:+COMP-NULL", NULL); + } + /* initializes the argument pointer variable */ va_start (ap, dh_cls); @@ -890,6 +900,14 @@ MHD_start_daemon (unsigned int options, case MHD_OPTION_HTTPS_MEM_CERT: retVal->https_mem_cert = va_arg (ap, const char *); break; + case MHDS_KX_PRIORITY: + _set_priority (&retVal->priority_cache->kx, + va_arg (ap, const int *)); + break; + case MHDS_CIPHER_ALGORITHM: + _set_priority (&retVal->priority_cache->cipher, + va_arg (ap, const int *)); + break; default: #if HAVE_MESSAGES fprintf (stderr, diff --git a/src/daemon/https/errcodes.c b/src/daemon/https/errcodes.c @@ -15,7 +15,6 @@ typedef struct int error_index; } error_name; - static int compar (const void *_n1, const void *_n2) { @@ -23,43 +22,3 @@ compar (const void *_n1, const void *_n2) *n2 = (const error_name *) _n2; return strcmp (n1->name, n2->name); } - -//int -//main (int argc, char *argv[]) -//{ -// int i, j; -// const char *desc; -// const char *_name; -// error_name names_to_sort[400]; /* up to 400 names */ -// -// printf ("@table @code\n"); -// -// memset (names_to_sort, 0, sizeof (names_to_sort)); -// j = 0; -// for (i = 0; i > -400; i--) -// { -// _name = _gnutls_strerror (i); -// if (_name == NULL) -// continue; -// -// strcpy (names_to_sort[j].name, _name); -// names_to_sort[j].error_index = i; -// j++; -// } -// -// qsort (names_to_sort, j, sizeof (error_name), compar); -// -// for (i = 0; i < j; i++) -// { -// _name = names_to_sort[i].name; -// desc = gnutls_strerror (names_to_sort[i].error_index); -// if (desc == NULL || _name == NULL) -// continue; -// -// printf ("@item %s:\n%s\n\n", _name, desc); -// } -// -// printf ("@end table\n"); -// -// return 0; -//} diff --git a/src/daemon/https/includes/gnutls.h b/src/daemon/https/includes/gnutls.h @@ -93,8 +93,6 @@ extern "C" GNUTLS_KX_RSA_EXPORT, GNUTLS_KX_SRP_RSA, GNUTLS_KX_SRP_DSS, - GNUTLS_KX_PSK, - GNUTLS_KX_DHE_PSK } gnutls_kx_algorithm_t; typedef enum @@ -318,7 +316,7 @@ extern "C" typedef struct gnutls_x509_privkey_int *gnutls_rsa_params_t; /* XXX ugly. */ struct gnutls_priority_st; - typedef struct gnutls_priority_st *gnutls_priority_t; + typedef struct gnutls_priority_st * gnutls_priority_t; typedef struct { @@ -508,7 +506,7 @@ extern "C" /* if you just want some defaults, use the following. */ - int gnutls_priority_init( gnutls_priority_t*, const char *priority, const char** err_pos); + int gnutls_priority_init( gnutls_priority_t * , const char *priority, const char** err_pos); void gnutls_priority_deinit( gnutls_priority_t); int gnutls_priority_set(gnutls_session_t session, gnutls_priority_t); diff --git a/src/daemon/https/tls/auth_dh_common.c b/src/daemon/https/tls/auth_dh_common.c @@ -23,7 +23,7 @@ */ /* This file contains common stuff in Ephemeral Diffie Hellman (DHE) and - * Anonymous DH key exchange(DHA). These are used in the handshake procedure + * Anonymous DH key exchange(DHA). These are used in the handshake procedure * of the certificate and anoymous authentication. */ @@ -86,29 +86,7 @@ _gnutls_proc_dh_common_client_kx (gnutls_session_t session, _gnutls_mpi_release (&session->key->client_Y); _gnutls_mpi_release (&session->key->dh_secret); - - if (_gnutls_cipher_suite_get_kx_algo - (&session->security_parameters.current_cipher_suite) - != GNUTLS_KX_DHE_PSK) - { - ret = _gnutls_mpi_dprint (&session->key->key, session->key->KEY); - } - /* In DHE_PSK the key is set differently - else - { - gnutls_datum_t tmp_dh_key; - ret = _gnutls_mpi_dprint (&tmp_dh_key, session->key->KEY); - if (ret < 0) - { - gnutls_assert (); - return ret; - } - - ret = _gnutls_set_psk_session_key (session, &tmp_dh_key); - _gnutls_free_datum (&tmp_dh_key); - - } - */ + ret = _gnutls_mpi_dprint (&session->key->key, session->key->KEY); _gnutls_mpi_release (&session->key->KEY); @@ -170,27 +148,7 @@ _gnutls_gen_dh_common_client_kx (gnutls_session_t session, opaque ** data) _gnutls_mpi_release (&session->key->client_p); _gnutls_mpi_release (&session->key->client_g); - if (_gnutls_cipher_suite_get_kx_algo - (&session->security_parameters.current_cipher_suite) - != GNUTLS_KX_DHE_PSK) - { - ret = _gnutls_mpi_dprint (&session->key->key, session->key->KEY); - } - /* In DHE_PSK the key is set differently - else - { - gnutls_datum_t tmp_dh_key; - ret = _gnutls_mpi_dprint (&tmp_dh_key, session->key->KEY); - if (ret < 0) - { - gnutls_assert (); - goto error; - } - - ret = _gnutls_set_psk_session_key (session, &tmp_dh_key); - _gnutls_free_datum (&tmp_dh_key); - - }*/ + ret = _gnutls_mpi_dprint (&session->key->key, session->key->KEY); _gnutls_mpi_release (&session->key->KEY); diff --git a/src/daemon/https/tls/gnutls_algorithms.c b/src/daemon/https/tls/gnutls_algorithms.c @@ -29,7 +29,7 @@ /* x509 */ #include "common.h" -/* Cred type mappings to KX algorithms +/* Cred type mappings to KX algorithms * FIXME: The mappings are not 1-1. Some KX such as SRP_RSA require * more than one credentials type. */ @@ -57,12 +57,6 @@ static const gnutls_cred_map cred_mappings[] = { {GNUTLS_KX_DHE_RSA, GNUTLS_CRD_CERTIFICATE, GNUTLS_CRD_CERTIFICATE}, - {GNUTLS_KX_PSK, - GNUTLS_CRD_PSK, - GNUTLS_CRD_PSK}, - {GNUTLS_KX_DHE_PSK, - GNUTLS_CRD_PSK, - GNUTLS_CRD_PSK}, {GNUTLS_KX_SRP, GNUTLS_CRD_SRP, GNUTLS_CRD_SRP}, @@ -197,7 +191,7 @@ struct gnutls_cipher_entry }; typedef struct gnutls_cipher_entry gnutls_cipher_entry; -/* Note that all algorithms are in CBC or STREAM modes. +/* Note that all algorithms are in CBC or STREAM modes. * Do not add any algorithms in other modes (avoid modified algorithms). * View first: "The order of encryption and authentication for * protecting communications" by Hugo Krawczyk - CRYPTO 2001 @@ -614,34 +608,6 @@ static const gnutls_cipher_suite_entry cs_algorithms[] = { GNUTLS_MAC_SHA1, GNUTLS_TLS1), #endif - /* PSK */ - GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_PSK_SHA_ARCFOUR_SHA1, - GNUTLS_CIPHER_ARCFOUR, GNUTLS_KX_PSK, - GNUTLS_MAC_SHA1, GNUTLS_TLS1), - GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_PSK_SHA_3DES_EDE_CBC_SHA1, - GNUTLS_CIPHER_3DES_CBC, GNUTLS_KX_PSK, - GNUTLS_MAC_SHA1, GNUTLS_TLS1), - GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_PSK_SHA_AES_128_CBC_SHA1, - GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_PSK, - GNUTLS_MAC_SHA1, GNUTLS_TLS1), - GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_PSK_SHA_AES_256_CBC_SHA1, - GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_PSK, - GNUTLS_MAC_SHA1, GNUTLS_TLS1), - - /* DHE-PSK */ - GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_DHE_PSK_SHA_ARCFOUR_SHA1, - GNUTLS_CIPHER_ARCFOUR, GNUTLS_KX_DHE_PSK, - GNUTLS_MAC_SHA1, GNUTLS_TLS1), - GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_DHE_PSK_SHA_3DES_EDE_CBC_SHA1, - GNUTLS_CIPHER_3DES_CBC, GNUTLS_KX_DHE_PSK, - GNUTLS_MAC_SHA1, GNUTLS_TLS1), - GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_DHE_PSK_SHA_AES_128_CBC_SHA1, - GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_DHE_PSK, - GNUTLS_MAC_SHA1, GNUTLS_TLS1), - GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_DHE_PSK_SHA_AES_256_CBC_SHA1, - GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_DHE_PSK, - GNUTLS_MAC_SHA1, GNUTLS_TLS1), - /* SRP */ GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_SRP_SHA_3DES_EDE_CBC_SHA1, GNUTLS_CIPHER_3DES_CBC, GNUTLS_KX_SRP, @@ -1689,8 +1655,8 @@ _gnutls_qsort (gnutls_session_t session, compar); } -/* a compare function for KX algorithms (using priorities). - * For use with qsort +/* a compare function for KX algorithms (using priorities). + * For use with qsort */ static int _gnutls_compare_algo (gnutls_session_t session, @@ -1894,7 +1860,7 @@ _gnutls_supported_ciphersuites (gnutls_session_t session, #define MIN_PRIVATE_COMP_ALGO 0xEF -/* returns the TLS numbers of the compression methods we support +/* returns the TLS numbers of the compression methods we support */ #define SUPPORTED_COMPRESSION_METHODS session->internals.priorities.compression.algorithms int diff --git a/src/daemon/https/tls/gnutls_global.c b/src/daemon/https/tls/gnutls_global.c @@ -27,10 +27,19 @@ #include <libtasn1.h> #include <gnutls_dh.h> +/* this is used in order to make the multi-threaded initialization call to libgcrypt */ +#include <pthread.h> +#include <gcrypt.h> +/* TODO fix : needed by GCRY_THREAD_OPTION_PTHREAD_IMPL but missing otherwise */ +#define ENOMEM 12 /* Out of memory */ + #ifdef HAVE_WINSOCK # include <winsock2.h> #endif + +GCRY_THREAD_OPTION_PTHREAD_IMPL; + #include "gettext.h" #define gnutls_log_func LOG_FUNC @@ -57,7 +66,8 @@ ASN1_TYPE _gnutls_gnutls_asn; * gnutls_log_func is of the form, * void (*gnutls_log_func)( int level, const char*); **/ -void gnutls_global_set_log_function(gnutls_log_func log_func) +void +gnutls_global_set_log_function (gnutls_log_func log_func) { _gnutls_log_func = log_func; } @@ -74,7 +84,8 @@ void gnutls_global_set_log_function(gnutls_log_func log_func) * Use a log level over 10 to enable all debugging options. * **/ -void gnutls_global_set_log_level(int level) +void +gnutls_global_set_log_level (int level) { _gnutls_log_level = level; } @@ -83,21 +94,20 @@ void gnutls_global_set_log_level(int level) /* default logging function */ static void dlog (int level, const char *str) - { - fputs (str, stderr); - } +{ + fputs (str, stderr); +} #endif extern gnutls_alloc_function gnutls_secure_malloc; extern gnutls_alloc_function gnutls_malloc; extern gnutls_free_function gnutls_free; -extern int (*_gnutls_is_secure_memory)(const void *); +extern int (*_gnutls_is_secure_memory) (const void *); extern gnutls_realloc_function gnutls_realloc; -extern char *(*gnutls_strdup)(const char *); -extern void *(*gnutls_calloc)(size_t, - size_t); +extern char *(*gnutls_strdup) (const char *); +extern void *(*gnutls_calloc) (size_t, size_t); -int _gnutls_is_secure_mem_null(const void *); +int _gnutls_is_secure_mem_null (const void *); /** * gnutls_global_set_mem_functions - This function sets the memory allocation functions @@ -116,13 +126,14 @@ int _gnutls_is_secure_mem_null(const void *); * This function must be called before gnutls_global_init() is called. * **/ -void gnutls_global_set_mem_functions(gnutls_alloc_function alloc_func, - gnutls_alloc_function - secure_alloc_func, - gnutls_is_secure_function - is_secure_func, - gnutls_realloc_function realloc_func, - gnutls_free_function free_func) +void +gnutls_global_set_mem_functions (gnutls_alloc_function alloc_func, + gnutls_alloc_function + secure_alloc_func, + gnutls_is_secure_function + is_secure_func, + gnutls_realloc_function realloc_func, + gnutls_free_function free_func) { gnutls_secure_malloc = secure_alloc_func; gnutls_malloc = alloc_func; @@ -152,10 +163,10 @@ void gnutls_global_set_mem_functions(gnutls_alloc_function alloc_func, #ifdef DEBUG static void _gnutls_gcry_log_handler (void *dummy, int level, - const char *fmt, va_list list) - { - _gnutls_log (fmt, list); - } + const char *fmt, va_list list) +{ + _gnutls_log (fmt, list); +} #endif static int _gnutls_init = 0; @@ -190,7 +201,8 @@ static int _gnutls_init = 0; * memory leak is also an option. * **/ -int gnutls_global_init(void) +int +gnutls_global_init (void) { int result = 0; int res; @@ -200,41 +212,62 @@ int gnutls_global_init(void) return; #if HAVE_WINSOCK + { + WORD requested; + WSADATA data; + int err; + + requested = MAKEWORD (1, 1); + err = WSAStartup (requested, &data); + if (err != 0) + { + _gnutls_debug_log ("WSAStartup failed: %d.\n", err); + return GNUTLS_E_LIBRARY_VERSION_MISMATCH; + } + + if (data.wVersion < requested) + { + _gnutls_debug_log ("WSAStartup version check failed (%d < %d).\n", + data.wVersion, requested); + WSACleanup (); + return GNUTLS_E_LIBRARY_VERSION_MISMATCH; + } + } +#endif + + + // bindtextdomain("mhd", "./"); + + if (gcry_control (GCRYCTL_ANY_INITIALIZATION_P) == 0) { - WORD requested; - WSADATA data; - int err; + const char *p; - requested = MAKEWORD (1, 1); - err = WSAStartup (requested, &data); - if (err != 0) - { - _gnutls_debug_log ("WSAStartup failed: %d.\n", err); - return GNUTLS_E_LIBRARY_VERSION_MISMATCH; - } + /* to enable multi-threading this call must precede any other call made to libgcrypt */ + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); - if (data.wVersion < requested) + /* set p to point at the required version of gcrypt */ + p = strchr(MHD_GCRYPT_VERSION, ':'); + if (p == NULL) + p = MHD_GCRYPT_VERSION; + else + p++; + + /* this call initializes libgcrypt */ + if (gcry_check_version(p) == NULL) { - _gnutls_debug_log ("WSAStartup version check failed (%d < %d).\n", - data.wVersion, requested); - WSACleanup (); - return GNUTLS_E_LIBRARY_VERSION_MISMATCH; + gnutls_assert(); + _gnutls_debug_log("Checking for libgcrypt failed '%s'\n", p); + return GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARY; } - } -#endif - // TODO rm ? bindtextdomain(PACKAGE, LOCALEDIR); - - if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0) - { /* for gcrypt in order to be able to allocate memory */ - gcry_set_allocation_handler(gnutls_malloc, gnutls_secure_malloc, - _gnutls_is_secure_memory, gnutls_realloc, - gnutls_free); + gcry_set_allocation_handler (gnutls_malloc, gnutls_secure_malloc, + _gnutls_is_secure_memory, gnutls_realloc, + gnutls_free); /* gcry_control (GCRYCTL_DISABLE_INTERNAL_LOCKING, NULL, 0); */ - gcry_control(GCRYCTL_INITIALIZATION_FINISHED, NULL, 0); + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, NULL, 0); #ifdef DEBUG /* applications may want to override that, so we only use @@ -244,7 +277,7 @@ int gnutls_global_init(void) #endif } - if (gc_init() != GC_OK) + if (gc_init () != GC_OK) { gnutls_assert (); _gnutls_debug_log ("Initializing crypto backend failed\n"); @@ -267,16 +300,16 @@ int gnutls_global_init(void) return result; } - res = asn1_array2tree(gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL); + res = asn1_array2tree (gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL); if (res != ASN1_SUCCESS) { - asn1_delete_structure(&_gnutls_pkix1_asn); - result = _gnutls_asn2err(res); + asn1_delete_structure (&_gnutls_pkix1_asn); + result = _gnutls_asn2err (res); return result; } /* Initialize the gcrypt (if used random generator) */ - gc_pseudo_random(&c, 1); + gc_pseudo_random (&c, 1); return result; } @@ -291,16 +324,17 @@ int gnutls_global_init(void) * gnutls_global_init() for more information. * **/ -void gnutls_global_deinit(void) +void +gnutls_global_deinit (void) { if (_gnutls_init == 1) { #if HAVE_WINSOCK WSACleanup (); #endif - asn1_delete_structure(&_gnutls_gnutls_asn); - asn1_delete_structure(&_gnutls_pkix1_asn); - gc_done(); + asn1_delete_structure (&_gnutls_gnutls_asn); + asn1_delete_structure (&_gnutls_pkix1_asn); + gc_done (); } _gnutls_init--; } @@ -322,8 +356,9 @@ void gnutls_global_deinit(void) * PULL_FUNC is of the form, * ssize_t (*gnutls_pull_func)(gnutls_transport_ptr_t, void*, size_t); **/ -void gnutls_transport_set_pull_function(gnutls_session_t session, - gnutls_pull_func pull_func) +void +gnutls_transport_set_pull_function (gnutls_session_t session, + gnutls_pull_func pull_func) { session->internals._gnutls_pull_func = pull_func; } @@ -342,8 +377,9 @@ void gnutls_transport_set_pull_function(gnutls_session_t session, * PUSH_FUNC is of the form, * ssize_t (*gnutls_push_func)(gnutls_transport_ptr_t, const void*, size_t); **/ -void gnutls_transport_set_push_function(gnutls_session_t session, - gnutls_push_func push_func) +void +gnutls_transport_set_push_function (gnutls_session_t session, + gnutls_push_func push_func) { session->internals._gnutls_push_func = push_func; } @@ -366,9 +402,10 @@ void gnutls_transport_set_push_function(gnutls_session_t session, * %NULL is passed to this function no check is done and only the * version string is returned. **/ -const char * gnutls_check_version(const char *req_version) +const char * +gnutls_check_version (const char *req_version) { - if (!req_version || strverscmp(req_version, VERSION) <= 0) + if (!req_version || strverscmp (req_version, VERSION) <= 0) return VERSION; return NULL; diff --git a/src/daemon/https/tls/gnutls_int.h b/src/daemon/https/tls/gnutls_int.h @@ -28,9 +28,9 @@ #include <defines.h> -#include <gnutls.h> -#include <extra.h> -#include <gnutls_mem.h> +#include "gnutls.h" +#include "extra.h" +#include "gnutls_mem.h" /* FIXME: delete this once opencdk has reentrant keyring functions */ @@ -210,7 +210,7 @@ struct gnutls_key_st */ void *auth_info; gnutls_credentials_type_t auth_info_type; - int auth_info_size; /* needed in order to store to db for restoring + int auth_info_size; /* needed in order to store to db for restoring */ uint8_t crypt_algo; @@ -424,7 +424,7 @@ typedef struct typedef struct { gnutls_buffer application_data_buffer; /* holds data to be delivered to application layer */ - gnutls_buffer handshake_hash_buffer; /* used to keep the last received handshake + gnutls_buffer handshake_hash_buffer; /* used to keep the last received handshake * message */ mac_hd_t handshake_mac_handle_sha; /* hash of the handshake messages */ mac_hd_t handshake_mac_handle_md5; /* hash of the handshake messages */ @@ -500,10 +500,12 @@ typedef struct int expire_time; /* after expire_time seconds this session will expire */ struct mod_auth_st_int *auth_struct; /* used in handshake packets and KX algorithms */ + + /* TODO rm */ int v2_hello; /* 0 if the client hello is v3+. * non-zero if we got a v2 hello. */ - /* keeps the headers of the handshake packet + /* keeps the headers of the handshake packet */ handshake_header_buffer_st handshake_header_buffer; @@ -653,8 +655,7 @@ struct gnutls_session_int gnutls_key_st key; }; -/* functions - */ +/* functions */ void _gnutls_set_current_version(gnutls_session_t session, gnutls_protocol_t version); diff --git a/src/daemon/https/tls/gnutls_priority.c b/src/daemon/https/tls/gnutls_priority.c @@ -32,10 +32,6 @@ #define MAX_ELEMENTS 48 -static void break_comma_list (char *etag, - char **broken_etag, - int *elements, int max_elements, char sep); - /** * gnutls_cipher_set_priority - Sets the priority on the ciphers supported by gnutls. * @session: is a #gnutls_session_t structure. @@ -87,7 +83,6 @@ _set_priority (priority_st * st, const int *list) } return 0; - } /** @@ -215,7 +210,8 @@ gnutls_certificate_type_set_priority (gnutls_session_t session, } static const int protocol_priority[] = { GNUTLS_TLS1_1, - GNUTLS_TLS1_0, GNUTLS_SSL3, + GNUTLS_TLS1_0, + GNUTLS_SSL3, 0 }; @@ -336,10 +332,6 @@ int gnutls_priority_init (gnutls_priority_t * priority_cache, const char *priorities, const char **err_pos) { - int broken_list_size, i, j; - char *darg; - int algo; - *priority_cache = gnutls_calloc (1, sizeof (struct gnutls_priority_st)); if (*priority_cache == NULL) { @@ -354,8 +346,8 @@ gnutls_priority_init (gnutls_priority_t * priority_cache, _set_priority (&(*priority_cache)->mac, mac_priority_secure); _set_priority (&(*priority_cache)->cert_type, cert_type_priority); _set_priority (&(*priority_cache)->compression, comp_priority); - (*priority_cache)->no_padding = 0; + (*priority_cache)->no_padding = 0; return 0; } @@ -412,40 +404,6 @@ gnutls_priority_set_direct (gnutls_session_t session, return 0; } -/* Breaks a list of "xxx", "yyy", to a character array, of - * MAX_COMMA_SEP_ELEMENTS size; Note that the given string is modified. - */ -static void -break_comma_list (char *etag, - char **broken_etag, - int *elements, int max_elements, char sep) -{ - char *p = etag; - if (sep == 0) - sep = ','; - - *elements = 0; - - do - { - broken_etag[*elements] = p; - - (*elements)++; - - p = strchr (p, sep); - if (p) - { - *p = 0; - p++; /* move to next entry and skip white - * space. - */ - while (*p == ' ') - p++; - } - } - while (p != NULL && *elements < max_elements); -} - /** * gnutls_set_default_priority - Sets some default priority on the cipher suites supported by gnutls. * @session: is a #gnutls_session_t structure. diff --git a/src/daemon/https/tls/gnutls_session_pack.c b/src/daemon/https/tls/gnutls_session_pack.c @@ -49,21 +49,6 @@ static int unpack_certificate_auth_info (gnutls_session_t, const gnutls_datum_t * packed_session); -static int unpack_srp_auth_info (gnutls_session_t session, - const gnutls_datum_t * packed_session); -static int pack_srp_auth_info (gnutls_session_t session, - gnutls_datum_t * packed_session); - -static int unpack_psk_auth_info (gnutls_session_t session, - const gnutls_datum_t * packed_session); -static int pack_psk_auth_info (gnutls_session_t session, - gnutls_datum_t * packed_session); - -static int unpack_anon_auth_info (gnutls_session_t session, - const gnutls_datum_t * packed_session); -static int pack_anon_auth_info (gnutls_session_t session, - gnutls_datum_t * packed_session); - static int unpack_security_parameters (gnutls_session_t session, const gnutls_datum_t * packed_session); static int pack_security_parameters (gnutls_session_t session, @@ -230,7 +215,7 @@ _gnutls_session_unpack (gnutls_session_t session, } -/* Format: +/* Format: * 1 byte the credentials type * 4 bytes the size of the whole structure * DH stuff diff --git a/src/daemon/internal.c b/src/daemon/internal.c @@ -42,6 +42,13 @@ MHD_DLOG (const struct MHD_Daemon *daemon, const char *format, ...) VFPRINTF (stderr, format, va); va_end (va); } + +void +MHD_tls_log_func (int level, const char *str) +{ + fprintf (stdout, "|<%d>| %s", level, str); +} + #endif /** diff --git a/src/daemon/internal.h b/src/daemon/internal.h @@ -60,15 +60,13 @@ */ #define MHD_BUF_INC_SIZE 2048 -/* TLS Diffie-Hellman parameter */ -#define DH_BITS 1024 - #if HAVE_MESSAGES /** * fprintf-like helper function for logging debug * messages. */ void MHD_DLOG (const struct MHD_Daemon *daemon, const char *format, ...); +void MHD_tls_log_func (int level, const char *str); #endif /** @@ -288,6 +286,11 @@ enum MHD_CONNECTION_STATE }; + +/** + * States in a state machine for a secure SSL/TLS connection. + * + */ enum MHDS_CONNECTION_STATE { /* initial HTTPS state */ @@ -297,20 +300,6 @@ enum MHDS_CONNECTION_STATE MHDS_HANDSHAKE_COMPLETE, - /* while receiving an HTTP request through the encrypted channel */ - MHDS_REQUEST_READING, - - /* msg waiting to be forwarded to the internal HTTP daemon */ - MHDS_REQUEST_READ, - - /* http msg waiting to be sent */ - MHDS_REPLY_READY, - - /* while receiving an HTTP request through the encrypted channel */ - MHDS_REPLY_SENDING, - - MHDS_REPLY_SENT, - MHDS_CONNECTION_CLOSED }; @@ -558,9 +547,9 @@ struct MHD_Connection int (*send_cls) (struct MHD_Connection * connection); #if HTTPS_SUPPORT + /* TODO rename as this might be an SSL connection */ gnutls_session_t tls_session; #endif - }; struct MHD_Daemon diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h @@ -349,6 +349,7 @@ enum MHD_OPTION */ MHD_OPTION_PER_IP_CONNECTION_LIMIT = 5, +#if HTTPS_SUPPORT // TODO rename /** * Filename for the private key (key.pem) to be used by the @@ -383,6 +384,22 @@ enum MHD_OPTION * This should be used in conjunction with 'MHD_OPTION_HTTPS_MEM_KEY'. */ MHD_OPTION_HTTPS_MEM_CERT = 9, + + + /* + * Memory pointer to a zero terminated int array representing the + * cipher priority order to which the HTTPS daemon should adhere. + * "const int *" argument. + */ + MHDS_CIPHER_ALGORITHM, + + /* + * Memory pointer to a zero terminated int array representing the + * key exchange algorithm priority order to which the HTTPS daemon should adhere. + * "const int *" argument. + */ + MHDS_KX_PRIORITY, +#endif }; /** diff --git a/src/testcurl/https/Makefile.am b/src/testcurl/https/Makefile.am @@ -1,6 +1,6 @@ SUBDIRS = . -AM_CPPFLAGS = -ggdb \ +AM_CPPFLAGS = \ -I$(top_srcdir)/src/daemon/https/includes \ -I$(top_srcdir)/src/daemon \ -I$(top_srcdir)/src/include diff --git a/src/testcurl/https/daemon_https_test_get.c b/src/testcurl/https/daemon_https_test_get.c @@ -21,7 +21,7 @@ /** * @file daemon_HTTPS_test_get.c * @brief Testcase for libmicrohttpd GET operations - * @author lv-426 + * @author Sagie Amir */ #include "config.h" @@ -43,6 +43,11 @@ #define PAGE_NOT_FOUND "<html><head><title>File not found</title></head><body>File not found</body></html>" +#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" + /* Test Certificate */ const char cert_pem[] = "-----BEGIN CERTIFICATE-----\n" @@ -173,9 +178,8 @@ http_ahc (void *cls, struct MHD_Connection *connection, * @param test_fd: file to attempt transfering */ static int -test_HTTPS_Get (FILE * test_fd, char * cipher_suite, int proto_version) +test_daemon_get (FILE * test_fd, char *cipher_suite, int proto_version) { - struct MHD_Daemon *d; CURL *c; struct CBC cbc; CURLcode errornum; @@ -192,7 +196,7 @@ test_HTTPS_Get (FILE * test_fd, char * cipher_suite, int proto_version) mem_test_file_local = malloc (len); fseek (test_fd, 0, SEEK_SET); - if (fread (mem_test_file_local, sizeof(char), len, test_fd) != len) + 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", @@ -202,30 +206,20 @@ test_HTTPS_Get (FILE * test_fd, char * cipher_suite, int proto_version) if (NULL == (cbc.buf = malloc (sizeof (char) * len))) { - fclose (test_fd); - fprintf (stderr, "Error: failed to read test file. %s\n", - strerror (errno)); - return -1; - } + fclose (test_fd); + fprintf (stderr, "Error: failed to read test file. %s\n", + strerror (errno)); + return -1; + } cbc.size = len; cbc.pos = 0; - /* setup test */ - 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, key_pem, - MHD_OPTION_HTTPS_MEM_CERT, cert_pem, MHD_OPTION_END); - - if (d == NULL) - return 2; - /* construct url - this might use doc_path */ sprintf (url, "%s%s/%s", "https://localhost:42433", doc_path, test_file_name); c = curl_easy_init (); - //curl_easy_setopt (c, CURLOPT_VERBOSE, 1); + // curl_easy_setopt (c, CURLOPT_VERBOSE, 1); 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, 10L); @@ -252,36 +246,107 @@ test_HTTPS_Get (FILE * test_fd, char * cipher_suite, int proto_version) fprintf (stderr, "curl_easy_perform failed: `%s'\n", curl_easy_strerror (errornum)); curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 4; + return errornum; } curl_easy_cleanup (c); - MHD_stop_daemon (d); if (memcmp (cbc.buf, mem_test_file_local, len) != 0) { - fprintf (stderr, "Error: local file & received file differ. %s\n"); - return 8; + fprintf (stderr, "Error: local file & received file differ.\n"); + return -1; } 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, key_pem, + MHD_OPTION_HTTPS_MEM_CERT, 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 server works with 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]; + + sprintf (cert_path, "%s/%s", get_current_dir_name (), "cert.pem"); + sprintf (key_path, "%s/%s", get_current_dir_name (), "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 (key_pem, strlen (key_pem), sizeof (char), key_fd); + fwrite (cert_pem, strlen (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); + + remove (cert_path); + remove (key_path); + return ret; +} + /* setup a temporary transfer test file */ FILE * setupTestFile () { FILE *test_fd; - if ( NULL == (test_fd = fopen (test_file_name, "w+"))) + 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)) + 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)); @@ -302,19 +367,27 @@ main (int argc, char *const *argv) { FILE *test_fd; unsigned int errorCount = 0; - if ((test_fd = setupTestFile ()) == NULL ) + + gnutls_global_set_log_level (0); + + if ((test_fd = setupTestFile ()) == NULL) { - return 16; + fprintf (stderr, MHD_E_TEST_FILE_CREAT); + return -1; } if (0 != curl_global_init (CURL_GLOBAL_ALL)) { fprintf (stderr, "Error (code: %u)\n", errorCount); - return 32; + return -1; } - errorCount += test_HTTPS_Get (test_fd, "AES256-SHA", CURL_SSLVERSION_SSLv3); - errorCount += test_HTTPS_Get (test_fd, "AES256-SHA", CURL_SSLVERSION_TLSv1); + 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_TLSv1); if (errorCount != 0) fprintf (stderr, "Error (code: %u)\n", errorCount); @@ -322,6 +395,7 @@ main (int argc, char *const *argv) curl_global_cleanup (); fclose (test_fd); - + remove (test_file_name); + return errorCount != 0; } diff --git a/src/testcurl/https/mhds_test_session_info.c b/src/testcurl/https/mhds_test_session_info.c @@ -21,7 +21,7 @@ /** * @file mhds_test_session_info.c * @brief Testcase for libmicrohttpd GET operations - * @author lv-426 + * @author Sagie Amir */ #include "config.h"