Merge pull request #6403 from mpg/print-failed-suites

Print the list of failed suites in verbose mode
diff --git a/ChangeLog.d/fix_build_tls1_2_with_single_encryption_type.txt b/ChangeLog.d/fix_build_tls1_2_with_single_encryption_type.txt
new file mode 100644
index 0000000..bac4910
--- /dev/null
+++ b/ChangeLog.d/fix_build_tls1_2_with_single_encryption_type.txt
@@ -0,0 +1,4 @@
+Bugfix
+    * Fix bugs and missing dependencies when
+      building and testing configurations with
+      only one encryption type enabled in TLS 1.2.
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index 1038706..6997ffd 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -874,6 +874,11 @@
 #error "MBEDTLS_SSL_TICKET_C defined, but not all prerequisites"
 #endif
 
+#if defined(MBEDTLS_SSL_TICKET_C) && \
+    !( defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) || defined(MBEDTLS_CHACHAPOLY_C) )
+#error "MBEDTLS_SSL_TICKET_C defined, but not all prerequisites"
+#endif
+
 #if defined(MBEDTLS_SSL_TLS1_3_TICKET_NONCE_LENGTH) && \
     MBEDTLS_SSL_TLS1_3_TICKET_NONCE_LENGTH >= 256
 #error "MBEDTLS_SSL_TLS1_3_TICKET_NONCE_LENGTH must be less than 256"
@@ -962,7 +967,9 @@
 #error "MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH defined, but not all prerequisites"
 #endif
 
-
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION) && !( defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) || defined(MBEDTLS_CHACHAPOLY_C) )
+#error "MBEDTLS_SSL_CONTEXT_SERIALIZATION defined, but not all prerequisites"
+#endif
 
 /* Reject attempts to enable options that have been removed and that could
  * cause a build to succeed but with features removed. */
diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h
index 9e8ae37..23e601b 100644
--- a/include/mbedtls/mbedtls_config.h
+++ b/include/mbedtls/mbedtls_config.h
@@ -1380,6 +1380,8 @@
  * saved after the handshake to allow for more efficient serialization, so if
  * you don't need this feature you'll save RAM by disabling it.
  *
+ * Requires: MBEDTLS_GCM_C or MBEDTLS_CCM_C or MBEDTLS_CHACHAPOLY_C
+ *
  * Comment to disable the context serialization APIs.
  */
 #define MBEDTLS_SSL_CONTEXT_SERIALIZATION
@@ -3052,7 +3054,8 @@
  * Module:  library/ssl_ticket.c
  * Caller:
  *
- * Requires: MBEDTLS_CIPHER_C || MBEDTLS_USE_PSA_CRYPTO
+ * Requires: (MBEDTLS_CIPHER_C || MBEDTLS_USE_PSA_CRYPTO) &&
+ *           (MBEDTLS_GCM_C || MBEDTLS_CCM_C || MBEDTLS_CHACHAPOLY_C)
  */
 #define MBEDTLS_SSL_TICKET_C
 
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/constant_time.c b/library/constant_time.c
index 8980701..01a6976 100644
--- a/library/constant_time.c
+++ b/library/constant_time.c
@@ -81,7 +81,7 @@
 #endif
 }
 
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC)
+#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
 
 size_t mbedtls_ct_size_mask( size_t value )
 {
@@ -97,7 +97,7 @@
 #endif
 }
 
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
+#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
 
 #if defined(MBEDTLS_BIGNUM_C)
 
@@ -404,7 +404,7 @@
 
 #endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */
 
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC)
+#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
 
 void mbedtls_ct_memcpy_if_eq( unsigned char *dest,
                               const unsigned char *src,
@@ -654,7 +654,7 @@
 }
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
+#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
 
 #if defined(MBEDTLS_BIGNUM_C)
 
diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h
index fc24ae5..340a588 100644
--- a/library/constant_time_internal.h
+++ b/library/constant_time_internal.h
@@ -213,7 +213,7 @@
 
 #endif /* MBEDTLS_BASE64_C */
 
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC)
+#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
 
 /** Conditional memcpy without branches.
  *
@@ -321,7 +321,7 @@
                      unsigned char *output );
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
+#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
 
 #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
 
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 38b49cb..5434231 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -3592,6 +3592,7 @@
             break;
 #endif /* PSA_WANT_ALG_CHACHA20_POLY1305 */
         default:
