From f384495972315c94471d97fc4c6256181d9936e8 Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Fri, 16 Oct 2020 23:03:01 +0200 Subject: [PATCH] Sideport the variable IO buffer size feature to baremetal Signed-off-by: Andrzej Kurek --- configs/baremetal.h | 3 + include/mbedtls/config.h | 7 + include/mbedtls/ssl.h | 67 +++++- include/mbedtls/ssl_internal.h | 30 ++- library/ssl_tls.c | 295 +++++++++++++++++++++++-- library/version_features.c | 3 + programs/ssl/query_config.c | 8 + programs/ssl/ssl_client2.c | 6 +- programs/ssl/ssl_server2.c | 18 +- tests/scripts/all.sh | 69 ++++++ tests/ssl-opt.sh | 391 ++++++++++++++++++++++++++++++--- 11 files changed, 826 insertions(+), 71 deletions(-) diff --git a/configs/baremetal.h b/configs/baremetal.h index 7168976e5..954154206 100644 --- a/configs/baremetal.h +++ b/configs/baremetal.h @@ -115,6 +115,9 @@ #define MBEDTLS_SSL_CONF_ENFORCE_EXTENDED_MASTER_SECRET \ MBEDTLS_SSL_EXTENDED_MS_ENFORCE_ENABLED +#define MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + #define MBEDTLS_USE_TINYCRYPT #define MBEDTLS_HAVE_ASM #if !( defined(__STRICT_ANSI__) && defined(__CC_ARM) ) diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 3587bbaa4..5534ec4f8 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -1909,6 +1909,13 @@ */ //#define MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT +/** + * \def MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH + * + * Enable modifying the maximum I/O buffer size. + */ +//#define MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH + /** * \def MBEDTLS_THREADING_ALT * diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index ee231a599..f447cf3f3 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -1370,6 +1370,10 @@ struct mbedtls_ssl_context int in_msgtype; /*!< record header: message type */ size_t in_msglen; /*!< record header: message length */ size_t in_left; /*!< amount of data read so far */ +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + size_t in_buf_len; /*!< length of input buffer */ +#endif + #if defined(MBEDTLS_SSL_PROTO_DTLS) size_t next_record_offset; /*!< offset of the next record in datagram (equal to in_left if none) */ @@ -1399,6 +1403,9 @@ struct mbedtls_ssl_context int out_msgtype; /*!< record header: message type */ size_t out_msglen; /*!< record header: message length */ size_t out_left; /*!< amount of data not yet written */ +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + size_t out_buf_len; /*!< length of output buffer */ +#endif #if defined(MBEDTLS_ZLIB_SUPPORT) unsigned char *compress_buf; /*!< zlib data buffer */ @@ -3597,18 +3604,61 @@ int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl ); #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) /** - * \brief Return the maximum fragment length (payload, in bytes). - * This is the value negotiated with peer if any, - * or the locally configured value. + * \brief Return the maximum fragment length (payload, in bytes) for + * the output buffer. For the client, this is the configured + * value. For the server, it is the minimum of two - the + * configured value and the negotiated one. * * \sa mbedtls_ssl_conf_max_frag_len() * \sa mbedtls_ssl_get_max_record_payload() * * \param ssl SSL context * - * \return Current maximum fragment length. + * \return Current maximum fragment length for the output buffer. */ -size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl ); +size_t mbedtls_ssl_get_output_max_frag_len( const mbedtls_ssl_context *ssl ); + +/** + * \brief Return the maximum fragment length (payload, in bytes) for + * the input buffer. This is the negotiated maximum fragment + * length, or, if there is none, MBEDTLS_SSL_MAX_CONTENT_LEN. + * If it is not defined either, the value is 2^14. This function + * works as its predecessor, \c mbedtls_ssl_get_max_frag_len(). + * + * \sa mbedtls_ssl_conf_max_frag_len() + * \sa mbedtls_ssl_get_max_record_payload() + * + * \param ssl SSL context + * + * \return Current maximum fragment length for the output buffer. + */ +size_t mbedtls_ssl_get_input_max_frag_len( const mbedtls_ssl_context *ssl ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) + +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif + +/** + * \brief This function is a deprecated approach to getting the max + * fragment length. Its an alias for + * \c mbedtls_ssl_get_output_max_frag_len(), as the behaviour + * is the same. See \c mbedtls_ssl_get_output_max_frag_len() for + * more detail. + * + * \sa mbedtls_ssl_get_input_max_frag_len() + * \sa mbedtls_ssl_get_output_max_frag_len() + * + * \param ssl SSL context + * + * \return Current maximum fragment length for the output buffer. + */ +MBEDTLS_DEPRECATED size_t mbedtls_ssl_get_max_frag_len( + const mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_DEPRECATED_REMOVED */ #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ /** @@ -3629,7 +3679,8 @@ size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl ); * when record compression is enabled. * * \sa mbedtls_ssl_set_mtu() - * \sa mbedtls_ssl_get_max_frag_len() + * \sa mbedtls_ssl_get_output_max_frag_len() + * \sa mbedtls_ssl_get_input_max_frag_len() * \sa mbedtls_ssl_get_record_expansion() * * \param ssl SSL context @@ -3930,8 +3981,8 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) * or negotiated with the peer), then: * - with TLS, less bytes than requested are written. * - with DTLS, MBEDTLS_ERR_SSL_BAD_INPUT_DATA is returned. - * \c mbedtls_ssl_get_max_frag_len() may be used to query the - * active maximum fragment length. + * \c mbedtls_ssl_get_output_max_frag_len() may be used to + * query the active maximum fragment length. * * \note Attempting to write 0 bytes will result in an empty TLS * application record being sent. diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index a1c5d1d09..17c576369 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -260,7 +260,7 @@ implicit sequence number. */ #define MBEDTLS_SSL_HEADER_LEN 13 -#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) +#if !defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) #define MBEDTLS_SSL_IN_BUFFER_LEN \ ( ( MBEDTLS_SSL_HEADER_LEN ) + ( MBEDTLS_SSL_IN_PAYLOAD_LEN ) ) #else @@ -269,7 +269,7 @@ + ( MBEDTLS_SSL_CID_IN_LEN_MAX ) ) #endif -#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) +#if !defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) #define MBEDTLS_SSL_OUT_BUFFER_LEN \ ( ( MBEDTLS_SSL_HEADER_LEN ) + ( MBEDTLS_SSL_OUT_PAYLOAD_LEN ) ) #else @@ -278,6 +278,32 @@ + ( MBEDTLS_SSL_CID_OUT_LEN_MAX ) ) #endif +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) +static inline uint32_t mbedtls_ssl_get_output_buflen( const mbedtls_ssl_context *ctx ) +{ +#if defined (MBEDTLS_SSL_DTLS_CONNECTION_ID) + return (uint32_t) mbedtls_ssl_get_output_max_frag_len( ctx ) + + MBEDTLS_SSL_HEADER_LEN + MBEDTLS_SSL_PAYLOAD_OVERHEAD + + MBEDTLS_SSL_CID_OUT_LEN_MAX; +#else + return (uint32_t) mbedtls_ssl_get_output_max_frag_len( ctx ) + + MBEDTLS_SSL_HEADER_LEN + MBEDTLS_SSL_PAYLOAD_OVERHEAD; +#endif +} + +static inline uint32_t mbedtls_ssl_get_input_buflen( const mbedtls_ssl_context *ctx ) +{ +#if defined (MBEDTLS_SSL_DTLS_CONNECTION_ID) + return (uint32_t) mbedtls_ssl_get_input_max_frag_len( ctx ) + + MBEDTLS_SSL_HEADER_LEN + MBEDTLS_SSL_PAYLOAD_OVERHEAD + + MBEDTLS_SSL_CID_IN_LEN_MAX; +#else + return (uint32_t) mbedtls_ssl_get_input_max_frag_len( ctx ) + + MBEDTLS_SSL_HEADER_LEN + MBEDTLS_SSL_PAYLOAD_OVERHEAD; +#endif +} +#endif + #ifdef MBEDTLS_ZLIB_SUPPORT /* Compression buffer holds both IN and OUT buffers, so should be size of the larger */ #define MBEDTLS_SSL_COMPRESS_BUFFER_LEN ( \ diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 7dfc0afb3..8a014ced3 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -432,11 +432,16 @@ static size_t ssl_get_current_mtu( const mbedtls_ssl_context *ssl ); static size_t ssl_get_maximum_datagram_size( mbedtls_ssl_context const *ssl ) { size_t mtu = ssl_get_current_mtu( ssl ); +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + size_t out_buf_len = ssl->out_buf_len; +#else + size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN; +#endif - if( mtu != 0 && mtu < MBEDTLS_SSL_OUT_BUFFER_LEN ) + if( mtu != 0 && mtu < out_buf_len ) return( mtu ); - return( MBEDTLS_SSL_OUT_BUFFER_LEN ); + return( out_buf_len ); } static int ssl_get_remaining_space_in_datagram( mbedtls_ssl_context const *ssl ) @@ -462,7 +467,7 @@ static int ssl_get_remaining_payload_in_datagram( mbedtls_ssl_context const *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 ); + const size_t mfl = mbedtls_ssl_get_output_max_frag_len( ssl ); if( max_len > mfl ) max_len = mfl; @@ -640,6 +645,29 @@ int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst, return( 0 ); } +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) +static int resize_buffer( unsigned char **buffer, size_t len_new, size_t *len_old ) +{ + unsigned char* resized_buffer = mbedtls_calloc( 1, len_new ); + if( resized_buffer == NULL ) + return -1; + + /* We want to copy len_new bytes when downsizing the buffer, and + * len_old bytes when upsizing, so we choose the smaller of two sizes, + * to fit one buffer into another. Size checks, ensuring that no data is + * lost, are done outside of this function. */ + memcpy( resized_buffer, *buffer, + ( len_new < *len_old ) ? len_new : *len_old ); + mbedtls_platform_zeroize( *buffer, *len_old ); + mbedtls_free( *buffer ); + + *buffer = resized_buffer; + *len_old = len_new; + + return 0; +} +#endif /* MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH */ + #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) int (*mbedtls_ssl_hw_record_init)( mbedtls_ssl_context *ssl, const unsigned char *key_enc, const unsigned char *key_dec, @@ -3810,6 +3838,11 @@ static int ssl_compress_buf( mbedtls_ssl_context *ssl ) ptrdiff_t bytes_written = ssl->out_msg - ssl->out_buf; size_t len_pre = ssl->out_msglen; unsigned char *msg_pre = ssl->compress_buf; +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + size_t out_buf_len = ssl->out_buf_len; +#else + size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN; +#endif MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> compress buf" ) ); @@ -3827,7 +3860,7 @@ static int ssl_compress_buf( mbedtls_ssl_context *ssl ) ssl->transform_out->ctx_deflate.next_in = msg_pre; ssl->transform_out->ctx_deflate.avail_in = len_pre; ssl->transform_out->ctx_deflate.next_out = msg_post; - ssl->transform_out->ctx_deflate.avail_out = MBEDTLS_SSL_OUT_BUFFER_LEN - bytes_written; + ssl->transform_out->ctx_deflate.avail_out = out_buf_len - bytes_written; ret = deflate( &ssl->transform_out->ctx_deflate, Z_SYNC_FLUSH ); if( ret != Z_OK ) @@ -3836,7 +3869,7 @@ static int ssl_compress_buf( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED ); } - ssl->out_msglen = MBEDTLS_SSL_OUT_BUFFER_LEN - + ssl->out_msglen = out_buf_len - ssl->transform_out->ctx_deflate.avail_out - bytes_written; MBEDTLS_SSL_DEBUG_MSG( 3, ( "after compression: msglen = %d, ", @@ -3857,6 +3890,11 @@ static int ssl_decompress_buf( mbedtls_ssl_context *ssl ) ptrdiff_t header_bytes = ssl->in_msg - ssl->in_buf; size_t len_pre = ssl->in_msglen; unsigned char *msg_pre = ssl->compress_buf; +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + size_t in_buf_len = ssl->in_buf_len; +#else + size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN; +#endif MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> decompress buf" ) ); @@ -3874,7 +3912,7 @@ static int ssl_decompress_buf( mbedtls_ssl_context *ssl ) ssl->transform_in->ctx_inflate.next_in = msg_pre; ssl->transform_in->ctx_inflate.avail_in = len_pre; ssl->transform_in->ctx_inflate.next_out = msg_post; - ssl->transform_in->ctx_inflate.avail_out = MBEDTLS_SSL_IN_BUFFER_LEN - + ssl->transform_in->ctx_inflate.avail_out = in_buf_len - header_bytes; ret = inflate( &ssl->transform_in->ctx_inflate, Z_SYNC_FLUSH ); @@ -3884,7 +3922,7 @@ static int ssl_decompress_buf( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED ); } - ssl->in_msglen = MBEDTLS_SSL_IN_BUFFER_LEN - + ssl->in_msglen = in_buf_len - ssl->transform_in->ctx_inflate.avail_out - header_bytes; MBEDTLS_SSL_DEBUG_MSG( 3, ( "after decompression: msglen = %d, ", @@ -3951,6 +3989,11 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ) { int ret; size_t len; +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + size_t in_buf_len = ssl->in_buf_len; +#else + size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN; +#endif MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> fetch input" ) ); @@ -3962,7 +4005,7 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ) return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); } - if( nb_want > MBEDTLS_SSL_IN_BUFFER_LEN - (size_t)( ssl->in_hdr - ssl->in_buf ) ) + if( nb_want > in_buf_len - (size_t)( ssl->in_hdr - ssl->in_buf ) ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "requesting more data than fits" ) ); return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); @@ -4049,7 +4092,7 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ) } else { - len = MBEDTLS_SSL_IN_BUFFER_LEN - ( ssl->in_hdr - ssl->in_buf ); + len = in_buf_len - ( ssl->in_hdr - ssl->in_buf ); if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) timeout = ssl->handshake->retransmit_timeout; @@ -4821,6 +4864,11 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush ) unsigned i; size_t protected_record_size; volatile int encrypted_fi = 0; +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + size_t out_buf_len = ssl->out_buf_len; +#else + size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN; +#endif /* Skip writing the record content type to after the encryption, * as it may change when using the CID extension. */ @@ -4837,8 +4885,7 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush ) mbedtls_record rec; rec.buf = ssl->out_iv; - rec.buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN - - ( ssl->out_iv - ssl->out_buf ); + rec.buf_len = out_buf_len - ( ssl->out_iv - ssl->out_buf ); rec.data_len = ssl->out_msglen; rec.data_offset = ssl->out_msg - rec.buf; @@ -6563,6 +6610,11 @@ static int ssl_load_buffered_record( mbedtls_ssl_context *ssl ) unsigned char * rec; size_t rec_len; unsigned rec_epoch; +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + size_t in_buf_len = ssl->in_buf_len; +#else + size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN; +#endif if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) ) return( 0 ); @@ -6593,8 +6645,7 @@ static int ssl_load_buffered_record( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "Found buffered record from current epoch - load" ) ); /* Double-check that the record is not too large */ - if( rec_len > MBEDTLS_SSL_IN_BUFFER_LEN - - (size_t)( ssl->in_hdr - ssl->in_buf ) ) + if( rec_len > in_buf_len - (size_t)( ssl->in_hdr - ssl->in_buf ) ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); @@ -8761,6 +8812,66 @@ static int ssl_handshake_init( mbedtls_ssl_context *ssl ) ssl->handshake = mbedtls_calloc( 1, sizeof(mbedtls_ssl_handshake_params) ); } +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + /* If the buffers are too small - reallocate */ + { + int modified = 0; + size_t written_in = 0, len_offset_in = 0; + size_t written_out = 0, iv_offset_out = 0, len_offset_out = 0; + if( ssl->in_buf != NULL ) + { + written_in = ssl->in_msg - ssl->in_buf; + len_offset_in = ssl->in_len - ssl->in_buf; + if( ssl->in_buf_len < MBEDTLS_SSL_IN_BUFFER_LEN ) + { + if( resize_buffer( &ssl->in_buf, MBEDTLS_SSL_IN_BUFFER_LEN, + &ssl->in_buf_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "input buffer resizing failed - out of memory" ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Reallocating in_buf to %d", MBEDTLS_SSL_IN_BUFFER_LEN ) ); + modified = 1; + } + } + } + + if( ssl->out_buf != NULL ) + { + written_out = ssl->out_msg - ssl->out_buf; + iv_offset_out = ssl->out_iv - ssl->out_buf; + len_offset_out = ssl->out_len - ssl->out_buf; + if( ssl->out_buf_len < MBEDTLS_SSL_OUT_BUFFER_LEN ) + { + if( resize_buffer( &ssl->out_buf, MBEDTLS_SSL_OUT_BUFFER_LEN, + &ssl->out_buf_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "output buffer resizing failed - out of memory" ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Reallocating out_buf to %d", MBEDTLS_SSL_OUT_BUFFER_LEN ) ); + modified = 1; + } + } + } + if( modified ) + { + /* Update pointers here to avoid doing it twice. */ + ssl_reset_in_out_pointers( ssl ); + /* Fields below might not be properly updated with record + * splitting or with CID, so they are manually updated here. */ + ssl->out_msg = ssl->out_buf + written_out; + ssl->out_len = ssl->out_buf + len_offset_out; + ssl->out_iv = ssl->out_buf + iv_offset_out; + + ssl->in_msg = ssl->in_buf + written_in; + ssl->in_len = ssl->in_buf + len_offset_in; + } + } +#endif + /* All pointers should exist and can be directly freed without issue */ if( ssl->handshake == NULL || ssl->transform_negotiate == NULL || @@ -8966,6 +9077,8 @@ int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, const mbedtls_ssl_config *conf ) { int ret; + size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN; + size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN; ssl->conf = conf; @@ -8980,18 +9093,25 @@ int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, /* Set to NULL in case of an error condition */ ssl->out_buf = NULL; - ssl->in_buf = mbedtls_calloc( 1, MBEDTLS_SSL_IN_BUFFER_LEN ); +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + ssl->in_buf_len = in_buf_len; +#endif + ssl->in_buf = mbedtls_calloc( 1, in_buf_len ); if( ssl->in_buf == NULL ) { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", MBEDTLS_SSL_IN_BUFFER_LEN) ); + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", in_buf_len) ); ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; goto error; } - ssl->out_buf = mbedtls_calloc( 1, MBEDTLS_SSL_OUT_BUFFER_LEN ); +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + ssl->out_buf_len = out_buf_len; +#endif + + ssl->out_buf = mbedtls_calloc( 1, out_buf_len ); if( ssl->out_buf == NULL ) { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", MBEDTLS_SSL_OUT_BUFFER_LEN) ); + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", out_buf_len) ); ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; goto error; } @@ -9011,6 +9131,11 @@ error: ssl->conf = NULL; +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + ssl->in_buf_len = 0; + ssl->out_buf_len = 0; +#endif + ssl->in_buf = NULL; ssl->out_buf = NULL; @@ -9038,6 +9163,13 @@ error: static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) { int ret; +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + size_t in_buf_len = ssl->in_buf_len; + size_t out_buf_len = ssl->out_buf_len; +#else + size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN; + size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN; +#endif #if !defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) || \ !defined(MBEDTLS_SSL_SRV_C) @@ -9093,14 +9225,14 @@ static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) ssl->session_in = NULL; ssl->session_out = NULL; - mbedtls_platform_memset( ssl->out_buf, 0, MBEDTLS_SSL_OUT_BUFFER_LEN ); + mbedtls_platform_memset( ssl->out_buf, 0, out_buf_len ); #if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C) if( partial == 0 ) #endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */ { ssl->in_left = 0; - mbedtls_platform_memset( ssl->in_buf, 0, MBEDTLS_SSL_IN_BUFFER_LEN ); + mbedtls_platform_memset( ssl->in_buf, 0, in_buf_len ); } #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) @@ -10167,7 +10299,42 @@ int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl ) } #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) -size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl ) +size_t mbedtls_ssl_get_input_max_frag_len( const mbedtls_ssl_context *ssl ) +{ + size_t max_len = MBEDTLS_SSL_MAX_CONTENT_LEN; + size_t read_mfl; + + /* Use the configured MFL for the client if we're past SERVER_HELLO_DONE */ + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && + ssl->state >= MBEDTLS_SSL_SERVER_HELLO_DONE ) + { + return ssl_mfl_code_to_length( ssl->conf->mfl_code ); + } + + /* Check if a smaller max length was negotiated */ + if( ssl->session_out != NULL ) + { + read_mfl = ssl_mfl_code_to_length( ssl->session_out->mfl_code ); + if( read_mfl < max_len ) + { + max_len = read_mfl; + } + } + + // During a handshake, use the value being negotiated + if( ssl->session_negotiate != NULL ) + { + read_mfl = ssl_mfl_code_to_length( ssl->session_negotiate->mfl_code ); + if( read_mfl < max_len ) + { + max_len = read_mfl; + } + } + + return( max_len ); +} + +size_t mbedtls_ssl_get_output_max_frag_len( const mbedtls_ssl_context *ssl ) { size_t max_len; @@ -10192,6 +10359,13 @@ size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl ) return( max_len ); } + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl ) +{ + return mbedtls_ssl_get_output_max_frag_len( ssl ); +} +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ #if defined(MBEDTLS_SSL_PROTO_DTLS) @@ -10224,7 +10398,7 @@ int mbedtls_ssl_get_max_out_record_payload( const mbedtls_ssl_context *ssl ) #endif #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) - const size_t mfl = mbedtls_ssl_get_max_frag_len( ssl ); + const size_t mfl = mbedtls_ssl_get_output_max_frag_len( ssl ); if( max_len > mfl ) max_len = mfl; @@ -11880,6 +12054,71 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ) mbedtls_platform_zeroize( handshake, sizeof( mbedtls_ssl_handshake_params ) ); + +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + /* If the buffers are too big - reallocate. Because of the way Mbed TLS + * processes datagrams and the fact that a datagram is allowed to have + * several records in it, it is possible that the I/O buffers are not + * empty at this stage */ + { + int modified = 0; + uint32_t buf_len = mbedtls_ssl_get_input_buflen( ssl ); + size_t written_in = 0, len_offset_in = 0; + size_t written_out = 0, iv_offset_out = 0, len_offset_out = 0; + if( ssl->in_buf != NULL ) + { + written_in = ssl->in_msg - ssl->in_buf; + len_offset_in = ssl->in_len - ssl->in_buf; + if( ssl->in_buf_len > buf_len && ssl->in_left < buf_len ) + { + if( resize_buffer( &ssl->in_buf, buf_len, &ssl->in_buf_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "input buffer resizing failed - out of memory" ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Reallocating in_buf to %d", buf_len ) ); + modified = 1; + } + } + } + + + buf_len = mbedtls_ssl_get_output_buflen( ssl ); + if( ssl->out_buf != NULL ) + { + written_out = ssl->out_msg - ssl->out_buf; + iv_offset_out = ssl->out_iv - ssl->out_buf; + len_offset_out = ssl->out_len - ssl->out_buf; + if( ssl->out_buf_len > mbedtls_ssl_get_output_buflen( ssl ) && + ssl->out_left < buf_len ) + { + if( resize_buffer( &ssl->out_buf, buf_len, &ssl->out_buf_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "output buffer resizing failed - out of memory" ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Reallocating out_buf to %d", buf_len ) ); + modified = 1; + } + } + } + if( modified ) + { + /* Update pointers here to avoid doing it twice. */ + ssl_reset_in_out_pointers( ssl ); + /* Fields below might not be properly updated with record + * splitting or with CID, so they are manually updated here. */ + ssl->out_msg = ssl->out_buf + written_out; + ssl->out_len = ssl->out_buf + len_offset_out; + ssl->out_iv = ssl->out_buf + iv_offset_out; + + ssl->in_msg = ssl->in_buf + written_in; + ssl->in_len = ssl->in_buf + len_offset_in; + } + } +#endif } void mbedtls_ssl_session_free( mbedtls_ssl_session *session ) @@ -12495,13 +12734,23 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl ) if( ssl->out_buf != NULL ) { - mbedtls_platform_zeroize( ssl->out_buf, MBEDTLS_SSL_OUT_BUFFER_LEN ); +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + size_t out_buf_len = ssl->out_buf_len; +#else + size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN; +#endif + mbedtls_platform_zeroize( ssl->out_buf, out_buf_len ); mbedtls_free( ssl->out_buf ); } if( ssl->in_buf != NULL ) { - mbedtls_platform_zeroize( ssl->in_buf, MBEDTLS_SSL_IN_BUFFER_LEN ); +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + size_t in_buf_len = ssl->in_buf_len; +#else + size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN; +#endif + mbedtls_platform_zeroize( ssl->in_buf, in_buf_len ); mbedtls_free( ssl->in_buf ); } diff --git a/library/version_features.c b/library/version_features.c index 1a226c872..b0e16375d 100644 --- a/library/version_features.c +++ b/library/version_features.c @@ -555,6 +555,9 @@ static const char *features[] = { #if defined(MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT) "MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT", #endif /* MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT */ +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + "MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH", +#endif /* MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH */ #if defined(MBEDTLS_THREADING_ALT) "MBEDTLS_THREADING_ALT", #endif /* MBEDTLS_THREADING_ALT */ diff --git a/programs/ssl/query_config.c b/programs/ssl/query_config.c index ba4b59650..21800bb78 100644 --- a/programs/ssl/query_config.c +++ b/programs/ssl/query_config.c @@ -1522,6 +1522,14 @@ int query_config( const char *config ) } #endif /* MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT */ +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + if( strcmp( "MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH", config ) == 0 ) + { + MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH ); + return( 0 ); + } +#endif /* MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH */ + #if defined(MBEDTLS_THREADING_ALT) if( strcmp( "MBEDTLS_THREADING_ALT", config ) == 0 ) { diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 3bf9e6243..f6907f2b9 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -2332,8 +2332,10 @@ int main( int argc, char *argv[] ) mbedtls_printf( " [ Record expansion is unknown (compression) ]\n" ); #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) - mbedtls_printf( " [ Maximum fragment length is %u ]\n", - (unsigned int) mbedtls_ssl_get_max_frag_len( ssl ) ); + mbedtls_printf( " [ Maximum input fragment length is %u ]\n", + (unsigned int) mbedtls_ssl_get_input_max_frag_len( ssl ) ); + mbedtls_printf( " [ Maximum output fragment length is %u ]\n", + (unsigned int) mbedtls_ssl_get_output_max_frag_len( ssl ) ); #endif #if defined(MBEDTLS_SSL_ALPN) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index bf10987df..52c4742cc 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -2312,7 +2312,10 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) mbedtls_memory_buffer_alloc_init( alloc_buf, sizeof(alloc_buf) ); -#endif +#if defined(MBEDTLS_MEMORY_DEBUG) + size_t current_heap_memory, peak_heap_memory, heap_blocks; +#endif /* MBEDTLS_MEMORY_DEBUG */ +#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */ ssl = mbedtls_calloc( 1, sizeof( *ssl ) ); conf = mbedtls_calloc( 1, sizeof( *conf ) ); @@ -3420,8 +3423,10 @@ handshake: mbedtls_printf( " [ Record expansion is unknown (compression) ]\n" ); #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) - mbedtls_printf( " [ Maximum fragment length is %u ]\n", - (unsigned int) mbedtls_ssl_get_max_frag_len( ssl ) ); + mbedtls_printf( " [ Maximum input fragment length is %u ]\n", + (unsigned int) mbedtls_ssl_get_input_max_frag_len( ssl ) ); + mbedtls_printf( " [ Maximum output fragment length is %u ]\n", + (unsigned int) mbedtls_ssl_get_output_max_frag_len( ssl ) ); #endif #if defined(MBEDTLS_SSL_ALPN) @@ -3486,6 +3491,13 @@ handshake: } #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_memory_buffer_alloc_cur_get( ¤t_heap_memory, &heap_blocks ); + mbedtls_memory_buffer_alloc_max_get( &peak_heap_memory, &heap_blocks ); + mbedtls_printf( "Heap memory usage after handshake: %lu bytes. Peak memory usage was %lu\n", + (unsigned long) current_heap_memory, (unsigned long) peak_heap_memory ); +#endif /* MBEDTLS_MEMORY_DEBUG */ + if( opt.exchanges == 0 ) goto close_notify; diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh index 7ae142502..a8747c2a0 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -1276,6 +1276,75 @@ component_test_no_max_fragment_length_small_ssl_out_content_len () { if_build_succeeded tests/ssl-opt.sh -f "Max fragment length\|Large buffer" } +component_test_variable_ssl_in_out_buffer_len () { + msg "build: MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH enabled (ASan build)" + scripts/config.pl set MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH + CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan . + make + + msg "test: MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH enabled" + make test + + msg "test: ssl-opt.sh, MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH enabled" + if_build_succeeded tests/ssl-opt.sh + + msg "test: compat.sh, MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH enabled" + if_build_succeeded tests/compat.sh +} + +component_test_variable_ssl_in_out_buffer_len_CID () { + msg "build: MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH and MBEDTLS_SSL_DTLS_CONNECTION_ID enabled (ASan build)" + scripts/config.pl set MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH + scripts/config.pl set MBEDTLS_SSL_DTLS_CONNECTION_ID + + CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan . + make + + msg "test: MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH and MBEDTLS_SSL_DTLS_CONNECTION_ID" + make test + + msg "test: ssl-opt.sh, MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH and MBEDTLS_SSL_DTLS_CONNECTION_ID enabled" + if_build_succeeded tests/ssl-opt.sh + + msg "test: compat.sh, MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH and MBEDTLS_SSL_DTLS_CONNECTION_ID enabled" + if_build_succeeded tests/compat.sh +} + +component_test_variable_ssl_in_out_buffer_len_record_splitting () { + msg "build: MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH and MBEDTLS_SSL_CBC_RECORD_SPLITTING enabled (ASan build)" + scripts/config.pl set MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH + scripts/config.pl set MBEDTLS_SSL_CBC_RECORD_SPLITTING + + CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan . + make + + msg "test: MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH and MBEDTLS_SSL_CBC_RECORD_SPLITTING" + make test + + msg "test: ssl-opt.sh, MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH and MBEDTLS_SSL_CBC_RECORD_SPLITTING enabled" + if_build_succeeded tests/ssl-opt.sh + + msg "test: compat.sh, MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH and MBEDTLS_SSL_CBC_RECORD_SPLITTING enabled" + if_build_succeeded tests/compat.sh +} + +component_test_ssl_alloc_buffer_and_mfl () { + msg "build: default config with memory buffer allocator and MFL extension" + scripts/config.pl set MBEDTLS_MEMORY_BUFFER_ALLOC_C + scripts/config.pl set MBEDTLS_PLATFORM_MEMORY + scripts/config.pl set MBEDTLS_MEMORY_DEBUG + scripts/config.pl set MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + scripts/config.pl set MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH + CC=gcc cmake . + make + + msg "test: MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH, MBEDTLS_MEMORY_BUFFER_ALLOC_C, MBEDTLS_MEMORY_DEBUG and MBEDTLS_SSL_MAX_FRAGMENT_LENGTH" + make test + + msg "test: MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH, MBEDTLS_MEMORY_BUFFER_ALLOC_C, MBEDTLS_MEMORY_DEBUG and MBEDTLS_SSL_MAX_FRAGMENT_LENGTH" + if_build_succeeded tests/ssl-opt.sh -f "Handshake memory usage" +} + component_test_when_no_ciphersuites_have_mac () { msg "build: when no ciphersuites have MAC" scripts/config.pl unset MBEDTLS_CIPHER_NULL_CIPHER diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index b2113103e..81ea9e1f6 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -153,7 +153,7 @@ skip_next_test() { } requires_ciphersuite_enabled() { - if [ -z "$($P_CLI --help | grep "$1")" ]; then + if [ -z "$($P_CLI --help 2>/dev/null | grep $1)" ]; then SKIP_NEXT="YES" fi } @@ -510,6 +510,45 @@ check_server_hello_time() { fi } +# Get handshake memory usage from server or client output and put it into the variable specified by the first argument +handshake_memory_get() { + OUTPUT_VARIABLE="$1" + OUTPUT_FILE="$2" + + # Get memory usage from a pattern like "Heap memory usage after handshake: 23112 bytes. Peak memory usage was 33112" + MEM_USAGE=$(sed -n 's/.*Heap memory usage after handshake: //p' < "$OUTPUT_FILE" | grep -o "[0-9]*" | head -1) + + # Check if memory usage was read + if [ -z "$MEM_USAGE" ]; then + echo "Error: Can not read the value of handshake memory usage" + return 1 + else + eval "$OUTPUT_VARIABLE=$MEM_USAGE" + return 0 + fi +} + +# Get handshake memory usage from server or client output and check if this value +# is not higher than the maximum given by the first argument +handshake_memory_check() { + MAX_MEMORY="$1" + OUTPUT_FILE="$2" + + # Get memory usage + if ! handshake_memory_get "MEMORY_USAGE" "$OUTPUT_FILE"; then + return 1 + fi + + # Check if memory usage is below max value + if [ "$MEMORY_USAGE" -gt "$MAX_MEMORY" ]; then + echo "\nFailed: Handshake memory usage was $MEMORY_USAGE bytes," \ + "but should be below $MAX_MEMORY bytes" + return 1 + else + return 0 + fi +} + # wait for client to terminate and set CLI_EXIT # must be called right after starting the client wait_client_done() { @@ -999,6 +1038,58 @@ run_test() { rm -f $SRV_OUT $CLI_OUT $PXY_OUT } +# Test that the server's memory usage after a handshake is reduced when a client specifies +# a maximum fragment length. +# first argument ($1) is MFL for SSL client +# second argument ($2) is memory usage for SSL client with default MFL (16k) +run_test_memory_after_hanshake_with_mfl() +{ + # The test passes if the difference is around 2*(16k-MFL) + local MEMORY_USAGE_LIMIT="$(( $2 - ( 2 * ( 16384 - $1 )) ))" + + # Leave some margin for robustness + MEMORY_USAGE_LIMIT="$(( ( MEMORY_USAGE_LIMIT * 110 ) / 100 ))" + + run_test "Handshake memory usage (MFL $1)" \ + "$P_SRV debug_level=3 auth_mode=required force_version=tls1_2" \ + "$P_CLI debug_level=3 force_version=tls1_2 \ + crt_file=data_files/server5.crt key_file=data_files/server5.key \ + force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM max_frag_len=$1" \ + 0 \ + -F "handshake_memory_check $MEMORY_USAGE_LIMIT" +} + + +# Test that the server's memory usage after a handshake is reduced when a client specifies +# different values of Maximum Fragment Length: default (16k), 4k, 2k, 1k and 512 bytes +run_tests_memory_after_hanshake() +{ + # all tests in this sequence requires the same configuration (see requires_config_enabled()) + SKIP_THIS_TESTS="$SKIP_NEXT" + + # first test with default MFU is to get reference memory usage + MEMORY_USAGE_MFL_16K=0 + run_test "Handshake memory usage initial (MFL 16384 - default)" \ + "$P_SRV debug_level=3 auth_mode=required force_version=tls1_2" \ + "$P_CLI debug_level=3 force_version=tls1_2 \ + crt_file=data_files/server5.crt key_file=data_files/server5.key \ + force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM" \ + 0 \ + -F "handshake_memory_get MEMORY_USAGE_MFL_16K" + + SKIP_NEXT="$SKIP_THIS_TESTS" + run_test_memory_after_hanshake_with_mfl 4096 "$MEMORY_USAGE_MFL_16K" + + SKIP_NEXT="$SKIP_THIS_TESTS" + run_test_memory_after_hanshake_with_mfl 2048 "$MEMORY_USAGE_MFL_16K" + + SKIP_NEXT="$SKIP_THIS_TESTS" + run_test_memory_after_hanshake_with_mfl 1024 "$MEMORY_USAGE_MFL_16K" + + SKIP_NEXT="$SKIP_THIS_TESTS" + run_test_memory_after_hanshake_with_mfl 512 "$MEMORY_USAGE_MFL_16K" +} + cleanup() { rm -f $CLI_OUT $SRV_OUT $PXY_OUT $SESSION test -n "${SRV_PID:-}" && kill $SRV_PID >/dev/null 2>&1 @@ -2176,6 +2267,32 @@ run_test "Connection ID, 3D: Cli+Srv enabled, Srv disables on renegotiation" -c "ignoring unexpected CID" \ -s "ignoring unexpected CID" +requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_enabled MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH +run_test "Connection ID: Cli+Srv enabled, variable buffer lengths, MFL=512" \ + "$P_SRV dtls=1 cid=1 cid_val=dead debug_level=2" \ + "$P_CLI force_ciphersuite="TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" max_frag_len=512 dtls=1 cid=1 cid_val=beef" \ + 0 \ + -c "(initial handshake) Peer CID (length 2 Bytes): de ad" \ + -s "(initial handshake) Peer CID (length 2 Bytes): be ef" \ + -s "(initial handshake) Use of Connection ID has been negotiated" \ + -c "(initial handshake) Use of Connection ID has been negotiated" \ + -s "Reallocating in_buf" \ + -s "Reallocating out_buf" + +requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_enabled MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH +run_test "Connection ID: Cli+Srv enabled, variable buffer lengths, MFL=1024" \ + "$P_SRV dtls=1 cid=1 cid_val=dead debug_level=2" \ + "$P_CLI force_ciphersuite="TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" max_frag_len=1024 dtls=1 cid=1 cid_val=beef" \ + 0 \ + -c "(initial handshake) Peer CID (length 2 Bytes): de ad" \ + -s "(initial handshake) Peer CID (length 2 Bytes): be ef" \ + -s "(initial handshake) Use of Connection ID has been negotiated" \ + -c "(initial handshake) Use of Connection ID has been negotiated" \ + -s "Reallocating in_buf" \ + -s "Reallocating out_buf" + # Tests for Encrypt-then-MAC extension run_test "Encrypt then MAC: default" \ @@ -3047,14 +3164,15 @@ run_test "Session resume using cache, DTLS: openssl server" \ if [ $MAX_CONTENT_LEN -ne 16384 ]; then printf "Using non-default maximum content length $MAX_CONTENT_LEN\n" fi - requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH run_test "Max fragment length: enabled, default" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3" \ 0 \ - -c "Maximum fragment length is $MAX_CONTENT_LEN" \ - -s "Maximum fragment length is $MAX_CONTENT_LEN" \ + -c "Maximum input fragment length is $MAX_CONTENT_LEN" \ + -c "Maximum output fragment length is $MAX_CONTENT_LEN" \ + -s "Maximum input fragment length is $MAX_CONTENT_LEN" \ + -s "Maximum output fragment length is $MAX_CONTENT_LEN" \ -C "client hello, adding max_fragment_length extension" \ -S "found max fragment length extension" \ -S "server hello, max_fragment_length extension" \ @@ -3065,8 +3183,10 @@ run_test "Max fragment length: enabled, default, larger message" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 request_size=$(( $MAX_CONTENT_LEN + 1))" \ 0 \ - -c "Maximum fragment length is $MAX_CONTENT_LEN" \ - -s "Maximum fragment length is $MAX_CONTENT_LEN" \ + -c "Maximum input fragment length is $MAX_CONTENT_LEN" \ + -c "Maximum output fragment length is $MAX_CONTENT_LEN" \ + -s "Maximum input fragment length is $MAX_CONTENT_LEN" \ + -s "Maximum output fragment length is $MAX_CONTENT_LEN" \ -C "client hello, adding max_fragment_length extension" \ -S "found max fragment length extension" \ -S "server hello, max_fragment_length extension" \ @@ -3076,13 +3196,14 @@ run_test "Max fragment length: enabled, default, larger message" \ -s "1 bytes read" requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH -requires_config_value_at_least "MBEDTLS_SSL_MAX_CONTENT_LEN" 4096 run_test "Max fragment length, DTLS: enabled, default, larger message" \ "$P_SRV debug_level=3 dtls=1" \ "$P_CLI debug_level=3 dtls=1 request_size=$(( $MAX_CONTENT_LEN + 1))" \ 1 \ - -c "Maximum fragment length is $MAX_CONTENT_LEN" \ - -s "Maximum fragment length is $MAX_CONTENT_LEN" \ + -c "Maximum input fragment length is $MAX_CONTENT_LEN" \ + -c "Maximum output fragment length is $MAX_CONTENT_LEN" \ + -s "Maximum input fragment length is $MAX_CONTENT_LEN" \ + -s "Maximum output fragment length is $MAX_CONTENT_LEN" \ -C "client hello, adding max_fragment_length extension" \ -S "found max fragment length extension" \ -S "server hello, max_fragment_length extension" \ @@ -3094,72 +3215,245 @@ run_test "Max fragment length, DTLS: enabled, default, larger message" \ # content length configuration.) requires_config_disabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH -requires_config_value_at_least "MBEDTLS_SSL_MAX_CONTENT_LEN" 16384 run_test "Max fragment length: disabled, larger message" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 request_size=$(( $MAX_CONTENT_LEN + 1))" \ 0 \ - -C "Maximum fragment length is 16384" \ - -S "Maximum fragment length is 16384" \ + -C "Maximum input fragment length is 16384" \ + -C "Maximum output fragment length is 16384" \ + -S "Maximum input fragment length is 16384" \ + -S "Maximum output fragment length is 16384" \ -c "$(( $MAX_CONTENT_LEN + 1)) bytes written in 2 fragments" \ -s "$MAX_CONTENT_LEN bytes read" \ -s "1 bytes read" requires_config_disabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH -requires_config_value_at_least "MBEDTLS_SSL_MAX_CONTENT_LEN" 16384 run_test "Max fragment length DTLS: disabled, larger message" \ "$P_SRV debug_level=3 dtls=1" \ "$P_CLI debug_level=3 dtls=1 request_size=$(( $MAX_CONTENT_LEN + 1))" \ 1 \ - -C "Maximum fragment length is 16384" \ - -S "Maximum fragment length is 16384" \ + -C "Maximum input fragment length is 16384" \ + -C "Maximum output fragment length is 16384" \ + -S "Maximum input fragment length is 16384" \ + -S "Maximum output fragment length is 16384" \ -c "fragment larger than.*maximum " requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH -requires_config_value_at_least "MBEDTLS_SSL_MAX_CONTENT_LEN" 4096 run_test "Max fragment length: used by client" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 max_frag_len=4096" \ 0 \ - -c "Maximum fragment length is 4096" \ - -s "Maximum fragment length is 4096" \ + -c "Maximum input fragment length is 4096" \ + -c "Maximum output fragment length is 4096" \ + -s "Maximum input fragment length is 4096" \ + -s "Maximum output fragment length is 4096" \ + -c "client hello, adding max_fragment_length extension" \ + -s "found max fragment length extension" \ + -s "server hello, max_fragment_length extension" \ + -c "found max_fragment_length extension" + +requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +run_test "Max fragment length: client 512, server 1024" \ + "$P_SRV debug_level=3 max_frag_len=1024" \ + "$P_CLI debug_level=3 max_frag_len=512" \ + 0 \ + -c "Maximum input fragment length is 512" \ + -c "Maximum output fragment length is 512" \ + -s "Maximum input fragment length is 512" \ + -s "Maximum output fragment length is 512" \ + -c "client hello, adding max_fragment_length extension" \ + -s "found max fragment length extension" \ + -s "server hello, max_fragment_length extension" \ + -c "found max_fragment_length extension" + +requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +run_test "Max fragment length: client 512, server 2048" \ + "$P_SRV debug_level=3 max_frag_len=2048" \ + "$P_CLI debug_level=3 max_frag_len=512" \ + 0 \ + -c "Maximum input fragment length is 512" \ + -c "Maximum output fragment length is 512" \ + -s "Maximum input fragment length is 512" \ + -s "Maximum output fragment length is 512" \ + -c "client hello, adding max_fragment_length extension" \ + -s "found max fragment length extension" \ + -s "server hello, max_fragment_length extension" \ + -c "found max_fragment_length extension" + +requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +run_test "Max fragment length: client 512, server 4096" \ + "$P_SRV debug_level=3 max_frag_len=4096" \ + "$P_CLI debug_level=3 max_frag_len=512" \ + 0 \ + -c "Maximum input fragment length is 512" \ + -c "Maximum output fragment length is 512" \ + -s "Maximum input fragment length is 512" \ + -s "Maximum output fragment length is 512" \ + -c "client hello, adding max_fragment_length extension" \ + -s "found max fragment length extension" \ + -s "server hello, max_fragment_length extension" \ + -c "found max_fragment_length extension" + +requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +run_test "Max fragment length: client 1024, server 512" \ + "$P_SRV debug_level=3 max_frag_len=512" \ + "$P_CLI debug_level=3 max_frag_len=1024" \ + 0 \ + -c "Maximum input fragment length is 1024" \ + -c "Maximum output fragment length is 1024" \ + -s "Maximum input fragment length is 1024" \ + -s "Maximum output fragment length is 512" \ + -c "client hello, adding max_fragment_length extension" \ + -s "found max fragment length extension" \ + -s "server hello, max_fragment_length extension" \ + -c "found max_fragment_length extension" + +requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +run_test "Max fragment length: client 1024, server 2048" \ + "$P_SRV debug_level=3 max_frag_len=2048" \ + "$P_CLI debug_level=3 max_frag_len=1024" \ + 0 \ + -c "Maximum input fragment length is 1024" \ + -c "Maximum output fragment length is 1024" \ + -s "Maximum input fragment length is 1024" \ + -s "Maximum output fragment length is 1024" \ + -c "client hello, adding max_fragment_length extension" \ + -s "found max fragment length extension" \ + -s "server hello, max_fragment_length extension" \ + -c "found max_fragment_length extension" + +requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +run_test "Max fragment length: client 1024, server 4096" \ + "$P_SRV debug_level=3 max_frag_len=4096" \ + "$P_CLI debug_level=3 max_frag_len=1024" \ + 0 \ + -c "Maximum input fragment length is 1024" \ + -c "Maximum output fragment length is 1024" \ + -s "Maximum input fragment length is 1024" \ + -s "Maximum output fragment length is 1024" \ + -c "client hello, adding max_fragment_length extension" \ + -s "found max fragment length extension" \ + -s "server hello, max_fragment_length extension" \ + -c "found max_fragment_length extension" + +requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +run_test "Max fragment length: client 2048, server 512" \ + "$P_SRV debug_level=3 max_frag_len=512" \ + "$P_CLI debug_level=3 max_frag_len=2048" \ + 0 \ + -c "Maximum input fragment length is 2048" \ + -c "Maximum output fragment length is 2048" \ + -s "Maximum input fragment length is 2048" \ + -s "Maximum output fragment length is 512" \ + -c "client hello, adding max_fragment_length extension" \ + -s "found max fragment length extension" \ + -s "server hello, max_fragment_length extension" \ + -c "found max_fragment_length extension" + +requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +run_test "Max fragment length: client 2048, server 1024" \ + "$P_SRV debug_level=3 max_frag_len=1024" \ + "$P_CLI debug_level=3 max_frag_len=2048" \ + 0 \ + -c "Maximum input fragment length is 2048" \ + -c "Maximum output fragment length is 2048" \ + -s "Maximum input fragment length is 2048" \ + -s "Maximum output fragment length is 1024" \ + -c "client hello, adding max_fragment_length extension" \ + -s "found max fragment length extension" \ + -s "server hello, max_fragment_length extension" \ + -c "found max_fragment_length extension" + +requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +run_test "Max fragment length: client 2048, server 4096" \ + "$P_SRV debug_level=3 max_frag_len=4096" \ + "$P_CLI debug_level=3 max_frag_len=2048" \ + 0 \ + -c "Maximum input fragment length is 2048" \ + -c "Maximum output fragment length is 2048" \ + -s "Maximum input fragment length is 2048" \ + -s "Maximum output fragment length is 2048" \ + -c "client hello, adding max_fragment_length extension" \ + -s "found max fragment length extension" \ + -s "server hello, max_fragment_length extension" \ + -c "found max_fragment_length extension" + +requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +run_test "Max fragment length: client 4096, server 512" \ + "$P_SRV debug_level=3 max_frag_len=512" \ + "$P_CLI debug_level=3 max_frag_len=4096" \ + 0 \ + -c "Maximum input fragment length is 4096" \ + -c "Maximum output fragment length is 4096" \ + -s "Maximum input fragment length is 4096" \ + -s "Maximum output fragment length is 512" \ + -c "client hello, adding max_fragment_length extension" \ + -s "found max fragment length extension" \ + -s "server hello, max_fragment_length extension" \ + -c "found max_fragment_length extension" + +requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +run_test "Max fragment length: client 4096, server 1024" \ + "$P_SRV debug_level=3 max_frag_len=1024" \ + "$P_CLI debug_level=3 max_frag_len=4096" \ + 0 \ + -c "Maximum input fragment length is 4096" \ + -c "Maximum output fragment length is 4096" \ + -s "Maximum input fragment length is 4096" \ + -s "Maximum output fragment length is 1024" \ + -c "client hello, adding max_fragment_length extension" \ + -s "found max fragment length extension" \ + -s "server hello, max_fragment_length extension" \ + -c "found max_fragment_length extension" + +requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +run_test "Max fragment length: client 4096, server 2048" \ + "$P_SRV debug_level=3 max_frag_len=2048" \ + "$P_CLI debug_level=3 max_frag_len=4096" \ + 0 \ + -c "Maximum input fragment length is 4096" \ + -c "Maximum output fragment length is 4096" \ + -s "Maximum input fragment length is 4096" \ + -s "Maximum output fragment length is 2048" \ -c "client hello, adding max_fragment_length extension" \ -s "found max fragment length extension" \ -s "server hello, max_fragment_length extension" \ -c "found max_fragment_length extension" requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH -requires_config_value_at_least "MBEDTLS_SSL_MAX_CONTENT_LEN" 4096 run_test "Max fragment length: used by server" \ "$P_SRV debug_level=3 max_frag_len=4096" \ "$P_CLI debug_level=3" \ 0 \ - -c "Maximum fragment length is $MAX_CONTENT_LEN" \ - -s "Maximum fragment length is 4096" \ + -c "Maximum input fragment length is $MAX_CONTENT_LEN" \ + -c "Maximum output fragment length is $MAX_CONTENT_LEN" \ + -s "Maximum input fragment length is $MAX_CONTENT_LEN" \ + -s "Maximum output fragment length is 4096" \ -C "client hello, adding max_fragment_length extension" \ -S "found max fragment length extension" \ -S "server hello, max_fragment_length extension" \ -C "found max_fragment_length extension" requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH -requires_config_value_at_least "MBEDTLS_SSL_MAX_CONTENT_LEN" 4096 requires_gnutls run_test "Max fragment length: gnutls server" \ "$G_SRV" \ - "$P_CLI debug_level=3 max_frag_len=4096 ca_file=data_files/test-ca2.crt" \ + "$P_CLI debug_level=3 max_frag_len=4096" \ 0 \ - -c "Maximum fragment length is 4096" \ + -c "Maximum input fragment length is 4096" \ + -c "Maximum output fragment length is 4096" \ -c "client hello, adding max_fragment_length extension" \ -c "found max_fragment_length extension" requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH -requires_config_value_at_least "MBEDTLS_SSL_MAX_CONTENT_LEN" 2048 run_test "Max fragment length: client, message just fits" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 max_frag_len=2048 request_size=2048" \ 0 \ - -c "Maximum fragment length is 2048" \ - -s "Maximum fragment length is 2048" \ + -c "Maximum input fragment length is 2048" \ + -c "Maximum output fragment length is 2048" \ + -s "Maximum input fragment length is 2048" \ + -s "Maximum output fragment length is 2048" \ -c "client hello, adding max_fragment_length extension" \ -s "found max fragment length extension" \ -s "server hello, max_fragment_length extension" \ @@ -3168,13 +3462,14 @@ run_test "Max fragment length: client, message just fits" \ -s "2048 bytes read" requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH -requires_config_value_at_least "MBEDTLS_SSL_MAX_CONTENT_LEN" 2048 run_test "Max fragment length: client, larger message" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 max_frag_len=2048 request_size=2345" \ 0 \ - -c "Maximum fragment length is 2048" \ - -s "Maximum fragment length is 2048" \ + -c "Maximum input fragment length is 2048" \ + -c "Maximum output fragment length is 2048" \ + -s "Maximum input fragment length is 2048" \ + -s "Maximum output fragment length is 2048" \ -c "client hello, adding max_fragment_length extension" \ -s "found max fragment length extension" \ -s "server hello, max_fragment_length extension" \ @@ -3184,13 +3479,14 @@ run_test "Max fragment length: client, larger message" \ -s "297 bytes read" requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH -requires_config_value_at_least "MBEDTLS_SSL_MAX_CONTENT_LEN" 2048 run_test "Max fragment length: DTLS client, larger message" \ "$P_SRV debug_level=3 dtls=1" \ "$P_CLI debug_level=3 dtls=1 max_frag_len=2048 request_size=2345" \ 1 \ - -c "Maximum fragment length is 2048" \ - -s "Maximum fragment length is 2048" \ + -c "Maximum input fragment length is 2048" \ + -c "Maximum output fragment length is 2048" \ + -s "Maximum input fragment length is 2048" \ + -s "Maximum output fragment length is 2048" \ -c "client hello, adding max_fragment_length extension" \ -s "found max fragment length extension" \ -s "server hello, max_fragment_length extension" \ @@ -3291,6 +3587,29 @@ run_test "Renegotiation: double" \ -s "=> renegotiate" \ -s "write hello request" +requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +run_test "Renegotiation with max fragment length: client 2048, server 512" \ + "$P_SRV debug_level=3 exchanges=2 renegotiation=1 auth_mode=optional renegotiate=1 max_frag_len=512" \ + "$P_CLI debug_level=3 exchanges=2 renegotiation=1 renegotiate=1 max_frag_len=2048 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ + 0 \ + -c "Maximum input fragment length is 2048" \ + -c "Maximum output fragment length is 2048" \ + -s "Maximum input fragment length is 2048" \ + -s "Maximum output fragment length is 512" \ + -c "client hello, adding max_fragment_length extension" \ + -s "found max fragment length extension" \ + -s "server hello, max_fragment_length extension" \ + -c "found max_fragment_length extension" \ + -c "client hello, adding renegotiation extension" \ + -s "received TLS_EMPTY_RENEGOTIATION_INFO" \ + -s "found renegotiation extension" \ + -s "server hello, secure renegotiation extension" \ + -c "found renegotiation extension" \ + -c "=> renegotiate" \ + -s "=> renegotiate" \ + -s "write hello request" + requires_config_enabled MBEDTLS_SSL_RENEGOTIATION run_test "Renegotiation: client-initiated, server-rejected" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=0 auth_mode=optional" \ @@ -8774,6 +9093,12 @@ run_test "DTLS proxy: 3d, gnutls server, fragmentation, nbio" \ -s "Extra-header:" \ -c "Extra-header:" +# Test heap memory usage after handshake +requires_config_enabled MBEDTLS_MEMORY_DEBUG +requires_config_enabled MBEDTLS_MEMORY_BUFFER_ALLOC_C +requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +run_tests_memory_after_hanshake + # Final report echo "------------------------------------------------------------------------"