connection_https.c

Go to the documentation of this file.
00001 /*
00002      This file is part of libmicrohttpd
00003      (C) 2007, 2008 Daniel Pittman and Christian Grothoff
00004 
00005      This library is free software; you can redistribute it and/or
00006      modify it under the terms of the GNU Lesser General Public
00007      License as published by the Free Software Foundation; either
00008      version 2.1 of the License, or (at your option) any later version.
00009 
00010      This library is distributed in the hope that it will be useful,
00011      but WITHOUT ANY WARRANTY; without even the implied warranty of
00012      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013      Lesser General Public License for more details.
00014 
00015      You should have received a copy of the GNU Lesser General Public
00016      License along with this library; if not, write to the Free Software
00017      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00018 
00019 */
00020 
00029 #include "internal.h"
00030 #include "connection.h"
00031 #include "memorypool.h"
00032 #include "response.h"
00033 #include "reason_phrase.h"
00034 
00035 /* get opaque type */
00036 #include "gnutls_int.h"
00037 #include "gnutls_record.h"
00038 
00039 /* TODO #include rm "gnutls_errors.h" */
00040 #include "gnutls_errors.h"
00041 
00051 const union MHD_ConnectionInfo *
00052 MHD_get_connection_info (struct MHD_Connection *connection,
00053                          enum MHD_ConnectionInfoType infoType, ...)
00054 {
00055   if (connection->tls_session == NULL)
00056     return NULL;
00057   switch (infoType)
00058     {
00059 #if HTTPS_SUPPORT
00060     case MHD_CONNECTION_INFO_CIPHER_ALGO:
00061       return (const union MHD_ConnectionInfo *) &connection->tls_session->
00062         security_parameters.read_bulk_cipher_algorithm;
00063     case MHD_CONNECTION_INFO_KX_ALGO:
00064       return (const union MHD_ConnectionInfo *) &connection->tls_session->
00065         security_parameters.kx_algorithm;
00066     case MHD_CONNECTION_INFO_CREDENTIALS_TYPE:
00067       return (const union MHD_ConnectionInfo *) &connection->tls_session->
00068         key->cred->algorithm;
00069     case MHD_CONNECTION_INFO_MAC_ALGO:
00070       return (const union MHD_ConnectionInfo *) &connection->tls_session->
00071         security_parameters.read_mac_algorithm;
00072     case MHD_CONNECTION_INFO_COMPRESSION_METHOD:
00073       return (const union MHD_ConnectionInfo *) &connection->tls_session->
00074         security_parameters.read_compression_algorithm;
00075     case MHD_CONNECTION_INFO_PROTOCOL:
00076       return (const union MHD_ConnectionInfo *) &connection->tls_session->
00077         security_parameters.version;
00078     case MHD_CONNECTION_INFO_CERT_TYPE:
00079       return (const union MHD_ConnectionInfo *) &connection->tls_session->
00080         security_parameters.cert_type;
00081 #endif
00082     default:
00083       return NULL;
00084     };
00085 }
00086 
00097 static void
00098 MHD_tls_connection_close (struct MHD_Connection *connection,
00099                           enum MHD_RequestTerminationCode termination_code)
00100 {
00101   MHD__gnutls_bye (connection->tls_session, GNUTLS_SHUT_WR);
00102   connection->tls_session->internals.read_eof = 1;
00103   MHD_connection_close(connection,
00104                        termination_code);
00105 }
00106 
00117 static int
00118 MHD_tls_connection_handle_idle (struct MHD_Connection *connection)
00119 {
00120   unsigned int timeout;
00121 
00122 #if DEBUG_STATES
00123   MHD_DLOG (connection->daemon, "%s: state: %s\n",
00124             __FUNCTION__, MHD_state_to_string (connection->state));
00125 #endif
00126   timeout = connection->daemon->connection_timeout;
00127   if ((connection->socket_fd != -1) && (timeout != 0)
00128       && (time (NULL) - timeout > connection->last_activity))
00129     {
00130       MHD_tls_connection_close (connection,
00131                                 MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
00132       return MHD_NO;
00133     }
00134   switch (connection->state)
00135     {
00136       /* on newly created connections we might reach here before any reply has been received */
00137     case MHD_TLS_CONNECTION_INIT:
00138       return MHD_YES;
00139       /* close connection if necessary */
00140     case MHD_CONNECTION_CLOSED:
00141       if (connection->socket_fd != -1)
00142         MHD_tls_connection_close (connection,
00143                                   MHD_REQUEST_TERMINATED_COMPLETED_OK);
00144       return MHD_NO;
00145     case MHD_TLS_HANDSHAKE_FAILED:
00146       MHD_tls_connection_close (connection,
00147                                 MHD_REQUEST_TERMINATED_WITH_ERROR);
00148       return MHD_NO;
00149       /* some HTTP state */
00150     default:
00151       return MHD_connection_handle_idle (connection);
00152     }
00153   return MHD_YES;
00154 }
00155 
00173 static int
00174 MHD_tls_connection_handle_read (struct MHD_Connection *connection)
00175 {
00176   int ret;
00177   unsigned char msg_type;
00178 
00179   connection->last_activity = time (NULL);
00180   if (connection->state == MHD_CONNECTION_CLOSED ||
00181       connection->state == MHD_TLS_HANDSHAKE_FAILED)
00182     return MHD_NO;
00183 
00184 #if DEBUG_STATES
00185   MHD_DLOG (connection->daemon, "%s: state: %s\n",
00186             __FUNCTION__, MHD_state_to_string (connection->state));
00187 #endif
00188 
00189   /* discover content type */
00190   if (RECV (connection->socket_fd, &msg_type, 1, MSG_PEEK) == -1)
00191     {
00192 #if HAVE_MESSAGES
00193       MHD_DLOG (connection->daemon, "Failed to peek into TLS content type\n");
00194 #endif
00195       return MHD_NO;
00196     }
00197 
00198   switch (msg_type)
00199     {
00200       /* check for handshake messages first */
00201     case GNUTLS_HANDSHAKE:
00202       /* negotiate handshake only while in INIT & HELLO_REQUEST states */
00203       if (connection->state == MHD_TLS_CONNECTION_INIT ||
00204           connection->state == MHD_TLS_HELLO_REQUEST)
00205         {
00206           ret = MHD__gnutls_handshake (connection->tls_session);
00207           if (ret == 0)
00208             {
00209               /* set connection state to enable HTTP processing */
00210               connection->state = MHD_CONNECTION_INIT;
00211               break;
00212             }
00213           /* set connection as closed */
00214           else
00215             {
00216 #if HAVE_MESSAGES
00217               MHD_DLOG (connection->daemon,
00218                         "Error: Handshake has failed (%d)\n", ret);
00219 #endif
00220               connection->state = MHD_TLS_HANDSHAKE_FAILED;
00221               return MHD_NO;
00222             }
00223         }
00224       /* a handshake message has been received out of bound */
00225       else
00226         {
00227 #if HAVE_MESSAGES
00228           MHD_DLOG (connection->daemon,
00229                     "Error: received handshake message out of context\n");
00230 #endif
00231           MHD_tls_connection_close (connection,
00232                                     MHD_REQUEST_TERMINATED_WITH_ERROR);
00233           return MHD_NO;
00234         }
00235 
00236       /* ignore any out of bound change chiper spec messages */
00237     case GNUTLS_CHANGE_CIPHER_SPEC:
00238       MHD_tls_connection_close (connection,
00239                                 MHD_REQUEST_TERMINATED_WITH_ERROR);
00240       return MHD_NO;
00241 
00242     case GNUTLS_ALERT:
00243       /*
00244        * this call of MHD_gtls_recv_int expects 0 bytes read.
00245        * done to decrypt alert message
00246        */
00247       MHD_gtls_recv_int (connection->tls_session, GNUTLS_ALERT,
00248                          GNUTLS_HANDSHAKE_FINISHED, 0, 0);
00249 
00250       /* CLOSE_NOTIFY */
00251       if (connection->tls_session->internals.last_alert ==
00252           GNUTLS_A_CLOSE_NOTIFY)
00253         {
00254           connection->state = MHD_CONNECTION_CLOSED;
00255           return MHD_YES;
00256         }
00257       /* non FATAL or WARNING */
00258       else if (connection->tls_session->internals.last_alert_level !=
00259                GNUTLS_AL_FATAL)
00260         {
00261 #if HAVE_MESSAGES
00262           MHD_DLOG (connection->daemon,
00263                     "Received TLS alert: %s\n",
00264                     MHD__gnutls_alert_get_name ((int) connection->
00265                                                 tls_session->internals.
00266                                                 last_alert));
00267 #endif
00268           return MHD_YES;
00269         }
00270       /* FATAL */
00271       else if (connection->tls_session->internals.last_alert_level ==
00272                GNUTLS_AL_FATAL)
00273         {
00274           MHD_tls_connection_close (connection,
00275                                     MHD_REQUEST_TERMINATED_WITH_ERROR);
00276           return MHD_NO;
00277         }
00278       /* this should never execute */
00279       else
00280         {
00281 #if HAVE_MESSAGES
00282           MHD_DLOG (connection->daemon,
00283                     "Received unrecognized alert: %d\n",
00284                     connection->tls_session->internals.last_alert);
00285 #endif
00286           return MHD_NO;
00287         }
00288 
00289 
00290       /* forward application level content to MHD */
00291     case GNUTLS_APPLICATION_DATA:
00292       return MHD_connection_handle_read (connection);
00293 
00294     case GNUTLS_INNER_APPLICATION:
00295       break;
00296     default:
00297 #if HAVE_MESSAGES
00298       MHD_DLOG (connection->daemon,
00299                 "Error: unrecognized TLS message type: %d, connection state: %s. l: %d, f: %s\n",
00300                 msg_type, MHD_state_to_string (connection->state), __LINE__,
00301                 __FUNCTION__);
00302 #endif
00303       /* close connection upon reception of unrecognized message type */
00304       MHD_tls_connection_close (connection,
00305                                 MHD_REQUEST_TERMINATED_WITH_ERROR);
00306       return MHD_NO;
00307     }
00308 
00309   return MHD_YES;
00310 }
00311 
00321 static int
00322 MHD_tls_connection_handle_write (struct MHD_Connection *connection)
00323 {
00324   connection->last_activity = time (NULL);
00325 
00326 #if DEBUG_STATES
00327   MHD_DLOG (connection->daemon, "%s: state: %s\n",
00328             __FUNCTION__, MHD_state_to_string (connection->state));
00329 #endif
00330 
00331   switch (connection->state)
00332     {
00333     case MHD_CONNECTION_CLOSED:
00334     case MHD_TLS_HANDSHAKE_FAILED:
00335       return MHD_NO;
00336       /* some HTTP connection state */
00337     default:
00338       return MHD_connection_handle_write (connection);
00339     }
00340   return MHD_NO;
00341 }
00342 
00347 void
00348 MHD_set_https_calbacks (struct MHD_Connection *connection)
00349 {
00350   connection->read_handler = &MHD_tls_connection_handle_read;
00351   connection->write_handler = &MHD_tls_connection_handle_write;
00352   connection->idle_handler = &MHD_tls_connection_handle_idle;
00353 }
00354 
00355 /* end of connection_https.c */

Generated on Sun Nov 16 16:53:03 2008 for GNU libmicrohttpd by  doxygen 1.5.1