+            (void) nonce_length;
             return( PSA_ERROR_NOT_SUPPORTED );
     }
 
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_msg.c b/library/ssl_msg.c
index dbef29b..06194bd 100644
--- a/library/ssl_msg.c
+++ b/library/ssl_msg.c
@@ -1124,7 +1124,9 @@
                              mbedtls_ssl_transform *transform,
                              mbedtls_record *rec )
 {
+#if defined(MBEDTLS_SSL_SOME_SUITES_USE_CBC) || defined(MBEDTLS_CIPHER_MODE_AEAD)
     size_t olen;
+#endif /* MBEDTLS_SSL_SOME_SUITES_USE_CBC || MBEDTLS_CIPHER_MODE_AEAD */
     mbedtls_ssl_mode_t ssl_mode;
     int ret;
 
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/fuzz/fuzz_server.c b/programs/fuzz/fuzz_server.c
index 3d11d47..95f43b8 100644
--- a/programs/fuzz/fuzz_server.c
+++ b/programs/fuzz/fuzz_server.c
@@ -42,7 +42,7 @@
     mbedtls_ssl_config conf;
     mbedtls_ctr_drbg_context ctr_drbg;
     mbedtls_entropy_context entropy;
-#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
     mbedtls_ssl_ticket_context ticket_ctx;
 #endif
     unsigned char buf[4096];
@@ -89,7 +89,7 @@
     }
     mbedtls_ssl_init( &ssl );
     mbedtls_ssl_config_init( &conf );
-#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
     mbedtls_ssl_ticket_init( &ticket_ctx );
 #endif
 
@@ -114,7 +114,7 @@
         mbedtls_ssl_conf_alpn_protocols( &conf, alpn_list );
     }
 #endif
-#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
     if( options & 0x4 )
     {
         if( mbedtls_ssl_ticket_setup( &ticket_ctx,
@@ -173,7 +173,7 @@
     }
 
 exit:
-#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
     mbedtls_ssl_ticket_free( &ticket_ctx );
 #endif
     mbedtls_entropy_free( &entropy );
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 7526bc6..4f789d5 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -49,7 +49,7 @@
 #include "mbedtls/ssl_cache.h"
 #endif
 
-#if defined(MBEDTLS_SSL_TICKET_C)
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
 #include "mbedtls/ssl_ticket.h"
 #endif
 
@@ -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
@@ -283,7 +284,7 @@
 #else
 #define USAGE_CA_CALLBACK ""
 #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */
-#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
 #define USAGE_TICKETS                                       \
     "    tickets=%%d          default: 1 (enabled)\n"       \
     "    ticket_rotate=%%d    default: 0 (disabled)\n"      \
@@ -291,7 +292,7 @@
     "    ticket_aead=%%s      default: \"AES-256-GCM\"\n"
 #else
 #define USAGE_TICKETS ""
-#endif /* MBEDTLS_SSL_SESSION_TICKETS */
+#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_TICKET_C */
 
 #define USAGE_EAP_TLS                                       \
     "    eap_tls=%%d          default: 0 (disabled)\n"
@@ -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;
@@ -1406,9 +1477,9 @@
 #if defined(MBEDTLS_SSL_CACHE_C)
     mbedtls_ssl_cache_context cache;
 #endif
-#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
     mbedtls_ssl_ticket_context ticket_ctx;
-#endif
+#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_TICKET_C */
 #if defined(SNI_OPTION)
     sni_entry *sni_info = NULL;
 #endif
@@ -1497,7 +1568,7 @@
 #if defined(MBEDTLS_SSL_CACHE_C)
     mbedtls_ssl_cache_init( &cache );
 #endif
-#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
     mbedtls_ssl_ticket_init( &ticket_ctx );
 #endif
 #if defined(MBEDTLS_SSL_ALPN)
@@ -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 );
@@ -2916,22 +2994,37 @@
                                    mbedtls_ssl_cache_set );
 #endif
 
-#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
     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
@@ -4212,7 +4305,7 @@
 #if defined(MBEDTLS_SSL_CACHE_C)
     mbedtls_ssl_cache_free( &cache );
 #endif
-#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
     mbedtls_ssl_ticket_free( &ticket_ctx );
 #endif
 #if defined(MBEDTLS_SSL_COOKIE_C)
