From: Nikos Mavrogiannopoulos Date: Sun, 1 Sep 2013 13:37:10 +0000 (+0300) Subject: _gnutls_send_tlen_int() accepts the actual pad rather than the intended data. Correct... X-Git-Tag: gnutls_3_2_5~67 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5cc6fdb16476a45e066b3f04f8a1b8d9c9ba390d;p=thirdparty%2Fgnutls.git _gnutls_send_tlen_int() accepts the actual pad rather than the intended data. Corrections in sending records with %NEW_PADDING. --- diff --git a/lib/gnutls_cipher.c b/lib/gnutls_cipher.c index db09a1b427..da710fe9dc 100644 --- a/lib/gnutls_cipher.c +++ b/lib/gnutls_cipher.c @@ -45,7 +45,7 @@ static int compressed_to_ciphertext (gnutls_session_t session, uint8_t * cipher_data, int cipher_size, gnutls_datum_t *compressed, - size_t target_size, + size_t min_pad, content_type_t _type, record_parameters_st * params); static int ciphertext_to_compressed (gnutls_session_t session, @@ -64,7 +64,7 @@ static int compressed_to_ciphertext_new (gnutls_session_t session, uint8_t * cipher_data, int cipher_size, gnutls_datum_t *compressed, - size_t target_size, + size_t min_pad, content_type_t type, record_parameters_st * params); @@ -94,7 +94,7 @@ is_read_comp_null (record_parameters_st * record_params) int _gnutls_encrypt (gnutls_session_t session, const uint8_t * data, size_t data_size, - size_t target_size, + size_t min_pad, mbuffer_st* bufel, content_type_t type, record_parameters_st * params) @@ -134,11 +134,11 @@ _gnutls_encrypt (gnutls_session_t session, if (params->write.new_record_padding != 0) ret = compressed_to_ciphertext_new (session, _mbuffer_get_udata_ptr(bufel), _mbuffer_get_udata_size(bufel), - &comp, target_size, type, params); + &comp, min_pad, type, params); else ret = compressed_to_ciphertext (session, _mbuffer_get_udata_ptr(bufel), _mbuffer_get_udata_size(bufel), - &comp, target_size, type, params); + &comp, min_pad, type, params); if (free_comp) gnutls_free(comp.data); @@ -306,7 +306,7 @@ static int compressed_to_ciphertext (gnutls_session_t session, uint8_t * cipher_data, int cipher_size, gnutls_datum_t *compressed, - size_t target_size, + size_t min_pad, content_type_t type, record_parameters_st * params) { @@ -349,7 +349,7 @@ compressed_to_ciphertext (gnutls_session_t session, if (ret < 0) return gnutls_assert_val(ret); - pad = target_size - compressed->size; + pad = min_pad; length = calc_enc_length_block (session, ver, compressed->size, tag_size, &pad, @@ -442,11 +442,11 @@ static int compressed_to_ciphertext_new (gnutls_session_t session, uint8_t * cipher_data, int cipher_size, gnutls_datum_t *compressed, - size_t target_size, + size_t min_pad, content_type_t type, record_parameters_st * params) { - uint16_t pad = target_size - compressed->size; + uint16_t pad = min_pad; int length, length_to_encrypt, ret; uint8_t preamble[MAX_PREAMBLE_SIZE]; int preamble_size; @@ -459,7 +459,7 @@ compressed_to_ciphertext_new (gnutls_session_t session, int explicit_iv = _gnutls_version_has_explicit_iv (ver); 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, final_cipher_size; if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); @@ -544,15 +544,36 @@ compressed_to_ciphertext_new (gnutls_session_t session, data_ptr += 2; length_to_encrypt += 2; length += 2; - + final_cipher_size = cipher_size; + if (pad > 0) { + unsigned t; + + t = cipher_size - compressed->size; + if (pad > t) + { + if (block_algo == CIPHER_BLOCK) + { + if (pad <= blocksize) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + pad -= blocksize*((pad-t)/blocksize); + } + else + pad = t; + } + + DECR_LEN(cipher_size, pad); + memset(data_ptr, 0, pad); data_ptr += pad; length_to_encrypt += pad; length += pad; } + DECR_LEN(cipher_size, compressed->size); + memcpy (data_ptr, compressed->data, compressed->size); data_ptr += compressed->size; length_to_encrypt += compressed->size; @@ -560,6 +581,8 @@ compressed_to_ciphertext_new (gnutls_session_t session, if (tag_size > 0) { + DECR_LEN(cipher_size, tag_size); + data_ptr += tag_size; /* In AEAD ciphers we don't encrypt the tag @@ -583,7 +606,7 @@ compressed_to_ciphertext_new (gnutls_session_t session, ret = _gnutls_auth_cipher_encrypt2_tag (¶ms->write.cipher_state, cipher_data, length_to_encrypt, - cipher_data, cipher_size, 0); + cipher_data, final_cipher_size, 0); if (ret < 0) return gnutls_assert_val(ret); @@ -907,6 +930,9 @@ ciphertext_to_compressed_new (gnutls_session_t restrict session, return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); length_to_decrypt = ciphertext->size; + if (length_to_decrypt < blocksize) + return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); + break; default: diff --git a/lib/gnutls_cipher.h b/lib/gnutls_cipher.h index 0e8dd7e109..cc4a1a08f1 100644 --- a/lib/gnutls_cipher.h +++ b/lib/gnutls_cipher.h @@ -22,7 +22,7 @@ int _gnutls_encrypt (gnutls_session_t session, const uint8_t * data, - size_t data_size, size_t target_size, + size_t data_size, size_t min_pad, mbuffer_st* bufel, content_type_t type, record_parameters_st * params); diff --git a/lib/gnutls_cipher_int.c b/lib/gnutls_cipher_int.c index fb54be0821..129c6b42fa 100644 --- a/lib/gnutls_cipher_int.c +++ b/lib/gnutls_cipher_int.c @@ -328,6 +328,8 @@ int ret; { _gnutls_cipher_tag(&handle->cipher, tag, tag_size); } + else + memset(tag, 0, tag_size); return 0; } diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index bffa3e41d7..2c892f5166 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -182,7 +182,6 @@ typedef enum record_flush_t #define RECORD_HEADER_SIZE(session) (IS_DTLS(session) ? DTLS_RECORD_HEADER_SIZE : TLS_RECORD_HEADER_SIZE) #define MAX_RECORD_HEADER_SIZE DTLS_RECORD_HEADER_SIZE -#define MAX_USER_SEND_SIZE(session) (IS_DTLS(session)?((size_t)gnutls_dtls_get_data_mtu(session)):(size_t)session->security_parameters.max_record_send_size) #define MAX_RECORD_SEND_SIZE(session) (IS_DTLS(session)?((size_t)gnutls_dtls_get_mtu(session)):(size_t)session->security_parameters.max_record_send_size+MAX_RECORD_OVERHEAD(session)) #define MAX_RECORD_RECV_SIZE(session) ((size_t)session->security_parameters.max_record_recv_size) #define MAX_PAD_SIZE 255 @@ -1062,4 +1061,23 @@ unsigned int /* returns a-b in ms */ timespec_sub_ms (struct timespec *a, struct timespec *b); +#include +inline static size_t max_user_send_size(gnutls_session_t session, record_parameters_st *record_params) +{ +size_t max; + + if (IS_DTLS(session)) + max = gnutls_dtls_get_data_mtu(session); + else + max = session->security_parameters.max_record_send_size; + + if (record_params->write.new_record_padding != 0) + max -= 2; + + if (_gnutls_cipher_is_block (record_params->cipher)) + max -= _gnutls_cipher_get_block_size(record_params->cipher); + + return max; +} + #endif /* GNUTLS_INT_H */ diff --git a/lib/gnutls_range.c b/lib/gnutls_range.c index 67c39287d8..a087ff9a32 100644 --- a/lib/gnutls_range.c +++ b/lib/gnutls_range.c @@ -59,7 +59,7 @@ _gnutls_range_max_lh_pad (gnutls_session_t session, ssize_t data_length, if (session->security_parameters.new_record_padding != 0) { - max_pad = MAX_USER_SEND_SIZE (session); + max_pad = max_user_send_size (session, record_params); fixed_pad = 2; } else @@ -163,9 +163,16 @@ gnutls_range_split (gnutls_session_t session, gnutls_range_st * remainder) { int ret; - ssize_t max_frag = MAX_USER_SEND_SIZE (session); + ssize_t max_frag; ssize_t orig_low = (ssize_t) orig->low; ssize_t orig_high = (ssize_t) orig->high; + record_parameters_st *record_params; + + ret = _gnutls_epoch_get (session, EPOCH_WRITE_CURRENT, &record_params); + if (ret < 0) + return gnutls_assert_val(ret); + + max_frag = max_user_send_size (session, record_params); if (orig_high == orig_low) { @@ -283,7 +290,7 @@ gnutls_record_send_range (gnutls_session_t session, const void *data, EPOCH_WRITE_CURRENT, &(((char *) data)[sent]), next_fragment_length, - cur_range.high, + cur_range.high-next_fragment_length, MBUFFER_FLUSH); while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c index d261585e22..bc62081495 100644 --- a/lib/gnutls_record.c +++ b/lib/gnutls_record.c @@ -427,7 +427,7 @@ sequence_increment (gnutls_session_t session, * @epoch_rel: %EPOCH_READ_* or %EPOCH_WRITE_* * @data: the data to be sent * @data_size: the size of the @data - * @target_length: @data_size + minimum required padding + * @min_pad: the minimum required padding * @mflags: zero or %MBUFFER_FLUSH * * Oct 30 2001: Removed capability to send data more than MAX_RECORD_SIZE. @@ -443,7 +443,7 @@ ssize_t _gnutls_send_tlen_int (gnutls_session_t session, content_type_t type, gnutls_handshake_description_t htype, unsigned int epoch_rel, const void *_data, - size_t data_size, size_t target_length, unsigned int mflags) + size_t data_size, size_t min_pad, unsigned int mflags) { mbuffer_st *bufel; ssize_t cipher_size; @@ -453,6 +453,7 @@ _gnutls_send_tlen_int (gnutls_session_t session, content_type_t type, int header_size; const uint8_t *data = _data; record_parameters_st *record_params; + size_t max_send_size; record_state_st *record_state; ret = _gnutls_epoch_get (session, epoch_rel, &record_params); @@ -483,13 +484,14 @@ _gnutls_send_tlen_int (gnutls_session_t session, content_type_t type, return GNUTLS_E_INVALID_SESSION; } + max_send_size = max_user_send_size(session, record_params); - if (data_size > MAX_USER_SEND_SIZE(session)) + if (data_size > max_send_size) { if (IS_DTLS(session)) return gnutls_assert_val(GNUTLS_E_LARGE_PACKET); - send_data_size = MAX_USER_SEND_SIZE(session); + send_data_size = max_send_size; } else send_data_size = data_size; @@ -509,7 +511,7 @@ _gnutls_send_tlen_int (gnutls_session_t session, content_type_t type, } else { - if (unlikely((send_data_size == 0 && target_length == 0))) + if (unlikely((send_data_size == 0 && min_pad == 0))) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); /* now proceed to packet encryption @@ -530,15 +532,15 @@ _gnutls_send_tlen_int (gnutls_session_t session, content_type_t type, memcpy(&headers[3], &record_state->sequence_number.i, 8); _gnutls_record_log - ("REC[%p]: Preparing Packet %s(%d) with length: %d and target length: %d\n", session, - _gnutls_packet2str (type), type, (int) data_size, (int) target_length); + ("REC[%p]: Preparing Packet %s(%d) with length: %d and min pad: %d\n", session, + _gnutls_packet2str (type), type, (int) data_size, (int) min_pad); _mbuffer_set_udata_size(bufel, cipher_size); _mbuffer_set_uhead_size(bufel, header_size); ret = _gnutls_encrypt (session, - data, send_data_size, target_length, + data, send_data_size, min_pad, bufel, type, record_params); if (ret <= 0) { diff --git a/lib/gnutls_record.h b/lib/gnutls_record.h index 0e21552151..5c85dedf53 100644 --- a/lib/gnutls_record.h +++ b/lib/gnutls_record.h @@ -30,7 +30,7 @@ ssize_t _gnutls_send_tlen_int (gnutls_session_t session, content_type_t type, gnutls_handshake_description_t htype, unsigned int epoch_rel, const void *data, size_t sizeofdata, - size_t targetlength, + size_t min_pad, unsigned int mflags); inline static ssize_t @@ -39,7 +39,7 @@ _gnutls_send_int (gnutls_session_t session, content_type_t type, unsigned int epoch_rel, const void *_data, size_t data_size, unsigned int mflags) { - return _gnutls_send_tlen_int(session,type,htype,epoch_rel,_data,data_size,data_size,mflags); + return _gnutls_send_tlen_int(session,type,htype,epoch_rel,_data,data_size,0,mflags); } ssize_t _gnutls_recv_int (gnutls_session_t session, content_type_t type,