From: Nikos Mavrogiannopoulos Date: Sun, 15 Dec 2013 20:18:05 +0000 (+0100) Subject: Align on 16-byte boundaries the buffers provided to cryptodev. X-Git-Tag: gnutls_3_3_0pre0~451 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ca5b8a57febb8601c0d3cd1c66f75ca8dc746b99;p=thirdparty%2Fgnutls.git Align on 16-byte boundaries the buffers provided to cryptodev. When gnutls is compiled with support for cryptodev, the buffers provided to crypto backend are ensured to be 16-byte aligned (except the ones provided by the user). That increases performance in several crypto accelerators. --- diff --git a/lib/algorithms.h b/lib/algorithms.h index d57e48fd3f..8fff5104dd 100644 --- a/lib/algorithms.h +++ b/lib/algorithms.h @@ -191,7 +191,23 @@ _gnutls_cipher_get_implicit_iv_size(const cipher_entry_st * e) { if (unlikely(e == NULL)) return 0; - return e->iv; + return e->implicit_iv; +} + +inline static int +_gnutls_cipher_get_iv_size(const cipher_entry_st * e) +{ + if (unlikely(e == NULL)) + return 0; + return e->cipher_iv; +} + +inline static int +_gnutls_cipher_get_explicit_iv_size(const cipher_entry_st * e) +{ + if (unlikely(e == NULL)) + return 0; + return e->explicit_iv; } inline static int _gnutls_cipher_get_key_size(const cipher_entry_st * e) diff --git a/lib/algorithms/ciphers.c b/lib/algorithms/ciphers.c index a99273fe79..ebec727a7b 100644 --- a/lib/algorithms/ciphers.c +++ b/lib/algorithms/ciphers.c @@ -35,63 +35,55 @@ */ static const cipher_entry_st algorithms[] = { {"AES-256-CBC", GNUTLS_CIPHER_AES_256_CBC, 16, 32, CIPHER_BLOCK, - 16, 16, 0}, + 0, 16, 16, 0}, {"AES-192-CBC", GNUTLS_CIPHER_AES_192_CBC, 16, 24, CIPHER_BLOCK, - 16, 16, 0}, + 0, 16, 16, 0}, {"AES-128-CBC", GNUTLS_CIPHER_AES_128_CBC, 16, 16, CIPHER_BLOCK, - 16, 16, 0}, + 0, 16, 16, 0}, {"AES-128-GCM", GNUTLS_CIPHER_AES_128_GCM, 16, 16, CIPHER_STREAM, - AEAD_IMPLICIT_DATA_SIZE, 12, 1}, + 4, 8, 12, 1}, {"AES-256-GCM", GNUTLS_CIPHER_AES_256_GCM, 16, 32, CIPHER_STREAM, - AEAD_IMPLICIT_DATA_SIZE, 12, 1}, - {"ARCFOUR-128", GNUTLS_CIPHER_ARCFOUR_128, 1, 16, CIPHER_STREAM, 0, - 0, 0}, + 4, 8, 12, 1}, + {"ARCFOUR-128", GNUTLS_CIPHER_ARCFOUR_128, 1, 16, CIPHER_STREAM, + 0, 0, 0, 0}, {"ESTREAM-SALSA20-256", GNUTLS_CIPHER_ESTREAM_SALSA20_256, 64, 32, - CIPHER_STREAM, 8, 8, 0}, + CIPHER_STREAM, 0, 0, 8, 0}, {"SALSA20-256", GNUTLS_CIPHER_SALSA20_256, 64, 32, CIPHER_STREAM, - 8, 8, 0}, + 0, 0, 8, 0}, {"CAMELLIA-256-CBC", GNUTLS_CIPHER_CAMELLIA_256_CBC, 16, 32, - CIPHER_BLOCK, - 16, 16, 0}, + CIPHER_BLOCK, 0, 16, 16, 0}, {"CAMELLIA-192-CBC", GNUTLS_CIPHER_CAMELLIA_192_CBC, 16, 24, - CIPHER_BLOCK, - 16, 16, 0}, + CIPHER_BLOCK, 0, 16, 16, 0}, {"CAMELLIA-128-CBC", GNUTLS_CIPHER_CAMELLIA_128_CBC, 16, 16, - CIPHER_BLOCK, - 16, 16, 0}, + CIPHER_BLOCK, 0, 16, 16, 0}, {"CAMELLIA-128-GCM", GNUTLS_CIPHER_CAMELLIA_128_GCM, 16, 16, - CIPHER_STREAM, AEAD_IMPLICIT_DATA_SIZE, 12, 1}, + CIPHER_STREAM, 4, 8, 12, 1}, {"CAMELLIA-256-GCM", GNUTLS_CIPHER_CAMELLIA_256_GCM, 16, 32, - CIPHER_STREAM, AEAD_IMPLICIT_DATA_SIZE, 12, 1}, - {"3DES-CBC", GNUTLS_CIPHER_3DES_CBC, 8, 24, CIPHER_BLOCK, 8, 8, 0}, - {"DES-CBC", GNUTLS_CIPHER_DES_CBC, 8, 8, CIPHER_BLOCK, 8, 8, 0}, - {"ARCFOUR-40", GNUTLS_CIPHER_ARCFOUR_40, 1, 5, CIPHER_STREAM, 0, 0, - 0}, - {"RC2-40", GNUTLS_CIPHER_RC2_40_CBC, 8, 5, CIPHER_BLOCK, 8, 8, 0}, + CIPHER_STREAM, 4, 8, 12, 1}, + {"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}, + {"RC2-40", GNUTLS_CIPHER_RC2_40_CBC, 8, 5, CIPHER_BLOCK, 0, 8, 8, 0}, #ifdef ENABLE_OPENPGP {"IDEA-PGP-CFB", GNUTLS_CIPHER_IDEA_PGP_CFB, 8, 16, CIPHER_BLOCK, - 8, 8, 0}, + 0, 8, 8, 0}, {"3DES-PGP-CFB", GNUTLS_CIPHER_3DES_PGP_CFB, 8, 24, CIPHER_BLOCK, - 8, 8, 0}, + 0, 8, 8, 0}, {"CAST5-PGP-CFB", GNUTLS_CIPHER_CAST5_PGP_CFB, 8, 16, CIPHER_BLOCK, - 8, 8, 0}, + 0, 8, 8, 0}, {"BLOWFISH-PGP-CFB", GNUTLS_CIPHER_BLOWFISH_PGP_CFB, 8, - 16 /*actually unlimited */ , CIPHER_BLOCK, 8, 8, 0}, + 16 /*actually unlimited */ , CIPHER_BLOCK, 0, 8, 8, 0}, {"SAFER-SK128-PGP-CFB", GNUTLS_CIPHER_SAFER_SK128_PGP_CFB, 8, 16, - CIPHER_BLOCK, 8, 8, 0}, + CIPHER_BLOCK, 0, 8, 8, 0}, {"AES-128-PGP-CFB", GNUTLS_CIPHER_AES128_PGP_CFB, 16, 16, - CIPHER_BLOCK, 16, - 16, 0}, + CIPHER_BLOCK, 0, 16, 16, 0}, {"AES-192-PGP-CFB", GNUTLS_CIPHER_AES192_PGP_CFB, 16, 24, - CIPHER_BLOCK, 16, - 16, 0}, + CIPHER_BLOCK, 0, 16, 16, 0}, {"AES-256-PGP-CFB", GNUTLS_CIPHER_AES256_PGP_CFB, 16, 32, - CIPHER_BLOCK, 16, - 16, 0}, + CIPHER_BLOCK, 0, 16, 16, 0}, {"TWOFISH-PGP-CFB", GNUTLS_CIPHER_TWOFISH_PGP_CFB, 16, 16, - CIPHER_BLOCK, 16, - 16, 0}, + CIPHER_BLOCK, 0, 16, 16, 0}, #endif #ifndef ENABLE_FIPS140 diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c index b0aa3ae5da..ec38b1b4bc 100644 --- a/lib/gnutls_buffers.c +++ b/lib/gnutls_buffers.c @@ -218,7 +218,7 @@ _gnutls_dgram_read(gnutls_session_t session, mbuffer_st ** bufel, gettime(&t1); } - *bufel = _mbuffer_alloc(max_size); + *bufel = _mbuffer_alloc_align16(max_size, get_total_headers(session)); if (*bufel == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); @@ -286,7 +286,7 @@ _gnutls_stream_read(gnutls_session_t session, mbuffer_st ** bufel, session->internals.direction = 0; - *bufel = _mbuffer_alloc(MAX(max_size, size)); + *bufel = _mbuffer_alloc_align16(MAX(max_size, size), get_total_headers(session)); if (!*bufel) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; diff --git a/lib/gnutls_cipher.c b/lib/gnutls_cipher.c index 760e6607f3..571cd51a29 100644 --- a/lib/gnutls_cipher.c +++ b/lib/gnutls_cipher.c @@ -269,13 +269,14 @@ calc_enc_length_block(gnutls_session_t session, inline static int calc_enc_length_stream(gnutls_session_t session, int data_size, - int hash_size, unsigned auth_cipher) + int hash_size, unsigned auth_cipher, + unsigned exp_iv_size) { unsigned int length; length = data_size + hash_size; if (auth_cipher) - length += AEAD_EXPLICIT_DATA_SIZE; + length += exp_iv_size; return length; } @@ -336,12 +337,14 @@ compressed_to_ciphertext(gnutls_session_t session, int auth_cipher = _gnutls_auth_cipher_is_aead(¶ms->write.cipher_state); uint8_t nonce[MAX_CIPHER_BLOCK_SIZE]; - unsigned iv_size; + unsigned iv_size, imp_iv_size, exp_iv_size; if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); - iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); + iv_size = _gnutls_cipher_get_iv_size(params->cipher); + imp_iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); + exp_iv_size = _gnutls_cipher_get_explicit_iv_size(params->cipher); _gnutls_hard_log("ENC[%p]: cipher: %s, MAC: %s, Epoch: %u\n", session, _gnutls_cipher_get_name(params->cipher), @@ -372,7 +375,7 @@ compressed_to_ciphertext(gnutls_session_t session, pad = 0; length = calc_enc_length_stream(session, compressed->size, - tag_size, auth_cipher); + tag_size, auth_cipher, exp_iv_size); } if (length < 0) @@ -381,11 +384,12 @@ compressed_to_ciphertext(gnutls_session_t session, /* copy the encrypted data to cipher_data. */ if (cipher_size < length) - return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); data_ptr = cipher_data; if (explicit_iv) { /* TLS 1.1 or later */ + if (block_algo == CIPHER_BLOCK) { /* copy the random IV. */ @@ -401,7 +405,7 @@ compressed_to_ciphertext(gnutls_session_t session, */ if (params->write.IV.data == NULL || params->write.IV.size != - AEAD_IMPLICIT_DATA_SIZE) + imp_iv_size) return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR); @@ -411,21 +415,21 @@ compressed_to_ciphertext(gnutls_session_t session, */ memcpy(nonce, params->write.IV.data, params->write.IV.size); - memcpy(&nonce[AEAD_IMPLICIT_DATA_SIZE], + memcpy(&nonce[imp_iv_size], UINT64DATA(params->write.sequence_number), 8); _gnutls_auth_cipher_setiv(¶ms->write. cipher_state, nonce, - AEAD_IMPLICIT_DATA_SIZE + - AEAD_EXPLICIT_DATA_SIZE); + imp_iv_size + + exp_iv_size); /* copy the explicit part */ - memcpy(data_ptr, &nonce[AEAD_IMPLICIT_DATA_SIZE], - AEAD_EXPLICIT_DATA_SIZE); + memcpy(data_ptr, &nonce[imp_iv_size], + exp_iv_size); - data_ptr += AEAD_EXPLICIT_DATA_SIZE; - cipher_data += AEAD_EXPLICIT_DATA_SIZE; + data_ptr += exp_iv_size; + cipher_data += exp_iv_size; } else if (iv_size > 0) _gnutls_auth_cipher_setiv(¶ms->write. cipher_state, @@ -491,12 +495,14 @@ compressed_to_ciphertext_new(gnutls_session_t session, int auth_cipher = _gnutls_auth_cipher_is_aead(¶ms->write.cipher_state); uint8_t nonce[MAX_CIPHER_BLOCK_SIZE]; - unsigned iv_size, final_cipher_size; + unsigned imp_iv_size, final_cipher_size, iv_size, exp_iv_size; if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); - iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); + imp_iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); + exp_iv_size = _gnutls_cipher_get_explicit_iv_size(params->cipher); + iv_size = _gnutls_cipher_get_iv_size(params->cipher); _gnutls_hard_log("ENC[%p]: cipher: %s, MAC: %s, Epoch: %u\n", session, _gnutls_cipher_get_name(params->cipher), @@ -533,7 +539,7 @@ compressed_to_ciphertext_new(gnutls_session_t session, */ if (params->write.IV.data == NULL || params->write.IV.size != - AEAD_IMPLICIT_DATA_SIZE) + imp_iv_size) return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR); @@ -543,23 +549,23 @@ compressed_to_ciphertext_new(gnutls_session_t session, */ memcpy(nonce, params->write.IV.data, params->write.IV.size); - memcpy(&nonce[AEAD_IMPLICIT_DATA_SIZE], + memcpy(&nonce[imp_iv_size], UINT64DATA(params->write.sequence_number), 8); _gnutls_auth_cipher_setiv(¶ms->write. cipher_state, nonce, - AEAD_IMPLICIT_DATA_SIZE + - AEAD_EXPLICIT_DATA_SIZE); + imp_iv_size + + exp_iv_size); /* copy the explicit part */ - DECR_LEN(cipher_size, AEAD_EXPLICIT_DATA_SIZE); - memcpy(data_ptr, &nonce[AEAD_IMPLICIT_DATA_SIZE], - AEAD_EXPLICIT_DATA_SIZE); + DECR_LEN(cipher_size, exp_iv_size); + memcpy(data_ptr, &nonce[imp_iv_size], + exp_iv_size); - data_ptr += AEAD_EXPLICIT_DATA_SIZE; - cipher_data += AEAD_EXPLICIT_DATA_SIZE; - length += AEAD_EXPLICIT_DATA_SIZE; + data_ptr += exp_iv_size; + cipher_data += exp_iv_size; + length += exp_iv_size; } else if (iv_size > 0) _gnutls_auth_cipher_setiv(¶ms->write. cipher_state, @@ -719,12 +725,14 @@ ciphertext_to_compressed(gnutls_session_t session, unsigned int tag_size = _gnutls_auth_cipher_tag_len(¶ms->read.cipher_state); unsigned int explicit_iv = _gnutls_version_has_explicit_iv(ver); - unsigned iv_size; + unsigned imp_iv_size, iv_size, exp_iv_size; if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); - iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); + imp_iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); + exp_iv_size = _gnutls_cipher_get_explicit_iv_size(params->cipher); + iv_size = _gnutls_cipher_get_iv_size(params->cipher); blocksize = _gnutls_cipher_get_block_size(params->cipher); /* actual decryption (inplace) @@ -749,23 +757,23 @@ ciphertext_to_compressed(gnutls_session_t session, if (unlikely (ciphertext->size < - tag_size + AEAD_EXPLICIT_DATA_SIZE)) + tag_size + exp_iv_size)) return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET_LENGTH); memcpy(nonce, params->read.IV.data, - AEAD_IMPLICIT_DATA_SIZE); - memcpy(&nonce[AEAD_IMPLICIT_DATA_SIZE], - ciphertext->data, AEAD_EXPLICIT_DATA_SIZE); + imp_iv_size); + memcpy(&nonce[imp_iv_size], + ciphertext->data, exp_iv_size); _gnutls_auth_cipher_setiv(¶ms->read. cipher_state, nonce, - AEAD_EXPLICIT_DATA_SIZE + - AEAD_IMPLICIT_DATA_SIZE); + exp_iv_size + + imp_iv_size); - ciphertext->data += AEAD_EXPLICIT_DATA_SIZE; - ciphertext->size -= AEAD_EXPLICIT_DATA_SIZE; + ciphertext->data += exp_iv_size; + ciphertext->size -= exp_iv_size; length = length_to_decrypt = ciphertext->size - tag_size; @@ -974,12 +982,14 @@ ciphertext_to_compressed_new(gnutls_session_t restrict session, unsigned int tag_size = _gnutls_auth_cipher_tag_len(¶ms->read.cipher_state); unsigned int explicit_iv = _gnutls_version_has_explicit_iv(ver); - unsigned iv_size; + unsigned imp_iv_size, iv_size, exp_iv_size; if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); - iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); + imp_iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); + exp_iv_size = _gnutls_cipher_get_explicit_iv_size(params->cipher); + iv_size = _gnutls_cipher_get_iv_size(params->cipher); blocksize = _gnutls_cipher_get_block_size(params->cipher); /* actual decryption (inplace) @@ -1002,26 +1012,26 @@ ciphertext_to_compressed_new(gnutls_session_t restrict session, (GNUTLS_E_INTERNAL_ERROR); if (ciphertext->size < - tag_size + AEAD_EXPLICIT_DATA_SIZE + 2) + tag_size + exp_iv_size + 2) return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET_LENGTH); memcpy(nonce, params->read.IV.data, - AEAD_IMPLICIT_DATA_SIZE); - memcpy(&nonce[AEAD_IMPLICIT_DATA_SIZE], - ciphertext->data, AEAD_EXPLICIT_DATA_SIZE); + imp_iv_size); + memcpy(&nonce[imp_iv_size], + ciphertext->data, exp_iv_size); _gnutls_auth_cipher_setiv(¶ms->read. cipher_state, nonce, - AEAD_EXPLICIT_DATA_SIZE + - AEAD_IMPLICIT_DATA_SIZE); + exp_iv_size + + imp_iv_size); - ciphertext->data += AEAD_EXPLICIT_DATA_SIZE; - ciphertext->size -= AEAD_EXPLICIT_DATA_SIZE; + ciphertext->data += exp_iv_size; + ciphertext->size -= exp_iv_size; length_to_decrypt = ciphertext->size - tag_size; - } else if (iv_size > 0) { /* a stream cipher with explicit IV */ + } else if (iv_size > 0) { /* a stream cipher with implicit IV */ _gnutls_auth_cipher_setiv(¶ms->read. cipher_state, UINT64DATA(*sequence), diff --git a/lib/gnutls_constate.c b/lib/gnutls_constate.c index 0ea7dae0ae..1336652556 100644 --- a/lib/gnutls_constate.c +++ b/lib/gnutls_constate.c @@ -343,7 +343,14 @@ int _gnutls_epoch_set_keys(gnutls_session_t session, uint16_t epoch) gnutls_assert_val (GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM); - IV_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); + if (!_gnutls_version_has_explicit_iv(ver)) { + if (_gnutls_cipher_is_block(params->cipher) != CIPHER_STREAM) { + IV_size = _gnutls_cipher_get_iv_size(params->cipher); + } else + IV_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); + } else + IV_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); + key_size = _gnutls_cipher_get_key_size(params->cipher); hash_size = _gnutls_mac_get_key_size(params->mac); diff --git a/lib/gnutls_dtls.c b/lib/gnutls_dtls.c index a8da2f07df..c1d8727f1a 100644 --- a/lib/gnutls_dtls.c +++ b/lib/gnutls_dtls.c @@ -584,7 +584,7 @@ static int record_overhead(const cipher_entry_st * cipher, int t, ret; if (_gnutls_cipher_is_block(cipher) == CIPHER_BLOCK) { - t = _gnutls_cipher_get_implicit_iv_size(cipher); + t = _gnutls_cipher_get_explicit_iv_size(cipher); total += t; /* padding */ diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 3d30218cd6..a8b24c72c3 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -444,7 +444,8 @@ typedef struct cipher_entry_st { uint16_t blocksize; uint16_t keysize; bool block; - uint16_t iv; /* the size of implicit IV - TLS related */ + 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 */ } cipher_entry_st; @@ -556,7 +557,7 @@ typedef struct { /* Holds the signature algorithm used in this session - If any */ gnutls_sign_algorithm_t server_sign_algo; gnutls_sign_algorithm_t client_sign_algo; - + /* FIXME: The following are not saved in the session storage * for session resumption. */ diff --git a/lib/gnutls_mbuffers.c b/lib/gnutls_mbuffers.c index 7b603437e5..a2b6d5a674 100644 --- a/lib/gnutls_mbuffers.c +++ b/lib/gnutls_mbuffers.c @@ -275,6 +275,7 @@ mbuffer_st *_mbuffer_alloc(size_t maximum_size) return st; } + /* Copy data into a segment. The segment must not be part of a buffer * head when using this function. * @@ -301,24 +302,112 @@ _mbuffer_append_data(mbuffer_st * bufel, void *newdata, return 0; } +#ifdef ENABLE_CRYPTODEV +# define ALIGN_SIZE 16 + +/* Allocate a 16-byte alligned buffer segment. The segment is not initially "owned" by + * any buffer. + * + * maximum_size: Amount of data that this segment can contain. + * align_pos: identifies the position of the buffer that will be aligned at 16-bytes + * + * This function should be used to ensure that encrypted data or data to + * be encrypted are properly aligned. + * + * Returns the segment or NULL on error. + * + * Cost: O(1) + */ +mbuffer_st *_mbuffer_alloc_align16(size_t maximum_size, unsigned align_pos) +{ + mbuffer_st *st; + size_t cur_alignment; + + st = gnutls_malloc(maximum_size + sizeof(mbuffer_st) + ALIGN_SIZE); + if (st == NULL) { + gnutls_assert(); + return NULL; + } + + /* set the structure to zero */ + memset(st, 0, sizeof(*st)); + + /* payload points after the mbuffer_st structure */ + st->msg.data = (uint8_t *) st + sizeof(mbuffer_st); + + cur_alignment = ((size_t)(st->msg.data+align_pos)) % ALIGN_SIZE; + if (cur_alignment > 0) + st->msg.data += ALIGN_SIZE - cur_alignment; + + st->msg.size = 0; + st->maximum_size = maximum_size; + + return st; +} + +static unsigned is_aligned16(mbuffer_st * bufel, unsigned align_pos) +{ +uint8_t * ptr = _mbuffer_get_udata_ptr(bufel); + + if (((size_t)(ptr+align_pos)) % ALIGN_SIZE == 0) + return 1; + else + return 0; +} + /* Takes a buffer in multiple chunks and puts all the data in a single - * contiguous segment. + * contiguous segment, ensuring that the @align_pos is 16-byte aligned. * * Returns 0 on success or an error code otherwise. * * Cost: O(n) * n: number of segments initially in the buffer */ -int _mbuffer_linearize(mbuffer_head_st * buf) +int _mbuffer_linearize_align16(mbuffer_head_st * buf, unsigned align_pos) { mbuffer_st *bufel, *cur; gnutls_datum_t msg; size_t pos = 0; - if (buf->length <= 1) + if (buf->length == 0) { /* Nothing to do */ return 0; + } + + bufel = _mbuffer_head_get_first(buf, NULL); + if (buf->length == 1 && is_aligned16(bufel, align_pos)) + return 0; + bufel = _mbuffer_alloc_align16(buf->byte_length, align_pos); + if (!bufel) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + for (cur = _mbuffer_head_get_first(buf, &msg); + msg.data != NULL; cur = _mbuffer_head_get_next(cur, &msg)) { + memcpy(&bufel->msg.data[pos], msg.data, msg.size); + bufel->msg.size += msg.size; + pos += msg.size; + } + + _mbuffer_head_clear(buf); + _mbuffer_enqueue(buf, bufel); + + return 0; +} +#else +int _mbuffer_linearize(mbuffer_head_st * buf) +{ + mbuffer_st *bufel, *cur; + gnutls_datum_t msg; + size_t pos = 0; + + if (buf->length <= 1) { + /* Nothing to do */ + return 0; + } + bufel = _mbuffer_alloc(buf->byte_length); if (!bufel) { gnutls_assert(); @@ -337,3 +426,4 @@ int _mbuffer_linearize(mbuffer_head_st * buf) return 0; } +#endif diff --git a/lib/gnutls_mbuffers.h b/lib/gnutls_mbuffers.h index 72f8f6a8d7..a22ebbf521 100644 --- a/lib/gnutls_mbuffers.h +++ b/lib/gnutls_mbuffers.h @@ -32,6 +32,7 @@ void _mbuffer_enqueue(mbuffer_head_st * buf, mbuffer_st * bufel); mbuffer_st *_mbuffer_dequeue(mbuffer_head_st * buf, mbuffer_st * bufel); int _mbuffer_head_remove_bytes(mbuffer_head_st * buf, size_t bytes); mbuffer_st *_mbuffer_alloc(size_t maximum_size); +int _mbuffer_linearize(mbuffer_head_st * buf); mbuffer_st *_mbuffer_head_get_first(mbuffer_head_st * buf, gnutls_datum_t * msg); @@ -44,7 +45,6 @@ mbuffer_st *_mbuffer_head_pop_first(mbuffer_head_st * buf); */ int _mbuffer_append_data(mbuffer_st * bufel, void *newdata, size_t newdata_size); -int _mbuffer_linearize(mbuffer_head_st * buf); /* For "user" use. One can have buffer data and header. @@ -133,4 +133,12 @@ inline static void _mbuffer_xfree(mbuffer_st ** bufel) *bufel = NULL; } +#ifdef ENABLE_CRYPTODEV +mbuffer_st *_mbuffer_alloc_align16(size_t maximum_size, unsigned align_pos); +int _mbuffer_linearize_align16(mbuffer_head_st * buf, unsigned align_pos); +#else +# define _mbuffer_alloc_align16(x,y) _mbuffer_alloc(x) +# define _mbuffer_linearize_align16(x,y) _mbuffer_linearize(x) +#endif + #endif diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c index 00c9f27f86..a17d2f5148 100644 --- a/lib/gnutls_record.c +++ b/lib/gnutls_record.c @@ -501,7 +501,9 @@ _gnutls_send_tlen_int(gnutls_session_t session, content_type_t type, /* now proceed to packet encryption */ cipher_size = MAX_RECORD_SEND_SIZE(session); - bufel = _mbuffer_alloc(cipher_size + CIPHER_SLACK_SIZE); + + bufel = _mbuffer_alloc_align16(cipher_size + CIPHER_SLACK_SIZE, + get_total_headers2(session, record_params)); if (bufel == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); @@ -510,7 +512,6 @@ _gnutls_send_tlen_int(gnutls_session_t session, content_type_t type, /* Use the default record version, if it is * set. */ copy_record_version(session, htype, &headers[1]); - header_size = RECORD_HEADER_SIZE(session); /* Adjust header length and add sequence for DTLS */ if (IS_DTLS(session)) memcpy(&headers[3], @@ -521,6 +522,7 @@ _gnutls_send_tlen_int(gnutls_session_t session, content_type_t type, session, _gnutls_packet2str(type), type, (int) data_size, (int) min_pad); + header_size = RECORD_HEADER_SIZE(session); _mbuffer_set_udata_size(bufel, cipher_size); _mbuffer_set_uhead_size(bufel, header_size); @@ -1020,7 +1022,9 @@ record_read_headers(gnutls_session_t session, } -static int recv_headers(gnutls_session_t session, content_type_t type, +static int recv_headers(gnutls_session_t session, + record_parameters_st *record_params, + content_type_t type, gnutls_handshake_description_t htype, struct tls_record_st *record, unsigned int *ms) { @@ -1045,7 +1049,8 @@ static int recv_headers(gnutls_session_t session, content_type_t type, return gnutls_assert_val(ret); } - ret = _mbuffer_linearize(&session->internals.record_recv_buffer); + ret = _mbuffer_linearize_align16(&session->internals.record_recv_buffer, + get_total_headers2(session, record_params)); if (ret < 0) return gnutls_assert_val(ret); @@ -1160,7 +1165,7 @@ _gnutls_recv_in_buffers(gnutls_session_t session, content_type_t type, record_state = &record_params->read; /* receive headers */ - ret = recv_headers(session, type, htype, &record, &ms); + ret = recv_headers(session, record_params, type, htype, &record, &ms); if (ret < 0) { ret = gnutls_assert_val_fatal(ret); goto recv_error; @@ -1184,7 +1189,8 @@ _gnutls_recv_in_buffers(gnutls_session_t session, content_type_t type, /* ok now we are sure that we have read all the data - so * move on ! */ - ret = _mbuffer_linearize(&session->internals.record_recv_buffer); + ret = _mbuffer_linearize_align16(&session->internals.record_recv_buffer, + get_total_headers2(session, record_params)); if (ret < 0) return gnutls_assert_val(ret); @@ -1199,7 +1205,7 @@ _gnutls_recv_in_buffers(gnutls_session_t session, content_type_t type, * they are encrypted). */ ret = max_decrypted_size(session) + MAX_PAD_SIZE + MAX_HASH_SIZE; - decrypted = _mbuffer_alloc(ret); + decrypted = _mbuffer_alloc_align16(ret, 0); if (decrypted == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); diff --git a/lib/gnutls_record.h b/lib/gnutls_record.h index 12fcc9b362..71689b75f0 100644 --- a/lib/gnutls_record.h +++ b/lib/gnutls_record.h @@ -25,6 +25,7 @@ #include #include +#include ssize_t _gnutls_send_tlen_int(gnutls_session_t session, content_type_t type, @@ -73,4 +74,35 @@ inline static unsigned max_decrypted_size(gnutls_session_t session) return size; } +/* Returns the headers + any IV that the ciphersuite + * requires */ +inline static +unsigned int get_total_headers(gnutls_session_t session) +{ + int ret; + record_parameters_st *params; + unsigned total = RECORD_HEADER_SIZE(session); + + if (session->security_parameters.new_record_padding) + total += 2; + + ret = _gnutls_epoch_get(session, EPOCH_WRITE_CURRENT, ¶ms); + if (ret < 0) { + return total; + } + + return total + _gnutls_cipher_get_explicit_iv_size(params->cipher); +} + +inline static +unsigned int get_total_headers2(gnutls_session_t session, record_parameters_st *params) +{ + unsigned total = RECORD_HEADER_SIZE(session); + + if (session->security_parameters.new_record_padding) + total += 2; + + return total + _gnutls_cipher_get_explicit_iv_size(params->cipher); +} + #endif