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-94-gbb42c28


From: Nikos Mavrogiannopoulos
Subject: [SCM] GNU gnutls branch, master, updated. gnutls_2_11_6-94-gbb42c28
Date: Sun, 06 Feb 2011 22:01:49 +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=bb42c28e389d2b30d8d99ab5ee2a470abb09b801

The branch, master has been updated
       via  bb42c28e389d2b30d8d99ab5ee2a470abb09b801 (commit)
       via  61ac5d4cb9fd3856b687b4f48bc1cfdafb8525a1 (commit)
       via  255743fe481668e05746bbe49d1f362cb0ee60f8 (commit)
       via  069f5e2f4e584d302d850eaf7207f8274d478b13 (commit)
       via  74ff2e952564018a93d5930f2427cdf98266673b (commit)
      from  e971ba89e1fac6892ead5c2210e4687055cbad79 (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 bb42c28e389d2b30d8d99ab5ee2a470abb09b801
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun Feb 6 22:59:05 2011 +0100

    Use nettle's new API for GCM.

commit 61ac5d4cb9fd3856b687b4f48bc1cfdafb8525a1
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun Feb 6 22:03:44 2011 +0100

    removed old comment

commit 255743fe481668e05746bbe49d1f362cb0ee60f8
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun Feb 6 16:54:40 2011 +0100

    Removed inner application extension.

commit 069f5e2f4e584d302d850eaf7207f8274d478b13
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun Feb 6 16:32:50 2011 +0100

    gnutls_certificate_verify_peers is deprecated.

commit 74ff2e952564018a93d5930f2427cdf98266673b
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Fri Feb 4 11:02:30 2011 +0100

    Added support for GCM ciphersuites (not tested with other implementation).

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

Summary of changes:
 NEWS                             |   41 ++-
 doc/Makefile.am                  |   17 +-
 doc/cha-functions.texi           |    2 -
 doc/cha-gtls-app.texi            |    9 -
 doc/examples/Makefile.am         |    1 -
 doc/examples/ex-client-tlsia.c   |  161 ------
 lib/gcrypt/mac.c                 |    8 +
 lib/gnutls_algorithms.c          |   70 ++-
 lib/gnutls_algorithms.h          |    1 +
 lib/gnutls_cipher.c              |  401 ++++++++--------
 lib/gnutls_cipher.h              |   10 -
 lib/gnutls_cipher_int.c          |  258 +++++++++--
 lib/gnutls_cipher_int.h          |   82 +++-
 lib/gnutls_constate.c            |   22 +-
 lib/gnutls_hash_int.c            |   42 ++-
 lib/gnutls_hash_int.h            |    5 +
 lib/gnutls_int.h                 |    4 +-
 lib/gnutls_kx.c                  |    4 -
 lib/gnutls_priority.c            |    7 +
 lib/includes/gnutls/compat.h     |    4 +
 lib/includes/gnutls/crypto.h     |    6 +-
 lib/includes/gnutls/gnutls.h.in  |   10 +-
 lib/m4/hooks.m4                  |    9 +
 lib/nettle/cipher.c              |  101 ++++-
 lib/nettle/mac.c                 |   76 +++-
 libextra/Makefile.am             |    5 -
 libextra/ext_inner_application.c |  266 ----------
 libextra/ext_inner_application.h |   64 ---
 libextra/gnutls_extra.c          |    7 -
 libextra/gnutls_ia.c             | 1004 --------------------------------------
 libextra/libgnutls-extra.map     |   20 -
 src/cli.c                        |    7 -
 tests/Makefile.am                |    3 +-
 tests/tlsia.c                    |  586 ----------------------
 34 files changed, 840 insertions(+), 2473 deletions(-)
 delete mode 100644 doc/examples/ex-client-tlsia.c
 delete mode 100644 libextra/ext_inner_application.c
 delete mode 100644 libextra/ext_inner_application.h
 delete mode 100644 libextra/gnutls_ia.c
 delete mode 100644 tests/tlsia.c

diff --git a/NEWS b/NEWS
index e82d9b0..c46a4c1 100644
--- a/NEWS
+++ b/NEWS
@@ -3,7 +3,10 @@ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005,
               2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 See the end for copying conditions.
 
-* Version 2.11.7 (unreleased)
+* Version 2.99.0 (unreleased)
+
+** libgnutls-extra: Inner application extension was removed.
+It was never standardized nor published as an RFC.
 
 ** libgnutls: Added new certificate verification functions, that
 can provide more details and are more efficient. Check 
@@ -16,6 +19,36 @@ gnutls_x509_trust_list_*.
 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_ext_register: REMOVED
+gnutls_certificate_get_x509_crls: REMOVED
+gnutls_certificate_get_x509_cas: REMOVED
+gnutls_session_get_server_random: REMOVED
+gnutls_session_get_client_random: REMOVED
+gnutls_session_get_master_secret: REMOVED
+gnutls_ia_allocate_client_credentials: REMOVED
+gnutls_ia_allocate_server_credentials: REMOVED
+gnutls_ia_enable: REMOVED
+gnutls_ia_endphase_send: REMOVED
+gnutls_ia_extract_inner_secret: REMOVED
+gnutls_ia_free_client_credentials: REMOVED
+gnutls_ia_free_server_credentials: REMOVED
+gnutls_ia_generate_challenge: REMOVED
+gnutls_ia_get_client_avp_ptr: REMOVED
+gnutls_ia_get_server_avp_ptr: REMOVED
+gnutls_ia_handshake: REMOVED
+gnutls_ia_handshake_p: REMOVED
+gnutls_ia_permute_inner_secret: REMOVED
+gnutls_ia_recv: REMOVED
+gnutls_ia_send: REMOVED
+gnutls_ia_set_client_avp_function: REMOVED
+gnutls_ia_set_client_avp_ptr: REMOVED
+gnutls_ia_set_server_avp_function: REMOVED
+gnutls_ia_set_server_avp_ptr: REMOVED
+gnutls_ia_verify_endphase: REMOVED
+
+* Version 2.11.7
+
 ** libgnutls: The deprecated  gnutls_x509_privkey_sign_hash() was
 replaced by gnutls_privkey_sign_hash2().
 
@@ -79,12 +112,6 @@ gnutls_openpgp_privkey_sign_hash: DEPRECATED (use: 
gnutls_privkey_sign_hash2)
 gnutls_pkcs11_privkey_sign_hash: REMOVED (was added in 2.11.0)
 gnutls_pkcs11_privkey_decrypt_data: REMOVED (was added in 2.11.0)
 gnutls_privkey_sign_hash: REMOVED (was added in 2.11.0)
-gnutls_ext_register: REMOVED
-gnutls_certificate_get_x509_crls: REMOVED
-gnutls_certificate_get_x509_cas: REMOVED
-gnutls_session_get_server_random: REMOVED
-gnutls_session_get_client_random: REMOVED
-gnutls_session_get_master_secret: REMOVED
 
 * Version 2.11.6 (released 2010-12-06)
 
diff --git a/doc/Makefile.am b/doc/Makefile.am
index ec1a5db..f1b1002 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -40,7 +40,7 @@ gnutls_TEXINFOS = gnutls.texi fdl-1.3.texi lgpl-2.1.texi 
gpl-3.0.texi \
 gnutls_TEXINFOS += examples/ex-client1.c examples/ex-client2.c         \
        examples/ex-session-info.c examples/ex-verify.c                 \
        examples/ex-cert-select.c examples/ex-client-resume.c           \
-       examples/ex-client-srp.c examples/ex-client-tlsia.c             \
+       examples/ex-client-srp.c        \
        examples/ex-rfc2818.c examples/ex-serv1.c                       \
        examples/ex-serv-anon.c         \
        examples/ex-serv-pgp.c examples/ex-serv-srp.c                   \
@@ -100,9 +100,9 @@ MAINTAINERCLEANFILES =
 
 # Generated texinfos.
 
-gnutls_TEXINFOS += gnutls-api.texi extra-api.texi ia-api.texi  \
+gnutls_TEXINFOS += gnutls-api.texi extra-api.texi \
        x509-api.texi pgp-api.texi
-MAINTAINERCLEANFILES += gnutls-api.texi extra-api.texi ia-api.texi     \
+MAINTAINERCLEANFILES += gnutls-api.texi extra-api.texi \
        x509-api.texi pgp-api.texi
 
 gnutls-api.texi: $(srcdir)/../lib/*.c
@@ -149,17 +149,6 @@ extra-api.texi: $(srcdir)/../libextra/gnutls_extra.c
        rm -f address@hidden
        mv -f address@hidden $@
 
-ia-api.texi: $(srcdir)/../libextra/gnutls_ia.c
-       echo "" > address@hidden
-       for i in $^; do \
-               echo -n "Creating documentation for file $$i... " && \
-               $(srcdir)/scripts/gdoc -texinfo $$i >> address@hidden && \
-               echo "ok"; \
-       done
-       $(srcdir)/scripts/sort2.pl < address@hidden > address@hidden
-       rm -f address@hidden
-       mv -f address@hidden $@
-
 # Generated texinfos.
 
 gnutls_TEXINFOS += error_codes.texi algorithms.texi
diff --git a/doc/cha-functions.texi b/doc/cha-functions.texi
index f73bc57..d0260ba 100644
--- a/doc/cha-functions.texi
+++ b/doc/cha-functions.texi
@@ -105,8 +105,6 @@ The control flow in a typical server is similar to the 
above, use
 @code{gnutls_ia_client_credentials_t}, and replace the call to the
 client functions with the corresponding server functions.
 
address@hidden ia-api.texi
-
 @node Error codes and descriptions
 @section Error Codes and Descriptions
 @anchor{Error Codes}
diff --git a/doc/cha-gtls-app.texi b/doc/cha-gtls-app.texi
index 16a5da1..3f907e2 100644
--- a/doc/cha-gtls-app.texi
+++ b/doc/cha-gtls-app.texi
@@ -182,7 +182,6 @@ implemented by another example.
 * Client using a PKCS #11 token with TLS::
 * Client with Resume capability example::
 * Simple client example with SRP authentication::
-* Simple client example with TLS/IA support::
 * Simple client example in C++::
 * Helper function for TCP connections::
 @end menu
@@ -286,14 +285,6 @@ itself using a certificate, and in that case it has to be 
verified.
 
 @verbatiminclude examples/ex-client-srp.c
 
address@hidden Simple client example with TLS/IA support
address@hidden Simple Client Example with @acronym{TLS/IA} Support
-
-The following client is a simple client which uses the
address@hidden/IA} extension to authenticate with the server.
-
address@hidden examples/ex-client-tlsia.c
-
 @node Simple client example in C++
 @subsection Simple Client Example using the C++ API
 
diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am
index 9a19409..ef9d1d6 100644
--- a/doc/examples/Makefile.am
+++ b/doc/examples/Makefile.am
@@ -56,7 +56,6 @@ endif
 
 if ENABLE_ANON
 noinst_PROGRAMS += ex-client1 ex-serv-anon
-noinst_PROGRAMS += ex-client-tlsia 
 endif
 
 if ENABLE_OPENPGP
diff --git a/doc/examples/ex-client-tlsia.c b/doc/examples/ex-client-tlsia.c
deleted file mode 100644
index 99d3640..0000000
--- a/doc/examples/ex-client-tlsia.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/* This example code is placed in the public domain. */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <gnutls/gnutls.h>
-#include <gnutls/extra.h>
-
-/* A basic TLS client, with anonymous authentication and TLS/IA handshake.
- */
-
-#define MAX_BUF 1024
-#define MSG "GET / HTTP/1.0\r\n\r\n"
-
-extern int tcp_connect (void);
-extern void tcp_close (int sd);
-
-static int
-client_avp (gnutls_session_t session, void *ptr,
-            const char *last, size_t lastlen, char **new, size_t * newlen)
-{
-
-  if (last)
-    printf ("- received %d bytes AVP: `%.*s'\n",
-            (int) lastlen, (int) lastlen, last);
-  else
-    printf ("- new application phase\n");
-
-  *new = gnutls_strdup ("client avp");
-  if (!*new)
-    return -1;
-  *newlen = strlen (*new);
-
-  printf ("- sending %d bytes AVP: `%s'\n", (int) *newlen, *new);
-
-  gnutls_ia_permute_inner_secret (session, 3, "foo");
-
-  return 0;
-
-}
-
-int
-main (void)
-{
-  int ret, sd, ii;
-  gnutls_session_t session;
-  char buffer[MAX_BUF + 1];
-  gnutls_anon_client_credentials_t anoncred;
-  gnutls_ia_client_credentials_t iacred;
-  /* Need to enable anonymous KX specifically. */
-
-  gnutls_global_init ();
-
-  gnutls_anon_allocate_client_credentials (&anoncred);
-  gnutls_ia_allocate_client_credentials (&iacred);
-
-  /* Set TLS/IA stuff
-   */
-  gnutls_ia_set_client_avp_function (iacred, client_avp);
-
-  /* Initialize TLS session 
-   */
-  gnutls_init (&session, GNUTLS_CLIENT);
-
-  /* Use default priorities */
-  gnutls_priority_set_direct (session, "NORMAL:+ANON-DH", NULL);
-
-  /* put the anonymous and TLS/IA credentials to the current session
-   */
-  gnutls_credentials_set (session, GNUTLS_CRD_ANON, anoncred);
-  gnutls_credentials_set (session, GNUTLS_CRD_IA, iacred);
-
-  /* connect to the peer
-   */
-  sd = tcp_connect ();
-
-  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd);
-
-  /* Perform the TLS handshake
-   */
-  ret = gnutls_handshake (session);
-
-  if (ret < 0)
-    {
-      fprintf (stderr, "*** Handshake failed\n");
-      gnutls_perror (ret);
-      goto end;
-    }
-  else
-    {
-      printf ("- Handshake was completed\n");
-    }
-
-  if (!gnutls_ia_handshake_p (session))
-    {
-      fprintf (stderr, "*** TLS/IA not negotiated...\n");
-      goto end;
-    }
-  else
-    {
-      printf ("- Starting TLS/IA handshake...\n");
-
-      ret = gnutls_ia_handshake (session);
-
-      if (ret < 0)
-        {
-          fprintf (stderr, "*** TLS/IA handshake failed\n");
-          gnutls_perror (ret);
-          goto end;
-        }
-      else
-        {
-          printf ("- TLS/IA Handshake was completed\n");
-        }
-    }
-
-
-  gnutls_record_send (session, MSG, strlen (MSG));
-
-  ret = gnutls_record_recv (session, buffer, MAX_BUF);
-  if (ret == 0)
-    {
-      printf ("- Peer has closed the TLS connection\n");
-      goto end;
-    }
-  else if (ret < 0)
-    {
-      fprintf (stderr, "*** Error: %s\n", gnutls_strerror (ret));
-      goto end;
-    }
-
-  printf ("- Received %d bytes: ", ret);
-  for (ii = 0; ii < ret; ii++)
-    {
-      fputc (buffer[ii], stdout);
-    }
-  fputs ("\n", stdout);
-
-  gnutls_bye (session, GNUTLS_SHUT_RDWR);
-
-end:
-
-  tcp_close (sd);
-
-  gnutls_deinit (session);
-
-  gnutls_ia_free_client_credentials (iacred);
-  gnutls_anon_free_client_credentials (anoncred);
-
-  gnutls_global_deinit ();
-
-  return 0;
-}
diff --git a/lib/gcrypt/mac.c b/lib/gcrypt/mac.c
index 0b1099e..af1c0af 100644
--- a/lib/gcrypt/mac.c
+++ b/lib/gcrypt/mac.c
@@ -96,6 +96,12 @@ wrap_gcry_md_close (void *hd)
   gcry_md_close (hd);
 }
 
+static void
+wrap_gcry_md_reset (void *hd)
+{
+  gcry_md_reset (hd);
+}
+
 static int
 wrap_gcry_hash_init (gnutls_mac_algorithm_t algo, void **ctx)
 {
@@ -164,6 +170,7 @@ gnutls_crypto_mac_st _gnutls_mac_ops = {
   .init = wrap_gcry_mac_init,
   .setkey = wrap_gcry_md_setkey,
   .hash = wrap_gcry_md_write,
+  .reset = wrap_gcry_md_reset,
   .output = wrap_gcry_mac_output,
   .deinit = wrap_gcry_md_close,
 };
@@ -172,6 +179,7 @@ gnutls_crypto_digest_st _gnutls_digest_ops = {
   .init = wrap_gcry_hash_init,
   .hash = wrap_gcry_md_write,
   .copy = wrap_gcry_md_copy,
+  .reset = wrap_gcry_md_reset,
   .output = wrap_gcry_mac_output,
   .deinit = wrap_gcry_md_close,
 };
diff --git a/lib/gnutls_algorithms.c b/lib/gnutls_algorithms.c
index 5695871..5696a6e 100644
--- a/lib/gnutls_algorithms.c
+++ b/lib/gnutls_algorithms.c
@@ -169,9 +169,10 @@ struct gnutls_cipher_entry
   gnutls_cipher_algorithm_t id;
   uint16_t blocksize;
   uint16_t keysize;
-  cipher_type_t block;
-  uint16_t iv;
-  int export_flag;              /* 0 non export */
+  unsigned block:1;
+  uint16_t iv; /* the size of IV */
+  unsigned export_flag:1; /* 0 non export */
+  unsigned auth:1; /* Whether it is authenc cipher */
 };
 typedef struct gnutls_cipher_entry gnutls_cipher_entry;
 