diff --git a/scripts/config.py b/scripts/config.py
index f045f98..470c63d 100755
--- a/scripts/config.py
+++ b/scripts/config.py
@@ -7,6 +7,11 @@
     if 'MBEDTLS_RSA_C' in config: print('RSA is enabled')
 """
 
+# Note that as long as Mbed TLS 2.28 LTS is maintained, the version of
+# this script in the mbedtls-2.28 branch must remain compatible with
+# Python 3.4. The version in development may only use more recent features
+# in parts that are not backported to 2.28.
+
 ## Copyright The Mbed TLS Contributors
 ## SPDX-License-Identifier: Apache-2.0
 ##
diff --git a/tests/include/test/helpers.h b/tests/include/test/helpers.h
index fe3b787..6ec967e 100644
--- a/tests/include/test/helpers.h
+++ b/tests/include/test/helpers.h
@@ -298,12 +298,13 @@
  *                      of limbs is 0.
  * \param[out] plimbs   The address where the number of limbs will be stored.
  * \param[in] input     The test argument to read.
- *                      It is interpreted as a big-endian integer in base 256.
+ *                      It is interpreted as a hexadecimal representation
+ *                      of a non-negative integer.
  *
  * \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise.
  */
 int mbedtls_test_read_mpi_core( mbedtls_mpi_uint **pX, size_t *plimbs,
-                                const data_t *input );
+                                const char *input );
 
 /** Read an MPI from a hexadecimal string.
  *
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/scripts/all.sh b/tests/scripts/all.sh
index a1b47f4..298f6fb 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -1274,6 +1274,163 @@
     make test
 }
 
+component_test_tls1_2_default_stream_cipher_only () {
+    msg "build: default with only stream cipher"
+
+    # Disable AEAD (controlled by the presence of one of GCM_C, CCM_C, CHACHAPOLY_C
+    scripts/config.py unset MBEDTLS_GCM_C
+    scripts/config.py unset MBEDTLS_CCM_C
+    scripts/config.py unset MBEDTLS_CHACHAPOLY_C
+    # Disable CBC-legacy (controlled by MBEDTLS_CIPHER_MODE_CBC plus at least one block cipher (AES, ARIA, Camellia, DES))
+    scripts/config.py unset MBEDTLS_CIPHER_MODE_CBC
+    # Disable CBC-EtM (controlled by the same as CBC-legacy plus MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+    scripts/config.py unset MBEDTLS_SSL_ENCRYPT_THEN_MAC
+    # Enable stream (currently that's just the NULL pseudo-cipher (controlled by MBEDTLS_CIPHER_NULL_CIPHER))
+    scripts/config.py set MBEDTLS_CIPHER_NULL_CIPHER
+    # Modules that depend on AEAD
+    scripts/config.py unset MBEDTLS_SSL_CONTEXT_SERIALIZATION
+    scripts/config.py unset MBEDTLS_SSL_TICKET_C
+
+    make
+
+    msg "test: default with only stream cipher"
+    make test
+
+    # Not running ssl-opt.sh because most tests require a non-NULL ciphersuite.
+}
+
+component_test_tls1_2_default_stream_cipher_only_use_psa () {
+    msg "build: default with only stream cipher use psa"
+
+    scripts/config.py set MBEDTLS_USE_PSA_CRYPTO
+    # Disable AEAD (controlled by the presence of one of GCM_C, CCM_C, CHACHAPOLY_C)
+    scripts/config.py unset MBEDTLS_GCM_C
+    scripts/config.py unset MBEDTLS_CCM_C
+    scripts/config.py unset MBEDTLS_CHACHAPOLY_C
+    # Disable CBC-legacy (controlled by MBEDTLS_CIPHER_MODE_CBC plus at least one block cipher (AES, ARIA, Camellia, DES))
+    scripts/config.py unset MBEDTLS_CIPHER_MODE_CBC
+    # Disable CBC-EtM (controlled by the same as CBC-legacy plus MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+    scripts/config.py unset MBEDTLS_SSL_ENCRYPT_THEN_MAC
+    # Enable stream (currently that's just the NULL pseudo-cipher (controlled by MBEDTLS_CIPHER_NULL_CIPHER))
+    scripts/config.py set MBEDTLS_CIPHER_NULL_CIPHER
+    # Modules that depend on AEAD
+    scripts/config.py unset MBEDTLS_SSL_CONTEXT_SERIALIZATION
+    scripts/config.py unset MBEDTLS_SSL_TICKET_C
+
+    make
+
+    msg "test: default with only stream cipher use psa"
+    make test
+
+    # Not running ssl-opt.sh because most tests require a non-NULL ciphersuite.
+}
+
+component_test_tls1_2_default_cbc_legacy_cipher_only () {
+    msg "build: default with only CBC-legacy cipher"
+
+    # Disable AEAD (controlled by the presence of one of GCM_C, CCM_C, CHACHAPOLY_C)
+    scripts/config.py unset MBEDTLS_GCM_C
+    scripts/config.py unset MBEDTLS_CCM_C
+    scripts/config.py unset MBEDTLS_CHACHAPOLY_C
+    # Enable CBC-legacy (controlled by MBEDTLS_CIPHER_MODE_CBC plus at least one block cipher (AES, ARIA, Camellia, DES))
+    scripts/config.py set MBEDTLS_CIPHER_MODE_CBC
+    # Disable CBC-EtM (controlled by the same as CBC-legacy plus MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+    scripts/config.py unset MBEDTLS_SSL_ENCRYPT_THEN_MAC
+    # Disable stream (currently that's just the NULL pseudo-cipher (controlled by MBEDTLS_CIPHER_NULL_CIPHER))
+    scripts/config.py unset MBEDTLS_CIPHER_NULL_CIPHER
+    # Modules that depend on AEAD
+    scripts/config.py unset MBEDTLS_SSL_CONTEXT_SERIALIZATION
+    scripts/config.py unset MBEDTLS_SSL_TICKET_C
+
+    make
+
+    msg "test: default with only CBC-legacy cipher"
+    make test
+
+    msg "test: default with only CBC-legacy cipher - ssl-opt.sh (subset)"
+    tests/ssl-opt.sh -f "TLS 1.2"
+}
+
+component_test_tls1_2_deafult_cbc_legacy_cipher_only_use_psa () {
+    msg "build: default with only CBC-legacy cipher use psa"
+
+    scripts/config.py set MBEDTLS_USE_PSA_CRYPTO
+    # Disable AEAD (controlled by the presence of one of GCM_C, CCM_C, CHACHAPOLY_C)
+    scripts/config.py unset MBEDTLS_GCM_C
+    scripts/config.py unset MBEDTLS_CCM_C
+    scripts/config.py unset MBEDTLS_CHACHAPOLY_C
+    # Enable CBC-legacy (controlled by MBEDTLS_CIPHER_MODE_CBC plus at least one block cipher (AES, ARIA, Camellia, DES))
+    scripts/config.py set MBEDTLS_CIPHER_MODE_CBC
+    # Disable CBC-EtM (controlled by the same as CBC-legacy plus MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+    scripts/config.py unset MBEDTLS_SSL_ENCRYPT_THEN_MAC
+    # Disable stream (currently that's just the NULL pseudo-cipher (controlled by MBEDTLS_CIPHER_NULL_CIPHER))
+    scripts/config.py unset MBEDTLS_CIPHER_NULL_CIPHER
+    # Modules that depend on AEAD
+    scripts/config.py unset MBEDTLS_SSL_CONTEXT_SERIALIZATION
+    scripts/config.py unset MBEDTLS_SSL_TICKET_C
+
+    make
+
+    msg "test: default with only CBC-legacy cipher use psa"
+    make test
+
+    msg "test: default with only CBC-legacy cipher use psa - ssl-opt.sh (subset)"
+    tests/ssl-opt.sh -f "TLS 1.2"
+}
+
+component_test_tls1_2_default_cbc_legacy_cbc_etm_cipher_only () {
+    msg "build: default with only CBC-legacy and CBC-EtM ciphers"
+
+    # Disable AEAD (controlled by the presence of one of GCM_C, CCM_C, CHACHAPOLY_C)
+    scripts/config.py unset MBEDTLS_GCM_C
+    scripts/config.py unset MBEDTLS_CCM_C
+    scripts/config.py unset MBEDTLS_CHACHAPOLY_C
+    # Enable CBC-legacy (controlled by MBEDTLS_CIPHER_MODE_CBC plus at least one block cipher (AES, ARIA, Camellia, DES))
+    scripts/config.py set MBEDTLS_CIPHER_MODE_CBC
+    # Enable CBC-EtM (controlled by the same as CBC-legacy plus MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+    scripts/config.py set MBEDTLS_SSL_ENCRYPT_THEN_MAC
+    # Disable stream (currently that's just the NULL pseudo-cipher (controlled by MBEDTLS_CIPHER_NULL_CIPHER))
+    scripts/config.py unset MBEDTLS_CIPHER_NULL_CIPHER
+    # Modules that depend on AEAD
+    scripts/config.py unset MBEDTLS_SSL_CONTEXT_SERIALIZATION
+    scripts/config.py unset MBEDTLS_SSL_TICKET_C
+
+    make
+
+    msg "test: default with only CBC-legacy and CBC-EtM ciphers"
+    make test
+
+    msg "test: default with only CBC-legacy and CBC-EtM ciphers - ssl-opt.sh (subset)"
+    tests/ssl-opt.sh -f "TLS 1.2"
+}
+
+component_test_tls1_2_default_cbc_legacy_cbc_etm_cipher_only_use_psa () {
+    msg "build: default with only CBC-legacy and CBC-EtM ciphers use psa"
+
+    scripts/config.py set MBEDTLS_USE_PSA_CRYPTO
+    # Disable AEAD (controlled by the presence of one of GCM_C, CCM_C, CHACHAPOLY_C)
+    scripts/config.py unset MBEDTLS_GCM_C
+    scripts/config.py unset MBEDTLS_CCM_C
+    scripts/config.py unset MBEDTLS_CHACHAPOLY_C
+    # Enable CBC-legacy (controlled by MBEDTLS_CIPHER_MODE_CBC plus at least one block cipher (AES, ARIA, Camellia, DES))
+    scripts/config.py set MBEDTLS_CIPHER_MODE_CBC
+    # Enable CBC-EtM (controlled by the same as CBC-legacy plus MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+    scripts/config.py set MBEDTLS_SSL_ENCRYPT_THEN_MAC
+    # Disable stream (currently that's just the NULL pseudo-cipher (controlled by MBEDTLS_CIPHER_NULL_CIPHER))
+    scripts/config.py unset MBEDTLS_CIPHER_NULL_CIPHER
+    # Modules that depend on AEAD
+    scripts/config.py unset MBEDTLS_SSL_CONTEXT_SERIALIZATION
+    scripts/config.py unset MBEDTLS_SSL_TICKET_C
+
+    make
+
+    msg "test: default with only CBC-legacy and CBC-EtM ciphers use psa"
+    make test
+
+    msg "test: default with only CBC-legacy and CBC-EtM ciphers use psa - ssl-opt.sh (subset)"
+    tests/ssl-opt.sh -f "TLS 1.2"
+}
+
 component_test_psa_external_rng_use_psa_crypto () {
     msg "build: full + PSA_CRYPTO_EXTERNAL_RNG + USE_PSA_CRYPTO minus CTR_DRBG"
     scripts/config.py full
diff --git a/tests/src/helpers.c b/tests/src/helpers.c
index 557c13c..b7c8364 100644
--- a/tests/src/helpers.c
+++ b/tests/src/helpers.c
@@ -348,19 +348,46 @@
 #include "bignum_core.h"
 
 int mbedtls_test_read_mpi_core( mbedtls_mpi_uint **pX, size_t *plimbs,
-                                const data_t *input )
+                                const char *input )
 {
     /* Sanity check */
     if( *pX != NULL )
         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
 
-    *plimbs = CHARS_TO_LIMBS( input->len );
+    size_t hex_len = strlen( input );
+    size_t byte_len = ( hex_len + 1 ) / 2;
+    *plimbs = CHARS_TO_LIMBS( byte_len );
     if( *plimbs == 0 )
         return( 0 );
+
     *pX = mbedtls_calloc( *plimbs, sizeof( **pX ) );
     if( *pX == NULL )
         return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
-    return( mbedtls_mpi_core_read_be( *pX, *plimbs, input->x, input->len ) );
+
+    unsigned char *byte_start = ( unsigned char * ) *pX;
+    if( byte_len % sizeof( mbedtls_mpi_uint ) != 0 )
+    {
+        byte_start += sizeof( mbedtls_mpi_uint ) - byte_len % sizeof( mbedtls_mpi_uint );
+    }
+    if( ( hex_len & 1 ) != 0 )
+    {
+        /* mbedtls_test_unhexify wants an even number of hex digits */
+        TEST_ASSERT( ascii2uc( *input, byte_start ) == 0 );
+        ++byte_start;
+        ++input;
+        --byte_len;
+    }
+    TEST_ASSERT( mbedtls_test_unhexify( byte_start,
+                                        byte_len,
+                                        input,
+                                        &byte_len ) == 0 );
+
+    mbedtls_mpi_core_bigendian_to_host( *pX, *plimbs );
+    return( 0 );
+
+exit:
+    mbedtls_free( *pX );
+    return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
 }
 
 int mbedtls_test_read_mpi( mbedtls_mpi *X, const char *s )
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_cipher.function b/tests/suites/test_suite_cipher.function
index 37468df..af617fc 100644
--- a/tests/suites/test_suite_cipher.function
+++ b/tests/suites/test_suite_cipher.function
@@ -1,9 +1,6 @@
 /* BEGIN_HEADER */
 #include "mbedtls/cipher.h"
-
-#if defined(MBEDTLS_AES_C)
 #include "mbedtls/aes.h"
-#endif
 
 #if defined(MBEDTLS_GCM_C)
 #include "mbedtls/gcm.h"
diff --git a/tests/suites/test_suite_cmac.data b/tests/suites/test_suite_cmac.data
index 70b7609..5956a69 100644
--- a/tests/suites/test_suite_cmac.data
+++ b/tests/suites/test_suite_cmac.data
@@ -22,15 +22,15 @@
 
 CMAC init #5 AES-224: bad key size
 depends_on:MBEDTLS_AES_C
-mbedtls_cmac_setkey:MBEDTLS_CIPHER_ID_AES:224:MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
+mbedtls_cmac_setkey:MBEDTLS_CIPHER_AES_128_ECB:224:MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
 
 CMAC init #6 AES-0: bad key size
 depends_on:MBEDTLS_AES_C
-mbedtls_cmac_setkey:MBEDTLS_CIPHER_ID_AES:0:MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
+mbedtls_cmac_setkey:MBEDTLS_CIPHER_AES_128_ECB:0:MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
 
 CMAC init #7 Camellia: wrong cipher
 depends_on:MBEDTLS_CAMELLIA_C
-mbedtls_cmac_setkey:MBEDTLS_CIPHER_ID_CAMELLIA:128:MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
+mbedtls_cmac_setkey:MBEDTLS_CIPHER_CAMELLIA_192_ECB:128:MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
 
 CMAC Single Blocks #1 - Empty block, no updates
 mbedtls_cmac_multiple_blocks:MBEDTLS_CIPHER_AES_128_ECB:"2b7e151628aed2a6abf7158809cf4f3c":128:16:"":-1:"":-1:"":-1:"":-1:"bb1d6929e95937287fa37d129b756746"
diff --git a/tests/suites/test_suite_mpi.data b/tests/suites/test_suite_mpi.data
index be4c056..95e0d31 100644
--- a/tests/suites/test_suite_mpi.data
+++ b/tests/suites/test_suite_mpi.data
@@ -441,30 +441,66 @@
 Base test mbedtls_mpi_lsb #4
 mpi_lsb:"2000":13
 
-Base test mbedtls_mpi_bitlen #1
+Test mbedtls_mpi_core_bitlen 764-bit
+mpi_core_bitlen:"941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":764
+
+Test mbedtls_mpi_core_bitlen 0x18
+mpi_core_bitlen:"18":5
+
+Test mbedtls_mpi_core_bitlen 0x18 with leading 0 limb(s)
+mpi_core_bitlen:"00000000000000018":5
+
+Test mbedtls_mpi_core_bitlen 0x18 << 64
+mpi_core_bitlen:"180000000000000000":69
+
+Test mbedtls_mpi_core_bitlen 0x01
+mpi_core_bitlen:"1":1
+
+Test mbedtls_mpi_core_bitlen 0x0f
+mpi_core_bitlen:"f":4
+
+Test mbedtls_mpi_core_bitlen 0x10
+mpi_core_bitlen:"10":5
+
+Test mbedtls_mpi_core_bitlen 0x0a
+mpi_core_bitlen:"a":4
+
+Test mbedtls_mpi_core_bitlen: 0 (1 limb)
+mpi_core_bitlen:"0":0
+
+Test mbedtls_mpi_bitlen 764-bit
 mpi_bitlen:"941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":764
 
-Base test mbedtls_mpi_bitlen #2
+Test mbedtls_mpi_bitlen 0x18
 mpi_bitlen:"18":5
 
-Base test mbedtls_mpi_bitlen #3
+Test mbedtls_mpi_bitlen 0x18 with leading 0 limb(s)
+mpi_bitlen:"00000000000000018":5
+
+Test mbedtls_mpi_bitlen 0x18 << 64
+mpi_bitlen:"180000000000000000":69
+
+Test mbedtls_mpi_bitlen 0x01
 mpi_bitlen:"1":1
 
-Base test mbedtls_mpi_bitlen #4
+Test mbedtls_mpi_bitlen 0x0f
 mpi_bitlen:"f":4
 
-Base test mbedtls_mpi_bitlen #5
+Test mbedtls_mpi_bitlen 0x10
 mpi_bitlen:"10":5
 
-Base test mbedtls_mpi_bitlen #6
+Test mbedtls_mpi_bitlen 0x0a
 mpi_bitlen:"a":4
 
-Base test mbedtls_mpi_bitlen: 0 (null)
+Test mbedtls_mpi_bitlen: 0 (null)
 mpi_bitlen:"":0
 
-Base test mbedtls_mpi_bitlen: 0 (1 limb)
+Test mbedtls_mpi_bitlen: 0 (1 limb)
 mpi_bitlen:"0":0
 
+Test mbedtls_mpi_bitlen: -0x18
+mpi_bitlen:"-18":5
+
 Base test mbedtls_mpi_cmp_int #1
 mpi_cmp_int:693:693:0
 
@@ -595,13 +631,13 @@
 mpi_cmp_mpi:"-1230000000000000000":"0":-1
 
 mbedtls_mpi_core_lt_ct: x=y (1 limb)
-mpi_core_lt_ct:"02B5":"02B5":0
+mpi_core_lt_ct:"2B5":"2B5":0
 
 mbedtls_mpi_core_lt_ct: x>y (1 limb)
-mpi_core_lt_ct:"02B5":"02B4":0
+mpi_core_lt_ct:"2B5":"2B4":0
 
 mbedtls_mpi_core_lt_ct: x<y (1 limb)
-mpi_core_lt_ct:"02B5":"02B6":1
+mpi_core_lt_ct:"2B5":"2B6":1
 
 mbedtls_mpi_core_lt_ct: x=y (0 limbs)
 mpi_core_lt_ct:"":"":0
@@ -667,7 +703,7 @@
 mpi_core_lt_ct:"000000FF":"FFFFFFFF":1
 
 mbedtls_mpi_core_lt_ct: x<y, zero vs non-zero MS limb
-mpi_core_lt_ct:"00FFFFFFFFFFFFFFFF":"01FFFFFFFFFFFFFFFF":1
+mpi_core_lt_ct:"0FFFFFFFFFFFFFFFF":"1FFFFFFFFFFFFFFFF":1
 
 mbedtls_mpi_core_lt_ct: x>y, equal MS limbs
 mpi_core_lt_ct:"EEFFFFFFFFFFFFFFFF":"EEFFFFFFFFFFFFFFF1":0
diff --git a/tests/suites/test_suite_mpi.function b/tests/suites/test_suite_mpi.function
index d450197..9812c56 100644
--- a/tests/suites/test_suite_mpi.function
+++ b/tests/suites/test_suite_mpi.function
@@ -665,6 +665,20 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void mpi_core_bitlen( char *input_X, int nr_bits )
+{
+    mbedtls_mpi_uint *X = NULL;
+    size_t limbs;
+
+    TEST_EQUAL( mbedtls_test_read_mpi_core( &X, &limbs, input_X ), 0 );
+    TEST_EQUAL( mbedtls_mpi_core_bitlen( X, limbs ), nr_bits );
+
+exit:
+    mbedtls_free( X );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void mpi_bitlen( char * input_X, int nr_bits )
 {
     mbedtls_mpi X;
@@ -728,7 +742,7 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
-void mpi_core_lt_ct( data_t * input_X, data_t * input_Y, int exp_ret )
+void mpi_core_lt_ct( char *input_X, char *input_Y, int exp_ret )
 {
     mbedtls_mpi_uint *X = NULL;
     size_t X_limbs;
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)