]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added support for GCM ciphersuites (not tested with other implementation).
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 4 Feb 2011 10:02:30 +0000 (11:02 +0100)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 6 Feb 2011 21:05:53 +0000 (22:05 +0100)
17 files changed:
lib/gcrypt/mac.c
lib/gnutls_algorithms.c
lib/gnutls_algorithms.h
lib/gnutls_cipher.c
lib/gnutls_cipher.h
lib/gnutls_cipher_int.c
lib/gnutls_cipher_int.h
lib/gnutls_constate.c
lib/gnutls_hash_int.c
lib/gnutls_hash_int.h
lib/gnutls_int.h
lib/gnutls_priority.c
lib/includes/gnutls/crypto.h
lib/includes/gnutls/gnutls.h.in
lib/m4/hooks.m4
lib/nettle/cipher.c
lib/nettle/mac.c

index 0b1099e289167170218ec50ff867536817e7cfc6..af1c0af2f93c022f2b547f0f69ec3a45ceaac430 100644 (file)
@@ -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,
 };
index 56958715c23ebbd885e73c6997b7951bc9b67291..5696a6e8cd379e4bb61a0bddcc15bd5fd37c4628 100644 (file)
@@ -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)
index 60834d1a7cd000d61cc7b74f5b3ca3b87783be4c..eabbda1bf3b59adcf4683ab921cc75476eb42fad 100644 (file)
@@ -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);
index 22d02f64f08050da0ef4ff1bb5d2c57fc1f92602..53ca23ea5fe2af6f1028176e96264380055a4746 100644 (file)
 #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;
index c90467f488f4f05a7107021fd46c8af57b9302e4..5a47f20856201be8f391f54736bfa307f14dbb1e 100644 (file)
@@ -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);
index d3b7698a94e1c9e72e2b6f3c8b80de942778878c..410a6b48efc3ac5f0cb40a9f4d0c2292fa158a1d 100644 (file)
@@ -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);
+}
index 89d7966370191ca6915ad8dad7b915f1b797ae93..bbc259d211063edd6fa38e49ee974f7851078231 100644 (file)
@@ -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 */
index a3f2b028de8eb0e30f6f44d8c384ef5d003a87e5..0546e92d32ad46e5c66070a3e0c4a2d7175b5a88 100644 (file)
@@ -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);
index 5990d988521f6f758fd59f544962e719537e2388..1bf31fa3b9f14a4af335005e4b06e653aad69927 100644 (file)
@@ -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
index ca6bba02b671a052881f88407978d17d1d1b93c8..95f1402b45c43e39d4280fb72c54c98cfccd5fd6 100644 (file)
@@ -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,
index 15d87354c791e932dafa375d4350c8f73393d123..0727596270e6104b63d72e0124bee3bc3f9abc36 100644 (file)
@@ -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;
 };
index 5021c52256e7ca3f75e30dd5381cdc752a7faa8d..5884a0f3a8bdfaf508927fc4bea34ee59bdab05c 100644 (file)
@@ -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
 };
 
index 0f61981d9948d9a654bdff69eeb33efd67b90226..edec2f4d871a868265f7c10e07727203e8e411ae 100644 (file)
@@ -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);
index cd0b96b771a73d16f79bfd6b07d862a70697dd23..eb5fdd9e4c3ff727ee40993e0408d5cb29b27a52 100644 (file)
@@ -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;
 
   /**
index 341e0ca2664300aff26e780f226c68ff204ad656..26a9bfc14c4ab43f8146e6be89d2b4c7bd6e2422 100644 (file)
@@ -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)
index 7669b5b09ba666c5dda0fe0d4d085e29a3e612a5..c8420fdfc7beca03d12bb6a7d1879fd412af41ef 100644 (file)
@@ -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
@@ -122,6 +129,12 @@ struct nettle_cipher_ctx
     struct des3_ctx des3;
     struct des_ctx des;
   } ctx;
+#ifdef NETTLE_GCM
+  union
+  {
+    struct gcm_ctx gcm;
+  } mode_ctx;
+#endif
   void *ctx_ptr;
   uint8_t iv[MAX_BLOCK_SIZE];
   gnutls_cipher_algorithm_t algo;
@@ -130,9 +143,30 @@ struct nettle_cipher_ctx
   nettle_crypt_func *i_decrypt;
   encrypt_func encrypt;
   decrypt_func decrypt;
+  auth_func auth;
+  tag_func tag;
 };
 
+#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)
+{
+  gcm_set_nonce(ctx, GCM_DEFAULT_NONCE_SIZE, iv);
 
+  return gcm_encrypt(ctx, 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)
+{
+  gcm_set_nonce(ctx, GCM_DEFAULT_NONCE_SIZE, iv);
+  return gcm_decrypt(ctx, length, dst, src);
+}
+#endif
 
 static int
 wrap_nettle_cipher_init (gnutls_cipher_algorithm_t algo, void **_ctx)
@@ -150,6 +184,16 @@ 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->auth = (auth_func)gcm_auth;
+      ctx->tag = (tag_func)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 +264,15 @@ 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);
+  
+      gcm_init(&ctx->mode_ctx.gcm, &ctx->ctx.aes_bidi, (nettle_crypt_func *) aes_bidi_encrypt,
+        AES_BLOCK_SIZE);
+
+      break;
+#endif
     case GNUTLS_CIPHER_AES_128_CBC:
     case GNUTLS_CIPHER_AES_192_CBC:
     case GNUTLS_CIPHER_AES_256_CBC:
@@ -314,6 +367,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 +394,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,
 };
index a0b3ee098f2f4a0379904d46ba151648b5333479..cec1d03c162c9a5133dcb42132e939db7a639f2c 100644 (file)
@@ -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,
 };