Merge pull request #6327 from yuhaoth/pr/tls13-psk-after-session-tickets

TLS 1.3: PSK and NewSessionTicket: Add support for sending PSK and Ticket together.
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index eda6bc2..5a02182 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -1390,10 +1390,12 @@
 #endif
 
 #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
+#if defined(MBEDTLS_SSL_SRV_C)
     /** Callback to retrieve PSK key from identity                          */
     int (*MBEDTLS_PRIVATE(f_psk))(void *, mbedtls_ssl_context *, const unsigned char *, size_t);
     void *MBEDTLS_PRIVATE(p_psk);                    /*!< context for PSK callback           */
 #endif
+#endif
 
 #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C)
     /** Callback to create & write a cookie for ClientHello verification    */
@@ -3415,6 +3417,7 @@
                                    mbedtls_svc_key_id_t psk );
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
+#if defined(MBEDTLS_SSL_SRV_C)
 /**
  * \brief          Set the PSK callback (server-side only).
  *
@@ -3457,6 +3460,7 @@
                      int (*f_psk)(void *, mbedtls_ssl_context *, const unsigned char *,
                                   size_t),
                      void *p_psk );
+#endif /* MBEDTLS_SSL_SRV_C */
 #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */
 
 #if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_SRV_C)
diff --git a/library/ssl_client.c b/library/ssl_client.c
index e7453d5..1b59125 100644
--- a/library/ssl_client.c
+++ b/library/ssl_client.c
@@ -713,12 +713,39 @@
                             MBEDTLS_CLIENT_HELLO_RANDOM_LEN - gmt_unix_time_len );
     return( ret );
 }
