From 0feb28b62b788cb76c7bbc65a6cb74f2f0dfe8c3 Mon Sep 17 00:00:00 2001 From: Joshua Siegel Date: Tue, 14 Dec 2021 21:20:11 -0500 Subject: [PATCH 1/3] use trial decryption if server rejects client 0-RTT attempt --- library/ssl_misc.h | 3 ++ library/ssl_msg.c | 68 +++++++++++++++++++++++++++++++++---- library/ssl_tls13_generic.c | 1 + library/ssl_tls13_server.c | 3 ++ tests/ssl-opt.sh | 13 +++++++ 5 files changed, 82 insertions(+), 6 deletions(-) diff --git a/library/ssl_misc.h b/library/ssl_misc.h index 4a9c1c72e3e3..401795f9d742 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -939,6 +939,9 @@ struct mbedtls_ssl_handshake_params 1 -- MBEDTLS_SSL_EARLY_DATA_ENABLED (for use early data) */ int early_data; +#if defined(MBEDTLS_SSL_SRV_C) + int skip_failed_decryption; +#endif /* MBEDTLS_SSL_SRV_C */ #endif /* MBEDTLS_ZERO_RTT */ #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */ diff --git a/library/ssl_msg.c b/library/ssl_msg.c index b5ee52255e50..3db70247dcb7 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -4114,10 +4114,21 @@ int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl, return( ret ); } - if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && - update_hs_digest == 1 ) + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) { - mbedtls_ssl_update_handshake_status( ssl ); + if( update_hs_digest == 1) + mbedtls_ssl_update_handshake_status( ssl ); + +#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_ZERO_RTT) + if( ssl->handshake != NULL && + ssl->handshake->skip_failed_decryption != 0 && + ssl->transform_in != NULL ) + { + /* Record deprotected successfully */ + ssl->handshake->skip_failed_decryption = 0; + MBEDTLS_SSL_DEBUG_MSG( 4, ( "disabling skip_failed_decryption" ) ); + } +#endif /* MBEDTLS_SSL_SRV_C && MBEDTLS_ZERO_RTT */ } } else @@ -4711,6 +4722,41 @@ static int ssl_buffer_future_record( mbedtls_ssl_context *ssl, #endif /* MBEDTLS_SSL_PROTO_DTLS */ +/* + * RFC 8446: + * "If the client attempts a 0-RTT handshake but the server + * rejects it, the server will generally not have the 0-RTT record + * protection keys and must instead use trial decryption (either with + * the 1-RTT handshake keys or by looking for a cleartext ClientHello in + * the case of a HelloRetryRequest) to find the first non-0-RTT message." + */ +#if defined(MBEDTLS_SSL_SRV_C) +static int ssl_should_drop_record( mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_ZERO_RTT) && !defined(MBEDTLS_SSL_USE_MPS) + if( ssl->conf->endpoint != MBEDTLS_SSL_IS_SERVER || ssl->handshake == NULL ) + return( 0 ); + + /* + * Drop record iff: + * 1. Client indicated early data use (skip_failed_decryption). + * 2. Server does not have early data enabled (skip_failed_decryption). + * 3. First non-0-RTT record has not yet been found (skip_failed_decryption). + * 4. 1-RTT handshake keys are in use. + */ + if( ssl->handshake->skip_failed_decryption == 1 && + ssl->transform_in == ssl->handshake->transform_handshake ) + { + return( 1 ); + } + +#endif /* MBEDTLS_ZERO_RTT && !MBEDTLS_SSL_USE_MPS */ + ((void) ssl); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SRV_C */ + static int ssl_get_next_record( mbedtls_ssl_context *ssl ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; @@ -4879,15 +4925,25 @@ static int ssl_get_next_record( mbedtls_ssl_context *ssl ) else #endif { - /* Error out (and send alert) on invalid records */ -#if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES) if( ret == MBEDTLS_ERR_SSL_INVALID_MAC ) { +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->handshake != NULL && + ssl_should_drop_record( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid record (mac), dropping 0-RTT message" ) ); + return( MBEDTLS_ERR_SSL_CONTINUE_PROCESSING ); + } +#endif /* MBEDTLS_SSL_SRV_C */ + + /* Error out (and send alert) on invalid records */ +#if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES) mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC ); +#endif /* MBEDTLS_SSL_ALL_ALERT_MESSAGES */ } -#endif + return( ret ); } } diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index 51d6f1a13f82..2e6ebf735ba4 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -2130,6 +2130,7 @@ int mbedtls_ssl_tls13_write_early_data_ext( mbedtls_ssl_context *ssl, { MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write early_data extension" ) ); ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_OFF; + ssl->handshake->skip_failed_decryption = 1; return( 0 ); } } diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index 3126f687ba25..8da0b260a14f 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -2754,6 +2754,9 @@ static int ssl_tls13_client_hello_postprocess( mbedtls_ssl_context *ssl, int ret = 0; #if defined(MBEDTLS_ZERO_RTT) mbedtls_ssl_key_set traffic_keys; + + if( ssl->handshake->hello_retry_requests_sent == 1 ) + ssl->handshake->skip_failed_decryption = 0; #endif /* MBEDTLS_ZERO_RTT */ if( ssl->handshake->hello_retry_requests_sent == 0 && diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 20a89808dbd0..ef94cd7806a5 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -2188,6 +2188,19 @@ run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ext PSK, early data status - no 0 \ -c "early data status = 0" \ +# test early data status - rejected +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_SSL_SRV_C +requires_config_enabled MBEDTLS_SSL_CLI_C +requires_config_enabled MBEDTLS_ZERO_RTT +requires_config_disabled MBEDTLS_SSL_USE_MPS +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ext PSK, early data status - rejected" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls13 early_data=0 tls13_kex_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls13 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 tls13_kex_modes=psk early_data=1 psk=010203 psk_identity=0a0b0c" \ + 0 \ + -c "early data status = 1" \ + # test early data status - accepted requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 requires_config_enabled MBEDTLS_DEBUG_C From 744de0f54a225b9f4b5db9f702bd43820a081dcd Mon Sep 17 00:00:00 2001 From: Joshua Siegel Date: Tue, 21 Dec 2021 16:31:25 -0500 Subject: [PATCH 2/3] RFC implementation for new 0-RTT API --- include/mbedtls/ssl.h | 120 ++++++++++++++++++++++++++++- library/ssl_misc.h | 6 +- library/ssl_msg.c | 71 +++++++++++++++++- library/ssl_tls.c | 8 ++ library/ssl_tls13_client.c | 146 ++++++++++++++++++++++++++---------- library/ssl_tls13_generic.c | 14 +++- library/ssl_tls13_server.c | 19 ++++- programs/ssl/ssl_client2.c | 2 +- programs/ssl/ssl_server2.c | 1 + 9 files changed, 334 insertions(+), 53 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 3091b55a289d..da1dcde1e699 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -337,6 +337,14 @@ #define MBEDTLS_SSL_EARLY_DATA_OFF 0 #define MBEDTLS_SSL_EARLY_DATA_ON 1 +#define MBEDTLS_SSL_EARLY_DATA_OLD_API 0 +#define MBEDTLS_SSL_EARLY_DATA_NEW_API 1 + +#define MBEDTLS_SSL_EARLY_DATA_STATE_DISABLED 0 +#define MBEDTLS_SSL_EARLY_DATA_STATE_ENABLED 1 +#define MBEDTLS_SSL_EARLY_DATA_STATE_OFF 2 /* early_data extension sent, cannot send early_data */ +#define MBEDTLS_SSL_EARLY_DATA_STATE_ON 3 /* early_data extension sent, can send early_data */ + #define MBEDTLS_SSL_FORCE_RR_CHECK_OFF 0 #define MBEDTLS_SSL_FORCE_RR_CHECK_ON 1 @@ -862,6 +870,42 @@ typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; * of 0-RTT and the server has accepted it. */ int mbedtls_ssl_get_early_data_status( mbedtls_ssl_context *ssl ); + +/** + * \brief Get information about the eligibility of sending early data + * in a 0-RTT handshake + * + * \param ssl The SSL context to query. + * + * \returns #MBEDTLS_SSL_EARLY_DATA_STATE_DISABLED if early data is + * disabled for the session. + * \returns #MBEDTLS_SSL_EARLY_DATA_STATE_ENABLED if early data is + * enabled for the session. + * \returns #MBEDTLS_SSL_EARLY_DATA_STATE_ON if the client has provided + * early data indication. + * \returns #MBEDTLS_SSL_EARLY_DATA_STATE_OFF if early data indication + * was provided but the session can no longer send early data, + * (e.g. EndOfEarlyData message has been sent). + * + * \note This function may only be used if the new 0-RTT API is + * enabled by passing #MBEDTLS_SSL_EARLY_DATA_NEW_API to + * \c mbedtls_ssl_conf_early_data(). + */ +int mbedtls_ssl_get_early_data_state( mbedtls_ssl_context *ssl ); + +/** + * \brief Get current status of the handshake. + * + * \param ssl The SSL context to query. + * + * \returns \c 1 if the handshake is over. + * \returns \c 0 if the handshake is still in progress. + * + * \note If you need to determine whether to defer sending data until + * the connection is replay-safe, this function can be used to + * check if the handshake is complete. + */ +int mbedtls_ssl_is_init_finished( mbedtls_ssl_context *ssl ); #endif /* MBEDTLS_SSL_PROTO_TLS1_3 && MBEDTLS_ZERO_RTT && MBEDTLS_SSL_CLI_C */ typedef enum @@ -1592,7 +1636,12 @@ struct mbedtls_ssl_config * - MBEDTLS_SSL_EARLY_DATA_DISABLED, * - MBEDTLS_SSL_EARLY_DATA_ENABLED */ - int early_data_enabled; + int MBEDTLS_PRIVATE(early_data_enabled); + /*!< Early data api: + * - MBEDTLS_SSL_EARLY_DATA_OLD_API, + * - MBEDTLS_SSL_EARLY_DATA_NEW_API + */ + int MBEDTLS_PRIVATE(early_data_api); #if defined(MBEDTLS_SSL_SRV_C) /* Max number of bytes of early data acceptable by the server. */ size_t max_early_data; @@ -2084,6 +2133,7 @@ void mbedtls_ssl_conf_authmode( mbedtls_ssl_config *conf, int authmode ); #if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_ZERO_RTT) void mbedtls_ssl_conf_early_data( mbedtls_ssl_config* conf, int early_data, size_t max_early_data, + int early_data_api, int(*early_data_callback)( mbedtls_ssl_context*, const unsigned char*, size_t ) ); @@ -5058,6 +5108,74 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) */ int mbedtls_ssl_write( mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len ); +#if defined(MBEDTLS_ZERO_RTT) +/** TODO: Add complete documentation. */ +/** + * \brief Try to write exactly 'len' early data bytes + * + * \warning This function will do partial writes in some cases. If the + * return value is non-negative but less than length, the + * function must be called again with updated arguments: + * buf + ret, len - ret (if ret is the return value) until + * it returns a value equal to the last 'len' argument. + * + * \param ssl SSL context + * \param buf buffer holding the data + * \param len how many bytes must be written + * + * \return The (non-negative) number of bytes actually written if + * successful (may be less than \p len). + * \return #MBEDTLS_ERR_SSL_WANT_READ or #MBEDTLS_ERR_SSL_WANT_WRITE + * if the handshake is incomplete and waiting for data to + * be available for reading from or writing to the underlying + * transport - in this case you may call this function again + * when the underlying transport is ready for the operation to + * send additional early data. + * + * \return Another SSL error code - in this case you must stop using + * the context (see below). + * + * \warning If this function returns something other than + * a non-negative value, + * #MBEDTLS_ERR_SSL_WANT_READ, + * #MBEDTLS_ERR_SSL_WANT_WRITE, + * #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS or + * #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS, + * you must stop using the SSL context for reading or writing, + * and either free it or call \c mbedtls_ssl_session_reset() + * on it before re-using it for a new connection; the current + * connection must be closed. + * + * \warning 0-RTT can be subject to replay attacks and should only be + * used for data that is replay-safe. + * \c mbedtls_ssl_is_init_finished() can be used if you need to + * ensure a request is sent only when the connection is + * replay-safe. + * + * \note This function will implicitly begin the handshake until it + * reaches the early data stage, at which point it will send + * the early data. + * + * \note This function can be called multiple times throughout the + * duration of the handshake, but it must be the first IO + * function called on a new connection to guarantee the + * handshake does not complete atomically before the initial + * early data is sent. After a successful return, you should + * call \c mbedtls_ssl_handshake() to try and complete the + * handshake. + * + * \note This function may not be called if + * \c mbedtls_ssl_get_early_data_state() returns + * #MBEDTLS_SSL_EARLY_DATA_STATE_DISABLED or + * #MBEDTLS_SSL_EARLY_DATA_STATE_OFF. + * + * \note This function may only be used if the new 0-RTT API is + * enabled by passing #MBEDTLS_SSL_EARLY_DATA_NEW_API to + * \c mbedtls_ssl_conf_early_data(). + */ +int mbedtls_ssl_write_early_data( mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len ); +#endif /* MBEDTLS_ZERO_RTT*/ + /** * \brief Send an alert message * diff --git a/library/ssl_misc.h b/library/ssl_misc.h index 401795f9d742..0468355f79e6 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -934,11 +934,9 @@ struct mbedtls_ssl_handshake_params #if defined(MBEDTLS_ZERO_RTT) mbedtls_ssl_tls13_early_secrets early_secrets; - /*!< Early data indication: - 0 -- MBEDTLS_SSL_EARLY_DATA_DISABLED (for no early data), and - 1 -- MBEDTLS_SSL_EARLY_DATA_ENABLED (for use early data) - */ int early_data; + int early_data_write; + int early_data_ready; #if defined(MBEDTLS_SSL_SRV_C) int skip_failed_decryption; #endif /* MBEDTLS_SSL_SRV_C */ diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 3db70247dcb7..7996a97899ec 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -5942,6 +5942,15 @@ int mbedtls_ssl_write( mbedtls_ssl_context *ssl, return( ret ); } +int mbedtls_ssl_write_early_data( mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len ) +{ + ( ( void ) buf ); + ( ( void ) len ); + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "new 0-RTT api is not compatible with MPS" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); +} + /* * Notify the peer that the connection is being closed */ @@ -6273,8 +6282,9 @@ int mbedtls_ssl_write( mbedtls_ssl_context *ssl, const unsigned char *buf, size_ #if defined(MBEDTLS_ZERO_RTT) /* TODO: What's the purpose of this check? */ - if( ( ssl->handshake != NULL ) && - ( ssl->handshake->early_data == MBEDTLS_SSL_EARLY_DATA_OFF ) ) + if( ( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_NEW_API ) || + ( ( ssl->handshake != NULL ) && + ( ssl->handshake->early_data == MBEDTLS_SSL_EARLY_DATA_OFF ) ) ) #endif /* MBEDTLS_ZERO_RTT */ { if( mbedtls_ssl_is_handshake_over( ssl ) == 0 ) @@ -6294,6 +6304,63 @@ int mbedtls_ssl_write( mbedtls_ssl_context *ssl, const unsigned char *buf, size_ return( ret ); } +#if defined(MBEDTLS_ZERO_RTT) +/* + * Write application data as early data (public-facing wrapper) + */ +int mbedtls_ssl_write_early_data( mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len ) +{ + if( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_OLD_API ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "new api must be enabled for mbedtls_ssl_write_early_data" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write early_data" ) ); + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + /* Advance handshake if necessary */ + if( ssl->handshake->early_data_ready == 0 ) + { + /* Indicate handshake initiated from an early data write */ + ssl->handshake->early_data_write = 1; + ret = mbedtls_ssl_handshake( ssl ); + + if( ( ssl->handshake->early_data_ready == 0 ) || + ( ret != 0 && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); + return( ret ); + } + } + + if( ( mbedtls_ssl_is_init_finished( ssl ) ) || + ( ssl->handshake->early_data != MBEDTLS_SSL_EARLY_DATA_STATE_ON ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "cannot send early_data" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ( ret = ssl_check_ctr_renegotiate( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_check_ctr_renegotiate", ret ); + return( ret ); + } +#endif + + ret = ssl_write_real( ssl, buf, len ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write early_data" ) ); + + return( ret ); +} +#endif /* MBEDTLS_ZERO_RTT*/ + /* * Notify the peer that the connection is being closed */ diff --git a/library/ssl_tls.c b/library/ssl_tls.c index ed682af2b6a5..14430d5b030e 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -775,6 +775,14 @@ static int ssl_handshake_init( mbedtls_ssl_context *ssl ) } #endif +#if defined(MBEDTLS_ZERO_RTT) + if( ( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_NEW_API ) && + ( ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_ENABLED ) ) + { + ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_STATE_ENABLED; + } +#endif + /* * curve_list is translated to IANA TLS group identifiers here because * mbedtls_ssl_conf_curves returns void and so can't return diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index ff0d0e38fcf2..b4a2fd92ba5f 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -1650,7 +1650,10 @@ static int ssl_tls13_parse_encrypted_extensions_early_data_ext( mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len ) { - if( ssl->handshake->early_data != MBEDTLS_SSL_EARLY_DATA_ON ) + int early_data_state = ( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_NEW_API ) + ? MBEDTLS_SSL_EARLY_DATA_STATE_ON + : MBEDTLS_SSL_EARLY_DATA_ON; + if( ssl->handshake->early_data != early_data_state ) { /* The server must not send the EarlyDataIndication if the * client hasn't indicated the use of 0-RTT. */ @@ -1681,6 +1684,34 @@ int mbedtls_ssl_get_early_data_status( mbedtls_ssl_context *ssl ) return( ssl->early_data_status ); } +int mbedtls_ssl_get_early_data_state( mbedtls_ssl_context *ssl ) +{ + if( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_OLD_API ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "new api must be enabled for mbedtls_ssl_get_early_data_state" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + return( ssl->handshake->early_data ); +} + +int mbedtls_ssl_is_init_finished( mbedtls_ssl_context *ssl ) +{ + if( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_OLD_API ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "new api must be enabled for mbedtls_ssl_is_init_finished" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER && + ssl->state != MBEDTLS_SSL_CLIENT_NEW_SESSION_TICKET ) + { + return( 0 ); + } + + return( 1 ); +} + int mbedtls_ssl_set_early_data( mbedtls_ssl_context *ssl, const unsigned char *buffer, size_t len ) { @@ -2185,9 +2216,18 @@ static int ssl_tls13_process_server_hello( mbedtls_ssl_context *ssl ) #endif /* MBEDTLS_SSL_USE_MPS */ if( is_hrr ) + { + if( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_NEW_API ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received HelloRetryRequest, turn off early_data" ) ); + ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_STATE_OFF; + } MBEDTLS_SSL_PROC_CHK( ssl_tls13_postprocess_hrr( ssl ) ); + } else + { MBEDTLS_SSL_PROC_CHK( ssl_tls13_postprocess_server_hello( ssl ) ); + } cleanup: MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= %s ( %s )", __func__, @@ -2374,6 +2414,15 @@ static int ssl_tls13_parse_encrypted_extensions( mbedtls_ssl_context *ssl, return( MBEDTLS_ERR_SSL_DECODE_ERROR ); } +#if defined(MBEDTLS_ZERO_RTT) + if( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_NEW_API && + ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_REJECTED ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "early data rejected by server" ) ); + ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_STATE_OFF; + } +#endif /* MBEDTLS_ZERO_RTT */ + return( ret ); } @@ -2433,7 +2482,9 @@ int ssl_tls13_write_early_data_process( mbedtls_ssl_context *ssl ) unsigned char *buf; mbedtls_mps_size_t buf_len, msg_len; #endif /* MBEDTLS_SSL_USE_MPS */ - MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write early data" ) ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_NEW_API ) + ? ( "=> prepare early data" ) + : ( "=> write early data" ) ); MBEDTLS_SSL_PROC_CHK_NEG( ssl_tls13_write_early_data_coordinate( ssl ) ); if( ret == SSL_EARLY_DATA_WRITE ) @@ -2442,42 +2493,56 @@ int ssl_tls13_write_early_data_process( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_PROC_CHK( ssl_tls13_write_early_data_prepare( ssl ) ); + if( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_OLD_API ) + { #if defined(MBEDTLS_SSL_USE_MPS) - MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_application( &ssl->mps->l4, - &msg ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_application( &ssl->mps->l4, + &msg ) ); - /* Request write-buffer */ - MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg, MBEDTLS_MPS_SIZE_MAX, - &buf, &buf_len ) ); + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); - MBEDTLS_SSL_PROC_CHK( ssl_tls13_write_early_data_write( - ssl, buf, buf_len, &msg_len ) ); + MBEDTLS_SSL_PROC_CHK( ssl_tls13_write_early_data_write( + ssl, buf, buf_len, &msg_len ) ); - /* Commit message */ - MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg, - buf_len - msg_len ) ); + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg, + buf_len - msg_len ) ); - MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps->l4 ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps->l4 ) ); - /* Update state */ - MBEDTLS_SSL_PROC_CHK( ssl_tls13_write_early_data_postprocess( ssl ) ); + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_tls13_write_early_data_postprocess( ssl ) ); #else /* MBEDTLS_SSL_USE_MPS */ - /* Write early-data to message buffer. */ - MBEDTLS_SSL_PROC_CHK( ssl_tls13_write_early_data_write( ssl, ssl->out_msg, - MBEDTLS_SSL_OUT_CONTENT_LEN, - &ssl->out_msglen ) ); + /* Write early-data to message buffer. */ + MBEDTLS_SSL_PROC_CHK( ssl_tls13_write_early_data_write( ssl, ssl->out_msg, + MBEDTLS_SSL_OUT_CONTENT_LEN, + &ssl->out_msglen ) ); - ssl->out_msgtype = MBEDTLS_SSL_MSG_APPLICATION_DATA; + ssl->out_msgtype = MBEDTLS_SSL_MSG_APPLICATION_DATA; - /* Update state */ - MBEDTLS_SSL_PROC_CHK( ssl_tls13_write_early_data_postprocess( ssl ) ); + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_tls13_write_early_data_postprocess( ssl ) ); - /* Dispatch message */ - MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_record( ssl, 1 ) ); + /* Dispatch message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_record( ssl, 1 ) ); #endif /* MBEDTLS_SSL_USE_MPS */ + } + else + { + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_tls13_write_early_data_postprocess( ssl ) ); + + ssl->handshake->early_data_ready = 1; + + /* Only return early if handshake was initiated from an early data write */ + if( ssl->handshake->early_data_write == 1 ) + ret = MBEDTLS_ERR_SSL_WANT_WRITE; + } #else /* MBEDTLS_ZERO_RTT */ /* Should never happen */ @@ -2493,7 +2558,9 @@ int ssl_tls13_write_early_data_process( mbedtls_ssl_context *ssl ) cleanup: - MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write early data" ) ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_NEW_API ) + ? ( "<= prepare early data" ) + : ( "<= write early data" ) ); return( ret ); } @@ -2501,7 +2568,10 @@ int ssl_tls13_write_early_data_process( mbedtls_ssl_context *ssl ) static int ssl_tls13_write_early_data_coordinate( mbedtls_ssl_context *ssl ) { - if( ssl->handshake->early_data != MBEDTLS_SSL_EARLY_DATA_ON ) + int early_data_state = ( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_NEW_API ) + ? MBEDTLS_SSL_EARLY_DATA_STATE_ON + : MBEDTLS_SSL_EARLY_DATA_ON; + if( ssl->handshake->early_data != early_data_state ) return( SSL_EARLY_DATA_SKIP ); return( SSL_EARLY_DATA_WRITE ); @@ -2679,6 +2749,9 @@ int ssl_tls13_write_end_of_early_data_process( mbedtls_ssl_context *ssl ) unsigned char *buf; size_t buf_len; + if( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_NEW_API ) + ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_STATE_OFF; + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_start_handshake_msg( ssl, MBEDTLS_SSL_HS_END_OF_EARLY_DATA, &buf, &buf_len ) ); @@ -2705,20 +2778,17 @@ static int ssl_tls13_write_end_of_early_data_coordinate( mbedtls_ssl_context *ss ((void) ssl); #if defined(MBEDTLS_ZERO_RTT) - if( ssl->handshake->early_data == MBEDTLS_SSL_EARLY_DATA_ON ) - { - if( ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_ACCEPTED ) - return( SSL_END_OF_EARLY_DATA_WRITE ); + if( ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_ACCEPTED ) + return( SSL_END_OF_EARLY_DATA_WRITE ); - /* - * RFC 8446: - * "If the server does not send an "early_data" - * extension in EncryptedExtensions, then the client MUST NOT send an - * EndOfEarlyData message." - */ + /* + * RFC 8446: + * "If the server does not send an "early_data" + * extension in EncryptedExtensions, then the client MUST NOT send an + * EndOfEarlyData message." + */ - MBEDTLS_SSL_DEBUG_MSG( 4, ( "skip EndOfEarlyData, server rejected" ) ); - } + MBEDTLS_SSL_DEBUG_MSG( 4, ( "skip EndOfEarlyData, server rejected" ) ); #endif /* MBEDTLS_ZERO_RTT */ return( SSL_END_OF_EARLY_DATA_SKIP ); diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index 2e6ebf735ba4..77af9f420998 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -2052,6 +2052,7 @@ int mbedtls_ssl_tls13_write_certificate_verify( mbedtls_ssl_context *ssl ) void mbedtls_ssl_conf_early_data( mbedtls_ssl_config *conf, int early_data, size_t max_early_data, + int early_data_api, int(*early_data_callback)( mbedtls_ssl_context*, const unsigned char*, size_t ) ) @@ -2061,6 +2062,7 @@ void mbedtls_ssl_conf_early_data( ( ( void ) early_data_callback ); #endif /* !MBEDTLS_SSL_SRV_C */ conf->early_data_enabled = early_data; + conf->early_data_api = early_data_api; #if defined(MBEDTLS_SSL_SRV_C) @@ -2112,7 +2114,9 @@ int mbedtls_ssl_tls13_write_early_data_ext( mbedtls_ssl_context *ssl, ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_DISABLED ) { MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write early_data extension" ) ); - ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_OFF; + ssl->handshake->early_data = ( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_NEW_API ) + ? MBEDTLS_SSL_EARLY_DATA_STATE_DISABLED + : MBEDTLS_SSL_EARLY_DATA_OFF; return( 0 ); } } @@ -2129,7 +2133,9 @@ int mbedtls_ssl_tls13_write_early_data_ext( mbedtls_ssl_context *ssl, ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_DISABLED ) { MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write early_data extension" ) ); - ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_OFF; + ssl->handshake->early_data = ( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_NEW_API ) + ? MBEDTLS_SSL_EARLY_DATA_STATE_DISABLED + : MBEDTLS_SSL_EARLY_DATA_OFF; ssl->handshake->skip_failed_decryption = 1; return( 0 ); } @@ -2159,7 +2165,9 @@ int mbedtls_ssl_tls13_write_early_data_ext( mbedtls_ssl_context *ssl, } #endif /* MBEDTLS_SSL_SRV_C */ - ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_ON; + ssl->handshake->early_data = ( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_NEW_API ) + ? MBEDTLS_SSL_EARLY_DATA_STATE_ON + : MBEDTLS_SSL_EARLY_DATA_ON; /* Write extension header */ MBEDTLS_PUT_UINT16_BE( MBEDTLS_TLS_EXT_EARLY_DATA, p, 0 ); diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index 8da0b260a14f..f78610f4bcf7 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -1770,7 +1770,10 @@ static int ssl_tls13_read_end_of_early_data_coordinate( mbedtls_ssl_context *ssl #else /* MBEDTLS_ZERO_RTT */ static int ssl_tls13_read_end_of_early_data_coordinate( mbedtls_ssl_context *ssl ) { - if( ssl->handshake->early_data != MBEDTLS_SSL_EARLY_DATA_ON ) + int early_data_state = ( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_NEW_API ) + ? MBEDTLS_SSL_EARLY_DATA_STATE_ON + : MBEDTLS_SSL_EARLY_DATA_ON; + if( ssl->handshake->early_data != early_data_state ) return( SSL_END_OF_EARLY_DATA_SKIP ); return( SSL_END_OF_EARLY_DATA_EXPECT ); @@ -1939,7 +1942,10 @@ static int ssl_tls13_read_early_data_coordinate( mbedtls_ssl_context *ssl ) { int ret; - if( ssl->handshake->early_data != MBEDTLS_SSL_EARLY_DATA_ON ) + int early_data_state = ( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_NEW_API ) + ? MBEDTLS_SSL_EARLY_DATA_STATE_ON + : MBEDTLS_SSL_EARLY_DATA_ON; + if( ssl->handshake->early_data != early_data_state ) return( SSL_EARLY_DATA_SKIP ); /* Activate early data transform */ @@ -2232,7 +2238,9 @@ static int ssl_tls13_check_use_0rtt_handshake( mbedtls_ssl_context *ssl ) } /* Accept 0-RTT */ - ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_ON; + ssl->handshake->early_data = ( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_NEW_API ) + ? MBEDTLS_SSL_EARLY_DATA_STATE_ON + : MBEDTLS_SSL_EARLY_DATA_ON; return( 0 ); } #endif /* MBEDTLS_ZERO_RTT*/ @@ -2793,7 +2801,10 @@ static int ssl_tls13_client_hello_postprocess( mbedtls_ssl_context *ssl, } #if defined(MBEDTLS_ZERO_RTT) - if( ssl->handshake->early_data == MBEDTLS_SSL_EARLY_DATA_ON ) + int early_data_state = ( ssl->conf->early_data_api == MBEDTLS_SSL_EARLY_DATA_NEW_API ) + ? MBEDTLS_SSL_EARLY_DATA_STATE_ON + : MBEDTLS_SSL_EARLY_DATA_ON; + if( ssl->handshake->early_data == early_data_state ) { mbedtls_ssl_transform *transform_earlydata; diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index d0f640212ebb..03f87fc513da 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -2099,7 +2099,7 @@ int main( int argc, char *argv[] ) mbedtls_ssl_conf_max_tls_version( &conf, opt.max_version ); #if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_ZERO_RTT) - mbedtls_ssl_conf_early_data( &conf, opt.early_data, 0, NULL ); + mbedtls_ssl_conf_early_data( &conf, opt.early_data, 0, MBEDTLS_SSL_EARLY_DATA_OLD_API, NULL ); mbedtls_ssl_set_early_data( &ssl, (const unsigned char*) early_data, strlen( early_data ) ); #endif /* MBEDTLS_SSL_PROTO_TLS1_3 && MBEDTLS_ZERO_RTT */ diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index a97fb8aaa3ca..a1f6d263dbd7 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -2842,6 +2842,7 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_ZERO_RTT) mbedtls_ssl_conf_early_data( &conf, opt.early_data, opt.early_data_max, + MBEDTLS_SSL_EARLY_DATA_OLD_API, early_data_callback ); #endif /* MBEDTLS_ZERO_RTT */ From 3a50d364a977a61914c0d34d560c207eb71734d9 Mon Sep 17 00:00:00 2001 From: Joshua Siegel Date: Tue, 21 Dec 2021 16:31:42 -0500 Subject: [PATCH 3/3] Add tests for new 0-RTT API --- library/ssl_tls13_generic.c | 3 +- library/ssl_tls13_server.c | 2 +- programs/ssl/ssl_client2.c | 72 +++++++++++-- tests/ssl-opt.sh | 205 +++++++++++++++++++++++++++++++++++- 4 files changed, 270 insertions(+), 12 deletions(-) diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index 77af9f420998..e3de11d0fe81 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -2128,8 +2128,7 @@ int mbedtls_ssl_tls13_write_early_data_ext( mbedtls_ssl_context *ssl, if( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_EARLY_DATA ) == 0 ) return( 0 ); - if( ssl->conf->tls13_kex_modes != - MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK || + if( !mbedtls_ssl_conf_tls13_some_psk_enabled( ssl ) || ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_DISABLED ) { MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write early_data extension" ) ); diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index f78610f4bcf7..5ea71aba2fa7 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -1922,7 +1922,7 @@ static int ssl_tls13_early_data_fetch( mbedtls_ssl_context *ssl, } *buf = ssl->in_msg; - *buflen = ssl->in_hslen; + *buflen = ssl->in_msglen; cleanup: diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 03f87fc513da..e25e7305324b 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -65,6 +65,7 @@ int main( void ) #define DFL_KEY_PWD "" #define DFL_PSK "" #define DFL_EARLY_DATA MBEDTLS_SSL_EARLY_DATA_DISABLED +#define DFL_EARLY_DATA_API MBEDTLS_SSL_EARLY_DATA_OLD_API #define DFL_PSK_OPAQUE 0 #define DFL_PSK_IDENTITY "Client_identity" #define DFL_ECJPAKE_PW NULL @@ -349,8 +350,12 @@ int main( void ) #define USAGE_EARLY_DATA \ " early_data=%%d default: 0 (disabled)\n" \ " options: 0 (disabled), 1 (enabled)\n" +#define USAGE_EARLY_DATA_API \ + " early_data_api=%%d default: 0 (old api)\n" \ + " options: 0 (old api), 1 (new api)\n" #else #define USAGE_EARLY_DATA "" +#define USAGE_EARLY_DATA_API "" #endif /* MBEDTLS_ZERO_RTT && MBEDTLS_SSL_PROTO_TLS1_3 */ #if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3) @@ -429,6 +434,7 @@ int main( void ) USAGE_CURVES \ USAGE_SIG_ALGS \ USAGE_EARLY_DATA \ + USAGE_EARLY_DATA_API \ USAGE_NAMED_GROUP \ USAGE_DHMLEN \ "\n" @@ -543,6 +549,7 @@ struct options const char *named_groups_string; /* list of named groups */ const char *key_share_named_groups_string; /* list of named groups */ int early_data; /* support for early data */ + int early_data_api; /* old or new 0-RTT API */ int query_config_mode; /* whether to read config */ int use_srtp; /* Support SRTP */ int force_srtp_profile; /* SRTP protection profile to use or all */ @@ -882,6 +889,7 @@ int main( int argc, char *argv[] ) opt.psk = DFL_PSK; opt.sig_algs = DFL_SIG_ALGS; opt.early_data = DFL_EARLY_DATA; + opt.early_data_api = DFL_EARLY_DATA_API; #if defined(MBEDTLS_USE_PSA_CRYPTO) opt.psk_opaque = DFL_PSK_OPAQUE; #endif @@ -1173,6 +1181,19 @@ int main( int argc, char *argv[] ) default: goto usage; } } + else if( strcmp( p, "early_data_api" ) == 0 ) + { + switch( atoi( q ) ) + { + case 0: + opt.early_data_api = MBEDTLS_SSL_EARLY_DATA_OLD_API; + break; + case 1: + opt.early_data_api = MBEDTLS_SSL_EARLY_DATA_NEW_API; + break; + default: goto usage; + } + } #endif /* MBEDTLS_ZERO_RTT */ #if defined(MBEDTLS_ECP_C) @@ -2099,8 +2120,9 @@ int main( int argc, char *argv[] ) mbedtls_ssl_conf_max_tls_version( &conf, opt.max_version ); #if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_ZERO_RTT) - mbedtls_ssl_conf_early_data( &conf, opt.early_data, 0, MBEDTLS_SSL_EARLY_DATA_OLD_API, NULL ); - mbedtls_ssl_set_early_data( &ssl, (const unsigned char*) early_data, + mbedtls_ssl_conf_early_data( &conf, opt.early_data, 0, opt.early_data_api, NULL ); + if( opt.early_data_api == MBEDTLS_SSL_EARLY_DATA_OLD_API ) + mbedtls_ssl_set_early_data( &ssl, (const unsigned char*) early_data, strlen( early_data ) ); #endif /* MBEDTLS_SSL_PROTO_TLS1_3 && MBEDTLS_ZERO_RTT */ @@ -3183,7 +3205,8 @@ int main( int argc, char *argv[] ) #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */ #if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_ZERO_RTT) - mbedtls_ssl_set_early_data( &ssl, (const unsigned char*) early_data, + if( opt.early_data_api == MBEDTLS_SSL_EARLY_DATA_OLD_API ) + mbedtls_ssl_set_early_data( &ssl, (const unsigned char*) early_data, strlen( early_data ) ); #endif /* MBEDTLS_SSL_PROTO_TLS1_3 && MBEDTLS_ZERO_RTT */ @@ -3209,9 +3232,44 @@ int main( int argc, char *argv[] ) goto exit; } - while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 ) - { - if( ret != MBEDTLS_ERR_SSL_WANT_READ && +#if defined(MBEDTLS_ZERO_RTT) + char early_buf[256]; + int early_count = 0; +#endif + do { +#if defined(MBEDTLS_ZERO_RTT) + if( ( opt.early_data_api == MBEDTLS_SSL_EARLY_DATA_NEW_API ) && + ( mbedtls_ssl_get_early_data_state( &ssl ) == MBEDTLS_SSL_EARLY_DATA_STATE_ENABLED || + mbedtls_ssl_get_early_data_state( &ssl ) == MBEDTLS_SSL_EARLY_DATA_STATE_ON ) ) + { + int early_written = 0; + int early_len = mbedtls_snprintf( early_buf, sizeof( early_buf ), "early data test %d", early_count ); + do { + ret = mbedtls_ssl_write_early_data( &ssl, (const unsigned char*) early_buf + early_written, early_len - early_written ); + if( ret < 0 && + ret != MBEDTLS_ERR_SSL_WANT_READ && + ret != MBEDTLS_ERR_SSL_WANT_WRITE && + ret != MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_write_early_data returned -0x%x\n\n", + (unsigned int) -ret ); + goto exit; + } + + if( ret < 0 ) + continue; + + early_written += ret; + } while ( early_written < early_len ); + + early_buf[ret] = '\0'; + mbedtls_printf( " %zu bytes early data sent: %s\n", ret, early_buf ); + early_count++; + } +#endif + ret = mbedtls_ssl_handshake( &ssl ); + if( ret < 0 && + ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret != MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS ) { @@ -3219,7 +3277,7 @@ int main( int argc, char *argv[] ) (unsigned int) -ret ); goto exit; } - } + } while ( ret != 0 ); mbedtls_printf( " ok\n" ); diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index ef94cd7806a5..3451135ad298 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -833,6 +833,17 @@ find_in_both() { fi } +find_in_both_same_count() { + srv_count=$(sed -n -e "$1" "$2" | sort | uniq -c); + cli_count=$(sed -n -e "$1" "$3" | sort | uniq -c); + + if [ "$srv_count" = "$cli_count" ]; then + return 0; + else + return 1; + fi +} + SKIP_HANDSHAKE_CHECK="NO" skip_handshake_stage_check() { SKIP_HANDSHAKE_CHECK="YES" @@ -2103,6 +2114,104 @@ run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ECDHE-ECDSA, client tries early -c "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" \ -c "early data status = 0" +# early data new api +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_SSL_SRV_C +requires_config_enabled MBEDTLS_SSL_CLI_C +requires_config_enabled MBEDTLS_ZERO_RTT +requires_config_disabled MBEDTLS_SSL_USE_MPS +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ext PSK, early data new api" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls13 early_data=-1 tls13_kex_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls13 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 tls13_kex_modes=psk early_data=1 early_data_api=1 psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early data" \ + -s "<= parse end_of_early_data" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_SSL_SRV_C +requires_config_enabled MBEDTLS_SSL_CLI_C +requires_config_enabled MBEDTLS_ZERO_RTT +requires_config_disabled MBEDTLS_SSL_USE_MPS +run_test "TLS 1.3, TLS1-3-AES-128-CCM-SHA256, ext PSK, early data new api" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls13 early_data=-1 tls13_kex_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls13 force_ciphersuite=TLS1-3-AES-128-CCM-SHA256 tls13_kex_modes=psk early_data=1 early_data_api=1 psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-SHA256" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early data" \ + -s "<= parse end_of_early_data" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_SSL_SRV_C +requires_config_enabled MBEDTLS_SSL_CLI_C +requires_config_enabled MBEDTLS_ZERO_RTT +requires_config_disabled MBEDTLS_SSL_USE_MPS +run_test "TLS 1.3, TLS1-3-AES-128-GCM-SHA256, ext PSK, early data new api" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls13 early_data=-1 tls13_kex_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls13 force_ciphersuite=TLS1-3-AES-128-GCM-SHA256 tls13_kex_modes=psk early_data=1 early_data_api=1 psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-GCM-SHA256" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early data" \ + -s "<= parse end_of_early_data" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_SSL_SRV_C +requires_config_enabled MBEDTLS_SSL_CLI_C +requires_config_enabled MBEDTLS_ZERO_RTT +requires_config_disabled MBEDTLS_SSL_USE_MPS +run_test "TLS 1.3, TLS1-3-AES-128-CCM-8-SHA256, ext PSK, early data new api" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls13 early_data=-1 tls13_kex_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls13 force_ciphersuite=TLS1-3-AES-128-CCM-8-SHA256 tls13_kex_modes=psk early_data=1 early_data_api=1 psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-8-SHA256" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early data" \ + -s "<= parse end_of_early_data" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_SSL_SRV_C +requires_config_enabled MBEDTLS_SSL_CLI_C +requires_config_enabled MBEDTLS_ZERO_RTT +requires_config_disabled MBEDTLS_SSL_USE_MPS +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ECDHE-ECDSA, client tries early data new api without PSK, and falls back to 1-RTT" \ + "$P_SRV crt_file=data_files/server5.crt key_file=data_files/server5.key \ + nbio=2 debug_level=4 force_version=tls13" \ + "$P_CLI nbio=2 debug_level=4 force_version=tls13 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 early_data=1 early_data_api=1" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -c "<= skip write early_data extension" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" \ + -c "early data status = 0" + requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 requires_config_enabled MBEDTLS_DEBUG_C requires_config_enabled MBEDTLS_SSL_SRV_C @@ -2186,7 +2295,7 @@ run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ext PSK, early data status - no "$P_SRV nbio=2 debug_level=5 force_version=tls13 psk=010203 psk_identity=0a0b0c" \ "$P_CLI_ nbio=2 debug_level=5 force_version=tls13 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 psk=010203 psk_identity=0a0b0c" \ 0 \ - -c "early data status = 0" \ + -c "early data status = 0" \ # test early data status - rejected requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 @@ -2211,7 +2320,81 @@ run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ext PSK, early data status - ac "$P_SRV_ nbio=2 debug_level=5 force_version=tls13 early_data=-1 tls13_kex_modes=psk psk=010203 psk_identity=0a0b0c" \ "$P_CLI_ nbio=2 debug_level=5 force_version=tls13 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 tls13_kex_modes=psk early_data=1 psk=010203 psk_identity=0a0b0c" \ 0 \ - -c "early data status = 2" \ + -c "early data status = 2" \ + +# test new early data status - not sent +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_SSL_SRV_C +requires_config_enabled MBEDTLS_SSL_CLI_C +requires_config_enabled MBEDTLS_ZERO_RTT +requires_config_disabled MBEDTLS_SSL_USE_MPS +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ext PSK, early data new api status - not sent" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls13 psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls13 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 psk=010203 psk_identity=0a0b0c early_data_api=1" \ + 0 \ + -c "early data status = 0" \ + +# test new early data status - accepted +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_SSL_SRV_C +requires_config_enabled MBEDTLS_SSL_CLI_C +requires_config_enabled MBEDTLS_ZERO_RTT +requires_config_disabled MBEDTLS_SSL_USE_MPS +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ext PSK, early data new api status - accepted" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls13 tls13_kex_modes=psk psk=010203 psk_identity=0a0b0c early_data=-1" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls13 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 tls13_kex_modes=psk psk=010203 psk_identity=0a0b0c early_data=1 early_data_api=1" \ + 0 \ + -c "early data status = 2" \ + +# test new early data status with resumption - rejected +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_SSL_SRV_C +requires_config_enabled MBEDTLS_SSL_CLI_C +requires_config_enabled MBEDTLS_ZERO_RTT +requires_config_disabled MBEDTLS_SSL_USE_MPS +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ext PSK, early data new api status with resumption - rejected" \ + "$P_SRV crt_file=data_files/server5.crt key_file=data_files/server5.key nbio=2 debug_level=5 force_version=tls13 early_data=0 tickets=1" \ + "$P_CLI crt_file=data_files/cli2.crt key_file=data_files/cli2.key server_name=localhost nbio=2 debug_level=5 force_version=tls13 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 reconnect=1 tickets=1 early_data=1 early_data_api=1 auth_mode=required" \ + 0 \ + -c "early data status, reconnect = 1" \ + -s "<= parse new session ticket" \ + -s "<= skip write early_data extension" \ + -c "early data rejected by server" \ + -c "skip EndOfEarlyData, server rejected" + +# test new early data status with resumption - not sent +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_SSL_SRV_C +requires_config_enabled MBEDTLS_SSL_CLI_C +requires_config_enabled MBEDTLS_ZERO_RTT +requires_config_disabled MBEDTLS_SSL_USE_MPS +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ext PSK, early data new api status with resumption - not sent" \ + "$P_SRV crt_file=data_files/server5.crt key_file=data_files/server5.key nbio=2 debug_level=5 force_version=tls13 early_data=-1 tickets=1" \ + "$P_CLI crt_file=data_files/cli2.crt key_file=data_files/cli2.key server_name=localhost nbio=2 debug_level=5 force_version=tls13 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 reconnect=1 tickets=1 early_data=0 early_data_api=1 auth_mode=required" \ + 0 \ + -c "early data status, reconnect = 0" \ + -s "<= parse new session ticket" + +# test new early data with resumption and multiple sends: +# find_in_both_same_count will verify the count, size, and content +# matches for all early data sent and received +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_SSL_SRV_C +requires_config_enabled MBEDTLS_SSL_CLI_C +requires_config_enabled MBEDTLS_ZERO_RTT +requires_config_disabled MBEDTLS_SSL_USE_MPS +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ext PSK, early data new api multiple sends" \ + "$P_SRV crt_file=data_files/server5.crt key_file=data_files/server5.key nbio=2 debug_level=5 force_version=tls13 early_data=-1 tickets=1" \ + "$P_CLI crt_file=data_files/cli2.crt key_file=data_files/cli2.key server_name=localhost nbio=2 debug_level=5 force_version=tls13 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 reconnect=1 tickets=1 early_data=1 early_data_api=1 auth_mode=required" \ + 0 \ + -c "early data status, reconnect = 2" \ + -s "<= parse new session ticket" \ + -g "find_in_both_same_count 's/^\(.*bytes early data\).*\(:.*\)$/\1\2/p'" requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 requires_config_enabled MBEDTLS_DEBUG_C @@ -2272,6 +2455,24 @@ run_test "TLS 1.3, TLS1-3-AES-128-GCM-SHA256, reject early data, OpenSSL serv -c "skip EndOfEarlyData, server rejected" \ -c "early data status, reconnect = 1" +# Test OpenSSL server with resumption and reject early data new api +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_SSL_CLI_C +requires_config_disabled MBEDTLS_SSL_USE_MPS +requires_openssl_with_tls1_3 +run_test "TLS 1.3, TLS1-3-AES-128-GCM-SHA256, reject early data new api, OpenSSL server" \ + "$O_SRV" \ + "$P_CLI debug_level=5 force_version=tls13 server_name=localhost \ + force_ciphersuite=TLS1-3-AES-128-GCM-SHA256 reconnect=1 tickets=1 \ + early_data=1 early_data_api=1" \ + 0 \ + -c "=> prepare early data" \ + -c "=> mbedtls_ssl_tls1_3_generate_early_data_keys" \ + -c "=> write early_data" \ + -c "skip EndOfEarlyData, server rejected" \ + -c "early data status, reconnect = 1" + requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 requires_config_enabled MBEDTLS_DEBUG_C requires_config_enabled MBEDTLS_SSL_SRV_C