gnutls-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU gnutls branch, master, updated. gnutls_2_11_6-109-g5d11254


From: Nikos Mavrogiannopoulos
Subject: [SCM] GNU gnutls branch, master, updated. gnutls_2_11_6-109-g5d11254
Date: Mon, 07 Feb 2011 12:49:01 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU gnutls".

http://git.savannah.gnu.org/cgit/gnutls.git/commit/?id=5d112546b955935101df4488cb85d0451858837b

The branch, master has been updated
       via  5d112546b955935101df4488cb85d0451858837b (commit)
       via  94175a16a53c2dee626a4a2bfc96abcd82191b95 (commit)
       via  807154eb0c2904e929ffbf26d7aceb8db1de9b7c (commit)
       via  fa72f202b690bfb57bd7663bfe62080e0ec8e758 (commit)
       via  8dbb79875c5d2b5d95286675eb369d9daf2b10a9 (commit)
       via  535e41c9cc75faecb1078a0f97dc638ab4262fb2 (commit)
       via  40b78037dabe8daa70147a98bf1f7c55264595af (commit)
       via  d499f4e58afb40b577b50eec81d83f3c0ba3af41 (commit)
       via  e843e5f1cc24113fd7dc085d80aa84e4ba3b5eb9 (commit)
       via  8316c2ecaad8d1fc10549c8b49ef31a8271a956b (commit)
      from  0567caaa942f2e0ecf6158a5821dc1ef415f9159 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 5d112546b955935101df4488cb85d0451858837b
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon Feb 7 13:48:53 2011 +0100

    Cleanups and moved definitions to gnutls_int.h. AEAD modes now use the 
record packet counter as nonce.

commit 94175a16a53c2dee626a4a2bfc96abcd82191b95
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon Feb 7 13:39:53 2011 +0100

    Reset GCM mode when setting IV.

commit 807154eb0c2904e929ffbf26d7aceb8db1de9b7c
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon Feb 7 13:39:19 2011 +0100

    Added more GCM ciphersuites (DHE-* and anonymous).

commit fa72f202b690bfb57bd7663bfe62080e0ec8e758
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon Feb 7 10:59:19 2011 +0100

    updated priorities. Removed ARCFOUR from the secure ciphersuites and
    moved GCM to bottom of the ciphers in performance.

commit 8dbb79875c5d2b5d95286675eb369d9daf2b10a9
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon Feb 7 10:50:54 2011 +0100

    Added gnutls_cipher_add_auth() gnutls_cipher_tag() to export the
    GCM interface. Updated the benchmark.

commit 535e41c9cc75faecb1078a0f97dc638ab4262fb2
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon Feb 7 10:19:27 2011 +0100

    removed gnutls_certificate_get_openpgp_keyring().

commit 40b78037dabe8daa70147a98bf1f7c55264595af
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon Feb 7 09:44:04 2011 +0100

    minor optimizations.

commit d499f4e58afb40b577b50eec81d83f3c0ba3af41
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon Feb 7 09:24:24 2011 +0100

    inlined several small functions.

commit e843e5f1cc24113fd7dc085d80aa84e4ba3b5eb9
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon Feb 7 09:11:48 2011 +0100

    Better error checking on SSL3.

commit 8316c2ecaad8d1fc10549c8b49ef31a8271a956b
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon Feb 7 08:34:31 2011 +0100

    calculation for c_length occurs in a single place.

-----------------------------------------------------------------------

Summary of changes:
 NEWS                         |    3 +
 lib/crypto-api.c             |   51 +++++++++++++++
 lib/gnutls_algorithms.c      |   69 +++++++++++++++-----
 lib/gnutls_algorithms.h      |    2 +-
 lib/gnutls_cert.c            |   21 ------
 lib/gnutls_cipher.c          |  106 ++++++++++++++++----------------
 lib/gnutls_cipher_int.c      |  110 ++++++++------------------------
 lib/gnutls_cipher_int.h      |   91 +++++++++++++++++++++-----
 lib/gnutls_handshake.c       |   16 ++++-
 lib/gnutls_hash_int.c        |  143 ++++++++++++------------------------------
 lib/gnutls_hash_int.h        |   96 ++++++++++++++++++++++++----
 lib/gnutls_int.h             |    3 +
 lib/gnutls_priority.c        |   18 +++---
 lib/gnutls_sig.c             |   30 +++++++--
 lib/includes/gnutls/crypto.h |    3 +
 lib/libgnutls.map            |    9 +--
 lib/nettle/cipher.c          |   31 +++++++---
 src/benchmark.c              |  123 +++++++++++++++++++++++++++++++-----
 18 files changed, 565 insertions(+), 360 deletions(-)

diff --git a/NEWS b/NEWS
index f91641a..1fb6119 100644
--- a/NEWS
+++ b/NEWS
@@ -22,9 +22,12 @@ using the --verify option. Combined with 
--load-ca-certificate
 it can verify a certificate chain against a list of certificates.
 
 ** API and ABI modifications:
+gnutls_cipher_add_auth: ADDED
+gnutls_cipher_tag: ADDED
 gnutls_ext_register: REMOVED
 gnutls_certificate_get_x509_crls: REMOVED
 gnutls_certificate_get_x509_cas: REMOVED
+gnutls_certificate_get_openpgp_keyring: REMOVED
 gnutls_session_get_server_random: REMOVED
 gnutls_session_get_client_random: REMOVED
 gnutls_session_get_master_secret: REMOVED
diff --git a/lib/crypto-api.c b/lib/crypto-api.c
index d89b7a2..b5f6cc5 100644
--- a/lib/crypto-api.c
+++ b/lib/crypto-api.c
@@ -62,6 +62,57 @@ gnutls_cipher_init (gnutls_cipher_hd_t * handle,
 }
 
 /**
+ * gnutls_cipher_tag:
+ * @handle: is a #gnutls_cipher_hd_t structure.
+ * @tag: will hold the tag
+ * @tag_size: The length of the tag to return
+ *
+ * This function operates on authenticated encryption with
+ * associated data (AEAD) ciphers and will return the
+ * output tag.
+ *
+ * Returns: Zero or a negative value on error.
+ *
+ * Since: 2.99.0
+ **/
+int
+gnutls_cipher_tag (gnutls_cipher_hd_t handle, void *tag, size_t tag_size)
+{
+  if (_gnutls_cipher_is_aead( (cipher_hd_st*)handle)==0)
+    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+  _gnutls_cipher_tag( (cipher_hd_st*)handle, tag, tag_size);
+  
+  return 0;
+}
+
+/**
+ * gnutls_cipher_add_auth:
+ * @handle: is a #gnutls_cipher_hd_t structure.
+ * @text: the data to be authenticated
+ * @text_size: The length of the data
+ *
+ * This function operates on authenticated encryption with
+ * associated data (AEAD) ciphers and authenticate the
+ * input data. This function can only be called before
+ * encryption operations.
+ *
+ * Returns: Zero or a negative value on error.
+ *
+ * Since: 2.99.0
+ **/
+int
+gnutls_cipher_add_auth (gnutls_cipher_hd_t handle, const void *text, size_t 
text_size)
+{
+  if (_gnutls_cipher_is_aead( (cipher_hd_st*)handle)==0)
+    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+  _gnutls_cipher_auth( (cipher_hd_st*)handle, text, text_size);
+  
+  return 0;
+}
+
+/**
  * gnutls_cipher_encrypt:
  * @handle: is a #gnutls_cipher_hd_t structure.
  * @text: the data to encrypt
diff --git a/lib/gnutls_algorithms.c b/lib/gnutls_algorithms.c
index 5696a6e..639f9fa 100644
--- a/lib/gnutls_algorithms.c
+++ b/lib/gnutls_algorithms.c
@@ -187,7 +187,7 @@ static const gnutls_cipher_entry algorithms[] = {
   {"AES-256-CBC", GNUTLS_CIPHER_AES_256_CBC, 16, 32, CIPHER_BLOCK, 16, 0, 0},
   {"AES-192-CBC", GNUTLS_CIPHER_AES_192_CBC, 16, 24, CIPHER_BLOCK, 16, 0, 0},
   {"AES-128-CBC", GNUTLS_CIPHER_AES_128_CBC, 16, 16, CIPHER_BLOCK, 16, 0, 0},
-  {"AES-128-GCM", GNUTLS_CIPHER_AES_128_GCM, 16, 16, CIPHER_STREAM, 4, 0, 1},
+  {"AES-128-GCM", GNUTLS_CIPHER_AES_128_GCM, 16, 16, CIPHER_STREAM, 
AEAD_IMPLICIT_DATA_SIZE, 0, 1},
   {"3DES-CBC", GNUTLS_CIPHER_3DES_CBC, 8, 24, CIPHER_BLOCK, 8, 0, 0},
   {"DES-CBC", GNUTLS_CIPHER_DES_CBC, 8, 8, CIPHER_BLOCK, 8, 0, 0},
   {"ARCFOUR-128", GNUTLS_CIPHER_ARCFOUR_128, 1, 16, CIPHER_STREAM, 0, 0, 0},
@@ -503,6 +503,9 @@ typedef struct
 
 /* GCM: RFC5288 */
 #define GNUTLS_RSA_AES_128_GCM_SHA256 { 0x00, 0x9C }
