diff --git a/configs/baremetal.h b/configs/baremetal.h index 80ed74c36..a0fb744e6 100644 --- a/configs/baremetal.h +++ b/configs/baremetal.h @@ -161,6 +161,13 @@ #define MBEDTLS_FI_COUNTERMEASURES #define MBEDTLS_CCM_SHUFFLING_MASKING +/* Further optimizations */ +#define MBEDTLS_SSL_KEEP_PEER_CERTIFICATE +#define MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION +#define MBEDTLS_SSL_FREE_SERVER_CERTIFICATE +#define MBEDTLS_SSL_IMMEDIATE_TRANSMISSION +#define MBEDTLS_SSL_EARLY_KEY_COMPUTATION + #if defined(MBEDTLS_USER_CONFIG_FILE) #include MBEDTLS_USER_CONFIG_FILE #endif diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h index 6e7c27098..4c92954e9 100644 --- a/include/mbedtls/check_config.h +++ b/include/mbedtls/check_config.h @@ -910,6 +910,15 @@ #undef MBEDTLS_HASHES_ENABLED #endif /* MBEDTLS_MD_SINGLE_HASH */ +#if defined(MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION) && !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) +#error "MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION can only be used with MBEDTLS_SSL_KEEP_PEER_CERTIFICATE" +#endif + + +#if defined(MBEDTLS_SSL_EARLY_KEY_COMPUTATION) && !defined(MBEDTLS_USE_TINYCRYPT) +#error "MBEDTLS_SSL_EARLY_KEY_COMPUTATION can only be used with MBEDTLS_USE_TINYCRYPT" +#endif + /* * Note: the dependency on TinyCrypt is reflected in several ways in the code: * diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index ee25107d2..22eba11de 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -40,6 +40,15 @@ * \{ */ +/** + * \def MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION + * + * Enable the delayed verification of server + * certificates on the client side. + * + */ +//#define MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION + /** * \def MBEDTLS_HAVE_ASM * @@ -1592,6 +1601,39 @@ */ #define MBEDTLS_SSL_KEEP_PEER_CERTIFICATE +/** + * \def MBEDTLS_SSL_FREE_SERVER_CERTIFICATE + * + * This option controls determines whether the server certificate is discarded + * after a handshake when the MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is enabled. + * + * Use of this option is useful in combined with the delayed certificate verification + * when the server certificate has to be kept for the duration of the handshake + * but not afterwards. + * + */ +//#define MBEDTLS_SSL_FREE_SERVER_CERTIFICATE + + +/** + * \def MBEDTLS_SSL_IMMEDIATE_TRANSMISSION + * + * Force stack to immediately transmit messages. + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + */ +//#define MBEDTLS_SSL_IMMEDIATE_TRANSMISSION + +/** + * \def MBEDTLS_SSL_EARLY_KEY_COMPUTATION + * + * Create ephemeral Diffie-Hellman key pair after + * the ClientHello has been successfully transmitted. + * + * Requires: + */ +//#define MBEDTLS_SSL_EARLY_KEY_COMPUTATION + /** * \def MBEDTLS_SSL_HW_RECORD_ACCEL * diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index ea1b847a7..441109dd4 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -573,6 +573,10 @@ struct mbedtls_ssl_handshake_params #if defined(MBEDTLS_USE_TINYCRYPT) uint8_t ecdh_privkey[NUM_ECC_BYTES]; +#if defined(MBEDTLS_SSL_EARLY_KEY_COMPUTATION) + uint8_t ecdhe_computed; + uint8_t ecdh_publickey[2*NUM_ECC_BYTES]; +#endif /* MBEDTLS_SSL_EARLY_KEY_COMPUTATION */ uint8_t ecdh_peerkey[2*NUM_ECC_BYTES]; #endif /* MBEDTLS_USE_TINYCRYPT */ @@ -1085,6 +1089,14 @@ int mbedtls_ssl_check_sig_hash( const mbedtls_ssl_context *ssl, mbedtls_md_type_t md ); #endif +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) && defined(MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION) +int mbedtls_ssl_parse_delayed_certificate_verify( mbedtls_ssl_context *ssl, + int authmode, + mbedtls_x509_crt *chain, + void *rs_ctx ); +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED && MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION */ + + static inline int mbedtls_ssl_get_minor_ver( mbedtls_ssl_context const *ssl ) { #if !defined(MBEDTLS_SSL_CONF_FIXED_MINOR_VER) @@ -1191,6 +1203,9 @@ void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl ); void mbedtls_ssl_recv_flight_completed( mbedtls_ssl_context *ssl ); int mbedtls_ssl_resend( mbedtls_ssl_context *ssl ); int mbedtls_ssl_flight_transmit( mbedtls_ssl_context *ssl ); +#if defined(MBEDTLS_SSL_IMMEDIATE_TRANSMISSION) +void mbedtls_ssl_immediate_flight_done( mbedtls_ssl_context *ssl ); +#endif #endif /* Visible for testing purposes only */ diff --git a/library/ssl_cli.c b/library/ssl_cli.c index cec2f0962..85473e689 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -1141,11 +1141,17 @@ static int ssl_write_client_hello( mbedtls_ssl_context *ssl ) } #if defined(MBEDTLS_SSL_PROTO_DTLS) - if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) && - ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) ) { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret ); - return( ret ); +#if defined(MBEDTLS_SSL_IMMEDIATE_TRANSMISSION) + mbedtls_ssl_immediate_flight_done( ssl ); +#else + if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret ); + return( ret ); + } +#endif } #endif /* MBEDTLS_SSL_PROTO_DTLS */ @@ -3593,7 +3599,7 @@ static int ssl_out_client_key_exchange_write( mbedtls_ssl_context *ssl, size_t buflen, size_t *olen ) { - int ret; + int ret = MBEDTLS_ERR_PLATFORM_FAULT_DETECTED; unsigned char *p, *end; size_t n; mbedtls_ssl_ciphersuite_handle_t ciphersuite_info = @@ -3654,18 +3660,23 @@ static int ssl_out_client_key_exchange_write( mbedtls_ssl_context *ssl, { ((void) n); - + ((void) ret); if( (size_t)( end - p ) < 2 * NUM_ECC_BYTES + 2 ) return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); *p++ = 2 * NUM_ECC_BYTES + 1; *p++ = 0x04; /* uncompressed point presentation */ +#if defined(MBEDTLS_SSL_EARLY_KEY_COMPUTATION) + mbedtls_platform_memcpy( p, ssl->handshake->ecdh_publickey, + 2 * NUM_ECC_BYTES ); +#else ret = uECC_make_key( p, ssl->handshake->ecdh_privkey ); if( ret == UECC_FAULT_DETECTED ) return( MBEDTLS_ERR_PLATFORM_FAULT_DETECTED ); if( ret != UECC_SUCCESS ) return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); +#endif /* MBEDTLS_SSL_EARLY_KEY_COMPUTATION && MBEDTLS_USE_TINYCRYPT */ p += 2 * NUM_ECC_BYTES; } else @@ -4217,7 +4228,11 @@ static int ssl_parse_new_session_ticket( mbedtls_ssl_context *ssl ) */ int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl ) { - int ret = 0; + int ret = MBEDTLS_ERR_PLATFORM_FAULT_DETECTED; +#if defined(MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION) + void *rs_ctx = NULL; + int authmode; +#endif /* MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION */ if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER || ssl->handshake == NULL ) return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); @@ -4246,10 +4261,12 @@ int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl ) } #endif + ret = MBEDTLS_ERR_PLATFORM_FAULT_DETECTED; switch( ssl->state ) { case MBEDTLS_SSL_HELLO_REQUEST: ssl->state = MBEDTLS_SSL_CLIENT_HELLO; + ret = 0; break; /* @@ -4267,6 +4284,25 @@ int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl ) * ServerHelloDone */ case MBEDTLS_SSL_SERVER_HELLO: +#if defined(MBEDTLS_SSL_EARLY_KEY_COMPUTATION) && defined(MBEDTLS_USE_TINYCRYPT) + { + volatile uint8_t ecdhe_computed = ssl->handshake->ecdhe_computed; + /* Make sure that the ECDHE pre-computation is only done once */ + if( ecdhe_computed == 0 ) + { + ret = uECC_make_key( ssl->handshake->ecdh_publickey, ssl->handshake->ecdh_privkey ); + if( ret == UECC_FAULT_DETECTED ) + return( MBEDTLS_ERR_PLATFORM_FAULT_DETECTED ); + if( ret != UECC_SUCCESS ) + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + ssl->handshake->ecdhe_computed = 1; + ecdhe_computed = 1; + } + if( ecdhe_computed == 0 || ssl->handshake->ecdhe_computed == 0 ) + return( MBEDTLS_ERR_PLATFORM_FAULT_DETECTED ); + } +#endif /* MBEDTLS_SSL_EARLY_KEY_COMPUTATION && MBEDTLS_USE_TINYCRYPT */ + ret = ssl_parse_server_hello( ssl ); break; @@ -4310,6 +4346,24 @@ int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl ) break; case MBEDTLS_SSL_CLIENT_FINISHED: + +#if defined(MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION) +#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + authmode = ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET + ? ssl->handshake->sni_authmode + : mbedtls_ssl_conf_get_authmode( ssl->conf ); +#else + authmode = mbedtls_ssl_conf_get_authmode( ssl->conf ); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "execute delayed server certificate verification" ) ); + + ret = mbedtls_ssl_parse_delayed_certificate_verify( ssl, authmode, + ssl->session_negotiate->peer_cert, rs_ctx ); + if( ret != 0 ) + break; +#endif /* MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION */ + ret = mbedtls_ssl_write_finished( ssl ); break; @@ -4335,6 +4389,7 @@ int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl ) case MBEDTLS_SSL_FLUSH_BUFFERS: MBEDTLS_SSL_DEBUG_MSG( 2, ( "handshake: done" ) ); ssl->state = MBEDTLS_SSL_HANDSHAKE_WRAPUP; + ret = 0; break; case MBEDTLS_SSL_HANDSHAKE_WRAPUP: diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 389a24e48..7ef263c49 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2743,11 +2743,17 @@ static int ssl_write_hello_verify_request( mbedtls_ssl_context *ssl ) } #if defined(MBEDTLS_SSL_PROTO_DTLS) - if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) && - ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) ) { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret ); - return( ret ); +#if defined(MBEDTLS_SSL_IMMEDIATE_TRANSMISSION) + mbedtls_ssl_immediate_flight_done( ssl ); +#else + if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret ); + return( ret ); + } +#endif } #endif /* MBEDTLS_SSL_PROTO_DTLS */ @@ -3802,11 +3808,17 @@ static int ssl_write_server_hello_done( mbedtls_ssl_context *ssl ) } #if defined(MBEDTLS_SSL_PROTO_DTLS) - if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) && - ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) ) { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret ); - return( ret ); +#if defined(MBEDTLS_SSL_IMMEDIATE_TRANSMISSION) + mbedtls_ssl_immediate_flight_done( ssl ); +#else + if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret ); + return( ret ); + } +#endif } #endif /* MBEDTLS_SSL_PROTO_DTLS */ diff --git a/library/ssl_tls.c b/library/ssl_tls.c index a33760fdf..64152814a 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -4360,6 +4360,131 @@ int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ) * Functions to handle the DTLS retransmission state machine */ #if defined(MBEDTLS_SSL_PROTO_DTLS) +static int ssl_swap_epochs( mbedtls_ssl_context *ssl ); + +static int mbedtls_ssl_flight_transmit_msg( mbedtls_ssl_context *ssl, mbedtls_ssl_flight_item *msg ) +{ + size_t max_frag_len; + int ret = MBEDTLS_ERR_PLATFORM_FAULT_DETECTED; + int const is_retransmitting = + ( ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ); + int const is_finished = + ( msg->type == MBEDTLS_SSL_MSG_HANDSHAKE && + msg->p[0] == MBEDTLS_SSL_HS_FINISHED ); + + uint8_t const force_flush = ssl->disable_datagram_packing == 1 ? + SSL_FORCE_FLUSH : SSL_DONT_FORCE_FLUSH; + + /* Swap epochs before sending Finished: we can't do it after + * sending ChangeCipherSpec, in case write returns WANT_READ. + * Must be done before copying, may change out_msg pointer */ + if( is_retransmitting && is_finished && ssl->handshake->cur_msg_p == ( msg->p + 12 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "swap epochs to send finished message" ) ); + if( ( ret = ssl_swap_epochs( ssl ) ) != 0 ) + return( ret ); + } + + ret = ssl_get_remaining_payload_in_datagram( ssl ); + if( ret < 0 ) + return( ret ); + max_frag_len = (size_t) ret; + + /* CCS is copied as is, while HS messages may need fragmentation */ + if( msg->type == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC ) + { + if( max_frag_len == 0 ) + { + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + + return( 0 ); + } + + mbedtls_platform_memcpy( ssl->out_msg, msg->p, msg->len ); + ssl->out_msglen = msg->len; + ssl->out_msgtype = msg->type; + + /* Update position inside current message */ + ssl->handshake->cur_msg_p += msg->len; + } + else + { + const unsigned char * const p = ssl->handshake->cur_msg_p; + const size_t hs_len = msg->len - 12; + const size_t frag_off = p - ( msg->p + 12 ); + const size_t rem_len = hs_len - frag_off; + size_t cur_hs_frag_len, max_hs_frag_len; + + if( ( max_frag_len < 12 ) || ( max_frag_len == 12 && hs_len != 0 ) ) + { + if( is_finished && is_retransmitting ) + { + if( ( ret = ssl_swap_epochs( ssl ) ) != 0 ) + return( ret ); + } + + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + + return( 0 ); + } + max_hs_frag_len = max_frag_len - 12; + + cur_hs_frag_len = rem_len > max_hs_frag_len ? + max_hs_frag_len : rem_len; + + if( frag_off == 0 && cur_hs_frag_len != hs_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "fragmenting handshake message (%u > %u)", + (unsigned) cur_hs_frag_len, + (unsigned) max_hs_frag_len ) ); + } + + /* Messages are stored with handshake headers as if not fragmented, + * copy beginning of headers then fill fragmentation fields. + * Handshake headers: type(1) len(3) seq(2) f_off(3) f_len(3) */ + mbedtls_platform_memcpy( ssl->out_msg, msg->p, 6 ); + + (void)mbedtls_platform_put_uint24_be( &ssl->out_msg[6], frag_off ); + (void)mbedtls_platform_put_uint24_be( &ssl->out_msg[9], + cur_hs_frag_len ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "handshake header", ssl->out_msg, 12 ); + + /* Copy the handshake message content and set records fields */ + mbedtls_platform_memcpy( ssl->out_msg + 12, p, cur_hs_frag_len ); + ssl->out_msglen = cur_hs_frag_len + 12; + ssl->out_msgtype = msg->type; + + /* Update position inside current message */ + ssl->handshake->cur_msg_p += cur_hs_frag_len; + } + + /* If done with the current message move to the next one if any */ + if( ssl->handshake->cur_msg_p >= msg->p + msg->len ) + { + if( msg->next != NULL ) + { + ssl->handshake->cur_msg = msg->next; + ssl->handshake->cur_msg_p = msg->next->p + 12; + } + else + { + ssl->handshake->cur_msg = NULL; + ssl->handshake->cur_msg_p = NULL; + } + } + + /* Actually send the message out */ + if( ( ret = mbedtls_ssl_write_record( ssl, force_flush ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + return( ret ); +} + /* * Append current handshake message to current outgoing flight */ @@ -4402,6 +4527,24 @@ static int ssl_flight_append( mbedtls_ssl_context *ssl ) cur->next = msg; } +#if defined(MBEDTLS_SSL_IMMEDIATE_TRANSMISSION) + ssl->handshake->cur_msg = msg; + ssl->handshake->cur_msg_p = msg->p + 12; + { + int ret = MBEDTLS_ERR_PLATFORM_FAULT_DETECTED; + while( ssl->handshake->cur_msg != NULL ) + { + if( ( ret = mbedtls_ssl_flight_transmit_msg( ssl, ssl->handshake->cur_msg ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit_msg", ret ); + return( ret ); + } + + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + } + } +#endif MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= ssl_flight_append" ) ); return( 0 ); } @@ -4491,6 +4634,24 @@ int mbedtls_ssl_resend( mbedtls_ssl_context *ssl ) return( ret ); } +#if defined(MBEDTLS_SSL_IMMEDIATE_TRANSMISSION) +void mbedtls_ssl_immediate_flight_done( mbedtls_ssl_context *ssl ) +{ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_immediate_flight_done" ) ); + + /* Update state and set timer */ + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER ) + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_FINISHED; + else + { + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_WAITING; + ssl_set_timer( ssl, ssl->handshake->retransmit_timeout ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_immediate_flight_done" ) ); +} +#endif + /* * Transmit or retransmit the current flight of messages. * @@ -4517,121 +4678,9 @@ int mbedtls_ssl_flight_transmit( mbedtls_ssl_context *ssl ) while( ssl->handshake->cur_msg != NULL ) { - size_t max_frag_len; - const mbedtls_ssl_flight_item * const cur = ssl->handshake->cur_msg; - - int const is_finished = - ( cur->type == MBEDTLS_SSL_MSG_HANDSHAKE && - cur->p[0] == MBEDTLS_SSL_HS_FINISHED ); - - uint8_t const force_flush = ssl->disable_datagram_packing == 1 ? - SSL_FORCE_FLUSH : SSL_DONT_FORCE_FLUSH; - - /* Swap epochs before sending Finished: we can't do it after - * sending ChangeCipherSpec, in case write returns WANT_READ. - * Must be done before copying, may change out_msg pointer */ - if( is_finished && ssl->handshake->cur_msg_p == ( cur->p + 12 ) ) + if( ( ret = mbedtls_ssl_flight_transmit_msg( ssl, ssl->handshake->cur_msg ) ) != 0 ) { - MBEDTLS_SSL_DEBUG_MSG( 2, ( "swap epochs to send finished message" ) ); - if( ( ret = ssl_swap_epochs( ssl ) ) != 0 ) - return( ret ); - } - - ret = ssl_get_remaining_payload_in_datagram( ssl ); - if( ret < 0 ) - return( ret ); - max_frag_len = (size_t) ret; - - /* CCS is copied as is, while HS messages may need fragmentation */ - if( cur->type == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC ) - { - if( max_frag_len == 0 ) - { - if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) - return( ret ); - - continue; - } - - mbedtls_platform_memcpy( ssl->out_msg, cur->p, cur->len ); - ssl->out_msglen = cur->len; - ssl->out_msgtype = cur->type; - - /* Update position inside current message */ - ssl->handshake->cur_msg_p += cur->len; - } - else - { - const unsigned char * const p = ssl->handshake->cur_msg_p; - const size_t hs_len = cur->len - 12; - const size_t frag_off = p - ( cur->p + 12 ); - const size_t rem_len = hs_len - frag_off; - size_t cur_hs_frag_len, max_hs_frag_len; - - if( ( max_frag_len < 12 ) || ( max_frag_len == 12 && hs_len != 0 ) ) - { - if( is_finished ) - { - if( ( ret = ssl_swap_epochs( ssl ) ) != 0 ) - return( ret ); - } - - if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) - return( ret ); - - continue; - } - max_hs_frag_len = max_frag_len - 12; - - cur_hs_frag_len = rem_len > max_hs_frag_len ? - max_hs_frag_len : rem_len; - - if( frag_off == 0 && cur_hs_frag_len != hs_len ) - { - MBEDTLS_SSL_DEBUG_MSG( 2, ( "fragmenting handshake message (%u > %u)", - (unsigned) cur_hs_frag_len, - (unsigned) max_hs_frag_len ) ); - } - - /* Messages are stored with handshake headers as if not fragmented, - * copy beginning of headers then fill fragmentation fields. - * Handshake headers: type(1) len(3) seq(2) f_off(3) f_len(3) */ - mbedtls_platform_memcpy( ssl->out_msg, cur->p, 6 ); - - (void)mbedtls_platform_put_uint24_be( &ssl->out_msg[6], frag_off ); - (void)mbedtls_platform_put_uint24_be( &ssl->out_msg[9], - cur_hs_frag_len ); - - MBEDTLS_SSL_DEBUG_BUF( 3, "handshake header", ssl->out_msg, 12 ); - - /* Copy the handshake message content and set records fields */ - mbedtls_platform_memcpy( ssl->out_msg + 12, p, cur_hs_frag_len ); - ssl->out_msglen = cur_hs_frag_len + 12; - ssl->out_msgtype = cur->type; - - /* Update position inside current message */ - ssl->handshake->cur_msg_p += cur_hs_frag_len; - } - - /* If done with the current message move to the next one if any */ - if( ssl->handshake->cur_msg_p >= cur->p + cur->len ) - { - if( cur->next != NULL ) - { - ssl->handshake->cur_msg = cur->next; - ssl->handshake->cur_msg_p = cur->next->p + 12; - } - else - { - ssl->handshake->cur_msg = NULL; - ssl->handshake->cur_msg_p = NULL; - } - } - - /* Actually send the message out */ - if( ( ret = mbedtls_ssl_write_record( ssl, force_flush ) ) != 0 ) - { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit_msg", ret ); return( ret ); } } @@ -4650,7 +4699,7 @@ int mbedtls_ssl_flight_transmit( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_flight_transmit" ) ); - return( 0 ); + return( ret ); } /* @@ -7972,6 +8021,26 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl, return( verify_ret ); } + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) && defined(MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION) +/* mbedtls_ssl_parse_delayed_certificate_verify() defines a wrapper around ssl_parse_certificate_verify + * to call it in ssl_cli.c rather than purely internal to ssl_tls.c. + */ +int mbedtls_ssl_parse_delayed_certificate_verify( mbedtls_ssl_context *ssl, + int authmode, + mbedtls_x509_crt *chain, + void *rs_ctx ) +{ + + return( ssl_parse_certificate_verify( ssl, + authmode, + chain, + rs_ctx ) ); + +} +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED && MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION */ + + #if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) #if defined(MBEDTLS_SSL_RENEGOTIATION) @@ -8112,10 +8181,19 @@ crt_verify: rs_ctx = &ssl->handshake->ecrs_ctx; #endif - ret = ssl_parse_certificate_verify( ssl, authmode, - chain, rs_ctx ); - if( ret != 0 ) - goto exit; +#if defined(MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION) + if (mbedtls_ssl_conf_get_endpoint( ssl->conf ) == MBEDTLS_SSL_IS_CLIENT ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "delay server certificate verification" ) ); + } + else +#endif /* MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION */ + { + ret = ssl_parse_certificate_verify( ssl, authmode, + chain, rs_ctx ); + if( ret != 0 ) + goto exit; + } #if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) { @@ -8663,13 +8741,19 @@ int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl ) } #if defined(MBEDTLS_SSL_PROTO_DTLS) - if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) && - ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) ) { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret ); - return( ret ); - } +#if defined(MBEDTLS_SSL_IMMEDIATE_TRANSMISSION) + mbedtls_ssl_immediate_flight_done( ssl ); +#else + if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret ); + return( ret ); + } #endif + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write finished" ) ); @@ -12013,6 +12097,19 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ) #endif #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_FREE_SERVER_CERTIFICATE) && \ + defined(MBEDTLS_X509_CRT_PARSE_C) && \ + defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + if( ssl->session_negotiate ) + { + ssl_clear_peer_cert( ssl->session_negotiate ); + } + if( ssl->session ) + { + ssl_clear_peer_cert( ssl->session ); + } +#endif /* MBEDTLS_SSL_FREE_SERVER_CERTIFICATE */ + #if defined(MBEDTLS_DHM_C) mbedtls_dhm_free( &handshake->dhm_ctx ); #endif diff --git a/library/version_features.c b/library/version_features.c index ea072ac25..c270c3a63 100644 --- a/library/version_features.c +++ b/library/version_features.c @@ -33,6 +33,9 @@ static const char *features[] = { #if defined(MBEDTLS_VERSION_FEATURES) +#if defined(MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION) + "MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION", +#endif /* MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION */ #if defined(MBEDTLS_HAVE_ASM) "MBEDTLS_HAVE_ASM", #endif /* MBEDTLS_HAVE_ASM */ @@ -489,6 +492,15 @@ static const char *features[] = { #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) "MBEDTLS_SSL_KEEP_PEER_CERTIFICATE", #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +#if defined(MBEDTLS_SSL_FREE_SERVER_CERTIFICATE) + "MBEDTLS_SSL_FREE_SERVER_CERTIFICATE", +#endif /* MBEDTLS_SSL_FREE_SERVER_CERTIFICATE */ +#if defined(MBEDTLS_SSL_IMMEDIATE_TRANSMISSION) + "MBEDTLS_SSL_IMMEDIATE_TRANSMISSION", +#endif /* MBEDTLS_SSL_IMMEDIATE_TRANSMISSION */ +#if defined(MBEDTLS_SSL_EARLY_KEY_COMPUTATION) + "MBEDTLS_SSL_EARLY_KEY_COMPUTATION", +#endif /* MBEDTLS_SSL_EARLY_KEY_COMPUTATION */ #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) "MBEDTLS_SSL_HW_RECORD_ACCEL", #endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ diff --git a/programs/ssl/query_config.c b/programs/ssl/query_config.c index 0711703fe..4798f7ca7 100644 --- a/programs/ssl/query_config.c +++ b/programs/ssl/query_config.c @@ -130,6 +130,14 @@ int query_config( const char *config ) { +#if defined(MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION) + if( strcmp( "MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION", config ) == 0 ) + { + MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION ); + return( 0 ); + } +#endif /* MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION */ + #if defined(MBEDTLS_HAVE_ASM) if( strcmp( "MBEDTLS_HAVE_ASM", config ) == 0 ) { @@ -1346,6 +1354,30 @@ int query_config( const char *config ) } #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +#if defined(MBEDTLS_SSL_FREE_SERVER_CERTIFICATE) + if( strcmp( "MBEDTLS_SSL_FREE_SERVER_CERTIFICATE", config ) == 0 ) + { + MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_FREE_SERVER_CERTIFICATE ); + return( 0 ); + } +#endif /* MBEDTLS_SSL_FREE_SERVER_CERTIFICATE */ + +#if defined(MBEDTLS_SSL_IMMEDIATE_TRANSMISSION) + if( strcmp( "MBEDTLS_SSL_IMMEDIATE_TRANSMISSION", config ) == 0 ) + { + MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_IMMEDIATE_TRANSMISSION ); + return( 0 ); + } +#endif /* MBEDTLS_SSL_IMMEDIATE_TRANSMISSION */ + +#if defined(MBEDTLS_SSL_EARLY_KEY_COMPUTATION) + if( strcmp( "MBEDTLS_SSL_EARLY_KEY_COMPUTATION", config ) == 0 ) + { + MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_EARLY_KEY_COMPUTATION ); + return( 0 ); + } +#endif /* MBEDTLS_SSL_EARLY_KEY_COMPUTATION */ + #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) if( strcmp( "MBEDTLS_SSL_HW_RECORD_ACCEL", config ) == 0 ) { diff --git a/scripts/config.pl b/scripts/config.pl index af85824f1..6d6a470b9 100755 --- a/scripts/config.pl +++ b/scripts/config.pl @@ -61,6 +61,11 @@ # MBEDTLS_VALIDATE_SSL_KEYS_INTEGRITY # MBEDTLS_OPTIMIZE_TINYCRYPT_ASM # MBEDTLS_AES_128_BIT_MASKED +# MBEDTLS_PLATFORM_FAULT_CALLBACKS +# MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION +# MBEDTLS_SSL_FREE_SERVER_CERTIFICATE +# MBEDTLS_SSL_IMMEDIATE_TRANSMISSION +# MBEDTLS_SSL_EARLY_KEY_COMPUTATION # and any symbol beginning _ALT # # The baremetal configuration excludes options that require a library or @@ -149,6 +154,10 @@ MBEDTLS_VALIDATE_SSL_KEYS_INTEGRITY MBEDTLS_OPTIMIZE_TINYCRYPT_ASM MBEDTLS_AES_128_BIT_MASKED MBEDTLS_PLATFORM_FAULT_CALLBACKS +MBEDTLS_SSL_DELAYED_SERVER_CERT_VERIFICATION +MBEDTLS_SSL_FREE_SERVER_CERTIFICATE +MBEDTLS_SSL_IMMEDIATE_TRANSMISSION +MBEDTLS_SSL_EARLY_KEY_COMPUTATION _ALT\s*$ ); diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh index a770f6d5b..fd67349d3 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -1827,6 +1827,13 @@ component_test_baremetal () { msg "test: baremetal.h + baremetal_test.h" if_build_succeeded make test if_build_succeeded tests/ssl-opt.sh + + # Optional parts (slow; currently broken on OS X because programs don't + # seem to receive signals under valgrind on OS X). + if [ "$MEMORY" -gt 0 ]; then + msg "test: ssl-opt.sh --memcheck" + if_build_succeeded tests/ssl-opt.sh --memcheck + fi } component_test_hardware_entropy () { diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 81ea9e1f6..bcefb8e34 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -1368,6 +1368,7 @@ run_test "SHA-256 allowed by default in client certificate" \ 0 # Tests for datagram packing +requires_config_disabled MBEDTLS_SSL_IMMEDIATE_TRANSMISSION run_test "DTLS: multiple records in same datagram, client and server" \ "$P_SRV dtls=1 dgram_packing=1 debug_level=2" \ "$P_CLI dtls=1 dgram_packing=1 debug_level=2" \ @@ -1375,6 +1376,7 @@ run_test "DTLS: multiple records in same datagram, client and server" \ -c "next record in same datagram" \ -s "next record in same datagram" +requires_config_disabled MBEDTLS_SSL_IMMEDIATE_TRANSMISSION run_test "DTLS: multiple records in same datagram, client only" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=2" \ "$P_CLI dtls=1 dgram_packing=1 debug_level=2" \ @@ -1382,6 +1384,7 @@ run_test "DTLS: multiple records in same datagram, client only" \ -s "next record in same datagram" \ -C "next record in same datagram" +requires_config_disabled MBEDTLS_SSL_IMMEDIATE_TRANSMISSION run_test "DTLS: multiple records in same datagram, server only" \ "$P_SRV dtls=1 dgram_packing=1 debug_level=2" \ "$P_CLI dtls=1 dgram_packing=0 debug_level=2" \