summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2011-02-04 11:02:30 +0100
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2011-02-06 22:05:53 +0100
commit74ff2e952564018a93d5930f2427cdf98266673b (patch)
tree0a611a4dc93b335f7226bb7a7e8b85e07c70672c
parente971ba89e1fac6892ead5c2210e4687055cbad79 (diff)
downloadgnutls-74ff2e952564018a93d5930f2427cdf98266673b.tar.gz
Added support for GCM ciphersuites (not tested with other implementation).
-rw-r--r--lib/gcrypt/mac.c8
-rw-r--r--lib/gnutls_algorithms.c70
-rw-r--r--lib/gnutls_algorithms.h1
-rw-r--r--lib/gnutls_cipher.c401
-rw-r--r--lib/gnutls_cipher.h10
-rw-r--r--lib/gnutls_cipher_int.c258
-rw-r--r--lib/gnutls_cipher_int.h82
-rw-r--r--lib/gnutls_constate.c22
-rw-r--r--lib/gnutls_hash_int.c42
-rw-r--r--lib/gnutls_hash_int.h5
-rw-r--r--lib/gnutls_int.h4
-rw-r--r--lib/gnutls_priority.c7
-rw-r--r--lib/includes/gnutls/crypto.h6
-rw-r--r--lib/includes/gnutls/gnutls.h.in7
-rw-r--r--lib/m4/hooks.m49
-rw-r--r--lib/nettle/cipher.c76
-rw-r--r--lib/nettle/mac.c76
17 files changed, 773 insertions, 311 deletions
diff --git a/lib/gcrypt/mac.c b/lib/gcrypt/mac.c
index 0b1099e289..af1c0af2f9 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 56958715c2..5696a6e8cd 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 60834d1a7c..eabbda1bf3 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 22d02f64f0..53ca23ea5f 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 c90467f488..5a47f20856 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 d3b7698a94..410a6b48ef 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 89d7966370..bbc259d211 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 a3f2b028de..0546e92d32 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 5990d98852..1bf31fa3b9 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 ca6bba02b6..95f1402b45 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 15d87354c7..0727596270 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_priority.c b/lib/gnutls_priority.c
index 5021c52256..5884a0f3a8 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/crypto.h b/lib/includes/gnutls/crypto.h
index 0f61981d99..edec2f4d87 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 cd0b96b771..eb5fdd9e4c 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;
/**
diff --git a/lib/m4/hooks.m4 b/lib/m4/hooks.m4
index 341e0ca266..26a9bfc14c 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 7669b5b09b..c8420fdfc7 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
@@ -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,
};
diff --git a/lib/nettle/mac.c b/lib/nettle/mac.c
index a0b3ee098f..cec1d03c16 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,
};