Make handshake fragmentation follow max_frag_len

Note: no interop tests in ssl-opt.sh for now, as some of them make us run into
bugs in (the CI's default versions of) OpenSSL and GnuTLS, so interop tests
will be added later once the situation is clarified. <- TODO
This commit is contained in:
Manuel Pégourié-Gonnard 2017-09-19 13:00:47 +02:00
parent 28f4beab1c
commit 2cb17e201b
2 changed files with 123 additions and 11 deletions

View File

@ -2845,12 +2845,23 @@ int mbedtls_ssl_resend( mbedtls_ssl_context *ssl )
*/ */
int mbedtls_ssl_flight_transmit( 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
/* DTLS handshake headers are 12 bytes */
const size_t max_hs_fragment_len = max_record_content_len - 12;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_flight_transmit" ) ); MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_flight_transmit" ) );
if( ssl->handshake->retransmit_state != MBEDTLS_SSL_RETRANS_SENDING ) if( ssl->handshake->retransmit_state != MBEDTLS_SSL_RETRANS_SENDING )
{ {
MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialise fligh transmission" ) ); MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialise fligh transmission" ) );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "max handshake fragment length: %u",
max_hs_fragment_len ) );
ssl->handshake->cur_msg = ssl->handshake->flight; ssl->handshake->cur_msg = ssl->handshake->flight;
ssl->handshake->cur_msg_p = ssl->handshake->flight->p + 12; ssl->handshake->cur_msg_p = ssl->handshake->flight->p + 12;
ssl_swap_epochs( ssl ); ssl_swap_epochs( ssl );
@ -2858,13 +2869,6 @@ int mbedtls_ssl_flight_transmit( mbedtls_ssl_context *ssl )
ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_SENDING; ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_SENDING;
} }
/*
* XXX: this should not be hardcoded.
* Currently UDP limit - HS header - Record header
* (Should account for encryption overhead (renegotiation, finished)?)
*/
#define HS_LIMIT ( 512 - 12 - 13 )
while( ssl->handshake->cur_msg != NULL ) while( ssl->handshake->cur_msg != NULL )
{ {
int ret; int ret;
@ -2894,7 +2898,8 @@ int mbedtls_ssl_flight_transmit( mbedtls_ssl_context *ssl )
const size_t hs_len = cur->len - 12; const size_t hs_len = cur->len - 12;
const size_t frag_off = p - ( cur->p + 12 ); const size_t frag_off = p - ( cur->p + 12 );
const size_t rem_len = hs_len - frag_off; const size_t rem_len = hs_len - frag_off;
const size_t frag_len = rem_len > HS_LIMIT ? HS_LIMIT : rem_len; const size_t frag_len = rem_len > max_hs_fragment_len
? max_hs_fragment_len : rem_len;
/* Messages are stored with handshake headers as if not fragmented, /* Messages are stored with handshake headers as if not fragmented,
* copy beginning of headers then fill fragmentation fields. * copy beginning of headers then fill fragmentation fields.
@ -7029,15 +7034,20 @@ size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl )
*/ */
max_len = ssl_mfl_code_to_length( ssl->conf->mfl_code ); max_len = ssl_mfl_code_to_length( ssl->conf->mfl_code );
/* /* Check if a smaller max length was negotiated */
* Check if a smaller max length was negotiated
*/
if( ssl->session_out != NULL && if( ssl->session_out != NULL &&
ssl_mfl_code_to_length( ssl->session_out->mfl_code ) < max_len ) ssl_mfl_code_to_length( ssl->session_out->mfl_code ) < max_len )
{ {
max_len = ssl_mfl_code_to_length( ssl->session_out->mfl_code ); max_len = ssl_mfl_code_to_length( ssl->session_out->mfl_code );
} }
/* During a handshake, use the value being negotiated */
if( ssl->session_negotiate != NULL &&
ssl_mfl_code_to_length( ssl->session_negotiate->mfl_code ) < max_len )
{
max_len = ssl_mfl_code_to_length( ssl->session_negotiate->mfl_code );
}
return max_len; return max_len;
} }
#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */

