]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Corrected SSL2 client hello handling.
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Sat, 12 Mar 2011 21:52:07 +0000 (22:52 +0100)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Sat, 12 Mar 2011 21:52:07 +0000 (22:52 +0100)
lib/debug.c
lib/gnutls_buffers.c
lib/gnutls_constate.c
lib/gnutls_handshake.c
lib/gnutls_record.c
lib/gnutls_v2_compat.c

index f5eb466d53d19aba40ea752550b27a2e1f8c10c7..14ec82f1f8c12177d93571256c995da15bb836cd 100644 (file)
@@ -75,6 +75,9 @@ _gnutls_handshake2str (gnutls_handshake_description_t handshake)
     case GNUTLS_HANDSHAKE_CLIENT_HELLO:
       return "CLIENT HELLO";
       break;
+    case GNUTLS_HANDSHAKE_CLIENT_HELLO_V2:
+      return "SSL2 CLIENT HELLO";
+      break;
     case GNUTLS_HANDSHAKE_SERVER_HELLO:
       return "SERVER HELLO";
       break;
index c66f1124ad2d4b798dbda2cb22b19cc535159fbd..645d78de5513af91a503506229d10bafca171219 100644 (file)
@@ -745,15 +745,14 @@ parse_handshake_header (gnutls_session_t session, mbuffer_st* bufel, gnutls_hand
     return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
 
   dataptr = _mbuffer_get_udata_ptr(bufel);
-
   /* if reading a client hello of SSLv2 */
   if (!IS_DTLS(session) && htype == GNUTLS_HANDSHAKE_CLIENT_HELLO &&
     bufel->htype == GNUTLS_HANDSHAKE_CLIENT_HELLO_V2)
     {
-      hsk->length = _mbuffer_get_udata_size(bufel) - SSL2_HEADERS;    /* we've read the first byte */
-
       handshake_header_size = SSL2_HEADERS; /* we've already read one byte */
 
+      hsk->length = _mbuffer_get_udata_size(bufel) - handshake_header_size;    /* we've read the first byte */
+
       if (dataptr[0] != GNUTLS_HANDSHAKE_CLIENT_HELLO)
         return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
 
@@ -892,6 +891,17 @@ int ret;
   return 0;
 }
 
+/* returns non-zero on match and zero on mismatch
+ */
+inline static int cmp_hsk_types(gnutls_handshake_description_t expected, gnutls_handshake_description_t recvd)
+{
+  if ((expected != GNUTLS_HANDSHAKE_CLIENT_HELLO || recvd != GNUTLS_HANDSHAKE_CLIENT_HELLO_V2) &&
+        (expected != recvd))
+    return 0;
+  
+  return 1; 
+}
+
 #define LAST_ELEMENT (session->internals.handshake_recv_buffer_size-1)
 
 /* returns the last stored handshake packet.
@@ -929,7 +939,7 @@ handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer;
     {
       if (session->internals.handshake_recv_buffer_size > 0 && recv_buf[0].length == recv_buf[0].data.length)
         {
-          if (recv_buf[0].htype != htype)
+          if (cmp_hsk_types(htype, recv_buf[0].htype) == 0)
             {
               hsk->htype = recv_buf[LAST_ELEMENT].htype;
               return gnutls_assert_val(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
@@ -940,15 +950,15 @@ handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer;
           return 0;
         }
       else
-        return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
+        return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
     }
 }
 
 /* This is a receive function for the gnutls handshake 
  * protocol. Makes sure that we have received all data.
  */
-ssize_t
-_gnutls_handshake_io_recv_int (gnutls_session_t session,
+static int
+parse_record_buffered_msgs (gnutls_session_t session,
                                gnutls_handshake_description_t htype,
                                handshake_buffer_st * hsk)
 {
@@ -958,19 +968,9 @@ _gnutls_handshake_io_recv_int (gnutls_session_t session,
   size_t data_size;
   handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer;
 
-  ret = get_last_packet(session, htype, hsk);
-  if (ret >= 0)
-    return ret;
-
-  /* if we don't have a complete message waiting for us, try 
-   * receiving more */
-  ret = _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, htype);
-  if (ret < 0)
-    return gnutls_assert_val(ret);
-
   bufel = _mbuffer_head_get_first(&session->internals.record_buffer, &msg);
   if (bufel == NULL)
-    return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
+    return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
 
   if (!IS_DTLS(session))
     {
@@ -1018,7 +1018,8 @@ _gnutls_handshake_io_recv_int (gnutls_session_t session,
 
               _mbuffer_head_remove_bytes(&session->internals.record_buffer, data_size+header_size);
 
-              if (htype != recv_buf[0].htype)
+
+              if (cmp_hsk_types(htype, recv_buf[0].htype) == 0)
                 { /* an unexpected packet */
                   hsk->htype = recv_buf[0].htype;
                   return gnutls_assert_val(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
@@ -1117,6 +1118,40 @@ next:
     }
 }
 
+/* This is a receive function for the gnutls handshake 
+ * protocol. Makes sure that we have received all data.
+ */
+ssize_t
+_gnutls_handshake_io_recv_int (gnutls_session_t session,
+                               gnutls_handshake_description_t htype,
+                               handshake_buffer_st * hsk)
+{
+  gnutls_datum_t msg;
+  mbuffer_st* bufel = NULL, *prev = NULL;
+  int ret;
+  size_t data_size;
+  handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer;
+
+  ret = get_last_packet(session, htype, hsk);
+  if (ret >= 0)
+    return ret;
+
+  /* try using the already existing records before
+   * trying to receive.
+   */
+  ret = parse_record_buffered_msgs(session, htype, hsk);
+  if (ret >= 0)
+    return ret;
+
+  /* if we don't have a complete message waiting for us, try 
+   * receiving more */
+  ret = _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, htype);
+  if (ret < 0)
+    return gnutls_assert_val(ret);
+
+  return parse_record_buffered_msgs(session, htype, hsk); 
+}
+
 /* Buffer for handshake packets. Keeps the packets in order
  * for finished messages to use them. Used in HMAC calculation
  * and finished messages.
index 33548e0008564e837cb1feb5c5bc594b0c794eb9..90372d9b7520d597b218345558670eafe5ba5279 100644 (file)
@@ -675,7 +675,7 @@ epoch_get_slot (gnutls_session_t session, uint16_t epoch)
 
   if (epoch_index >= MAX_EPOCH_INDEX)
     {
-      _gnutls_dtls_log("Epoch %d out of range (idx: %d, max: %d)\n", (int)epoch, (int)epoch_index, MAX_EPOCH_INDEX);
+      _gnutls_handshake_log("Epoch %d out of range (idx: %d, max: %d)\n", (int)epoch, (int)epoch_index, MAX_EPOCH_INDEX);
       gnutls_assert ();
       return NULL;
     }
index a95b2076b7874ecaaf14107497819b2c39460626..ba592719ee01a4c5066b76d673fbd793733a0d3a 100644 (file)
@@ -1045,8 +1045,7 @@ _gnutls_server_select_comp_method (gnutls_session_t session,
       return x;
     }
 
-  memset (&session->internals.compression_method, 0,
-          sizeof (gnutls_compression_method_t));
+  session->internals.compression_method = 0;
 
   for (j = 0; j < datalen; j++)
     {
@@ -1284,7 +1283,7 @@ _gnutls_handshake_hash_add_recvd (gnutls_session_t session,
   if ((session->security_parameters.entity == GNUTLS_SERVER
        || recv_type != GNUTLS_HANDSHAKE_SERVER_HELLO)
       && (session->security_parameters.entity == GNUTLS_CLIENT
-          || recv_type != GNUTLS_HANDSHAKE_CLIENT_HELLO))
+          || (recv_type != GNUTLS_HANDSHAKE_CLIENT_HELLO && recv_type != GNUTLS_HANDSHAKE_CLIENT_HELLO_V2)))
     {
       if ((ret = _gnutls_handshake_hash_pending (session)) < 0)
         {
@@ -2571,10 +2570,7 @@ gnutls_handshake (gnutls_session_t session)
         _gnutls_epoch_alloc (session, session->security_parameters.epoch_next,
                              NULL);
       if (ret < 0)
-        {
-          gnutls_assert ();
-          return ret;
-        }
+        return gnutls_assert_val(ret);
     }
 
   if (session->security_parameters.entity == GNUTLS_CLIENT)
index e7a70362b906fd813c46c053f092503f697605d8..fa47d12fb099fbafa264785c5b363129de3b4437 100644 (file)
@@ -349,17 +349,11 @@ _gnutls_send_int (gnutls_session_t session, content_type_t type,
 
   ret = _gnutls_epoch_get (session, epoch_rel, &record_params);
   if (ret < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
+    return gnutls_assert_val(ret);
 
   /* Safeguard against processing data with an incomplete cipher state. */
   if (!record_params->initialized)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INVALID_REQUEST;
-    }
+    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
 
   record_state = &record_params->write;
 
@@ -782,7 +776,7 @@ record_read_headers (gnutls_session_t session,
       record->length = (((headers[0] & 0x7f) << 8)) | headers[1];
 
       /* SSL 2.0 headers */
-      record->header_size = 2;
+      record->header_size = record->packet_size = 2;
       record->type = GNUTLS_HANDSHAKE;    /* we accept only v2 client hello
                                          */
 
index abc17b7e4b8f8a5e0a7740f043f294449f9fec42..9d78287efecd71db625d9051ff2e48ee220beb0a 100644 (file)
@@ -42,6 +42,7 @@
 #include "gnutls_extensions.h"
 #include "gnutls_auth.h"
 #include "gnutls_v2_compat.h"
+#include "gnutls_constate.h"
 
 /* This selects the best supported ciphersuite from the ones provided */
 static int
@@ -250,6 +251,7 @@ _gnutls_read_client_hello_v2 (gnutls_session_t session, opaque * data,
     }
 
   session->internals.compression_method = GNUTLS_COMP_NULL;
+  _gnutls_epoch_set_compression (session, EPOCH_NEXT, session->internals.compression_method);
 
   return 0;
 }