Merge pull request #3946 from AndrzejKurek/optimized-key-exchange
Key exchange optimizations
diff --git a/configs/baremetal.h b/configs/baremetal.h
index 80ed74c..a0fb744 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 6e7c270..4c92954 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 ee25107..22eba11 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -41,6 +41,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
*
* The compiler has support for asm().
@@ -1593,6 +1602,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
*
* Enable hooking functions in SSL module for hardware acceleration of
diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index ea1b847..441109d 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -573,6 +573,10 @@
#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 @@
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_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 cec2f09..85473e6 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -1141,11 +1141,17 @@
}
#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 @@
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 @@
{
((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 @@
*/
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 @@
}
#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 @@
* 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 @@
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 @@
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 389a24e..7ef263c 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -2743,11 +2743,17 @@
}
#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 @@
}
#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 a33760f..6415281 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -4360,6 +4360,131 @@
* 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 @@
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 @@
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 @@
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 @@
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_flight_transmit" ) );
- return( 0 );
+ return( ret );
}
/*
@@ -7972,6 +8021,26 @@
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 @@
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 @@
}
#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 @@
#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 ea072ac..c270c3a 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 @@
#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 0711703..4798f7c 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 @@
}
#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 af85824..6d6a470 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_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 a770f6d..fd67349 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -1827,6 +1827,13 @@
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 81ea9e1..bcefb8e 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -1368,6 +1368,7 @@
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 @@
-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 @@
-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" \