diff options
-rw-r--r-- | lib/algorithms.h | 13 | ||||
-rw-r--r-- | lib/algorithms/ciphers.c | 12 | ||||
-rw-r--r-- | lib/crypto-api.c | 12 | ||||
-rw-r--r-- | lib/gnutls_cipher.c | 212 | ||||
-rw-r--r-- | lib/gnutls_constate.c | 4 | ||||
-rw-r--r-- | lib/gnutls_dtls.c | 2 | ||||
-rw-r--r-- | lib/gnutls_int.h | 8 | ||||
-rw-r--r-- | lib/gnutls_range.c | 6 |
8 files changed, 149 insertions, 120 deletions
diff --git a/lib/algorithms.h b/lib/algorithms.h index 93ef670d45..205f6f681a 100644 --- a/lib/algorithms.h +++ b/lib/algorithms.h @@ -175,11 +175,11 @@ _gnutls_cipher_suite_get_id(gnutls_kx_algorithm_t kx_algorithm, /* Functions for ciphers. */ const cipher_entry_st *cipher_to_entry(gnutls_cipher_algorithm_t c); -inline static int _gnutls_cipher_is_block(const cipher_entry_st * e) +inline static cipher_type_t _gnutls_cipher_type(const cipher_entry_st * e) { if (unlikely(e == NULL)) return 0; - return e->block; + return e->type; } inline static int _gnutls_cipher_get_block_size(const cipher_entry_st * e) @@ -232,7 +232,7 @@ inline static int _gnutls_cipher_algo_is_aead(const cipher_entry_st * e) { if (unlikely(e == NULL)) return 0; - return e->aead; + return (e->type == CIPHER_AEAD)?1:0; } inline static int _gnutls_cipher_is_ok(const cipher_entry_st * e) @@ -250,11 +250,8 @@ inline static int _gnutls_cipher_get_tag_size(const cipher_entry_st * e) if (unlikely(e == NULL)) return ret; - if (e->aead) - ret = e->blocksize; /* FIXME: happens to be the same for now */ - else - ret = 0; - return ret; + /* non-AEAD have 0 as tag size */ + return e->tagsize; } /* Functions for key exchange. */ diff --git a/lib/algorithms/ciphers.c b/lib/algorithms/ciphers.c index ebec727a7b..df202f34aa 100644 --- a/lib/algorithms/ciphers.c +++ b/lib/algorithms/ciphers.c @@ -40,10 +40,10 @@ static const cipher_entry_st algorithms[] = { 0, 16, 16, 0}, {"AES-128-CBC", GNUTLS_CIPHER_AES_128_CBC, 16, 16, CIPHER_BLOCK, 0, 16, 16, 0}, - {"AES-128-GCM", GNUTLS_CIPHER_AES_128_GCM, 16, 16, CIPHER_STREAM, - 4, 8, 12, 1}, - {"AES-256-GCM", GNUTLS_CIPHER_AES_256_GCM, 16, 32, CIPHER_STREAM, - 4, 8, 12, 1}, + {"AES-128-GCM", GNUTLS_CIPHER_AES_128_GCM, 16, 16, CIPHER_AEAD, + 4, 8, 12, 16}, + {"AES-256-GCM", GNUTLS_CIPHER_AES_256_GCM, 16, 32, CIPHER_AEAD, + 4, 8, 12, 16}, {"ARCFOUR-128", GNUTLS_CIPHER_ARCFOUR_128, 1, 16, CIPHER_STREAM, 0, 0, 0, 0}, {"ESTREAM-SALSA20-256", GNUTLS_CIPHER_ESTREAM_SALSA20_256, 64, 32, @@ -57,9 +57,9 @@ static const cipher_entry_st algorithms[] = { {"CAMELLIA-128-CBC", GNUTLS_CIPHER_CAMELLIA_128_CBC, 16, 16, CIPHER_BLOCK, 0, 16, 16, 0}, {"CAMELLIA-128-GCM", GNUTLS_CIPHER_CAMELLIA_128_GCM, 16, 16, - CIPHER_STREAM, 4, 8, 12, 1}, + CIPHER_AEAD, 4, 8, 12, 16}, {"CAMELLIA-256-GCM", GNUTLS_CIPHER_CAMELLIA_256_GCM, 16, 32, - CIPHER_STREAM, 4, 8, 12, 1}, + CIPHER_AEAD, 4, 8, 12, 16}, {"3DES-CBC", GNUTLS_CIPHER_3DES_CBC, 8, 24, CIPHER_BLOCK, 0, 8, 8, 0}, {"DES-CBC", GNUTLS_CIPHER_DES_CBC, 8, 8, CIPHER_BLOCK, 0, 8, 8, 0}, {"ARCFOUR-40", GNUTLS_CIPHER_ARCFOUR_40, 1, 5, CIPHER_STREAM, 0, 0, 0, 0}, diff --git a/lib/crypto-api.c b/lib/crypto-api.c index 70dbb772bb..c7add3e6b9 100644 --- a/lib/crypto-api.c +++ b/lib/crypto-api.c @@ -75,7 +75,7 @@ gnutls_cipher_init(gnutls_cipher_hd_t * handle, _gnutls_cipher_init(&h->ctx_enc, e, key, iv, 1); - if (ret >= 0 && _gnutls_cipher_is_block(e) != 0) + if (ret >= 0 && _gnutls_cipher_type(e) == CIPHER_BLOCK) ret = _gnutls_cipher_init(&h->ctx_dec, e, key, iv, 0); @@ -156,7 +156,7 @@ gnutls_cipher_set_iv(gnutls_cipher_hd_t handle, void *iv, size_t ivlen) _gnutls_cipher_setiv(&h->ctx_enc, iv, ivlen); - if (_gnutls_cipher_is_block(h->ctx_enc.e) != 0) + if (_gnutls_cipher_type(h->ctx_enc.e) == CIPHER_BLOCK) _gnutls_cipher_setiv(&h->ctx_dec, iv, ivlen); } @@ -204,7 +204,7 @@ gnutls_cipher_decrypt(gnutls_cipher_hd_t handle, void *ctext, { api_cipher_hd_st *h = handle; - if (_gnutls_cipher_is_block(h->ctx_enc.e) == 0) + if (_gnutls_cipher_type(h->ctx_enc.e) != CIPHER_BLOCK) return _gnutls_cipher_decrypt(&h->ctx_enc, ctext, ctext_len); else @@ -262,7 +262,7 @@ gnutls_cipher_decrypt2(gnutls_cipher_hd_t handle, const void *ctext, { api_cipher_hd_st *h = handle; - if (_gnutls_cipher_is_block(h->ctx_enc.e) == 0) + if (_gnutls_cipher_type(h->ctx_enc.e) != CIPHER_BLOCK) return _gnutls_cipher_decrypt2(&h->ctx_enc, ctext, ctext_len, ptext, ptext_len); @@ -286,7 +286,7 @@ void gnutls_cipher_deinit(gnutls_cipher_hd_t handle) api_cipher_hd_st *h = handle; _gnutls_cipher_deinit(&h->ctx_enc); - if (_gnutls_cipher_is_block(h->ctx_enc.e) != 0) + if (_gnutls_cipher_type(h->ctx_enc.e) == CIPHER_BLOCK) _gnutls_cipher_deinit(&h->ctx_dec); gnutls_free(handle); } @@ -646,7 +646,7 @@ int gnutls_aead_cipher_init(gnutls_aead_cipher_hd_t * handle, const cipher_entry_st* e; e = cipher_to_entry(cipher); - if (e == NULL || e->aead == 0) + if (e == NULL || e->type != CIPHER_AEAD) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); if (tag_size == 0) diff --git a/lib/gnutls_cipher.c b/lib/gnutls_cipher.c index 5dbf1c5f7e..e9f76cf39e 100644 --- a/lib/gnutls_cipher.c +++ b/lib/gnutls_cipher.c @@ -291,7 +291,7 @@ compressed_to_ciphertext(gnutls_session_t session, int tag_size = _gnutls_auth_cipher_tag_len(¶ms->write.cipher_state); int blocksize = _gnutls_cipher_get_block_size(params->cipher); - unsigned block_algo = _gnutls_cipher_is_block(params->cipher); + unsigned algo_type = _gnutls_cipher_type(params->cipher); uint8_t *data_ptr; const version_entry_st *ver = get_version(session); int explicit_iv = _gnutls_version_has_explicit_iv(ver); @@ -318,7 +318,7 @@ compressed_to_ciphertext(gnutls_session_t session, /* Calculate the encrypted length (padding etc.) */ - if (block_algo == CIPHER_BLOCK) { + if (algo_type == CIPHER_BLOCK) { /* Call _gnutls_rnd() once. Get data used for the IV */ ret = _gnutls_rnd(GNUTLS_RND_NONCE, nonce, blocksize); @@ -331,7 +331,7 @@ compressed_to_ciphertext(gnutls_session_t session, calc_enc_length_block(session, ver, compressed->size, tag_size, &pad, auth_cipher, blocksize); - } else { + } else { /* AEAD + STREAM */ pad = 0; length = calc_enc_length_stream(session, compressed->size, @@ -348,49 +348,47 @@ compressed_to_ciphertext(gnutls_session_t session, data_ptr = cipher_data; - if (explicit_iv) { /* TLS 1.1 or later */ + if (algo_type == CIPHER_BLOCK && explicit_iv != 0) { + /* copy the random IV. + */ + memcpy(data_ptr, nonce, blocksize); + _gnutls_auth_cipher_setiv(¶ms->write. + cipher_state, data_ptr, + blocksize); - if (block_algo == CIPHER_BLOCK) { - /* copy the random IV. - */ - memcpy(data_ptr, nonce, blocksize); - _gnutls_auth_cipher_setiv(¶ms->write. - cipher_state, data_ptr, - blocksize); + data_ptr += blocksize; + cipher_data += blocksize; + } else if (algo_type == CIPHER_AEAD) { + /* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block + */ + if (params->write.IV.data == NULL + || params->write.IV.size != + imp_iv_size) + return + gnutls_assert_val + (GNUTLS_E_INTERNAL_ERROR); - data_ptr += blocksize; - cipher_data += 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 != - imp_iv_size) - return - gnutls_assert_val - (GNUTLS_E_INTERNAL_ERROR); - - /* Instead of generating a new nonce on every packet, we use the - * write.sequence_number (It is a MAY on RFC 5288). - */ - memcpy(nonce, params->write.IV.data, - params->write.IV.size); - memcpy(&nonce[imp_iv_size], - UINT64DATA(params->write.sequence_number), - 8); - - _gnutls_auth_cipher_setiv(¶ms->write. - cipher_state, nonce, - imp_iv_size + - exp_iv_size); - - /* copy the explicit part */ - memcpy(data_ptr, &nonce[imp_iv_size], - exp_iv_size); - - data_ptr += exp_iv_size; - cipher_data += exp_iv_size; - } + /* Instead of generating a new nonce on every packet, we use the + * write.sequence_number (It is a MAY on RFC 5288), and safer + * as it will never reuse a value. + */ + memcpy(nonce, params->write.IV.data, + params->write.IV.size); + memcpy(&nonce[imp_iv_size], + UINT64DATA(params->write.sequence_number), + 8); + + _gnutls_auth_cipher_setiv(¶ms->write. + cipher_state, nonce, + imp_iv_size + + exp_iv_size); + + /* copy the explicit part */ + memcpy(data_ptr, &nonce[imp_iv_size], + exp_iv_size); + + data_ptr += exp_iv_size; + cipher_data += exp_iv_size; } /* add the authenticate data */ @@ -418,7 +416,7 @@ static void dummy_wait(record_parameters_st * params, unsigned int pad, unsigned total) { /* this hack is only needed on CBC ciphers */ - if (_gnutls_cipher_is_block(params->cipher) == CIPHER_BLOCK) { + if (_gnutls_cipher_type(params->cipher) == CIPHER_BLOCK) { unsigned len; /* force an additional hash compression function evaluation to prevent timing @@ -460,6 +458,7 @@ ciphertext_to_compressed(gnutls_session_t session, uint64 * sequence) { uint8_t tag[MAX_HASH_SIZE]; + uint8_t nonce[MAX_CIPHER_BLOCK_SIZE]; const uint8_t *tag_ptr; unsigned int pad = 0, i; int length, length_to_decrypt; @@ -484,58 +483,89 @@ ciphertext_to_compressed(gnutls_session_t session, /* actual decryption (inplace) */ - switch (_gnutls_cipher_is_block(params->cipher)) { - case CIPHER_STREAM: + switch (_gnutls_cipher_type(params->cipher)) { + case CIPHER_AEAD: /* 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)) { - uint8_t nonce[MAX_CIPHER_BLOCK_SIZE]; - /* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block - */ - if (unlikely - (params->read.IV.data == NULL - || params->read.IV.size != 4)) - return - gnutls_assert_val - (GNUTLS_E_INTERNAL_ERROR); - - if (unlikely - (ciphertext->size < - tag_size + exp_iv_size)) - return - gnutls_assert_val - (GNUTLS_E_UNEXPECTED_PACKET_LENGTH); - - memcpy(nonce, params->read.IV.data, - imp_iv_size); - memcpy(&nonce[imp_iv_size], - ciphertext->data, exp_iv_size); + if (unlikely(_gnutls_auth_cipher_is_aead(¶ms->read. + cipher_state) == 0)) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); - _gnutls_auth_cipher_setiv(¶ms->read. - cipher_state, nonce, - exp_iv_size + - imp_iv_size); - - ciphertext->data += exp_iv_size; - ciphertext->size -= exp_iv_size; - - length = length_to_decrypt = - ciphertext->size - tag_size; - tag_ptr = ciphertext->data + length_to_decrypt; - } else { - if (unlikely(ciphertext->size < tag_size)) - return - gnutls_assert_val - (GNUTLS_E_UNEXPECTED_PACKET_LENGTH); - - length_to_decrypt = ciphertext->size; - length = ciphertext->size - tag_size; - tag_ptr = compressed->data + length; + /* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block + */ + if (unlikely + (params->read.IV.data == NULL + || params->read.IV.size != 4)) + return + gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + + if (unlikely(ciphertext->size < tag_size + exp_iv_size)) + return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); + + memcpy(nonce, params->read.IV.data, + imp_iv_size); + memcpy(&nonce[imp_iv_size], + ciphertext->data, exp_iv_size); + + _gnutls_auth_cipher_setiv(¶ms->read. + cipher_state, nonce, + exp_iv_size + + imp_iv_size); + + ciphertext->data += exp_iv_size; + ciphertext->size -= exp_iv_size; + + length = length_to_decrypt = + ciphertext->size - tag_size; + tag_ptr = ciphertext->data + length_to_decrypt; + + /* Pass the type, version, length and compressed through + * MAC. + */ + preamble_size = + make_preamble(UINT64DATA(*sequence), type, + length, ver, preamble); + + ret = + _gnutls_auth_cipher_add_auth(¶ms->read. + cipher_state, preamble, + preamble_size); + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + + if (unlikely + ((unsigned) length_to_decrypt > compressed->size)) { + _gnutls_audit_log(session, + "Received %u bytes, while expecting less than %u\n", + (unsigned int) length_to_decrypt, + (unsigned int) compressed->size); + return + gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); } + ret = + _gnutls_auth_cipher_decrypt2(¶ms->read. + cipher_state, + ciphertext->data, + length_to_decrypt, + compressed->data, + compressed->size); + + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + + break; + case CIPHER_STREAM: + if (unlikely(ciphertext->size < tag_size)) + return + gnutls_assert_val + (GNUTLS_E_UNEXPECTED_PACKET_LENGTH); + + length_to_decrypt = ciphertext->size; + length = ciphertext->size - tag_size; + tag_ptr = compressed->data + length; + /* Pass the type, version, length and compressed through * MAC. */ diff --git a/lib/gnutls_constate.c b/lib/gnutls_constate.c index e9b9678f42..25299982cb 100644 --- a/lib/gnutls_constate.c +++ b/lib/gnutls_constate.c @@ -199,7 +199,7 @@ _gnutls_init_record_state(record_parameters_st * params, gnutls_datum_t *iv = NULL; if (!_gnutls_version_has_explicit_iv(ver)) { - if (_gnutls_cipher_is_block(params->cipher) != + if (_gnutls_cipher_type(params->cipher) != CIPHER_STREAM) iv = &state->IV; } @@ -344,7 +344,7 @@ int _gnutls_epoch_set_keys(gnutls_session_t session, uint16_t epoch) (GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM); if (!_gnutls_version_has_explicit_iv(ver)) { - if (_gnutls_cipher_is_block(params->cipher) != CIPHER_STREAM) { + if (_gnutls_cipher_type(params->cipher) != CIPHER_STREAM) { IV_size = _gnutls_cipher_get_iv_size(params->cipher); } else IV_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); diff --git a/lib/gnutls_dtls.c b/lib/gnutls_dtls.c index c07f08f6eb..7b359eb768 100644 --- a/lib/gnutls_dtls.c +++ b/lib/gnutls_dtls.c @@ -590,7 +590,7 @@ static int record_overhead(const cipher_entry_st * cipher, int total = 0; int t, ret; - if (_gnutls_cipher_is_block(cipher) == CIPHER_BLOCK) { + if (_gnutls_cipher_type(cipher) == CIPHER_BLOCK) { t = _gnutls_cipher_get_explicit_iv_size(cipher); total += t; diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 7faa5ace05..3b9259cf4b 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -290,7 +290,7 @@ typedef enum extensions_t { GNUTLS_EXTENSION_SAFE_RENEGOTIATION = 65281 /* aka: 0xff01 */ } extensions_t; -typedef enum { CIPHER_STREAM, CIPHER_BLOCK } cipher_type_t; +typedef enum { CIPHER_STREAM, CIPHER_BLOCK, CIPHER_AEAD } cipher_type_t; #define RESUME_TRUE 1 #define RESUME_FALSE 0 @@ -463,11 +463,11 @@ typedef struct cipher_entry_st { gnutls_cipher_algorithm_t id; uint16_t blocksize; uint16_t keysize; - bool block; + cipher_type_t type; uint16_t implicit_iv; /* the size of implicit IV - the IV generated but not sent */ uint16_t explicit_iv; /* the size of explicit IV - the IV stored in record */ uint16_t cipher_iv; /* the size of IV needed by the cipher */ - bool aead; /* Whether it is authenc cipher */ + uint16_t tagsize; } cipher_entry_st; /* This structure is used both for MACs and digests @@ -1080,7 +1080,7 @@ inline static size_t max_user_send_size(gnutls_session_t session, max = session->security_parameters.max_record_send_size; /* DTLS data MTU accounts for those */ - if (_gnutls_cipher_is_block(record_params->cipher)) + if (_gnutls_cipher_type(record_params->cipher) != CIPHER_STREAM) max -= _gnutls_cipher_get_block_size(record_params-> cipher); diff --git a/lib/gnutls_range.c b/lib/gnutls_range.c index 0e29a8994c..e130431edb 100644 --- a/lib/gnutls_range.c +++ b/lib/gnutls_range.c @@ -67,7 +67,8 @@ _gnutls_range_max_lh_pad(gnutls_session_t session, ssize_t data_length, tag_size = _gnutls_auth_cipher_tag_len(&record_params->write. cipher_state); - switch (_gnutls_cipher_is_block(record_params->cipher)) { + switch (_gnutls_cipher_type(record_params->cipher)) { + case CIPHER_AEAD: case CIPHER_STREAM: return this_pad; @@ -115,10 +116,11 @@ int gnutls_record_can_use_length_hiding(gnutls_session_t session) return 0; } - switch (_gnutls_cipher_is_block(record_params->cipher)) { + switch (_gnutls_cipher_type(record_params->cipher)) { case CIPHER_BLOCK: return 1; case CIPHER_STREAM: + case CIPHER_AEAD: default: return 0; } |