]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
skip replays in handshake packets.
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 20 Feb 2011 16:01:43 +0000 (17:01 +0100)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 20 Feb 2011 16:01:43 +0000 (17:01 +0100)
lib/gnutls_buffers.c
lib/gnutls_buffers.h
lib/gnutls_dtls.c
lib/gnutls_handshake.c
lib/gnutls_int.h
lib/gnutls_num.c
lib/gnutls_state.c

index 3ecfcb74dfc95380a957b2712dbbc653d425c551..0cd367f964a2cf9a73bd35c7c5e7d3640329f9db 100644 (file)
@@ -895,8 +895,34 @@ _gnutls_handshake_io_cache_int (gnutls_session_t session,
   _mbuffer_enqueue (send_buffer, bufel);
 
   _gnutls_write_log
-    ("HWRITE: enqueued %d. Total %d bytes.\n",
-     (int) bufel->msg.size, (int) send_buffer->byte_length);
+    ("HWRITE: enqueued [%s] %d. Total %d bytes.\n",
+     _gnutls_handshake2str (bufel->htype), (int) bufel->msg.size, (int) send_buffer->byte_length);
+
+  return 0;
+}
+
+/* Skips a handshake packet
+ */
+int
+_gnutls_handshake_io_recv_skip (gnutls_session_t session,
+                               content_type_t type,
+                               gnutls_handshake_description_t htype,
+                               size_t ptr_size)
+{
+  opaque * ptr;
+  int ret;
+
+  if (ptr_size == 0) return 0;
+
+  ptr = gnutls_malloc(ptr_size);
+  if (ptr == NULL)
+    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+  ret = _gnutls_handshake_io_recv_int(session, type, htype, ptr, ptr_size);
+  gnutls_free(ptr);
+
+  if (ret < 0)
+    return gnutls_assert_val(ret);
 
   return 0;
 }
