Merge pull request #6167 from yuhaoth/pr/finalize-tls13-session-tickets
diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h
index 990dc58..687c5ef 100644
--- a/include/mbedtls/mbedtls_config.h
+++ b/include/mbedtls/mbedtls_config.h
@@ -1550,6 +1550,26 @@
//#define MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE
/**
+ * \def MBEDTLS_SSL_TLS1_3_TICKET_AGE_TOLERANCE
+ *
+ * Maximum time difference in milliseconds tolerated between the age of a
+ * ticket from the server and client point of view.
+ * From the client point of view, the age of a ticket is the time difference
+ * between the time when the client proposes to the server to use the ticket
+ * (time of writing of the Pre-Shared Key Extension including the ticket) and
+ * the time the client received the ticket from the server.
+ * From the server point of view, the age of a ticket is the time difference
+ * between the time when the server receives a proposition from the client
+ * to use the ticket and the time when the ticket was created by the server.
+ * The server age is expected to be always greater than the client one and
+ * MBEDTLS_SSL_TLS1_3_TICKET_AGE_TOLERANCE defines the
+ * maximum difference tolerated for the server to accept the ticket.
+ * This is not used in TLS 1.2.
+ *
+ */
+#define MBEDTLS_SSL_TLS1_3_TICKET_AGE_TOLERANCE 6000
+
+/**
* \def MBEDTLS_SSL_TLS1_3_TICKET_NONCE_LENGTH
*
* Size in bytes of a ticket nonce. This is not used in TLS 1.2.
diff --git a/library/ssl_misc.h b/library/ssl_misc.h
index a59e672..0b3ba90 100644
--- a/library/ssl_misc.h
+++ b/library/ssl_misc.h
@@ -2457,16 +2457,6 @@
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
-/* Check if we have any PSK to offer, returns 0 if PSK is available.
- * Assign the psk and ticket if pointers are present.
- */
-MBEDTLS_CHECK_RETURN_CRITICAL
-int mbedtls_ssl_get_psk_to_offer(
- const mbedtls_ssl_context *ssl,
- int *psk_type,
- const unsigned char **psk, size_t *psk_len,
- const unsigned char **psk_identity, size_t *psk_identity_len );
-
/**
* \brief Given an SSL context and its associated configuration, write the TLS
* 1.3 specific Pre-Shared key extension.
diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c
index 505f8dd..33e8cc6 100644
--- a/library/ssl_tls13_client.c
+++ b/library/ssl_tls13_client.c
@@ -664,10 +664,59 @@
ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_PSK_KEY_EXCHANGE_MODES;
return ( 0 );
}
-#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */
+
+/* Check if we have any PSK to offer, returns 0 if a PSK is available. */
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_tls13_get_psk_to_offer(
+ const mbedtls_ssl_context *ssl,
+ int *psk_type,
+ const unsigned char **psk, size_t *psk_len,
+ const unsigned char **psk_identity, size_t *psk_identity_len )
+{
+ *psk = NULL;
+ *psk_len = 0;
+ *psk_identity = NULL;
+ *psk_identity_len = 0;
+ *psk_type = MBEDTLS_SSL_TLS1_3_PSK_EXTERNAL;
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ /* Check if a ticket has been configured. */
+ if( ssl->session_negotiate != NULL &&
+ ssl->session_negotiate->ticket != NULL )
+ {
+#if defined(MBEDTLS_HAVE_TIME)
+ mbedtls_time_t now = mbedtls_time( NULL );
+ if( ssl->session_negotiate->ticket_received <= now &&
+ (uint64_t)( now - ssl->session_negotiate->ticket_received )
+ <= ssl->session_negotiate->ticket_lifetime )
+ {
+ *psk_type = MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION;
+ *psk = ssl->session_negotiate->resumption_key;
+ *psk_len = ssl->session_negotiate->resumption_key_len;
+ *psk_identity = ssl->session_negotiate->ticket;
+ *psk_identity_len = ssl->session_negotiate->ticket_len;
+ return( 0 );
+ }
+#endif /* MBEDTLS_HAVE_TIME */
+ MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket expired" ) );
+ }
+#endif
+
+ /* Check if an external PSK has been configured. */
+ if( ssl->conf->psk != NULL )
+ {
+ *psk = ssl->conf->psk;
+ *psk_len = ssl->conf->psk_len;
+ *psk_identity = ssl->conf->psk_identity;
+ *psk_identity_len = ssl->conf->psk_identity_len;
+ return( 0 );
+ }
+
+ return( MBEDTLS_ERR_ERROR_GENERIC_ERROR );
+}
/*
- * mbedtls_ssl_tls13_write_pre_shared_key_ext() structure:
+ * mbedtls_ssl_tls13_write_identities_of_pre_shared_key_ext() structure:
*
* struct {
* opaque identity<1..2^16-1>;
@@ -689,9 +738,6 @@
* } PreSharedKeyExtension;
*
*/
-
-#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
-
int mbedtls_ssl_tls13_write_identities_of_pre_shared_key_ext(
mbedtls_ssl_context *ssl,
unsigned char *buf, unsigned char *end,
@@ -725,9 +771,8 @@
* configured, offer that.
* - Otherwise, skip the PSK extension.
*/
-
- if( mbedtls_ssl_get_psk_to_offer( ssl, &psk_type, &psk, &psk_len,
- &psk_identity, &psk_identity_len ) != 0 )
+ if( ssl_tls13_get_psk_to_offer( ssl, &psk_type, &psk, &psk_len,
+ &psk_identity, &psk_identity_len ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip pre_shared_key extensions" ) );
return( 0 );
@@ -757,6 +802,26 @@
break;
}
}
+ else
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ if( psk_type == MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION )
+ {
+#if defined(MBEDTLS_HAVE_TIME)
+ mbedtls_time_t now = mbedtls_time( NULL );
+
+ obfuscated_ticket_age =
+ ( (uint32_t)( now - ssl->session_negotiate->ticket_received ) * 1000 )
+ + ssl->session_negotiate->ticket_age_add;
+#endif
+ }
+ else
+#endif /* MBEDTLS_SSL_SESSION_TICKETS */
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "write_identities_of_pre_shared_key_ext: "
+ "should never happen" ) );
+ return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+ }
+
ciphersuite_info = mbedtls_ssl_ciphersuite_from_id(
ssl->session_negotiate->ciphersuite );
@@ -831,8 +896,8 @@
unsigned char transcript[MBEDTLS_MD_MAX_SIZE];
size_t transcript_len;
- if( mbedtls_ssl_get_psk_to_offer( ssl, &psk_type, &psk, &psk_len,
- &psk_identity, &psk_identity_len ) != 0 )
+ if( ssl_tls13_get_psk_to_offer( ssl, &psk_type, &psk, &psk_len,
+ &psk_identity, &psk_identity_len ) != 0 )
{
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
@@ -1266,15 +1331,15 @@
size_t psk_len;
const unsigned char *psk_identity;
size_t psk_identity_len;
-
+ int psk_type;
/* Check which PSK we've offered.
*
* NOTE: Ultimately, we want to offer multiple PSKs, and in this
* case, we need to iterate over them here.
*/
- if( mbedtls_ssl_get_psk_to_offer( ssl, NULL, &psk, &psk_len,
- &psk_identity, &psk_identity_len ) != 0 )
+ if( ssl_tls13_get_psk_to_offer( ssl, &psk_type, &psk, &psk_len,
+ &psk_identity, &psk_identity_len ) != 0 )
{
/* If we haven't offered a PSK, the server must not send
* a PSK identity extension. */
@@ -1622,16 +1687,19 @@
/* Only the pre_shared_key extension was received */
case MBEDTLS_SSL_EXT_PRE_SHARED_KEY:
handshake->key_exchange_mode = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK;
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "key exchange mode: psk" ) );
break;
/* Only the key_share extension was received */
case MBEDTLS_SSL_EXT_KEY_SHARE:
handshake->key_exchange_mode = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL;
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "key exchange mode: ephemeral" ) );
break;
/* Both the pre_shared_key and key_share extensions were received */
case ( MBEDTLS_SSL_EXT_PRE_SHARED_KEY | MBEDTLS_SSL_EXT_KEY_SHARE ):
handshake->key_exchange_mode = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL;
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "key exchange mode: psk_ephemeral" ) );
break;
/* Neither pre_shared_key nor key_share extension was received */
@@ -1819,7 +1887,12 @@
*/
switch( extension_type )
{
+ case MBEDTLS_TLS_EXT_SERVERNAME:
+ MBEDTLS_SSL_DEBUG_MSG( 3, ( "found server_name extension" ) );
+ /* The server_name extension should be an empty extension */
+
+ break;
case MBEDTLS_TLS_EXT_SUPPORTED_GROUPS:
MBEDTLS_SSL_DEBUG_MSG( 3, ( "found extensions supported groups" ) );
break;
@@ -2237,11 +2310,11 @@
if( ret != 0 )
return( ret );
- ret = mbedtls_ssl_tls13_generate_resumption_master_secret( ssl );
+ ret = mbedtls_ssl_tls13_compute_resumption_master_secret( ssl );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1,
- "mbedtls_ssl_tls13_generate_resumption_master_secret ", ret );
+ "mbedtls_ssl_tls13_compute_resumption_master_secret ", ret );
return ( ret );
}
@@ -2405,6 +2478,9 @@
return( ret );
}
+ /* session has been updated, allow export */
+ session->exported = 0;
+
return( 0 );
}
diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c
index 6f60fab..f74cb40 100644
--- a/library/ssl_tls13_generic.c
+++ b/library/ssl_tls13_generic.c
@@ -1504,41 +1504,4 @@
}
#endif /* MBEDTLS_ECDH_C */
-#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
-/* Check if we have any PSK to offer, returns 0 if PSK is available.
- * Assign the psk and ticket if pointers are present.
- */
-int mbedtls_ssl_get_psk_to_offer(
- const mbedtls_ssl_context *ssl,
- int *psk_type,
- const unsigned char **psk, size_t *psk_len,
- const unsigned char **psk_identity, size_t *psk_identity_len )
-{
- int ptrs_present = 0;
-
- if( psk_type != NULL && psk != NULL && psk_len != NULL &&
- psk_identity != NULL && psk_identity_len != NULL )
- {
- ptrs_present = 1;
- }
-
- /* Check if an external PSK has been configured. */
- if( ssl->conf->psk != NULL )
- {
- if( ptrs_present )
- {
- *psk_type = MBEDTLS_SSL_TLS1_3_PSK_EXTERNAL;
- *psk = ssl->conf->psk;
- *psk_len = ssl->conf->psk_len;
- *psk_identity = ssl->conf->psk_identity;
- *psk_identity_len = ssl->conf->psk_identity_len;
- }
-
- return( 0 );
- }
-
- return( 1 );
-}
-#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */
-
#endif /* MBEDTLS_SSL_TLS_C && MBEDTLS_SSL_PROTO_TLS1_3 */
diff --git a/library/ssl_tls13_keys.c b/library/ssl_tls13_keys.c
index 32a4f2a..48de3d0 100644
--- a/library/ssl_tls13_keys.c
+++ b/library/ssl_tls13_keys.c
@@ -1504,12 +1504,43 @@
return( ret );
}
-int mbedtls_ssl_tls13_generate_resumption_master_secret(
- mbedtls_ssl_context *ssl )
+int mbedtls_ssl_tls13_compute_resumption_master_secret( mbedtls_ssl_context *ssl )
{
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+ mbedtls_md_type_t md_type;
+ mbedtls_ssl_handshake_params *handshake = ssl->handshake;
+ unsigned char transcript[MBEDTLS_TLS1_3_MD_MAX_SIZE];
+ size_t transcript_len;
+
+ MBEDTLS_SSL_DEBUG_MSG( 2,
+ ( "=> mbedtls_ssl_tls13_compute_resumption_master_secret" ) );
+
+ md_type = handshake->ciphersuite_info->mac;
+
+ ret = mbedtls_ssl_get_handshake_transcript( ssl, md_type,
+ transcript, sizeof( transcript ),
+ &transcript_len );
+ if( ret != 0 )
+ return( ret );
+
+ ret = mbedtls_ssl_tls13_derive_resumption_master_secret(
+ mbedtls_psa_translate_md( md_type ),
+ handshake->tls13_master_secrets.app,
+ transcript, transcript_len,
+ &ssl->session_negotiate->app_secrets );
+ if( ret != 0 )
+ return( ret );
+
/* Erase master secrets */
- mbedtls_platform_zeroize( &ssl->handshake->tls13_master_secrets,
- sizeof( ssl->handshake->tls13_master_secrets ) );
+ mbedtls_platform_zeroize( &handshake->tls13_master_secrets,
+ sizeof( handshake->tls13_master_secrets ) );
+
+ MBEDTLS_SSL_DEBUG_BUF( 4, "Resumption master secret",
+ ssl->session_negotiate->app_secrets.resumption_master_secret,
+ PSA_HASH_LENGTH( mbedtls_psa_translate_md( md_type ) ) ) ;
+
+ MBEDTLS_SSL_DEBUG_MSG( 2,
+ ( "<= mbedtls_ssl_tls13_compute_resumption_master_secret" ) );
return( 0 );
}
diff --git a/library/ssl_tls13_keys.h b/library/ssl_tls13_keys.h
index d82bf7a..f3bdf37 100644
--- a/library/ssl_tls13_keys.h
+++ b/library/ssl_tls13_keys.h
@@ -636,8 +636,7 @@
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
-int mbedtls_ssl_tls13_generate_resumption_master_secret(
- mbedtls_ssl_context *ssl );
+int mbedtls_ssl_tls13_compute_resumption_master_secret( mbedtls_ssl_context *ssl );
/**
* \brief Calculate the verify_data value for the client or server TLS 1.3
diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c
index a10e59b..e185dc1 100644
--- a/library/ssl_tls13_server.c
+++ b/library/ssl_tls13_server.c
@@ -121,14 +121,170 @@
#define SSL_TLS1_3_OFFERED_PSK_NOT_MATCH 1
#define SSL_TLS1_3_OFFERED_PSK_MATCH 0
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_tls13_offered_psks_check_identity_match_ticket(
+ mbedtls_ssl_context *ssl,
+ const unsigned char *identity,
+ size_t identity_len,
+ uint32_t obfuscated_ticket_age,
+ mbedtls_ssl_session *session )
+{
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+ unsigned char *ticket_buffer;
+#if defined(MBEDTLS_HAVE_TIME)
+ mbedtls_time_t now;
+ uint64_t age_in_s;
+ int64_t age_diff_in_ms;
+#endif
+
+ ((void) obfuscated_ticket_age);
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> check_identity_match_ticket" ) );
+
+ /* Ticket parser is not configured, Skip */
+ if( ssl->conf->f_ticket_parse == NULL || identity_len == 0 )
+ return( 0 );
+
+ /* We create a copy of the encrypted ticket since the ticket parsing
+ * function is allowed to use its input buffer as an output buffer
+ * (in-place decryption). We do, however, need the original buffer for
+ * computing the PSK binder value.
+ */
+ ticket_buffer = mbedtls_calloc( 1, identity_len );
+ if( ticket_buffer == NULL )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) );
+ return ( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+ }
+ memcpy( ticket_buffer, identity, identity_len );
+
+ if( ( ret = ssl->conf->f_ticket_parse( ssl->conf->p_ticket,
+ session,
+ ticket_buffer, identity_len ) ) != 0 )
+ {
+ if( ret == MBEDTLS_ERR_SSL_INVALID_MAC )
+ MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket is not authentic" ) );
+ else if( ret == MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED )
+ MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket is expired" ) );
+ else
+ MBEDTLS_SSL_DEBUG_RET( 1, "ticket_parse", ret );
+ }
+
+ /* We delete the temporary buffer */
+ mbedtls_free( ticket_buffer );
+
+ if( ret != 0 )
+ goto exit;
+
+ ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
+#if defined(MBEDTLS_HAVE_TIME)
+ now = mbedtls_time( NULL );
+
+ if( now < session->start )
+ {
+ MBEDTLS_SSL_DEBUG_MSG(
+ 3, ( "Ticket expired: now=%" MBEDTLS_PRINTF_LONGLONG
+ ", start=%" MBEDTLS_PRINTF_LONGLONG,
+ (long long)now, (long long)session->start ) );
+ goto exit;
+ }
+
+ age_in_s = (uint64_t)( now - session->start );
+
+ /* RFC 8446 section 4.6.1
+ *
+ * Servers MUST NOT use any value greater than 604800 seconds (7 days).
+ *
+ * RFC 8446 section 4.2.11.1
+ *
+ * Clients MUST NOT attempt to use tickets which have ages greater than
+ * the "ticket_lifetime" value which was provided with the ticket.
+ *
+ * For time being, the age MUST be less than 604800 seconds (7 days).
+ */
+ if( age_in_s > 604800 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG(
+ 3, ( "Ticket expired: Ticket age exceed limitation ticket_age=%lu",
+ (long unsigned int)age_in_s ) );
+ goto exit;
+ }
+
+ /* RFC 8446 section 4.2.10
+ *
+ * For PSKs provisioned via NewSessionTicket, a server MUST validate that
+ * the ticket age for the selected PSK identity (computed by subtracting
+ * ticket_age_add from PskIdentity.obfuscated_ticket_age modulo 2^32) is
+ * within a small tolerance of the time since the ticket was issued.
+ *
+ * NOTE: When `now == session->start`, `age_diff_in_ms` may be negative
+ * as the age units are different on the server (s) and in the
+ * client (ms) side. Add a -1000 ms tolerance window to take this
+ * into account.
+ */
+ age_diff_in_ms = age_in_s * 1000;
+ age_diff_in_ms -= ( obfuscated_ticket_age - session->ticket_age_add );
+ if( age_diff_in_ms <= -1000 ||
+ age_diff_in_ms > MBEDTLS_SSL_TLS1_3_TICKET_AGE_TOLERANCE )
+ {
+ MBEDTLS_SSL_DEBUG_MSG(
+ 3, ( "Ticket expired: Ticket age outside tolerance window "
+ "( diff=%d )", (int)age_diff_in_ms ) );
+ goto exit;
+ }
+
+ ret = 0;
+
+#endif /* MBEDTLS_HAVE_TIME */
+
+exit:
+ if( ret != 0 )
+ mbedtls_ssl_session_free( session );
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= check_identity_match_ticket" ) );
+ return( ret );
+}
+#endif /* MBEDTLS_SSL_SESSION_TICKETS */
+
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_tls13_offered_psks_check_identity_match(
mbedtls_ssl_context *ssl,
const unsigned char *identity,
size_t identity_len,
- int *psk_type )
+ uint32_t obfuscated_ticket_age,
+ int *psk_type,
+ mbedtls_ssl_session *session )
{
+ ((void) session);
+ ((void) obfuscated_ticket_age);
*psk_type = MBEDTLS_SSL_TLS1_3_PSK_EXTERNAL;
+
+ MBEDTLS_SSL_DEBUG_BUF( 4, "identity", identity, identity_len );
+ ssl->handshake->resume = 0;
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ if( ssl_tls13_offered_psks_check_identity_match_ticket(
+ ssl, identity, identity_len, obfuscated_ticket_age,
+ session ) == SSL_TLS1_3_OFFERED_PSK_MATCH )
+ {
+ ssl->handshake->resume = 1;
+ *psk_type = MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION;
+ mbedtls_ssl_set_hs_psk( ssl,
+ session->resumption_key,
+ session->resumption_key_len );
+
+ MBEDTLS_SSL_DEBUG_BUF( 4, "Ticket-resumed PSK:",
+ session->resumption_key,
+ session->resumption_key_len );
+ MBEDTLS_SSL_DEBUG_MSG( 4, ( "ticket: obfuscated_ticket_age: %u",
+ (unsigned)obfuscated_ticket_age ) );
+ return( SSL_TLS1_3_OFFERED_PSK_MATCH );
+ }
+#endif /* MBEDTLS_SSL_SESSION_TICKETS */
+
/* Check identity with external configured function */
if( ssl->conf->f_psk != NULL )
{
@@ -256,6 +412,7 @@
return( MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE );
}
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_tls13_select_ciphersuite_for_resumption(
mbedtls_ssl_context *ssl,
@@ -265,15 +422,46 @@
uint16_t *selected_ciphersuite,
const mbedtls_ssl_ciphersuite_t **selected_ciphersuite_info )
{
- ((void) ssl);
- ((void) session);
- ((void) cipher_suites);
- ((void) cipher_suites_end);
+
*selected_ciphersuite = 0;
*selected_ciphersuite_info = NULL;
- return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
+ for( const unsigned char *p = cipher_suites; p < cipher_suites_end; p += 2 )
+ {
+ uint16_t cipher_suite = MBEDTLS_GET_UINT16_BE( p, 0 );
+ const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
+
+ if( cipher_suite != session->ciphersuite )
+ continue;
+
+ ciphersuite_info = ssl_tls13_validate_peer_ciphersuite( ssl,
+ cipher_suite );
+ if( ciphersuite_info == NULL )
+ continue;
+
+ *selected_ciphersuite = cipher_suite;
+ *selected_ciphersuite_info = ciphersuite_info;
+
+ return( 0 );
+ }
+
+ return( MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE );
}
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_tls13_session_copy_ticket( mbedtls_ssl_session *dst,
+ const mbedtls_ssl_session *src )
+{
+ dst->ticket_age_add = src->ticket_age_add;
+ dst->ticket_flags = src->ticket_flags;
+ dst->resumption_key_len = src->resumption_key_len;
+ if( src->resumption_key_len == 0 )
+ return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+ memcpy( dst->resumption_key, src->resumption_key, src->resumption_key_len );
+
+ return( 0 );
+}
+#endif /* MBEDTLS_SSL_SESSION_TICKETS */
+
/* Parser for pre_shared_key extension in client hello
* struct {
* opaque identity<1..2^16-1>;
@@ -343,17 +531,23 @@
{
const unsigned char *identity;
size_t identity_len;
+ uint32_t obfuscated_ticket_age;
const unsigned char *binder;
size_t binder_len;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int psk_type;
uint16_t cipher_suite;
const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ mbedtls_ssl_session session;
+ mbedtls_ssl_session_init( &session );
+#endif
MBEDTLS_SSL_CHK_BUF_READ_PTR( p_identity_len, identities_end, 2 + 1 + 4 );
identity_len = MBEDTLS_GET_UINT16_BE( p_identity_len, 0 );
identity = p_identity_len + 2;
MBEDTLS_SSL_CHK_BUF_READ_PTR( identity, identities_end, identity_len + 4 );
+ obfuscated_ticket_age = MBEDTLS_GET_UINT32_BE( identity , identity_len );
p_identity_len += identity_len + 6;
MBEDTLS_SSL_CHK_BUF_READ_PTR( p_binder_len, binders_end, 1 + 32 );
@@ -367,7 +561,8 @@
continue;
ret = ssl_tls13_offered_psks_check_identity_match(
- ssl, identity, identity_len, &psk_type );
+ ssl, identity, identity_len, obfuscated_ticket_age,
+ &psk_type, &session );
if( ret != SSL_TLS1_3_OFFERED_PSK_MATCH )
continue;
@@ -380,9 +575,15 @@
&cipher_suite, &ciphersuite_info );
break;
case MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION:
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
ret = ssl_tls13_select_ciphersuite_for_resumption(
- ssl, ciphersuites, ciphersuites_end, NULL,
+ ssl, ciphersuites, ciphersuites_end, &session,
&cipher_suite, &ciphersuite_info );
+ if( ret != 0 )
+ mbedtls_ssl_session_free( &session );
+#else
+ ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
+#endif
break;
default:
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
@@ -406,6 +607,9 @@
/* For security reasons, the handshake should be aborted when we
* fail to validate a binder value. See RFC 8446 section 4.2.11.2
* and appendix E.6. */
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ mbedtls_ssl_session_free( &session );
+#endif
MBEDTLS_SSL_DEBUG_MSG( 3, ( "Invalid binder." ) );
MBEDTLS_SSL_DEBUG_RET( 1,
"ssl_tls13_offered_psks_check_binder_match" , ret );
@@ -418,11 +622,20 @@
matched_identity = identity_id;
/* Update handshake parameters */
- ssl->session_negotiate->ciphersuite = cipher_suite;
ssl->handshake->ciphersuite_info = ciphersuite_info;
+ ssl->session_negotiate->ciphersuite = cipher_suite;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "overwrite ciphersuite: %04x - %s",
cipher_suite, ciphersuite_info->name ) );
-
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ if( psk_type == MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION )
+ {
+ ret = ssl_tls13_session_copy_ticket( ssl->session_negotiate,
+ &session );
+ mbedtls_ssl_session_free( &session );
+ if( ret != 0 )
+ return( ret );
+ }
+#endif /* MBEDTLS_SSL_SESSION_TICKETS */
}
if( p_identity_len != identities_end || p_binder_len != binders_end )
@@ -2366,11 +2579,11 @@
if( ret != 0 )
return( ret );
- ret = mbedtls_ssl_tls13_generate_resumption_master_secret( ssl );
+ ret = mbedtls_ssl_tls13_compute_resumption_master_secret( ssl );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1,
- "mbedtls_ssl_tls13_generate_resumption_master_secret ", ret );
+ "mbedtls_ssl_tls13_compute_resumption_master_secret", ret );
}
mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_HANDSHAKE_WRAPUP );
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 8915011..050d518 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -657,6 +657,58 @@
}
#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+static int ssl_save_session_serialize( mbedtls_ssl_context *ssl,
+ unsigned char **session_data,
+ size_t *session_data_len )
+{
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+ mbedtls_ssl_session exported_session;
+
+ /* free any previously saved data */
+ if( *session_data != NULL )
+ {
+ mbedtls_platform_zeroize( *session_data, *session_data_len );
+ mbedtls_free( *session_data );
+ *session_data = NULL;
+ *session_data_len = 0;
+ }
+
+ mbedtls_ssl_session_init( &exported_session );
+ ret = mbedtls_ssl_get_session( ssl, &exported_session );
+ if( ret != 0 )
+ {
+ mbedtls_printf(
+ "failed\n ! mbedtls_ssl_get_session() returned -%#02x\n",
+ (unsigned) -ret );
+ goto exit;
+ }
+
+ /* get size of the buffer needed */
+ mbedtls_ssl_session_save( &exported_session, NULL, 0, session_data_len );
+ *session_data = mbedtls_calloc( 1, *session_data_len );
+ if( *session_data == NULL )
+ {
+ mbedtls_printf( " failed\n ! alloc %u bytes for session data\n",
+ (unsigned) *session_data_len );
+ ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
+ goto exit;
+ }
+
+ /* actually save session data */
+ if( ( ret = mbedtls_ssl_session_save( &exported_session,
+ *session_data, *session_data_len,
+ session_data_len ) ) != 0 )
+ {
+ mbedtls_printf( " failed\n ! mbedtls_ssl_session_saved returned -0x%04x\n\n",
+ (unsigned int) -ret );
+ goto exit;
+ }
+
+exit:
+ mbedtls_ssl_session_free( &exported_session );
+ return( ret );
+}
+
int main( int argc, char *argv[] )
{
int ret = 0, len, tail_len, i, written, frags, retry_left;
@@ -2360,57 +2412,21 @@
}
}
#endif /* MBEDTLS_SSL_DTLS_SRTP */
- if( opt.reconnect != 0 )
+ if( opt.reconnect != 0 && ssl.tls_version != MBEDTLS_SSL_VERSION_TLS1_3 )
{
mbedtls_printf(" . Saving session for reuse..." );
fflush( stdout );
if( opt.reco_mode == 1 )
{
- mbedtls_ssl_session exported_session;
-
- /* free any previously saved data */
- if( session_data != NULL )
+ if( ( ret = ssl_save_session_serialize( &ssl,
+ &session_data, &session_data_len ) ) != 0 )
{
- mbedtls_platform_zeroize( session_data, session_data_len );
- mbedtls_free( session_data );
- session_data = NULL;
- }
-
- mbedtls_ssl_session_init( &exported_session );
- ret = mbedtls_ssl_get_session( &ssl, &exported_session );
- if( ret != 0 )
- {
- mbedtls_printf(
- "failed\n ! mbedtls_ssl_get_session() returned -%#02x\n",
- (unsigned) -ret );
- goto exit;
- }
-
- /* get size of the buffer needed */
- mbedtls_ssl_session_save( &exported_session, NULL, 0, &session_data_len );
- session_data = mbedtls_calloc( 1, session_data_len );
- if( session_data == NULL )
- {
- mbedtls_printf( " failed\n ! alloc %u bytes for session data\n",
- (unsigned) session_data_len );
- mbedtls_ssl_session_free( &exported_session );
- ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
- goto exit;
- }
-
- /* actually save session data */
- if( ( ret = mbedtls_ssl_session_save( &exported_session,
- session_data, session_data_len,
- &session_data_len ) ) != 0 )
- {
- mbedtls_printf( " failed\n ! mbedtls_ssl_session_saved returned -0x%04x\n\n",
+ mbedtls_printf( " failed\n ! ssl_save_session_serialize returned -0x%04x\n\n",
(unsigned int) -ret );
- mbedtls_ssl_session_free( &exported_session );
goto exit;
}
- mbedtls_ssl_session_free( &exported_session );
}
else
{
@@ -2700,6 +2716,40 @@
/* We were waiting for application data but got
* a NewSessionTicket instead. */
mbedtls_printf( " got new session ticket.\n" );
+ if( opt.reconnect != 0 )
+ {
+ mbedtls_printf(" . Saving session for reuse..." );
+ fflush( stdout );
+
+ if( opt.reco_mode == 1 )
+ {
+ if( ( ret = ssl_save_session_serialize( &ssl,
+ &session_data, &session_data_len ) ) != 0 )
+ {
+ mbedtls_printf( " failed\n ! ssl_save_session_serialize returned -0x%04x\n\n",
+ (unsigned int) -ret );
+ goto exit;
+ }
+ }
+ else
+ {
+ if( ( ret = mbedtls_ssl_get_session( &ssl, &saved_session ) ) != 0 )
+ {
+ mbedtls_printf( " failed\n ! mbedtls_ssl_get_session returned -0x%x\n\n",
+ (unsigned int) -ret );
+ goto exit;
+ }
+ }
+
+ mbedtls_printf( " ok\n" );
+
+ if( opt.reco_mode == 1 )
+ {
+ mbedtls_printf( " [ Saved %u bytes of session data]\n",
+ (unsigned) session_data_len );
+ }
+ }
+
continue;
#endif /* MBEDTLS_SSL_SESSION_TICKETS */
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 9e14af1..84bcd3c 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -12096,7 +12096,7 @@
run_test "TLS 1.3, default suite, PSK" \
"$P_SRV nbio=2 debug_level=5 force_version=tls13 psk=010203 psk_identity=0a0b0c tls13_kex_modes=psk" \
"$P_CLI nbio=2 debug_level=5 force_version=tls13 psk=010203 psk_identity=0a0b0c tls13_kex_modes=psk" \
- 1 \
+ 0 \
-c "=> write client hello" \
-c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
-c "client hello, adding psk_key_exchange_modes extension" \
@@ -12111,7 +12111,7 @@
run_test "TLS 1.3, default suite, PSK - openssl" \
"$O_NEXT_SRV -msg -debug -tls1_3 -psk_identity 0a0b0c -psk 010203 -allow_no_dhe_kex -nocert" \
"$P_CLI debug_level=4 psk=010203 psk_identity=0a0b0c tls13_kex_modes=psk" \
- 1 \
+ 0 \
-c "=> write client hello" \
-c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
-c "client hello, adding psk_key_exchange_modes extension" \
@@ -12756,13 +12756,13 @@
requires_config_enabled MBEDTLS_SSL_CLI_C
requires_config_enabled MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE
run_test "TLS 1.3: NewSessionTicket: Basic check, m->O" \
- "$O_NEXT_SRV -msg -tls1_3 -no_resume_ephemeral -no_cache " \
- "$P_CLI debug_level=4 reco_mode=1 reconnect=1" \
+ "$O_NEXT_SRV -msg -tls1_3 -no_resume_ephemeral -no_cache --num_tickets 4" \
+ "$P_CLI debug_level=1 reco_mode=1 reconnect=1" \
0 \
-c "Protocol is TLSv1.3" \
- -c "MBEDTLS_SSL_NEW_SESSION_TICKET" \
-c "got new session ticket." \
-c "Saving session for reuse... ok" \
+ -c "Reconnecting with saved session" \
-c "HTTP/1.0 200 ok"
requires_gnutls_tls1_3
@@ -12771,27 +12771,15 @@
requires_config_enabled MBEDTLS_DEBUG_C
requires_config_enabled MBEDTLS_SSL_CLI_C
run_test "TLS 1.3: NewSessionTicket: Basic check, m->G" \
- "$G_NEXT_SRV --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:+CIPHER-ALL:+PSK --disable-client-cert" \
- "$P_CLI debug_level=4 reco_mode=1 reconnect=1" \
+ "$G_NEXT_SRV -d 10 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:+CIPHER-ALL:+PSK --disable-client-cert" \
+ "$P_CLI debug_level=1 reco_mode=1 reconnect=1" \
0 \
-c "Protocol is TLSv1.3" \
- -c "MBEDTLS_SSL_NEW_SESSION_TICKET" \
-c "got new session ticket." \
-c "Saving session for reuse... ok" \
- -c "HTTP/1.0 200 OK"
-
-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
-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=1" \
- "$O_NEXT_CLI -msg -debug -tls1_3 -no_middlebox" \
- 0 \
- -s "=> write NewSessionTicket msg" \
- -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET" \
- -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET_FLUSH"
+ -c "Reconnecting with saved session" \
+ -c "HTTP/1.0 200 OK" \
+ -s "This is a resumed session"
requires_gnutls_tls1_3
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
@@ -12800,12 +12788,16 @@
requires_config_enabled MBEDTLS_DEBUG_C
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" \
+ "$G_NEXT_CLI localhost -d 4 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:%DISABLE_TLS13_COMPAT_MODE -V -r" \
0 \
+ -c "Connecting again- trying to resume previous session" \
+ -c "NEW SESSION TICKET (4) was received" \
-s "=> write NewSessionTicket msg" \
-s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET" \
-s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET_FLUSH" \
- -c "NEW SESSION TICKET (4) was received"
+ -s "key exchange mode: ephemeral" \
+ -s "key exchange mode: psk_ephemeral" \
+ -s "found pre_shared_key extension"
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
requires_config_enabled MBEDTLS_SSL_SESSION_TICKETS
@@ -12817,13 +12809,17 @@
"$P_CLI debug_level=4 reco_mode=1 reconnect=1" \
0 \
-c "Protocol is TLSv1.3" \
- -c "MBEDTLS_SSL_NEW_SESSION_TICKET" \
-c "got new session ticket." \
-c "Saving session for reuse... ok" \
+ -c "Reconnecting with saved session" \
-c "HTTP/1.0 200 OK" \
-s "=> write NewSessionTicket msg" \
-s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET" \
- -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET_FLUSH"
+ -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET_FLUSH" \
+ -s "key exchange mode: ephemeral" \
+ -s "key exchange mode: psk_ephemeral" \
+ -s "found pre_shared_key extension"
+
requires_openssl_tls1_3
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2