Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 488f7d353752a24f1cc3f6fc2e121835 > files > 11

gnutls-1.4.1-10.el5_9.1.src.rpm

diff -up gnutls-1.4.1/lib/gnutls_cipher.c.lucky13 gnutls-1.4.1/lib/gnutls_cipher.c
--- gnutls-1.4.1/lib/gnutls_cipher.c.lucky13	2012-06-06 14:25:44.000000000 +0200
+++ gnutls-1.4.1/lib/gnutls_cipher.c	2013-02-21 19:39:52.828556530 +0100
@@ -403,6 +403,48 @@ _gnutls_compressed2ciphertext (gnutls_se
   return length;
 }
 
+static void dummy_wait(gnutls_session_t session, gnutls_datum_t* plaintext, 
+                       unsigned pad_failed, unsigned int pad, unsigned total, int ver)
+{
+  /* this hack is only needed on CBC ciphers */
+  if (_gnutls_cipher_is_block (session->security_parameters.read_bulk_cipher_algorithm) == CIPHER_BLOCK)
+    {
+      uint8_t MAC[MAX_HASH_SIZE];
+      unsigned len;
+      mac_hd_t td;
+
+      td = mac_init (session->security_parameters.read_mac_algorithm,
+		  session->connection_state.read_mac_secret.data,
+		  session->connection_state.read_mac_secret.size, ver);
+
+      if (td == GNUTLS_MAC_FAILED)
+        return;
+
+      /* force an additional hash compression function evaluation to prevent timing 
+       * attacks that distinguish between wrong-mac + correct pad, from wrong-mac + incorrect pad.
+       */
+      if (pad_failed == 0 && pad > 0) 
+        {
+          len = _gnutls_get_hash_block_len(session->security_parameters.read_mac_algorithm);
+          if (len > 0)
+            {
+              /* This is really specific to the current hash functions.
+               * It should be removed once a protocol fix is in place.
+               */
+	      if ((pad+total) % len > len-9 && total % len <= len-9) 
+	        {
+	          if (len < plaintext->size)
+                    _gnutls_hmac (td, plaintext->data, len);
+                  else
+                    _gnutls_hmac (td, plaintext->data, plaintext->size);
+                }
+            }
+        }
+
+      mac_deinit (td, MAC, ver);
+    }
+}
+
 /* Deciphers the ciphertext packet, and puts the result to compress_data, of compress_size.
  * Returns the actual compressed packet size.
  */