@@ -908,7 +934,7 @@ ssize_t
 _gnutls_handshake_io_recv_int (gnutls_session_t session,
                                content_type_t type,
                                gnutls_handshake_description_t htype,
-                               void *iptr, size_t sizeOfPtr)
+                               void *iptr, size_t ptr_size)
 {
   size_t left;
   ssize_t i;
@@ -916,9 +942,9 @@ _gnutls_handshake_io_recv_int (gnutls_session_t session,
   size_t dsize;
 
   ptr = iptr;
-  left = sizeOfPtr;
+  left = ptr_size;
 
-  if (sizeOfPtr == 0 || iptr == NULL)
+  if (ptr_size == 0 || iptr == NULL)
     {
       gnutls_assert ();
       return GNUTLS_E_INVALID_REQUEST;
@@ -929,20 +955,20 @@ _gnutls_handshake_io_recv_int (gnutls_session_t session,
       size_t tmp;
 
       /* if we have already received some data */
-      if (sizeOfPtr <= session->internals.handshake_recv_buffer.length)
+      if (ptr_size <= session->internals.handshake_recv_buffer.length)
         {
           /* if requested less data then return it.
            */
           gnutls_assert ();
 
-          tmp = sizeOfPtr;
+          tmp = ptr_size;
           _gnutls_buffer_pop_data (&session->internals.handshake_recv_buffer,
                                    iptr, &tmp);
           return tmp;
         }
       gnutls_assert ();
 
-      tmp = sizeOfPtr;
+      tmp = ptr_size;
       _gnutls_buffer_pop_data (&session->internals.handshake_recv_buffer,
                                iptr, &tmp);
       left -= tmp;
@@ -950,7 +976,7 @@ _gnutls_handshake_io_recv_int (gnutls_session_t session,
 
   while (left > 0)
     {
-      dsize = sizeOfPtr - left;
+      dsize = ptr_size - left;
       i = _gnutls_recv_int (session, type, htype, &ptr[dsize], left);
       if (i < 0)
         {
@@ -977,7 +1003,7 @@ _gnutls_handshake_io_recv_int (gnutls_session_t session,
 
   session->internals.handshake_recv_buffer.length = 0;
 
-  return sizeOfPtr - left;
+  return ptr_size - left;
 }
 
 /* Buffer for handshake packets. Keeps the packets in order
index 37371ba6fbb0e28164bca9087f1602cc66ba898b..6e1b9012728dfdeb74a15da33f2ab580df07e266 100644 (file)
@@ -59,6 +59,12 @@ ssize_t _gnutls_handshake_io_recv_int (gnutls_session_t, content_type_t,
 int _gnutls_handshake_io_cache_int (gnutls_session_t,
                                      gnutls_handshake_description_t,
                                      mbuffer_st * bufel);
+int
+_gnutls_handshake_io_recv_skip (gnutls_session_t session,
+                               content_type_t type,
+                               gnutls_handshake_description_t htype,
+                               size_t ptr_size);
+
 ssize_t _gnutls_io_write_flush (gnutls_session_t session);
 int
 _gnutls_io_check_recv (gnutls_session_t session, void* data, size_t data_size, unsigned int ms);
index a2004362eec60e86a2f3cc0bfcb3770d69a8aa9b..1f3d9bd10836beefb4ed9d005fc9c102db77b0b9 100644 (file)
@@ -50,6 +50,12 @@ transmit_message (gnutls_session_t session,
 
   if (bufel->type == GNUTLS_CHANGE_CIPHER_SPEC)
     {
+      _gnutls_dtls_log ("DTLS[%p]: Sending Packet[%u] fragment %s(%d) with "
+                       "length: %u, offset: %u, fragment length: %u\n",
+                       session, bufel->sequence,
+                       _gnutls_handshake2str (bufel->htype),
+                       bufel->htype, data_size, offset, frag_len);
+
       return _gnutls_send_int (session, bufel->type, -1,
         bufel->epoch, 
         _mbuffer_get_uhead_ptr(bufel), 
index 5be063b81d5bfaecf67618338610827e0a2eb2bf..2d0aec7878800c23c0ff985ac5062bb5462c0c38 100644 (file)
@@ -1279,6 +1279,11 @@ _gnutls_send_handshake (gnutls_session_t session, mbuffer_st * bufel,
   return ret;
 }
 
+#define _gnutls_handshake_header_buffer_clear( session) session->internals.handshake_header_buffer.header_size = 0; \
+  session->internals.handshake_header_buffer.sequence = -1; \
+  session->internals.handshake_header_buffer.frag_offset = 0; \
+  session->internals.handshake_header_buffer.frag_length = 0
+
 /* This function will read the handshake header and return it to the caller. If the
  * received handshake packet is not the one expected then it buffers the header, and
  * returns UNEXPECTED_HANDSHAKE_PACKET.
@@ -1381,6 +1386,14 @@ _gnutls_recv_handshake_header (gnutls_session_t session,
       length32 = _gnutls_read_uint24 (&dataptr[1]);
       handshake_header_size = HANDSHAKE_HEADER_SIZE(session);
 
+      if (IS_DTLS(session))
+        {
+          session->internals.handshake_header_buffer.sequence = _gnutls_read_uint16 (&dataptr[4]);
+          session->internals.handshake_header_buffer.frag_offset = _gnutls_read_uint24 (&dataptr[6]);
+          session->internals.handshake_header_buffer.frag_length = _gnutls_read_uint24 (&dataptr[9]);
+        }
+          
+
       _gnutls_handshake_log ("HSK[%p]: %s was received [%ld bytes]\n",
                              session, _gnutls_handshake2str (dataptr[0]),
                              (long int) (length32 + HANDSHAKE_HEADER_SIZE(session)));
@@ -1398,7 +1411,10 @@ _gnutls_recv_handshake_header (gnutls_session_t session,
                              session, _gnutls_handshake2str (*recv_type),
                              (long int) (length32 + handshake_header_size));
 
-      if (*recv_type != GNUTLS_HANDSHAKE_CLIENT_HELLO)
+      /* The IS_DTLS() check is redundant since the record layer will
+       * prevent us from reaching here.
+       */
+      if (IS_DTLS(session) || *recv_type != GNUTLS_HANDSHAKE_CLIENT_HELLO)
         {                       /* it should be one or nothing */
           gnutls_assert ();
           return GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET;
@@ -1411,11 +1427,26 @@ _gnutls_recv_handshake_header (gnutls_session_t session,
   session->internals.handshake_header_buffer.packet_length = length32;
   session->internals.handshake_header_buffer.recv_type = *recv_type;
 
-  if (_gnutls_is_dtls (session)
-      && type == GNUTLS_HANDSHAKE_SERVER_HELLO
-      && *recv_type == GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST)
-    return length32;
-  else if (*recv_type != type)
+  if (IS_DTLS(session))
+    {
+      if ((int)session->internals.handshake_header_buffer.sequence <= session->internals.dtls.hsk_read_seq)
+        {
+          _gnutls_audit_log("Dropping replayed handshake packet with sequence %d\n", session->internals.handshake_header_buffer.sequence);
+          ret = _gnutls_handshake_io_recv_skip(session, GNUTLS_HANDSHAKE, *recv_type, length32);
+          if (ret < 0)
+            return gnutls_assert_val(ret);
+
+          _gnutls_handshake_header_buffer_clear (session);
+          return GNUTLS_E_AGAIN;
+        }
+      session->internals.dtls.hsk_read_seq = session->internals.handshake_header_buffer.sequence;
+
+      if (type == GNUTLS_HANDSHAKE_SERVER_HELLO
+        && *recv_type == GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST)
+        return length32;
+    }
+
+  if (*recv_type != type)
     {
       _gnutls_handshake_log ("HSK[%p]: %s was received, expected %s\n",
                              session, _gnutls_handshake2str (*recv_type),
@@ -1427,10 +1458,6 @@ _gnutls_recv_handshake_header (gnutls_session_t session,
   return length32;
 }
 
-#define _gnutls_handshake_header_buffer_clear( session) session->internals.handshake_header_buffer.header_size = 0
-
-
-
 /* This function will hash the handshake headers and the
  * handshake data.
  */
@@ -1501,7 +1528,6 @@ _gnutls_recv_handshake (gnutls_session_t session, uint8_t ** data,
   ret = _gnutls_recv_handshake_header (session, type, &recv_type);
   if (ret < 0)
     {
-
       if (ret == GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET
           && optional == OPTIONAL_PACKET)
         {
@@ -1553,7 +1579,6 @@ _gnutls_recv_handshake (gnutls_session_t session, uint8_t ** data,
   if (data != NULL && length32 > 0)
     *data = dataptr;
 
-
   ret = _gnutls_handshake_hash_add_recvd (session, recv_type,
                                           session->
                                           internals.handshake_header_buffer.
index 30618fae2c38789353a4270d6e8b33902746db44..47978e6e198cf5313dd41c1924d1c2024f50c8f4 100644 (file)
@@ -551,7 +551,7 @@ typedef struct
 
   /* For DTLS handshake fragmentation and reassembly. */
   uint16_t hsk_write_seq;
-  uint16_t hsk_read_seq;
+  int hsk_read_seq;
   uint16_t mtu;
 
   unsigned int retrans_timeout;
@@ -569,6 +569,11 @@ typedef struct
   /* this holds the length of the handshake packet */
   size_t packet_length;
   gnutls_handshake_description_t recv_type;
+  
+  /* DTLS fields */
+  uint16_t sequence;
+  size_t frag_offset;
+  size_t frag_length;
 } handshake_header_buffer_st;
 
 typedef union
index 2528447564850753db134fb3c5223bf4641147c3..2e5c04974cfb51b1929699af28590c7815183037 100644 (file)
@@ -69,15 +69,25 @@ _gnutls_uint64pp (uint64 * x)
 int
 _gnutls_uint48pp (uint64 * x)
 {
-  int ret;
-  
-  ret = _gnutls_uint64pp(x);
-  if (ret != 0)
-    return ret;
-  
-  if (x->i[6] != 0)
-    return -1;
-    
+  register int i, y = 0;
+
+  for (i = 5; i >= 0; i--)
+    {
+      y = 0;
+      if (x->i[i] == 0xff)
+        {
+          x->i[i] = 0;
+          y = 1;
+        }
+      else
+        x->i[i]++;
+
+      if (y == 0)
+        break;
+    }
+  if (y != 0)
+    return -1;                  /* over 48 bits */
+
   return 0;
 }
 
index cffbb099d9df0e15186c5f7a4f1c2cd793e69d94..2ba28af94d7559ea0391b411e75214f1f1a4ea1f 100644 (file)
@@ -258,6 +258,9 @@ _gnutls_handshake_internal_state_init (gnutls_session_t session)
   session->internals.last_handshake_out = -1;
 
   session->internals.resumable = RESUME_TRUE;
+  
+  session->internals.dtls.hsk_read_seq = -1;
+  session->internals.dtls.hsk_write_seq = 0;
 }
 
 void
@@ -405,8 +408,8 @@ gnutls_init_dtls (gnutls_session_t * session,
   (*session)->internals.dtls.mtu = DTLS_DEFAULT_MTU;
   (*session)->internals.transport = GNUTLS_DGRAM;
 
-  (*session)->internals.dtls.retrans_timeout = 1000;
-  (*session)->internals.dtls.total_timeout = 4000;
+  (*session)->internals.dtls.retrans_timeout = 300;
+  (*session)->internals.dtls.total_timeout = 6000;
 
   return 0;
 }