]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Implemented a sliding window-like thing to discard replayed packets.
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 20 Feb 2011 20:07:29 +0000 (21:07 +0100)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 20 Feb 2011 20:11:05 +0000 (21:11 +0100)
lib/gnutls_buffers.c
lib/gnutls_dtls.c
lib/gnutls_dtls.h
lib/gnutls_int.h
lib/gnutls_record.c
lib/gnutls_state.c

index 0cd367f964a2cf9a73bd35c7c5e7d3640329f9db..9a44af76d490cf29980344598f23c59f649b333c 100644 (file)
@@ -826,7 +826,7 @@ _gnutls_handshake_io_write_flush (gnutls_session_t session)
                      (int) send_buffer->byte_length);
 
   if (IS_DTLS(session))
-    return _gnutls_dtls_transmit(session);
+    return _dtls_transmit(session);
 
   for (cur = _mbuffer_get_first (send_buffer, &msg);
        cur != NULL; cur = _mbuffer_get_first (send_buffer, &msg))
index 1f3d9bd10836beefb4ed9d005fc9c102db77b0b9..db598b97a6fe136c8f453824ea3f74de5fc9c378 100644 (file)
@@ -144,7 +144,7 @@ static int drop_usage_count(gnutls_session_t session)
  * record layer.
  */
 int
-_gnutls_dtls_transmit (gnutls_session_t session)
+_dtls_transmit (gnutls_session_t session)
 {
 int ret;
 
@@ -215,6 +215,105 @@ cleanup:
   return ret;
 }
 
+#define window_table session->internals.dtls.record_sw
+#define window_size session->internals.dtls.record_sw_size
+
+/* FIXME: could we modify that code to avoid using
+ * uint64_t?
+ */
+
+static void rot_window(gnutls_session_t session, int places)
+{
+  window_size -= places;
+  memmove(window_table, &window_table[places], window_size*sizeof(window_table[0]));
+}
+
+#define MOVE_SIZE 20
+/* Checks if a sequence number is not replayed. If replayed
+ * returns a negative value, otherwise zero.
+ */
+int _dtls_record_check(gnutls_session_t session, uint64 * _seq)
+{
+uint64_t seq = 0, diff;
+int i, offset = 0;
+
+  for (i=0;i<8;i++) 
+    {
+      seq |= _seq->i[i];
+      seq <<= 8;
+    }
+
+  if (window_size == 0)
+    {
+      window_size = 1;
+      window_table[0] = seq;
+      return 0;
+    }
+
+  if (seq <= window_table[0])
+    {
+      return -1;
+    }
+
+  if (window_size == DTLS_RECORD_WINDOW_SIZE) {
+    rot_window(session, MOVE_SIZE);
+  }
+
+  if (seq < window_table[window_size-1])
+    {
+      /* is between first and last */
+      diff = window_table[window_size-1] - seq;
+
+      if (diff >= window_size) 
+        {
+          return -1;
+        }
+
+      offset = window_size-1-diff;
+
+      if (window_table[offset] == seq)
+        {
+          return -1;
+        }
+      else
+        {
+          window_table[offset] = seq;
+        }
+    }
+  else /* seq >= last */
+    {
+      if (seq == window_table[window_size-1]) 
+        {
+          return -1;
+        }
+
+      diff = seq - window_table[window_size-1];
+      if (diff <= DTLS_RECORD_WINDOW_SIZE - window_size)
+        { /* fits in our empty space */
+          offset = diff + window_size-1;
+
+          window_table[offset] = seq;
+          window_size = offset + 1;
+        }
+      else
+        {
+          if (diff > DTLS_RECORD_WINDOW_SIZE/2)
+            { /* difference is too big */
+              window_table[DTLS_RECORD_WINDOW_SIZE-1] = seq;
+              window_size = DTLS_RECORD_WINDOW_SIZE;
+            }
+          else
+            {
+              rot_window(session, diff);
+              offset = diff + window_size-1;
+              window_table[offset] = seq;
+              window_size = offset + 1;            
+            }
+        }
+    }
+  return 0;
+}
+
 
 /**
  * gnutls_dtls_set_timeouts:
index d3a4870bbbf9d3753b40cbfe744f8cb78e844573..ab4e4da6faffeb6b8c0bc2db6a907ead34390f17 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "gnutls_int.h"
 
-int _gnutls_dtls_transmit(gnutls_session_t session);
+int _dtls_transmit(gnutls_session_t session);
+int _dtls_record_check(gnutls_session_t session, uint64 * _seq);
 
 #endif
index 47978e6e198cf5313dd41c1924d1c2024f50c8f4..56324140ad176e396c895101dadd255422f5dfcf 100644 (file)
@@ -539,6 +539,8 @@ typedef struct
   int free_rsa_params;
 } internal_params_st;
 
+#define DTLS_RECORD_WINDOW_SIZE 64
+
 /* DTLS session state
  */
 typedef struct