-
 MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_prepare_client_hello( mbedtls_ssl_context *ssl )
 {
     int ret;
     size_t session_id_len;
+    mbedtls_ssl_session *session_negotiate = ssl->session_negotiate;
+
+    if( session_negotiate == NULL )
+        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && \
+    defined(MBEDTLS_SSL_SESSION_TICKETS) && \
+    defined(MBEDTLS_HAVE_TIME)
+
+    /* Check if a tls13 ticket has been configured. */
+    if( ssl->handshake->resume != 0 &&
+        session_negotiate->tls_version == MBEDTLS_SSL_VERSION_TLS1_3 &&
+        session_negotiate->ticket != NULL )
+    {
+        mbedtls_time_t now = mbedtls_time( NULL );
+        uint64_t age = (uint64_t)( now - session_negotiate->ticket_received );
+        if( session_negotiate->ticket_received > now ||
+            age > session_negotiate->ticket_lifetime )
+        {
+            /* Without valid ticket, disable session resumption.*/
+            MBEDTLS_SSL_DEBUG_MSG(
+                3, ( "Ticket expired, disable session resumption" ) );
+            ssl->handshake->resume = 0;
+        }
+    }
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 &&
+          MBEDTLS_SSL_SESSION_TICKETS &&
+          MBEDTLS_HAVE_TIME */
 
     if( ssl->conf->f_rng == NULL )
     {
@@ -737,7 +764,7 @@
     {
         if( ssl->handshake->resume )
         {
-             ssl->tls_version = ssl->session_negotiate->tls_version;
+             ssl->tls_version = session_negotiate->tls_version;
              ssl->handshake->min_tls_version = ssl->tls_version;
         }
         else
@@ -771,7 +798,7 @@
      * to zero, except in the case of a TLS 1.2 session renegotiation or
      * session resumption.
      */
-    session_id_len = ssl->session_negotiate->id_len;
+    session_id_len = session_negotiate->id_len;
 
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
     if( ssl->tls_version == MBEDTLS_SSL_VERSION_TLS1_2 )
@@ -794,8 +821,8 @@
         if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE )
 #endif
         {
-            if( ( ssl->session_negotiate->ticket != NULL ) &&
-                ( ssl->session_negotiate->ticket_len != 0 ) )
+            if( ( session_negotiate->ticket != NULL ) &&
+                ( session_negotiate->ticket_len != 0 ) )
             {
                 session_id_len = 32;
             }
@@ -827,13 +854,13 @@
     }
 #endif /* MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE */
 
-    if( session_id_len != ssl->session_negotiate->id_len )
+    if( session_id_len != session_negotiate->id_len )
     {
-        ssl->session_negotiate->id_len = session_id_len;
+        session_negotiate->id_len = session_id_len;
         if( session_id_len > 0 )
         {
             ret = ssl->conf->f_rng( ssl->conf->p_rng,
-                                    ssl->session_negotiate->id,
+                                    session_negotiate->id,
                                     session_id_len );
             if( ret != 0 )
             {
@@ -845,7 +872,6 @@
 
     return( 0 );
 }
-
 /*
  * Write ClientHello handshake message.
  * Handler for MBEDTLS_SSL_CLIENT_HELLO
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index f0615ea..9741a6e 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -1373,6 +1373,23 @@
     if( ssl->handshake->resume == 1 )
         return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
 
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+    if( session->tls_version == MBEDTLS_SSL_VERSION_TLS1_3 )
+    {
+        const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
+                    mbedtls_ssl_ciphersuite_from_id( session->ciphersuite );
+
+        if( mbedtls_ssl_validate_ciphersuite(
+                ssl, ciphersuite_info, MBEDTLS_SSL_VERSION_TLS1_3,
+                MBEDTLS_SSL_VERSION_TLS1_3 ) != 0 )
+        {
+            MBEDTLS_SSL_DEBUG_MSG( 4, ( "%d is not a valid TLS 1.3 ciphersuite.",
+                                        session->ciphersuite ) );
+            return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+        }
+    }
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+
     if( ( ret = mbedtls_ssl_session_copy( ssl->session_negotiate,
                                           session ) ) != 0 )
         return( ret );
@@ -1795,6 +1812,7 @@
 }
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
+#if defined(MBEDTLS_SSL_SRV_C)
 void mbedtls_ssl_conf_psk_cb( mbedtls_ssl_config *conf,
                      int (*f_psk)(void *, mbedtls_ssl_context *, const unsigned char *,
                      size_t),
@@ -1803,6 +1821,8 @@
     conf->f_psk = f_psk;
     conf->p_psk = p_psk;
 }
+#endif /* MBEDTLS_SSL_SRV_C */
+
 #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c
index 40e3cfd..2b59b4a 100644
--- a/library/ssl_tls13_client.c
+++ b/library/ssl_tls13_client.c
@@ -665,54 +665,194 @@
     return ( 0 );
 }
 
-/* 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 )
+static psa_algorithm_t ssl_tls13_get_ciphersuite_hash_alg( int ciphersuite )
 {
-    *psk = NULL;
-    *psk_len = 0;
-    *psk_identity = NULL;
-    *psk_identity_len = 0;
-    *psk_type = MBEDTLS_SSL_TLS1_3_PSK_EXTERNAL;
+    const mbedtls_ssl_ciphersuite_t *ciphersuite_info = NULL;
+    ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuite );
+
+    if( ciphersuite_info != NULL )
+       return( mbedtls_psa_translate_md( ciphersuite_info->mac ) );
+
+    return( PSA_ALG_NONE );
+}
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
-    /* Check if a ticket has been configured. */
-    if( ssl->session_negotiate != NULL &&
-        ssl->session_negotiate->ticket != NULL )
+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,
+                                          const unsigned char **identity,
+                                          size_t *identity_len )
+{
+    mbedtls_ssl_session *session = ssl->session_negotiate;
+
+    if( !ssl_tls13_has_configured_ticket( ssl ) )
+        return( -1 );
+
+    *hash_alg = ssl_tls13_get_ciphersuite_hash_alg( session->ciphersuite );
+    *identity = session->ticket;
+    *identity_len = session->ticket_len;
+    return( 0 );
+}
+
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_tls13_ticket_get_psk( mbedtls_ssl_context *ssl,
+                                     psa_algorithm_t *hash_alg,
+                                     const unsigned char **psk,
+                                     size_t *psk_len )
+{
+
+    mbedtls_ssl_session *session = ssl->session_negotiate;
+
+    if( !ssl_tls13_has_configured_ticket( ssl ) )
+        return( -1 );
+
+    *hash_alg = ssl_tls13_get_ciphersuite_hash_alg( session->ciphersuite );
+    *psk = session->resumption_key;
+    *psk_len = session->resumption_key_len;
+
+    return( 0 );
+}
+#endif /* MBEDTLS_SSL_SESSION_TICKETS */
+
+static int ssl_tls13_has_configured_psk( const mbedtls_ssl_config *conf )
+{
+    return( conf->psk != NULL && conf->psk_identity != NULL );
+}
+
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_tls13_psk_get_identity( mbedtls_ssl_context *ssl,
+                                       psa_algorithm_t *hash_alg,
+                                       const unsigned char **identity,
+                                       size_t *identity_len )
+{
+
+    if( !ssl_tls13_has_configured_psk( ssl->conf ) )
+        return( -1 );
+
+    *hash_alg = PSA_ALG_SHA_256;
+    *identity = ssl->conf->psk_identity;
+    *identity_len = ssl->conf->psk_identity_len;
+    return( 0 );
+}
+
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_tls13_psk_get_psk( mbedtls_ssl_context *ssl,
+                                  psa_algorithm_t *hash_alg,
+                                  const unsigned char **psk,
+                                  size_t *psk_len )
+{
+
+    if( !ssl_tls13_has_configured_psk( ssl->conf ) )
+        return( -1 );
+
+    *hash_alg = PSA_ALG_SHA_256;
+    *psk = ssl->conf->psk;
+    *psk_len = ssl->conf->psk_len;
+    return( 0 );
+}
+
+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 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" ) );
+        MBEDTLS_SSL_DEBUG_MSG( 3, ( "Ticket is configured" ) );
+        configured_psk_count++;
     }
 #endif
-
-    /* Check if an external PSK has been configured. */
-    if( ssl->conf->psk != NULL )
+    if( ssl_tls13_has_configured_psk( ssl->conf ) )
     {
-        *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 );
+        MBEDTLS_SSL_DEBUG_MSG( 3, ( "PSK is configured" ) );
+        configured_psk_count++;
     }
+    return( configured_psk_count );
+}
 