@@ -183,39 +184,40 @@ typedef struct gnutls_cipher_entry gnutls_cipher_entry;
  * Make sure to updated MAX_CIPHER_BLOCK_SIZE and MAX_CIPHER_KEY_SIZE as well.
  */
 static const gnutls_cipher_entry algorithms[] = {
-  {"AES-256-CBC", GNUTLS_CIPHER_AES_256_CBC, 16, 32, CIPHER_BLOCK, 16, 0},
-  {"AES-192-CBC", GNUTLS_CIPHER_AES_192_CBC, 16, 24, CIPHER_BLOCK, 16, 0},
-  {"AES-128-CBC", GNUTLS_CIPHER_AES_128_CBC, 16, 16, CIPHER_BLOCK, 16, 0},
-  {"3DES-CBC", GNUTLS_CIPHER_3DES_CBC, 8, 24, CIPHER_BLOCK, 8, 0},
-  {"DES-CBC", GNUTLS_CIPHER_DES_CBC, 8, 8, CIPHER_BLOCK, 8, 0},
-  {"ARCFOUR-128", GNUTLS_CIPHER_ARCFOUR_128, 1, 16, CIPHER_STREAM, 0, 0},
-  {"ARCFOUR-40", GNUTLS_CIPHER_ARCFOUR_40, 1, 5, CIPHER_STREAM, 0, 1},
-  {"RC2-40", GNUTLS_CIPHER_RC2_40_CBC, 8, 5, CIPHER_BLOCK, 8, 1},
+  {"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},
+  {"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},
+  {"ARCFOUR-40", GNUTLS_CIPHER_ARCFOUR_40, 1, 5, CIPHER_STREAM, 0, 1, 0},
+  {"RC2-40", GNUTLS_CIPHER_RC2_40_CBC, 8, 5, CIPHER_BLOCK, 8, 1, 0},
 #ifdef ENABLE_CAMELLIA
   {"CAMELLIA-256-CBC", GNUTLS_CIPHER_CAMELLIA_256_CBC, 16, 32, CIPHER_BLOCK,
-   16, 0},
+   16, 0, 0},
   {"CAMELLIA-128-CBC", GNUTLS_CIPHER_CAMELLIA_128_CBC, 16, 16, CIPHER_BLOCK,
-   16, 0},
+   16, 0, 0},
 #endif
 
 #ifdef ENABLE_OPENPGP
-  {"IDEA-PGP-CFB", GNUTLS_CIPHER_IDEA_PGP_CFB, 8, 16, CIPHER_BLOCK, 8, 0},
-  {"3DES-PGP-CFB", GNUTLS_CIPHER_3DES_PGP_CFB, 8, 24, CIPHER_BLOCK, 8, 0},
-  {"CAST5-PGP-CFB", GNUTLS_CIPHER_CAST5_PGP_CFB, 8, 16, CIPHER_BLOCK, 8, 0},
+  {"IDEA-PGP-CFB", GNUTLS_CIPHER_IDEA_PGP_CFB, 8, 16, CIPHER_BLOCK, 8, 0, 0},
+  {"3DES-PGP-CFB", GNUTLS_CIPHER_3DES_PGP_CFB, 8, 24, CIPHER_BLOCK, 8, 0, 0},
+  {"CAST5-PGP-CFB", GNUTLS_CIPHER_CAST5_PGP_CFB, 8, 16, CIPHER_BLOCK, 8, 0, 0},
   {"BLOWFISH-PGP-CFB", GNUTLS_CIPHER_BLOWFISH_PGP_CFB, 8,
-   16 /*actually unlimited */ , CIPHER_BLOCK, 8, 0},
+   16 /*actually unlimited */ , CIPHER_BLOCK, 8, 0, 0},
   {"SAFER-SK128-PGP-CFB", GNUTLS_CIPHER_SAFER_SK128_PGP_CFB, 8, 16,
-   CIPHER_BLOCK, 8, 0},
+   CIPHER_BLOCK, 8, 0, 0},
   {"AES-128-PGP-CFB", GNUTLS_CIPHER_AES128_PGP_CFB, 16, 16, CIPHER_BLOCK, 16,
-   0},
+   0, 0},
   {"AES-192-PGP-CFB", GNUTLS_CIPHER_AES192_PGP_CFB, 16, 24, CIPHER_BLOCK, 16,
-   0},
+   0, 0},
   {"AES-256-PGP-CFB", GNUTLS_CIPHER_AES256_PGP_CFB, 16, 32, CIPHER_BLOCK, 16,
-   0},
+   0, 0},
   {"TWOFISH-PGP-CFB", GNUTLS_CIPHER_TWOFISH_PGP_CFB, 16, 16, CIPHER_BLOCK, 16,
-   0},
+   0, 0},
 #endif
-  {"NULL", GNUTLS_CIPHER_NULL, 1, 0, CIPHER_STREAM, 0, 0},
+  {"NULL", GNUTLS_CIPHER_NULL, 1, 0, CIPHER_STREAM, 0, 0, 0},
   {0, 0, 0, 0, 0, 0, 0}
 };
 
@@ -259,6 +261,7 @@ static const gnutls_hash_entry hash_algorithms[] = {
   {"SHA256", HASH_OID_SHA256, GNUTLS_MAC_SHA256, 32},
   {"SHA384", HASH_OID_SHA384, GNUTLS_MAC_SHA384, 48},
   {"SHA512", HASH_OID_SHA512, GNUTLS_MAC_SHA512, 64},
+  {"AEAD", NULL, GNUTLS_MAC_AEAD, 0},
   {"MD2", HASH_OID_MD2, GNUTLS_MAC_MD2, 0},     /* not used as MAC */
   {"RIPEMD160", HASH_OID_RMD160, GNUTLS_MAC_RMD160, 20},
   {"MAC-NULL", NULL, GNUTLS_MAC_NULL, 0},
@@ -498,6 +501,9 @@ typedef struct
 #define GNUTLS_DHE_RSA_AES_128_CBC_SHA256 { 0x00, 0x67 }
 #define GNUTLS_DHE_RSA_AES_256_CBC_SHA256 { 0x00, 0x6B }
 
+/* GCM: RFC5288 */
+#define GNUTLS_RSA_AES_128_GCM_SHA256 { 0x00, 0x9C }
+
 /* Safe renegotiation */
 
 #define GNUTLS_RENEGO_PROTECTION_REQUEST { 
GNUTLS_RENEGO_PROTECTION_REQUEST_MAJOR, GNUTLS_RENEGO_PROTECTION_REQUEST_MINOR }
@@ -752,6 +758,12 @@ static const gnutls_cipher_suite_entry cs_algorithms[] = {
                              GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_RSA,
                              GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
                              GNUTLS_VERSION_MAX),
+/* GCM */
+  GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RSA_AES_128_GCM_SHA256,
+                             GNUTLS_CIPHER_AES_128_GCM, GNUTLS_KX_RSA,
+                             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,
@@ -945,6 +957,16 @@ _gnutls_cipher_is_block (gnutls_cipher_algorithm_t 
algorithm)
 
 }
 
+int
+_gnutls_cipher_is_aead (gnutls_cipher_algorithm_t algorithm)
+{
+  size_t ret = 0;
+
+  GNUTLS_ALG_LOOP (ret = p->auth);
+  return ret;
+
+}
+
 /**
  * gnutls_cipher_get_key_size:
  * @algorithm: is an encryption algorithm
@@ -1779,9 +1801,11 @@ _gnutls_supported_ciphersuites (gnutls_session_t session,
       if (_gnutls_kx_priority
           (session, _gnutls_cipher_suite_get_kx_algo (&tmp_ciphers[i])) < 0)
         continue;
+
       if (_gnutls_mac_priority
           (session, _gnutls_cipher_suite_get_mac_algo (&tmp_ciphers[i])) < 0)
         continue;
+
       if (_gnutls_cipher_priority
           (session,
            _gnutls_cipher_suite_get_cipher_algo (&tmp_ciphers[i])) < 0)
diff --git a/lib/gnutls_algorithms.h b/lib/gnutls_algorithms.h
index 60834d1..eabbda1 100644
--- a/lib/gnutls_algorithms.h
+++ b/lib/gnutls_algorithms.h
@@ -77,6 +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_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_cipher.c b/lib/gnutls_cipher.c
index 22d02f6..53ca23e 100644
--- a/lib/gnutls_cipher.c
+++ b/lib/gnutls_cipher.c
@@ -42,12 +42,23 @@
 #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,
+                                   content_type_t _type, int random_pad,
+                                   record_parameters_st * params);
+static int _gnutls_ciphertext2compressed (gnutls_session_t session,
+                                   opaque * compress_data,
+                                   int compress_size,
+                                   gnutls_datum_t ciphertext, uint8_t type,
+                                   record_parameters_st * params);
+
 inline static int
-is_write_comp_null (gnutls_session_t session)
+is_write_comp_null (record_parameters_st * record_params)
 {
-  record_parameters_st *record_params;
-
-  _gnutls_epoch_get (session, EPOCH_WRITE_CURRENT, &record_params);
   if (record_params->compression_algorithm == GNUTLS_COMP_NULL)
     return 0;
 
@@ -55,11 +66,8 @@ is_write_comp_null (gnutls_session_t session)
 }
 
 inline static int
-is_read_comp_null (gnutls_session_t session)
+is_read_comp_null (record_parameters_st * record_params)
 {
-  record_parameters_st *record_params;
-
-  _gnutls_epoch_get (session, EPOCH_READ_CURRENT, &record_params);
   if (record_params->compression_algorithm == GNUTLS_COMP_NULL)
     return 0;
 
@@ -83,11 +91,16 @@ _gnutls_encrypt (gnutls_session_t session, const opaque * 
headers,
   gnutls_datum_t comp;
   int ret;
   int free_comp = 1;
+  record_parameters_st *cur_record_params;
+
+  ret = _gnutls_epoch_get (session, EPOCH_WRITE_CURRENT, &cur_record_params);
+  if (ret < 0)
+    return gnutls_assert_val(ret);
 
   plain.data = (opaque *) data;
   plain.size = data_size;
 
-  if (plain.size == 0 || is_write_comp_null (session) == 0)
+  if (plain.size == 0 || is_write_comp_null (cur_record_params) == 0)
     {
       comp = plain;
       free_comp = 0;
@@ -99,10 +112,7 @@ _gnutls_encrypt (gnutls_session_t session, const opaque * 
headers,
        */
       ret = _gnutls_m_plaintext2compressed (session, &comp, &plain, params);
       if (ret < 0)