@@ -558,6 +560,9 @@ typedef struct
   unsigned int total_timeout;
 
   unsigned int hsk_hello_verify_requests;
+  
+  uint64_t record_sw[DTLS_RECORD_WINDOW_SIZE];
+  int record_sw_size;
 } dtls_st;
 
 
index 950579a7864bdfcc826c8ac197f15fc2e1911e60..2ac4ce98e5bd8198f27380c713c7a98a437e16ce 100644 (file)
@@ -45,6 +45,7 @@
 #include "gnutls_constate.h"
 #include "ext_max_record.h"
 #include <gnutls_state.h>
+#include <gnutls_dtls.h>
 #include <gnutls_dh.h>
 
 /**
@@ -427,8 +428,7 @@ _gnutls_send_int (gnutls_session_t session, content_type_t type,
     sequence_write(&record_state->sequence_number, &headers[3]);
 
   _gnutls_record_log
-    ("REC[%p]: Sending Packet[%d] %s(%d) with length: %d\n", session,
-     (int) _gnutls_uint64touint32 (&record_state->sequence_number),
+    ("REC[%p]: Preparing Packet %s(%d) with length: %d\n", session,
      _gnutls_packet2str (type), type, (int) sizeofdata);
 
   if (sizeofdata > MAX_RECORD_SEND_SIZE(session))
@@ -518,7 +518,7 @@ _gnutls_send_int (gnutls_session_t session, content_type_t type,
 
   _gnutls_record_log ("REC[%p]: Sent Packet[%d] %s(%d) with length: %d\n",
                       session,
-                      (int)
+                      (unsigned int)
                       _gnutls_uint64touint32
                       (&record_state->sequence_number),
                       _gnutls_packet2str (type), type, (int) cipher_size);
@@ -1094,6 +1094,21 @@ begin:
                          header_size + length);
   decrypted_length = ret;
 
+  /* check for duplicates. We check after the message
+   * is processed an authenticated to avoid someone
+   * messing with our windows.
+   */
+  if (IS_DTLS(session)) 
+    {
+      ret = _dtls_record_check(session, decrypt_sequence);
+      if (ret < 0)
+        {
+          _gnutls_audit_log("Duplicate message with sequence %u\n",
+            (unsigned int) _gnutls_uint64touint32 (decrypt_sequence));
+          return GNUTLS_E_AGAIN;
+        }
+    }
+
 /* Check if this is a CHANGE_CIPHER_SPEC
  */
   if (type == GNUTLS_CHANGE_CIPHER_SPEC &&
@@ -1103,19 +1118,19 @@ begin:
       _gnutls_record_log
         ("REC[%p]: ChangeCipherSpec Packet was received\n", session);
 
-      if ((size_t) ret != sizeofdata)
+      if ((size_t) decrypted_length != sizeofdata)
         {                       /* sizeofdata should be 1 */
           gnutls_assert ();
           return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
         }
       memcpy (data, tmp.data, sizeofdata);
 
-      return ret;
+      return decrypted_length;
     }
 
   _gnutls_record_log
     ("REC[%p]: Decrypted Packet[%d] %s(%d) with length: %d\n", session,
-     (int) _gnutls_uint64touint32 (&record_state->sequence_number),
+     (int) _gnutls_uint64touint32 (decrypt_sequence),
      _gnutls_packet2str (recv_type), recv_type, decrypted_length);
 
 /* increase sequence number 
index 6ba5dd153c85912db368dedac9b2d1db01be748c..c679c24b19f8e8379fc6850150c89c6d328b844a 100644 (file)
@@ -412,6 +412,8 @@ gnutls_init_dtls (gnutls_session_t * session,
   (*session)->internals.dtls.retrans_timeout = 300;
   (*session)->internals.dtls.total_timeout = 6000;
 
+  (*session)->internals.dtls.record_sw_size = 0;
+
   return 0;
 }