+#define GNUTLS_DHE_RSA_WITH_AES_128_GCM_SHA256 {0x00,0x9E}
+#define GNUTLS_DHE_DSS_WITH_AES_128_GCM_SHA256 {0x00,0xA2}
+#define GNUTLS_DH_ANON_WITH_AES_128_GCM_SHA256 {0x00,0xA6}
 
 /* Safe renegotiation */
 
@@ -763,11 +766,24 @@ static const gnutls_cipher_suite_entry cs_algorithms[] = {
                              GNUTLS_CIPHER_AES_128_GCM, GNUTLS_KX_RSA,
                              GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
                              GNUTLS_VERSION_MAX),
+  GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+                             GNUTLS_CIPHER_AES_128_GCM, GNUTLS_KX_DHE_RSA,
+                             GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
+                             GNUTLS_VERSION_MAX),
+  GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_DHE_DSS_WITH_AES_128_GCM_SHA256,
+                             GNUTLS_CIPHER_AES_128_GCM, GNUTLS_KX_DHE_DSS,
+                             GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
+                             GNUTLS_VERSION_MAX),
+  GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_DH_ANON_WITH_AES_128_GCM_SHA256,
+                             GNUTLS_CIPHER_AES_128_GCM, GNUTLS_KX_ANON_DH,
+                             GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
+                             GNUTLS_VERSION_MAX),
 /* Renegotiation hack */
   GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RENEGO_PROTECTION_REQUEST,
                              GNUTLS_CIPHER_UNKNOWN, GNUTLS_KX_UNKNOWN,
                              GNUTLS_MAC_UNKNOWN, GNUTLS_SSL3,
                              GNUTLS_VERSION_MAX),
+
   {0, {{0, 0}}, 0, 0, 0, 0, 0}
 };
 
@@ -958,7 +974,7 @@ _gnutls_cipher_is_block (gnutls_cipher_algorithm_t 
algorithm)
 }
 
 int
-_gnutls_cipher_is_aead (gnutls_cipher_algorithm_t algorithm)
+_gnutls_cipher_algo_is_aead (gnutls_cipher_algorithm_t algorithm)
 {
   size_t ret = 0;
 
@@ -1334,7 +1350,15 @@ _gnutls_version_is_supported (gnutls_session_t session,
 int
 _gnutls_version_has_selectable_prf (gnutls_protocol_t version)
 {
-  return version == GNUTLS_TLS1_2;
+  switch (version)
+    {
+    case GNUTLS_TLS1_1:
+    case GNUTLS_TLS1_0:
+    case GNUTLS_SSL3:
+      return 0;
+    default:
+      return 1;
+    }
 }
 
 /* This function determines if the version specified has selectable
@@ -1342,7 +1366,15 @@ _gnutls_version_has_selectable_prf (gnutls_protocol_t 
version)
 int
 _gnutls_version_has_selectable_sighash (gnutls_protocol_t version)
 {
-  return version == GNUTLS_TLS1_2;
+  switch (version)
+    {
+    case GNUTLS_TLS1_1:
+    case GNUTLS_TLS1_0:
+    case GNUTLS_SSL3:
+      return 0;
+    default:
+      return 1;
+    }
 }
 
 /* This function determines if the version specified has support for
@@ -1352,12 +1384,14 @@ _gnutls_version_has_extensions (gnutls_protocol_t 
version)
 {
   switch (version)
     {
-    case GNUTLS_TLS1_0:
-    case GNUTLS_TLS1_1:
-    case GNUTLS_TLS1_2:
-      return 1;
-    default:
+    case GNUTLS_SSL3:
       return 0;
+    default:
+      /* Versions after TLS 1.0 are required to handle extensions.
+       * SSL 3.0 also required extensions to be ignored, but
+       * some earlier draft didn't.
+       */
+      return 1;
     }
 }
 
@@ -1368,11 +1402,12 @@ _gnutls_version_has_explicit_iv (gnutls_protocol_t 
version)
 {
   switch (version)
     {
-    case GNUTLS_TLS1_1:
-    case GNUTLS_TLS1_2:
-      return 1;
-    default:
+    case GNUTLS_TLS1_0:
+    case GNUTLS_SSL3:
       return 0;
+    default:
+      /* All versions after TLS 1.1 have explicit IV */
+      return 1;
     }
 }
 
@@ -1383,12 +1418,10 @@ _gnutls_version_has_variable_padding (gnutls_protocol_t 
version)
 {
   switch (version)
     {
-    case GNUTLS_TLS1_0:
-    case GNUTLS_TLS1_1:
-    case GNUTLS_TLS1_2:
-      return 1;
-    default:
+    case GNUTLS_SSL3:
       return 0;
+    default:
+      return 1;
     }
 }
 
diff --git a/lib/gnutls_algorithms.h b/lib/gnutls_algorithms.h
index eabbda1..50504f3 100644
--- a/lib/gnutls_algorithms.h
+++ b/lib/gnutls_algorithms.h
@@ -77,7 +77,7 @@ cipher_suite_st _gnutls_cipher_suite_get_suite_name 
(cipher_suite_st *
 
 /* Functions for ciphers. */
 int _gnutls_cipher_is_block (gnutls_cipher_algorithm_t algorithm);
-int _gnutls_cipher_is_aead (gnutls_cipher_algorithm_t algorithm);
+int _gnutls_cipher_algo_is_aead (gnutls_cipher_algorithm_t algorithm);
 int _gnutls_cipher_is_ok (gnutls_cipher_algorithm_t algorithm);
 int _gnutls_cipher_get_iv_size (gnutls_cipher_algorithm_t algorithm);
 int _gnutls_cipher_get_export_flag (gnutls_cipher_algorithm_t algorithm);
diff --git a/lib/gnutls_cert.c b/lib/gnutls_cert.c
index ef8b3d5..da80735 100644
--- a/lib/gnutls_cert.c
+++ b/lib/gnutls_cert.c
@@ -102,27 +102,6 @@ gnutls_certificate_free_cas 
(gnutls_certificate_credentials_t sc)
   return;
 }
 
-#ifdef ENABLE_OPENPGP
-
-/**
- * gnutls_certificate_get_openpgp_keyring:
- * @sc: is a #gnutls_certificate_credentials_t structure.
- * @keyring: the exported keyring. Should be treated as constant
- *
- * This function will export the OpenPGP keyring associated with the
- * given credentials.
- *
- * Since: 2.4.0
- **/
-void
-gnutls_certificate_get_openpgp_keyring (gnutls_certificate_credentials_t sc,
-                                        gnutls_openpgp_keyring_t * keyring)
-{
-  *keyring = sc->keyring;
-}
-
-#endif
-
 /**
  * gnutls_certificate_free_ca_names:
  * @sc: is a #gnutls_certificate_credentials_t structure.
diff --git a/lib/gnutls_cipher.c b/lib/gnutls_cipher.c
index 53ca23e..f238fd4 100644
--- a/lib/gnutls_cipher.c
+++ b/lib/gnutls_cipher.c
@@ -42,9 +42,6 @@
 #include "gnutls_constate.h"
 #include <random.h>
 
-#define AEAD_EXPLICIT_DATA 8
-#define AEAD_IMPLICIT_DATA 4
-
 static int _gnutls_compressed2ciphertext (gnutls_session_t session,
                                    opaque * cipher_data, int cipher_size,
                                    gnutls_datum_t compressed,
@@ -226,7 +223,7 @@ calc_enc_length (gnutls_session_t session, int data_size,
     case CIPHER_STREAM:
       length = data_size + hash_size;
       if (auth_cipher)
-        length += AEAD_EXPLICIT_DATA;
+        length += AEAD_EXPLICIT_DATA_SIZE;
 
       break;
     case CIPHER_BLOCK:
@@ -267,21 +264,28 @@ calc_enc_length (gnutls_session_t session, int data_size,
   return length;
 }
 
-#define PREAMBLE_SIZE 16
+#define MAX_PREAMBLE_SIZE 16
+
+/* generates the authentication data (data to be hashed only
+ * and are not to be send). Returns their size.
+ */
 static inline int