-        {
-          gnutls_assert ();
-          return ret;
-        }
+        return gnutls_assert_val(ret);
     }
 
   ret = _gnutls_compressed2ciphertext (session, &ciphertext[headers_size],
@@ -113,10 +123,7 @@ _gnutls_encrypt (gnutls_session_t session, const opaque * 
headers,
     _gnutls_free_datum (&comp);
 
   if (ret < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
+    return gnutls_assert_val(ret);
 
 
   /* copy the headers */
@@ -138,6 +145,11 @@ _gnutls_decrypt (gnutls_session_t session, opaque * 
ciphertext,
   gnutls_datum_t gtxt;
   gnutls_datum_t gcipher;
   int ret;
+  record_parameters_st *cur_record_params;
+
+  ret = _gnutls_epoch_get (session, EPOCH_READ_CURRENT, &cur_record_params);
+  if (ret < 0)
+    return gnutls_assert_val(ret);
 
   if (ciphertext_size == 0)
     return 0;
@@ -153,7 +165,7 @@ _gnutls_decrypt (gnutls_session_t session, opaque * 
ciphertext,
       return ret;
     }
 
-  if (ret == 0 || is_read_comp_null (session) == 0)
+  if (ret == 0 || is_read_comp_null (cur_record_params) == 0)
     {
       /* ret == ret */
 
@@ -175,20 +187,18 @@ _gnutls_decrypt (gnutls_session_t session, opaque * 
ciphertext,
 
       if (gtxt.size > MAX_RECORD_RECV_SIZE)
         {
-          gnutls_assert ();
           _gnutls_free_datum (&gtxt);
           /* This shouldn't have happen and
            * is a TLS fatal error.
            */
-          return GNUTLS_E_DECOMPRESSION_FAILED;
+          return gnutls_assert_val(GNUTLS_E_DECOMPRESSION_FAILED);
         }
 
       /* This check is not really needed */
       if (max_data_size < MAX_RECORD_RECV_SIZE)
         {
-          gnutls_assert ();
           _gnutls_free_datum (&gtxt);
-          return GNUTLS_E_INTERNAL_ERROR;
+          return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
         }
 
       memcpy (data, gtxt.data, gtxt.size);
@@ -200,59 +210,11 @@ _gnutls_decrypt (gnutls_session_t session, opaque * 
ciphertext,
   return ret;
 }
 
-static inline int
-mac_init (digest_hd_st * td, gnutls_mac_algorithm_t mac, opaque * secret,
-          int secret_size, int ver)
-{
-  int ret = 0;
-
-  if (mac == GNUTLS_MAC_NULL)
-    {
-      return GNUTLS_E_HASH_FAILED;
-    }
-
-  if (ver == GNUTLS_SSL3)
-    {                           /* SSL 3.0 */
-      ret = _gnutls_mac_init_ssl3 (td, mac, secret, secret_size);
-    }
-  else
-    {                           /* TLS 1.x */
-      ret = _gnutls_hmac_init (td, mac, secret, secret_size);
-    }
-
-  return ret;
-}
-
-static inline void
-mac_hash (digest_hd_st * td, void *data, int data_size, int ver)
-{
-  if (ver == GNUTLS_SSL3)
-    {                           /* SSL 3.0 */
-      _gnutls_hash (td, data, data_size);
-    }
-  else
-    {
-      _gnutls_hmac (td, data, data_size);
-    }
-}
-
-static inline void
-mac_deinit (digest_hd_st * td, opaque * res, int ver)
-{
-  if (ver == GNUTLS_SSL3)
-    {                           /* SSL 3.0 */
-      _gnutls_mac_deinit_ssl3 (td, res);
-    }
-  else
-    {
-      _gnutls_hmac_deinit (td, res);
-    }
-}
 
 inline static int
 calc_enc_length (gnutls_session_t session, int data_size,
                  int hash_size, uint8_t * pad, int random_pad,
-                 cipher_type_t block_algo, uint16_t blocksize)
+                 unsigned block_algo, unsigned auth_cipher, uint16_t blocksize)
 {
   uint8_t rnd;
   int length, ret;
@@ -263,15 +225,14 @@ 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;
 
       break;
     case CIPHER_BLOCK:
       ret = _gnutls_rnd (GNUTLS_RND_NONCE, &rnd, 1);
       if (ret < 0)
-        {
-          gnutls_assert ();
-          return ret;
-        }
+        return gnutls_assert_val(ret);
 
       /* make rnd a multiple of blocksize */
       if (session->security_parameters.version == GNUTLS_SSL3 ||
@@ -300,8 +261,7 @@ calc_enc_length (gnutls_session_t session, int data_size,
 
       break;
     default:
-      gnutls_assert ();
-      return GNUTLS_E_INTERNAL_ERROR;
+      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
     }
 
   return length;
@@ -321,7 +281,7 @@ make_preamble (opaque * uint64_data, opaque type, uint16_t 
c_length,
   *p = type;
   p++;
   if (_gnutls_version_has_variable_padding (ver))
-    {                           /* TLS 1.0 or higher */
+    { /* TLS 1.0 or higher */
       *p = major;
       p++;
       *p = minor;
@@ -332,118 +292,134 @@ 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.
  * return the actual encrypted data length.
  */
-int
+static int
 _gnutls_compressed2ciphertext (gnutls_session_t session,
                                opaque * cipher_data, int cipher_size,
                                gnutls_datum_t compressed,
-                               content_type_t _type, int random_pad,
+                               content_type_t type, int random_pad,
                                record_parameters_st * params)
 {
-  uint8_t MAC[MAX_HASH_SIZE];
+  uint8_t * tag_ptr = NULL;
   uint16_t c_length;
   uint8_t pad;
-  int length, ret;
-  uint8_t type = _type;
+  int length, length_to_encrypt, ret;
   opaque preamble[PREAMBLE_SIZE];
   int preamble_size;
-  int hash_size = _gnutls_hash_get_algo_len (params->mac_algorithm);
+  int tag_size = _gnutls_auth_cipher_tag_len (&params->write.cipher_state);
   int blocksize = gnutls_cipher_get_block_size (params->cipher_algorithm);
-  cipher_type_t block_algo =
+  unsigned block_algo =
     _gnutls_cipher_is_block (params->cipher_algorithm);
   opaque *data_ptr;
   int ver = gnutls_protocol_get_version (session);
-
-
-  /* Initialize MAC */
-
+  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);
 
-  if (params->mac_algorithm != GNUTLS_MAC_NULL)
-    {                           /* actually when the algorithm in not the NULL 
one */
-      digest_hd_st td;
-
-      ret = mac_init (&td, params->mac_algorithm,
-                      params->write.mac_secret.data,
-                      params->write.mac_secret.size, ver);
-
-      if (ret < 0)
-        {
-          gnutls_assert ();
-          return ret;
-        }
-      preamble_size =
-        make_preamble (UINT64DATA
-                       (params->write.sequence_number),
-                       type, c_length, ver, preamble);
-      mac_hash (&td, preamble, preamble_size, ver);
-      mac_hash (&td, compressed.data, compressed.size, ver);
-      mac_deinit (&td, MAC, ver);
-    }
-
+  preamble_size =
+    make_preamble (UINT64DATA
+                   (params->write.sequence_number),
+                   type, c_length, ver, preamble);
 
   /* Calculate the encrypted length (padding etc.)
    */
-  length =
-    calc_enc_length (session, compressed.size, hash_size, &pad,
-                     random_pad, block_algo, blocksize);
+  length_to_encrypt = length =
+    calc_enc_length (session, compressed.size, tag_size, &pad,
+                     random_pad, block_algo, auth_cipher, blocksize);
   if (length < 0)
     {
-      gnutls_assert ();
-      return length;
+      return gnutls_assert_val(length);
     }
 
   /* copy the encrypted data to cipher_data.
    */
   if (cipher_size < length)
     {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
+      return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
     }
 
   data_ptr = cipher_data;
-  if (block_algo == CIPHER_BLOCK &&
-      _gnutls_version_has_explicit_iv (session->security_parameters.version))
+
+  if (explicit_iv)
     {
+      uint8_t nonce[blocksize];
+
       /* copy the random IV.
        */
-      ret = _gnutls_rnd (GNUTLS_RND_NONCE, data_ptr, blocksize);
+      ret = _gnutls_rnd (GNUTLS_RND_NONCE, nonce, blocksize);
       if (ret < 0)
+        return gnutls_assert_val(ret);
+
+      if (block_algo == CIPHER_BLOCK)
         {
-          gnutls_assert ();
-          return ret;
+          memcpy(data_ptr, nonce, blocksize);
+          _gnutls_auth_cipher_setiv(&params->write.cipher_state, nonce, 
blocksize);
+
+          data_ptr += blocksize;
+          cipher_data += blocksize;
+          length_to_encrypt -= blocksize;
         }
+      else if (auth_cipher)
+        {
+          /* 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)
+            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);
 
-      data_ptr += blocksize;
+          /* copy the explicit part */
+          memcpy(data_ptr, &nonce[AEAD_IMPLICIT_DATA], AEAD_EXPLICIT_DATA);
+
+          data_ptr += AEAD_EXPLICIT_DATA;
+          cipher_data += AEAD_EXPLICIT_DATA;
+          /* In AEAD ciphers we don't encrypt the tag 
+           */
+          length_to_encrypt -= AEAD_EXPLICIT_DATA + tag_size;
+        }
     }
 
   memcpy (data_ptr, compressed.data, compressed.size);
   data_ptr += compressed.size;
 
-  if (hash_size > 0)
+  if (tag_size > 0)
     {
-      memcpy (data_ptr, MAC, hash_size);
-      data_ptr += hash_size;
+      tag_ptr = data_ptr;
+      data_ptr += tag_size;
     }
   if (block_algo == CIPHER_BLOCK && pad > 0)
     {
       memset (data_ptr, pad - 1, pad);
     }
 
+  /* add the authenticate data */
+  _gnutls_auth_cipher_add_auth(&params->write.cipher_state, preamble, 
preamble_size);
 
   /* Actual encryption (inplace).
    */
   ret =
-    _gnutls_cipher_encrypt (&params->write.cipher_state, cipher_data, length);
+    _gnutls_auth_cipher_encrypt_tag (&params->write.cipher_state,
+      cipher_data, length_to_encrypt, tag_ptr, tag_size, compressed.size);
   if (ret < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
+    return gnutls_assert_val(ret);
 
   return length;
 }
@@ -452,63 +428,94 @@ _gnutls_compressed2ciphertext (gnutls_session_t session,
 /* Deciphers the ciphertext packet, and puts the result to compress_data, of 
compress_size.
  * Returns the actual compressed packet size.
  */
-int
+static int
 _gnutls_ciphertext2compressed (gnutls_session_t session,
                                opaque * compress_data,
                                int compress_size,
                                gnutls_datum_t ciphertext, uint8_t type,
                                record_parameters_st * params)
 {
-  uint8_t MAC[MAX_HASH_SIZE];
+  uint8_t tag[MAX_HASH_SIZE];
   uint16_t c_length;
   uint8_t pad;
-  int length;
+  int length, length_to_decrypt;
   uint16_t blocksize;
   int ret, i, pad_failed = 0;
   opaque preamble[PREAMBLE_SIZE];
   int preamble_size;
   int ver = gnutls_protocol_get_version (session);
-  int hash_size = _gnutls_hash_get_algo_len (params->mac_algorithm);
+  int tag_size = _gnutls_auth_cipher_tag_len (&params->read.cipher_state);
+  int explicit_iv = _gnutls_version_has_explicit_iv 
(session->security_parameters.version);
 
   blocksize = gnutls_cipher_get_block_size (params->cipher_algorithm);
 
-
   /* actual decryption (inplace)
    */
   switch (_gnutls_cipher_is_block (params->cipher_algorithm))
     {
     case CIPHER_STREAM:
-      if ((ret =
-           _gnutls_cipher_decrypt (&params->read.cipher_state,
-                                   ciphertext.data, ciphertext.size)) < 0)
+      /* The way AEAD ciphers are defined in RFC5246, it allows
+       * only stream ciphers.
+       */
+      if (explicit_iv && 
_gnutls_auth_cipher_is_aead(&params->read.cipher_state))
         {
-          gnutls_assert ();
-          return ret;
+          uint8_t nonce[blocksize];
+          /* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block
+           */
+          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)
+            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);
+          
+          _gnutls_auth_cipher_setiv(&params->read.cipher_state, nonce, 
AEAD_EXPLICIT_DATA+AEAD_IMPLICIT_DATA);
+
+          ciphertext.data += AEAD_EXPLICIT_DATA;
+          ciphertext.size -= AEAD_EXPLICIT_DATA;
+          
+          length_to_decrypt = ciphertext.size - tag_size;
         }
-
-      length = ciphertext.size - hash_size;
-
-      break;
-    case CIPHER_BLOCK:
-      if ((ciphertext.size < blocksize) || (ciphertext.size % blocksize != 0))
+      else
         {
-          gnutls_assert ();
-          return GNUTLS_E_DECRYPTION_FAILED;
+          if (ciphertext.size < tag_size)
+            return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+  
+          length_to_decrypt = ciphertext.size;
         }
 
+      length = ciphertext.size - tag_size;
+      c_length = _gnutls_conv_uint16 ((uint16_t) (length));
+
+      /* Pass the type, version, length and compressed through
+       * MAC.
+       */
+      preamble_size =
+        make_preamble (UINT64DATA
+                       (params->read.sequence_number), type,
+                       c_length, ver, preamble);
+
+      _gnutls_auth_cipher_add_auth (&params->read.cipher_state, preamble, 
preamble_size);
+
       if ((ret =
-           _gnutls_cipher_decrypt (&params->read.cipher_state,
-                                   ciphertext.data, ciphertext.size)) < 0)
-        {
-          gnutls_assert ();
-          return ret;
-        }
+           _gnutls_auth_cipher_decrypt (&params->read.cipher_state,
+             ciphertext.data, length_to_decrypt)) < 0)
+        return gnutls_assert_val(ret);
 
-      /* ignore the IV in TLS 1.1.
+      break;
+    case CIPHER_BLOCK:
+      if ((ciphertext.size < blocksize+tag_size) || (ciphertext.size % 
blocksize != 0))
+        return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+      /* ignore the IV in TLS 1.1+
        */
-      if (_gnutls_version_has_explicit_iv
-          (session->security_parameters.version))
+      if (explicit_iv)
         {
+          _gnutls_auth_cipher_setiv(&params->read.cipher_state,
+            ciphertext.data, blocksize);
+
           ciphertext.size -= blocksize;
           ciphertext.data += blocksize;
 
@@ -519,21 +526,31 @@ _gnutls_ciphertext2compressed (gnutls_session_t session,
             }
         }
 
+      /* we don't use the auth_cipher interface here, since
+       * TLS with block ciphers is impossible to be used under such
+       * an API. (the length of plaintext is required to calculate
+       * auth_data, but it is not available before decryption).
+       */
+      if ((ret =
+           _gnutls_cipher_decrypt (&params->read.cipher_state.cipher,
+             ciphertext.data, ciphertext.size)) < 0)
+        return gnutls_assert_val(ret);
+
       pad = ciphertext.data[ciphertext.size - 1] + 1;   /* pad */
 
-      if ((int) pad > (int) ciphertext.size - hash_size)
+      if ((int) pad > (int) ciphertext.size - tag_size)
         {
           gnutls_assert ();
           _gnutls_record_log
             ("REC[%p]: Short record length %d > %d - %d (under attack?)\n",
-             session, pad, ciphertext.size, hash_size);
+             session, pad, ciphertext.size, tag_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;
+      length = ciphertext.size - tag_size - pad;
 
       /* Check the pading bytes (TLS 1.x)
        */
@@ -544,68 +561,44 @@ _gnutls_ciphertext2compressed (gnutls_session_t session,
                 ciphertext.data[ciphertext.size - 1])
               pad_failed = GNUTLS_E_DECRYPTION_FAILED;
           }
-      break;
-    default:
-      gnutls_assert ();
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  if (length < 0)
-    length = 0;
-  c_length = _gnutls_conv_uint16 ((uint16_t) length);
-
-  /* Pass the type, version, length and compressed through
-   * MAC.
-   */
-  if (params->mac_algorithm != GNUTLS_MAC_NULL)
-    {
-      digest_hd_st td;
 
-      ret = mac_init (&td, params->mac_algorithm,
-                      params->read.mac_secret.data,
-                      params->read.mac_secret.size, ver);
-
-      if (ret < 0)
-        {
-          gnutls_assert ();
-          return GNUTLS_E_INTERNAL_ERROR;
-        }
+      if (length < 0)
+        length = 0;
+      c_length = _gnutls_conv_uint16 ((uint16_t) length);
 
+      /* Pass the type, version, length and compressed through
+       * MAC.
+       */
       preamble_size =
         make_preamble (UINT64DATA
                        (params->read.sequence_number), type,
                        c_length, ver, preamble);
-      mac_hash (&td, preamble, preamble_size, ver);
-      if (length > 0)
-        mac_hash (&td, ciphertext.data, length, ver);
+      _gnutls_auth_cipher_add_auth (&params->read.cipher_state, preamble, 
preamble_size);
+      _gnutls_auth_cipher_add_auth (&params->read.cipher_state, 
ciphertext.data, length);
 
-      mac_deinit (&td, MAC, ver);
+      break;
+    default:
+      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
     }
 
+  _gnutls_auth_cipher_tag(&params->read.cipher_state, tag, tag_size);
+
   /* This one was introduced to avoid a timing attack against the TLS
    * 1.0 protocol.
    */
   if (pad_failed != 0)
-    {
-      gnutls_assert ();
-      return pad_failed;
-    }
+    return gnutls_assert_val(pad_failed);
 
   /* HMAC was not the same. 
    */
-  if (memcmp (MAC, &ciphertext.data[length], hash_size) != 0)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_DECRYPTION_FAILED;
-    }
+  if (memcmp (tag, &ciphertext.data[length], tag_size) != 0)
+    return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
 
   /* copy the decrypted stuff to compress_data.
    */
   if (compress_size < length)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_DECOMPRESSION_FAILED;
-    }
+    return gnutls_assert_val(GNUTLS_E_DECOMPRESSION_FAILED);
+
   memcpy (compress_data, ciphertext.data, length);
 
   return length;
diff --git a/lib/gnutls_cipher.h b/lib/gnutls_cipher.h
index c90467f..5a47f20 100644
--- a/lib/gnutls_cipher.h
+++ b/lib/gnutls_cipher.h
@@ -32,13 +32,3 @@ int _gnutls_encrypt (gnutls_session_t session, const opaque 
* headers,
 int _gnutls_decrypt (gnutls_session_t session, opaque * ciphertext,
                      size_t ciphertext_size, uint8_t * data, size_t data_size,
                      content_type_t type, record_parameters_st * params);
-int _gnutls_compressed2ciphertext (gnutls_session_t session,
-                                   opaque * cipher_data, int cipher_size,
-                                   gnutls_datum_t compressed,
-                                   content_type_t _type, int random_pad,
-                                   record_parameters_st * params);
-int _gnutls_ciphertext2compressed (gnutls_session_t session,
-                                   opaque * compress_data,
-                                   int compress_size,
-                                   gnutls_datum_t ciphertext, uint8_t type,
-                                   record_parameters_st * params);
diff --git a/lib/gnutls_cipher_int.c b/lib/gnutls_cipher_int.c
index d3b7698..410a6b4 100644
--- a/lib/gnutls_cipher_int.c
+++ b/lib/gnutls_cipher_int.c
@@ -28,6 +28,7 @@
 #include <gnutls_datum.h>
 #include <gnutls/crypto.h>
 #include <crypto.h>
+#include <gnutls_algorithms.h>
 
 #define SR(x, cleanup) if ( (x)<0 ) { \
   gnutls_assert(); \
@@ -47,18 +48,30 @@ _gnutls_cipher_init (cipher_hd_st * handle, 
gnutls_cipher_algorithm_t cipher,
   cc = _gnutls_get_crypto_cipher (cipher);
   if (cc != NULL)
     {
-      SR (cc->init (cipher, &handle->handle), cc_cleanup);
-      SR (cc->setkey (handle->handle, key->data, key->size), cc_cleanup);
-
       handle->encrypt = cc->encrypt;
       handle->decrypt = cc->decrypt;
       handle->deinit = cc->deinit;
+      handle->auth = cc->auth;
+      handle->tag = cc->tag;
+      handle->setiv = cc->setiv;
+
+      SR (cc->init (cipher, &handle->handle), cc_cleanup);
+      SR (cc->setkey( handle->handle, key->data, key->size), cc_cleanup);
+      if (iv)
+        {
+          SR (cc->setiv( handle->handle, iv->data, iv->size), cc_cleanup);
+        }
 
-      if (iv && iv->data && iv->size && cc->setiv)
-        SR (cc->setiv (handle->handle, iv->data, iv->size), cc_cleanup);
       return 0;
     }
 
+  handle->encrypt = _gnutls_cipher_ops.encrypt;
+  handle->decrypt = _gnutls_cipher_ops.decrypt;
+  handle->deinit = _gnutls_cipher_ops.deinit;
+  handle->auth = _gnutls_cipher_ops.auth;
+  handle->tag = _gnutls_cipher_ops.tag;
+  handle->setiv = _gnutls_cipher_ops.setiv;
+
   /* otherwise use generic cipher interface
    */
   ret = _gnutls_cipher_ops.init (cipher, &handle->handle);
@@ -68,51 +81,37 @@ _gnutls_cipher_init (cipher_hd_st * handle, 
gnutls_cipher_algorithm_t cipher,
       return ret;
     }
 
-  ret = _gnutls_cipher_ops.setkey (handle->handle, key->data, key->size);
+  ret = _gnutls_cipher_ops.setkey(handle->handle, key->data, key->size);
   if (ret < 0)
     {
-      _gnutls_cipher_ops.deinit (handle->handle);
       gnutls_assert ();
-      return ret;
+      goto cc_cleanup;
     }
 
-  handle->encrypt = _gnutls_cipher_ops.encrypt;
-  handle->decrypt = _gnutls_cipher_ops.decrypt;
-  handle->deinit = _gnutls_cipher_ops.deinit;
-
-  if (iv && iv->data != NULL && iv->size > 0)
-    _gnutls_cipher_ops.setiv (handle->handle, iv->data, iv->size);
+  if (iv)
+    {
+      ret = _gnutls_cipher_ops.setiv(handle->handle, iv->data, iv->size);
+      if (ret < 0)
+        {
+          gnutls_assert ();
+          goto cc_cleanup;
+        }
+    }
 
   return 0;
 
 cc_cleanup:
 
   if (handle->handle)
-    cc->deinit (handle->handle);
+    handle->deinit (handle->handle);
 
   return ret;
 }
 
-int
-_gnutls_cipher_encrypt (const cipher_hd_st * handle, void *text, int textlen)
+void _gnutls_cipher_setiv (const cipher_hd_st * handle, 
+    const void *iv, int ivlen)
 {
-  if (handle != NULL && handle->handle != NULL)
-    {
-      return handle->encrypt (handle->handle, text, textlen, text, textlen);
-    }
-  return 0;
-}
-
-int
-_gnutls_cipher_decrypt (const cipher_hd_st * handle, void *ciphertext,
-                        int ciphertextlen)
-{
-  if (handle != NULL && handle->handle != NULL)
-    {
-      return handle->decrypt (handle->handle, ciphertext, ciphertextlen,
-                              ciphertext, ciphertextlen);
-    }
-  return 0;
+  handle->setiv(handle->handle, iv, ivlen);
 }
 
 int
@@ -124,6 +123,7 @@ _gnutls_cipher_encrypt2 (const cipher_hd_st * handle, const 
void *text,
       return handle->encrypt (handle->handle, text, textlen, ciphertext,
                               ciphertextlen);
     }
+
   return 0;
 }
 
@@ -136,6 +136,7 @@ _gnutls_cipher_decrypt2 (const cipher_hd_st * handle, const 
void *ciphertext,
       return handle->decrypt (handle->handle, ciphertext, ciphertextlen,
                               text, textlen);
     }
+
   return 0;
 }
 
@@ -148,3 +149,192 @@ _gnutls_cipher_deinit (cipher_hd_st * 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, 
+  gnutls_cipher_algorithm_t cipher,
+  const gnutls_datum_t * cipher_key,
+  const gnutls_datum_t * iv,
+  gnutls_mac_algorithm_t mac,
+  const gnutls_datum_t * mac_key,
+  int ssl_hmac)
+{
+int ret;
+
+  memset(handle, 0, sizeof(*handle));
+
+  ret = _gnutls_cipher_init(&handle->cipher, cipher, cipher_key, iv);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      return ret;
+    }
+
+  if (mac != GNUTLS_MAC_AEAD)
+    {
+      handle->is_mac = 1;
+      handle->ssl_hmac = ssl_hmac;
+
+      if (ssl_hmac)
+        ret = _gnutls_mac_init_ssl3(&handle->mac, mac, mac_key->data, 
mac_key->size);
+      else
+        ret = _gnutls_hmac_init(&handle->mac, mac, mac_key->data, 
mac_key->size);
+      if (ret < 0)
+        {
+          gnutls_assert();
+          goto cleanup;
+        }
+
+      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);
+    }
+
+  return 0;
+cleanup:
+  _gnutls_cipher_deinit(&handle->cipher);
+  return ret;
+
+}
+
+int _gnutls_auth_cipher_add_auth (auth_cipher_hd_st * handle, const void *text,
+                             int textlen)
+{
+  if (handle->is_mac)
+    {
+      if (handle->ssl_hmac)
+        return _gnutls_hash(&handle->mac, text, textlen);
+      else
+        return _gnutls_hmac(&handle->mac, text, textlen);
+    }
+  else if (handle->is_auth)
+    return _gnutls_cipher_auth(&handle->cipher, text, textlen);
+  else
+    return 0;
+}
+
+int _gnutls_auth_cipher_encrypt2_tag (auth_cipher_hd_st * handle, const 
uint8_t *text,
+                      int textlen, void *ciphertext, int ciphertextlen, 
+                      void* tag_ptr, int tag_size,
+                      int auth_size)
+{
+int ret;
+
+  if (handle->is_mac)
+    {
+      if (handle->ssl_hmac)
+        ret = _gnutls_hash(&handle->mac, text, auth_size);
+      else
+        ret = _gnutls_hmac(&handle->mac, text, auth_size);
+      if (ret < 0)
+        {
+          gnutls_assert();
+          return ret;
+        }
+      _gnutls_auth_cipher_tag(handle, tag_ptr, tag_size);
+
+      ret = _gnutls_cipher_encrypt2(&handle->cipher, text, textlen, 
ciphertext, ciphertextlen);
+      if (ret < 0)
+        {
+          gnutls_assert();
+          return ret;
+        }
+    }
+  else if (handle->is_auth)
+    {
+      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 0;
+}
+
+int _gnutls_auth_cipher_decrypt2 (auth_cipher_hd_st * handle,
+                             const void *ciphertext, int ciphertextlen,
+                             void *text, int textlen)
+{
+int ret;
+
+  ret = _gnutls_cipher_decrypt2(&handle->cipher, ciphertext, ciphertextlen, 
+    text, textlen);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      return ret;
+    }
+
+  if (handle->is_mac)
+    {
+      /* The MAC is not to be hashed */
+      textlen -= handle->tag_size;
+
+      if (handle->ssl_hmac)
+        return _gnutls_hash(&handle->mac, text, textlen);
+      else
+        return _gnutls_hmac(&handle->mac, text, textlen);
+    }
+
+  return 0;
+}
+
+void _gnutls_auth_cipher_tag(auth_cipher_hd_st * handle, void* tag, int 
tag_size)
+{
+  if (handle->is_mac)
+    {
+      if (handle->ssl_hmac)
+        {
+          _gnutls_mac_output_ssl3 (&handle->mac, tag);
+          _gnutls_hash_reset (&handle->mac);
+        }
+      else
+        {
+          _gnutls_hmac_output (&handle->mac, tag);
+          _gnutls_hmac_reset (&handle->mac);
+        }
+    }
+  else if (handle->is_auth)
+    {
+      _gnutls_cipher_tag(&handle->cipher, tag, tag_size);
+    }
+}
+
+void _gnutls_auth_cipher_deinit (auth_cipher_hd_st * handle)
+{
+  if (handle->is_mac)
+    {
+      if (handle->ssl_hmac)
+        _gnutls_mac_deinit_ssl3 (&handle->mac, NULL);
+      else
+        _gnutls_hmac_deinit(&handle->mac, NULL);
+    }
+  _gnutls_cipher_deinit(&handle->cipher);
+}
diff --git a/lib/gnutls_cipher_int.h b/lib/gnutls_cipher_int.h
index 89d7966..bbc259d 100644
--- a/lib/gnutls_cipher_int.h
+++ b/lib/gnutls_cipher_int.h
@@ -37,27 +37,101 @@ typedef int (*cipher_decrypt_func) (void *hd, const void 
*ciphertext, size_t,
                                     void *plaintext, size_t);
 typedef void (*cipher_deinit_func) (void *hd);
 
+typedef int (*cipher_auth_func) (void *hd, const void *data, size_t);
+typedef int (*cipher_setiv_func) (void *hd, const void *iv, size_t);
+
+typedef void (*cipher_tag_func) (void *hd, void *tag, size_t);
+
 typedef struct
 {
   void *handle;
   cipher_encrypt_func encrypt;
   cipher_decrypt_func decrypt;
+  cipher_auth_func auth;
+  cipher_tag_func tag;
+  cipher_setiv_func setiv;
   cipher_deinit_func deinit;
 } 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);
-int _gnutls_cipher_encrypt (const cipher_hd_st * handle, void *text,
-                            int textlen);
-int _gnutls_cipher_decrypt (const cipher_hd_st * handle, void *ciphertext,
-                            int ciphertextlen);
+
+/* Add auth data for AUTHENC ciphers
+ */
+int _gnutls_cipher_auth (const cipher_hd_st * handle, const void *text,
+                             int textlen);
+
+void _gnutls_cipher_setiv (const cipher_hd_st * handle, const void *iv,
+                            int ivlen);
+
 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);
+
+/* returns the tag in AUTHENC ciphers */
+void _gnutls_cipher_tag( const cipher_hd_st * handle, void* tag, int tag_size);
+
+#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.
+ */
+
+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;
+} auth_cipher_hd_st;
+
+int _gnutls_auth_cipher_init (auth_cipher_hd_st * handle, 
+  gnutls_cipher_algorithm_t cipher,
+  const gnutls_datum_t * cipher_key,
+  const gnutls_datum_t * iv,
+  gnutls_mac_algorithm_t mac,
+  const gnutls_datum_t * mac_key, int ssl_hmac);
+
+int _gnutls_auth_cipher_add_auth (auth_cipher_hd_st * handle, const void *text,
+                             int textlen);
+
+int _gnutls_auth_cipher_encrypt2_tag (auth_cipher_hd_st * handle, const 
uint8_t *text,
+                             int textlen, void *ciphertext, int ciphertextlen,
+                             void* tag_ptr, int tag_size, 
+                             int auth_size);
+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);
+
+inline static void _gnutls_auth_cipher_setiv (const auth_cipher_hd_st * 
handle, 
+    const void *iv, int ivlen)
+{
+  _gnutls_cipher_setiv(&handle->cipher, iv, ivlen);
+}
+
+inline static unsigned int _gnutls_auth_cipher_tag_len( auth_cipher_hd_st * 
handle)
+{
+  return handle->tag_size;
+}
+
+inline static unsigned int _gnutls_auth_cipher_is_aead( auth_cipher_hd_st * 
handle)
+{
+  return handle->is_auth;
+}
+
+#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)
+#define _gnutls_auth_cipher_decrypt(x,y,z) 
_gnutls_auth_cipher_decrypt2(x,y,z,y,z)
+
+void _gnutls_auth_cipher_deinit (auth_cipher_hd_st * handle);
+
+
 #endif /* GNUTLS_CIPHER_INT */
