libmicrohttpd

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

commit 8538fe9783d1de18742ce7113860cfe1d6b558c5
parent 7afe06474b2f59ea7816d444d435d5e4c15b40f8
Author: lv-426 <oxcafebaby@yahoo.com>
Date:   Sun, 29 Jun 2008 21:33:00 +0000

- gnutls alert handling
- simplified HTTPS example use
- added alert level to tls-session structs
- some gnutls removed code

Diffstat:
Msrc/daemon/connection.c | 65+++++++++++++++++++++++++++++++++++++++++++++--------------------
Msrc/daemon/daemon.c | 12++++++------
Msrc/daemon/https/https_common.c | 175-------------------------------------------------------------------------------
Msrc/daemon/https/tls/gnutls_db.c | 2+-
Msrc/daemon/https/tls/gnutls_int.h | 1+
Msrc/daemon/https/tls/gnutls_record.c | 6+++---
Dsrc/daemon/https/tls/gnutls_session.h | 23-----------------------
Msrc/examples/https_server_example.c | 157+++----------------------------------------------------------------------------
8 files changed, 62 insertions(+), 379 deletions(-)

diff --git a/src/daemon/connection.c b/src/daemon/connection.c @@ -1531,8 +1531,8 @@ MHDS_connection_handle_read (struct MHD_Connection *connection) return MHD_NO; /* discover content type */ - unsigned char msg_type[7]; - if (recv (connection->socket_fd, msg_type, 1, MSG_PEEK) == -1) + 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"); @@ -1540,39 +1540,68 @@ MHDS_connection_handle_read (struct MHD_Connection *connection) return MHD_NO; } - switch (msg_type[0]) + switch (msg_type) { case GNUTLS_CHANGE_CIPHER_SPEC: break; case GNUTLS_ALERT: - /* find out if alert is fatal */ - if (recv (connection->socket_fd, msg_type, 7, MSG_PEEK) == -1) + /* + * 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, - "Failed to peek into TLS alert level\n"); + "Received TLS alert: %s\n", + gnutls_alert_get_name ((int) connection->tls_session-> + internals.last_alert)); #endif - return MHD_NO; + 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); - if (msg_type[5] == GNUTLS_AL_FATAL) + return MHD_NO; + } + /* this should never execut */ + else { #if HAVE_MESSAGES - MHD_DLOG (connection->daemon, "Received TLS alert: %s\n", - gnutls_alert_get_name ((int) msg_type[6])); + MHD_DLOG (connection->daemon, + "Received unrecognized alert: %s\n", + connection->tls_session->internals.last_alert); #endif - gnutls_bye (connection->tls_session, GNUTLS_SHUT_WR); - connection->socket_fd = -1; - gnutls_deinit (connection->tls_session); return MHD_NO; } + /* forward application level content to MHD */ case GNUTLS_APPLICATION_DATA: return MHD_connection_handle_read (connection); - - // TODO impl + // TODO impl case GNUTLS_HANDSHAKE: break; case GNUTLS_INNER_APPLICATION: @@ -1621,7 +1650,6 @@ MHD_connection_handle_write (struct MHD_Connection *connection) { struct MHD_Response *response; int ret; - connection->last_activity = time (NULL); while (1) { @@ -1775,7 +1803,6 @@ int MHDS_connection_handle_write (struct MHD_Connection *connection) { connection->last_activity = time (NULL); - while (1) { #if HAVE_MESSAGES @@ -1796,7 +1823,7 @@ MHDS_connection_handle_write (struct MHD_Connection *connection) connection->s_state = MHDS_REPLY_SENDING; do_write (connection); break; - + case MHDS_CONNECTION_CLOSED: if (connection->socket_fd != -1) connection_close_error (connection); @@ -1832,7 +1859,6 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) unsigned int timeout; const char *end; char *line; - while (1) { #if DEBUG_STATES @@ -2154,7 +2180,6 @@ MHDS_connection_handle_idle (struct MHD_Connection *connection) const char *end; char *line; ssize_t msgLength; - while (1) { #if HAVE_MESSAGES diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c @@ -237,16 +237,14 @@ MHDS_handle_connection (void *data) /* set connection as closed */ fprintf (stderr, "*** Handshake has failed (%s)\n\n", gnutls_strerror (ret)); - gnutls_deinit (tls_session); con->s_state = MHDS_HANDSHAKE_FAILED; + gnutls_bye (con->tls_session, GNUTLS_SHUT_WR); + gnutls_deinit (tls_session); con->socket_fd = 1; return MHD_NO; - + } - // printf ("TLS Handshake completed\n"); - - MHD_handle_connection (data); } #endif @@ -958,7 +956,9 @@ MHDS_init (struct MHD_Daemon *daemon) gnutls_dh_params_init (&daemon->dh_params); gnutls_dh_params_generate2 (daemon->dh_params, DH_BITS); - gnutls_priority_init (&daemon->priority_cache, "NORMAL", 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); diff --git a/src/daemon/https/https_common.c b/src/daemon/https/https_common.c @@ -246,7 +246,6 @@ print_x509_info (gnutls_session_t session, const char *hostname) } #ifdef ENABLE_OPENPGP - void print_openpgp_info (gnutls_session_t session, const char *hostname) { @@ -356,7 +355,6 @@ print_openpgp_info (gnutls_session_t session, const char *hostname) } } - #endif void @@ -662,179 +660,6 @@ print_license (void) stdout); } -static int depr_printed = 0; -#define DEPRECATED if (depr_printed==0) { \ - fprintf(stderr, "This method of specifying algorithms is deprecated. Please use the --priority option.\n"); \ - depr_printed = 1; \ - } - -void -parse_protocols (char **protocols, int protocols_size, int *protocol_priority) -{ - int i, j; - - if (protocols != NULL && protocols_size > 0) - { - DEPRECATED; - - for (j = i = 0; i < protocols_size; i++) - { - if (strncasecmp (protocols[i], "SSL", 3) == 0) - protocol_priority[j++] = GNUTLS_SSL3; - else if (strncasecmp (protocols[i], "TLS1.1", 6) == 0) - protocol_priority[j++] = GNUTLS_TLS1_1; - else if (strncasecmp (protocols[i], "TLS1.2", 6) == 0) - protocol_priority[j++] = GNUTLS_TLS1_2; - else if (strncasecmp (protocols[i], "TLS", 3) == 0) - protocol_priority[j++] = GNUTLS_TLS1_0; - else - fprintf (stderr, "Unknown protocol: '%s'\n", protocols[i]); - } - protocol_priority[j] = 0; - } -} - -void -parse_ciphers (char **ciphers, int nciphers, int *cipher_priority) -{ - int j, i; - - if (ciphers != NULL && nciphers > 0) - { - DEPRECATED; - for (j = i = 0; i < nciphers; i++) - { - if (strncasecmp (ciphers[i], "AES-2", 5) == 0) - cipher_priority[j++] = GNUTLS_CIPHER_AES_256_CBC; - else if (strncasecmp (ciphers[i], "AES", 3) == 0) - cipher_priority[j++] = GNUTLS_CIPHER_AES_128_CBC; - else if (strncasecmp (ciphers[i], "3DE", 3) == 0) - cipher_priority[j++] = GNUTLS_CIPHER_3DES_CBC; - else if (strcasecmp (ciphers[i], "ARCFOUR-40") == 0) - cipher_priority[j++] = GNUTLS_CIPHER_ARCFOUR_40; - else if (strcasecmp (ciphers[i], "ARCFOUR") == 0) - cipher_priority[j++] = GNUTLS_CIPHER_ARCFOUR_128; -#ifdef ENABLE_CAMELLIA - else if (strncasecmp (ciphers[i], "CAMELLIA-2", 10) == 0) - cipher_priority[j++] = GNUTLS_CIPHER_CAMELLIA_256_CBC; - else if (strncasecmp (ciphers[i], "CAM", 3) == 0) - cipher_priority[j++] = GNUTLS_CIPHER_CAMELLIA_128_CBC; -#endif - else if (strncasecmp (ciphers[i], "NUL", 3) == 0) - cipher_priority[j++] = GNUTLS_CIPHER_NULL; - else - fprintf (stderr, "Unknown cipher: '%s'\n", ciphers[i]); - } - cipher_priority[j] = 0; - } -} - -void -parse_macs (char **macs, int nmacs, int *mac_priority) -{ - int i, j; - - if (macs != NULL && nmacs > 0) - { - DEPRECATED; - for (j = i = 0; i < nmacs; i++) - { - if (strncasecmp (macs[i], "MD5", 3) == 0) - mac_priority[j++] = GNUTLS_MAC_MD5; - else if (strncasecmp (macs[i], "SHA256", 6) == 0) - mac_priority[j++] = GNUTLS_MAC_SHA256; - else if (strncasecmp (macs[i], "SHA", 3) == 0) - mac_priority[j++] = GNUTLS_MAC_SHA1; - else - fprintf (stderr, "Unknown MAC: '%s'\n", macs[i]); - } - mac_priority[j] = 0; - } -} - -void -parse_ctypes (char **ctype, int nctype, int *cert_type_priority) -{ - int i, j; - - if (ctype != NULL && nctype > 0) - { - DEPRECATED; - for (j = i = 0; i < nctype; i++) - { - if (strncasecmp (ctype[i], "OPE", 3) == 0) - cert_type_priority[j++] = GNUTLS_CRT_OPENPGP; - else if (strncasecmp (ctype[i], "X", 1) == 0) - cert_type_priority[j++] = GNUTLS_CRT_X509; - else - fprintf (stderr, "Unknown certificate type: '%s'\n", ctype[i]); - } - cert_type_priority[j] = 0; - } -} - -void -parse_kx (char **kx, int nkx, int *kx_priority) -{ - int i, j; - - if (kx != NULL && nkx > 0) - { - DEPRECATED; - for (j = i = 0; i < nkx; i++) - { - if (strcasecmp (kx[i], "SRP") == 0) - kx_priority[j++] = GNUTLS_KX_SRP; - else if (strcasecmp (kx[i], "SRP-RSA") == 0) - kx_priority[j++] = GNUTLS_KX_SRP_RSA; - else if (strcasecmp (kx[i], "SRP-DSS") == 0) - kx_priority[j++] = GNUTLS_KX_SRP_DSS; - else if (strcasecmp (kx[i], "RSA") == 0) - kx_priority[j++] = GNUTLS_KX_RSA; - else if (strcasecmp (kx[i], "PSK") == 0) - kx_priority[j++] = GNUTLS_KX_PSK; - else if (strcasecmp (kx[i], "DHE-PSK") == 0) - kx_priority[j++] = GNUTLS_KX_DHE_PSK; - else if (strcasecmp (kx[i], "RSA-EXPORT") == 0) - kx_priority[j++] = GNUTLS_KX_RSA_EXPORT; - else if (strncasecmp (kx[i], "DHE-RSA", 7) == 0) - kx_priority[j++] = GNUTLS_KX_DHE_RSA; - else if (strncasecmp (kx[i], "DHE-DSS", 7) == 0) - kx_priority[j++] = GNUTLS_KX_DHE_DSS; - else if (strncasecmp (kx[i], "ANON", 4) == 0) - kx_priority[j++] = GNUTLS_KX_ANON_DH; - else - fprintf (stderr, "Unknown key exchange: '%s'\n", kx[i]); - } - kx_priority[j] = 0; - } -} - -void -parse_comp (char **comp, int ncomp, int *comp_priority) -{ - int i, j; - - if (comp != NULL && ncomp > 0) - { - DEPRECATED; - for (j = i = 0; i < ncomp; i++) - { - if (strncasecmp (comp[i], "NUL", 3) == 0) - comp_priority[j++] = GNUTLS_COMP_NULL; - else if (strncasecmp (comp[i], "ZLI", 3) == 0) - comp_priority[j++] = GNUTLS_COMP_DEFLATE; - else if (strncasecmp (comp[i], "DEF", 3) == 0) - comp_priority[j++] = GNUTLS_COMP_DEFLATE; - else if (strncasecmp (comp[i], "LZO", 3) == 0) - comp_priority[j++] = GNUTLS_COMP_LZO; - else - fprintf (stderr, "Unknown compression: '%s'\n", comp[i]); - } - comp_priority[j] = 0; - } -} - void sockets_init (void) { diff --git a/src/daemon/https/tls/gnutls_db.c b/src/daemon/https/tls/gnutls_db.c @@ -28,7 +28,7 @@ #include "gnutls_int.h" #include "gnutls_errors.h" -#include "gnutls_session.h" +// #include "gnutls_session.h" #include <gnutls_db.h> #include "debug.h" #include <gnutls_session_pack.h> diff --git a/src/daemon/https/tls/gnutls_int.h b/src/daemon/https/tls/gnutls_int.h @@ -447,6 +447,7 @@ typedef struct int read_eof; /* non-zero if we have received a closure alert. */ int last_alert; /* last alert received */ + int last_alert_level; /* last alert level */ /* The last handshake messages sent or received. */ diff --git a/src/daemon/https/tls/gnutls_record.c b/src/daemon/https/tls/gnutls_record.c @@ -657,6 +657,7 @@ static int record_check_type(gnutls_session_t session, data[0], data[1], gnutls_alert_get_name ((int) data[1])); session->internals.last_alert = data[1]; + session->internals.last_alert_level = data[0]; /* if close notify is received and * the alert is not fatal @@ -674,7 +675,6 @@ static int record_check_type(gnutls_session_t session, /* if the alert is FATAL or WARNING * return the apropriate message */ - gnutls_assert (); ret = GNUTLS_E_WARNING_ALERT_RECEIVED; if (data[0] == GNUTLS_AL_FATAL) @@ -968,8 +968,7 @@ ssize_t _gnutls_recv_int(gnutls_session_t session, return ret; } - /* decrypt the data we got. - */ + /* decrypt the data we got. */ ret = _gnutls_decrypt(session, ciphertext, length, tmp.data, tmp.size, recv_type); if (ret < 0) @@ -1015,6 +1014,7 @@ ssize_t _gnutls_recv_int(gnutls_session_t session, return GNUTLS_E_RECORD_LIMIT_REACHED; } + /* check type - this will also invalidate sessions if a fatal alert has been received */ ret = record_check_type(session, recv_type, type, htype, tmp.data, decrypted_length); if (ret < 0) diff --git a/src/daemon/https/tls/gnutls_session.h b/src/daemon/https/tls/gnutls_session.h @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation - * - * Author: Nikos Mavrogiannopoulos - * - * This file is part of GNUTLS. - * - * The GNUTLS 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 - * - */ diff --git a/src/examples/https_server_example.c b/src/examples/https_server_example.c @@ -36,7 +36,7 @@ #include "config.h" #include <microhttpd.h> -#include "internal.h" +#include <sys/stat.h> #include <stdlib.h> #ifndef MINGW @@ -53,29 +53,13 @@ #define KEYFILE "key.pem" #define CERTFILE "cert.pem" + // TODO remove if unused #define CAFILE "ca.pem" #define CRLFILE "crl.pem" #define PAGE_NOT_FOUND "<html><head><title>File not found</title></head><body>File not found</body></html>" -gnutls_session_t -initialize_tls_session (struct MHD_Connection *connection) -{ - gnutls_session_t session; - - gnutls_init (&session, GNUTLS_SERVER); - - /* sets cipher priorities */ - gnutls_priority_set (session, connection->daemon->priority_cache); - - /* set needed credentials for certificate authentication. */ - gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, - connection->daemon->x509_cret); - - return session; -} - static int file_reader (void *cls, size_t pos, char *buf, int max) { @@ -85,122 +69,6 @@ file_reader (void *cls, size_t pos, char *buf, int max) return fread (buf, 1, max, file); } -/* HTTPS access handler call back */ -static int -https_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) -{ - /* loopback HTTP socket */ - int loopback_sd, err; - ssize_t ret; - struct sockaddr_in servaddr4; - const struct sockaddr *servaddr; - struct sockaddr_in loopback_sa; - socklen_t addrlen; - - gnutls_session_t session; - static int aptr; - struct MHD_Response *response; - char buffer[BUF_SIZE]; - - printf ("accepted connection from %d\n", connection->addr->sin_addr); - - session = initialize_tls_session (connection); - - gnutls_transport_set_ptr (session, connection->socket_fd); - - ret = gnutls_handshake (session); - - if (ret < 0) - { - /* set connection as closed */ - connection->socket_fd = 1; - gnutls_deinit (session); - fprintf (stderr, "*** Handshake has failed (%s)\n\n", - gnutls_strerror (ret)); - return MHD_NO; - } - - printf ("TLS Handshake completed\n"); - connection->state = MHDS_HANDSHAKE_COMPLETE; - - /* initialize loopback socket */ - loopback_sd = socket (AF_INET, SOCK_STREAM, 0); - memset (&loopback_sa, '\0', sizeof (loopback_sa)); - loopback_sa.sin_family = AF_INET; - - // TODO solve magic number issue - the http's daemons port must be shared with the https daemon - rosolve data sharing point - loopback_sa.sin_port = htons (50000); - inet_pton (AF_INET, "127.0.0.1", &loopback_sa.sin_addr); - - /* connect loopback socket */ - err = connect (loopback_sd, (struct sockaddr *) &loopback_sa, - sizeof (loopback_sa)); - if (err < 0) - { - // TODO err handle - fprintf (stderr, "Error : failed to create TLS loopback socket\n"); - exit (1); - } - - /* - * This loop pipes data received through the TLS tunnel into the loopback connection. - * message encryption/decryption is acheived via 'gnutls_record_send' & gnutls_record_recv calls. - */ - memset (buffer, 0, BUF_SIZE); - if (gnutls_record_recv (session, buffer, BUF_SIZE) < 0) - { - fprintf (stderr, "\n*** Received corrupted " - "data(%d). Closing the connection.\n\n", ret); - connection->socket_fd = -1; - gnutls_deinit (session); - return MHD_NO; - } - - if (write (loopback_sd, buffer, BUF_SIZE) < 0) - { - printf ("failed to write to TLS loopback socket\n"); - connection->socket_fd = -1; - gnutls_deinit (session); - return MHD_NO; - } - - for (;;) - { - memset (buffer, 0, BUF_SIZE); - - ret = read (loopback_sd, buffer, BUF_SIZE); - - if (ret < 0) - { - printf ("failed to read from TLS loopback socket\n"); - break; - } - - if (ret == 0) - { - break; - } - - /* echo data back to the client */ - ret = gnutls_record_send (session, buffer, ret); - if (ret < 0) - { - printf ("failed to write to TLS socket\n"); - break; - } - } - /* mark connection as closed */ - connection->socket_fd = -1; - gnutls_deinit (session); - - return MHD_YES; -} - /* HTTP access handler call back */ static int http_ahc (void *cls, @@ -225,7 +93,7 @@ http_ahc (void *cls, return MHD_YES; } *ptr = NULL; /* reset when done */ - + file = fopen (url, "r"); if (file == NULL) { @@ -247,17 +115,16 @@ http_ahc (void *cls, } return ret; } - + int main (int argc, char *const *argv) { char keyfile[255] = KEYFILE; char certfile[255] = CERTFILE; - struct MHD_Daemon *HTTP_daemon; struct MHD_Daemon *TLS_daemon; /* look for HTTPS arguments */ - if (argc < 6) + if (argc < 5) { printf ("Usage : %s HTTP-PORT SECONDS-TO-RUN HTTPS-PORT KEY-FILE CERT-FILE\n", @@ -268,20 +135,10 @@ main (int argc, char *const *argv) // TODO check if this is truly necessary - disallow usage of the blocking /dev/random */ // gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0); - HTTP_daemon = - MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, - atoi (argv[1]), NULL, NULL, &http_ahc, NULL, MHD_OPTION_END); - - if (HTTP_daemon == NULL) - { - printf ("Error: failed to start HTTP_daemon"); - return 1; - } - TLS_daemon = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG | MHD_USE_SSL, atoi (argv[3]), NULL, - NULL, &https_ahc, + NULL, &http_ahc, NULL, MHD_OPTION_CONNECTION_TIMEOUT, 256, MHD_OPTION_HTTPS_KEY_PATH, argv[4], MHD_OPTION_HTTPS_CERT_PATH, argv[5], @@ -295,8 +152,6 @@ main (int argc, char *const *argv) sleep (atoi (argv[2])); - MHD_stop_daemon (HTTP_daemon); - MHD_stop_daemon (TLS_daemon); return 0;