From ceb092a86ca3c6eb1030f90d842962278e52970d Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Sat, 30 Jun 2012 00:35:56 +0200 Subject: [PATCH] gnutls_dtls_get_data_mtu() is more precise. Based on patch by David Woodhouse. --- lib/gnutls_dtls.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++----- lib/gnutls_int.h | 3 ++- lib/gnutls_state.c | 47 --------------------------------- lib/gnutls_state.h | 2 -- 4 files changed, 72 insertions(+), 56 deletions(-) diff --git a/lib/gnutls_dtls.c b/lib/gnutls_dtls.c index f07b300cb..979198cc2 100644 --- a/lib/gnutls_dtls.c +++ b/lib/gnutls_dtls.c @@ -581,6 +581,63 @@ void gnutls_dtls_set_mtu (gnutls_session_t session, unsigned int mtu) session->internals.dtls.mtu = mtu; } +/* returns overhead imposed by the record layer (encryption/compression) + * etc. It does not include the record layer headers, since the caller + * needs to cope with rounding to multiples of blocksize, and the header + * is outside that. + * + * blocksize: will contain the block size when padding may be required or 1 + * + * It may return a negative error code on error. + */ +static int _gnutls_record_overhead_rt(gnutls_session_t session, unsigned int *blocksize) +{ +record_parameters_st *params; +int total = 0, ret, iv_size; + + if (session->internals.initial_negotiation_completed == 0) + return GNUTLS_E_INVALID_REQUEST; + + ret = _gnutls_epoch_get (session, EPOCH_WRITE_CURRENT, ¶ms); + if (ret < 0) + return gnutls_assert_val(ret); + + /* requires padding */ + iv_size = _gnutls_cipher_get_iv_size(params->cipher_algorithm); + + if (_gnutls_cipher_is_block (params->cipher_algorithm) == CIPHER_BLOCK) + { + *blocksize = iv_size; + + if (!IS_DTLS(session)) + total += MAX_PAD_SIZE; + else + total += iv_size; /* iv_size == block_size */ + } + else + { + *blocksize = 1; + } + + if (params->mac_algorithm == GNUTLS_MAC_AEAD) + total += _gnutls_cipher_get_tag_size(params->cipher_algorithm); + else + { + ret = _gnutls_hmac_get_algo_len(params->mac_algorithm); + if (ret < 0) + return gnutls_assert_val(ret); + total+=ret; + } + + if (params->compression_algorithm != GNUTLS_COMP_NULL) + total += EXTRA_COMP_SIZE; + + /* We always pad with at least one byte; never 0. */ + total++; + + return total; +} + /** * gnutls_dtls_get_data_mtu: * @session: is a #gnutls_session_t structure. @@ -595,13 +652,20 @@ void gnutls_dtls_set_mtu (gnutls_session_t session, unsigned int mtu) **/ unsigned int gnutls_dtls_get_data_mtu (gnutls_session_t session) { -int ret; +int mtu = session->internals.dtls.mtu; +int blocksize = 0; +int overhead; + + mtu -= RECORD_HEADER_SIZE(session); - ret = _gnutls_record_overhead_rt(session); - if (ret >= 0) - return session->internals.dtls.mtu - ret; - else - return session->internals.dtls.mtu - RECORD_HEADER_SIZE(session); + overhead = _gnutls_record_overhead_rt(session, &blocksize); + if (overhead < 0) + return mtu; + + if (blocksize) + mtu -= mtu % blocksize; + + return mtu - overhead; } /** diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 02c4f9524..77705a304 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -82,6 +82,7 @@ typedef struct } uint64; #include +#include #include #include @@ -174,7 +175,7 @@ typedef enum transport_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_RECORD_SEND_SIZE(session) (IS_DTLS(session)?((size_t)session->internals.dtls.mtu-DTLS_RECORD_HEADER_SIZE):(size_t)session->security_parameters.max_record_send_size) +#define MAX_RECORD_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_RECV_SIZE(session) ((size_t)session->security_parameters.max_record_recv_size) #define MAX_PAD_SIZE 255 #define EXTRA_COMP_SIZE 2048 diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c index 6fae277de..c868d48d9 100644 --- a/lib/gnutls_state.c +++ b/lib/gnutls_state.c @@ -1353,53 +1353,6 @@ gnutls_session_channel_binding (gnutls_session_t session, return 0; } -/* returns overhead imposed by the record layer (encryption/compression) - * etc. It does include the record layer headers. - * - * It may return a negative error code on error. - */ -int _gnutls_record_overhead_rt(gnutls_session_t session) -{ -record_parameters_st *params; -int total = 0, ret, iv_size; - - if (session->internals.initial_negotiation_completed == 0) - return RECORD_HEADER_SIZE(session); - - ret = _gnutls_epoch_get (session, EPOCH_WRITE_CURRENT, ¶ms); - if (ret < 0) - return gnutls_assert_val(ret); - - /* requires padding */ - iv_size = _gnutls_cipher_get_iv_size(params->cipher_algorithm); - total += iv_size; - - if (_gnutls_cipher_is_block (params->cipher_algorithm) == CIPHER_BLOCK) - { - if (!IS_DTLS(session)) - total += MAX_PAD_SIZE; - else - total += iv_size; /* iv_size == block_size */ - } - - if (params->mac_algorithm == GNUTLS_MAC_AEAD) - total += _gnutls_cipher_get_tag_size(params->cipher_algorithm); - else - { - ret = _gnutls_hmac_get_algo_len(params->mac_algorithm); - if (ret < 0) - return gnutls_assert_val(ret); - total+=ret; - } - - if (params->compression_algorithm != GNUTLS_COMP_NULL) - total += EXTRA_COMP_SIZE; - - total += RECORD_HEADER_SIZE(session); - - return total; -} - /** * gnutls_ecc_curve_get: * @session: is a #gnutls_session_t structure. diff --git a/lib/gnutls_state.h b/lib/gnutls_state.h index b2e5511f1..a89e1817e 100644 --- a/lib/gnutls_state.h +++ b/lib/gnutls_state.h @@ -43,8 +43,6 @@ void _gnutls_record_set_default_version (gnutls_session_t session, unsigned char major, unsigned char minor); -int _gnutls_record_overhead_rt(gnutls_session_t session); - #include #define CHECK_AUTH(auth, ret) if (gnutls_auth_get_type(session) != auth) { \ -- 2.11.4.GIT