View File

@ -4877,6 +4877,108 @@ run_test "DTLS reassembly: fragmentation, nbio (openssl server)" \
-c "found fragmented DTLS handshake message" \ -c "found fragmented DTLS handshake message" \
-C "error" -C "error"
# Tests for sending fragmented handshake messages with DTLS
#
# Use client auth when we need the client to send large messages,
# and use large cert chains on both sides too (the long chains we have all use
# both RSA and ECDSA, but ideally we should have long chains with either).
# Sizes reached (UDP payload):
# - 2037B for server certificate
# - 1542B for client certificate
# - 1013B for newsessionticket
# - all others below 512B
# All those tests assume MAX_CONTENT_LEN is at least 2048
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_config_enabled MBEDTLS_ECDSA_C
requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
run_test "DTLS fragmenting: none (for reference)" \
"$P_SRV dtls=1 debug_level=2 auth_mode=required \
crt_file=data_files/server7_int-ca.crt \
key_file=data_files/server7.key \
max_frag_len=2048" \
"$P_CLI dtls=1 debug_level=2 \
crt_file=data_files/server8_int-ca2.crt \
key_file=data_files/server8.key \
max_frag_len=2048" \
0 \
-S "found fragmented DTLS handshake message" \
-C "found fragmented DTLS handshake message" \
-C "error"
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_config_enabled MBEDTLS_ECDSA_C
requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
run_test "DTLS fragmenting: server only" \
"$P_SRV dtls=1 debug_level=2 auth_mode=required \
crt_file=data_files/server7_int-ca.crt \
key_file=data_files/server7.key \
max_frag_len=1024" \
"$P_CLI dtls=1 debug_level=2 \
crt_file=data_files/server8_int-ca2.crt \
key_file=data_files/server8.key \
max_frag_len=2048" \
0 \
-S "found fragmented DTLS handshake message" \
-c "found fragmented DTLS handshake message" \
-C "error"
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_config_enabled MBEDTLS_ECDSA_C
requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
run_test "DTLS fragmenting: server only (more)" \
"$P_SRV dtls=1 debug_level=2 auth_mode=required \
crt_file=data_files/server7_int-ca.crt \
key_file=data_files/server7.key \
max_frag_len=512" \
"$P_CLI dtls=1 debug_level=2 \
crt_file=data_files/server8_int-ca2.crt \
key_file=data_files/server8.key \
max_frag_len=2048" \
0 \
-S "found fragmented DTLS handshake message" \
-c "found fragmented DTLS handshake message" \
-C "error"
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_config_enabled MBEDTLS_ECDSA_C
requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
run_test "DTLS fragmenting: client-initiated, server only" \
"$P_SRV dtls=1 debug_level=2 auth_mode=none \
crt_file=data_files/server7_int-ca.crt \
key_file=data_files/server7.key \
max_frag_len=2048" \
"$P_CLI dtls=1 debug_level=2 \
crt_file=data_files/server8_int-ca2.crt \
key_file=data_files/server8.key \
max_frag_len=512" \
0 \
-S "found fragmented DTLS handshake message" \
-c "found fragmented DTLS handshake message" \
-C "error"
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_config_enabled MBEDTLS_ECDSA_C
requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
run_test "DTLS fragmenting: client-initiated, both" \
"$P_SRV dtls=1 debug_level=2 auth_mode=required \
crt_file=data_files/server7_int-ca.crt \
key_file=data_files/server7.key \
max_frag_len=2048" \
"$P_CLI dtls=1 debug_level=2 \
crt_file=data_files/server8_int-ca2.crt \
key_file=data_files/server8.key \
max_frag_len=512" \
0 \
-s "found fragmented DTLS handshake message" \
-c "found fragmented DTLS handshake message" \
-C "error"
# Tests for specific things with "unreliable" UDP connection # Tests for specific things with "unreliable" UDP connection
not_with_valgrind # spurious resend due to timeout not_with_valgrind # spurious resend due to timeout