@@ -414,12 +456,12 @@ _gnutls_ciphertext2compressed (gnutls_se
 {
   uint8_t MAC[MAX_HASH_SIZE];
   uint16_t c_length;
-  uint8_t pad;
+  unsigned int pad = 0;
   int length;
-  mac_hd_t td;
   uint16_t blocksize;
   int ret, i, pad_failed = 0;
   uint8_t major, minor;
+  int preamble_size = 11;
   gnutls_protocol_t ver;
   int hash_size =
     _gnutls_hash_get_algo_len (session->security_parameters.
@@ -429,21 +471,12 @@ _gnutls_ciphertext2compressed (gnutls_se
   minor = _gnutls_version_get_minor (ver);
   major = _gnutls_version_get_major (ver);
 
+  if (ver >= GNUTLS_TLS1)
+    preamble_size +=2;
+
   blocksize = _gnutls_cipher_get_block_size (session->security_parameters.
 					     read_bulk_cipher_algorithm);
 
-  /* initialize MAC 
-   */
-  td = mac_init (session->security_parameters.read_mac_algorithm,
-		 session->connection_state.read_mac_secret.data,
-		 session->connection_state.read_mac_secret.size, ver);
-
-  if (td == GNUTLS_MAC_FAILED
-      && session->security_parameters.read_mac_algorithm != GNUTLS_MAC_NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
 
   /* actual decryption (inplace)
    */
@@ -488,35 +521,27 @@ _gnutls_ciphertext2compressed (gnutls_se
 	}
 
       if (ciphertext.size < hash_size)
-	{
-	  gnutls_assert ();
-	  return GNUTLS_E_DECRYPTION_FAILED;
-	}
-      pad = ciphertext.data[ciphertext.size - 1] + 1;	/* pad */
-
-      if ((int)pad > (int)ciphertext.size - hash_size)
-	{
-	  gnutls_assert ();
-	  _gnutls_record_log
-	    ("REC[%x]: Short record length %d > %d - %d (under attack?)\n",
-	     session, pad, ciphertext.size, hash_size);
-	  /* We do not fail here. We check below for the
-	   * the pad_failed. If zero means success.
-	   */
-	  pad_failed = GNUTLS_E_DECRYPTION_FAILED;
-	}
-
-      length = ciphertext.size - hash_size - pad;
-
-      /* Check the pading bytes (TLS 1.x)
+        {
+          gnutls_assert ();
+          return GNUTLS_E_DECRYPTION_FAILED;
+        }
+      pad = ciphertext.data[ciphertext.size - 1];   /* pad */
+
+      /* Check the pading bytes (TLS 1.x). 
+       * Note that we access all 256 bytes of ciphertext for padding check
+       * because there is a timing channel in that memory access (in certain CPUs).
        */
       if (ver >= GNUTLS_TLS1 && pad_failed == 0)
-	for (i = 2; i < pad; i++)
+	for (i = 2; i <= pad; i++)
 	  {
-	    if (ciphertext.data[ciphertext.size - i] !=
-		ciphertext.data[ciphertext.size - 1])
+	    if (ciphertext.data[ciphertext.size - i] != pad)
 	      pad_failed = GNUTLS_E_DECRYPTION_FAILED;
 	  }
+
+      if (pad_failed)
+        pad = 0;
+      length = ciphertext.size - hash_size - pad - 1;
+
       break;
     default:
       gnutls_assert ();
@@ -530,8 +555,20 @@ _gnutls_ciphertext2compressed (gnutls_se
   /* Pass the type, version, length and compressed through
    * MAC.
    */
-  if (td != GNUTLS_MAC_FAILED)
+  if (session->security_parameters.read_mac_algorithm != GNUTLS_MAC_NULL)
     {
+      mac_hd_t td;
+
+      td = mac_init (session->security_parameters.read_mac_algorithm,
+		 session->connection_state.read_mac_secret.data,
+		 session->connection_state.read_mac_secret.size, ver);
+
+      if (td == GNUTLS_MAC_FAILED)
+        {
+          gnutls_assert ();
+          return GNUTLS_E_INTERNAL_ERROR;
+        }
+
       _gnutls_hmac (td,
 		    UINT64DATA (session->connection_state.
 				read_sequence_number), 8);
@@ -550,16 +587,14 @@ _gnutls_ciphertext2compressed (gnutls_se
       mac_deinit (td, MAC, ver);
     }
 
-  /* This one was introduced to avoid a timing attack against the TLS
-   * 1.0 protocol.
-   */
-  if (pad_failed != 0)
-    return pad_failed;
-
   /* HMAC was not the same. 
    */
-  if (memcmp (MAC, &ciphertext.data[length], hash_size) != 0)
+  if (memcmp (MAC, &ciphertext.data[length], hash_size) != 0 || pad_failed != 0)
     {
+      gnutls_datum_t compressed = {compress_data, compress_size};
+      /* HMAC was not the same. */
+      dummy_wait(session, &compressed, pad_failed, pad, length+preamble_size, ver);
+
       gnutls_assert ();
       return GNUTLS_E_DECRYPTION_FAILED;
     }
diff -up gnutls-1.4.1/lib/gnutls_hash_int.h.lucky13 gnutls-1.4.1/lib/gnutls_hash_int.h
--- gnutls-1.4.1/lib/gnutls_hash_int.h.lucky13	2006-03-08 11:44:59.000000000 +0100
+++ gnutls-1.4.1/lib/gnutls_hash_int.h	2013-02-21 19:43:13.578986259 +0100
@@ -69,4 +69,21 @@ void _gnutls_mac_deinit_ssl3_handshake (
 
 GNUTLS_HASH_HANDLE _gnutls_hash_copy (GNUTLS_HASH_HANDLE handle);
 
+/* We shouldn't need to know that, but a work-around in decoding
+ * TLS record padding requires that.
+ */
+inline static size_t
+_gnutls_get_hash_block_len (gnutls_digest_algorithm_t algo)
+{
+  switch (algo)
+    {
+    case GNUTLS_DIG_MD5:
+    case GNUTLS_DIG_SHA1:
+    case GNUTLS_DIG_RMD160:
+      return 64;
+    default:
+      return 0;
+    }
+}
+
 #endif /* GNUTLS_HASH_INT_H */