-    return( MBEDTLS_ERR_ERROR_GENERIC_ERROR );
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_tls13_write_identity( mbedtls_ssl_context *ssl,
+                                     unsigned char *buf,
+                                     unsigned char *end,
+                                     const unsigned char *identity,
+                                     size_t identity_len,
+                                     uint32_t obfuscated_ticket_age,
+                                     size_t *out_len )
+{
+    ((void) ssl);
+    *out_len = 0;
+
+    /*
+     * - identity_len           (2 bytes)
+     * - identity               (psk_identity_len bytes)
+     * - obfuscated_ticket_age  (4 bytes)
+     */
+    MBEDTLS_SSL_CHK_BUF_PTR( buf, end, 6 + identity_len );
+
+    MBEDTLS_PUT_UINT16_BE( identity_len, buf, 0 );
+    memcpy( buf + 2, identity, identity_len );
+    MBEDTLS_PUT_UINT32_BE( obfuscated_ticket_age, buf, 2 + identity_len );
+
+    MBEDTLS_SSL_DEBUG_BUF( 4, "write identity", buf, 6 + identity_len );
+
+    *out_len = 6 + identity_len;
+
+    return( 0 );
+}
+
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_tls13_write_binder( mbedtls_ssl_context *ssl,
+                                   unsigned char *buf,
+                                   unsigned char *end,
+                                   int psk_type,
+                                   psa_algorithm_t hash_alg,
+                                   const unsigned char *psk,
+                                   size_t psk_len,
+                                   size_t *out_len )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    unsigned char binder_len;
+    unsigned char transcript[ MBEDTLS_TLS1_3_MD_MAX_SIZE ];
+    size_t transcript_len = 0;
+
+    *out_len = 0;
+
+    binder_len = PSA_HASH_LENGTH( hash_alg );
+
+    /*
+     * - binder_len           (1 bytes)
+     * - binder               (binder_len bytes)
+     */
+    MBEDTLS_SSL_CHK_BUF_PTR( buf, end, 1 + binder_len );
+
+    buf[0] = binder_len;
+
+    /* Get current state of handshake transcript. */
+    ret = mbedtls_ssl_get_handshake_transcript(
+            ssl, mbedtls_hash_info_md_from_psa( hash_alg ),
+            transcript, sizeof( transcript ), &transcript_len );
+    if( ret != 0 )
+        return( ret );
+
+    ret = mbedtls_ssl_tls13_create_psk_binder( ssl, hash_alg,
+                                               psk, psk_len, psk_type,
+                                               transcript, buf + 1 );
+    if( ret != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_create_psk_binder", ret );
+        return( ret );
+    }
+    MBEDTLS_SSL_DEBUG_BUF( 4, "write binder", buf, 1 + binder_len );
+
+    *out_len = 1 + binder_len;
+
+    return( 0 );
 }
 
 /*
@@ -739,140 +879,104 @@
  *
  */
 int mbedtls_ssl_tls13_write_identities_of_pre_shared_key_ext(
-    mbedtls_ssl_context *ssl,
-    unsigned char *buf, unsigned char *end,
-    size_t *out_len, size_t *binders_len )
+        mbedtls_ssl_context *ssl, unsigned char *buf, unsigned char *end,
+        size_t *out_len, size_t *binders_len )
 {
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    int configured_psk_count = 0;
     unsigned char *p = buf;
-    const unsigned char *psk;
-    size_t psk_len;
-    const unsigned char *psk_identity;
-    size_t psk_identity_len;
-    int psk_type;
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info = NULL;
-    const int *ciphersuites;
-    psa_algorithm_t psa_hash_alg;
-    int hash_len = 0;
-    size_t identities_len, l_binders_len;
-    uint32_t obfuscated_ticket_age = 0;
+    psa_algorithm_t hash_alg;
+    const unsigned char *identity;
+    size_t identity_len;
+    size_t l_binders_len = 0;
+    size_t output_len;
 
     *out_len = 0;
     *binders_len = 0;
 
-    /* Check if we have any PSKs to offer. If so, return the first.
-     *
-     * NOTE: Ultimately, we want to be able to offer multiple PSKs,
-     *       in which case we want to iterate over them here.
-     *
-     * As it stands, however, we only ever offer one, chosen
-     * by the following heuristic:
-     * - If a ticket has been configured, offer the corresponding PSK.
-     * - If no ticket has been configured by an external PSK has been
-     *   configured, offer that.
-     * - Otherwise, skip the PSK extension.
-     */
-    if( ssl_tls13_get_psk_to_offer( ssl, &psk_type, &psk, &psk_len,
-                                    &psk_identity, &psk_identity_len ) != 0 )
+    /* Check if we have any PSKs to offer. If no, skip pre_shared_key */
+    configured_psk_count = ssl_tls13_get_configured_psk_count( ssl );
+    if( configured_psk_count == 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip pre_shared_key extensions" ) );
         return( 0 );
     }
 
-    if( psk_type == MBEDTLS_SSL_TLS1_3_PSK_EXTERNAL )
-    {
-        /*
-         * Ciphersuite list
-         */
-        ciphersuites = ssl->conf->ciphersuite_list;
-        for( int i = 0; ciphersuites[i] != 0; i++ )
-        {
-            ciphersuite_info = mbedtls_ssl_ciphersuite_from_id(
-                                    ciphersuites[i] );
+    MBEDTLS_SSL_DEBUG_MSG( 4, ( "Pre-configured PSK number = %d",
+                                configured_psk_count ) );
 
-            if( mbedtls_ssl_validate_ciphersuite(
-                                ssl, ciphersuite_info,
-                                MBEDTLS_SSL_VERSION_TLS1_3,
-                                MBEDTLS_SSL_VERSION_TLS1_3 ) != 0 )
-                continue;
-
-            /* In this implementation we only add one pre-shared-key
-             * extension.
-             */
-            ssl->session_negotiate->ciphersuite = ciphersuites[i];
-            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 );
-    /* No suitable ciphersuite for the PSK */
-    if( ciphersuite_info  == NULL )
-        return( 0 );
-
-    psa_hash_alg = mbedtls_psa_translate_md( ciphersuite_info->mac );
-    hash_len = PSA_HASH_LENGTH( psa_hash_alg );
-    if( hash_len == -1 )
-        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
-
-    /* Check if we have space to write the extension, binder included.
+    /* Check if we have space to write the extension, binders included.
      * - extension_type         (2 bytes)
      * - extension_data_len     (2 bytes)
      * - identities_len         (2 bytes)
-     * - identity_len           (2 bytes)
-     * - identity               (psk_identity_len bytes)
-     * - obfuscated_ticket_age  (4 bytes)
-     * - binders_len            (2 bytes)
-     * - binder_len             (1 byte)
-     * - binder                 (hash_len bytes)
      */
+    MBEDTLS_SSL_CHK_BUF_PTR( p, end, 6 );
+    p += 6;
 
-    identities_len = 6 + psk_identity_len;
-    l_binders_len = 1 + hash_len;
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+    if( ssl_tls13_ticket_get_identity(
+            ssl, &hash_alg, &identity, &identity_len ) == 0 )
+    {
+#if defined(MBEDTLS_HAVE_TIME)
+        mbedtls_time_t now = mbedtls_time( NULL );
+        mbedtls_ssl_session *session = ssl->session_negotiate;
+        uint32_t obfuscated_ticket_age =
+                                (uint32_t)( now - session->ticket_received );
+
+        obfuscated_ticket_age *= 1000;
+        obfuscated_ticket_age += session->ticket_age_add;
+
+        ret = ssl_tls13_write_identity( ssl, p, end,
+                                        identity, identity_len,
+                                        obfuscated_ticket_age,
+                                        &output_len );
+#else
+        ret = ssl_tls13_write_identity( ssl, p, end, identity, identity_len,
+                                        0, &output_len );
+#endif /* MBEDTLS_HAVE_TIME */
+        if( ret != 0 )
+            return( ret );
+
+        p += output_len;
+        l_binders_len += 1 + PSA_HASH_LENGTH( hash_alg );
+    }
+#endif /* MBEDTLS_SSL_SESSION_TICKETS */
+
+    if( ssl_tls13_psk_get_identity(
+            ssl, &hash_alg, &identity, &identity_len ) == 0 )
+    {
+
+        ret = ssl_tls13_write_identity( ssl, p, end, identity, identity_len, 0,
+                                        &output_len );
+        if( ret != 0 )
+            return( ret );
+
+        p += output_len;
+        l_binders_len += 1 + PSA_HASH_LENGTH( hash_alg );
+    }
 
     MBEDTLS_SSL_DEBUG_MSG( 3,
                  ( "client hello, adding pre_shared_key extension, "
                    "omitting PSK binder list" ) );
 
-    /* Extension header */
-    MBEDTLS_SSL_CHK_BUF_PTR( p, end, 8 );
-    MBEDTLS_PUT_UINT16_BE( MBEDTLS_TLS_EXT_PRE_SHARED_KEY, p, 0 );
-    MBEDTLS_PUT_UINT16_BE( 2 + identities_len + 2 + l_binders_len , p, 2 );
+    /* Take into account the two bytes for the length of the binders. */
+    l_binders_len += 2;
+    /* Check if there is enough space for binders */
+    MBEDTLS_SSL_CHK_BUF_PTR( p, end, l_binders_len );
 
-    MBEDTLS_PUT_UINT16_BE( identities_len, p, 4 );
-    MBEDTLS_PUT_UINT16_BE( psk_identity_len, p, 6 );
-    p += 8;
-    MBEDTLS_SSL_CHK_BUF_PTR( p, end, psk_identity_len );
-    memcpy( p, psk_identity, psk_identity_len );
-    p += psk_identity_len;
+    /*
+     * - extension_type         (2 bytes)
+     * - extension_data_len     (2 bytes)
+     * - identities_len         (2 bytes)
+     */
+    MBEDTLS_PUT_UINT16_BE( MBEDTLS_TLS_EXT_PRE_SHARED_KEY, buf, 0 );
+    MBEDTLS_PUT_UINT16_BE( p - buf - 4 + l_binders_len , buf, 2 );
+    MBEDTLS_PUT_UINT16_BE( p - buf - 6 , buf, 4 );
 
-    /* add obfuscated ticket age */
-    MBEDTLS_SSL_CHK_BUF_PTR( p, end, 4 );
-    MBEDTLS_PUT_UINT32_BE( obfuscated_ticket_age, p, 0 );
-    p += 4;
+    *out_len = ( p - buf ) + l_binders_len;
+    *binders_len = l_binders_len;
 
-    MBEDTLS_SSL_CHK_BUF_PTR( p, end, 2 + l_binders_len );
-    *out_len = ( p - buf ) + l_binders_len + 2;
-    *binders_len = l_binders_len + 2;
+    MBEDTLS_SSL_DEBUG_BUF( 3, "pre_shared_key identities", buf, p - buf );
 
     ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_PRE_SHARED_KEY;
 
@@ -880,67 +984,133 @@
 }
 
 int mbedtls_ssl_tls13_write_binders_of_pre_shared_key_ext(
-    mbedtls_ssl_context *ssl,
-    unsigned char *buf, unsigned char *end )
+        mbedtls_ssl_context *ssl, unsigned char *buf, unsigned char *end )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char *p = buf;
-    const unsigned char *psk_identity;
-    size_t psk_identity_len;
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info = NULL;
-    psa_algorithm_t psa_hash_alg;
-    int hash_len = 0;
-    const unsigned char *psk = NULL;
-    size_t psk_len = 0;
-    int psk_type;
-    unsigned char transcript[MBEDTLS_MD_MAX_SIZE];
-    size_t transcript_len;
+    psa_algorithm_t hash_alg = PSA_ALG_NONE;
+    const unsigned char *psk;
+    size_t psk_len;
+    size_t output_len;
 
