From 0e97d4d16dcf4d90fdac381a3c0ec7cd68fd29f2 Mon Sep 17 00:00:00 2001 From: Xiaokang Qian Date: Mon, 24 Oct 2022 11:12:51 +0000 Subject: [PATCH] Add early data indication to client side Add fields to mbedtls_ssl_context Add write early data indication function Add check whether write early data indication Add early data option to ssl_client2 Add test cases for early data Signed-off-by: Xiaokang Qian --- include/mbedtls/build_info.h | 4 ++++ include/mbedtls/ssl.h | 16 ++++++++++++++ library/ssl_misc.h | 19 ++++++++++++++++ library/ssl_tls.c | 9 ++++++++ library/ssl_tls13_client.c | 39 +++++++++++++++++++++++---------- library/ssl_tls13_generic.c | 35 ++++++++++++++++++++++++++++++ programs/ssl/ssl_client2.c | 42 ++++++++++++++++++++++++++++++++++++ tests/configs/tls13-only.h | 1 + tests/ssl-opt.sh | 18 ++++++++++++++++ 9 files changed, 172 insertions(+), 11 deletions(-) diff --git a/include/mbedtls/build_info.h b/include/mbedtls/build_info.h index 170cbebbe..f1bb52770 100644 --- a/include/mbedtls/build_info.h +++ b/include/mbedtls/build_info.h @@ -112,6 +112,10 @@ #undef MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED #undef MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED #undef MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED +#endif + +#if !defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED) && \ + !defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED) #undef MBEDTLS_SSL_EARLY_DATA #endif diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 01ede4088..47ce3c695 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -332,6 +332,9 @@ #define MBEDTLS_SSL_EARLY_DATA_DISABLED 0 #define MBEDTLS_SSL_EARLY_DATA_ENABLED 1 +#define MBEDTLS_SSL_EARLY_DATA_OFF 0 +#define MBEDTLS_SSL_EARLY_DATA_ON 1 + #define MBEDTLS_SSL_DTLS_SRTP_MKI_UNSUPPORTED 0 #define MBEDTLS_SSL_DTLS_SRTP_MKI_SUPPORTED 1 @@ -801,6 +804,11 @@ typedef struct mbedtls_ssl_key_cert mbedtls_ssl_key_cert; typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; #endif +#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C) +#define MBEDTLS_SSL_EARLY_DATA_NOT_SENT 0 +#define MBEDTLS_SSL_EARLY_DATA_REJECTED 1 +#define MBEDTLS_SSL_EARLY_DATA_ACCEPTED 2 +#endif /** * \brief Callback type: server-side session cache getter * @@ -1783,6 +1791,13 @@ struct mbedtls_ssl_context * and #MBEDTLS_SSL_CID_DISABLED. */ #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ +#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C) + /* + * early data request state + */ + int MBEDTLS_PRIVATE(early_data_status); +#endif /* MBEDTLS_SSL_EARLY_DATA && MBEDTLS_SSL_CLI_C */ + /** Callback to export key block and master secret */ mbedtls_ssl_export_keys_t *MBEDTLS_PRIVATE(f_export_keys); void *MBEDTLS_PRIVATE(p_export_keys); /*!< context for key export callback */ @@ -1936,6 +1951,7 @@ void mbedtls_ssl_conf_authmode( mbedtls_ssl_config *conf, int authmode ); */ void mbedtls_ssl_tls13_conf_early_data( mbedtls_ssl_config *conf, int early_data_enabled ); + #endif /* MBEDTLS_SSL_PROTO_TLS1_3 && MBEDTLS_SSL_EARLY_DATA */ #if defined(MBEDTLS_X509_CRT_PARSE_C) diff --git a/library/ssl_misc.h b/library/ssl_misc.h index ad8754cac..2b1f90f4f 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -987,6 +987,15 @@ struct mbedtls_ssl_handshake_params } tls13_master_secrets; mbedtls_ssl_tls13_handshake_secrets tls13_hs_secrets; + +#if defined(MBEDTLS_SSL_EARLY_DATA) + mbedtls_ssl_tls13_early_secrets early_secrets; + + int early_data; /*!< Early data indication: + * 0 -- MBEDTLS_SSL_EARLY_DATA_DISABLED (for no early data), and + * 1 -- MBEDTLS_SSL_EARLY_DATA_ENABLED (for use early data) + */ +#endif /* MBEDTLS_SSL_EARLY_DATA */ #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */ #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) @@ -1480,6 +1489,11 @@ int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, #endif /* !MBEDTLS_USE_PSA_CRYPTO */ #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ +#if defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_SESSION_TICKETS) +MBEDTLS_CHECK_RETURN_CRITICAL +int mbedtls_ssl_tls13_has_configured_ticket( mbedtls_ssl_context *ssl ); +#endif + #if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED) #if defined(MBEDTLS_SSL_CLI_C) MBEDTLS_CHECK_RETURN_CRITICAL @@ -2046,6 +2060,11 @@ int mbedtls_ssl_tls13_generate_and_write_ecdh_key_exchange( size_t *out_len ); #endif /* MBEDTLS_ECDH_C */ +#if defined(MBEDTLS_SSL_EARLY_DATA) +int mbedtls_ssl_tls13_write_early_data_ext( + mbedtls_ssl_context *ssl, + unsigned char *buf, const unsigned char *end, size_t *olen); +#endif /* MBEDTLS_SSL_EARLY_DATA */ #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */ diff --git a/library/ssl_tls.c b/library/ssl_tls.c index da90b2350..945a2e9bd 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -1872,6 +1872,15 @@ int mbedtls_ssl_set_hs_ecjpake_password( mbedtls_ssl_context *ssl, } #endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +int mbedtls_ssl_tls13_has_configured_ticket( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_session *session = ssl->session_negotiate; + return( ssl->handshake->resume && + session != NULL && session->ticket != NULL ); +} +#endif + #if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED) int mbedtls_ssl_conf_has_static_psk( mbedtls_ssl_config const *conf ) { diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index 9940a0e5e..0d24474ec 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -693,13 +693,6 @@ static psa_algorithm_t ssl_tls13_get_ciphersuite_hash_alg( int ciphersuite ) } #if defined(MBEDTLS_SSL_SESSION_TICKETS) -static int ssl_tls13_has_configured_ticket( mbedtls_ssl_context *ssl ) -{ - mbedtls_ssl_session *session = ssl->session_negotiate; - return( ssl->handshake->resume && - session != NULL && session->ticket != NULL ); -} - MBEDTLS_CHECK_RETURN_CRITICAL static int ssl_tls13_ticket_get_identity( mbedtls_ssl_context *ssl, psa_algorithm_t *hash_alg, @@ -708,7 +701,7 @@ static int ssl_tls13_ticket_get_identity( mbedtls_ssl_context *ssl, { mbedtls_ssl_session *session = ssl->session_negotiate; - if( !ssl_tls13_has_configured_ticket( ssl ) ) + if( !mbedtls_ssl_tls13_has_configured_ticket( ssl ) ) return( -1 ); *hash_alg = ssl_tls13_get_ciphersuite_hash_alg( session->ciphersuite ); @@ -726,7 +719,7 @@ static int ssl_tls13_ticket_get_psk( mbedtls_ssl_context *ssl, mbedtls_ssl_session *session = ssl->session_negotiate; - if( !ssl_tls13_has_configured_ticket( ssl ) ) + if( !mbedtls_ssl_tls13_has_configured_ticket( ssl ) ) return( -1 ); *hash_alg = ssl_tls13_get_ciphersuite_hash_alg( session->ciphersuite ); @@ -773,7 +766,7 @@ static int ssl_tls13_get_configured_psk_count( mbedtls_ssl_context *ssl ) { int configured_psk_count = 0; #if defined(MBEDTLS_SSL_SESSION_TICKETS) - if( ssl_tls13_has_configured_ticket( ssl ) ) + if( mbedtls_ssl_tls13_has_configured_ticket( ssl ) ) { MBEDTLS_SSL_DEBUG_MSG( 3, ( "Ticket is configured" ) ); configured_psk_count++; @@ -1093,7 +1086,8 @@ static int ssl_tls13_parse_server_pre_shared_key_ext( mbedtls_ssl_context *ssl, } #if defined(MBEDTLS_SSL_SESSION_TICKETS) - if( selected_identity == 0 && ssl_tls13_has_configured_ticket( ssl ) ) + if( selected_identity == 0 && + mbedtls_ssl_tls13_has_configured_ticket( ssl ) ) { ret = ssl_tls13_ticket_get_psk( ssl, &hash_alg, &psk, &psk_len ); } @@ -1160,6 +1154,29 @@ int mbedtls_ssl_tls13_write_client_hello_exts( mbedtls_ssl_context *ssl, } #endif +#if defined(MBEDTLS_SSL_EARLY_DATA) + if( mbedtls_ssl_conf_tls13_some_psk_enabled( ssl ) && + ( mbedtls_ssl_conf_has_static_psk( ssl->conf ) == 1 || + mbedtls_ssl_tls13_has_configured_ticket( ssl ) ) && + ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_ENABLED ) + { + ret = mbedtls_ssl_tls13_write_early_data_ext( ssl, p, end, &ext_len ); + if( ret != 0 ) + return( ret ); + p += ext_len; + + ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_ON; + /* We're using rejected once we send the EarlyData extension, + and change it to accepted upon receipt of the server extension. */ + ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_REJECTED; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write early_data extension" ) ); + ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_OFF; + } +#endif /* MBEDTLS_SSL_EARLY_DATA */ + #if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_PSK_ENABLED) /* For PSK-based key exchange we need the pre_shared_key extension * and the psk_key_exchange_modes extension. diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index f85499889..875748753 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -1374,6 +1374,41 @@ cleanup: #endif /* MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE */ +/* Early Data Extension + * + * struct {} Empty; + * + * struct { + * select ( Handshake.msg_type ) { + * case new_session_ticket: uint32 max_early_data_size; + * case client_hello: Empty; + * case encrypted_extensions: Empty; + * }; + * } EarlyDataIndication; + */ +#if defined(MBEDTLS_SSL_EARLY_DATA) +int mbedtls_ssl_tls13_write_early_data_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + const unsigned char *end, + size_t *out_len ) +{ + unsigned char *p = buf; + *out_len = 0; + ((void) ssl); + + MBEDTLS_SSL_CHK_BUF_PTR( p, end, 4 ); + MBEDTLS_SSL_DEBUG_MSG( + 3, ( "client hello, adding early_data extension" ) ); + + MBEDTLS_PUT_UINT16_BE( MBEDTLS_TLS_EXT_EARLY_DATA, p, 0 ); + /* Write length of the early data indication extension */ + MBEDTLS_PUT_UINT16_BE( 0, p, 2 ); + + *out_len = 4; + return( 0 ); +} +#endif /* MBEDTLS_SSL_EARLY_DATA */ + /* Reset SSL context and update hash for handling HRR. * * Replace Transcript-Hash(X) by diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 56efb3c17..9685e69d4 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -344,6 +344,14 @@ int main( void ) #define USAGE_SERIALIZATION "" #endif +#if defined(MBEDTLS_SSL_EARLY_DATA) +#define USAGE_EARLY_DATA \ + " early_data=%%d default: 0 (disabled)\n" \ + " options: 0 (disabled), 1 (enabled)\n" +#else +#define USAGE_EARLY_DATA "" +#endif /* MBEDTLS_SSL_EARLY_DATA && MBEDTLS_SSL_PROTO_TLS1_3 */ + #define USAGE_KEY_OPAQUE_ALGS \ " key_opaque_algs=%%s Allowed opaque key algorithms.\n" \ " comma-separated pair of values among the following:\n" \ @@ -533,6 +541,7 @@ struct options * after renegotiation */ int reproducible; /* make communication reproducible */ int skip_close_notify; /* skip sending the close_notify alert */ + int early_data; /* support for early data */ int query_config_mode; /* whether to read config */ int use_srtp; /* Support SRTP */ int force_srtp_profile; /* SRTP protection profile to use or all */ @@ -1189,7 +1198,24 @@ int main( int argc, char *argv[] ) default: goto usage; } } + #if defined(MBEDTLS_SSL_PROTO_TLS1_3) +#if defined(MBEDTLS_SSL_EARLY_DATA) + else if( strcmp( p, "early_data" ) == 0 ) + { + switch( atoi( q ) ) + { + case 0: + opt.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED; + break; + case 1: + opt.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED; + break; + default: goto usage; + } + } +#endif /* MBEDTLS_SSL_EARLY_DATA */ + else if( strcmp( p, "tls13_kex_modes" ) == 0 ) { if( strcmp( q, "psk" ) == 0 ) @@ -2091,6 +2117,10 @@ int main( int argc, char *argv[] ) if( opt.max_version != DFL_MAX_VERSION ) mbedtls_ssl_conf_max_tls_version( &conf, opt.max_version ); +#if defined(MBEDTLS_SSL_EARLY_DATA) + mbedtls_ssl_tls13_conf_early_data( &conf, opt.early_data ); +#endif /* MBEDTLS_SSL_EARLY_DATA */ + if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_setup returned -0x%x\n\n", @@ -2467,6 +2497,12 @@ int main( int argc, char *argv[] ) } } +#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C) + /* TODO: We can log the actual early data status after we define + * the API mbedtls_ssl_get_early_data_status. + */ +#endif /* MBEDTLS_SSL_EARLY_DATA && MBEDTLS_SSL_CLI_C */ + #if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED) /* * 5. Verify the server certificate @@ -3177,6 +3213,12 @@ reconnect: mbedtls_printf( " ok\n" ); +#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C) + /* TODO: We can log the actual early data status when reconnect + * after we define the API mbedtls_ssl_get_early_data_status. + */ +#endif /* MBEDTLS_SSL_EARLY_DATA && MBEDTLS_SSL_CLI_C */ + goto send_request; } diff --git a/tests/configs/tls13-only.h b/tests/configs/tls13-only.h index 7483f1cd9..a4dcb92ba 100644 --- a/tests/configs/tls13-only.h +++ b/tests/configs/tls13-only.h @@ -24,6 +24,7 @@ /* Enable TLS 1.3 and core 1.3 features */ #define MBEDTLS_SSL_PROTO_TLS1_3 +#define MBEDTLS_SSL_EARLY_DATA #define MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE /* Disable TLS 1.2 and 1.2-specific features */ diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 9eb925aa1..14123fa9a 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -80,12 +80,14 @@ fi if [ -n "${OPENSSL_NEXT:-}" ]; then O_NEXT_SRV="$OPENSSL_NEXT s_server -www -cert data_files/server5.crt -key data_files/server5.key" + O_NEXT_SRV_NO_WWW="$OPENSSL_NEXT s_server -cert data_files/server5.crt -key data_files/server5.key" O_NEXT_SRV_NO_CERT="$OPENSSL_NEXT s_server -www " O_NEXT_CLI="echo 'GET / HTTP/1.0' | $OPENSSL_NEXT s_client -CAfile data_files/test-ca_cat12.crt" O_NEXT_CLI_NO_CERT="echo 'GET / HTTP/1.0' | $OPENSSL_NEXT s_client" else O_NEXT_SRV=false O_NEXT_SRV_NO_CERT=false + O_NEXT_SRV_NO_WWW=false O_NEXT_CLI_NO_CERT=false O_NEXT_CLI=false fi @@ -1690,6 +1692,7 @@ fi if [ -n "${OPENSSL_NEXT:-}" ]; then O_NEXT_SRV="$O_NEXT_SRV -accept $SRV_PORT" O_NEXT_SRV_NO_CERT="$O_NEXT_SRV_NO_CERT -accept $SRV_PORT" + O_NEXT_SRV_NO_WWW="$O_NEXT_SRV_NO_WWW -accept $SRV_PORT" O_NEXT_CLI="$O_NEXT_CLI -connect 127.0.0.1:+SRV_PORT" O_NEXT_CLI_NO_CERT="$O_NEXT_CLI_NO_CERT -connect 127.0.0.1:+SRV_PORT" fi @@ -13039,6 +13042,21 @@ run_test "TLS 1.3: NewSessionTicket: servername negative check, m->m" \ -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET" \ -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET_FLUSH" +requires_openssl_next +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_SSL_EARLY_DATA +run_test "TLS 1.3, ext PSK, early data" \ + "$O_NEXT_SRV_NO_WWW -msg -debug -tls1_3 -early_data -psk_identity 0a0b0c -psk 010203 -allow_no_dhe_kex -nocert" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls13 tls13_kex_modes=psk early_data=1 psk=010203 psk_identity=0a0b0c" \ + 1 \ + -c "=> write client hello" \ + -c "client hello, adding early_data extension" \ + -c "<= write client hello" \ + -c "client state: MBEDTLS_SSL_SERVER_HELLO" + # Test heap memory usage after handshake requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2 requires_config_enabled MBEDTLS_MEMORY_DEBUG