gnutls_record.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation
00003  *
00004  * Author: Nikos Mavrogiannopoulos
00005  *
00006  * This file is part of GNUTLS.
00007  *
00008  * The GNUTLS library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public License
00010  * as published by the Free Software Foundation; either version 2.1 of
00011  * the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
00021  * USA
00022  *
00023  */
00024 
00025 /* Functions that are record layer specific, are included in this file.
00026  */
00027 
00028 #include "gnutls_int.h"
00029 #include "gnutls_errors.h"
00030 #include "debug.h"
00031 #include "gnutls_cipher.h"
00032 #include "gnutls_buffers.h"
00033 #include "gnutls_handshake.h"
00034 #include "gnutls_hash_int.h"
00035 #include "gnutls_cipher_int.h"
00036 #include "gnutls_algorithms.h"
00037 #include "gnutls_auth_int.h"
00038 #include "gnutls_num.h"
00039 #include "gnutls_record.h"
00040 #include "gnutls_datum.h"
00041 #include "ext_max_record.h"
00042 #include <gnutls_state.h>
00043 #include <gnutls_dh.h>
00044 
00051 enum MHD_GNUTLS_Protocol
00052 MHD__gnutls_protocol_get_version (MHD_gtls_session_t session)
00053 {
00054   return session->security_parameters.version;
00055 }
00056 
00057 void
00058 MHD_gtls_set_current_version (MHD_gtls_session_t session,
00059                               enum MHD_GNUTLS_Protocol version)
00060 {
00061   session->security_parameters.version = version;
00062 }
00063 
00076 void
00077 MHD__gnutls_transport_set_lowat (MHD_gtls_session_t session, int num)
00078 {
00079   session->internals.lowat = num;
00080 }
00081 
00091 void
00092 MHD__gnutls_transport_set_ptr (MHD_gtls_session_t session,
00093                                MHD_gnutls_transport_ptr_t ptr)
00094 {
00095   session->internals.transport_recv_ptr = ptr;
00096   session->internals.transport_send_ptr = ptr;
00097 }
00098 
00132 int
00133 MHD__gnutls_bye (MHD_gtls_session_t session, MHD_gnutls_close_request_t how)
00134 {
00135   int ret = 0;
00136 
00137   switch (STATE)
00138     {
00139     case STATE0:
00140     case STATE60:
00141       ret = MHD_gtls_io_write_flush (session);
00142       STATE = STATE60;
00143       if (ret < 0)
00144         {
00145           MHD_gnutls_assert ();
00146           return ret;
00147         }
00148 
00149     case STATE61:
00150       ret =
00151         MHD__gnutls_alert_send (session, GNUTLS_AL_WARNING,
00152                                 GNUTLS_A_CLOSE_NOTIFY);
00153       STATE = STATE61;
00154       if (ret < 0)
00155         {
00156           MHD_gnutls_assert ();
00157           return ret;
00158         }
00159 
00160     case STATE62:
00161       STATE = STATE62;
00162       if (how == GNUTLS_SHUT_RDWR)
00163         {
00164           do
00165             {
00166               MHD_gtls_io_clear_peeked_data (session);
00167               ret = MHD_gtls_recv_int (session, GNUTLS_ALERT, -1, NULL, 0);
00168             }
00169           while (ret == GNUTLS_E_GOT_APPLICATION_DATA);
00170 
00171           if (ret >= 0)
00172             session->internals.may_not_read = 1;
00173 
00174           if (ret < 0)
00175             {
00176               MHD_gnutls_assert ();
00177               return ret;
00178             }
00179         }
00180       STATE = STATE62;
00181 
00182       break;
00183     default:
00184       MHD_gnutls_assert ();
00185       return GNUTLS_E_INTERNAL_ERROR;
00186     }
00187 
00188   STATE = STATE0;
00189 
00190   session->internals.may_not_write = 1;
00191   return 0;
00192 }
00193 
00194 inline static void
00195 session_invalidate (MHD_gtls_session_t session)
00196 {
00197   session->internals.valid_connection = VALID_FALSE;
00198 }
00199 
00200 inline static void
00201 session_unresumable (MHD_gtls_session_t session)
00202 {
00203   session->internals.resumable = RESUME_FALSE;
00204 }
00205 
00206 /* returns 0 if session is valid
00207  */
00208 inline static int
00209 session_is_valid (MHD_gtls_session_t session)
00210 {
00211   if (session->internals.valid_connection == VALID_FALSE)
00212     return GNUTLS_E_INVALID_SESSION;
00213 
00214   return 0;
00215 }
00216 
00217 /* Copies the record version into the headers. The
00218  * version must have 2 bytes at least.
00219  */
00220 inline static void
00221 copy_record_version (MHD_gtls_session_t session,
00222                      MHD_gnutls_handshake_description_t htype,
00223                      opaque version[2])
00224 {
00225   enum MHD_GNUTLS_Protocol lver;
00226 
00227   if (htype != GNUTLS_HANDSHAKE_CLIENT_HELLO
00228       || session->internals.default_record_version[0] == 0)
00229     {
00230       lver = MHD__gnutls_protocol_get_version (session);
00231 
00232       version[0] = MHD_gtls_version_get_major (lver);
00233       version[1] = MHD_gtls_version_get_minor (lver);
00234     }
00235   else
00236     {
00237       version[0] = session->internals.default_record_version[0];
00238       version[1] = session->internals.default_record_version[1];
00239     }
00240 }
00241 
00242 /* This function behaves exactly like write(). The only difference is
00243  * that it accepts, the MHD_gtls_session_t and the content_type_t of data to
00244  * send (if called by the user the Content is specific)
00245  * It is intended to transfer data, under the current session.
00246  *
00247  * Oct 30 2001: Removed capability to send data more than MAX_RECORD_SIZE.
00248  * This makes the function much easier to read, and more error resistant
00249  * (there were cases were the old function could mess everything up).
00250  * --nmav
00251  *
00252  * This function may accept a NULL pointer for data, and 0 for size, if
00253  * and only if the previous send was interrupted for some reason.
00254  *
00255  */
00256 ssize_t
00257 MHD_gtls_send_int (MHD_gtls_session_t session,
00258                    content_type_t type,
00259                    MHD_gnutls_handshake_description_t htype,
00260                    const void *_data, size_t sizeofdata)
00261 {
00262   uint8_t *cipher;
00263   int cipher_size;
00264   int retval, ret;
00265   int data2send_size;
00266   uint8_t headers[5];
00267   const uint8_t *data = _data;
00268 
00269   /* Do not allow null pointer if the send buffer is empty.
00270    * If the previous send was interrupted then a null pointer is
00271    * ok, and means to resume.
00272    */
00273   if (session->internals.record_send_buffer.length == 0 && (sizeofdata == 0
00274                                                             && _data == NULL))
00275     {
00276       MHD_gnutls_assert ();
00277       return GNUTLS_E_INVALID_REQUEST;
00278     }
00279 
00280   if (type != GNUTLS_ALERT)     /* alert messages are sent anyway */
00281     if (session_is_valid (session) || session->internals.may_not_write != 0)
00282       {
00283         MHD_gnutls_assert ();
00284         return GNUTLS_E_INVALID_SESSION;
00285       }
00286 
00287   headers[0] = type;
00288 
00289   /* Use the default record version, if it is
00290    * set.
00291    */
00292   copy_record_version (session, htype, &headers[1]);
00293 
00294   MHD__gnutls_record_log
00295     ("REC[%x]: Sending Packet[%d] %s(%d) with length: %d\n", session,
00296      (int) MHD_gtls_uint64touint32 (&session->connection_state.
00297                                     write_sequence_number),
00298      MHD__gnutls_packet2str (type), type, sizeofdata);
00299 
00300   if (sizeofdata > MAX_RECORD_SEND_SIZE)
00301     data2send_size = MAX_RECORD_SEND_SIZE;
00302   else
00303     data2send_size = sizeofdata;
00304 
00305   /* Only encrypt if we don't have data to send
00306    * from the previous run. - probably interrupted.
00307    */
00308   if (session->internals.record_send_buffer.length > 0)
00309     {
00310       ret = MHD_gtls_io_write_flush (session);
00311       if (ret > 0)
00312         cipher_size = ret;
00313       else
00314         cipher_size = 0;
00315 
00316       cipher = NULL;
00317 
00318       retval = session->internals.record_send_buffer_user_size;
00319     }
00320   else
00321     {
00322       /* now proceed to packet encryption
00323        */
00324       cipher_size = data2send_size + MAX_RECORD_OVERHEAD;
00325       cipher = MHD_gnutls_malloc (cipher_size);
00326       if (cipher == NULL)
00327         {
00328           MHD_gnutls_assert ();
00329           return GNUTLS_E_MEMORY_ERROR;
00330         }
00331 
00332       cipher_size =
00333         MHD_gtls_encrypt (session, headers, RECORD_HEADER_SIZE, data,
00334                           data2send_size, cipher, cipher_size, type,
00335                           (session->internals.priorities.no_padding ==
00336                            0) ? 1 : 0);
00337       if (cipher_size <= 0)
00338         {
00339           MHD_gnutls_assert ();
00340           if (cipher_size == 0)
00341             cipher_size = GNUTLS_E_ENCRYPTION_FAILED;
00342           MHD_gnutls_free (cipher);
00343           return cipher_size;   /* error */
00344         }
00345 
00346       retval = data2send_size;
00347       session->internals.record_send_buffer_user_size = data2send_size;
00348 
00349       /* increase sequence number
00350        */
00351       if (MHD_gtls_uint64pp
00352           (&session->connection_state.write_sequence_number) != 0)
00353         {
00354           session_invalidate (session);
00355           MHD_gnutls_assert ();
00356           MHD_gnutls_free (cipher);
00357           return GNUTLS_E_RECORD_LIMIT_REACHED;
00358         }
00359 
00360       ret = MHD_gtls_io_write_buffered (session, cipher, cipher_size);
00361       MHD_gnutls_free (cipher);
00362     }
00363 
00364   if (ret != cipher_size)
00365     {
00366       if (ret < 0 && MHD_gtls_error_is_fatal (ret) == 0)
00367         {
00368           /* If we have sent any data then just return
00369            * the error value. Do not invalidate the session.
00370            */
00371           MHD_gnutls_assert ();
00372           return ret;
00373         }
00374 
00375       if (ret > 0)
00376         {
00377           MHD_gnutls_assert ();
00378           ret = GNUTLS_E_INTERNAL_ERROR;
00379         }
00380       session_unresumable (session);
00381       session->internals.may_not_write = 1;
00382       MHD_gnutls_assert ();
00383       return ret;
00384     }
00385 
00386   session->internals.record_send_buffer_user_size = 0;
00387 
00388   MHD__gnutls_record_log ("REC[%x]: Sent Packet[%d] %s(%d) with length: %d\n",
00389                           session,
00390                           (int)
00391                           MHD_gtls_uint64touint32
00392                           (&session->connection_state.write_sequence_number),
00393                           MHD__gnutls_packet2str (type), type, cipher_size);
00394 
00395   return retval;
00396 }
00397 
00398 /* This function is to be called if the handshake was successfully
00399  * completed. This sends a Change Cipher Spec packet to the peer.
00400  */
00401 ssize_t
00402 MHD_gtls_send_change_cipher_spec (MHD_gtls_session_t session, int again)
00403 {
00404   static const opaque data[1] = {
00405     GNUTLS_TYPE_CHANGE_CIPHER_SPEC
00406   };
00407 
00408   MHD__gnutls_handshake_log ("REC[%x]: Sent ChangeCipherSpec\n", session);
00409 
00410   if (again == 0)
00411     return MHD_gtls_send_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1, data,
00412                               1);
00413   else
00414     {
00415       return MHD_gtls_io_write_flush (session);
00416     }
00417 }
00418 
00419 inline static int
00420 check_recv_type (content_type_t recv_type)
00421 {
00422   switch (recv_type)
00423     {
00424     case GNUTLS_CHANGE_CIPHER_SPEC:
00425     case GNUTLS_ALERT:
00426     case GNUTLS_HANDSHAKE:
00427     case GNUTLS_APPLICATION_DATA:
00428     case GNUTLS_INNER_APPLICATION:
00429       return 0;
00430     default:
00431       MHD_gnutls_assert ();
00432       return GNUTLS_A_UNEXPECTED_MESSAGE;
00433     }
00434 
00435 }
00436 
00437 /* Checks if there are pending data in the record buffers. If there are
00438  * then it copies the data.
00439  */
00440 static int
00441 check_buffers (MHD_gtls_session_t session,
00442                content_type_t type, opaque * data, int sizeofdata)
00443 {
00444   if ((type == GNUTLS_APPLICATION_DATA || type == GNUTLS_HANDSHAKE || type
00445        == GNUTLS_INNER_APPLICATION)
00446       && MHD_gnutls_record_buffer_get_size (type, session) > 0)
00447     {
00448       int ret, ret2;
00449       ret = MHD_gtls_record_buffer_get (type, session, data, sizeofdata);
00450       if (ret < 0)
00451         {
00452           MHD_gnutls_assert ();
00453           return ret;
00454         }
00455 
00456       /* if the buffer just got empty */
00457       if (MHD_gnutls_record_buffer_get_size (type, session) == 0)
00458         {
00459           if ((ret2 = MHD_gtls_io_clear_peeked_data (session)) < 0)
00460             {
00461               MHD_gnutls_assert ();
00462               return ret2;
00463             }
00464         }
00465 
00466       return ret;
00467     }
00468 
00469   return 0;
00470 }
00471 
00472 /* Checks the record headers and returns the length, version and
00473  * content type.
00474  */
00475 static int
00476 record_check_headers (MHD_gtls_session_t session,
00477                       uint8_t headers[RECORD_HEADER_SIZE],
00478                       content_type_t type,
00479                       MHD_gnutls_handshake_description_t htype,
00480                       /*output */ content_type_t * recv_type,
00481                       opaque version[2],
00482                       uint16_t * length, uint16_t * header_size)
00483 {
00484 
00485   /* Read the first two bytes to determine if this is a
00486    * version 2 message
00487    */
00488 
00489   if (htype == GNUTLS_HANDSHAKE_CLIENT_HELLO && type == GNUTLS_HANDSHAKE
00490       && headers[0] > 127)
00491     {
00492 
00493       /* if msb set and expecting handshake message
00494        * it should be SSL 2 hello
00495        */
00496       version[0] = 3;           /* assume SSL 3.0 */
00497       version[1] = 0;
00498 
00499       *length = (((headers[0] & 0x7f) << 8)) | headers[1];
00500 
00501       /* SSL 2.0 headers */
00502       *header_size = 2;
00503       *recv_type = GNUTLS_HANDSHAKE;    /* we accept only v2 client hello
00504                                          */
00505 
00506       /* in order to assist the handshake protocol.
00507        * V2 compatibility is a mess.
00508        */
00509       session->internals.v2_hello = *length;
00510 
00511       MHD__gnutls_record_log ("REC[%x]: V2 packet received. Length: %d\n",
00512                               session, *length);
00513 
00514     }
00515   else
00516     {
00517       /* version 3.x */
00518       *recv_type = headers[0];
00519       version[0] = headers[1];
00520       version[1] = headers[2];
00521 
00522       /* No DECR_LEN, since headers has enough size.
00523        */
00524       *length = MHD_gtls_read_uint16 (&headers[3]);
00525     }
00526 
00527   return 0;
00528 }
00529 
00530 /* Here we check if the advertized version is the one we
00531  * negotiated in the handshake.
00532  */
00533 inline static int
00534 record_check_version (MHD_gtls_session_t session,
00535                       MHD_gnutls_handshake_description_t htype,
00536                       opaque version[2])
00537 {
00538   if (htype == GNUTLS_HANDSHAKE_CLIENT_HELLO)
00539     {
00540       /* Reject hello packets with major version higher than 3.
00541        */
00542       if (version[0] > 3)
00543         {
00544           MHD_gnutls_assert ();
00545           MHD__gnutls_record_log
00546             ("REC[%x]: INVALID VERSION PACKET: (%d) %d.%d\n", session,
00547              htype, version[0], version[1]);
00548           return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
00549         }
00550     }
00551   else if (htype != GNUTLS_HANDSHAKE_SERVER_HELLO
00552            && MHD__gnutls_protocol_get_version (session)
00553            != MHD_gtls_version_get (version[0], version[1]))
00554     {
00555       /* Reject record packets that have a different version than the
00556        * one negotiated. Note that this version is not protected by any
00557        * mac. I don't really think that this check serves any purpose.
00558        */
00559       MHD_gnutls_assert ();
00560       MHD__gnutls_record_log ("REC[%x]: INVALID VERSION PACKET: (%d) %d.%d\n",
00561                               session, htype, version[0], version[1]);
00562 
00563       return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
00564     }
00565 
00566   return 0;
00567 }
00568 
00569 /* This function will check if the received record type is
00570  * the one we actually expect.
00571  */
00572 static int
00573 record_check_type (MHD_gtls_session_t session,
00574                    content_type_t recv_type,
00575                    content_type_t type,
00576                    MHD_gnutls_handshake_description_t htype,
00577                    opaque * data, int data_size)
00578 {
00579 
00580   int ret;
00581 
00582   if ((recv_type == type) && (type == GNUTLS_APPLICATION_DATA || type
00583                               == GNUTLS_HANDSHAKE
00584                               || type == GNUTLS_INNER_APPLICATION))
00585     {
00586       MHD_gnutls_record_buffer_put (type, session, (void *) data, data_size);
00587     }
00588   else
00589     {
00590       switch (recv_type)
00591         {
00592         case GNUTLS_ALERT:
00593 
00594           MHD__gnutls_record_log
00595             ("REC[%x]: Alert[%d|%d] - %s - was received\n", session,
00596              data[0], data[1], MHD__gnutls_alert_get_name ((int) data[1]));
00597 
00598           session->internals.last_alert = data[1];
00599           session->internals.last_alert_level = data[0];
00600 
00601           /* if close notify is received and
00602            * the alert is not fatal
00603            */
00604           if (data[1] == GNUTLS_A_CLOSE_NOTIFY && data[0] != GNUTLS_AL_FATAL)
00605             {
00606               /* If we have been expecting for an alert do
00607                */
00608               session->internals.read_eof = 1;
00609               return GNUTLS_E_INT_RET_0;        /* EOF */
00610             }
00611           else
00612             {
00613 
00614               /* if the alert is FATAL or WARNING
00615                * return the apropriate message
00616                */
00617               MHD_gnutls_assert ();
00618               ret = GNUTLS_E_WARNING_ALERT_RECEIVED;
00619               if (data[0] == GNUTLS_AL_FATAL)
00620                 {
00621                   session_unresumable (session);
00622                   session_invalidate (session);
00623                   ret = GNUTLS_E_FATAL_ALERT_RECEIVED;
00624                 }
00625 
00626               return ret;
00627             }
00628           break;
00629 
00630         case GNUTLS_CHANGE_CIPHER_SPEC:
00631           /* this packet is now handled in the recv_int()
00632            * function
00633            */
00634           MHD_gnutls_assert ();
00635 
00636           return GNUTLS_E_UNEXPECTED_PACKET;
00637 
00638         case GNUTLS_APPLICATION_DATA:
00639           /* even if data is unexpected put it into the buffer */
00640           if ((ret =
00641                MHD_gnutls_record_buffer_put (recv_type, session,
00642                                              (void *) data, data_size)) < 0)
00643             {
00644               MHD_gnutls_assert ();
00645               return ret;
00646             }
00647 
00648           /* the got_application data is only returned
00649            * if expecting client hello (for rehandshake
00650            * reasons). Otherwise it is an unexpected packet
00651            */
00652           if (type == GNUTLS_ALERT || (htype == GNUTLS_HANDSHAKE_CLIENT_HELLO
00653                                        && type == GNUTLS_HANDSHAKE))
00654             return GNUTLS_E_GOT_APPLICATION_DATA;
00655           else
00656             {
00657               MHD_gnutls_assert ();
00658               return GNUTLS_E_UNEXPECTED_PACKET;
00659             }
00660 
00661           break;
00662         case GNUTLS_HANDSHAKE:
00663           /* This is legal if HELLO_REQUEST is received - and we are a client.
00664            * If we are a server, a client may initiate a renegotiation at any time.
00665            */
00666           if (session->security_parameters.entity == GNUTLS_SERVER)
00667             {
00668               MHD_gnutls_assert ();
00669               return GNUTLS_E_REHANDSHAKE;
00670             }
00671 
00672           /* If we are already in a handshake then a Hello
00673            * Request is illegal. But here we don't really care
00674            * since this message will never make it up here.
00675            */
00676 
00677           /* So we accept it */
00678           return MHD_gtls_recv_hello_request (session, data, data_size);
00679 
00680           break;
00681         case GNUTLS_INNER_APPLICATION:
00682           /* even if data is unexpected put it into the buffer */
00683           if ((ret =
00684                MHD_gnutls_record_buffer_put (recv_type, session,
00685                                              (void *) data, data_size)) < 0)
00686             {
00687               MHD_gnutls_assert ();
00688               return ret;
00689             }
00690           MHD_gnutls_assert ();
00691           return GNUTLS_E_UNEXPECTED_PACKET;
00692           break;
00693         default:
00694 
00695           MHD__gnutls_record_log
00696             ("REC[%x]: Received Unknown packet %d expecting %d\n",
00697              session, recv_type, type);
00698 
00699           MHD_gnutls_assert ();
00700           return GNUTLS_E_INTERNAL_ERROR;
00701         }
00702     }
00703 
00704   return 0;
00705 
00706 }
00707 
00708 /* This function will return the internal (per session) temporary
00709  * recv buffer. If the buffer was not initialized before it will
00710  * also initialize it.
00711  */
00712 inline static int
00713 get_temp_recv_buffer (MHD_gtls_session_t session, MHD_gnutls_datum_t * tmp)
00714 {
00715   size_t max_record_size;
00716 
00717   max_record_size = MAX_RECORD_RECV_SIZE;
00718 
00719   /* We allocate MAX_RECORD_RECV_SIZE length
00720    * because we cannot predict the output data by the record
00721    * packet length (due to compression).
00722    */
00723 
00724   if (max_record_size > session->internals.recv_buffer.size
00725       || session->internals.recv_buffer.data == NULL)
00726     {
00727 
00728       /* Initialize the internal buffer.
00729        */
00730       session->internals.recv_buffer.data
00731         =
00732         MHD_gnutls_realloc (session->internals.recv_buffer.data,
00733                             max_record_size);
00734 
00735       if (session->internals.recv_buffer.data == NULL)
00736         {
00737           MHD_gnutls_assert ();
00738           return GNUTLS_E_MEMORY_ERROR;
00739         }
00740 
00741       session->internals.recv_buffer.size = max_record_size;
00742     }
00743 
00744   tmp->data = session->internals.recv_buffer.data;
00745   tmp->size = session->internals.recv_buffer.size;
00746 
00747   return 0;
00748 }
00749 
00750 #define MAX_EMPTY_PACKETS_SEQUENCE 4
00751 
00752 /* This function behaves exactly like read(). The only difference is
00753  * that it accepts the MHD_gtls_session_t and the content_type_t of data to
00754  * receive (if called by the user the Content is Userdata only)
00755  * It is intended to receive data, under the current session.
00756  *
00757  * The MHD_gnutls_handshake_description_t was introduced to support SSL V2.0 client hellos.
00758  */
00759 ssize_t
00760 MHD_gtls_recv_int (MHD_gtls_session_t session,
00761                    content_type_t type,
00762                    MHD_gnutls_handshake_description_t htype,
00763                    opaque * data, size_t sizeofdata)
00764 {
00765   MHD_gnutls_datum_t tmp;
00766   int decrypted_length;
00767   opaque version[2];
00768   uint8_t *headers;
00769   content_type_t recv_type;
00770   uint16_t length;
00771   uint8_t *ciphertext;
00772   uint8_t *recv_data;
00773   int ret, ret2;
00774   uint16_t header_size;
00775   int empty_packet = 0;
00776 
00777   if (type != GNUTLS_ALERT && (sizeofdata == 0 || data == NULL))
00778     {
00779       return GNUTLS_E_INVALID_REQUEST;
00780     }
00781 
00782 begin:
00783 
00784   if (empty_packet > MAX_EMPTY_PACKETS_SEQUENCE)
00785     {
00786       MHD_gnutls_assert ();
00787       return GNUTLS_E_TOO_MANY_EMPTY_PACKETS;
00788     }
00789 
00790   if (session->internals.read_eof != 0)
00791     {
00792       /* if we have already read an EOF
00793        */
00794       return 0;
00795     }
00796   else if (session_is_valid (session) != 0 || session->internals.may_not_read
00797            != 0)
00798     {
00799       MHD_gnutls_assert ();
00800       return GNUTLS_E_INVALID_SESSION;
00801     }
00802 
00803   /* If we have enough data in the cache do not bother receiving
00804    * a new packet. (in order to flush the cache)
00805    */
00806   ret = check_buffers (session, type, data, sizeofdata);
00807   if (ret != 0)
00808     return ret;
00809 
00810   /* default headers for TLS 1.0
00811    */
00812   header_size = RECORD_HEADER_SIZE;
00813 
00814   if ((ret = MHD_gtls_io_read_buffered (session, &headers, header_size, -1))
00815       != header_size)
00816     {
00817       if (ret < 0 && MHD_gtls_error_is_fatal (ret) == 0)
00818         return ret;
00819 
00820       session_invalidate (session);
00821       if (type == GNUTLS_ALERT)
00822         {
00823           MHD_gnutls_assert ();
00824           return 0;             /* we were expecting close notify */
00825         }
00826       session_unresumable (session);
00827       MHD_gnutls_assert ();
00828       return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
00829     }
00830 
00831   if ((ret = record_check_headers (session, headers, type, htype, &recv_type,
00832                                    version, &length, &header_size)) < 0)
00833     {
00834       MHD_gnutls_assert ();
00835       return ret;
00836     }
00837 
00838   /* Here we check if the Type of the received packet is
00839    * ok.
00840    */
00841   if ((ret = check_recv_type (recv_type)) < 0)
00842     {
00843       MHD_gnutls_assert ();
00844       return ret;
00845     }
00846 
00847   /* Here we check if the advertized version is the one we
00848    * negotiated in the handshake.
00849    */
00850   if ((ret = record_check_version (session, htype, version)) < 0)
00851     {
00852       MHD_gnutls_assert ();
00853       session_invalidate (session);
00854       return ret;
00855     }
00856 
00857   MHD__gnutls_record_log
00858     ("REC[%x]: Expected Packet[%d] %s(%d) with length: %d\n", session,
00859      (int) MHD_gtls_uint64touint32 (&session->connection_state.
00860                                     read_sequence_number),
00861      MHD__gnutls_packet2str (type), type, sizeofdata);
00862   MHD__gnutls_record_log
00863     ("REC[%x]: Received Packet[%d] %s(%d) with length: %d\n", session,
00864      (int) MHD_gtls_uint64touint32 (&session->connection_state.
00865                                     read_sequence_number),
00866      MHD__gnutls_packet2str (recv_type), recv_type, length);
00867 
00868   if (length > MAX_RECV_SIZE)
00869     {
00870       MHD__gnutls_record_log
00871         ("REC[%x]: FATAL ERROR: Received packet with length: %d\n",
00872          session, length);
00873 
00874       session_unresumable (session);
00875       session_invalidate (session);
00876       MHD_gnutls_assert ();
00877       return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
00878     }
00879 
00880   /* check if we have that data into buffer.
00881    */
00882   if ((ret = MHD_gtls_io_read_buffered (session, &recv_data,
00883                                         header_size + length, recv_type))
00884       != header_size + length)
00885     {
00886       if (ret < 0 && MHD_gtls_error_is_fatal (ret) == 0)
00887         return ret;
00888 
00889       session_unresumable (session);
00890       session_invalidate (session);
00891       MHD_gnutls_assert ();
00892       return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
00893     }
00894 
00895   /* ok now we are sure that we can read all the data - so
00896    * move on !
00897    */
00898   MHD_gtls_io_clear_read_buffer (session);
00899   ciphertext = &recv_data[header_size];
00900 
00901   ret = get_temp_recv_buffer (session, &tmp);
00902   if (ret < 0)
00903     {
00904       MHD_gnutls_assert ();
00905       return ret;
00906     }
00907 
00908   /* decrypt the data we got. */
00909   ret = MHD_gtls_decrypt (session, ciphertext, length, tmp.data, tmp.size,
00910                           recv_type);
00911   if (ret < 0)
00912     {
00913       session_unresumable (session);
00914       session_invalidate (session);
00915       MHD_gnutls_assert ();
00916       return ret;
00917     }
00918   decrypted_length = ret;
00919 
00920   /* Check if this is a CHANGE_CIPHER_SPEC
00921    */
00922   if (type == GNUTLS_CHANGE_CIPHER_SPEC && recv_type
00923       == GNUTLS_CHANGE_CIPHER_SPEC)
00924     {
00925 
00926       MHD__gnutls_record_log
00927         ("REC[%x]: ChangeCipherSpec Packet was received\n", session);
00928 
00929       if ((size_t) ret != sizeofdata)
00930         {                       /* sizeofdata should be 1 */
00931           MHD_gnutls_assert ();
00932           return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
00933         }
00934       memcpy (data, tmp.data, sizeofdata);
00935 
00936       return ret;
00937     }
00938 
00939   MHD__gnutls_record_log
00940     ("REC[%x]: Decrypted Packet[%d] %s(%d) with length: %d\n", session,
00941      (int) MHD_gtls_uint64touint32 (&session->connection_state.
00942                                     read_sequence_number),
00943      MHD__gnutls_packet2str (recv_type), recv_type, decrypted_length);
00944 
00945   /* increase sequence number
00946    */
00947   if (MHD_gtls_uint64pp (&session->connection_state.read_sequence_number) !=
00948       0)
00949     {
00950       session_invalidate (session);
00951       MHD_gnutls_assert ();
00952       return GNUTLS_E_RECORD_LIMIT_REACHED;
00953     }
00954 
00955   /* check type - this will also invalidate sessions if a fatal alert has been received */
00956   ret = record_check_type (session, recv_type, type, htype, tmp.data,
00957                            decrypted_length);
00958   if (ret < 0)
00959     {
00960       if (ret == GNUTLS_E_INT_RET_0)
00961         return 0;
00962       MHD_gnutls_assert ();
00963       return ret;
00964     }
00965 
00966   /* Get Application data from buffer
00967    */
00968   if ((recv_type == type) && (type == GNUTLS_APPLICATION_DATA || type
00969                               == GNUTLS_HANDSHAKE
00970                               || type == GNUTLS_INNER_APPLICATION))
00971     {
00972 
00973       ret = MHD_gtls_record_buffer_get (type, session, data, sizeofdata);
00974       if (ret < 0)
00975         {
00976           MHD_gnutls_assert ();
00977           return ret;
00978         }
00979 
00980       /* if the buffer just got empty
00981        */
00982       if (MHD_gnutls_record_buffer_get_size (type, session) == 0)
00983         {
00984           if ((ret2 = MHD_gtls_io_clear_peeked_data (session)) < 0)
00985             {
00986               MHD_gnutls_assert ();
00987               return ret2;
00988             }
00989         }
00990     }
00991   else
00992     {
00993       MHD_gnutls_assert ();
00994       return GNUTLS_E_UNEXPECTED_PACKET;
00995       /* we didn't get what we wanted to
00996        */
00997     }
00998 
00999   /* (originally for) TLS 1.0 CBC protection.
01000    * Actually this code is called if we just received
01001    * an empty packet. An empty TLS packet is usually
01002    * sent to protect some vulnerabilities in the CBC mode.
01003    * In that case we go to the beginning and start reading
01004    * the next packet.
01005    */
01006   if (ret == 0)
01007     {
01008       empty_packet++;
01009       goto begin;
01010     }
01011 
01012   return ret;
01013 }
01014 
01043 ssize_t
01044 MHD__gnutls_record_send (MHD_gtls_session_t session,
01045                          const void *data, size_t sizeofdata)
01046 {
01047   return MHD_gtls_send_int (session, GNUTLS_APPLICATION_DATA, -1, data,
01048                             sizeofdata);
01049 }
01050 
01081 ssize_t
01082 MHD__gnutls_record_recv (MHD_gtls_session_t session, void *data,
01083                          size_t sizeofdata)
01084 {
01085   return MHD_gtls_recv_int (session, GNUTLS_APPLICATION_DATA, -1, data,
01086                             sizeofdata);
01087 }

Generated on Tue May 19 23:21:08 2009 for GNU libmicrohttpd by  doxygen 1.5.8