-    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 );
-    }
-
-    ciphersuite_info = mbedtls_ssl_ciphersuite_from_id(
-            ssl->session_negotiate->ciphersuite );
-    if( ciphersuite_info  == NULL )
-        return( 0 );
-
-    psa_hash_alg = mbedtls_psa_translate_md( ciphersuite_info->mac );
-    hash_len = PSA_HASH_LENGTH( psa_hash_alg );
-    if( ( hash_len == -1 ) || ( ( end - buf ) != 3 + hash_len ) )
-        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
-
-    MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding PSK binder list" ) );
-
-    MBEDTLS_SSL_CHK_BUF_PTR( p, end, 3 + hash_len );
-    /* 2 bytes length field for array of psk binders */
-    MBEDTLS_PUT_UINT16_BE( hash_len + 1, p, 0 );
+    /* Check if we have space to write binders_len.
+     * - binders_len         (2 bytes)
+     */
+    MBEDTLS_SSL_CHK_BUF_PTR( p, end, 2 );
     p += 2;
 
-    /* 1 bytes length field for next psk binder */
-    *p++ = MBEDTLS_BYTE_0( hash_len );
-
-    /* Get current state of handshake transcript. */
-    ret = mbedtls_ssl_get_handshake_transcript( ssl, ciphersuite_info->mac,
-                                                transcript, sizeof( transcript ),
-                                                &transcript_len );
-    if( ret != 0 )
-        return( ret );
-
-    ret = mbedtls_ssl_tls13_create_psk_binder( ssl,
-              mbedtls_psa_translate_md( ciphersuite_info->mac ),
-              psk, psk_len, psk_type,
-              transcript, p );
-    if( ret != 0 )
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+    if( ssl_tls13_ticket_get_psk( ssl, &hash_alg, &psk, &psk_len ) == 0 )
     {
-        MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_create_psk_binder", ret );
-        return( ret );
+
+        ret = ssl_tls13_write_binder( ssl, p, end,
+                                      MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION,
+                                      hash_alg, psk, psk_len,
+                                      &output_len );
+        if( ret != 0 )
+            return( ret );
+        p += output_len;
     }