diff --git a/lib/gnutls_constate.c b/lib/gnutls_constate.c
index a3f2b02..0546e92 100644
--- a/lib/gnutls_constate.c
+++ b/lib/gnutls_constate.c
@@ -291,14 +291,20 @@ _gnutls_set_keys (gnutls_session_t session, 
record_parameters_st * params,
 }
 
 static int
-_gnutls_init_record_state (record_parameters_st * params, int read,
+_gnutls_init_record_state (record_parameters_st * params, int ver, int read,
                            record_state_st * state)
 {
   int ret;
+  gnutls_datum_t * iv = NULL;
 
-  ret = _gnutls_cipher_init (&state->cipher_state,
-                             params->cipher_algorithm,
-                             &state->key, &state->IV);
+  if (!_gnutls_version_has_explicit_iv(ver))
+    {
+      iv = &state->IV;
+    }
+
+  ret = _gnutls_auth_cipher_init (&state->cipher_state,
+    params->cipher_algorithm, &state->key, iv,
+    params->mac_algorithm, &state->mac_secret, (ver==GNUTLS_SSL3)?1:0);
   if (ret < 0 && params->cipher_algorithm != GNUTLS_CIPHER_NULL)
     return gnutls_assert_val (ret);
 
@@ -396,6 +402,7 @@ _gnutls_epoch_set_keys (gnutls_session_t session, uint16_t 
epoch)
   gnutls_compression_method_t comp_algo;
   record_parameters_st *params;
   int ret;
+  int ver = gnutls_protocol_get_version (session);
 
   ret = _gnutls_epoch_get (session, epoch, &params);
   if (ret < 0)
@@ -428,11 +435,11 @@ _gnutls_epoch_set_keys (gnutls_session_t session, 
uint16_t epoch)
   if (ret < 0)
     return gnutls_assert_val (ret);
 
-  ret = _gnutls_init_record_state (params, 1, &params->read);
+  ret = _gnutls_init_record_state (params, ver, 1, &params->read);
   if (ret < 0)
     return gnutls_assert_val (ret);
 
-  ret = _gnutls_init_record_state (params, 0, &params->write);
+  ret = _gnutls_init_record_state (params, ver, 0, &params->write);
   if (ret < 0)
     return gnutls_assert_val (ret);
 
@@ -673,7 +680,6 @@ epoch_get_slot (gnutls_session_t session, uint16_t epoch)
       gnutls_assert ();
       return NULL;
     }
-
   /* The slot may still be empty (NULL) */
   return &session->record_parameters[epoch_index];
 }
@@ -783,7 +789,7 @@ free_record_state (record_state_st * state, int read)
   _gnutls_free_datum (&state->IV);
   _gnutls_free_datum (&state->key);
 
-  _gnutls_cipher_deinit (&state->cipher_state);
+  _gnutls_auth_cipher_deinit (&state->cipher_state);
 
   if (state->compression_state != NULL)
     _gnutls_comp_deinit (state->compression_state, read);
diff --git a/lib/gnutls_hash_int.c b/lib/gnutls_hash_int.c
index 5990d98..1bf31fa 100644
--- a/lib/gnutls_hash_int.c
+++ b/lib/gnutls_hash_int.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2000, 2001, 2004, 2005, 2007, 2008, 2010 Free Software
+ * Copyright (C) 2000, 2001, 2004, 2005, 2007, 2008, 2010, 2011 Free Software
  * Foundation, Inc.
  *
  * Author: Nikos Mavrogiannopoulos
@@ -37,6 +37,7 @@ digest_length (gnutls_digest_algorithm_t algo)
   switch (algo)
     {
     case GNUTLS_DIG_NULL:
+    case GNUTLS_MAC_AEAD:
       return 0;
     case GNUTLS_DIG_MD5:
     case GNUTLS_DIG_MD2:
@@ -79,6 +80,7 @@ _gnutls_hash_init (digest_hd_st * dig, 
gnutls_digest_algorithm_t algorithm)
 
       dig->hash = cc->hash;
       dig->copy = cc->copy;
+      dig->reset = cc->reset;
       dig->output = cc->output;
       dig->deinit = cc->deinit;
 
@@ -94,6 +96,7 @@ _gnutls_hash_init (digest_hd_st * dig, 
gnutls_digest_algorithm_t algorithm)
 
   dig->hash = _gnutls_digest_ops.hash;
   dig->copy = _gnutls_digest_ops.copy;
+  dig->reset = _gnutls_digest_ops.reset;
   dig->output = _gnutls_digest_ops.output;
   dig->deinit = _gnutls_digest_ops.deinit;
 
@@ -163,6 +166,17 @@ _gnutls_hash_deinit (digest_hd_st * handle, void *digest)
   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,
                    const void *text, size_t textlen, void *digest)
@@ -256,6 +270,7 @@ _gnutls_hmac_init (digest_hd_st * dig, 
gnutls_mac_algorithm_t algorithm,
       dig->hash = cc->hash;
       dig->output = cc->output;
       dig->deinit = cc->deinit;
+      dig->reset = cc->reset;
 
       return 0;
     }
@@ -272,6 +287,7 @@ _gnutls_hmac_init (digest_hd_st * dig, 
gnutls_mac_algorithm_t algorithm,
   dig->hash = _gnutls_mac_ops.hash;
   dig->output = _gnutls_mac_ops.output;
   dig->deinit = _gnutls_mac_ops.deinit;
+  dig->reset = _gnutls_mac_ops.reset;
 
   return 0;
 }
@@ -314,6 +330,17 @@ _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)
 {
@@ -366,7 +393,7 @@ _gnutls_mac_init_ssl3 (digest_hd_st * ret, 
gnutls_mac_algorithm_t algorithm,
 }
 
 void
-_gnutls_mac_deinit_ssl3 (digest_hd_st * handle, void *digest)
+_gnutls_mac_output_ssl3 (digest_hd_st * handle, void *digest)
 {
   opaque ret[MAX_HASH_SIZE];
   digest_hd_st td;
@@ -378,7 +405,6 @@ _gnutls_mac_deinit_ssl3 (digest_hd_st * handle, void 
*digest)
   if (padsize == 0)
     {
       gnutls_assert ();
-      _gnutls_hash_deinit (handle, NULL);
       return;
     }
 
@@ -388,7 +414,6 @@ _gnutls_mac_deinit_ssl3 (digest_hd_st * handle, void 
*digest)
   if (rc < 0)
     {
       gnutls_assert ();
-      _gnutls_hash_deinit (handle, NULL);
       return;
     }
 
@@ -397,12 +422,17 @@ _gnutls_mac_deinit_ssl3 (digest_hd_st * handle, void 
*digest)
 
   _gnutls_hash (&td, opad, padsize);
   block = _gnutls_hmac_get_algo_len (handle->algorithm);
-  _gnutls_hash_deinit (handle, ret);    /* get the previous hash */
+  _gnutls_hash_output (handle, ret);    /* get the previous hash */
   _gnutls_hash (&td, ret, block);
 
   _gnutls_hash_deinit (&td, digest);
+}
 
-  return;
+void
+_gnutls_mac_deinit_ssl3 (digest_hd_st * handle, void *digest)
+{
+  if (digest != NULL) _gnutls_mac_output_ssl3(handle, digest);
+  _gnutls_hash_deinit(handle, NULL);
 }
 
 void
diff --git a/lib/gnutls_hash_int.h b/lib/gnutls_hash_int.h
index ca6bba0..95f1402 100644
--- a/lib/gnutls_hash_int.h
+++ b/lib/gnutls_hash_int.h
@@ -40,6 +40,7 @@ extern gnutls_crypto_digest_st _gnutls_digest_ops;
 
 typedef int (*hash_func) (void *handle, const void *text, size_t size);
 typedef int (*copy_func) (void **dst_ctx, void *src_ctx);
+typedef void (*reset_func) (void *ctx);
 typedef int (*output_func) (void *src_ctx, void *digest, size_t digestsize);
 typedef void (*deinit_func) (void *handle);
 
@@ -51,6 +52,7 @@ typedef struct
 
   hash_func hash;
   copy_func copy;
+  reset_func reset;
   output_func output;
   deinit_func deinit;
 
@@ -62,6 +64,7 @@ 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_hmac_fast (gnutls_mac_algorithm_t algorithm, const void *key,
                        int keylen, const void *text, size_t textlen,
@@ -74,6 +77,7 @@ 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);
 
 int
@@ -84,6 +88,7 @@ _gnutls_hash_fast (gnutls_digest_algorithm_t algorithm,
 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_ssl3_generate_random (void *secret, int secret_len,
                                   void *rnd, int random_len, int bytes,
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 15d8735..0727596 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -118,7 +118,7 @@ typedef struct
 #define MAX_RECORD_RECV_SIZE 
(size_t)session->security_parameters.max_record_recv_size
 #define MAX_PAD_SIZE 255
 #define EXTRA_COMP_SIZE 2048
-#define MAX_RECORD_OVERHEAD (MAX_PAD_SIZE+EXTRA_COMP_SIZE)
+#define MAX_RECORD_OVERHEAD 
(MAX_CIPHER_BLOCK_SIZE/*iv*/+MAX_PAD_SIZE+EXTRA_COMP_SIZE)
 #define MAX_RECV_SIZE 
(MAX_RECORD_OVERHEAD+MAX_RECORD_RECV_SIZE+RECORD_HEADER_SIZE)
 
 #define HANDSHAKE_HEADER_SIZE 4
@@ -392,7 +392,7 @@ struct record_state_st
   gnutls_datum_t mac_secret;
   gnutls_datum_t IV;
   gnutls_datum_t key;
-  cipher_hd_st cipher_state;
+  auth_cipher_hd_st cipher_state;
   comp_hd_t compression_state;
   uint64 sequence_number;
 };
diff --git a/lib/gnutls_kx.c b/lib/gnutls_kx.c
index e24292c..99be1f4 100644
--- a/lib/gnutls_kx.c
+++ b/lib/gnutls_kx.c
@@ -39,7 +39,6 @@
 #include <gnutls_datum.h>
 #include <gnutls_rsa_export.h>
 #include <gnutls_mbuffers.h>
-#include "../libextra/ext_inner_application.h"  /* isn't this too much? */
 
 /* This is a temporary function to be used before the generate_*
    internal API is changed to use mbuffers. For now we don't avoid the
@@ -140,9 +139,6 @@ generate_normal_master (gnutls_session_t session, int 
keep_premaster)
                      session->security_parameters.master_secret);
     }
 
-  /* TLS/IA inner secret is derived from the master secret. */
-  _gnutls_ia_derive_inner_secret (session);
-
   if (!keep_premaster)
     _gnutls_free_datum (&PREMASTER);
 
diff --git a/lib/gnutls_priority.c b/lib/gnutls_priority.c
index 5021c52..5884a0f 100644
--- a/lib/gnutls_priority.c
+++ b/lib/gnutls_priority.c
@@ -262,6 +262,7 @@ 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,
@@ -281,6 +282,7 @@ 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,
@@ -296,6 +298,7 @@ static const int cipher_priority_secure128[] = {
 #ifdef ENABLE_CAMELLIA
   GNUTLS_CIPHER_CAMELLIA_128_CBC,
 #endif
+  GNUTLS_CIPHER_AES_128_GCM,
   GNUTLS_CIPHER_3DES_CBC,
   GNUTLS_CIPHER_ARCFOUR_128,
   /* GNUTLS_CIPHER_ARCFOUR_40: Insecure, don't add! */
@@ -312,6 +315,7 @@ static const int cipher_priority_secure256[] = {
 #ifdef ENABLE_CAMELLIA
   GNUTLS_CIPHER_CAMELLIA_128_CBC,
 #endif
+  GNUTLS_CIPHER_AES_128_GCM,
   GNUTLS_CIPHER_3DES_CBC,
   GNUTLS_CIPHER_ARCFOUR_128,
   /* GNUTLS_CIPHER_ARCFOUR_40: Insecure, don't add! */
@@ -326,6 +330,7 @@ static const int cipher_priority_export[] = {
   GNUTLS_CIPHER_CAMELLIA_128_CBC,
   GNUTLS_CIPHER_CAMELLIA_256_CBC,
 #endif
+  GNUTLS_CIPHER_AES_128_GCM,
   GNUTLS_CIPHER_3DES_CBC,
   GNUTLS_CIPHER_ARCFOUR_128,
   GNUTLS_CIPHER_ARCFOUR_40,
@@ -362,6 +367,7 @@ static const int sign_priority_secure256[] = {
 
 static const int mac_priority_performance[] = {
   GNUTLS_MAC_SHA1,
+  GNUTLS_MAC_AEAD,
   0
 };
 
@@ -369,6 +375,7 @@ static const int mac_priority_performance[] = {
 static const int mac_priority_secure[] = {
   GNUTLS_MAC_SHA256,
   GNUTLS_MAC_SHA1,
+  GNUTLS_MAC_AEAD,
   0
 };
 
diff --git a/lib/includes/gnutls/compat.h b/lib/includes/gnutls/compat.h
index cc62eb2..78f1e38 100644
--- a/lib/includes/gnutls/compat.h
+++ b/lib/includes/gnutls/compat.h
@@ -284,4 +284,8 @@ gnutls_sign_callback_get (gnutls_session_t session, void 
**userdata)
                              unsigned int flags)
                              _GNUTLS_GCC_ATTR_DEPRECATED;
 
+  /* this is obsolete (?). */
+  int gnutls_certificate_verify_peers (gnutls_session_t session)
+  _GNUTLS_GCC_ATTR_DEPRECATED;
+
 #endif /* _GNUTLS_COMPAT_H */
diff --git a/lib/includes/gnutls/crypto.h b/lib/includes/gnutls/crypto.h
index 0f61981..edec2f4 100644
--- a/lib/includes/gnutls/crypto.h
+++ b/lib/includes/gnutls/crypto.h
@@ -76,7 +76,7 @@ extern "C"
 
 /* register ciphers */
 
-#define GNUTLS_CRYPTO_API_VERSION 0x03
+#define GNUTLS_CRYPTO_API_VERSION 0x04
 
 #define gnutls_crypto_single_cipher_st gnutls_crypto_cipher_st
 #define gnutls_crypto_single_mac_st gnutls_crypto_mac_st
@@ -91,6 +91,8 @@ extern "C"
                     void *encr, size_t encrsize);
     int (*decrypt) (void *ctx, const void *encr, size_t encrsize,
                     void *plain, size_t plainsize);
+    int (*auth) (void *ctx, const void *data, size_t datasize);
+    void (*tag) (void *ctx, void *tag, size_t tagsize);
     void (*deinit) (void *ctx);
   } gnutls_crypto_cipher_st;
 
@@ -98,6 +100,7 @@ extern "C"
   {
     int (*init) (gnutls_mac_algorithm_t, void **ctx);
     int (*setkey) (void *ctx, const void *key, size_t keysize);
+    void (*reset) (void *ctx);
     int (*hash) (void *ctx, const void *text, size_t textsize);
     int (*output) (void *src_ctx, void *digest, size_t digestsize);
     void (*deinit) (void *ctx);
@@ -106,6 +109,7 @@ extern "C"
   typedef struct
   {
     int (*init) (gnutls_mac_algorithm_t, void **ctx);
+    void (*reset) (void *ctx);
     int (*hash) (void *ctx, const void *text, size_t textsize);
     int (*copy) (void **dst_ctx, void *src_ctx);
     int (*output) (void *src_ctx, void *digest, size_t digestsize);
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index cd0b96b..65d10f3 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -73,13 +73,14 @@ extern "C"
    * @GNUTLS_CIPHER_ARCFOUR_128: ARCFOUR stream cipher with 128-bit keys.
    * @GNUTLS_CIPHER_3DES_CBC: 3DES in CBC mode.
    * @GNUTLS_CIPHER_AES_128_CBC: AES in CBC mode with 128-bit keys.
+   * @GNUTLS_CIPHER_AES_192_CBC: AES in CBC mode with 192-bit keys.
    * @GNUTLS_CIPHER_AES_256_CBC: AES in CBC mode with 256-bit keys.
    * @GNUTLS_CIPHER_ARCFOUR_40: ARCFOUR stream cipher with 40-bit keys.
    * @GNUTLS_CIPHER_CAMELLIA_128_CBC: Camellia in CBC mode with 128-bit keys.
    * @GNUTLS_CIPHER_CAMELLIA_256_CBC: Camellia in CBC mode with 256-bit keys.
    * @GNUTLS_CIPHER_RC2_40_CBC: RC2 in CBC mode with 40-bit keys.
    * @GNUTLS_CIPHER_DES_CBC: DES in CBC mode (56-bit keys).
-   * @GNUTLS_CIPHER_AES_192_CBC: AES in CBC mode with 192-bit keys.
+   * @GNUTLS_CIPHER_AES_128_GCM: AES in GCM mode with 128-bit keys.
    * @GNUTLS_CIPHER_IDEA_PGP_CFB: IDEA in CFB mode.
    * @GNUTLS_CIPHER_3DES_PGP_CFB: 3DES in CFB mode.
    * @GNUTLS_CIPHER_CAST5_PGP_CFB: CAST5 in CFB mode.
@@ -106,6 +107,7 @@ extern "C"
     GNUTLS_CIPHER_RC2_40_CBC = 90,
     GNUTLS_CIPHER_DES_CBC = 91,
     GNUTLS_CIPHER_AES_192_CBC = 92,
+    GNUTLS_CIPHER_AES_128_GCM = 93,
 
     /* used only for PGP internals. Ignored in TLS/SSL
      */
@@ -213,9 +215,10 @@ extern "C"
     GNUTLS_MAC_SHA256 = 6,
     GNUTLS_MAC_SHA384 = 7,
     GNUTLS_MAC_SHA512 = 8,
-    GNUTLS_MAC_SHA224 = 9
+    GNUTLS_MAC_SHA224 = 9,
       /* If you add anything here, make sure you align with
          gnutls_digest_algorithm_t. */
+    GNUTLS_MAC_AEAD = 200 /* indicates that MAC is on the cipher */
   } gnutls_mac_algorithm_t;
 
   /**
@@ -1561,9 +1564,6 @@ extern "C"
   int gnutls_certificate_verify_peers2 (gnutls_session_t session,
                                         unsigned int *status);
 
-  /* this is obsolete (?). */
-  int gnutls_certificate_verify_peers (gnutls_session_t session);
-
   int gnutls_pem_base64_encode (const char *msg, const gnutls_datum_t * data,
                                 char *result, size_t * result_size);
   int gnutls_pem_base64_decode (const char *header,
diff --git a/lib/m4/hooks.m4 b/lib/m4/hooks.m4
index 341e0ca..26a9bfc 100644
--- a/lib/m4/hooks.m4
+++ b/lib/m4/hooks.m4
@@ -70,6 +70,15 @@ if test "$cryptolib" = "nettle";then
   *** Libnettle 2.1 was not found. 
   ]])
     fi
+    AC_TRY_COMPILE(,
+  [
+    #include <nettle/gcm.h> 
+    gcm_set_nonce(0, 0, 0);
+    return 0;
+  ], [
+    AC_DEFINE([NETTLE_GCM], 1, [Nettle supports GCM])
+  ], [
+  ])
     NETTLE_LIBS="-lgmp -lpthread -lhogweed"
 else
   AC_MSG_RESULT(no)
diff --git a/lib/nettle/cipher.c b/lib/nettle/cipher.c
index 7669b5b..a2b5407 100644
--- a/lib/nettle/cipher.c
+++ b/lib/nettle/cipher.c
@@ -35,6 +35,9 @@
 #include <nettle/des.h>
 #include <nettle/nettle-meta.h>
 #include <nettle/cbc.h>
+# ifdef NETTLE_GCM
+#include <nettle/gcm.h>
+# endif
 
 /* Functions that refer to the libgcrypt library.
  */
@@ -45,6 +48,10 @@ typedef void (*encrypt_func) (void *, nettle_crypt_func, 
unsigned, uint8_t *,
                               unsigned, uint8_t *, const uint8_t *);
 typedef void (*decrypt_func) (void *, nettle_crypt_func, unsigned, uint8_t *,
                               unsigned, uint8_t *, const uint8_t *);
+typedef void (*auth_func) (void *, unsigned, const uint8_t *);
+
+typedef void (*tag_func) (void *, unsigned, uint8_t *);
+
 typedef void (*setkey_func) (void *, unsigned, const uint8_t *);
 
 static void
@@ -61,6 +68,13 @@ struct aes_bidi_ctx
   struct aes_ctx decrypt;
 };
 
+struct gcm_full_ctx
+{
+  struct gcm_ctx gcm;
+  void *cipher;
+  nettle_crypt_func *f;
+};
+
 static void
 aes_bidi_setkey (struct aes_bidi_ctx *ctx, unsigned length,
                  const uint8_t * key)
@@ -122,6 +136,12 @@ struct nettle_cipher_ctx
     struct des3_ctx des3;
     struct des_ctx des;
   } ctx;
+#ifdef NETTLE_GCM
+  union
+  {
+    struct gcm_full_ctx gcm;
+  } mode_ctx;
+#endif
   void *ctx_ptr;
   uint8_t iv[MAX_BLOCK_SIZE];
   gnutls_cipher_algorithm_t algo;
@@ -130,9 +150,44 @@ struct nettle_cipher_ctx
   nettle_crypt_func *i_decrypt;
   encrypt_func encrypt;
   decrypt_func decrypt;
+  auth_func auth;
+  tag_func tag;
 };
 
