Home | History | Annotate | Download | only in microhttpd
      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2007, 2008, 2010 Daniel Pittman and Christian Grothoff
      4 
      5      This library is free software; you can redistribute it and/or
      6      modify it under the terms of the GNU Lesser General Public
      7      License as published by the Free Software Foundation; either
      8      version 2.1 of the License, or (at your option) any later version.
      9 
     10      This library is distributed in the hope that it will be useful,
     11      but WITHOUT ANY WARRANTY; without even the implied warranty of
     12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13      Lesser General Public License for more details.
     14 
     15      You should have received a copy of the GNU Lesser General Public
     16      License along with this library; if not, write to the Free Software
     17      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     18 
     19 */
     20 
     21 /**
     22  * @file connection_https.c
     23  * @brief  Methods for managing SSL/TLS connections. This file is only
     24  *         compiled if ENABLE_HTTPS is set.
     25  * @author Sagie Amir
     26  * @author Christian Grothoff
     27  */
     28 
     29 #include "internal.h"
     30 #include "connection.h"
     31 #include "memorypool.h"
     32 #include "response.h"
     33 #include "reason_phrase.h"
     34 #include <openssl/ssl.h>
     35 
     36 
     37 /**
     38  * Give gnuTLS chance to work on the TLS handshake.
     39  *
     40  * @param connection connection to handshake on
     41  * @return #MHD_YES on error or if the handshake is progressing
     42  *         #MHD_NO if the handshake has completed successfully
     43  *         and we should start to read/write data
     44  */
     45 static int
     46 run_tls_handshake (struct MHD_Connection *connection)
     47 {
     48   int ret;
     49   connection->last_activity = MHD_monotonic_time();
     50   if (connection->state == MHD_TLS_CONNECTION_INIT)
     51     {
     52       ret = SSL_accept (connection->tls_session);
     53       if (ret == 1)
     54 	{
     55 	  /* set connection state to enable HTTP processing */
     56 	  connection->state = MHD_CONNECTION_INIT;
     57 	  return MHD_YES;
     58 	}
     59       int error = SSL_get_error (connection->tls_session, ret);
     60       if ( (error == SSL_ERROR_WANT_READ) ||
     61 	   (error == SSL_ERROR_WANT_WRITE) )
     62 	{
     63 	  /* handshake not done */
     64 	  return MHD_YES;
     65 	}
     66       /* handshake failed */
     67 #if HAVE_MESSAGES
     68       MHD_DLOG (connection->daemon,
     69 		"Error: received handshake message out of context\n");
     70 #endif
     71       MHD_connection_close (connection,
     72 			    MHD_REQUEST_TERMINATED_WITH_ERROR);
     73       return MHD_YES;
     74     }
     75   return MHD_NO;
     76 }
     77 
     78 
     79 /**
     80  * This function handles a particular SSL/TLS connection when
     81  * it has been determined that there is data to be read off a
     82  * socket. Message processing is done by message type which is
     83  * determined by peeking into the first message type byte of the
     84  * stream.
     85  *
     86  * Error message handling: all fatal level messages cause the
     87  * connection to be terminated.
     88  *
     89  * Application data is forwarded to the underlying daemon for
     90  * processing.
     91  *
     92  * @param connection the source connection
     93  * @return always #MHD_YES (we should continue to process the connection)
     94  */
     95 static int
     96 MHD_tls_connection_handle_read (struct MHD_Connection *connection)
     97 {
     98   if (MHD_YES == run_tls_handshake (connection))
     99     return MHD_YES;
    100   return MHD_connection_handle_read (connection);
    101 }
    102 
    103 
    104 /**
    105  * This function was created to handle writes to sockets when it has
    106  * been determined that the socket can be written to. This function
    107  * will forward all write requests to the underlying daemon unless
    108  * the connection has been marked for closing.
    109  *
    110  * @return always #MHD_YES (we should continue to process the connection)
    111  */
    112 static int
    113 MHD_tls_connection_handle_write (struct MHD_Connection *connection)
    114 {
    115   if (MHD_YES == run_tls_handshake (connection))
    116     return MHD_YES;
    117   return MHD_connection_handle_write (connection);
    118 }
    119 
    120 
    121 /**
    122  * This function was created to handle per-connection processing that
    123  * has to happen even if the socket cannot be read or written to.  All
    124  * implementations (multithreaded, external select, internal select)
    125  * call this function.
    126  *
    127  * @param connection being handled
    128  * @return #MHD_YES if we should continue to process the
    129  *         connection (not dead yet), #MHD_NO if it died
    130  */
    131 static int
    132 MHD_tls_connection_handle_idle (struct MHD_Connection *connection)
    133 {
    134   unsigned int timeout;
    135 
    136 #if DEBUG_STATES
    137   MHD_DLOG (connection->daemon,
    138             "%s: state: %s\n",
    139             __FUNCTION__,
    140             MHD_state_to_string (connection->state));
    141 #endif
    142   timeout = connection->connection_timeout;
    143   if ( (timeout != 0) && (timeout <= (MHD_monotonic_time() - connection->last_activity)))
    144     MHD_connection_close (connection,
    145 			  MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
    146   switch (connection->state)
    147     {
    148       /* on newly created connections we might reach here before any reply has been received */
    149     case MHD_TLS_CONNECTION_INIT:
    150       break;
    151       /* close connection if necessary */
    152     case MHD_CONNECTION_CLOSED:
    153       SSL_shutdown (connection->tls_session);
    154       return MHD_connection_handle_idle (connection);
    155     default:
    156       if ( (0 != SSL_pending (connection->tls_session)) &&
    157 	   (MHD_YES != MHD_tls_connection_handle_read (connection)) )
    158 	return MHD_YES;
    159       return MHD_connection_handle_idle (connection);
    160     }
    161 #if EPOLL_SUPPORT
    162   return MHD_connection_epoll_update_ (connection);
    163 #else
    164   return MHD_YES;
    165 #endif
    166 }
    167 
    168 
    169 /**
    170  * Set connection callback function to be used through out
    171  * the processing of this secure connection.
    172  *
    173  * @param connection which callbacks should be modified
    174  */
    175 void
    176 MHD_set_https_callbacks (struct MHD_Connection *connection)
    177 {
    178   connection->read_handler = &MHD_tls_connection_handle_read;
    179   connection->write_handler = &MHD_tls_connection_handle_write;
    180   connection->idle_handler = &MHD_tls_connection_handle_idle;
    181 }
    182 
    183 /* end of connection_https.c */
    184