+#endif /* MBEDTLS_SSL_SESSION_TICKETS */
+
+    if( ssl_tls13_psk_get_psk( ssl, &hash_alg, &psk, &psk_len ) == 0 )
+    {
+
+        ret = ssl_tls13_write_binder( ssl, p, end,
+                                      MBEDTLS_SSL_TLS1_3_PSK_EXTERNAL,
+                                      hash_alg, psk, psk_len,
+                                      &output_len );
+        if( ret != 0 )
+            return( ret );
+        p += output_len;
+    }
+
+    MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding PSK binder list." ) );
+
+    /*
+     * - binders_len         (2 bytes)
+     */
+    MBEDTLS_PUT_UINT16_BE( p - buf - 2, buf, 0 );
+
+    MBEDTLS_SSL_DEBUG_BUF( 3, "pre_shared_key binders", buf, p - buf );
 
     return( 0 );
 }
+
+/*
+ * struct {
+ *   opaque identity<1..2^16-1>;
+ *   uint32 obfuscated_ticket_age;
+ * } PskIdentity;
+ *
+ * opaque PskBinderEntry<32..255>;
+ *
+ * struct {
+ *
+ *   select (Handshake.msg_type) {
+ *         ...
+ *         case server_hello: uint16 selected_identity;
+ *   };
+ *
+ * } PreSharedKeyExtension;
+ *
+ */
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_tls13_parse_server_pre_shared_key_ext( mbedtls_ssl_context *ssl,
+                                                      const unsigned char *buf,
+                                                      const unsigned char *end )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    int selected_identity;
+    const unsigned char *psk;
+    size_t psk_len;
+    psa_algorithm_t hash_alg;
+
+    MBEDTLS_SSL_CHK_BUF_READ_PTR( buf, end, 2 );
+    selected_identity = MBEDTLS_GET_UINT16_BE( buf, 0 );
+
+    MBEDTLS_SSL_DEBUG_MSG( 3, ( "selected_identity = %d", selected_identity ) );
+
+    if( selected_identity >= ssl_tls13_get_configured_psk_count( ssl ) )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "Invalid PSK identity." ) );
+
+        MBEDTLS_SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER,
+                                      MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER );
+        return( MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER );
+    }
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+    if( selected_identity == 0 && ssl_tls13_has_configured_ticket( ssl ) )
+    {
+        ret = ssl_tls13_ticket_get_psk( ssl, &hash_alg, &psk, &psk_len );
+    }
+    else
+#endif
+    if( ssl_tls13_has_configured_psk( ssl->conf ) )
+    {
+        ret = ssl_tls13_psk_get_psk( ssl, &hash_alg, &psk, &psk_len );
+    }
+    else
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
+        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+    }
+    if( ret != 0 )
+        return( ret );
+
+    ret = mbedtls_ssl_set_hs_psk( ssl, psk, psk_len );
+    if( ret != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_set_hs_psk", ret );
+        return( ret );
+    }
+
+    ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_PRE_SHARED_KEY;
+
+    return( 0 );
+}
+
 #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */
 
 int mbedtls_ssl_tls13_write_client_hello_exts( mbedtls_ssl_context *ssl,
@@ -1299,92 +1469,6 @@
     return( 0 );
 }
 