+#define GCM_DEFAULT_NONCE_SIZE 12
+
+#ifdef NETTLE_GCM
+static void _gcm_encrypt(void *_ctx, nettle_crypt_func f,  
+            unsigned block_size, uint8_t *iv,
+            unsigned length, uint8_t *dst,
+            const uint8_t *src)
+{
+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);
+}
+
+static void _gcm_decrypt(void *_ctx, nettle_crypt_func f,  
+            unsigned block_size, uint8_t *iv,
+            unsigned length, uint8_t *dst,
+            const uint8_t *src)
+{
+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);
+}
+
+static void _gcm_tag(void *_ctx, unsigned length, uint8_t *dst)
+{
+struct gcm_full_ctx *ctx = _ctx;
+
+  gcm_digest(&ctx->gcm, ctx->cipher, ctx->f, length, dst);
+}
+#endif
 
 static int
 wrap_nettle_cipher_init (gnutls_cipher_algorithm_t algo, void **_ctx)
@@ -150,6 +205,17 @@ wrap_nettle_cipher_init (gnutls_cipher_algorithm_t algo, 
void **_ctx)
 
   switch (algo)
     {
+#ifdef NETTLE_GCM
+    case GNUTLS_CIPHER_AES_128_GCM:
+      ctx->encrypt = _gcm_encrypt;
+      ctx->decrypt = _gcm_decrypt;
+      ctx->i_encrypt = (nettle_crypt_func *) aes_bidi_encrypt;
+      ctx->auth = (auth_func)gcm_auth;
+      ctx->tag = _gcm_tag;
+      ctx->ctx_ptr = &ctx->mode_ctx.gcm;
+      ctx->block_size = AES_BLOCK_SIZE;
+      break;
+#endif
     case GNUTLS_CIPHER_CAMELLIA_128_CBC:
     case GNUTLS_CIPHER_CAMELLIA_256_CBC:
       ctx->encrypt = cbc_encrypt;
@@ -220,6 +286,18 @@ wrap_nettle_cipher_setkey (void *_ctx, const void *key, 
size_t keysize)
 
   switch (ctx->algo)
     {
+#ifdef NETTLE_GCM
+    case GNUTLS_CIPHER_AES_128_GCM:
+      aes_bidi_setkey (&ctx->ctx.aes_bidi, keysize, key);
+
+      ctx->mode_ctx.gcm.cipher = &ctx->ctx.aes_bidi;
+      ctx->mode_ctx.gcm.f = ctx->i_encrypt;
+  
+      gcm_set_key(&ctx->mode_ctx.gcm.gcm, ctx->mode_ctx.gcm.cipher,
+        ctx->mode_ctx.gcm.f);
+
+      break;
+#endif
     case GNUTLS_CIPHER_AES_128_CBC:
     case GNUTLS_CIPHER_AES_192_CBC:
     case GNUTLS_CIPHER_AES_256_CBC:
@@ -314,6 +392,25 @@ wrap_nettle_cipher_encrypt (void *_ctx, const void *plain, 
size_t plainsize,
   return 0;
 }
 
+static int
+wrap_nettle_cipher_auth (void *_ctx, const void *plain, size_t plainsize)
+{
+  struct nettle_cipher_ctx *ctx = _ctx;
+
+  ctx->auth (ctx->ctx_ptr, plainsize, plain);
+
+  return 0;
+}
+
+static void
+wrap_nettle_cipher_tag (void *_ctx, void *tag, size_t tagsize)
+{
+  struct nettle_cipher_ctx *ctx = _ctx;
+
+  ctx->tag (ctx->ctx_ptr, tagsize, tag);
+
+}
+
 static void
 wrap_nettle_cipher_close (void *h)
 {
@@ -322,9 +419,11 @@ wrap_nettle_cipher_close (void *h)
 
 gnutls_crypto_cipher_st _gnutls_cipher_ops = {
   .init = wrap_nettle_cipher_init,
-  .setkey = wrap_nettle_cipher_setkey,
   .setiv = wrap_nettle_cipher_setiv,
+  .setkey = wrap_nettle_cipher_setkey,
   .encrypt = wrap_nettle_cipher_encrypt,
   .decrypt = wrap_nettle_cipher_decrypt,
   .deinit = wrap_nettle_cipher_close,
+  .auth = wrap_nettle_cipher_auth,
+  .tag = wrap_nettle_cipher_tag,
 };
diff --git a/lib/nettle/mac.c b/lib/nettle/mac.c
index a0b3ee0..cec1d03 100644
--- a/lib/nettle/mac.c
+++ b/lib/nettle/mac.c
@@ -58,6 +58,8 @@ struct nettle_hash_ctx
   digest_func digest;
 };
 
+#define MAX_HMAC_KEY 128
+
 struct nettle_hmac_ctx
 {
   union
@@ -75,6 +77,8 @@ struct nettle_hmac_ctx
   update_func update;
   digest_func digest;
   set_key_func setkey;
+  opaque key[MAX_HMAC_KEY];
+  size_t key_size;
 };
 
 static int
@@ -150,11 +154,28 @@ wrap_nettle_hmac_setkey (void *_ctx, const void *key, 
size_t keylen)
 {
   struct nettle_hmac_ctx *ctx = _ctx;
 
+  if (keylen > MAX_HMAC_KEY)
+    {
+      gnutls_assert();
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+  memcpy(ctx->key, key, keylen);
+  ctx->key_size = keylen;
+
   ctx->setkey (ctx->ctx_ptr, keylen, key);
 
   return GNUTLS_E_SUCCESS;
 }
 
+static void
+wrap_nettle_hmac_reset (void *_ctx)
+{
+  struct nettle_hmac_ctx *ctx = _ctx;
+
+  ctx->setkey (ctx->ctx_ptr, ctx->key_size, ctx->key);
+  
+}
+
 static int
 wrap_nettle_hmac_update (void *_ctx, const void *text, size_t textsize)
 {
@@ -197,25 +218,13 @@ wrap_nettle_hash_copy (void **bhd, void *ahd)
 }
 
 static void
-wrap_nettle_md_close (void *hd)
+wrap_nettle_hash_deinit (void *hd)
 {
   gnutls_free (hd);
 }
 
-static int
-wrap_nettle_hash_init (gnutls_mac_algorithm_t algo, void **_ctx)
+static int _ctx_init(struct nettle_hash_ctx *ctx, gnutls_mac_algorithm_t algo)
 {
-  struct nettle_hash_ctx *ctx;
-
-  ctx = gnutls_malloc (sizeof (struct nettle_hash_ctx));
-  if (ctx == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
-    }
-
-  ctx->algo = algo;
-
   switch (algo)
     {
     case GNUTLS_DIG_MD5:
@@ -271,6 +280,30 @@ wrap_nettle_hash_init (gnutls_mac_algorithm_t algo, void 
**_ctx)
       gnutls_assert ();
       return GNUTLS_E_INVALID_REQUEST;
     }
+    
+    return 0;
+}
+
+static int
+wrap_nettle_hash_init (gnutls_mac_algorithm_t algo, void **_ctx)
+{
+  struct nettle_hash_ctx *ctx;
+  int ret;
+
+  ctx = gnutls_malloc (sizeof (struct nettle_hash_ctx));
+  if (ctx == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_MEMORY_ERROR;
+    }
+
+  ctx->algo = algo;
+
+  if ((ret=_ctx_init( ctx, algo)) < 0)
+    {
+      gnutls_assert ();
+      return ret;
+    }
 
   *_ctx = ctx;
 
@@ -294,6 +327,15 @@ wrap_nettle_hash_output (void *src_ctx, void *digest, 
size_t digestsize)
   return 0;
 }
 
+static void
+wrap_nettle_hash_reset (void *src_ctx)
+{
+  struct nettle_hash_ctx *ctx;
+  ctx = src_ctx;
+
+  _ctx_init(ctx->ctx_ptr, ctx->algo);
+}
+
 static int
 wrap_nettle_hmac_output (void *src_ctx, void *digest, size_t digestsize)
 {
@@ -315,14 +357,16 @@ gnutls_crypto_mac_st _gnutls_mac_ops = {
   .init = wrap_nettle_hmac_init,
   .setkey = wrap_nettle_hmac_setkey,
   .hash = wrap_nettle_hmac_update,
+  .reset = wrap_nettle_hmac_reset,
   .output = wrap_nettle_hmac_output,
-  .deinit = wrap_nettle_md_close,
+  .deinit = wrap_nettle_hash_deinit,
 };
 
 gnutls_crypto_digest_st _gnutls_digest_ops = {
   .init = wrap_nettle_hash_init,
   .hash = wrap_nettle_hash_update,
+  .reset = wrap_nettle_hash_reset,
   .copy = wrap_nettle_hash_copy,
   .output = wrap_nettle_hash_output,
-  .deinit = wrap_nettle_md_close,
+  .deinit = wrap_nettle_hash_deinit,
 };
diff --git a/libextra/Makefile.am b/libextra/Makefile.am
index fd95a9e..665d0ec 100644
--- a/libextra/Makefile.am
+++ b/libextra/Makefile.am
@@ -84,11 +84,6 @@ endif
 libgnutls_extra_la_LIBADD = $(LIBSOCKET)
 libgnutls_extra_la_LDFLAGS = -no-undefined
 
-# TLS/IA
-
-libgnutls_extra_la_SOURCES += \
-       ext_inner_application.h ext_inner_application.c gnutls_ia.c
-
 # Rest
 
 if HAVE_LD_OUTPUT_DEF
diff --git a/libextra/ext_inner_application.c b/libextra/ext_inner_application.c
deleted file mode 100644
index 329e4ec..0000000
--- a/libextra/ext_inner_application.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008, 2010 Free Software Foundation, Inc.
- *
- * Author: Simon Josefsson
- *
- * This file is part of GnuTLS-EXTRA.
- *
- * GnuTLS-extra is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * GnuTLS-extra is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "gnutls_int.h"
-#include "gnutls_auth.h"
-#include "gnutls_errors.h"
-#include "gnutls_num.h"
-#include "ext_inner_application.h"
-#include <gnutls/extra.h>
-
-#define NO 0
-#define YES 1
-
-static int _gnutls_inner_application_recv_params (gnutls_session_t session,
-                                                  const opaque * data,
-                                                  size_t data_size);
-static int _gnutls_inner_application_send_params (gnutls_session_t session,
-                                                  opaque * data, size_t);
-static int ia_unpack (gnutls_buffer_st * ps, extension_priv_data_t * _priv);
-static int ia_pack (extension_priv_data_t _priv, gnutls_buffer_st * ps);
-static void ia_deinit_data (extension_priv_data_t priv);
-
-extension_entry_st ext_mod_ia = {
-  .name = "INNER APPLICATION",
-  .type = GNUTLS_EXTENSION_INNER_APPLICATION,
-  .parse_type = GNUTLS_EXT_TLS,
-
-  .recv_func = _gnutls_inner_application_recv_params,
-  .send_func = _gnutls_inner_application_send_params,
-  .pack_func = ia_pack,
-  .unpack_func = ia_unpack,
-  .deinit_func = ia_deinit_data,
-};
-
-static int
-_gnutls_inner_application_recv_params (gnutls_session_t session,
-                                       const opaque * data, size_t data_size)
-{
-  extension_priv_data_t epriv;
-  ia_ext_st *priv;
-  int ret;
-
-  if (data_size != 1)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
-    }
-
-  ret =
-    _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_INNER_APPLICATION,
-                                  &epriv);
-  if (ret < 0)
-    {
-      priv = gnutls_calloc (1, sizeof (*priv));
-      if (priv == NULL)
-        {
-          gnutls_assert ();
-          return GNUTLS_E_MEMORY_ERROR;
-        }
-
-      epriv.ptr = priv;
-      _gnutls_ext_set_session_data (session,
-                                    GNUTLS_EXTENSION_INNER_APPLICATION,
-                                    epriv);
-    }
-  else
-    priv = epriv.ptr;
-
-  priv->flags |= IA_PEER_ENABLE;
-  priv->flags &= ~IA_PEER_ALLOW_SKIP;
-
-  switch ((unsigned char) *data)
-    {
-    case NO:                   /* Peer's ia_on_resume == no */
-      priv->flags |= IA_PEER_ALLOW_SKIP;
-      break;
-
-    case YES:
-      break;
-
-    default:
-      gnutls_assert ();
-    }
-
-
-  return 0;
-}
-
-
-/* returns data_size or a negative number on failure
- */
-static int
-_gnutls_inner_application_send_params (gnutls_session_t session,
-                                       opaque * data, size_t data_size)
-{
-  extension_priv_data_t epriv;
-  ia_ext_st *priv = NULL;
-  int ret;
-
-  ret =
-    _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_INNER_APPLICATION,
-                                  &epriv);
-  if (ret < 0)
-    {
-      priv = gnutls_calloc (1, sizeof (*priv));
-      if (priv == NULL)
-        {
-          gnutls_assert ();
-          return GNUTLS_E_MEMORY_ERROR;
-        }
-
-      epriv.ptr = priv;
-      _gnutls_ext_set_session_data (session,
-                                    GNUTLS_EXTENSION_INNER_APPLICATION,
-                                    epriv);
-    }
-  else
-    priv = epriv.ptr;
-
-  /* Set ext->gnutls_ia_enable depending on whether we have a TLS/IA
-     credential in the session. */
-
-  if (session->security_parameters.entity == GNUTLS_CLIENT)
-    {
-      gnutls_ia_client_credentials_t cred = (gnutls_ia_client_credentials_t)
-        _gnutls_get_cred (session->key, GNUTLS_CRD_IA, NULL);
-
-      if (cred)
-        priv->flags |= IA_ENABLE;
-    }
-  else                          /* SERVER */
-    {
-      gnutls_ia_server_credentials_t cred;
-
-      cred = (gnutls_ia_server_credentials_t)
-        _gnutls_get_cred (session->key, GNUTLS_CRD_IA, NULL);
-
-      if (cred)
-        priv->flags |= IA_PEER_ENABLE;
-    }
-
-  /* If we don't want gnutls_ia locally, or we are a server and the
-   * client doesn't want it, don't advertise TLS/IA support at all, as
-   * required. */
-
-  if (!(priv->flags & IA_ENABLE))
-    return 0;
-
-  if (session->security_parameters.entity == GNUTLS_SERVER &&
-      !(priv->flags & IA_PEER_ENABLE))
-    return 0;
-
-  /* We'll advertise. Check if there's room in the hello buffer. */
-
-  if (data_size < 1)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_SHORT_MEMORY_BUFFER;
-    }
-
-  /* default: require new application phase */
-
-  *data = YES;
-
-  if (session->security_parameters.entity == GNUTLS_CLIENT)
-    {
-
-      /* Client: value follows local setting */
-
-      if (priv->flags & IA_ALLOW_SKIP)
-        *data = NO;
-    }
-  else
-    {
-
-      /* Server: value follows local setting and client's setting, but only
-       * if we are resuming.
-       *
-       * XXX Can server test for resumption at this stage?
-       *
-       * Ai! It seems that read_client_hello only calls parse_extensions if
-       * we're NOT resuming! That would make us automatically violate the IA
-       * draft; if we're resuming, we must first learn what the client wants
-       * -- IA or no IA -- and then prepare our response. Right now we'll
-       * always skip IA on resumption, because recv_ext isn't even called
-       * to record the peer's support for IA at all. Simon? */
-
-      if ((priv->flags & IA_ALLOW_SKIP) &&
-          (priv->flags & IA_PEER_ALLOW_SKIP) &&
-          session->internals.resumed == RESUME_TRUE)
-        *data = NO;
-    }
-
-  return 1;
-}
-
-static void
-ia_deinit_data (extension_priv_data_t priv)
-{
-  gnutls_free (priv.ptr);
-}
-
-static int
-ia_pack (extension_priv_data_t epriv, gnutls_buffer_st * ps)
-{
-  ia_ext_st *priv = epriv.ptr;
-  int ret;
-
-  BUFFER_APPEND_NUM (ps, priv->flags);
-  BUFFER_APPEND_PFX (ps, priv->inner_secret, GNUTLS_MASTER_SIZE);
-
-  return 0;
-}
-
-static int
-ia_unpack (gnutls_buffer_st * ps, extension_priv_data_t * _priv)
-{
-  ia_ext_st *priv;
-  int size, ret;
-  extension_priv_data_t epriv;
-
-  priv = gnutls_calloc (1, sizeof (*priv));
-  if (priv == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
-    }
-
-  BUFFER_POP_NUM (ps, priv->flags);
-  BUFFER_POP_NUM (ps, size);
-  if (size != GNUTLS_MASTER_SIZE)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_PARSING_ERROR;
-    }
-  BUFFER_POP (ps, priv->inner_secret, GNUTLS_MASTER_SIZE);
-
-  epriv.ptr = priv;
-  *_priv = epriv;
-
-  return 0;
-
-error:
-  gnutls_free (priv);
-  return ret;
-}
diff --git a/libextra/ext_inner_application.h b/libextra/ext_inner_application.h
deleted file mode 100644
index a137c08..0000000
--- a/libextra/ext_inner_application.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2005, 2008, 2010 Free Software Foundation, Inc.
- *
- * Author: Simon Josefsson
- *
- * This file is part of GnuTLS-EXTRA.
- *
- * GnuTLS-extra is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * GnuTLS-extra is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef EXT_IA_H
-#define EXT_IA_H
-
-#include <gnutls_extensions.h>
-
-#define IA_PEER_ENABLE (1 << 1)
-#define IA_PEER_ALLOW_SKIP (1 << 2)
-#define IA_ENABLE (1 << 3)
-#define IA_ALLOW_SKIP (1 << 4)
-
-extension_entry_st ext_mod_ia;
-
-typedef struct
-{
-  unsigned int flags;
-  /* For TLS/IA.  XXX: Move to IA credential? */
-  opaque inner_secret[GNUTLS_MASTER_SIZE];
-} ia_ext_st;
-
-inline static void
-_gnutls_ia_derive_inner_secret (gnutls_session_t session)
-{
-  extension_priv_data_t epriv;
-  ia_ext_st *priv;
-  int ret;
-
-  ret =
-    _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_INNER_APPLICATION,
-                                  &epriv);
-  if (ret < 0)
-    {
-      return;
-    }
-  priv = epriv.ptr;
-
-  memcpy (priv->inner_secret,
-          session->security_parameters.master_secret, GNUTLS_MASTER_SIZE);
-
-}
-
-#endif
diff --git a/libextra/gnutls_extra.c b/libextra/gnutls_extra.c
index e890fbf..4887053 100644
--- a/libextra/gnutls_extra.c
+++ b/libextra/gnutls_extra.c
@@ -25,7 +25,6 @@
 #include <gnutls_errors.h>
 #include <gnutls_extensions.h>
 #include <gnutls_algorithms.h>
