Merge pull request #6486 from xkqian/tls13_add_early_data_indication
The merge job of the internal CI ran successfully. This is good to go.
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index d36db4a..3918639 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -842,10 +842,10 @@
"but no key exchange methods defined with MBEDTLS_KEY_EXCHANGE_xxxx"
#endif
-/* Early data requires PSK related mode defined */
#if defined(MBEDTLS_SSL_EARLY_DATA) && \
- ( !defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED) && \
- !defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED))
+ ( !defined(MBEDTLS_SSL_SESSION_TICKETS) || \
+ ( !defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED) && \
+ !defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED) ) )
#error "MBEDTLS_SSL_EARLY_DATA defined, but not all prerequisites"
#endif
diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h
index b4c8635..3f869b9 100644
--- a/include/mbedtls/mbedtls_config.h
+++ b/include/mbedtls/mbedtls_config.h
@@ -1637,7 +1637,8 @@
*
* Enable support for RFC 8446 TLS 1.3 early data.
*
-* Requires: MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED or
+* Requires: MBEDTLS_SSL_SESSION_TICKETS and either
+* MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED or
* MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
*
* Comment this to disable support for early data. If MBEDTLS_SSL_PROTO_TLS1_3
@@ -1647,7 +1648,7 @@
* production.
*
*/
-//#define MBEDTLS_SSL_EARLY_DATA
+#define MBEDTLS_SSL_EARLY_DATA
/**
* \def MBEDTLS_SSL_PROTO_DTLS
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 01ede40..d055851 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -801,6 +801,29 @@
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_STATUS_UNKNOWN 0
+#define MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT 1
+#define MBEDTLS_SSL_EARLY_DATA_STATUS_INDICATION_SENT 2
+#define MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED 3
+#define MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED 4
+#endif
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS)
+typedef uint8_t mbedtls_ssl_tls13_ticket_flags;
+
+#define MBEDTLS_SSL_TLS1_3_TICKET_ALLOW_PSK_RESUMPTION \
+ MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK /* 1U << 0 */
+#define MBEDTLS_SSL_TLS1_3_TICKET_ALLOW_PSK_EPHEMERAL_RESUMPTION \
+ MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL /* 1U << 2 */
+#define MBEDTLS_SSL_TLS1_3_TICKET_ALLOW_EARLY_DATA ( 1U << 3 )
+
+#define MBEDTLS_SSL_TLS1_3_TICKET_FLAGS_MASK \
+ ( MBEDTLS_SSL_TLS1_3_TICKET_ALLOW_PSK_RESUMPTION | \
+ MBEDTLS_SSL_TLS1_3_TICKET_ALLOW_PSK_EPHEMERAL_RESUMPTION | \
+ MBEDTLS_SSL_TLS1_3_TICKET_ALLOW_EARLY_DATA )
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 && MBEDTLS_SSL_SESSION_TICKETS */
+
/**
* \brief Callback type: server-side session cache getter
*
@@ -1783,6 +1806,10 @@
* and #MBEDTLS_SSL_CID_DISABLED. */
#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C)
+ 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 */
diff --git a/library/ssl_misc.h b/library/ssl_misc.h
index ad8754c..4d7f635 100644
--- a/library/ssl_misc.h
+++ b/library/ssl_misc.h
@@ -2046,6 +2046,12 @@
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 *out_len );
+#endif /* MBEDTLS_SSL_EARLY_DATA */
#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c
index 9940a0e..0372f2d 100644
--- a/library/ssl_tls13_client.c
+++ b/library/ssl_tls13_client.c
@@ -700,6 +700,19 @@
session != NULL && session->ticket != NULL );
}
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+static int ssl_tls13_early_data_has_valid_ticket( mbedtls_ssl_context *ssl )
+{
+ mbedtls_ssl_session *session = ssl->session_negotiate;
+ return( ssl->handshake->resume &&
+ session->tls_version == MBEDTLS_SSL_VERSION_TLS1_3 &&
+ ( session->ticket_flags &
+ MBEDTLS_SSL_TLS1_3_TICKET_ALLOW_EARLY_DATA ) &&
+ mbedtls_ssl_tls13_cipher_suite_is_offered(
+ ssl, session->ciphersuite ) );
+}
+#endif
+
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_tls13_ticket_get_identity( mbedtls_ssl_context *ssl,
psa_algorithm_t *hash_alg,
@@ -1160,6 +1173,29 @@
}
#endif
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+ if( mbedtls_ssl_conf_tls13_some_psk_enabled( ssl ) &&
+ ssl_tls13_early_data_has_valid_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;
+
+ /* Initializes the status to `indication sent`. It will be updated to
+ * `accepted` or `rejected` depending on whether the EncryptedExtension
+ * message will contain an early data indication extension or not.
+ */
+ ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_STATUS_INDICATION_SENT;
+ }
+ else
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write early_data extension" ) );
+ ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT;
+ }
+#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.
@@ -2505,6 +2541,23 @@
switch( extension_type )
{
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+ case MBEDTLS_TLS_EXT_EARLY_DATA:
+ if( extension_data_len != 4 )
+ {
+ MBEDTLS_SSL_PEND_FATAL_ALERT(
+ MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR,
+ MBEDTLS_ERR_SSL_DECODE_ERROR );
+ return( MBEDTLS_ERR_SSL_DECODE_ERROR );
+ }
+ if( ssl->session != NULL )
+ {
+ ssl->session->ticket_flags |=
+ MBEDTLS_SSL_TLS1_3_TICKET_ALLOW_EARLY_DATA;
+ }
+ break;
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
default:
MBEDTLS_SSL_PRINT_EXT(
3, MBEDTLS_SSL_HS_NEW_SESSION_TICKET,
diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c
index f854998..761c00e 100644
--- a/library/ssl_tls13_generic.c
+++ b/library/ssl_tls13_generic.c
@@ -1374,6 +1374,39 @@
#endif /* MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE */
+/* Early Data Indication Extension
+ *
+ * struct {
+ * select ( Handshake.msg_type ) {
+ * ...
+ * 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_PUT_UINT16_BE( MBEDTLS_TLS_EXT_EARLY_DATA, p, 0 );
+ MBEDTLS_PUT_UINT16_BE( 0, p, 2 );
+
+ *out_len = 4;
+
+ mbedtls_ssl_tls13_set_hs_sent_ext_mask( ssl, MBEDTLS_TLS_EXT_EARLY_DATA );
+
+ 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 56efb3c..6aa295d 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -64,6 +64,7 @@
#define DFL_KEY_OPAQUE 0
#define DFL_KEY_PWD ""
#define DFL_PSK ""
+#define DFL_EARLY_DATA MBEDTLS_SSL_EARLY_DATA_DISABLED
#define DFL_PSK_OPAQUE 0
#define DFL_PSK_IDENTITY "Client_identity"
#define DFL_ECJPAKE_PW NULL
@@ -344,6 +345,14 @@
#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" \
@@ -422,6 +431,7 @@
USAGE_REPRODUCIBLE \
USAGE_CURVES \
USAGE_SIG_ALGS \
+ USAGE_EARLY_DATA \
USAGE_DHMLEN \
USAGE_KEY_OPAQUE_ALGS \
"\n"
@@ -533,6 +543,9 @@
* after renegotiation */
int reproducible; /* make communication reproducible */
int skip_close_notify; /* skip sending the close_notify alert */
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+ int early_data; /* support for early data */
+#endif
int query_config_mode; /* whether to read config */
int use_srtp; /* Support SRTP */
int force_srtp_profile; /* SRTP protection profile to use or all */
@@ -932,6 +945,9 @@
opt.alpn_string = DFL_ALPN_STRING;
opt.curves = DFL_CURVES;
opt.sig_algs = DFL_SIG_ALGS;
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+ opt.early_data = DFL_EARLY_DATA;
+#endif
opt.transport = DFL_TRANSPORT;
opt.hs_to_min = DFL_HS_TO_MIN;
opt.hs_to_max = DFL_HS_TO_MAX;
@@ -1189,7 +1205,24 @@
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 +2124,10 @@
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",
diff --git a/tests/opt-testcases/tls13-misc.sh b/tests/opt-testcases/tls13-misc.sh
index 4ad6faa..3e2fd0b 100755
--- a/tests/opt-testcases/tls13-misc.sh
+++ b/tests/opt-testcases/tls13-misc.sh
@@ -282,3 +282,62 @@
0 \
-s "key exchange mode: ephemeral$"
+requires_gnutls_tls1_3
+requires_config_enabled MBEDTLS_DEBUG_C
+requires_config_enabled MBEDTLS_SSL_CLI_C
+requires_all_configs_enabled MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE \
+ MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED \
+ MBEDTLS_SSL_EARLY_DATA
+requires_any_configs_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED \
+ MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED
+run_test "TLS 1.3 m->G: EarlyData: basic check, good" \
+ "$G_NEXT_SRV -d 10 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:+CIPHER-ALL:+ECDHE-PSK:+PSK --earlydata --disable-client-cert" \
+ "$P_CLI debug_level=4 early_data=1 reco_mode=1 reconnect=1 reco_delay=2" \
+ 1 \
+ -c "Reconnecting with saved session" \
+ -c "NewSessionTicket: early_data(42) extension received." \
+ -c "ClientHello: early_data(42) extension exists." \
+ -c "EncryptedExtensions: early_data(42) extension received." \
+ -c "EncryptedExtensions: early_data(42) extension ( ignored )." \
+ -s "Parsing extension 'Early Data/42' (0 bytes)" \
+ -s "Sending extension Early Data/42 (0 bytes)" \
+ -s "early data accepted"
+
+requires_gnutls_tls1_3
+requires_config_enabled MBEDTLS_DEBUG_C
+requires_config_enabled MBEDTLS_SSL_CLI_C
+requires_all_configs_enabled MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE \
+ MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED \
+ MBEDTLS_SSL_EARLY_DATA
+requires_any_configs_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED \
+ MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED
+run_test "TLS 1.3 m->G: EarlyData: no early_data in NewSessionTicket, good" \
+ "$G_NEXT_SRV -d 10 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:+CIPHER-ALL:+ECDHE-PSK:+PSK --disable-client-cert" \
+ "$P_CLI debug_level=4 early_data=1 reco_mode=1 reconnect=1 reco_delay=2" \
+ 0 \
+ -c "Reconnecting with saved session" \
+ -C "NewSessionTicket: early_data(42) extension received." \
+ -c "ClientHello: early_data(42) extension does not exist." \
+ -C "EncryptedExtensions: early_data(42) extension received." \
+ -C "EncryptedExtensions: early_data(42) extension ( ignored )."
+
+#TODO: OpenSSL tests don't work now. It might be openssl options issue, cause GnuTLS has worked.
+skip_next_test
+requires_openssl_tls1_3
+requires_config_enabled MBEDTLS_DEBUG_C
+requires_config_enabled MBEDTLS_SSL_CLI_C
+requires_all_configs_enabled MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE \
+ MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED \
+ MBEDTLS_SSL_EARLY_DATA
+requires_any_configs_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED \
+ MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED
+run_test "TLS 1.3, ext PSK, early data" \
+ "$O_NEXT_SRV_EARLY_DATA -msg -debug -tls1_3 -psk_identity 0a0b0c -psk 010203 -allow_no_dhe_kex -nocert" \
+ "$P_CLI debug_level=5 force_version=tls13 tls13_kex_modes=psk early_data=1 psk=010203 psk_identity=0a0b0c" \
+ 1 \
+ -c "Reconnecting with saved session" \
+ -c "NewSessionTicket: early_data(42) extension received." \
+ -c "ClientHello: early_data(42) extension exists." \
+ -c "EncryptedExtensions: early_data(42) extension received." \
+ -c "EncryptedExtensions: early_data(42) extension ( ignored )."
+
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 9295c9d..245324a 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -3253,6 +3253,7 @@
msg "build: TLS 1.3 only from default, only ephemeral key exchange mode"
scripts/config.py unset MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED
scripts/config.py unset MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
+ scripts/config.py unset MBEDTLS_SSL_EARLY_DATA
make CFLAGS="'-DMBEDTLS_USER_CONFIG_FILE=\"../tests/configs/tls13-only.h\"'"
msg "test_suite_ssl: TLS 1.3 only, only ephemeral key exchange mode"
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 9eb925a..fdbb310 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -80,12 +80,14 @@
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_EARLY_DATA="$OPENSSL_NEXT s_server -early_data -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_EARLY_DATA=false
O_NEXT_CLI_NO_CERT=false
O_NEXT_CLI=false
fi
@@ -1690,6 +1692,7 @@
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_EARLY_DATA="$O_NEXT_SRV_EARLY_DATA -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