-#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
-/*
- * struct {
- *   opaque identity<1..2^16-1>;
- *   uint32 obfuscated_ticket_age;
- * } PskIdentity;
- *
- * opaque PskBinderEntry<32..255>;
- *
- * struct {
- *
- *   select (Handshake.msg_type) {
- *         ...
- *         case server_hello: uint16 selected_identity;
- *   };
- *
- * } PreSharedKeyExtension;
- *
- */
-
-MBEDTLS_CHECK_RETURN_CRITICAL
-static int ssl_tls13_parse_server_pre_shared_key_ext( mbedtls_ssl_context *ssl,
-                                                      const unsigned char *buf,
-                                                      const unsigned char *end )
-{
-    int ret = 0;
-    size_t selected_identity;
-
-    int psk_type;
-    const unsigned char *psk;
-    size_t psk_len;
-    const unsigned char *psk_identity;
-    size_t psk_identity_len;
-
-    /* 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( 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. */
-        return( MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE );
-    }
-
-    MBEDTLS_SSL_CHK_BUF_PTR( buf, end, 2 );
-    selected_identity = MBEDTLS_GET_UINT16_BE( buf, 0 );
-
-    /* We have offered only one PSK, so the only valid choice
-     * for the server is PSK index 0.
-     *
-     * This will change once we support multiple PSKs. */
-    if( selected_identity > 0 )
-    {
-        MBEDTLS_SSL_DEBUG_MSG( 1, ( "Server's chosen PSK identity out of range" ) );
-
-        if( ( ret = mbedtls_ssl_send_alert_message( ssl,
-                        MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                        MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ) ) != 0 )
-        {
-            return( ret );
-        }
-
-        return( MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER );
-    }
-
-    /* Set the chosen PSK
-     *
-     * TODO: We don't have to do this in case we offered 0-RTT and the
-     *       server accepted it, because in this case we've already
-     *       set the handshake PSK. */
-    ret = mbedtls_ssl_set_hs_psk( ssl, psk, psk_len );
-    if( ret != 0 )
-    {
-        MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_set_hs_psk", ret );
-        return( ret );
-    }
-
-    ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_PRE_SHARED_KEY;
-    return( 0 );
-}
-
-#endif
-
 /* Parse ServerHello message and configure context
  *
  * struct {
diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c
index 6591ecb..61a1bad 100644
--- a/library/ssl_tls13_server.c
+++ b/library/ssl_tls13_server.c
@@ -186,9 +186,9 @@
     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 ) );
+            3, ( "Invalid ticket start time ( now=%" MBEDTLS_PRINTF_LONGLONG
+                     ", start=%" MBEDTLS_PRINTF_LONGLONG " )",
+                 (long long)now, (long long)session->start ) );
         goto exit;
     }
 
@@ -208,7 +208,7 @@
     if( age_in_s > 604800 )
     {
         MBEDTLS_SSL_DEBUG_MSG(
-            3, ( "Ticket expired: Ticket age exceed limitation ticket_age=%lu",
+            3, ( "Ticket age exceeds limitation ticket_age=%lu",
                  (long unsigned int)age_in_s ) );
         goto exit;
     }
@@ -231,8 +231,8 @@
         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 ) );
+            3, ( "Ticket age outside tolerance window ( diff=%d )",
+                 (int)age_diff_in_ms ) );
         goto exit;
     }
 
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 7526bc6..6242e6e 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -120,6 +120,7 @@
 #define DFL_MFL_CODE            MBEDTLS_SSL_MAX_FRAG_LEN_NONE
 #define DFL_TRUNC_HMAC          -1
 #define DFL_TICKETS             MBEDTLS_SSL_SESSION_TICKETS_ENABLED
+#define DFL_DUMMY_TICKET        0
 #define DFL_TICKET_ROTATE       0
 #define DFL_TICKET_TIMEOUT      86400
 #define DFL_TICKET_AEAD         MBEDTLS_CIPHER_AES_256_GCM
@@ -638,6 +639,7 @@
     unsigned char mfl_code;     /* code for maximum fragment length         */
     int trunc_hmac;             /* accept truncated hmac?                   */
     int tickets;                /* enable / disable session tickets         */
+    int dummy_ticket;           /* enable / disable dummy ticket generator  */
     int ticket_rotate;          /* session ticket rotate (code coverage)    */
     int ticket_timeout;         /* session ticket lifetime                  */
     int ticket_aead;            /* session ticket protection                */
@@ -1351,6 +1353,75 @@
 }
 #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
 
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_HAVE_TIME)
+/* Functions for session ticket tests */
+int dummy_ticket_write( void *p_ticket, const mbedtls_ssl_session *session,
+                        unsigned char *start, const unsigned char *end,
+                        size_t *tlen, uint32_t *ticket_lifetime )
+{
+    int ret;
+    unsigned char *p = start;
+    size_t clear_len;
+    ((void) p_ticket);
+
+    if( end - p < 4 )
+    {
+        return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
+    }
+    *((uint32_t *)p) = 7 * 24 * 3600;
+    *ticket_lifetime = 7 * 24 * 3600;
+    p += 4;
+
+    /* Dump session state */
+    if( ( ret = mbedtls_ssl_session_save( session, p, end - p,
+                                          &clear_len ) ) != 0 )
+    {
+         return( ret );
+    }
+
+    *tlen = 4 + clear_len;
+
+    return( 0 );
+}
+
+int dummy_ticket_parse( void *p_ticket, mbedtls_ssl_session *session,
+                        unsigned char *buf, size_t len )
+{
+    int ret;
+    ((void) p_ticket);
+
+    if( ( ret = mbedtls_ssl_session_load( session, buf + 4, len - 4 ) ) != 0 )
+        return( ret );
+
+    switch( opt.dummy_ticket % 7 )
+    {
+        case 1:
+            return( MBEDTLS_ERR_SSL_INVALID_MAC );
+        case 2:
+            return( MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED );
+        case 3:
+            session->start = mbedtls_time( NULL ) + 10;
+            break;
+        case 4:
+            session->start = mbedtls_time( NULL ) - 10 - 7 * 24 * 3600;
+            break;
+        case 5:
+            session->start = mbedtls_time( NULL ) - 10;
+            break;
+        case 6:
+            session->start = mbedtls_time( NULL );
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+            session->ticket_age_add -= 1000;
+#endif
+            break;
+        default:
+            break;
+    }
+
+    return( ret );
+}
+#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_HAVE_TIME */
+
 int main( int argc, char *argv[] )
 {
     int ret = 0, len, written, frags, exchanges_left;
@@ -1607,6 +1678,7 @@
     opt.mfl_code            = DFL_MFL_CODE;
     opt.trunc_hmac          = DFL_TRUNC_HMAC;
     opt.tickets             = DFL_TICKETS;
+    opt.dummy_ticket        = DFL_DUMMY_TICKET;
     opt.ticket_rotate       = DFL_TICKET_ROTATE;
     opt.ticket_timeout      = DFL_TICKET_TIMEOUT;
     opt.ticket_aead         = DFL_TICKET_AEAD;
@@ -2002,6 +2074,12 @@
             if( opt.tickets < 0 )
                 goto usage;
         }
