diff options
-rw-r--r-- | lib/gcrypt/mac.c | 8 | ||||
-rw-r--r-- | lib/gnutls_algorithms.c | 70 | ||||
-rw-r--r-- | lib/gnutls_algorithms.h | 1 | ||||
-rw-r--r-- | lib/gnutls_cipher.c | 401 | ||||
-rw-r--r-- | lib/gnutls_cipher.h | 10 | ||||
-rw-r--r-- | lib/gnutls_cipher_int.c | 258 | ||||
-rw-r--r-- | lib/gnutls_cipher_int.h | 82 | ||||
-rw-r--r-- | lib/gnutls_constate.c | 22 | ||||
-rw-r--r-- | lib/gnutls_hash_int.c | 42 | ||||
-rw-r--r-- | lib/gnutls_hash_int.h | 5 | ||||
-rw-r--r-- | lib/gnutls_int.h | 4 | ||||
-rw-r--r-- | lib/gnutls_priority.c | 7 | ||||
-rw-r--r-- | lib/includes/gnutls/crypto.h | 6 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 7 | ||||
-rw-r--r-- | lib/m4/hooks.m4 | 9 | ||||
-rw-r--r-- | lib/nettle/cipher.c | 76 | ||||
-rw-r--r-- | lib/nettle/mac.c | 76 |
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 (>xt); /* 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 (>xt); - 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 (¶ms->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(¶ms->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(¶ms->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(¶ms->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(¶ms->write.cipher_state, preamble, preamble_size); /* Actual encryption (inplace). */ ret = - _gnutls_cipher_encrypt (¶ms->write.cipher_state, cipher_data, length); + _gnutls_auth_cipher_encrypt_tag (¶ms->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 (¶ms->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 (¶ms->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(¶ms->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(¶ms->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 (¶ms->read.cipher_state, preamble, preamble_size); + if ((ret = - _gnutls_cipher_decrypt (¶ms->read.cipher_state, - ciphertext.data, ciphertext.size)) < 0) - { - gnutls_assert (); - return ret; - } + _gnutls_auth_cipher_decrypt (¶ms->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(¶ms->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 (¶ms->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 (¶ms->read.cipher_state, preamble, preamble_size); + _gnutls_auth_cipher_add_auth (¶ms->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(¶ms->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, ¶ms); 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, ¶ms->read); + ret = _gnutls_init_record_state (params, ver, 1, ¶ms->read); if (ret < 0) return gnutls_assert_val (ret); - ret = _gnutls_init_record_state (params, 0, ¶ms->write); + ret = _gnutls_init_record_state (params, ver, 0, ¶ms->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, }; |