-#include <ext_inner_application.h>
 
 #ifdef HAVE_GCRYPT
 #include <gcrypt.h>
@@ -110,8 +109,6 @@ static int _gnutls_init_extra = 0;
 int
 gnutls_global_init_extra (void)
 {
-  int ret;
-
   /* If the version of libgnutls != version of
    * libextra, then do not initialize the library.
    * This is because it may break things.
@@ -126,10 +123,6 @@ gnutls_global_init_extra (void)
   if (_gnutls_init_extra != 1)
     return 0;
 
-  ret = _gnutls_ext_register (&ext_mod_ia);
-  if (ret != GNUTLS_E_SUCCESS)
-    return ret;
-
   /* Initialize the LZO library
    */
 #ifdef USE_LZO
diff --git a/libextra/gnutls_ia.c b/libextra/gnutls_ia.c
deleted file mode 100644
index e692bde..0000000
--- a/libextra/gnutls_ia.c
+++ /dev/null
@@ -1,1004 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008, 2009, 2010 Free Software Foundation,
- * Inc.
- *
- * Author: Simon Josefsson
- *
- * This file is part of GnuTLS-EXTRA.
- *
- * GnuTLS-extra is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GnuTLS-extra is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "gnutls_int.h"
-#include "gnutls_record.h"
-#include "gnutls_errors.h"
-#include "gnutls_num.h"
-#include "gnutls_state.h"
-#include <gnutls/extra.h>
-#include <ext_inner_application.h>
-
-#define CHECKSUM_SIZE 12
-
-struct gnutls_ia_client_credentials_st
-{
-  gnutls_ia_avp_func avp_func;
-  void *avp_ptr;
-};
-
-struct gnutls_ia_server_credentials_st
-{
-  gnutls_ia_avp_func avp_func;
-  void *avp_ptr;
-};
-
-static const char server_finished_label[] = "server phase finished";
-static const char client_finished_label[] = "client phase finished";
-static const char inner_permutation_label[] = "inner secret permutation";
-static const char challenge_label[] = "inner application challenge";
-
-/*
- * The TLS/IA packet is the InnerApplication token, described as
- * follows in draft-funk-tls-inner-application-extension-01.txt:
- *
- * enum {
- *   application_payload(0), intermediate_phase_finished(1),
- *   final_phase_finished(2), (255)
- * } InnerApplicationType;
- *
- * struct {
- *   InnerApplicationType msg_type;
- *   uint24 length;
- *   select (InnerApplicationType) {
- *     case application_payload:           ApplicationPayload;
- *     case intermediate_phase_finished:   IntermediatePhaseFinished;
- *     case final_phase_finished:          FinalPhaseFinished;
- *   } body;
- * } InnerApplication;
- *
- */
-
-/* Send TLS/IA data.  If data==NULL && sizeofdata==NULL, then the last
-   send was interrupted for some reason, and then we try to send it
-   again.  Returns the number of bytes sent, or an error code.  If
-   this return E_AGAIN and E_INTERRUPTED, call this function again
-   with data==NULL&&sizeofdata=0NULL until it returns successfully. */
-static ssize_t
-_gnutls_send_inner_application (gnutls_session_t session,
-                                gnutls_ia_apptype_t msg_type,
-                                const char *data, size_t sizeofdata)
-{
-  opaque *p = NULL;
-  size_t plen = 0;
-  ssize_t len;
-
-  if (data != NULL)
-    {
-      plen = sizeofdata + 4;
-      p = gnutls_malloc (plen);
-      if (!p)
-        {
-          gnutls_assert ();
-          return GNUTLS_E_MEMORY_ERROR;
-        }
-
-      *(unsigned char *) p = (unsigned char) (msg_type & 0xFF);
-      _gnutls_write_uint24 (sizeofdata, p + 1);
-      memcpy (p + 4, data, sizeofdata);
-    }
-
-  len =
-    _gnutls_send_int (session, GNUTLS_INNER_APPLICATION, -1,
-                      EPOCH_WRITE_CURRENT, p, plen, MBUFFER_FLUSH);
-
-  if (p)
-    gnutls_free (p);
-
-  return len;
-}
-
-/* Receive TLS/IA data.  Store received TLS/IA message type in
-   *MSG_TYPE, and the data in DATA of max SIZEOFDATA size.  Return the
-   number of bytes read, or an error code. */
-static ssize_t
-_gnutls_recv_inner_application (gnutls_session_t session,
-                                gnutls_ia_apptype_t * msg_type,
-                                opaque * data, size_t sizeofdata)
-{
-  ssize_t len;
-  uint32_t len24;
-  opaque pkt[4];
-
-  len = _gnutls_recv_int (session, GNUTLS_INNER_APPLICATION, -1, pkt, 4);
-  if (len != 4)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
-    }
-
-  *msg_type = pkt[0];
-  len24 = _gnutls_read_uint24 (&pkt[1]);
-
-  if (*msg_type != GNUTLS_IA_APPLICATION_PAYLOAD && len24 != CHECKSUM_SIZE)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
-    }
-
-  if (sizeofdata < len24)
-    {
-      /* XXX push back pkt to IA buffer? */
-      gnutls_assert ();
-      return GNUTLS_E_SHORT_MEMORY_BUFFER;
-    }
-
-  if (len24 > 0)
-    {
-      uint32_t tmplen = len24;
-
-      len24 = _gnutls_recv_int (session, GNUTLS_INNER_APPLICATION, -1,
-                                data, tmplen);
-      if (len24 != tmplen)
-        {
-          gnutls_assert ();
-          /* XXX Correct? */
-          return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
-        }
-    }
-
-  return len24;
-}
-
-/* Apply the TLS PRF using the TLS/IA inner secret as keying material,
-   where the seed is the client random concatenated with the server
-   random concatenated EXTRA of EXTRA_SIZE length (which can be NULL/0
-   respectively).  LABEL and LABEL_SIZE is used as the label.  The
-   result is placed in pre-allocated OUT of OUTSIZE length. */
-static int
-_gnutls_ia_prf (gnutls_session_t session,
-                size_t label_size,
-                const char *label,
-                size_t extra_size,
-                const char *extra, size_t outsize, opaque * out)
-{
-  int ret;
-  opaque *seed;
-  size_t seedsize = 2 * GNUTLS_RANDOM_SIZE + extra_size;
-  extension_priv_data_t epriv;
-  ia_ext_st *priv;
-
-  ret =
-    _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_INNER_APPLICATION,
-                                  &epriv);
-  if (ret < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
-  priv = epriv.ptr;
-
-  seed = gnutls_malloc (seedsize);
-  if (!seed)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
-    }
-
-  memcpy (seed, session->security_parameters.server_random,
-          GNUTLS_RANDOM_SIZE);
-  memcpy (seed + GNUTLS_RANDOM_SIZE,
-          session->security_parameters.client_random, GNUTLS_RANDOM_SIZE);
-  memcpy (seed + 2 * GNUTLS_RANDOM_SIZE, extra, extra_size);
-
-  ret = _gnutls_PRF (session, priv->inner_secret,
-                     GNUTLS_MASTER_SIZE,
-                     label, label_size, seed, seedsize, outsize, out);
-
-  gnutls_free (seed);
-
-  return ret;
-}
-
-/**
- * gnutls_ia_permute_inner_secret:
- * @session: is a #gnutls_session_t structure.
- * @session_keys_size: Size of generated session keys (0 if none).
- * @session_keys: Generated session keys, used to permute inner secret
- *                (NULL if none).
- *
- * Permute the inner secret using the generated session keys.
- *
- * This can be called in the TLS/IA AVP callback to mix any generated
- * session keys with the TLS/IA inner secret.
- *
- * Return value: Return zero on success, or a negative error code.
- **/
-int
-gnutls_ia_permute_inner_secret (gnutls_session_t session,
-                                size_t session_keys_size,
-                                const char *session_keys)
-{
-  extension_priv_data_t epriv;
-  ia_ext_st *priv;
-  int ret;
-
-  ret =
-    _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_INNER_APPLICATION,
-                                  &epriv);
-  if (ret < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
-  priv = epriv.ptr;
-
-  return _gnutls_ia_prf (session,
-                         sizeof (inner_permutation_label) - 1,
-                         inner_permutation_label,
-                         session_keys_size,
-                         session_keys,
-                         GNUTLS_RANDOM_SIZE, priv->inner_secret);
-}
-
-/**
- * gnutls_ia_generate_challenge:
- * @session: is a #gnutls_session_t structure.
- * @buffer_size: size of output buffer.
- * @buffer: pre-allocated buffer to contain @buffer_size bytes of output.
- *
- * Generate an application challenge that the client cannot control or
- * predict, based on the TLS/IA inner secret.
- *
- * Return value: Returns 0 on success, or an negative error code.
- **/
-int
-gnutls_ia_generate_challenge (gnutls_session_t session,
-                              size_t buffer_size, char *buffer)
-{
-  return _gnutls_ia_prf (session,
-                         sizeof (challenge_label) - 1,
-                         challenge_label, 0, NULL, buffer_size, buffer);
-}
-
-/**
- * gnutls_ia_extract_inner_secret:
- * @session: is a #gnutls_session_t structure.
- * @buffer: pre-allocated buffer to hold 48 bytes of inner secret.
- *
- * Copy the 48 bytes large inner secret into the specified buffer
- *
- * This function is typically used after the TLS/IA handshake has
- * concluded.  The TLS/IA inner secret can be used as input to a PRF
- * to derive session keys.  Do not use the inner secret directly as a
- * session key, because for a resumed session that does not include an
- * application phase, the inner secret will be identical to the inner
- * secret in the original session.  It is important to include, for
- * example, the client and server randomness when deriving a sesssion
- * key from the inner secret.
- **/
-void
-gnutls_ia_extract_inner_secret (gnutls_session_t session, char *buffer)
-{
-  extension_priv_data_t epriv;
-  ia_ext_st *priv;
-  int ret;
-
-  ret =
-    _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_INNER_APPLICATION,
-                                  &epriv);
-  if (ret < 0)
-    {
-      gnutls_assert ();
-      return;
-    }
-  priv = epriv.ptr;
-
-  memcpy (buffer, priv->inner_secret, GNUTLS_MASTER_SIZE);
-}
-
-/**
- * gnutls_ia_endphase_send:
- * @session: is a #gnutls_session_t structure.
- * @final_p: Set iff this should signal the final phase.
- *
- * Send a TLS/IA end phase message.
- *
- * In the client, this should only be used to acknowledge an end phase
- * message sent by the server.
- *
- * In the server, this can be called instead of gnutls_ia_send() if
- * the server wishes to end an application phase.
- *
- * Return value: Return 0 on success, or an error code.
- **/
-int
-gnutls_ia_endphase_send (gnutls_session_t session, int final_p)
-{
-  opaque local_checksum[CHECKSUM_SIZE];
-  int client = session->security_parameters.entity == GNUTLS_CLIENT;
-  const char *label = client ? client_finished_label : server_finished_label;
-  int size_of_label = client ? sizeof (client_finished_label) :
-    sizeof (server_finished_label);
-  ssize_t len;
-  int ret;
-  extension_priv_data_t epriv;
-  ia_ext_st *priv;
-
-  ret =
-    _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_INNER_APPLICATION,
-                                  &epriv);
-  if (ret < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
-  priv = epriv.ptr;
-
-  ret = _gnutls_PRF (session, priv->inner_secret,
-                     GNUTLS_MASTER_SIZE, label, size_of_label - 1,
-                     /* XXX specification unclear on seed. */
-                     "", 0, CHECKSUM_SIZE, local_checksum);
-  if (ret < 0)
-    return ret;
-
-  len = _gnutls_send_inner_application
-    (session,
-     final_p ? GNUTLS_IA_FINAL_PHASE_FINISHED :
-     GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED, local_checksum, CHECKSUM_SIZE);
-
-  /* XXX  Instead of calling this function over and over...?
-   * while (len == GNUTLS_E_AGAIN || len == GNUTLS_E_INTERRUPTED)
-   *  len = _gnutls_io_write_flush(session);
-   */
-
-  if (len < 0)
-    {
-      gnutls_assert ();
-      return len;
-    }
-
-  return 0;
-}
-
-/**
- * gnutls_ia_verify_endphase:
- * @session: is a #gnutls_session_t structure.
- * @checksum: 12-byte checksum data, received from gnutls_ia_recv().
- *
- * Verify TLS/IA end phase checksum data.  If verification fails, the
- * %GNUTLS_A_INNER_APPLICATION_VERIFICATION alert is sent to the other
- * sie.
- *
- * This function is called when gnutls_ia_recv() return
- * %GNUTLS_E_WARNING_IA_IPHF_RECEIVED or
- * %GNUTLS_E_WARNING_IA_FPHF_RECEIVED.
- *
- * Return value: Return 0 on successful verification, or an error
- * code.  If the checksum verification of the end phase message fails,
- * %GNUTLS_E_IA_VERIFY_FAILED is returned.
- **/
-int
-gnutls_ia_verify_endphase (gnutls_session_t session, const char *checksum)
-{
-  char local_checksum[CHECKSUM_SIZE];
-  int client = session->security_parameters.entity == GNUTLS_CLIENT;
-  const char *label = client ? server_finished_label : client_finished_label;
-  int size_of_label = client ? sizeof (server_finished_label) :
-    sizeof (client_finished_label);
-  int ret;
-  extension_priv_data_t epriv;
-  ia_ext_st *priv;
-
-  ret =
-    _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_INNER_APPLICATION,
-                                  &epriv);
-  if (ret < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
-  priv = epriv.ptr;
-
-  ret = _gnutls_PRF (session, priv->inner_secret,
-                     GNUTLS_MASTER_SIZE,
-                     label, size_of_label - 1,
-                     "", 0, CHECKSUM_SIZE, local_checksum);
-  if (ret < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
-
-  if (memcmp (local_checksum, checksum, CHECKSUM_SIZE) != 0)
-    {
-      ret = gnutls_alert_send (session, GNUTLS_AL_FATAL,
-                               GNUTLS_A_INNER_APPLICATION_VERIFICATION);
-      if (ret < 0)
-        {
-          gnutls_assert ();
-          return ret;
-        }
-
-      return GNUTLS_E_IA_VERIFY_FAILED;
-    }
-
-  return 0;
-}
-
-/**
- * gnutls_ia_send:
- * @session: is a #gnutls_session_t structure.
- * @data: contains the data to send
- * @sizeofdata: is the length of the data
- *
- * Send TLS/IA application payload data.  This function has the
- * similar semantics with send().  The only difference is that it
- * accepts a GnuTLS session, and uses different error codes.
- *
- * The TLS/IA protocol is synchronous, so you cannot send more than
- * one packet at a time.  The client always send the first packet.
- *
- * To finish an application phase in the server, use
- * gnutls_ia_endphase_send().  The client cannot end an application
- * phase unilaterally; rather, a client is required to respond with an
- * endphase of its own if gnutls_ia_recv indicates that the server has
- * sent one.
- *
- * If the EINTR is returned by the internal push function (the default
- * is send()} then %GNUTLS_E_INTERRUPTED will be returned.  If
- * %GNUTLS_E_INTERRUPTED or %GNUTLS_E_AGAIN is returned, you must call
- * this function again, with the same parameters; alternatively you
- * could provide a %NULL pointer for data, and 0 for size.
- *
- * Returns: The number of bytes sent, or a negative error code.
- **/
-ssize_t
-gnutls_ia_send (gnutls_session_t session, const char *data, size_t sizeofdata)
-{
-  ssize_t len;
-
-  len = _gnutls_send_inner_application (session,
-                                        GNUTLS_IA_APPLICATION_PAYLOAD,
-                                        data, sizeofdata);
-
-  return len;
-}
-
-/**
- * gnutls_ia_recv:
- * @session: is a #gnutls_session_t structure.
- * @data: the buffer that the data will be read into, must hold >= 12 bytes.
- * @sizeofdata: the number of requested bytes, must be >= 12.
- *
- * Receive TLS/IA data.  This function has the similar semantics with
- * recv().  The only difference is that it accepts a GnuTLS session,
- * and uses different error codes.
- *
- * If the server attempt to finish an application phase, this function
- * will return %GNUTLS_E_WARNING_IA_IPHF_RECEIVED or
- * %GNUTLS_E_WARNING_IA_FPHF_RECEIVED.  The caller should then invoke
- * gnutls_ia_verify_endphase(), and if it runs the client side, also
- * send an endphase message of its own using gnutls_ia_endphase_send.
- *
- * If EINTR is returned by the internal push function (the default is
- * @code{recv()}) then GNUTLS_E_INTERRUPTED will be returned.  If
- * GNUTLS_E_INTERRUPTED or GNUTLS_E_AGAIN is returned, you must call
- * this function again, with the same parameters; alternatively you
- * could provide a NULL pointer for data, and 0 for size.
- *
- * Returns: The number of bytes received.  A negative error code is
- * returned in case of an error.  The
- * %GNUTLS_E_WARNING_IA_IPHF_RECEIVED and
- * %GNUTLS_E_WARNING_IA_FPHF_RECEIVED errors are returned when an
- * application phase finished message has been sent by the server.
- **/
-ssize_t
-gnutls_ia_recv (gnutls_session_t session, char *data, size_t sizeofdata)
-{
-  gnutls_ia_apptype_t msg_type = 0;
-  ssize_t len;
-
-  len = _gnutls_recv_inner_application (session, &msg_type, data, sizeofdata);
-
-  if (msg_type == GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED)
-    return GNUTLS_E_WARNING_IA_IPHF_RECEIVED;
-  else if (msg_type == GNUTLS_IA_FINAL_PHASE_FINISHED)
-    return GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
-
-  return len;
-}
-
-/* XXX rewrite the following two functions as state machines, to
-   handle EAGAIN/EINTERRUPTED?  just add more problems to callers,
-   though.  */
-
-static int
-_gnutls_ia_client_handshake (gnutls_session_t session)
-{
-  char *buf = NULL;
-  size_t buflen = 0;
-  char tmp[1024];               /* XXX */
-  ssize_t len;
-  int ret;
-  const struct gnutls_ia_client_credentials_st *cred =
-    _gnutls_get_cred (session->key, GNUTLS_CRD_IA, NULL);
-
-  if (cred == NULL)
-    return GNUTLS_E_INTERNAL_ERROR;
-
-  while (1)
-    {
-      char *avp;
-      size_t avplen;
-
-      ret = cred->avp_func (session, cred->avp_ptr,
-                            buf, buflen, &avp, &avplen);
-      if (ret)
-        {
-          int tmpret;
-          tmpret = gnutls_alert_send (session, GNUTLS_AL_FATAL,
-                                      GNUTLS_A_INNER_APPLICATION_FAILURE);
-          if (tmpret < 0)
-            gnutls_assert ();
-          return ret;
-        }
-
-      len = gnutls_ia_send (session, avp, avplen);
-      gnutls_free (avp);
-      if (len < 0)
-        return len;
-
-      len = gnutls_ia_recv (session, tmp, sizeof (tmp));
-      if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
-          len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
-        {
-          ret = gnutls_ia_verify_endphase (session, tmp);
-          if (ret < 0)
-            return ret;
-
-          ret = gnutls_ia_endphase_send
-            (session, len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED);
-          if (ret < 0)
-            return ret;
-        }
-
-      if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED)
-        {
-          buf = NULL;
-          buflen = 0;
-          continue;
-        }
-      else if (len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
-        break;
-
-      if (len < 0)
-        return len;
-
-      buflen = len;
-      buf = tmp;
-    }
-
-  return 0;
-}
-
-static int
-_gnutls_ia_server_handshake (gnutls_session_t session)
-{
-  gnutls_ia_apptype_t msg_type;
-  ssize_t len;
-  char buf[1024];
-  int ret;
-  const struct gnutls_ia_server_credentials_st *cred =
-    _gnutls_get_cred (session->key, GNUTLS_CRD_IA, NULL);
-
-  if (cred == NULL)
-    return GNUTLS_E_INTERNAL_ERROR;
-
-  do
-    {
-      char *avp;
-      size_t avplen;
-
-      len = gnutls_ia_recv (session, buf, sizeof (buf));
-      if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
-          len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
-        {
-          ret = gnutls_ia_verify_endphase (session, buf);
-          if (ret < 0)
-            return ret;
-        }
-
-      if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED)
-        continue;
-      else if (len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
-        break;
-
-      if (len < 0)
-        return len;
-
-      avp = NULL;
-      avplen = 0;
-
-      ret = cred->avp_func (session, cred->avp_ptr, buf, len, &avp, &avplen);
-      if (ret < 0)
-        {
-          int tmpret;
-          tmpret = gnutls_alert_send (session, GNUTLS_AL_FATAL,
-                                      GNUTLS_A_INNER_APPLICATION_FAILURE);
-          if (tmpret < 0)
-            gnutls_assert ();
-          return ret;
-        }
-
-      msg_type = ret;
-
-      if (msg_type != GNUTLS_IA_APPLICATION_PAYLOAD)
-        {
-          ret = gnutls_ia_endphase_send (session, msg_type ==
-                                         GNUTLS_IA_FINAL_PHASE_FINISHED);
-          if (ret < 0)
-            return ret;
-        }
-      else
-        {
-          len = gnutls_ia_send (session, avp, avplen);
-          gnutls_free (avp);
-          if (len < 0)
-            return len;
-        }
-    }
-  while (1);
-
-  return 0;
-}
-
-/**
- * gnutls_ia_handshake_p:
- * @session: is a #gnutls_session_t structure.
- *
- * Predicate to be used after gnutls_handshake() to decide whether to
- * invoke gnutls_ia_handshake().  Usable by both clients and servers.
- *
- * Return value: non-zero if TLS/IA handshake is expected, zero
- *   otherwise.
- **/
-int
-gnutls_ia_handshake_p (gnutls_session_t session)
-{
-  extension_priv_data_t epriv;
-  ia_ext_st *priv;
-  int ret;
-
-  ret =
-    _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SERVER_NAME,
-                                  &epriv);
-  if (ret < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
-  priv = epriv.ptr;
-
-  /* Either local side or peer doesn't do TLS/IA: don't do IA */
-
-  if (!(priv->flags & IA_ENABLE) || !(priv->flags & IA_PEER_ENABLE))
-    return 0;
-
-  /* Not resuming or we don't allow skipping on resumption locally: do IA */
-
-  if (!(priv->flags & IA_ALLOW_SKIP) || !gnutls_session_is_resumed (session))
-    return 1;
-
-  /* If we're resuming and we and the peer both allow skipping on resumption: 
-   * don't do IA */
-
-  return !(priv->flags & IA_PEER_ALLOW_SKIP);
-}
-
-
-/**
- * gnutls_ia_handshake:
- * @session: is a #gnutls_session_t structure.
- *
- * Perform a TLS/IA handshake.  This should be called after
- * gnutls_handshake() iff gnutls_ia_handshake_p().
- *
- * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned,
- *   otherwise an error code is returned.
- **/
-int
-gnutls_ia_handshake (gnutls_session_t session)
-{
-  int ret;
-
-  if (session->security_parameters.entity == GNUTLS_CLIENT)
-    ret = _gnutls_ia_client_handshake (session);
-  else
-    ret = _gnutls_ia_server_handshake (session);
-
-  return ret;
-}
-
-/**
- * gnutls_ia_allocate_client_credentials:
- * @sc: is a pointer to a #gnutls_ia_server_credentials_t structure.
- *
- * This structure is complex enough to manipulate directly thus this
- * helper function is provided in order to allocate it.
- *
- * Adding this credential to a session will enable TLS/IA, and will
- * require an Application Phase after the TLS handshake (if the server
- * support TLS/IA).  Use gnutls_ia_enable() to toggle the TLS/IA mode.
- *
- * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
- *   an error code is returned.
- **/
-int
-gnutls_ia_allocate_client_credentials (gnutls_ia_client_credentials_t * sc)
-{
-  *sc = gnutls_calloc (1, sizeof (**sc));
-
-  if (*sc == NULL)
-    return GNUTLS_E_MEMORY_ERROR;
-
-  return 0;
-}
-
-/**
- * gnutls_ia_free_client_credentials:
- * @sc: is a #gnutls_ia_client_credentials_t structure.
- *
- * This structure is complex enough to manipulate directly thus this
- * helper function is provided in order to free (deallocate) it.
- *
- **/
-void
-gnutls_ia_free_client_credentials (gnutls_ia_client_credentials_t sc)
-{
-  gnutls_free (sc);
-}
-
-/**
- * gnutls_ia_set_client_avp_function:
- * @cred: is a #gnutls_ia_client_credentials_t structure.
- * @avp_func: is the callback function
- *
- * Set the TLS/IA AVP callback handler used for the session.
- *
- * The AVP callback is called to process AVPs received from the
- * server, and to get a new AVP to send to the server.
- *
- * The callback's function form is:
- * int (*avp_func) (gnutls_session_t session, void *ptr,
- *                  const char *last, size_t lastlen,
- *                  char **next, size_t *nextlen);
- *
- * The @session parameter is the #gnutls_session_t structure
- * corresponding to the current session.  The @ptr parameter is the
- * application hook pointer, set through
- * gnutls_ia_set_client_avp_ptr().  The AVP received from the server
- * is present in @last of @lastlen size, which will be %NULL on the
- * first invocation.  The newly allocated output AVP to send to the
- * server should be placed in address@hidden of address@hidden size.
- *
- * The callback may invoke gnutls_ia_permute_inner_secret() to mix any
- * generated session keys with the TLS/IA inner secret.
- *
- * Return 0 (%GNUTLS_IA_APPLICATION_PAYLOAD) on success, or a negative
- * error code to abort the TLS/IA handshake.
- *
- * Note that the callback must use allocate the @next parameter using
- * gnutls_malloc(), because it is released via gnutls_free() by the
- * TLS/IA handshake function.
- *
- **/
-void
-gnutls_ia_set_client_avp_function (gnutls_ia_client_credentials_t cred,
-                                   gnutls_ia_avp_func avp_func)
-{
-  cred->avp_func = avp_func;
-}
-
-/**
- * gnutls_ia_set_client_avp_ptr:
- * @cred: is a #gnutls_ia_client_credentials_t structure.
- * @ptr: is the pointer
- *
- * Sets the pointer that will be provided to the TLS/IA callback
- * function as the first argument.
- **/
-void
-gnutls_ia_set_client_avp_ptr (gnutls_ia_client_credentials_t cred, void *ptr)
-{
-  cred->avp_ptr = ptr;
-}
-
-/**
- * gnutls_ia_get_client_avp_ptr:
- * @cred: is a #gnutls_ia_client_credentials_t structure.
- *
- * Returns the pointer that will be provided to the TLS/IA callback
- * function as the first argument.
- *
- * Returns: The client callback data pointer.
- **/
-void *
-gnutls_ia_get_client_avp_ptr (gnutls_ia_client_credentials_t cred)
-{
-  return cred->avp_ptr;
-}
-
-/**
- * gnutls_ia_allocate_server_credentials:
- * @sc: is a pointer to a #gnutls_ia_server_credentials_t structure.
- *
- * This structure is complex enough to manipulate directly thus this
- * helper function is provided in order to allocate it.
- *
- * Adding this credential to a session will enable TLS/IA, and will
- * require an Application Phase after the TLS handshake (if the client
- * support TLS/IA).  Use gnutls_ia_enable() to toggle the TLS/IA mode.
- *
- * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
- *   an error code is returned.
- **/
-int
-gnutls_ia_allocate_server_credentials (gnutls_ia_server_credentials_t * sc)
-{
-  *sc = gnutls_calloc (1, sizeof (**sc));
-
-  if (*sc == NULL)
-    return GNUTLS_E_MEMORY_ERROR;
-
-  return 0;
-}
-
-/**
- * gnutls_ia_free_server_credentials:
- * @sc: is a #gnutls_ia_server_credentials_t structure.
- *
- * This structure is complex enough to manipulate directly thus this
- * helper function is provided in order to free (deallocate) it.
- *
- **/
-void
-gnutls_ia_free_server_credentials (gnutls_ia_server_credentials_t sc)
-{
-  gnutls_free (sc);
-}
-
-/**
- * gnutls_ia_set_server_credentials_function:
- * @cred: is a #gnutls_ia_server_credentials_t structure.
- * @func: is the callback function
- *
- * Set the TLS/IA AVP callback handler used for the session.
- *
- * The callback's function form is:
- * int (*avp_func) (gnutls_session_t session, void *ptr,
- *                  const char *last, size_t lastlen,
- *                  char **next, size_t *nextlen);
- *
- * The @session parameter is the #gnutls_session_t structure
- * corresponding to the current session.  The @ptr parameter is the
- * application hook pointer, set through
- * gnutls_ia_set_server_avp_ptr().  The AVP received from the client
- * is present in @last of @lastlen size.  The newly allocated output
- * AVP to send to the client should be placed in address@hidden of 
address@hidden
- * size.
- *
- * The AVP callback is called to process incoming AVPs from the
- * client, and to get a new AVP to send to the client.  It can also be
- * used to instruct the TLS/IA handshake to do go into the
- * Intermediate or Final phases.  It return a negative error code, or
- * a #gnutls_ia_apptype_t message type.
- *
- * The callback may invoke gnutls_ia_permute_inner_secret() to mix any
- * generated session keys with the TLS/IA inner secret.
- *
- * Specifically, return %GNUTLS_IA_APPLICATION_PAYLOAD (0) to send
- * another AVP to the client, return
- * %GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED (1) to indicate that an
- * IntermediatePhaseFinished message should be sent, and return
- * %GNUTLS_IA_FINAL_PHASE_FINISHED (2) to indicate that an
- * FinalPhaseFinished message should be sent.  In the last two cases,
- * the contents of the @next and @nextlen parameter is not used.
- *
- * Note that the callback must use allocate the @next parameter using
- * gnutls_malloc(), because it is released via gnutls_free() by the
- * TLS/IA handshake function.
- **/
-void
-gnutls_ia_set_server_avp_function (gnutls_ia_server_credentials_t cred,
-                                   gnutls_ia_avp_func avp_func)
-{
-  cred->avp_func = avp_func;
-}
-
-/**
- * gnutls_ia_set_server_avp_ptr:
- * @cred: is a #gnutls_ia_client_credentials_t structure.
- * @ptr: is the pointer
- *
- * Sets the pointer that will be provided to the TLS/IA callback
- * function as the first argument.
- **/
-void
-gnutls_ia_set_server_avp_ptr (gnutls_ia_server_credentials_t cred, void *ptr)
-{
-  cred->avp_ptr = ptr;
-}
-
-/**
- * gnutls_ia_get_server_avp_ptr:
- * @cred: is a #gnutls_ia_client_credentials_t structure.
- *
- * Returns the pointer that will be provided to the TLS/IA callback
- * function as the first argument.
- *
- * Returns: The server callback data pointer.
- **/
-void *
-gnutls_ia_get_server_avp_ptr (gnutls_ia_server_credentials_t cred)
-{
-  return cred->avp_ptr;
-}
-
-/**
- * gnutls_ia_enable:
- * @session: is a #gnutls_session_t structure.
- * @allow_skip_on_resume: non-zero if local party allows to skip the
- *                       TLS/IA application phases for a resumed session.
- *
- * Specify whether we must advertise support for the TLS/IA extension
- * during the handshake.
- *
- * At the client side, we always advertise TLS/IA if gnutls_ia_enable
- * was called before the handshake; at the server side, we also
- * require that the client has advertised that it wants to run TLS/IA
- * before including the advertisement, as required by the protocol.
- *
- * Similarly, at the client side we always advertise that we allow
- * TLS/IA to be skipped for resumed sessions if @allow_skip_on_resume
- * is non-zero; at the server side, we also require that the session
- * is indeed resumable and that the client has also advertised that it
- * allows TLS/IA to be skipped for resumed sessions.
- *
- * After the TLS handshake, call gnutls_ia_handshake_p() to find out
- * whether both parties agreed to do a TLS/IA handshake, before
- * calling gnutls_ia_handshake() or one of the lower level gnutls_ia_*
- * functions.
- **/
-void
-gnutls_ia_enable (gnutls_session_t session, int allow_skip_on_resume)
-{
-  extension_priv_data_t epriv;
-  ia_ext_st *priv;
-
-  priv = gnutls_calloc (1, sizeof (*priv));
-  if (priv == NULL)
-    {
-      gnutls_assert ();
-      return;
-    }
-
-  epriv.ptr = priv;
-
-  priv->flags |= IA_ENABLE;
-  if (allow_skip_on_resume)
-    priv->flags |= IA_ALLOW_SKIP;
-
-  _gnutls_ext_set_session_data (session, GNUTLS_EXTENSION_INNER_APPLICATION,
-                                epriv);
-
-}
diff --git a/libextra/libgnutls-extra.map b/libextra/libgnutls-extra.map
index a24e09f..746b821 100644
--- a/libextra/libgnutls-extra.map
+++ b/libextra/libgnutls-extra.map
@@ -26,26 +26,6 @@ GNUTLS_1_4
   global:
     gnutls_extra_check_version;
     gnutls_global_init_extra;
-    gnutls_ia_allocate_client_credentials;
-    gnutls_ia_allocate_server_credentials;
-    gnutls_ia_enable;
-    gnutls_ia_endphase_send;
-    gnutls_ia_extract_inner_secret;
-    gnutls_ia_free_client_credentials;
-    gnutls_ia_free_server_credentials;
-    gnutls_ia_generate_challenge;
-    gnutls_ia_get_client_avp_ptr;
-    gnutls_ia_get_server_avp_ptr;
-    gnutls_ia_handshake;
-    gnutls_ia_handshake_p;
-    gnutls_ia_permute_inner_secret;
-    gnutls_ia_recv;
-    gnutls_ia_send;
-    gnutls_ia_set_client_avp_function;
-    gnutls_ia_set_client_avp_ptr;
-    gnutls_ia_set_server_avp_function;
-    gnutls_ia_set_server_avp_ptr;
-    gnutls_ia_verify_endphase;
     gnutls_register_md5_handler;
 
   local:
diff --git a/src/cli.c b/src/cli.c
index 0b065f8..d10c699 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -665,12 +665,6 @@ handle_error (socket_st * hd, int err)
       if (str == NULL)
         str = str_unknown;
       printf ("*** Received alert [%d]: %s\n", alert, str);
-
-      /* In SRP if the alert is MISSING_SRP_USERNAME,
-       * we should read the username/password and
-       * call gnutls_handshake(). This is not implemented
-       * here.
-       */
     }
 
   check_rehandshake (hd, err);