+        else if( strcmp( p, "dummy_ticket" ) == 0 )
+        {
+            opt.dummy_ticket = atoi( q );
+            if( opt.dummy_ticket < 0 )
+                goto usage;
+        }
         else if( strcmp( p, "ticket_rotate" ) == 0 )
         {
             opt.ticket_rotate = atoi( q );
@@ -2919,19 +2997,34 @@
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
     if( opt.tickets != MBEDTLS_SSL_SESSION_TICKETS_DISABLED )
     {
-        if( ( ret = mbedtls_ssl_ticket_setup( &ticket_ctx,
-                        rng_get, &rng,
-                        opt.ticket_aead,
-                        opt.ticket_timeout ) ) != 0 )
+#if defined(MBEDTLS_HAVE_TIME)
+        if( opt.dummy_ticket )
         {
-            mbedtls_printf( " failed\n  ! mbedtls_ssl_ticket_setup returned %d\n\n", ret );
-            goto exit;
+            mbedtls_ssl_conf_session_tickets_cb( &conf,
+                    dummy_ticket_write,
+                    dummy_ticket_parse,
+                    NULL );
+        }
+        else
+#endif /* MBEDTLS_HAVE_TIME */
+        {
+            if( ( ret = mbedtls_ssl_ticket_setup( &ticket_ctx,
+                            rng_get, &rng,
+                            opt.ticket_aead,
+                            opt.ticket_timeout ) ) != 0 )
+            {
+                mbedtls_printf(
+                    " failed\n  ! mbedtls_ssl_ticket_setup returned %d\n\n",
+                    ret );
+                goto exit;
+            }
+
+            mbedtls_ssl_conf_session_tickets_cb( &conf,
+                    mbedtls_ssl_ticket_write,
+                    mbedtls_ssl_ticket_parse,
+                    &ticket_ctx );
         }
 
-        mbedtls_ssl_conf_session_tickets_cb( &conf,
-                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
diff --git a/tests/opt-testcases/tls13-kex-modes.sh b/tests/opt-testcases/tls13-kex-modes.sh
index 3487026..c8586d2 100755
--- a/tests/opt-testcases/tls13-kex-modes.sh
+++ b/tests/opt-testcases/tls13-kex-modes.sh
@@ -66,6 +66,165 @@
             -s "Found PSK KEX MODE" \
             -s "No matched ciphersuite"
 
+requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_SSL_SRV_C \
+                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME
+requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
+                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
+                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+run_test "TLS 1.3 m->m: Multiple PSKs: valid ticket, reconnect with ticket" \
+         "$P_SRV force_version=tls13 tls13_kex_modes=psk_ephemeral debug_level=5 psk_identity=Client_identity psk=6162636465666768696a6b6c6d6e6f70 tickets=8" \
+         "$P_CLI force_version=tls13 tls13_kex_modes=psk_ephemeral debug_level=5 psk_identity=Client_identity psk=6162636465666768696a6b6c6d6e6f70 reco_mode=1 reconnect=1" \
+         0 \
+         -c "Pre-configured PSK number = 2" \
+         -s "sent selected_identity: 0" \
+         -s "key exchange mode: psk_ephemeral" \
+         -S "key exchange mode: psk$" \
+         -S "key exchange mode: ephemeral$" \
+         -S "ticket is not authentic"
+
+requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_SSL_SRV_C \
+                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME
+requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
+                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
+                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+run_test "TLS 1.3 m->m: Multiple PSKs: invalid ticket, reconnect with PSK" \
+         "$P_SRV force_version=tls13 tls13_kex_modes=psk_ephemeral debug_level=5 psk_identity=Client_identity psk=6162636465666768696a6b6c6d6e6f70 tickets=8 dummy_ticket=1" \
+         "$P_CLI force_version=tls13 tls13_kex_modes=psk_ephemeral debug_level=5 psk_identity=Client_identity psk=6162636465666768696a6b6c6d6e6f70 reco_mode=1 reconnect=1" \
+         0 \
+         -c "Pre-configured PSK number = 2" \
+         -s "sent selected_identity: 1" \
+         -s "key exchange mode: psk_ephemeral" \
+         -S "key exchange mode: psk$" \
+         -S "key exchange mode: ephemeral$" \
+         -s "ticket is not authentic"
+
+requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_SSL_SRV_C \
+                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME
+requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
+                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED \
+                             MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+run_test "TLS 1.3 m->m: Session resumption failure, ticket authentication failed." \
+         "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=8 dummy_ticket=1" \
+         "$P_CLI debug_level=4 reco_mode=1 reconnect=1" \
+         0 \
+         -c "Pre-configured PSK number = 1" \
+         -S "sent selected_identity:" \
+         -s "key exchange mode: ephemeral" \
+         -S "key exchange mode: psk_ephemeral" \
+         -S "key exchange mode: psk$" \
+         -s "ticket is not authentic" \
+         -S "ticket is expired" \
+         -S "Invalid ticket start time" \
+         -S "Ticket age exceeds limitation" \
+         -S "Ticket age outside tolerance window"
+
+requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_SSL_SRV_C \
+                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME
+requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
+                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED \
+                             MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+run_test "TLS 1.3 m->m: Session resumption failure, ticket expired." \
+         "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=8 dummy_ticket=2" \
+         "$P_CLI debug_level=4 reco_mode=1 reconnect=1" \
+         0 \
+         -c "Pre-configured PSK number = 1" \
+         -S "sent selected_identity:" \
+         -s "key exchange mode: ephemeral" \
+         -S "key exchange mode: psk_ephemeral" \
+         -S "key exchange mode: psk$" \
+         -S "ticket is not authentic" \
+         -s "ticket is expired" \
+         -S "Invalid ticket start time" \
+         -S "Ticket age exceeds limitation" \
+         -S "Ticket age outside tolerance window"
+
+requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_SSL_SRV_C \
+                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME
+requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
+                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED \
+                             MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+run_test "TLS 1.3 m->m: Session resumption failure, invalid start time." \
+         "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=8 dummy_ticket=3" \
+         "$P_CLI debug_level=4 reco_mode=1 reconnect=1" \
+         0 \
+         -c "Pre-configured PSK number = 1" \
+         -S "sent selected_identity:" \
+         -s "key exchange mode: ephemeral" \
+         -S "key exchange mode: psk_ephemeral" \
+         -S "key exchange mode: psk$" \
+         -S "ticket is not authentic" \
+         -S "ticket is expired" \
+         -s "Invalid ticket start time" \
+         -S "Ticket age exceeds limitation" \
+         -S "Ticket age outside tolerance window"
+
+requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_SSL_SRV_C \
+                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME
+requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
+                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED \
+                             MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+run_test "TLS 1.3 m->m: Session resumption failure, ticket expired. too old" \
+         "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=8 dummy_ticket=4" \
+         "$P_CLI debug_level=4 reco_mode=1 reconnect=1" \
+         0 \
+         -c "Pre-configured PSK number = 1" \
+         -S "sent selected_identity:" \
+         -s "key exchange mode: ephemeral" \
+         -S "key exchange mode: psk_ephemeral" \
+         -S "key exchange mode: psk$" \
+         -S "ticket is not authentic" \
+         -S "ticket is expired" \
+         -S "Invalid ticket start time" \
+         -s "Ticket age exceeds limitation" \
+         -S "Ticket age outside tolerance window"
+
+requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_SSL_SRV_C \
+                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME
+requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
+                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED \
+                             MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+run_test "TLS 1.3 m->m: Session resumption failure, age outside tolerance window, too young." \
+         "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=8 dummy_ticket=5" \
+         "$P_CLI debug_level=4 reco_mode=1 reconnect=1" \
+         0 \
+         -c "Pre-configured PSK number = 1" \
+         -S "sent selected_identity:" \
+         -s "key exchange mode: ephemeral" \
+         -S "key exchange mode: psk_ephemeral" \
+         -S "key exchange mode: psk$" \
+         -S "ticket is not authentic" \
+         -S "ticket is expired" \
+         -S "Invalid ticket start time" \
+         -S "Ticket age exceeds limitation" \
+         -s "Ticket age outside tolerance window"
+
+requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_SSL_SRV_C \
+                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME
+requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
+                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED \
+                             MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+run_test "TLS 1.3 m->m: Session resumption failure, age outside tolerance window, too old." \
+         "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=8 dummy_ticket=6" \
+         "$P_CLI debug_level=4 reco_mode=1 reconnect=1" \
+         0 \
+         -c "Pre-configured PSK number = 1" \
+         -S "sent selected_identity:" \
+         -s "key exchange mode: ephemeral" \
+         -S "key exchange mode: psk_ephemeral" \
+         -S "key exchange mode: psk$" \
+         -S "ticket is not authentic" \
+         -S "ticket is expired" \
+         -S "Invalid ticket start time" \
+         -S "Ticket age exceeds limitation" \
+         -s "Ticket age outside tolerance window"
 
 requires_gnutls_tls1_3
 requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE MBEDTLS_SSL_SRV_C MBEDTLS_DEBUG_C
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 67e9cfb..48dd89e 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -12842,7 +12842,6 @@
             -s "key exchange mode: psk_ephemeral" \
             -s "found pre_shared_key extension"
 
-
 requires_openssl_tls1_3
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 requires_config_enabled MBEDTLS_DEBUG_C
diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function
index f24d1a4..7b5743e 100644
--- a/tests/suites/test_suite_ssl.function
+++ b/tests/suites/test_suite_ssl.function
@@ -2184,8 +2184,9 @@
                              options->psk_str->len,
                              (const unsigned char *) psk_identity,
                              strlen( psk_identity ) ) == 0 );
-
+#if defined(MBEDTLS_SSL_SRV_C)
         mbedtls_ssl_conf_psk_cb( &server.conf, psk_dummy_callback, NULL );
+#endif
     }
 #endif
 #if defined(MBEDTLS_SSL_RENEGOTIATION)