-make_preamble (opaque * uint64_data, opaque type, uint16_t c_length,
+make_preamble (opaque * uint64_data, opaque type, int length,
                opaque ver, opaque * preamble)
 {
   opaque minor = _gnutls_version_get_minor (ver);
   opaque major = _gnutls_version_get_major (ver);
   opaque *p = preamble;
+  uint16_t c_length;
+
+  c_length = _gnutls_conv_uint16 (length);
 
   memcpy (p, uint64_data, 8);
   p += 8;
   *p = type;
   p++;
-  if (_gnutls_version_has_variable_padding (ver))
-    { /* TLS 1.0 or higher */
+  if (ver != GNUTLS_SSL3)
+    { /* TLS protocols */
       *p = major;
       p++;
       *p = minor;
@@ -292,18 +296,6 @@ make_preamble (opaque * uint64_data, opaque type, uint16_t 
c_length,
   return p - preamble;
 }
 
-#if 0
-static void dump(const char* desc, uint8_t * data, int data_size)
-{
-int i;
-
-  fprintf(stderr, "%s[%d]: ", desc, data_size);
-  for (i=0;i<data_size;i++)
-    fprintf(stderr, "%.2x:", data[i]);
-  fprintf(stderr, "\n");
-}
-#endif
-
 /* This is the actual encryption 
  * Encrypts the given compressed datum, and puts the result to cipher_data,
  * which has cipher_size size.
@@ -317,10 +309,9 @@ _gnutls_compressed2ciphertext (gnutls_session_t session,
                                record_parameters_st * params)
 {
   uint8_t * tag_ptr = NULL;
-  uint16_t c_length;
   uint8_t pad;
   int length, length_to_encrypt, ret;
-  opaque preamble[PREAMBLE_SIZE];
+  opaque preamble[MAX_PREAMBLE_SIZE];
   int preamble_size;
   int tag_size = _gnutls_auth_cipher_tag_len (&params->write.cipher_state);
   int blocksize = gnutls_cipher_get_block_size (params->cipher_algorithm);
@@ -331,12 +322,11 @@ _gnutls_compressed2ciphertext (gnutls_session_t session,
   int explicit_iv = _gnutls_version_has_explicit_iv 
(session->security_parameters.version);
   int auth_cipher = _gnutls_auth_cipher_is_aead(&params->write.cipher_state);
   
-  c_length = _gnutls_conv_uint16 (compressed.size);
 
   preamble_size =
     make_preamble (UINT64DATA
                    (params->write.sequence_number),
-                   type, c_length, ver, preamble);
+                   type, compressed.size, ver, preamble);
 
   /* Calculate the encrypted length (padding etc.)
    */
@@ -359,18 +349,16 @@ _gnutls_compressed2ciphertext (gnutls_session_t session,
 
   if (explicit_iv)
     {
-      uint8_t nonce[blocksize];
-
-      /* copy the random IV.
-       */
-      ret = _gnutls_rnd (GNUTLS_RND_NONCE, nonce, blocksize);
-      if (ret < 0)
-        return gnutls_assert_val(ret);
 
       if (block_algo == CIPHER_BLOCK)
         {
-          memcpy(data_ptr, nonce, blocksize);
-          _gnutls_auth_cipher_setiv(&params->write.cipher_state, nonce, 
blocksize);
+          /* copy the random IV.
+           */
+          ret = _gnutls_rnd (GNUTLS_RND_NONCE, data_ptr, blocksize);
+          if (ret < 0)
+            return gnutls_assert_val(ret);
+
+          _gnutls_auth_cipher_setiv(&params->write.cipher_state, data_ptr, 
blocksize);
 
           data_ptr += blocksize;
           cipher_data += blocksize;
@@ -378,24 +366,37 @@ _gnutls_compressed2ciphertext (gnutls_session_t session,
         }
       else if (auth_cipher)
         {
+          uint8_t nonce[blocksize];
+
           /* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block
            */
-          if (params->write.IV.data == NULL || params->write.IV.size != 4)
+          if (params->write.IV.data == NULL || params->write.IV.size != 
AEAD_IMPLICIT_DATA_SIZE)
             return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
 
-          memcpy(nonce, params->write.IV.data, AEAD_IMPLICIT_DATA);
-          _gnutls_auth_cipher_setiv(&params->write.cipher_state, nonce, 
AEAD_IMPLICIT_DATA+AEAD_EXPLICIT_DATA);
+          /* Instead of generating a new nonce on every packet, we use the
+           * write.sequence_number (It is a MAY on RFC 5288).
+           */
+          memcpy(nonce, params->write.IV.data, params->write.IV.size);
+          memcpy(&nonce[AEAD_IMPLICIT_DATA_SIZE], 
UINT64DATA(params->write.sequence_number), 8);
+
+          _gnutls_auth_cipher_setiv(&params->write.cipher_state, nonce, 
AEAD_IMPLICIT_DATA_SIZE+AEAD_EXPLICIT_DATA_SIZE);
 
           /* copy the explicit part */
-          memcpy(data_ptr, &nonce[AEAD_IMPLICIT_DATA], AEAD_EXPLICIT_DATA);
+          memcpy(data_ptr, &nonce[AEAD_IMPLICIT_DATA_SIZE], 
AEAD_EXPLICIT_DATA_SIZE);
 
-          data_ptr += AEAD_EXPLICIT_DATA;
-          cipher_data += AEAD_EXPLICIT_DATA;
+          data_ptr += AEAD_EXPLICIT_DATA_SIZE;
+          cipher_data += AEAD_EXPLICIT_DATA_SIZE;
           /* In AEAD ciphers we don't encrypt the tag 
            */
-          length_to_encrypt -= AEAD_EXPLICIT_DATA + tag_size;
+          length_to_encrypt -= AEAD_EXPLICIT_DATA_SIZE + tag_size;
         }
     }
+  else
+    {
+      /* AEAD ciphers have an explicit IV. Shouldn't be used otherwise.
+       */
+      if (auth_cipher) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+    }
 
   memcpy (data_ptr, compressed.data, compressed.size);
   data_ptr += compressed.size;
@@ -436,12 +437,11 @@ _gnutls_ciphertext2compressed (gnutls_session_t session,
                                record_parameters_st * params)
 {
   uint8_t tag[MAX_HASH_SIZE];
-  uint16_t c_length;
   uint8_t pad;
   int length, length_to_decrypt;
   uint16_t blocksize;
   int ret, i, pad_failed = 0;
-  opaque preamble[PREAMBLE_SIZE];
+  opaque preamble[MAX_PREAMBLE_SIZE];
   int preamble_size;
   int ver = gnutls_protocol_get_version (session);
   int tag_size = _gnutls_auth_cipher_tag_len (&params->read.cipher_state);
@@ -465,16 +465,16 @@ _gnutls_ciphertext2compressed (gnutls_session_t session,
           if (params->read.IV.data == NULL || params->read.IV.size != 4)
             return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
           
-          if (ciphertext.size < tag_size+AEAD_EXPLICIT_DATA)
+          if (ciphertext.size < tag_size+AEAD_EXPLICIT_DATA_SIZE)
             return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
 
-          memcpy(nonce, params->read.IV.data, AEAD_IMPLICIT_DATA);
-          memcpy(&nonce[AEAD_IMPLICIT_DATA], ciphertext.data, 
AEAD_EXPLICIT_DATA);
+          memcpy(nonce, params->read.IV.data, AEAD_IMPLICIT_DATA_SIZE);
+          memcpy(&nonce[AEAD_IMPLICIT_DATA_SIZE], ciphertext.data, 
AEAD_EXPLICIT_DATA_SIZE);
           
-          _gnutls_auth_cipher_setiv(&params->read.cipher_state, nonce, 
AEAD_EXPLICIT_DATA+AEAD_IMPLICIT_DATA);
+          _gnutls_auth_cipher_setiv(&params->read.cipher_state, nonce, 
AEAD_EXPLICIT_DATA_SIZE+AEAD_IMPLICIT_DATA_SIZE);
 
-          ciphertext.data += AEAD_EXPLICIT_DATA;
-          ciphertext.size -= AEAD_EXPLICIT_DATA;
+          ciphertext.data += AEAD_EXPLICIT_DATA_SIZE;
+          ciphertext.size -= AEAD_EXPLICIT_DATA_SIZE;
           
           length_to_decrypt = ciphertext.size - tag_size;
         }
@@ -487,7 +487,6 @@ _gnutls_ciphertext2compressed (gnutls_session_t session,
         }
 
       length = ciphertext.size - tag_size;
-      c_length = _gnutls_conv_uint16 ((uint16_t) (length));
 
       /* Pass the type, version, length and compressed through
        * MAC.
@@ -495,7 +494,7 @@ _gnutls_ciphertext2compressed (gnutls_session_t session,
       preamble_size =
         make_preamble (UINT64DATA
                        (params->read.sequence_number), type,
-                       c_length, ver, preamble);
+                       length, ver, preamble);
 
       _gnutls_auth_cipher_add_auth (&params->read.cipher_state, preamble, 
preamble_size);
 
@@ -564,7 +563,6 @@ _gnutls_ciphertext2compressed (gnutls_session_t session,
 
       if (length < 0)
         length = 0;
-      c_length = _gnutls_conv_uint16 ((uint16_t) length);
 
       /* Pass the type, version, length and compressed through
        * MAC.
@@ -572,7 +570,7 @@ _gnutls_ciphertext2compressed (gnutls_session_t session,
       preamble_size =
         make_preamble (UINT64DATA
                        (params->read.sequence_number), type,
-                       c_length, ver, preamble);
+                       length, ver, preamble);
       _gnutls_auth_cipher_add_auth (&params->read.cipher_state, preamble, 
preamble_size);
       _gnutls_auth_cipher_add_auth (&params->read.cipher_state, 
ciphertext.data, length);
 
@@ -581,7 +579,9 @@ _gnutls_ciphertext2compressed (gnutls_session_t session,
       return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
     }
 
-  _gnutls_auth_cipher_tag(&params->read.cipher_state, tag, tag_size);
+  ret = _gnutls_auth_cipher_tag(&params->read.cipher_state, tag, tag_size);
+  if (ret < 0)
+    return gnutls_assert_val(ret);
 
   /* This one was introduced to avoid a timing attack against the TLS
    * 1.0 protocol.
diff --git a/lib/gnutls_cipher_int.c b/lib/gnutls_cipher_int.c
index 410a6b4..e766504 100644
--- a/lib/gnutls_cipher_int.c
+++ b/lib/gnutls_cipher_int.c
@@ -43,6 +43,10 @@ _gnutls_cipher_init (cipher_hd_st * handle, 
gnutls_cipher_algorithm_t cipher,
   int ret = GNUTLS_E_INTERNAL_ERROR;
   const gnutls_crypto_cipher_st *cc = NULL;
 
+  handle->is_aead = _gnutls_cipher_algo_is_aead(cipher);
+  if (handle->is_aead)
+     handle->tag_size = gnutls_cipher_get_block_size(cipher);
+
   /* check if a cipher has been registered
    */
   cc = _gnutls_get_crypto_cipher (cipher);
@@ -108,67 +112,6 @@ cc_cleanup:
   return ret;
 }
 
-void _gnutls_cipher_setiv (const cipher_hd_st * handle, 
-    const void *iv, int ivlen)
-{
-  handle->setiv(handle->handle, iv, ivlen);
-}
-
-int
-_gnutls_cipher_encrypt2 (const cipher_hd_st * handle, const void *text,
-                         int textlen, void *ciphertext, int ciphertextlen)
-{
-  if (handle != NULL && handle->handle != NULL)
-    {
-      return handle->encrypt (handle->handle, text, textlen, ciphertext,
-                              ciphertextlen);
-    }
-
-  return 0;
-}
-
-int
-_gnutls_cipher_decrypt2 (const cipher_hd_st * handle, const void *ciphertext,
-                         int ciphertextlen, void *text, int textlen)
-{
-  if (handle != NULL && handle->handle != NULL)
-    {
-      return handle->decrypt (handle->handle, ciphertext, ciphertextlen,
-                              text, textlen);
-    }
-
-  return 0;
-}
-
-void
-_gnutls_cipher_deinit (cipher_hd_st * handle)
-{
-  if (handle != NULL && handle->handle != NULL)
-    {
-      handle->deinit (handle->handle);
-      handle->handle = NULL;
-    }
-}
-
-/* returns the tag in AUTHENC ciphers */
-void _gnutls_cipher_tag( const cipher_hd_st * handle, void* tag, int tag_size)
-{
-  if (handle != NULL && handle->handle != NULL)
-    {
-      handle->tag (handle->handle, tag, tag_size);
-    }
-}
-
-int _gnutls_cipher_auth (const cipher_hd_st * handle, const void *text,
-                             int textlen)
-{
-  if (handle != NULL && handle->handle != NULL)
-    {
-      return handle->auth (handle->handle, text, textlen);
-    }
-  return GNUTLS_E_INTERNAL_ERROR;
-}
-
 /* Auth_cipher API 
  */
 int _gnutls_auth_cipher_init (auth_cipher_hd_st * handle, 
@@ -207,12 +150,8 @@ int ret;
 
       handle->tag_size = _gnutls_hash_get_algo_len(mac);
     }
-  else
-    {
-      handle->is_auth = _gnutls_cipher_is_aead(cipher);
-      if (handle->is_auth)
-        handle->tag_size = gnutls_cipher_get_block_size(cipher);
-    }
+  else if (_gnutls_cipher_is_aead(&handle->cipher))
+    handle->tag_size = _gnutls_cipher_tag_len(&handle->cipher);
 
   return 0;
 cleanup:
@@ -231,7 +170,7 @@ int _gnutls_auth_cipher_add_auth (auth_cipher_hd_st * 
handle, const void *text,
       else
         return _gnutls_hmac(&handle->mac, text, textlen);
     }
-  else if (handle->is_auth)
+  else if (_gnutls_cipher_is_aead(&handle->cipher))
     return _gnutls_cipher_auth(&handle->cipher, text, textlen);
   else
     return 0;
@@ -255,24 +194,23 @@ int ret;
           gnutls_assert();
           return ret;
         }
-      _gnutls_auth_cipher_tag(handle, tag_ptr, tag_size);
+      ret = _gnutls_auth_cipher_tag(handle, tag_ptr, tag_size);
+      if (ret < 0)
+        return gnutls_assert_val(ret);
 
       ret = _gnutls_cipher_encrypt2(&handle->cipher, text, textlen, 
ciphertext, ciphertextlen);
       if (ret < 0)
-        {
-          gnutls_assert();
-          return ret;
-        }
+        return gnutls_assert_val(ret);
     }
-  else if (handle->is_auth)
+  else if (_gnutls_cipher_is_aead(&handle->cipher))
     {
       ret = _gnutls_cipher_encrypt2(&handle->cipher, text, textlen, 
ciphertext, ciphertextlen);
       if (ret < 0)
-        {
-          gnutls_assert();
-          return ret;
-        }
-      _gnutls_auth_cipher_tag(handle, tag_ptr, tag_size);
+        return gnutls_assert_val(ret);
+
+      ret = _gnutls_auth_cipher_tag(handle, tag_ptr, tag_size);
+      if (ret < 0)
+        return gnutls_assert_val(ret);
     }
 
   return 0;
@@ -306,13 +244,17 @@ int ret;
   return 0;
 }
 
-void _gnutls_auth_cipher_tag(auth_cipher_hd_st * handle, void* tag, int 
tag_size)
+int _gnutls_auth_cipher_tag(auth_cipher_hd_st * handle, void* tag, int 
tag_size)
 {
+int ret = 0;
   if (handle->is_mac)
     {
       if (handle->ssl_hmac)
         {
-          _gnutls_mac_output_ssl3 (&handle->mac, tag);
+          ret = _gnutls_mac_output_ssl3 (&handle->mac, tag);
+          if (ret < 0)
+            return gnutls_assert_val(ret);
+
           _gnutls_hash_reset (&handle->mac);
         }
       else
@@ -321,17 +263,19 @@ void _gnutls_auth_cipher_tag(auth_cipher_hd_st * handle, 
void* tag, int tag_size
           _gnutls_hmac_reset (&handle->mac);
         }
     }
-  else if (handle->is_auth)
+  else if (_gnutls_cipher_is_aead(&handle->cipher))
     {
       _gnutls_cipher_tag(&handle->cipher, tag, tag_size);
     }
+    
+  return 0;
 }
 
 void _gnutls_auth_cipher_deinit (auth_cipher_hd_st * handle)
 {
   if (handle->is_mac)
     {
-      if (handle->ssl_hmac)
+      if (handle->ssl_hmac) /* failure here doesn't matter */
         _gnutls_mac_deinit_ssl3 (&handle->mac, NULL);
       else
         _gnutls_hmac_deinit(&handle->mac, NULL);
diff --git a/lib/gnutls_cipher_int.h b/lib/gnutls_cipher_int.h
index bbc259d..13de477 100644
--- a/lib/gnutls_cipher_int.h
+++ b/lib/gnutls_cipher_int.h
@@ -51,35 +51,91 @@ typedef struct
   cipher_tag_func tag;
   cipher_setiv_func setiv;
   cipher_deinit_func deinit;
+  
+  int tag_size;
+  int is_aead:1;
 } cipher_hd_st;
 
 int _gnutls_cipher_init (cipher_hd_st *, gnutls_cipher_algorithm_t cipher,
                          const gnutls_datum_t * key,
                          const gnutls_datum_t * iv);
 
-/* Add auth data for AUTHENC ciphers
- */
-int _gnutls_cipher_auth (const cipher_hd_st * handle, const void *text,
-                             int textlen);
+inline static void _gnutls_cipher_setiv (const cipher_hd_st * handle, 
+    const void *iv, int ivlen)
+{
+  handle->setiv(handle->handle, iv, ivlen);
+}
 
-void _gnutls_cipher_setiv (const cipher_hd_st * handle, const void *iv,
-                            int ivlen);
+inline static int
+_gnutls_cipher_encrypt2 (const cipher_hd_st * handle, const void *text,
+                         int textlen, void *ciphertext, int ciphertextlen)
+{
+  if (handle != NULL && handle->handle != NULL)
+    {
+      return handle->encrypt (handle->handle, text, textlen, ciphertext,
+                              ciphertextlen);
+    }
 
-int _gnutls_cipher_encrypt2 (const cipher_hd_st * handle, const void *text,
-                             int textlen, void *ciphertext,
-                             int ciphertextlen);
-int _gnutls_cipher_decrypt2 (const cipher_hd_st * handle,
-                             const void *ciphertext, int ciphertextlen,
-                             void *text, int textlen);
+  return 0;
+}
+
+inline static int
+_gnutls_cipher_decrypt2 (const cipher_hd_st * handle, const void *ciphertext,
+                         int ciphertextlen, void *text, int textlen)
+{
+  if (handle != NULL && handle->handle != NULL)
+    {
+      return handle->decrypt (handle->handle, ciphertext, ciphertextlen,
+                              text, textlen);
+    }
+
+  return 0;
+}
+
+inline static void
+_gnutls_cipher_deinit (cipher_hd_st * handle)
+{
+  if (handle != NULL && handle->handle != NULL)
+    {
+      handle->deinit (handle->handle);
+      handle->handle = NULL;
+    }
+}
+
+inline static unsigned int _gnutls_cipher_tag_len( cipher_hd_st * handle)
+{
+  return handle->tag_size;
+}
+
+inline static unsigned int _gnutls_cipher_is_aead( cipher_hd_st * handle)
+{
+  return handle->is_aead;
+}
 
 /* returns the tag in AUTHENC ciphers */
-void _gnutls_cipher_tag( const cipher_hd_st * handle, void* tag, int tag_size);
+inline static void _gnutls_cipher_tag( const cipher_hd_st * handle, void* tag, 
int tag_size)
+{
+  if (handle != NULL && handle->handle != NULL)
+    {
+      handle->tag (handle->handle, tag, tag_size);
+    }
+}
+
+/* Add auth data for AUTHENC ciphers
+ */
+inline static int _gnutls_cipher_auth (const cipher_hd_st * handle, const void 
*text,
+                             int textlen)
+{
+  if (handle != NULL && handle->handle != NULL)
+    {
+      return handle->auth (handle->handle, text, textlen);
+    }
+  return GNUTLS_E_INTERNAL_ERROR;
+}
 
 #define _gnutls_cipher_encrypt(x,y,z) _gnutls_cipher_encrypt2(x,y,z,y,z)
 #define _gnutls_cipher_decrypt(x,y,z) _gnutls_cipher_decrypt2(x,y,z,y,z)
 
-void _gnutls_cipher_deinit (cipher_hd_st * handle);
-
 /* auth_cipher API. Allows combining a cipher with a MAC.
  */
 
@@ -87,7 +143,6 @@ typedef struct
 {
   cipher_hd_st cipher;
   digest_hd_st mac;
-  int is_auth:1;
   int is_mac:1;
   int ssl_hmac:1;
   int tag_size;
@@ -110,7 +165,7 @@ int _gnutls_auth_cipher_encrypt2_tag (auth_cipher_hd_st * 
handle, const uint8_t
 int _gnutls_auth_cipher_decrypt2 (auth_cipher_hd_st * handle,
                              const void *ciphertext, int ciphertextlen,
                              void *text, int textlen);
-void _gnutls_auth_cipher_tag( auth_cipher_hd_st * handle, void* tag, int 
tag_size);
+int _gnutls_auth_cipher_tag( auth_cipher_hd_st * handle, void* tag, int 
tag_size);
 
 inline static void _gnutls_auth_cipher_setiv (const auth_cipher_hd_st * 
handle, 
     const void *iv, int ivlen)
@@ -125,7 +180,7 @@ inline static unsigned int _gnutls_auth_cipher_tag_len( 
auth_cipher_hd_st * hand
 
 inline static unsigned int _gnutls_auth_cipher_is_aead( auth_cipher_hd_st * 
handle)
 {
-  return handle->is_auth;
+  return _gnutls_cipher_is_aead(&handle->cipher);
 }
 
 #define _gnutls_auth_cipher_encrypt_tag(x,y,z,t,s,a) 
_gnutls_auth_cipher_encrypt2_tag(x,y,z,y,z,t,s,a)
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
index 5715306..7c884c7 100644
--- a/lib/gnutls_handshake.c
+++ b/lib/gnutls_handshake.c
@@ -223,14 +223,26 @@ _gnutls_ssl3_finished (gnutls_session_t session, int 
type, opaque * ret)
   _gnutls_hash (&td_md5, mesg, siz);
   _gnutls_hash (&td_sha, mesg, siz);
 
-  _gnutls_mac_deinit_ssl3_handshake (&td_md5, ret,
+  rc = _gnutls_mac_deinit_ssl3_handshake (&td_md5, ret,
                                      session->
                                      security_parameters.master_secret,
                                      GNUTLS_MASTER_SIZE);
-  _gnutls_mac_deinit_ssl3_handshake (&td_sha, &ret[16],
+  if (rc < 0)
+    {
+      _gnutls_hash_deinit (&td_md5, NULL);
+      _gnutls_hash_deinit (&td_sha, NULL);
+      return gnutls_assert_val(rc);
+    }
+
+  rc = _gnutls_mac_deinit_ssl3_handshake (&td_sha, &ret[16],
                                      session->
                                      security_parameters.master_secret,
                                      GNUTLS_MASTER_SIZE);
+  if (rc < 0)
+    {
+      _gnutls_hash_deinit (&td_sha, NULL);
+      return gnutls_assert_val(rc);
+    }
 
   return 0;
 }
diff --git a/lib/gnutls_hash_int.c b/lib/gnutls_hash_int.c
index 928c656..e925042 100644
--- a/lib/gnutls_hash_int.c
+++ b/lib/gnutls_hash_int.c
@@ -103,6 +103,21 @@ _gnutls_hash_init (digest_hd_st * dig, 
gnutls_digest_algorithm_t algorithm)
   return 0;
 }
 
+void
+_gnutls_hash_deinit (digest_hd_st * handle, void *digest)
+{
+  if (handle->handle == NULL)
+    {
+      return;
+    }
+
+  if (digest != NULL)
+    _gnutls_hash_output (handle, digest);
+
+  handle->deinit (handle->handle);
+  handle->handle = NULL;
+}
+
 /* returns the output size of the given hash/mac algorithm
  */
 int
@@ -112,16 +127,6 @@ _gnutls_hash_get_algo_len (gnutls_digest_algorithm_t 
algorithm)
 }
 
 int
-_gnutls_hash (digest_hd_st * handle, const void *text, size_t textlen)
-{
-  if (textlen > 0)
-    {
-      handle->hash (handle->handle, text, textlen);
-    }
-  return 0;
-}
-
-int
 _gnutls_hash_copy (digest_hd_st * dst, digest_hd_st * src)
 {
 
@@ -136,46 +141,7 @@ _gnutls_hash_copy (digest_hd_st * dst, digest_hd_st * src)
   return src->copy (&dst->handle, src->handle);
 }
 
-/* when the current output is needed without calling deinit
- */
-void
-_gnutls_hash_output (digest_hd_st * handle, void *digest)
-{
-  size_t maclen;
-
-  maclen = _gnutls_hash_get_algo_len (handle->algorithm);
-
-  if (digest != NULL)
-    {
-      handle->output (handle->handle, digest, maclen);
-    }
-}
-
-void
-_gnutls_hash_deinit (digest_hd_st * handle, void *digest)
-{
-  if (handle->handle == NULL)
-    {
-      return;
-    }
-
-  if (digest != NULL)
-    _gnutls_hash_output (handle, digest);
-
-  handle->deinit (handle->handle);
-  handle->handle = NULL;
-}
-
-void
-_gnutls_hash_reset (digest_hd_st * handle)
-{
-  if (handle->handle == NULL)
-    {
-      return;
-    }
 
-  handle->reset (handle->handle);
-}
 
 int
 _gnutls_hash_fast (gnutls_digest_algorithm_t algorithm,
@@ -207,12 +173,6 @@ _gnutls_hash_fast (gnutls_digest_algorithm_t algorithm,
 /* HMAC interface */
 
 int
-_gnutls_hmac_get_algo_len (gnutls_mac_algorithm_t algorithm)
-{
-  return digest_length (algorithm);
-}
-
-int
 _gnutls_hmac_fast (gnutls_mac_algorithm_t algorithm, const void *key,
                    int keylen, const void *text, size_t textlen, void *digest)
 {
@@ -297,29 +257,6 @@ _gnutls_hmac_init (digest_hd_st * dig, 
gnutls_mac_algorithm_t algorithm,
   return 0;
 }
 
-int
-_gnutls_hmac (digest_hd_st * handle, const void *text, size_t textlen)
-{
-  if (textlen > 0)
-    {
-      return handle->hash (handle->handle, text, textlen);
-    }
-  return 0;
-}
-
-void
-_gnutls_hmac_output (digest_hd_st * handle, void *digest)
-{
-  int maclen;
-
-  maclen = _gnutls_hmac_get_algo_len (handle->algorithm);
-
-  if (digest != NULL)
-    {
-      handle->output (handle->handle, digest, maclen);
-    }
-}
-
 void
 _gnutls_hmac_deinit (digest_hd_st * handle, void *digest)
 {
@@ -335,17 +272,6 @@ _gnutls_hmac_deinit (digest_hd_st * handle, void *digest)
   handle->handle = NULL;
 }
 
-void
-_gnutls_hmac_reset (digest_hd_st * handle)
-{
-  if (handle->handle == NULL)
-    {
-      return;
-    }
-
-  handle->reset (handle->handle);
-}
-
 inline static int
 get_padsize (gnutls_mac_algorithm_t algorithm)
 {
@@ -360,7 +286,6 @@ get_padsize (gnutls_mac_algorithm_t algorithm)
     }
 }
 
-
 /* Special functions for SSL3 MAC
  */
 
@@ -397,7 +322,7 @@ _gnutls_mac_init_ssl3 (digest_hd_st * ret, 
gnutls_mac_algorithm_t algorithm,
   return 0;
 }
 
-void
+int 
 _gnutls_mac_output_ssl3 (digest_hd_st * handle, void *digest)
 {
   opaque ret[MAX_HASH_SIZE];
@@ -410,7 +335,7 @@ _gnutls_mac_output_ssl3 (digest_hd_st * handle, void 
*digest)
   if (padsize == 0)
     {
       gnutls_assert ();
-      return;
+      return GNUTLS_E_INTERNAL_ERROR;
     }
 
   memset (opad, 0x5C, padsize);
@@ -419,7 +344,7 @@ _gnutls_mac_output_ssl3 (digest_hd_st * handle, void 
*digest)
   if (rc < 0)
     {
       gnutls_assert ();
-      return;
+      return rc;
     }
 
   if (handle->keysize > 0)
@@ -431,16 +356,22 @@ _gnutls_mac_output_ssl3 (digest_hd_st * handle, void 
*digest)
   _gnutls_hash (&td, ret, block);
 
   _gnutls_hash_deinit (&td, digest);
+  
+  return 0;
 }
 
-void
+int
 _gnutls_mac_deinit_ssl3 (digest_hd_st * handle, void *digest)
 {
-  if (digest != NULL) _gnutls_mac_output_ssl3(handle, digest);
+int ret = 0;
+
+  if (digest != NULL) ret = _gnutls_mac_output_ssl3(handle, digest);
   _gnutls_hash_deinit(handle, NULL);
+  
+  return ret;
 }
 
-void
+int
 _gnutls_mac_deinit_ssl3_handshake (digest_hd_st * handle,
                                    void *digest, opaque * key,
                                    uint32_t key_size)
@@ -456,7 +387,8 @@ _gnutls_mac_deinit_ssl3_handshake (digest_hd_st * handle,
   if (padsize == 0)
     {
       gnutls_assert ();
-      return;
+      rc = GNUTLS_E_INTERNAL_ERROR;
+      goto cleanup;
     }
 
   memset (opad, 0x5C, padsize);
@@ -466,7 +398,7 @@ _gnutls_mac_deinit_ssl3_handshake (digest_hd_st * handle,
   if (rc < 0)
     {
       gnutls_assert ();
-      return;
+      goto cleanup;
     }
 
   if (key_size > 0)
@@ -484,7 +416,11 @@ _gnutls_mac_deinit_ssl3_handshake (digest_hd_st * handle,
 
   _gnutls_hash_deinit (&td, digest);
 
-  return;
+  return 0;
+
+cleanup:
+  _gnutls_hash_deinit(handle, NULL);
+  return rc;
 }
 
 static int
@@ -516,6 +452,9 @@ ssl3_sha (int i, opaque * secret, int secret_len,
   return 0;
 }
 
+#define SHA1_DIGEST_OUTPUT 20
+#define MD5_DIGEST_OUTPUT 16
+
 static int
 ssl3_md5 (int i, opaque * secret, int secret_len,
           opaque * rnd, int rnd_len, void *digest)
@@ -541,7 +480,7 @@ ssl3_md5 (int i, opaque * secret, int secret_len,
       return ret;
     }
 
-  _gnutls_hash (&td, tmp, _gnutls_hash_get_algo_len (GNUTLS_MAC_SHA1));
+  _gnutls_hash (&td, tmp, SHA1_DIGEST_OUTPUT);
 
   _gnutls_hash_deinit (&td, digest);
   return 0;
@@ -554,7 +493,7 @@ _gnutls_ssl3_hash_md5 (const void *first, int first_len,
 {
   opaque digest[MAX_HASH_SIZE];
   digest_hd_st td;
-  int block = _gnutls_hash_get_algo_len (GNUTLS_MAC_MD5);
+  int block = MD5_DIGEST_OUTPUT;
   int rc;
 
   rc = _gnutls_hash_init (&td, GNUTLS_MAC_MD5);
@@ -588,7 +527,7 @@ _gnutls_ssl3_generate_random (void *secret, int secret_len,
 {
   int i = 0, copy, output_bytes;
   opaque digest[MAX_HASH_SIZE];
-  int block = _gnutls_hash_get_algo_len (GNUTLS_MAC_MD5);
+  int block = MD5_DIGEST_OUTPUT;
   int result, times;
 
   output_bytes = 0;
diff --git a/lib/gnutls_hash_int.h b/lib/gnutls_hash_int.h
index 95f1402..d0bcf14 100644
--- a/lib/gnutls_hash_int.h
+++ b/lib/gnutls_hash_int.h
@@ -62,23 +62,91 @@ typedef struct
 /* basic functions */
 int _gnutls_hmac_init (digest_hd_st *, gnutls_mac_algorithm_t algorithm,
                        const void *key, int keylen);
-int _gnutls_hmac_get_algo_len (gnutls_mac_algorithm_t algorithm);
-int _gnutls_hmac (digest_hd_st * handle, const void *text, size_t textlen);
-void _gnutls_hmac_reset (digest_hd_st * handle);
-
+int _gnutls_hash_get_algo_len (gnutls_digest_algorithm_t algorithm);
+#define _gnutls_hmac_get_algo_len _gnutls_hash_get_algo_len
 int _gnutls_hmac_fast (gnutls_mac_algorithm_t algorithm, const void *key,
                        int keylen, const void *text, size_t textlen,
                        void *digest);
 
-void _gnutls_hmac_deinit (digest_hd_st * handle, void *digest);
-void _gnutls_hmac_output (digest_hd_st * handle, void *digest);
+inline static int
+_gnutls_hmac (digest_hd_st * handle, const void *text, size_t textlen)
+{
+  if (textlen > 0)
+    {
+      return handle->hash (handle->handle, text, textlen);
+    }
+  return 0;
+}
+
+inline static void
+_gnutls_hmac_output (digest_hd_st * handle, void *digest)
+{
+  int maclen;
+
+  maclen = _gnutls_hmac_get_algo_len (handle->algorithm);
+
+  if (digest != NULL)
+    {
+      handle->output (handle->handle, digest, maclen);
+    }
+}
+
+void
+_gnutls_hmac_deinit (digest_hd_st * handle, void *digest);
+
+inline static void
+_gnutls_hmac_reset (digest_hd_st * handle)
+{
+  if (handle->handle == NULL)
+    {
+      return;
+    }
+
+  handle->reset (handle->handle);
+}
+
 
+/* Hash interface */
 int _gnutls_hash_init (digest_hd_st *, gnutls_digest_algorithm_t algorithm);
-int _gnutls_hash_get_algo_len (gnutls_digest_algorithm_t algorithm);
-int _gnutls_hash (digest_hd_st * handle, const void *text, size_t textlen);
-void _gnutls_hash_deinit (digest_hd_st * handle, void *digest);
-void _gnutls_hash_reset (digest_hd_st * handle);
-void _gnutls_hash_output (digest_hd_st * handle, void *digest);
+
+inline static int
+_gnutls_hash (digest_hd_st * handle, const void *text, size_t textlen)
+{
+  if (textlen > 0)
+    {
+      handle->hash (handle->handle, text, textlen);
+    }
+  return 0;
+}
+
+/* when the current output is needed without calling deinit
+ */
+inline static void
+_gnutls_hash_output (digest_hd_st * handle, void *digest)
+{
+  size_t maclen;
+
+  maclen = _gnutls_hash_get_algo_len (handle->algorithm);
+
+  if (digest != NULL)
+    {
+      handle->output (handle->handle, digest, maclen);
+    }
+}
+
+inline static void
+_gnutls_hash_reset (digest_hd_st * handle)
+{
+  if (handle->handle == NULL)
+    {
+      return;
+    }
+
+  handle->reset (handle->handle);
+}
+
+void
+_gnutls_hash_deinit (digest_hd_st * handle, void *digest);
 
 int
 _gnutls_hash_fast (gnutls_digest_algorithm_t algorithm,
@@ -87,8 +155,8 @@ _gnutls_hash_fast (gnutls_digest_algorithm_t algorithm,
 /* help functions */
 int _gnutls_mac_init_ssl3 (digest_hd_st *, gnutls_mac_algorithm_t algorithm,
                            void *key, int keylen);
-void _gnutls_mac_deinit_ssl3 (digest_hd_st * handle, void *digest);
-void _gnutls_mac_output_ssl3 (digest_hd_st * handle, void *digest);
+int _gnutls_mac_deinit_ssl3 (digest_hd_st * handle, void *digest);
+int _gnutls_mac_output_ssl3 (digest_hd_st * handle, void *digest);
 
 int _gnutls_ssl3_generate_random (void *secret, int secret_len,
                                   void *rnd, int random_len, int bytes,
@@ -97,7 +165,7 @@ int _gnutls_ssl3_hash_md5 (const void *first, int first_len,
                            const void *second, int second_len,
                            int ret_len, opaque * ret);
 
-void _gnutls_mac_deinit_ssl3_handshake (digest_hd_st * handle, void *digest,
+int _gnutls_mac_deinit_ssl3_handshake (digest_hd_st * handle, void *digest,
                                         opaque * key, uint32_t key_size);
 
 int _gnutls_hash_copy (digest_hd_st * dst_handle, digest_hd_st * src_handle);
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 0727596..14e2c0e 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -92,6 +92,9 @@ typedef struct
 #define SESSION_TICKET_IV_SIZE 16
 #define SESSION_TICKET_MAC_SECRET_SIZE 32
 
+#define AEAD_EXPLICIT_DATA_SIZE 8
+#define AEAD_IMPLICIT_DATA_SIZE 4
+
 #define GNUTLS_MASTER_SIZE 48
 #define GNUTLS_RANDOM_SIZE 32
 
diff --git a/lib/gnutls_priority.c b/lib/gnutls_priority.c
index 5884a0f..2600a47 100644
--- a/lib/gnutls_priority.c
+++ b/lib/gnutls_priority.c
@@ -262,7 +262,6 @@ static const int kx_priority_secure[] = {
 };
 
 static const int cipher_priority_performance[] = {
-  GNUTLS_CIPHER_AES_128_GCM,
   GNUTLS_CIPHER_ARCFOUR_128,
 #ifdef ENABLE_CAMELLIA
   GNUTLS_CIPHER_CAMELLIA_128_CBC,
@@ -273,7 +272,9 @@ static const int cipher_priority_performance[] = {
 #ifdef ENABLE_CAMELLIA
   GNUTLS_CIPHER_CAMELLIA_256_CBC,
 #endif
-  /* GNUTLS_CIPHER_ARCFOUR_40: Insecure, don't add! */
+#ifdef NETTLE_GCM
+  GNUTLS_CIPHER_AES_128_GCM,
+#endif
   0
 };
 
@@ -282,14 +283,15 @@ static const int cipher_priority_normal[] = {
 #ifdef ENABLE_CAMELLIA
   GNUTLS_CIPHER_CAMELLIA_128_CBC,
 #endif
-  GNUTLS_CIPHER_AES_128_GCM,
   GNUTLS_CIPHER_AES_256_CBC,
 #ifdef ENABLE_CAMELLIA
   GNUTLS_CIPHER_CAMELLIA_256_CBC,
 #endif
+#ifdef NETTLE_GCM
+  GNUTLS_CIPHER_AES_128_GCM,
+#endif
   GNUTLS_CIPHER_3DES_CBC,
   GNUTLS_CIPHER_ARCFOUR_128,
-  /* GNUTLS_CIPHER_ARCFOUR_40: Insecure, don't add! */
   0
 };
 
@@ -298,10 +300,10 @@ static const int cipher_priority_secure128[] = {
 #ifdef ENABLE_CAMELLIA
   GNUTLS_CIPHER_CAMELLIA_128_CBC,
 #endif
+#ifdef NETTLE_GCM
   GNUTLS_CIPHER_AES_128_GCM,
+#endif
   GNUTLS_CIPHER_3DES_CBC,
-  GNUTLS_CIPHER_ARCFOUR_128,
-  /* GNUTLS_CIPHER_ARCFOUR_40: Insecure, don't add! */
   0
 };
 
@@ -315,10 +317,10 @@ static const int cipher_priority_secure256[] = {
 #ifdef ENABLE_CAMELLIA
   GNUTLS_CIPHER_CAMELLIA_128_CBC,
 #endif
+#ifdef NETTLE_GCM
   GNUTLS_CIPHER_AES_128_GCM,
+#endif
   GNUTLS_CIPHER_3DES_CBC,
-  GNUTLS_CIPHER_ARCFOUR_128,
-  /* GNUTLS_CIPHER_ARCFOUR_40: Insecure, don't add! */
   0
 };
 
diff --git a/lib/gnutls_sig.c b/lib/gnutls_sig.c
index a23bd7f..17ebf40 100644
--- a/lib/gnutls_sig.c
+++ b/lib/gnutls_sig.c
@@ -585,18 +585,29 @@ _gnutls_handshake_verify_cert_vrfy (gnutls_session_t 
session,
       ret = _gnutls_generate_master (session, 1);
       if (ret < 0)
         {
-          gnutls_assert ();
-          return ret;
+          _gnutls_hash_deinit (&td_md5, NULL);
+          _gnutls_hash_deinit (&td_sha, NULL);
+          return gnutls_assert_val(ret);
         }
 
-      _gnutls_mac_deinit_ssl3_handshake (&td_md5, concat,
+      ret = _gnutls_mac_deinit_ssl3_handshake (&td_md5, concat,
                                          session->
                                          security_parameters.master_secret,
                                          GNUTLS_MASTER_SIZE);
-      _gnutls_mac_deinit_ssl3_handshake (&td_sha, &concat[16],
+      if (ret < 0)
+        {
+          _gnutls_hash_deinit (&td_sha, NULL);
+          return gnutls_assert_val(ret);
+        }
+
+      ret = _gnutls_mac_deinit_ssl3_handshake (&td_sha, &concat[16],
                                          session->
                                          security_parameters.master_secret,
                                          GNUTLS_MASTER_SIZE);
+      if (ret < 0)
+        {
+          return gnutls_assert_val(ret);
+        }
     }
   else
     {
@@ -744,13 +755,16 @@ _gnutls_handshake_sign_cert_vrfy (gnutls_session_t 
session,
       if (ret < 0)
         {
           gnutls_assert ();
+          _gnutls_hash_deinit (&td_sha, NULL);
           return ret;
         }
 
-      _gnutls_mac_deinit_ssl3_handshake (&td_sha, &concat[16],
+      ret = _gnutls_mac_deinit_ssl3_handshake (&td_sha, &concat[16],
                                          session->
                                          security_parameters.master_secret,
                                          GNUTLS_MASTER_SIZE);
+      if (ret < 0)
+        return gnutls_assert_val(ret);
     }
   else
     _gnutls_hash_deinit (&td_sha, &concat[16]);
@@ -769,10 +783,14 @@ _gnutls_handshake_sign_cert_vrfy (gnutls_session_t 
session,
         }
 
       if (ver == GNUTLS_SSL3)
-        _gnutls_mac_deinit_ssl3_handshake (&td_md5, concat,
+        {
+          ret = _gnutls_mac_deinit_ssl3_handshake (&td_md5, concat,
                                            session->
                                            security_parameters.master_secret,
                                            GNUTLS_MASTER_SIZE);
+          if (ret < 0)
+            return gnutls_assert_val(ret);
+        }
       else
         _gnutls_hash_deinit (&td_md5, concat);
 
diff --git a/lib/includes/gnutls/crypto.h b/lib/includes/gnutls/crypto.h
index edec2f4..0b2b00b 100644
--- a/lib/includes/gnutls/crypto.h
+++ b/lib/includes/gnutls/crypto.h
@@ -47,6 +47,9 @@ extern "C"
                               size_t textlen, void *ciphertext,
                               size_t ciphertextlen);
 
+  int gnutls_cipher_tag( gnutls_cipher_hd_t handle, void* tag, size_t 
tag_size);
+  int gnutls_cipher_add_auth( gnutls_cipher_hd_t handle, const void* test, 
size_t textlen);
+
   void gnutls_cipher_deinit (gnutls_cipher_hd_t handle);
   int gnutls_cipher_get_block_size (gnutls_cipher_algorithm_t algorithm);
 
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 623c0fd..d0b178b 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -52,11 +52,8 @@ GNUTLS_1_4
     gnutls_certificate_free_credentials;
     gnutls_certificate_free_crls;
     gnutls_certificate_free_keys;
-    gnutls_certificate_get_openpgp_keyring;
     gnutls_certificate_get_ours;
     gnutls_certificate_get_peers;
-    gnutls_certificate_get_x509_cas;
-    gnutls_certificate_get_x509_crls;
     gnutls_certificate_send_x509_rdn_sequence;
     gnutls_certificate_server_set_request;
     gnutls_certificate_server_set_retrieve_function;
@@ -139,7 +136,6 @@ GNUTLS_1_4
     gnutls_dh_set_prime_bits;
     gnutls_error_is_fatal;
     gnutls_error_to_alert;
-    gnutls_ext_register;
     gnutls_fingerprint;
     gnutls_free;
     gnutls_global_deinit;
@@ -334,13 +330,10 @@ GNUTLS_1_4
     gnutls_server_name_get;
     gnutls_server_name_set;
     gnutls_session_enable_compatibility_mode;
-    gnutls_session_get_client_random;
     gnutls_session_get_data2;
     gnutls_session_get_data;
     gnutls_session_get_id;
-    gnutls_session_get_master_secret;
     gnutls_session_get_ptr;
-    gnutls_session_get_server_random;
     gnutls_session_is_resumed;
     gnutls_session_set_data;
     gnutls_session_set_finished_function;
@@ -703,6 +696,8 @@ GNUTLS_2_12
        gnutls_x509_crl_list_import;
        gnutls_x509_crl_list_import2;
        gnutls_x509_crt_list_import2;
+       gnutls_cipher_tag;
+       gnutls_cipher_add_auth;
 } GNUTLS_2_10;
 
 GNUTLS_PRIVATE {
diff --git a/lib/nettle/cipher.c b/lib/nettle/cipher.c
index a2b5407..93c4e52 100644
--- a/lib/nettle/cipher.c
+++ b/lib/nettle/cipher.c
@@ -164,8 +164,6 @@ static void _gcm_encrypt(void *_ctx, nettle_crypt_func f,
 {
 struct gcm_full_ctx *ctx = _ctx;
 
-  gcm_set_iv(&ctx->gcm, GCM_DEFAULT_NONCE_SIZE, iv);
-
   return gcm_encrypt(&ctx->gcm, ctx->cipher, ctx->f, length, dst, src);
 }
 
@@ -176,8 +174,6 @@ static void _gcm_decrypt(void *_ctx, nettle_crypt_func f,
 {
 struct gcm_full_ctx *ctx = _ctx;
 
-  gcm_set_iv(&ctx->gcm, GCM_DEFAULT_NONCE_SIZE, iv);
-
   return gcm_decrypt(&ctx->gcm, ctx->cipher, ctx->f, length, dst, src);
 }
 
@@ -356,14 +352,31 @@ wrap_nettle_cipher_setkey (void *_ctx, const void *key, 
size_t keysize)
 static int
 wrap_nettle_cipher_setiv (void *_ctx, const void *iv, size_t ivsize)
 {
-  struct nettle_cipher_ctx *ctx = _ctx;
+struct nettle_cipher_ctx *ctx = _ctx;
 
-  if (ivsize > ctx->block_size)
+  switch (ctx->algo)
     {
-      gnutls_assert ();
-      return GNUTLS_E_INVALID_REQUEST;
+#ifdef NETTLE_GCM
+    case GNUTLS_CIPHER_AES_128_GCM:
+      if (ivsize != GCM_DEFAULT_NONCE_SIZE)
+        {
+          gnutls_assert ();
+          return GNUTLS_E_INVALID_REQUEST;
+        }
+
+      ctx->mode_ctx.gcm.gcm.data_size = ctx->mode_ctx.gcm.gcm.auth_size = 0;
+      gcm_set_iv(&ctx->mode_ctx.gcm.gcm, GCM_DEFAULT_NONCE_SIZE, iv);
+      break;
+#endif
+    default:
+      if (ivsize > ctx->block_size)
+        {
+          gnutls_assert ();
+          return GNUTLS_E_INVALID_REQUEST;
+        }
+
+      memcpy (ctx->iv, iv, ivsize);
     }
-  memcpy (ctx->iv, iv, ivsize);
 
   return 0;
 }
diff --git a/src/benchmark.c b/src/benchmark.c
index df96f53..d8196d7 100644
--- a/src/benchmark.c
+++ b/src/benchmark.c
@@ -82,10 +82,11 @@ value2human (double bytes, double time, double *data, 
double *speed,
 }
 
 static void
-cipher_bench (int algo, int size)
+cipher_mac_bench (int algo, int mac_algo, int size)
 {
   int ret;
   gnutls_cipher_hd_t ctx;
+  gnutls_hmac_hd_t mac_ctx;
   void *_key, *_iv;
   gnutls_datum_t key, iv;
   struct timespec start, stop;
@@ -95,6 +96,92 @@ cipher_bench (int algo, int size)
   int blocksize = gnutls_cipher_get_block_size (algo);
   int keysize = gnutls_cipher_get_key_size (algo);
   char metric[16];
+  int step = size*1024;
+
+  _key = malloc (keysize);
+  if (_key == NULL)
+    return;
+  memset (_key, 0xf0, keysize);
+
+  _iv = malloc (blocksize);
+  if (_iv == NULL)
+    return;
+  memset (_iv, 0xf0, blocksize);
+
+  iv.data = _iv;
+  iv.size = blocksize;
+
+  key.data = _key;
+  key.size = keysize;
+
+  printf ("Checking %s with %s (%dkb payload)... ", gnutls_cipher_get_name 
(algo),
+      gnutls_mac_get_name(mac_algo), size);
+  fflush (stdout);
+
+  must_finish = 0;
+  alarm (5);
+
+  gettime (&start);
+
+  ret = gnutls_hmac_init(&mac_ctx, mac_algo, key.data, key.size);
+  if (ret < 0)
+    {
+      fprintf (stderr, "error: %s\n", gnutls_strerror (ret));
+      goto leave;
+    }
+
+  ret = gnutls_cipher_init (&ctx, algo, &key, &iv);
+  if (ret < 0)
+    {
+      fprintf (stderr, "error: %s\n", gnutls_strerror (ret));
+      goto leave;
+    }
+
+  gnutls_hmac(mac_ctx, data, 1024);
+
+  do
+    {
+      gnutls_hmac(mac_ctx, data, step);
+      gnutls_cipher_encrypt (ctx, data, step);
+      data_size += step;
+    }
+  while (must_finish == 0);
+
+  gnutls_cipher_deinit (ctx);
+  gnutls_hmac_deinit(mac_ctx, NULL);
+
+  gettime (&stop);
+
+  secs = (stop.tv_sec * 1000 + stop.tv_nsec / (1000 * 1000) -
+          (start.tv_sec * 1000 + start.tv_nsec / (1000 * 1000)));
+  secs /= 1000;
+
+  value2human (data_size, secs, &ddata, &dspeed, metric);
+  printf ("Encrypted and hashed %.2f %s in %.2f secs: ", ddata, metric, secs);
+  printf ("%.2f %s/sec\n", dspeed, metric);
+
+leave:
+  free (_key);
+  free (_iv);
+
+}
+
+
+static void
+cipher_bench (int algo, int size, int aead)
+{
+  int ret;
+  gnutls_cipher_hd_t ctx;
+  void *_key, *_iv;
+  gnutls_datum_t key, iv;
+  struct timespec start, stop;
+  double secs;
+  double data_size = 0;
+  double dspeed, ddata;
+  int blocksize = gnutls_cipher_get_block_size (algo);
+  int keysize = gnutls_cipher_get_key_size (algo);
+  char metric[16];
+  int step = size*1024;
 
   _key = malloc (keysize);
   if (_key == NULL)
@@ -128,10 +215,13 @@ cipher_bench (int algo, int size)
       goto leave;
     }
 
+  if (aead)
+    gnutls_cipher_add_auth (ctx, data, 1024);
+
   do
     {
-      gnutls_cipher_encrypt (ctx, data, size * 1024);
-      data_size += size * 1024;
+      gnutls_cipher_encrypt (ctx, data, step);
+      data_size += step;
     }
   while (must_finish == 0);
 
@@ -163,6 +253,7 @@ mac_bench (int algo, int size)
   double ddata, dspeed;
   int blocksize = gnutls_hmac_get_len (algo);
   char metric[16];
+  int step = size*1024;
 
   _key = malloc (blocksize);
   if (_key == NULL)
@@ -179,8 +270,8 @@ mac_bench (int algo, int size)
 
   do
     {
-      gnutls_hmac_fast (algo, _key, blocksize, data, size * 1024, _key);
-      data_size += size * 1024;
+      gnutls_hmac_fast (algo, _key, blocksize, data, step, _key);
+      data_size += step;
     }
   while (must_finish == 0);
 
@@ -213,25 +304,21 @@ main (int argc, char **argv)
   gnutls_global_set_log_level (debug_level);
   gnutls_global_init ();
 
-  mac_bench (GNUTLS_MAC_SHA1, 4);
-  mac_bench (GNUTLS_MAC_SHA1, 8);
+  gnutls_rnd( GNUTLS_RND_NONCE, data, sizeof(data));
+
+  cipher_bench ( GNUTLS_CIPHER_AES_128_GCM, 16, 1);
+  cipher_mac_bench ( GNUTLS_CIPHER_AES_128_CBC, GNUTLS_MAC_SHA256, 16);
+  cipher_mac_bench ( GNUTLS_CIPHER_AES_128_CBC, GNUTLS_MAC_SHA1, 16);
+
   mac_bench (GNUTLS_MAC_SHA1, 16);
 
-  mac_bench (GNUTLS_MAC_SHA256, 4);
-  mac_bench (GNUTLS_MAC_SHA256, 8);
   mac_bench (GNUTLS_MAC_SHA256, 16);
 
-  cipher_bench (GNUTLS_CIPHER_3DES_CBC, 4);
-  cipher_bench (GNUTLS_CIPHER_3DES_CBC, 8);
-  cipher_bench (GNUTLS_CIPHER_3DES_CBC, 16);
+  cipher_bench (GNUTLS_CIPHER_3DES_CBC, 16, 0);
 
-  cipher_bench (GNUTLS_CIPHER_AES_128_CBC, 4);
-  cipher_bench (GNUTLS_CIPHER_AES_128_CBC, 8);
-  cipher_bench (GNUTLS_CIPHER_AES_128_CBC, 16);
+  cipher_bench (GNUTLS_CIPHER_AES_128_CBC, 16, 0);
 
-  cipher_bench (GNUTLS_CIPHER_ARCFOUR, 4);
-  cipher_bench (GNUTLS_CIPHER_ARCFOUR, 8);
-  cipher_bench (GNUTLS_CIPHER_ARCFOUR, 16);
+  cipher_bench (GNUTLS_CIPHER_ARCFOUR, 16, 0);
 
   return 0;
 }


hooks/post-receive
-- 
GNU gnutls



reply via email to

[Prev in Thread] Current Thread [Next in Thread]