From 9468ff1966faea814edbd2600ad196dd98c96686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Thu, 21 Sep 2017 13:49:50 +0200 Subject: [PATCH] Implement support for MTU setting --- include/mbedtls/ssl.h | 43 ++++++++++++++++++++++----- library/ssl_tls.c | 69 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 92 insertions(+), 20 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 0283eee625..706e27284b 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -2430,6 +2430,7 @@ void mbedtls_ssl_conf_cert_req_ca_list( mbedtls_ssl_config *conf, #if defined(MBEDTLS_SSL_PROTO_DTLS) /** * \brief Set the Maximum Tranport Unit (MTU). + * Special value: 0 means unset (no limit). * This represents the maximum size of a datagram payload * handled by the transport layer (usually UDP) as determined * by the network link and stack. In practice, this controls @@ -2446,7 +2447,8 @@ void mbedtls_ssl_conf_cert_req_ca_list( mbedtls_ssl_config *conf, * * \note Values larger than \c MBEDTLS_SSL_OUT_CONTENT_LEN have no * effect. This can only be used to decrease the maximum size - * of detagrams sent. + * of datagrams sent. Values lower than record layer expansion + * are ignored. * * \param conf SSL configuration * \param mtu Value of the path MTU in bytes @@ -2738,6 +2740,9 @@ const char *mbedtls_ssl_get_version( const mbedtls_ssl_context *ssl ); * \brief Return the (maximum) number of bytes added by the record * layer: header + encryption/MAC overhead (inc. padding) * + * \note This function is not available (always returns an error) + * when record compression is enabled. + * * \param ssl SSL context * * \return Current maximum record expansion in bytes, or @@ -2752,12 +2757,8 @@ int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl ); * This is the value negotiated with peer if any, * or the locally configured value. * - * \note With DTLS, \c mbedtls_ssl_write() will return an error if - * called with a larger length value. - * With TLS, \c mbedtls_ssl_write() will fragment the input if - * necessary and return the number of bytes written; it is up - * to the caller to call \c mbedtls_ssl_write() again in - * order to send the remaining bytes if any. + * \sa mbedtls_ssl_conf_max_frag_len() + * \sa mbedtls_ssl_get_max_record_payload() * * \param ssl SSL context * @@ -2766,6 +2767,34 @@ int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl ); size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl ); #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ +/** + * \brief Return the current maximum outgoing record payload in bytes. + * This takes into account the config.h setting \c + * MBEDTLS_SSL_OUT_CONTENT_LEN, the configured and negotiated + * max fragment length extension if used, and for DTLS the + * path MTU as configured and current record expansion. + * + * \note With DTLS, \c mbedtls_ssl_write() will return an error if + * called with a larger length value. + * With TLS, \c mbedtls_ssl_write() will fragment the input if + * necessary and return the number of bytes written; it is up + * to the caller to call \c mbedtls_ssl_write() again in + * order to send the remaining bytes if any. + * + * \note This function is not available (always returns an error) + * when record compression is enabled. + * + * \sa mbedtls_ssl_conf_mtu() + * \sa mbedtls_ssl_get_max_frag_len() + * \sa mbedtls_ssl_get_record_expansion() + * + * \param ssl SSL context + * + * \return Current maximum payload for an outgoing record, + * or a negative error code. + */ +int mbedtls_ssl_get_max_out_record_payload( const mbedtls_ssl_context *ssl ); + #if defined(MBEDTLS_X509_CRT_PARSE_C) /** * \brief Return the peer certificate from the current connection diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 4b124ba8f6..7b2ab0fb03 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -2845,16 +2845,20 @@ int mbedtls_ssl_resend( mbedtls_ssl_context *ssl ) */ int mbedtls_ssl_flight_transmit( mbedtls_ssl_context *ssl ) { -#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) - const size_t max_record_content_len = mbedtls_ssl_get_max_frag_len( ssl ); -#else - const size_t max_record_content_len = MBEDTLS_SSL_OUT_CONTENT_LEN; -#endif + const int ret_payload = mbedtls_ssl_get_max_out_record_payload( ssl ); + const size_t max_record_payload = (size_t) ret_payload; /* DTLS handshake headers are 12 bytes */ - const size_t max_hs_fragment_len = max_record_content_len - 12; + const size_t max_hs_fragment_len = max_record_payload - 12; MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_flight_transmit" ) ); + if( ret_payload < 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_get_max_out_record_payload", + ret_payload ); + return( ret_payload ); + } + if( ssl->handshake->retransmit_state != MBEDTLS_SSL_RETRANS_SENDING ) { MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialise fligh transmission" ) ); @@ -7008,6 +7012,7 @@ int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl ) #if defined(MBEDTLS_ZLIB_SUPPORT) if( ssl->session_out->compression != MBEDTLS_SSL_COMPRESS_NULL ) return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } #endif switch( mbedtls_cipher_get_cipher_mode( &transform->cipher_ctx_enc ) ) @@ -7055,10 +7060,45 @@ size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl ) max_len = ssl_mfl_code_to_length( ssl->session_negotiate->mfl_code ); } - return max_len; + return( max_len ); } #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ +int mbedtls_ssl_get_max_out_record_payload( const mbedtls_ssl_context *ssl ) +{ + size_t max_len = MBEDTLS_SSL_OUT_CONTENT_LEN; + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + const size_t mfl = mbedtls_ssl_get_max_frag_len( ssl ); + + if( max_len > mfl ) + max_len = mfl; +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->mtu != 0 ) + { + const size_t mtu = ssl->conf->mtu; + const int ret = mbedtls_ssl_get_record_expansion( ssl ); + const size_t overhead = (size_t) ret; + + if( ret < 0 ) + return( ret ); + + if( mtu <= overhead ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "MTU too low for record expansion" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + if( max_len > mtu - overhead ) + max_len = mtu - overhead; + } +#endif + + return( (int) max_len ); +} + #if defined(MBEDTLS_X509_CRT_PARSE_C) const mbedtls_x509_crt *mbedtls_ssl_get_peer_cert( const mbedtls_ssl_context *ssl ) { @@ -7610,12 +7650,15 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) static int ssl_write_real( mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len ) { - int ret; -#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) - size_t max_len = mbedtls_ssl_get_max_frag_len( ssl ); -#else - size_t max_len = MBEDTLS_SSL_OUT_CONTENT_LEN; -#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + int ret = mbedtls_ssl_get_max_out_record_payload( ssl ); + const size_t max_len = (size_t) ret; + + if( ret < 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_get_max_out_record_payload", ret ); + return( ret ); + } + if( len > max_len ) { #if defined(MBEDTLS_SSL_PROTO_DTLS)