@@ -1108,7 +1102,6 @@ do_handshake (socket_st * socket)
 
 
       socket->secure = 1;
-
     }
   else
     {
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 1f10d23..b8adcfd 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -74,13 +74,12 @@ endif
 
 if HAVE_FORK
 ctests += x509self x509dn anonself pskself dhepskself  \
-       tlsia resume setcredcrash
+       resume setcredcrash
 
 if ENABLE_OPENPGP
 ctests += openpgpself 
 endif
 
-tlsia_LDADD = ../libextra/libgnutls-extra.la $(LDADD) $(LTLIBREADLINE)
 endif
 
 check_PROGRAMS = $(ctests)
diff --git a/tests/tlsia.c b/tests/tlsia.c
deleted file mode 100644
index b63bc29..0000000
--- a/tests/tlsia.c
+++ /dev/null
@@ -1,586 +0,0 @@
-/*
- * Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010 Free Software
- * Foundation, Inc.
- *
- * Author: Simon Josefsson
- *
- * This file is part of GnuTLS.
- *
- * GnuTLS is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * GnuTLS is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GnuTLS; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/* Parts copied from GnuTLS example programs. */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <gnutls/gnutls.h>
-#include <gnutls/extra.h>
-
-#include "utils.h"
-
-#include "tcp.c"
-
-#include <readline.h>
-
-/* A very basic TLS client, with anonymous authentication.
- */
-
-#define MAX_BUF 1024
-#define MSG "Hello TLS"
-
-static void
-tls_log_func (int level, const char *str)
-{
-  fprintf (stderr, "<%d>| %s", level, str);
-}
-
-static int
-client_avp (gnutls_session_t session, void *ptr,
-            const char *last, size_t lastlen, char **new, size_t * newlen)
-{
-  static int iter = 0;
-  const char *p;
-
-  if (debug)
-    {
-      if (last)
-        printf ("client: received %d bytes AVP: `%.*s'\n",
-                (int) lastlen, (int) lastlen, last);
-      else
-        printf ("client: new application phase\n");
-    }
-
-  switch (iter)
-    {
-    case 0:
-      p = "client's first AVP, next will be empty";
-      break;
-
-    case 1:
-      p = "";
-      break;
-
-    case 2:
-      p = "client avp";
-      break;
-
-    default:
-      p = "final client AVP, we'll restart next";
-      iter = -1;
-      break;
-    }
-
-  iter++;
-
-  if (debug)
-    p = readline ("Client TLS/IA AVP: ");
-
-  *new = gnutls_strdup (p);
-  if (!*new)
-    return -1;
-  *newlen = strlen (*new);
-
-  if (debug)
-    printf ("client: sending %d bytes AVP: `%s'\n", (int) *newlen, *new);
-
-  gnutls_ia_permute_inner_secret (session, 3, "foo");
-
-  return 0;
-}
-
-static void
-client (void)
-{
-  int ret, sd, ii;
-  gnutls_session_t session;
-  char buffer[MAX_BUF + 1];
-  gnutls_anon_client_credentials_t anoncred;
-  gnutls_ia_client_credentials_t iacred;
-  /* Need to enable anonymous KX specifically. */
-  const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 };
-
-  ret = gnutls_global_init ();
-  gnutls_global_set_log_function (tls_log_func);
-  if (debug)
-    gnutls_global_set_log_level (2);
-
-  if (ret)
-    fail ("global_init: %d\n", ret);
-  ret = gnutls_global_init_extra ();
-  if (ret)
-    fail ("global_init_extra: %d\n", ret);
-
-  gnutls_anon_allocate_client_credentials (&anoncred);
-  gnutls_ia_allocate_client_credentials (&iacred);
-
-  /* Initialize TLS session
-   */
-  gnutls_init (&session, GNUTLS_CLIENT);
-
-  /* Use default priorities */
-  gnutls_set_default_priority (session);
-  gnutls_kx_set_priority (session, kx_prio);
-
-  /* put the anonymous credentials to the current session
-   */
-  gnutls_credentials_set (session, GNUTLS_CRD_ANON, anoncred);
-  gnutls_credentials_set (session, GNUTLS_CRD_IA, iacred);
-
-  /* connect to the peer
-   */
-  sd = tcp_connect ();
-
-  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd);
-
-  /* Enable TLS/IA. */
-  gnutls_ia_set_client_avp_function (iacred, client_avp);
-
-  /* Perform the TLS handshake
-   */
-  ret = gnutls_handshake (session);
-
-  if (ret < 0)
-    {
-      fail ("client: Handshake failed\n");
-      gnutls_perror (ret);
-      goto end;
-    }
-  else
-    {
-      if (debug)
-        success ("client: Handshake was completed\n");
-    }
-
-  /*
-     To test TLS/IA alert's (the server will print that a fatal alert
-     was received):
-     gnutls_alert_send(session, GNUTLS_AL_FATAL,
-     GNUTLS_A_INNER_APPLICATION_FAILURE);
-   */
-
-  if (!gnutls_ia_handshake_p (session))
-    fail ("client: No TLS/IA negotiation\n");
-  else
-    {
-      if (debug)
-        success ("client: TLS/IA handshake\n");
-
-      ret = gnutls_ia_handshake (session);
-
-      if (ret < 0)
-        {
-          fail ("client: TLS/IA handshake failed\n");
-          gnutls_perror (ret);
-          goto end;
-        }
-      else
-        {
-          if (debug)
-            success ("client: TLS/IA Handshake was completed\n");
-        }
-    }
-
-  gnutls_record_send (session, MSG, strlen (MSG));
-
-  ret = gnutls_record_recv (session, buffer, MAX_BUF);
-  if (ret == 0)
-    {
-      if (debug)
-        success ("client: Peer has closed the TLS connection\n");
-      goto end;
-    }
-  else if (ret < 0)
-    {
-      fail ("client: Error: %s\n", gnutls_strerror (ret));
-      goto end;
-    }
-
-  if (debug)
-    {
-      printf ("- Received %d bytes: ", ret);
-      for (ii = 0; ii < ret; ii++)
-        {
-          fputc (buffer[ii], stdout);
-        }
-      fputs ("\n", stdout);
-    }
-
-  gnutls_bye (session, GNUTLS_SHUT_RDWR);
-
-end:
-
-  tcp_close (sd);
-
-  gnutls_deinit (session);
-
-  gnutls_ia_free_client_credentials (iacred);
-
-  gnutls_anon_free_client_credentials (anoncred);
-
-  gnutls_global_deinit ();
-}
-
-/* This is a sample TLS 1.0 echo server, for anonymous authentication only.
- */
-
-#define SA struct sockaddr
-#define MAX_BUF 1024
-#define PORT 5556               /* listen to 5556 port */
-#define DH_BITS 1024
-
-/* These are global */
-gnutls_anon_server_credentials_t anoncred;
-gnutls_ia_server_credentials_t iacred;
-
-static gnutls_session_t
-initialize_tls_session (void)
-{
-  gnutls_session_t session;
-  const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 };
-
-  gnutls_init (&session, GNUTLS_SERVER);
-
-  /* avoid calling all the priority functions, since the defaults
-   * are adequate.
-   */
-  gnutls_set_default_priority (session);
-  gnutls_kx_set_priority (session, kx_prio);
-
-  gnutls_credentials_set (session, GNUTLS_CRD_ANON, anoncred);
-
-  gnutls_dh_set_prime_bits (session, DH_BITS);
-
-  return session;
-}
-
-static gnutls_dh_params_t dh_params;
-
-static int
-generate_dh_params (void)
-{
-  const gnutls_datum_t p3 = { (char *) pkcs3, strlen (pkcs3) };
-  /* Generate Diffie-Hellman parameters - for use with DHE
-   * kx algorithms. These should be discarded and regenerated
-   * once a day, once a week or once a month. Depending on the
-   * security requirements.
-   */
-  gnutls_dh_params_init (&dh_params);
-  return gnutls_dh_params_import_pkcs3 (dh_params, &p3, GNUTLS_X509_FMT_PEM);
-}
-
-int err, listen_sd, i;
-int sd, ret;
-struct sockaddr_in sa_serv;
-struct sockaddr_in sa_cli;
-socklen_t client_len;
-char topbuf[512];
-gnutls_session_t session;
-char buffer[MAX_BUF + 1];
-int optval = 1;
-
-static int
-server_avp (gnutls_session_t session, void *ptr,
-            const char *last, size_t lastlen, char **new, size_t * newlen)
-{
-  static int iter = 0;
-  const char *p;
-
-  if (last && debug)
-    printf ("server: received %d bytes AVP: `%.*s'\n",
-            (int) lastlen, (int) lastlen, last);
-
-  gnutls_ia_permute_inner_secret (session, 3, "foo");
-
-  switch (iter)
-    {
-    case 0:
-      p = "first server AVP";
-      break;
-
-    case 1:
-      p = "second server AVP, next will be empty, then a intermediate finish";
-      break;
-
-    case 2:
-      p = "";
-      break;
-
-    case 3:
-      p = "1";
-      break;
-
-    case 4:
-      p = "server avp, after intermediate finish, next another intermediate";
-      break;
-
-    case 5:
-      p = "1";
-      break;
-
-    case 6:
-      p = "server avp, next will be the finish phase";
-      break;
-
-    default:
-      p = "2";
-      break;
-    }
-
-  iter++;
-
-  if (debug)
-    p = readline ("Server TLS/IA AVP (type '1' to sync, '2' to finish): ");
-
-  if (!p)
-    return -1;
-
-  if (strcmp (p, "1") == 0)
-    {
-      if (debug)
-        success ("server: Sending IntermediatePhaseFinished...\n");
-      return 1;
-    }
-
-  if (strcmp (p, "2") == 0)
-    {
-      if (debug)
-        success ("server: Sending FinalPhaseFinished...\n");
-      return 2;
-    }
-
-  *new = gnutls_strdup (p);
-  if (!*new)
-    return -1;
-  *newlen = strlen (*new);
-
-  if (debug)
-    printf ("server: sending %d bytes AVP: `%s'\n", (int) *newlen, *new);
-
-  return 0;
-}
-
-static void
-server_start (void)
-{
-  /* Socket operations
-   */
-  listen_sd = socket (AF_INET, SOCK_STREAM, 0);
-  if (err == -1)
-    {
-      perror ("socket");
-      fail ("server: socket failed\n");
-      return;
-    }
-
-  memset (&sa_serv, '\0', sizeof (sa_serv));
-  sa_serv.sin_family = AF_INET;
-  sa_serv.sin_addr.s_addr = INADDR_ANY;
-  sa_serv.sin_port = htons (PORT);      /* Server Port number */
-
-  setsockopt (listen_sd, SOL_SOCKET, SO_REUSEADDR, (void *) &optval,
-              sizeof (int));
-
-  err = bind (listen_sd, (SA *) & sa_serv, sizeof (sa_serv));
-  if (err == -1)
-    {
-      perror ("bind");
-      fail ("server: bind failed\n");
-      return;
-    }
-
-  err = listen (listen_sd, 1024);
-  if (err == -1)
-    {
-      perror ("listen");
-      fail ("server: listen failed\n");
-      return;
-    }
-
-  if (debug)
-    success ("server: ready. Listening to port '%d'\n", PORT);
-}
-
-static void
-server (void)
-{
-  /* this must be called once in the program
-   */
-  ret = gnutls_global_init ();
-  if (ret)
-    fail ("global_init: %d\n", ret);
-  ret = gnutls_global_init_extra ();
-  if (ret)
-    fail ("global_init_extra: %d\n", ret);
-
-  gnutls_global_set_log_function (tls_log_func);
-  if (debug)
-    gnutls_global_set_log_level (2);
-
-  gnutls_anon_allocate_server_credentials (&anoncred);
-  gnutls_ia_allocate_server_credentials (&iacred);
-
-  if (debug)
-    success ("Launched, generating DH parameters...\n");
-
-  generate_dh_params ();
-
-  gnutls_anon_set_server_dh_params (anoncred, dh_params);
-
-  client_len = sizeof (sa_cli);
-
-  session = initialize_tls_session ();
-
-  sd = accept (listen_sd, (SA *) & sa_cli, &client_len);
-
-  if (debug)
-    success ("server: connection from %s, port %d\n",
-             inet_ntop (AF_INET, &sa_cli.sin_addr, topbuf,
-                        sizeof (topbuf)), ntohs (sa_cli.sin_port));
-
-  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd);
-
-  /* Enable TLS/IA. */
-  gnutls_credentials_set (session, GNUTLS_CRD_IA, iacred);
-  gnutls_ia_set_server_avp_function (iacred, server_avp);
-
-  ret = gnutls_handshake (session);
-  if (ret < 0)
-    {
-      close (sd);
-      gnutls_deinit (session);
-      fail ("server: Handshake has failed (%s)\n\n", gnutls_strerror (ret));
-      return;
-    }
-  if (debug)
-    success ("server: Handshake was completed\n");
-
-  if (!gnutls_ia_handshake_p (session))
-    fail ("server: No TLS/IA negotiation\n");
-  else
-    {
-      if (debug)
-        success ("server: TLS/IA handshake\n");
-
-      ret = gnutls_ia_handshake (session);
-
-      if (ret < 0)
-        {
-          fail ("server: TLS/IA handshake failed\n");
-          gnutls_perror (ret);
-          return;
-        }
-      else
-        {
-          if (debug)
-            success ("server: TLS/IA Handshake was completed\n");
-        }
-    }
-
-  /* see the Getting peer's information example */
-  /* print_info(session); */
-
-  i = 0;
-  for (;;)
-    {
-      memset (buffer, 0, MAX_BUF + 1);
-      ret = gnutls_record_recv (session, buffer, MAX_BUF);
-
-      if (ret == 0)
-        {
-          if (debug)
-            success ("server: Peer has closed the GnuTLS connection\n");
-          break;
-        }
-      else if (ret < 0)
-        {
-          if (ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
-            {
-              gnutls_alert_description_t alert;
-              const char *err;
-              alert = gnutls_alert_get (session);
-              err = gnutls_alert_get_name (alert);
-              if (err)
-                printf ("Fatal alert: %s\n", err);
-            }
-
-          fail ("server: Received corrupted data(%d). Closing...\n", ret);
-          break;
-        }
-      else if (ret > 0)
-        {
-          /* echo data back to the client
-           */
-          gnutls_record_send (session, buffer, strlen (buffer));
-        }
-    }
-  /* do not wait for the peer to close the connection.
-   */
-  gnutls_bye (session, GNUTLS_SHUT_WR);
-
-  close (sd);
-  gnutls_deinit (session);
-
-  close (listen_sd);
-
-  gnutls_ia_free_server_credentials (iacred);
-
-  gnutls_anon_free_server_credentials (anoncred);
-
-  gnutls_dh_params_deinit (dh_params);
-
-  gnutls_global_deinit ();
-
-  if (debug)
-    success ("server: finished\n");
-}
-
-void
-doit (void)
-{
-  pid_t child;
-
-  server_start ();
-  if (error_count)
-    return;
-
-  child = fork ();
-  if (child < 0)
-    {
-      perror ("fork");
-      fail ("fork");
-      return;
-    }
-
-  if (child)
-    {
-      int status;
-      /* parent */
-      server ();
-      wait (&status);
-    }
-  else
-    client ();
-}


hooks/post-receive
-- 
GNU gnutls



reply via email to

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