Merge pull request #6180 from yuhaoth/pr/add-tls13-multiple-session-tickets
TLS 1.3: NewSessionTicket: Add support for sending multiple tickets per session.
diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h
index 8359a9f..9e8ae37 100644
--- a/include/mbedtls/mbedtls_config.h
+++ b/include/mbedtls/mbedtls_config.h
@@ -1580,6 +1580,16 @@
#define MBEDTLS_SSL_TLS1_3_TICKET_NONCE_LENGTH 32
/**
+ * \def MBEDTLS_SSL_TLS1_3_DEFAULT_NEW_SESSION_TICKETS
+ *
+ * Default number of NewSessionTicket messages to be sent by a TLS 1.3 server
+ * after handshake completion. This is not used in TLS 1.2 and relevant only if
+ * the MBEDTLS_SSL_SESSION_TICKETS option is enabled.
+ *
+ */
+#define MBEDTLS_SSL_TLS1_3_DEFAULT_NEW_SESSION_TICKETS 1
+
+/**
* \def MBEDTLS_SSL_PROTO_DTLS
*
* Enable support for DTLS (all available versions).
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index b40b4f4..eda6bc2 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -1323,9 +1323,17 @@
#if defined(MBEDTLS_SSL_RENEGOTIATION)
uint8_t MBEDTLS_PRIVATE(disable_renegotiation); /*!< disable renegotiation? */
#endif
-#if defined(MBEDTLS_SSL_SESSION_TICKETS)
- uint8_t MBEDTLS_PRIVATE(session_tickets); /*!< use session tickets? */
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && \
+ defined(MBEDTLS_SSL_CLI_C)
+ uint8_t MBEDTLS_PRIVATE(session_tickets); /*!< use session tickets? */
#endif
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && \
+ defined(MBEDTLS_SSL_SRV_C) && \
+ defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ uint16_t MBEDTLS_PRIVATE(new_session_tickets_count); /*!< number of NewSessionTicket */
+#endif
+
#if defined(MBEDTLS_SSL_SRV_C)
uint8_t MBEDTLS_PRIVATE(cert_req_ca_list); /*!< enable sending CA list in
Certificate Request messages? */
@@ -4103,7 +4111,8 @@
void mbedtls_ssl_conf_preference_order( mbedtls_ssl_config *conf, int order );
#endif /* MBEDTLS_SSL_SRV_C */
-#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && \
+ defined(MBEDTLS_SSL_CLI_C)
/**
* \brief Enable / Disable session tickets (client only).
* (Default: MBEDTLS_SSL_SESSION_TICKETS_ENABLED.)
@@ -4115,7 +4124,34 @@
* MBEDTLS_SSL_SESSION_TICKETS_DISABLED)
*/
void mbedtls_ssl_conf_session_tickets( mbedtls_ssl_config *conf, int use_tickets );
-#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
+#endif /* MBEDTLS_SSL_SESSION_TICKETS &&
+ MBEDTLS_SSL_CLI_C */
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && \
+ defined(MBEDTLS_SSL_SRV_C) && \
+ defined(MBEDTLS_SSL_PROTO_TLS1_3)
+/**
+ * \brief Number of NewSessionTicket messages for the server to send
+ * after handshake completion.
+ *
+ * \note The default value is
+ * \c MBEDTLS_SSL_TLS1_3_DEFAULT_NEW_SESSION_TICKETS.
+ *
+ * \note In case of a session resumption, this setting only partially apply.
+ * At most one ticket is sent in that case to just renew the pool of
+ * tickets of the client. The rationale is to avoid the number of
+ * tickets on the server to become rapidly out of control when the
+ * server has the same configuration for all its connection instances.
+ *
+ * \param conf SSL configuration
+ * \param num_tickets Number of NewSessionTicket.
+ *
+ */
+void mbedtls_ssl_conf_new_session_tickets( mbedtls_ssl_config *conf,
+ uint16_t num_tickets );
+#endif /* MBEDTLS_SSL_SESSION_TICKETS &&
+ MBEDTLS_SSL_SRV_C &&
+ MBEDTLS_SSL_PROTO_TLS1_3*/
#if defined(MBEDTLS_SSL_RENEGOTIATION)
/**
diff --git a/library/ssl_misc.h b/library/ssl_misc.h
index 2e35e6c..afacb76 100644
--- a/library/ssl_misc.h
+++ b/library/ssl_misc.h
@@ -624,6 +624,9 @@
#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
uint8_t tls13_kex_modes; /*!< Key exchange modes supported by the client */
#endif
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ uint16_t new_session_tickets_count; /*!< number of session tickets */
+#endif
#endif /* MBEDTLS_SSL_SRV_C */
#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 12e1c1b..f0615ea 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -763,6 +763,13 @@
mbedtls_ssl_transform_init( ssl->transform_negotiate );
ssl_handshake_params_init( ssl->handshake );
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && \
+ defined(MBEDTLS_SSL_SRV_C) && \
+ defined(MBEDTLS_SSL_SESSION_TICKETS)
+ ssl->handshake->new_session_tickets_count =
+ ssl->conf->new_session_tickets_count ;
+#endif
+
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
{
@@ -2611,6 +2618,15 @@
#endif
#if defined(MBEDTLS_SSL_SRV_C)
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS)
+void mbedtls_ssl_conf_new_session_tickets( mbedtls_ssl_config *conf,
+ uint16_t num_tickets )
+{
+ conf->new_session_tickets_count = num_tickets;
+}
+#endif
+
void mbedtls_ssl_conf_session_tickets_cb( mbedtls_ssl_config *conf,
mbedtls_ssl_ticket_write_t *f_ticket_write,
mbedtls_ssl_ticket_parse_t *f_ticket_parse,
@@ -4644,6 +4660,10 @@
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_SESSION_TICKETS)
+ mbedtls_ssl_conf_new_session_tickets(
+ conf, MBEDTLS_SSL_TLS1_3_DEFAULT_NEW_SESSION_TICKETS );
+#endif
/*
* Allow all TLS 1.3 key exchange modes by default.
*/
diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c
index 94a07c8..bf281bf 100644
--- a/library/ssl_tls13_server.c
+++ b/library/ssl_tls13_server.c
@@ -2619,7 +2619,21 @@
/* Check whether the use of session tickets is enabled */
if( ssl->conf->f_ticket_write == NULL )
{
- MBEDTLS_SSL_DEBUG_MSG( 2, ( "new session ticket is not enabled" ) );
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "NewSessionTicket: disabled,"
+ " callback is not set" ) );
+ return( SSL_NEW_SESSION_TICKET_SKIP );
+ }
+ if( ssl->conf->new_session_tickets_count == 0 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "NewSessionTicket: disabled,"
+ " configured count is zero" ) );
+ return( SSL_NEW_SESSION_TICKET_SKIP );
+ }
+
+ if( ssl->handshake->new_session_tickets_count == 0 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "NewSessionTicket: all tickets have "
+ "been sent." ) );
return( SSL_NEW_SESSION_TICKET_SKIP );
}
@@ -2852,6 +2866,15 @@
MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_finish_handshake_msg(
ssl, buf_len, msg_len ) );
+ /* Limit session tickets count to one when resumption connection.
+ *
+ * See document of mbedtls_ssl_conf_new_session_tickets.
+ */
+ if( ssl->handshake->resume == 1 )
+ ssl->handshake->new_session_tickets_count = 0;
+ else
+ ssl->handshake->new_session_tickets_count--;
+
mbedtls_ssl_handshake_set_state( ssl,
MBEDTLS_SSL_NEW_SESSION_TICKET_FLUSH );
}
@@ -3002,7 +3025,11 @@
* as part of ssl_prepare_handshake_step.
*/
ret = 0;
- mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_HANDSHAKE_OVER );
+
+ if( ssl->handshake->new_session_tickets_count == 0 )
+ mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_HANDSHAKE_OVER );
+ else
+ mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_NEW_SESSION_TICKET );
break;
#endif /* MBEDTLS_SSL_SESSION_TICKETS */
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 6beaa12..64baa19 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -1139,7 +1139,7 @@
else if( strcmp( p, "tickets" ) == 0 )
{
opt.tickets = atoi( q );
- if( opt.tickets < 0 || opt.tickets > 2 )
+ if( opt.tickets < 0 )
goto usage;
}
else if( strcmp( p, "alpn" ) == 0 )
@@ -2668,6 +2668,9 @@
*/
if( opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM )
{
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS)
+ int ticket_id = 0;
+#endif
do
{
len = sizeof( buf ) - 1;
@@ -2715,7 +2718,8 @@
case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET:
/* We were waiting for application data but got
* a NewSessionTicket instead. */
- mbedtls_printf( " got new session ticket.\n" );
+ mbedtls_printf( " got new session ticket ( %d ).\n",
+ ticket_id++ );
if( opt.reconnect != 0 )
{
mbedtls_printf(" . Saving session for reuse..." );
@@ -2749,7 +2753,6 @@
(unsigned) session_data_len );
}
}
-
continue;
#endif /* MBEDTLS_SSL_SESSION_TICKETS */
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 3113d1b..a129de6 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -1997,7 +1997,7 @@
else if( strcmp( p, "tickets" ) == 0 )
{
opt.tickets = atoi( q );
- if( opt.tickets < 0 || opt.tickets > 1 )
+ if( opt.tickets < 0 )
goto usage;
}
else if( strcmp( p, "ticket_rotate" ) == 0 )
@@ -2915,7 +2915,7 @@
#endif
#if defined(MBEDTLS_SSL_SESSION_TICKETS)
- if( opt.tickets == MBEDTLS_SSL_SESSION_TICKETS_ENABLED )
+ if( opt.tickets != MBEDTLS_SSL_SESSION_TICKETS_DISABLED )
{
if( ( ret = mbedtls_ssl_ticket_setup( &ticket_ctx,
rng_get, &rng,
@@ -2930,7 +2930,9 @@
mbedtls_ssl_ticket_write,
mbedtls_ssl_ticket_parse,
&ticket_ctx );
-
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ mbedtls_ssl_conf_new_session_tickets( &conf, opt.tickets );
+#endif
/* exercise manual ticket rotation (not required for typical use)
* (used for external synchronization of session ticket encryption keys)
*/
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 84bcd3c..f51d945 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -12781,14 +12781,32 @@
-c "HTTP/1.0 200 OK" \
-s "This is a resumed session"
+requires_openssl_tls1_3
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
+requires_config_enabled MBEDTLS_SSL_SESSION_TICKETS
+requires_config_enabled MBEDTLS_SSL_SRV_C
+requires_config_enabled MBEDTLS_DEBUG_C
+requires_config_enabled MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE
+# https://github.com/openssl/openssl/issues/10714
+# Until now, OpenSSL client does not support reconnect.
+skip_next_test
+run_test "TLS 1.3: NewSessionTicket: Basic check, O->m" \
+ "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=4" \
+ "$O_NEXT_CLI -msg -debug -tls1_3 -reconnect" \
+ 0 \
+ -s "=> write NewSessionTicket msg" \
+ -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET" \
+ -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET_FLUSH"
+
requires_gnutls_tls1_3
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
requires_config_enabled MBEDTLS_SSL_SESSION_TICKETS
requires_config_enabled MBEDTLS_SSL_SRV_C
requires_config_enabled MBEDTLS_DEBUG_C
+requires_config_enabled MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE
run_test "TLS 1.3: NewSessionTicket: Basic check, G->m" \
- "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=1" \
- "$G_NEXT_CLI localhost -d 4 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:%DISABLE_TLS13_COMPAT_MODE -V -r" \
+ "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=4" \
+ "$G_NEXT_CLI localhost -d 4 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3 -V -r" \
0 \
-c "Connecting again- trying to resume previous session" \
-c "NEW SESSION TICKET (4) was received" \
@@ -12805,11 +12823,11 @@
requires_config_enabled MBEDTLS_SSL_CLI_C
requires_config_enabled MBEDTLS_DEBUG_C
run_test "TLS 1.3: NewSessionTicket: Basic check, m->m" \
- "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=1" \
+ "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=4" \
"$P_CLI debug_level=4 reco_mode=1 reconnect=1" \
0 \
-c "Protocol is TLSv1.3" \
- -c "got new session ticket." \
+ -c "got new session ticket ( 3 )" \
-c "Saving session for reuse... ok" \
-c "Reconnecting with saved session" \
-c "HTTP/1.0 200 OK" \