Merge pull request #8858 from waleed-elmelegy-arm/add_alpn_to_session

Add ALPN information in session tickets
diff --git a/ChangeLog.d/fix-new-rn-on-hrr.txt b/ChangeLog.d/fix-new-rn-on-hrr.txt
new file mode 100644
index 0000000..1b4f5e6
--- /dev/null
+++ b/ChangeLog.d/fix-new-rn-on-hrr.txt
@@ -0,0 +1,3 @@
+Bugfix
+   * In TLS 1.3 clients, fix an interoperability problem due to the client
+     generating a new random after a HelloRetryRequest. Fixes #8669.
diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h
index d2e8674..fde302f 100644
--- a/include/mbedtls/pk.h
+++ b/include/mbedtls/pk.h
@@ -390,77 +390,6 @@
                             const mbedtls_svc_key_id_t key);
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
-#if defined(MBEDTLS_PSA_CRYPTO_C)
-/**
- * \brief           Create a PK context starting from a key stored in PSA.
- *                  This key:
- *                  - must be exportable and
- *                  - must be an RSA or EC key pair or public key (FFDH is not supported in PK).
- *
- *                  The resulting PK object will be a transparent type:
- *                  - #MBEDTLS_PK_RSA for RSA keys or
- *                  - #MBEDTLS_PK_ECKEY for EC keys.
- *
- *                  Once this functions returns the PK object will be completely
- *                  independent from the original PSA key that it was generated
- *                  from.
- *                  Calling mbedtls_pk_sign(), mbedtls_pk_verify(),
- *                  mbedtls_pk_encrypt(), mbedtls_pk_decrypt() on the resulting
- *                  PK context will perform the corresponding algorithm for that
- *                  PK context type.
- *                  * For ECDSA, the choice of deterministic vs randomized will
- *                    be based on the compile-time setting #MBEDTLS_ECDSA_DETERMINISTIC.
- *                  * For an RSA key, the output PK context will allow both
- *                    encrypt/decrypt and sign/verify regardless of the original
- *                    key's policy.
- *                    The original key's policy determines the output key's padding
- *                    mode: PCKS1 v2.1 is set if the PSA key policy is OAEP or PSS,
- *                    otherwise PKCS1 v1.5 is set.
- *
- * \param key_id    The key identifier of the key stored in PSA.
- * \param pk        The PK context that will be filled. It must be initialized,
- *                  but not set up.
- *
- * \return          0 on success.
- * \return          #MBEDTLS_ERR_PK_BAD_INPUT_DATA in case the provided input
- *                  parameters are not correct.
- */
-int mbedtls_pk_copy_from_psa(mbedtls_svc_key_id_t key_id, mbedtls_pk_context *pk);
-
-/**
- * \brief           Create a PK context for the public key of a PSA key.
- *
- *                  The key must be an RSA or ECC key. It can be either a
- *                  public key or a key pair, and only the public key is copied.
- *                  The resulting PK object will be a transparent type:
- *                  - #MBEDTLS_PK_RSA for RSA keys or
- *                  - #MBEDTLS_PK_ECKEY for EC keys.
- *
- *                  Once this functions returns the PK object will be completely
- *                  independent from the original PSA key that it was generated
- *                  from.
- *                  Calling mbedtls_pk_verify() or
- *                  mbedtls_pk_encrypt() on the resulting
- *                  PK context will perform the corresponding algorithm for that
- *                  PK context type.
- *
- *                  For an RSA key, the output PK context will allow both
- *                  encrypt and verify regardless of the original key's policy.
- *                  The original key's policy determines the output key's padding
- *                  mode: PCKS1 v2.1 is set if the PSA key policy is OAEP or PSS,
- *                  otherwise PKCS1 v1.5 is set.
- *
- * \param key_id    The key identifier of the key stored in PSA.
- * \param pk        The PK context that will be filled. It must be initialized,
- *                  but not set up.
- *
- * \return          0 on success.
- * \return          MBEDTLS_ERR_PK_BAD_INPUT_DATA in case the provided input
- *                  parameters are not correct.
- */
-int mbedtls_pk_copy_public_from_psa(mbedtls_svc_key_id_t key_id, mbedtls_pk_context *pk);
-#endif /* MBEDTLS_PSA_CRYPTO_C */
-
 #if defined(MBEDTLS_PK_RSA_ALT_SUPPORT)
 /**
  * \brief           Initialize an RSA-alt context
@@ -529,7 +458,7 @@
  *                  PSA_ALG_RSA_PKCS1V15_CRYPT,
  *                  PSA_ALG_ECDSA(hash),
  *                  PSA_ALG_ECDH, where hash is a specific hash.
- * \param usage  PSA usage flag to check against, must be composed of:
+ * \param usage     PSA usage flag to check against, must be composed of:
  *                  PSA_KEY_USAGE_SIGN_HASH
  *                  PSA_KEY_USAGE_DECRYPT
  *                  PSA_KEY_USAGE_DERIVE.
@@ -550,7 +479,7 @@
                           psa_key_usage_t usage);
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
-#if defined(MBEDTLS_PSA_CRYPTO_C)
+#if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
 /**
  * \brief           Determine valid PSA attributes that can be used to
  *                  import a key into PSA.
@@ -710,7 +639,76 @@
 int mbedtls_pk_import_into_psa(const mbedtls_pk_context *pk,
                                const psa_key_attributes_t *attributes,
                                mbedtls_svc_key_id_t *key_id);
-#endif /* MBEDTLS_PSA_CRYPTO_C */
+
+/**
+ * \brief           Create a PK context starting from a key stored in PSA.
+ *                  This key:
+ *                  - must be exportable and
+ *                  - must be an RSA or EC key pair or public key (FFDH is not supported in PK).
+ *
+ *                  The resulting PK object will be a transparent type:
+ *                  - #MBEDTLS_PK_RSA for RSA keys or
+ *                  - #MBEDTLS_PK_ECKEY for EC keys.
+ *
+ *                  Once this functions returns the PK object will be completely
+ *                  independent from the original PSA key that it was generated
+ *                  from.
+ *                  Calling mbedtls_pk_sign(), mbedtls_pk_verify(),
+ *                  mbedtls_pk_encrypt(), mbedtls_pk_decrypt() on the resulting
+ *                  PK context will perform the corresponding algorithm for that
+ *                  PK context type.
+ *                  * For ECDSA, the choice of deterministic vs randomized will
+ *                    be based on the compile-time setting #MBEDTLS_ECDSA_DETERMINISTIC.
+ *                  * For an RSA key, the output PK context will allow both
+ *                    encrypt/decrypt and sign/verify regardless of the original
+ *                    key's policy.
+ *                    The original key's policy determines the output key's padding
+ *                    mode: PCKS1 v2.1 is set if the PSA key policy is OAEP or PSS,
+ *                    otherwise PKCS1 v1.5 is set.
+ *
+ * \param key_id    The key identifier of the key stored in PSA.
+ * \param pk        The PK context that will be filled. It must be initialized,
+ *                  but not set up.
+ *
+ * \return          0 on success.
+ * \return          #MBEDTLS_ERR_PK_BAD_INPUT_DATA in case the provided input
+ *                  parameters are not correct.
+ */
+int mbedtls_pk_copy_from_psa(mbedtls_svc_key_id_t key_id, mbedtls_pk_context *pk);
+
+/**
+ * \brief           Create a PK context for the public key of a PSA key.
+ *
+ *                  The key must be an RSA or ECC key. It can be either a
+ *                  public key or a key pair, and only the public key is copied.
+ *                  The resulting PK object will be a transparent type:
+ *                  - #MBEDTLS_PK_RSA for RSA keys or
+ *                  - #MBEDTLS_PK_ECKEY for EC keys.
+ *
+ *                  Once this functions returns the PK object will be completely
+ *                  independent from the original PSA key that it was generated
+ *                  from.
+ *                  Calling mbedtls_pk_verify() or
+ *                  mbedtls_pk_encrypt() on the resulting
+ *                  PK context will perform the corresponding algorithm for that
+ *                  PK context type.
+ *
+ *                  For an RSA key, the output PK context will allow both
+ *                  encrypt and verify regardless of the original key's policy.
+ *                  The original key's policy determines the output key's padding
+ *                  mode: PCKS1 v2.1 is set if the PSA key policy is OAEP or PSS,
+ *                  otherwise PKCS1 v1.5 is set.
+ *
+ * \param key_id    The key identifier of the key stored in PSA.
+ * \param pk        The PK context that will be filled. It must be initialized,
+ *                  but not set up.
+ *
+ * \return          0 on success.
+ * \return          MBEDTLS_ERR_PK_BAD_INPUT_DATA in case the provided input
+ *                  parameters are not correct.
+ */
+int mbedtls_pk_copy_public_from_psa(mbedtls_svc_key_id_t key_id, mbedtls_pk_context *pk);
+#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */
 
 /**
  * \brief           Verify signature (including padding if relevant).
diff --git a/include/mbedtls/ssl_ticket.h b/include/mbedtls/ssl_ticket.h
index 5842049..2ee1400 100644
--- a/include/mbedtls/ssl_ticket.h
+++ b/include/mbedtls/ssl_ticket.h
@@ -108,10 +108,16 @@
  *                  least as strong as the strongest ciphersuite
  *                  supported. Usually that means a 256-bit key.
  *
- * \note            The lifetime of the keys is twice the lifetime of tickets.
- *                  It is recommended to pick a reasonable lifetime so as not
+ * \note            It is recommended to pick a reasonable lifetime so as not
  *                  to negate the benefits of forward secrecy.
  *
+ * \note            The TLS 1.3 specification states that ticket lifetime must
+ *                  be smaller than seven days. If ticket lifetime has been
+ *                  set to a value greater than seven days in this module then
+ *                  if the TLS 1.3 is configured to send tickets after the
+ *                  handshake it will fail the connection when trying to send
+ *                  the first ticket.
+ *
  * \return          0 if successful,
  *                  or a specific MBEDTLS_ERR_XXX error code
  */
@@ -145,10 +151,16 @@
  * \note            \c klength must be sufficient for use by cipher specified
  *                  to \c mbedtls_ssl_ticket_setup
  *
- * \note            The lifetime of the keys is twice the lifetime of tickets.
- *                  It is recommended to pick a reasonable lifetime so as not
+ * \note            It is recommended to pick a reasonable lifetime so as not
  *                  to negate the benefits of forward secrecy.
  *
+ * \note            The TLS 1.3 specification states that ticket lifetime must
+ *                  be smaller than seven days. If ticket lifetime has been
+ *                  set to a value greater than seven days in this module then
+ *                  if the TLS 1.3 is configured to send tickets after the
+ *                  handshake it will fail the connection when trying to send
+ *                  the first ticket.
+ *
  * \return          0 if successful,
  *                  or a specific MBEDTLS_ERR_XXX error code
  */
diff --git a/library/pk.c b/library/pk.c
index 1d85c92..ec3741b 100644
--- a/library/pk.c
+++ b/library/pk.c
@@ -324,14 +324,14 @@
     }
 
     psa_algorithm_t key_alg = psa_get_key_algorithm(&attributes);
-    /* Key's enrollment is available only when MBEDTLS_PSA_CRYPTO_CLIENT is
-     * defined, i.e. when the Mbed TLS implementation of PSA Crypto is being used.
+    /* Key's enrollment is available only when an Mbed TLS implementation of PSA
+     * Crypto is being used, i.e. when MBEDTLS_PSA_CRYPTO_C is defined.
      * Even though we don't officially support using other implementations of PSA
-     * Crypto with TLS and X.509 (yet), we're still trying to simplify the life of
-     * people who would like to try it before it's officially supported. */
-#if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
+     * Crypto with TLS and X.509 (yet), we try to keep vendor's customizations
+     * separated. */
+#if defined(MBEDTLS_PSA_CRYPTO_C)
     psa_algorithm_t key_alg2 = psa_get_key_enrollment_algorithm(&attributes);
-#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */
+#endif /* MBEDTLS_PSA_CRYPTO_C */
     key_usage = psa_get_key_usage_flags(&attributes);
     psa_reset_key_attributes(&attributes);
 
@@ -349,11 +349,11 @@
     if (alg == key_alg) {
         return 1;
     }
-#if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
+#if defined(MBEDTLS_PSA_CRYPTO_C)
     if (alg == key_alg2) {
         return 1;
     }
-#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */
+#endif /* MBEDTLS_PSA_CRYPTO_C */
 
     /*
      * If key_alg [or key_alg2] is a hash-and-sign with a wildcard for the hash,
@@ -361,26 +361,25 @@
      * then alg is compliant with this key alg
      */
     if (PSA_ALG_IS_SIGN_HASH(alg)) {
-
         if (PSA_ALG_IS_SIGN_HASH(key_alg) &&
             PSA_ALG_SIGN_GET_HASH(key_alg) == PSA_ALG_ANY_HASH &&
             (alg & ~PSA_ALG_HASH_MASK) == (key_alg & ~PSA_ALG_HASH_MASK)) {
             return 1;
         }
-#if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
+#if defined(MBEDTLS_PSA_CRYPTO_C)
         if (PSA_ALG_IS_SIGN_HASH(key_alg2) &&
             PSA_ALG_SIGN_GET_HASH(key_alg2) == PSA_ALG_ANY_HASH &&
             (alg & ~PSA_ALG_HASH_MASK) == (key_alg2 & ~PSA_ALG_HASH_MASK)) {
             return 1;
         }
-#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */
+#endif /* MBEDTLS_PSA_CRYPTO_C */
     }
 
     return 0;
 }
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
-#if defined(MBEDTLS_PSA_CRYPTO_C)
+#if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
 #if defined(MBEDTLS_RSA_C)
 static psa_algorithm_t psa_algorithm_for_rsa(const mbedtls_rsa_context *rsa,
                                              int want_crypt)
@@ -577,7 +576,14 @@
     }
 
     psa_set_key_usage_flags(attributes, more_usage);
+    /* Key's enrollment is available only when an Mbed TLS implementation of PSA
+     * Crypto is being used, i.e. when MBEDTLS_PSA_CRYPTO_C is defined.
+     * Even though we don't officially support using other implementations of PSA
+     * Crypto with TLS and X.509 (yet), we try to keep vendor's customizations
+     * separated. */
+#if defined(MBEDTLS_PSA_CRYPTO_C)
     psa_set_key_enrollment_algorithm(attributes, PSA_ALG_NONE);
+#endif
 
     return 0;
 }
@@ -854,7 +860,136 @@
         return import_pair_into_psa(pk, attributes, key_id);
     }
 }
-#endif /* MBEDTLS_PSA_CRYPTO_C */
+
+static int copy_from_psa(mbedtls_svc_key_id_t key_id,
+                         mbedtls_pk_context *pk,
+                         int public_only)
+{
+    psa_status_t status;
+    psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_type_t key_type;
+    psa_algorithm_t alg_type;
+    size_t key_bits;
+    /* Use a buffer size large enough to contain either a key pair or public key. */
+    unsigned char exp_key[PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE];
+    size_t exp_key_len;
+    int ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+
+    if (pk == NULL) {
+        return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+    }
+
+    status = psa_get_key_attributes(key_id, &key_attr);
+    if (status != PSA_SUCCESS) {
+        return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+    }
+
+    if (public_only) {
+        status = psa_export_public_key(key_id, exp_key, sizeof(exp_key), &exp_key_len);
+    } else {
+        status = psa_export_key(key_id, exp_key, sizeof(exp_key), &exp_key_len);
+    }
+    if (status != PSA_SUCCESS) {
+        ret = PSA_PK_TO_MBEDTLS_ERR(status);
+        goto exit;
+    }
+
+    key_type = psa_get_key_type(&key_attr);
+    if (public_only) {
+        key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(key_type);
+    }
+    key_bits = psa_get_key_bits(&key_attr);
+    alg_type = psa_get_key_algorithm(&key_attr);
+
+#if defined(MBEDTLS_RSA_C)
+    if ((key_type == PSA_KEY_TYPE_RSA_KEY_PAIR) ||
+        (key_type == PSA_KEY_TYPE_RSA_PUBLIC_KEY)) {
+
+        ret = mbedtls_pk_setup(pk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA));
+        if (ret != 0) {
+            goto exit;
+        }
+
+        if (key_type == PSA_KEY_TYPE_RSA_KEY_PAIR) {
+            ret = mbedtls_rsa_parse_key(mbedtls_pk_rsa(*pk), exp_key, exp_key_len);
+        } else {
+            ret = mbedtls_rsa_parse_pubkey(mbedtls_pk_rsa(*pk), exp_key, exp_key_len);
+        }
+        if (ret != 0) {
+            goto exit;
+        }
+
+        mbedtls_md_type_t md_type = MBEDTLS_MD_NONE;
+        if (PSA_ALG_GET_HASH(alg_type) != PSA_ALG_ANY_HASH) {
+            md_type = mbedtls_md_type_from_psa_alg(alg_type);
+        }
+
+        if (PSA_ALG_IS_RSA_OAEP(alg_type) || PSA_ALG_IS_RSA_PSS(alg_type)) {
+            ret = mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pk), MBEDTLS_RSA_PKCS_V21, md_type);
+        } else if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg_type) ||
+                   alg_type == PSA_ALG_RSA_PKCS1V15_CRYPT) {
+            ret = mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pk), MBEDTLS_RSA_PKCS_V15, md_type);
+        }
+        if (ret != 0) {
+            goto exit;
+        }
+    } else
+#endif /* MBEDTLS_RSA_C */
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
+    if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(key_type) ||
+        PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(key_type)) {
+        mbedtls_ecp_group_id grp_id;
+
+        ret = mbedtls_pk_setup(pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
+        if (ret != 0) {
+            goto exit;
+        }
+
+        grp_id = mbedtls_ecc_group_from_psa(PSA_KEY_TYPE_ECC_GET_FAMILY(key_type), key_bits);
+        ret = mbedtls_pk_ecc_set_group(pk, grp_id);
+        if (ret != 0) {
+            goto exit;
+        }
+
+        if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(key_type)) {
+            ret = mbedtls_pk_ecc_set_key(pk, exp_key, exp_key_len);
+            if (ret != 0) {
+                goto exit;
+            }
+            ret = mbedtls_pk_ecc_set_pubkey_from_prv(pk, exp_key, exp_key_len,
+                                                     mbedtls_psa_get_random,
+                                                     MBEDTLS_PSA_RANDOM_STATE);
+        } else {
+            ret = mbedtls_pk_ecc_set_pubkey(pk, exp_key, exp_key_len);
+        }
+        if (ret != 0) {
+            goto exit;
+        }
+    } else
+#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
+    {
+        return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+    }
+
+exit:
+    psa_reset_key_attributes(&key_attr);
+    mbedtls_platform_zeroize(exp_key, sizeof(exp_key));
+
+    return ret;
+}
+
+int mbedtls_pk_copy_from_psa(mbedtls_svc_key_id_t key_id,
+                             mbedtls_pk_context *pk)
+{
+    return copy_from_psa(key_id, pk, 0);
+}
+
+int mbedtls_pk_copy_public_from_psa(mbedtls_svc_key_id_t key_id,
+                                    mbedtls_pk_context *pk)
+{
+    return copy_from_psa(key_id, pk, 1);
+}
+#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */
 
 /*
  * Helper for mbedtls_pk_sign and mbedtls_pk_verify
@@ -1187,7 +1322,10 @@
 
     if (mbedtls_pk_get_type(ctx) == MBEDTLS_PK_OPAQUE) {
         psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
-        psa_algorithm_t psa_alg, psa_enrollment_alg, sign_alg;
+        psa_algorithm_t psa_alg, sign_alg;
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+        psa_algorithm_t psa_enrollment_alg;
+#endif /* MBEDTLS_PSA_CRYPTO_C */
         psa_status_t status;
 
         status = psa_get_key_attributes(ctx->priv_id, &key_attr);
@@ -1195,16 +1333,22 @@
             return PSA_PK_RSA_TO_MBEDTLS_ERR(status);
         }
         psa_alg = psa_get_key_algorithm(&key_attr);
+#if defined(MBEDTLS_PSA_CRYPTO_C)
         psa_enrollment_alg = psa_get_key_enrollment_algorithm(&key_attr);
+#endif /* MBEDTLS_PSA_CRYPTO_C */
         psa_reset_key_attributes(&key_attr);
 
         /* Since we're PK type is MBEDTLS_PK_RSASSA_PSS at least one between
          * alg and enrollment alg should be of type RSA_PSS. */
         if (PSA_ALG_IS_RSA_PSS(psa_alg)) {
             sign_alg = psa_alg;
-        } else if (PSA_ALG_IS_RSA_PSS(psa_enrollment_alg)) {
+        }
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+        else if (PSA_ALG_IS_RSA_PSS(psa_enrollment_alg)) {
             sign_alg = psa_enrollment_alg;
-        } else {
+        }
+#endif /* MBEDTLS_PSA_CRYPTO_C */
+        else {
             /* The opaque key has no RSA PSS algorithm associated. */
             return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
         }
@@ -1378,136 +1522,4 @@
     return ctx->pk_info->type;
 }
 
-#if defined(MBEDTLS_PSA_CRYPTO_C)
-static int copy_from_psa(mbedtls_svc_key_id_t key_id,
-                         mbedtls_pk_context *pk,
-                         int public_only)
-{
-    psa_status_t status;
-    psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
-    psa_key_type_t key_type;
-    psa_algorithm_t alg_type;
-    size_t key_bits;
-    /* Use a buffer size large enough to contain either a key pair or public key. */
-    unsigned char exp_key[PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE];
-    size_t exp_key_len;
-    int ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA;
-
-    if (pk == NULL) {
-        return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
-    }
-
-    status = psa_get_key_attributes(key_id, &key_attr);
-    if (status != PSA_SUCCESS) {
-        return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
-    }
-
-    if (public_only) {
-        status = psa_export_public_key(key_id, exp_key, sizeof(exp_key), &exp_key_len);
-    } else {
-        status = psa_export_key(key_id, exp_key, sizeof(exp_key), &exp_key_len);
-    }
-    if (status != PSA_SUCCESS) {
-        ret = PSA_PK_TO_MBEDTLS_ERR(status);
-        goto exit;
-    }
-
-    key_type = psa_get_key_type(&key_attr);
-    if (public_only) {
-        key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(key_type);
-    }
-    key_bits = psa_get_key_bits(&key_attr);
-    alg_type = psa_get_key_algorithm(&key_attr);
-
-#if defined(MBEDTLS_RSA_C)
-    if ((key_type == PSA_KEY_TYPE_RSA_KEY_PAIR) ||
-        (key_type == PSA_KEY_TYPE_RSA_PUBLIC_KEY)) {
-
-        ret = mbedtls_pk_setup(pk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA));
-        if (ret != 0) {
-            goto exit;
-        }
-
-        if (key_type == PSA_KEY_TYPE_RSA_KEY_PAIR) {
-            ret = mbedtls_rsa_parse_key(mbedtls_pk_rsa(*pk), exp_key, exp_key_len);
-        } else {
-            ret = mbedtls_rsa_parse_pubkey(mbedtls_pk_rsa(*pk), exp_key, exp_key_len);
-        }
-        if (ret != 0) {
-            goto exit;
-        }
-
-        mbedtls_md_type_t md_type = MBEDTLS_MD_NONE;
-        if (PSA_ALG_GET_HASH(alg_type) != PSA_ALG_ANY_HASH) {
-            md_type = mbedtls_md_type_from_psa_alg(alg_type);
-        }
-
-        if (PSA_ALG_IS_RSA_OAEP(alg_type) || PSA_ALG_IS_RSA_PSS(alg_type)) {
-            ret = mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pk), MBEDTLS_RSA_PKCS_V21, md_type);
-        } else if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg_type) ||
-                   alg_type == PSA_ALG_RSA_PKCS1V15_CRYPT) {
-            ret = mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pk), MBEDTLS_RSA_PKCS_V15, md_type);
-        }
-        if (ret != 0) {
-            goto exit;
-        }
-    } else
-#endif /* MBEDTLS_RSA_C */
-#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
-    if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(key_type) ||
-        PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(key_type)) {
-        mbedtls_ecp_group_id grp_id;
-
-        ret = mbedtls_pk_setup(pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
-        if (ret != 0) {
-            goto exit;
-        }
-
-        grp_id = mbedtls_ecc_group_from_psa(PSA_KEY_TYPE_ECC_GET_FAMILY(key_type), key_bits);
-        ret = mbedtls_pk_ecc_set_group(pk, grp_id);
-        if (ret != 0) {
-            goto exit;
-        }
-
-        if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(key_type)) {
-            ret = mbedtls_pk_ecc_set_key(pk, exp_key, exp_key_len);
-            if (ret != 0) {
-                goto exit;
-            }
-            ret = mbedtls_pk_ecc_set_pubkey_from_prv(pk, exp_key, exp_key_len,
-                                                     mbedtls_psa_get_random,
-                                                     MBEDTLS_PSA_RANDOM_STATE);
-        } else {
-            ret = mbedtls_pk_ecc_set_pubkey(pk, exp_key, exp_key_len);
-        }
-        if (ret != 0) {
-            goto exit;
-        }
-    } else
-#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
-    {
-        return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
-    }
-
-exit:
-    psa_reset_key_attributes(&key_attr);
-    mbedtls_platform_zeroize(exp_key, sizeof(exp_key));
-
-    return ret;
-}
-
-
-int mbedtls_pk_copy_from_psa(mbedtls_svc_key_id_t key_id,
-                             mbedtls_pk_context *pk)
-{
-    return copy_from_psa(key_id, pk, 0);
-}
-
-int mbedtls_pk_copy_public_from_psa(mbedtls_svc_key_id_t key_id,
-                                    mbedtls_pk_context *pk)
-{
-    return copy_from_psa(key_id, pk, 1);
-}
-#endif /* MBEDTLS_PSA_CRYPTO_C */
-
 #endif /* MBEDTLS_PK_C */
diff --git a/library/ssl_client.c b/library/ssl_client.c
index 8892acf..345e608 100644
--- a/library/ssl_client.c
+++ b/library/ssl_client.c
@@ -792,10 +792,15 @@
         (ssl->handshake->cookie == NULL))
 #endif
     {
-        ret = ssl_generate_random(ssl);
-        if (ret != 0) {
-            MBEDTLS_SSL_DEBUG_RET(1, "Random bytes generation failed", ret);
-            return ret;
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+        if (!ssl->handshake->hello_retry_request_flag)
+#endif
+        {
+            ret = ssl_generate_random(ssl);
+            if (ret != 0) {
+                MBEDTLS_SSL_DEBUG_RET(1, "Random bytes generation failed", ret);
+                return ret;
+            }
         }
     }
 
diff --git a/library/ssl_ticket.c b/library/ssl_ticket.c
index 5da3887..6a31b0b 100644
--- a/library/ssl_ticket.c
+++ b/library/ssl_ticket.c
@@ -504,7 +504,7 @@
 #if defined(MBEDTLS_HAVE_TIME)
     mbedtls_ms_time_t ticket_creation_time, ticket_age;
     mbedtls_ms_time_t ticket_lifetime =
-        (mbedtls_ms_time_t) ctx->ticket_lifetime * 1000;
+        (mbedtls_ms_time_t) key->lifetime * 1000;
 
     ret = mbedtls_ssl_session_get_ticket_creation_time(session,
                                                        &ticket_creation_time);
diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c
index bda77e4..7fcc394 100644
--- a/library/ssl_tls13_client.c
+++ b/library/ssl_tls13_client.c
@@ -2917,12 +2917,17 @@
         return ret;
     }
 
-    /* session has been updated, allow export */
-    session->exported = 0;
-
     return 0;
 }
 
+/* Non negative return values for ssl_tls13_postprocess_new_session_ticket().
+ * - POSTPROCESS_NEW_SESSION_TICKET_SIGNAL, all good, we have to signal the
+ *   application that a valid ticket has been received.
+ * - POSTPROCESS_NEW_SESSION_TICKET_DISCARD, no fatal error, we keep the
+ *   connection alive but we do not signal the ticket to the application.
+ */
+#define POSTPROCESS_NEW_SESSION_TICKET_SIGNAL 0
+#define POSTPROCESS_NEW_SESSION_TICKET_DISCARD 1
 MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_tls13_postprocess_new_session_ticket(mbedtls_ssl_context *ssl,
                                                     unsigned char *ticket_nonce,
@@ -2934,6 +2939,10 @@
     psa_algorithm_t psa_hash_alg;
     int hash_length;
 
+    if (session->ticket_lifetime == 0) {
+        return POSTPROCESS_NEW_SESSION_TICKET_DISCARD;
+    }
+
 #if defined(MBEDTLS_HAVE_TIME)
     /* Store ticket creation time */
     session->ticket_reception_time = mbedtls_ms_time();
@@ -2990,7 +2999,7 @@
         session, ssl->conf->tls13_kex_modes);
     MBEDTLS_SSL_PRINT_TICKET_FLAGS(4, session->ticket_flags);
 
-    return 0;
+    return POSTPROCESS_NEW_SESSION_TICKET_SIGNAL;
 }
 
 /*
@@ -3011,12 +3020,37 @@
                              ssl, MBEDTLS_SSL_HS_NEW_SESSION_TICKET,
                              &buf, &buf_len));
 
+    /*
+     * We are about to update (maybe only partially) ticket data thus block
+     * any session export for the time being.
+     */
+    ssl->session->exported = 1;
+
     MBEDTLS_SSL_PROC_CHK(ssl_tls13_parse_new_session_ticket(
                              ssl, buf, buf + buf_len,
                              &ticket_nonce, &ticket_nonce_len));
 
-    MBEDTLS_SSL_PROC_CHK(ssl_tls13_postprocess_new_session_ticket(
-                             ssl, ticket_nonce, ticket_nonce_len));
+    MBEDTLS_SSL_PROC_CHK_NEG(ssl_tls13_postprocess_new_session_ticket(
+                                 ssl, ticket_nonce, ticket_nonce_len));
+
+    switch (ret) {
+        case POSTPROCESS_NEW_SESSION_TICKET_SIGNAL:
+            /*
+             * All good, we have received a new valid ticket, session data can
+             * be exported now and we signal the ticket to the application.
+             */
+            ssl->session->exported = 0;
+            ret = MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET;
+            break;
+
+        case POSTPROCESS_NEW_SESSION_TICKET_DISCARD:
+            ret = 0;
+            MBEDTLS_SSL_DEBUG_MSG(2, ("Discard new session ticket"));
+            break;
+
+        default:
+            ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
+    }
 
     mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_HANDSHAKE_OVER);
 
@@ -3133,10 +3167,6 @@
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
         case MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET:
             ret = ssl_tls13_process_new_session_ticket(ssl);
-            if (ret != 0) {
-                break;
-            }
-            ret = MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET;
             break;
 #endif /* MBEDTLS_SSL_SESSION_TICKETS */
 
diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c
index 9453c69..2c30da8 100644
--- a/library/ssl_tls13_server.c
+++ b/library/ssl_tls13_server.c
@@ -3282,20 +3282,21 @@
         MBEDTLS_SSL_DEBUG_RET(1, "write_ticket", ret);
         return ret;
     }
-    /* RFC 8446 4.6.1
+
+    /* RFC 8446 section 4.6.1
+     *
      *  ticket_lifetime:  Indicates the lifetime in seconds as a 32-bit
-     *      unsigned integer in network byte order from the time of ticket
-     *      issuance.  Servers MUST NOT use any value greater than
-     *      604800 seconds (7 days).  The value of zero indicates that the
-     *      ticket should be discarded immediately.  Clients MUST NOT cache
-     *      tickets for longer than 7 days, regardless of the ticket_lifetime,
-     *      and MAY delete tickets earlier based on local policy.  A server
-     *      MAY treat a ticket as valid for a shorter period of time than what
-     *      is stated in the ticket_lifetime.
+     *     unsigned integer in network byte order from the time of ticket
+     *     issuance.  Servers MUST NOT use any value greater than
+     *     604800 seconds (7 days) ...
      */
     if (ticket_lifetime > MBEDTLS_SSL_TLS1_3_MAX_ALLOWED_TICKET_LIFETIME) {
-        ticket_lifetime = MBEDTLS_SSL_TLS1_3_MAX_ALLOWED_TICKET_LIFETIME;
+        MBEDTLS_SSL_DEBUG_MSG(
+            1, ("Ticket lifetime (%u) is greater than 7 days.",
+                (unsigned int) ticket_lifetime));
+        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
     }
+
     MBEDTLS_PUT_UINT32_BE(ticket_lifetime, p, 0);
     MBEDTLS_SSL_DEBUG_MSG(3, ("ticket_lifetime: %u",
                               (unsigned int) ticket_lifetime));
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 332befd..43133d9 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -3072,16 +3072,16 @@
                 frags++;
                 written += ret;
             } while (written < len);
-        }
 
 end_of_early_data:
 
-        buf[written] = '\0';
-        mbedtls_printf(
-            " %" MBEDTLS_PRINTF_SIZET " bytes of early data written in %" MBEDTLS_PRINTF_SIZET " fragments\n\n%s\n",
-            written,
-            frags,
-            (char *) buf);
+            buf[written] = '\0';
+            mbedtls_printf(
+                " %" MBEDTLS_PRINTF_SIZET " bytes of early data written in %" MBEDTLS_PRINTF_SIZET " fragments\n\n%s\n",
+                written,
+                frags,
+                (char *) buf);
+        }
 #endif /* MBEDTLS_SSL_EARLY_DATA */
 
         while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
diff --git a/programs/test/metatest.c b/programs/test/metatest.c
index 5a45f71..5cd09bf 100644
--- a/programs/test/metatest.c
+++ b/programs/test/metatest.c
@@ -70,6 +70,41 @@
     mbedtls_test_fail("Forced test failure", __LINE__, __FILE__);
 }
 
+void meta_test_not_equal(const char *name)
+{
+    int left = 20;
+    int right = 10;
+
+    (void) name;
+
+    TEST_EQUAL(left, right);
+exit:
+    ;
+}
+
+void meta_test_not_le_s(const char *name)
+{
+    int left = 20;
+    int right = 10;
+
+    (void) name;
+
+    TEST_LE_S(left, right);
+exit:
+    ;
+}
+
+void meta_test_not_le_u(const char *name)
+{
+    size_t left = 20;
+    size_t right = 10;
+
+    (void) name;
+
+    TEST_LE_U(left, right);
+exit:
+    ;
+}
 
 /****************************************************************/
 /* Platform features */
@@ -285,6 +320,9 @@
  */
 metatest_t metatests[] = {
     { "test_fail", "any", meta_test_fail },
+    { "test_not_equal", "any", meta_test_not_equal },
+    { "test_not_le_s", "any", meta_test_not_le_s },
+    { "test_not_le_u", "any", meta_test_not_le_u },
     { "null_dereference", "any", null_pointer_dereference },
     { "null_call", "any", null_pointer_call },
     { "read_after_free", "asan", read_after_free },
diff --git a/scripts/lcov.sh b/scripts/lcov.sh
index 0584a0a..9a0c582 100755
--- a/scripts/lcov.sh
+++ b/scripts/lcov.sh
@@ -39,13 +39,19 @@
 lcov_library_report () {
     rm -rf Coverage
     mkdir Coverage Coverage/tmp
-    lcov --capture --initial --directory $library_dir -o Coverage/tmp/files.info
-    lcov --rc lcov_branch_coverage=1 --capture --directory $library_dir -o Coverage/tmp/tests.info
-    lcov --rc lcov_branch_coverage=1 --add-tracefile Coverage/tmp/files.info --add-tracefile Coverage/tmp/tests.info -o Coverage/tmp/all.info
-    lcov --rc lcov_branch_coverage=1 --remove Coverage/tmp/all.info -o Coverage/tmp/final.info '*.h'
-    gendesc tests/Descriptions.txt -o Coverage/tmp/descriptions
-    genhtml --title "$title" --description-file Coverage/tmp/descriptions --keep-descriptions --legend --branch-coverage -o Coverage Coverage/tmp/final.info
-    rm -f Coverage/tmp/*.info Coverage/tmp/descriptions
+    # Pass absolute paths as lcov output files. This works around a bug
+    # whereby lcov tries to create the output file in the root directory
+    # if it has emitted a warning. A fix was released in lcov 1.13 in 2016.
+    # Ubuntu 16.04 is affected, 18.04 and above are not.
+    # https://github.com/linux-test-project/lcov/commit/632c25a0d1f5e4d2f4fd5b28ce7c8b86d388c91f
+    COVTMP=$PWD/Coverage/tmp
+    lcov --capture --initial --directory $library_dir -o "$COVTMP/files.info"
+    lcov --rc lcov_branch_coverage=1 --capture --directory $library_dir -o "$COVTMP/tests.info"
+    lcov --rc lcov_branch_coverage=1 --add-tracefile "$COVTMP/files.info" --add-tracefile "$COVTMP/tests.info" -o "$COVTMP/all.info"
+    lcov --rc lcov_branch_coverage=1 --remove "$COVTMP/all.info" -o "$COVTMP/final.info" '*.h'
+    gendesc tests/Descriptions.txt -o "$COVTMP/descriptions"
+    genhtml --title "$title" --description-file "$COVTMP/descriptions" --keep-descriptions --legend --branch-coverage -o Coverage "$COVTMP/final.info"
+    rm -f "$COVTMP/"*.info "$COVTMP/descriptions"
     echo "Coverage report in: Coverage/index.html"
 }
 
diff --git a/tests/compat.sh b/tests/compat.sh
index ac29e50..a101ffd 100755
--- a/tests/compat.sh
+++ b/tests/compat.sh
@@ -125,7 +125,7 @@
 print_test_case() {
     for i in $3; do
         uniform_title $1 $2 $i
-        echo $TITLE
+        echo "compat;$TITLE"
     done
 }
 
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 2f18858..acfcf5c 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -1285,19 +1285,67 @@
     check_renamed_symbols tests/include/spe/crypto_spe.h library/libmbedcrypto.a
 }
 
-component_test_psa_crypto_client () {
-    msg "build: default config - PSA_CRYPTO_C + PSA_CRYPTO_CLIENT, make"
+# Get a list of library-wise undefined symbols and ensure that they only
+# belong to psa_xxx() functions and not to mbedtls_yyy() ones.
+# This function is a common helper used by both:
+# - component_test_default_psa_crypto_client_without_crypto_provider
+# - component_build_full_psa_crypto_client_without_crypto_provider.
+common_check_mbedtls_missing_symbols() {
+    nm library/libmbedcrypto.a | grep ' [TRrDC] ' | grep -Eo '(mbedtls_|psa_).*' | sort -u > sym_def.txt
+    nm library/libmbedcrypto.a | grep ' U ' | grep -Eo '(mbedtls_|psa_).*' | sort -u > sym_undef.txt
+    comm sym_def.txt sym_undef.txt -13 > linking_errors.txt
+    not grep mbedtls_ linking_errors.txt
+
+    rm sym_def.txt sym_undef.txt linking_errors.txt
+}
+
+component_test_default_psa_crypto_client_without_crypto_provider () {
+    msg "build: default config - PSA_CRYPTO_C + PSA_CRYPTO_CLIENT"
+
     scripts/config.py unset MBEDTLS_PSA_CRYPTO_C
     scripts/config.py unset MBEDTLS_PSA_CRYPTO_STORAGE_C
+    scripts/config.py unset MBEDTLS_PSA_ITS_FILE_C
     scripts/config.py set MBEDTLS_PSA_CRYPTO_CLIENT
     scripts/config.py unset MBEDTLS_LMS_C
-    scripts/config.py unset MBEDTLS_LMS_PRIVATE
+
     make
 
-    msg "test: default config - PSA_CRYPTO_C + PSA_CRYPTO_CLIENT, make"
+    msg "check missing symbols: default config - PSA_CRYPTO_C + PSA_CRYPTO_CLIENT"
+    common_check_mbedtls_missing_symbols
+
+    msg "test: default config - PSA_CRYPTO_C + PSA_CRYPTO_CLIENT"
     make test
 }
 
+component_build_full_psa_crypto_client_without_crypto_provider () {
+    msg "build: full config - PSA_CRYPTO_C"
+
+    # Use full config which includes USE_PSA and CRYPTO_CLIENT.
+    scripts/config.py full
+
+    scripts/config.py unset MBEDTLS_PSA_CRYPTO_C
+    scripts/config.py unset MBEDTLS_PSA_CRYPTO_STORAGE_C
+    # Dynamic secure element support is a deprecated feature and it is not
+    # available when CRYPTO_C and PSA_CRYPTO_STORAGE_C are disabled.
+    scripts/config.py unset MBEDTLS_PSA_CRYPTO_SE_C
+
+    # Since there is no crypto provider in this build it is not possible to
+    # build all the test executables and progrems due to missing PSA functions
+    # at link time. Therefore we will just build libraries and we'll check
+    # that symbols of interest are there.
+    make lib
+
+    msg "check missing symbols: full config - PSA_CRYPTO_C"
+
+    common_check_mbedtls_missing_symbols
+
+    # Ensure that desired functions are included into the build (extend the
+    # following list as required).
+    grep mbedtls_pk_get_psa_attributes library/libmbedcrypto.a
+    grep mbedtls_pk_import_into_psa library/libmbedcrypto.a
+    grep mbedtls_pk_copy_from_psa library/libmbedcrypto.a
+}
+
 component_test_psa_crypto_rsa_no_genprime() {
     msg "build: default config minus MBEDTLS_GENPRIME"
     scripts/config.py unset MBEDTLS_GENPRIME
diff --git a/tests/scripts/check_test_cases.py b/tests/scripts/check_test_cases.py
index 68e7e69..d67e678 100755
--- a/tests/scripts/check_test_cases.py
+++ b/tests/scripts/check_test_cases.py
@@ -16,6 +16,23 @@
 import subprocess
 import sys
 
+class ScriptOutputError(ValueError):
+    """A kind of ValueError that indicates we found
+    the script doesn't list test cases in an expected
+    pattern.
+    """
+
+    @property
+    def script_name(self):
+        return super().args[0]
+
+    @property
+    def idx(self):
+        return super().args[1]
+
+    @property
+    def line(self):
+        return super().args[2]
 
 class Results:
     """Store file and line information about errors or warnings in test suites."""
@@ -86,19 +103,27 @@
                                            data_file_name, line_number, line)
                 in_paragraph = True
 
-    def collect_from_script(self, file_name):
+    def collect_from_script(self, script_name):
         """Collect the test cases in a script by calling its listing test cases
 option"""
         descriptions = self.new_per_file_state() # pylint: disable=assignment-from-none
-        listed = subprocess.check_output(['sh', file_name, '--list-test-cases'])
+        listed = subprocess.check_output(['sh', script_name, '--list-test-cases'])
         # Assume test file is responsible for printing identical format of
         # test case description between --list-test-cases and its OUTCOME.CSV
         #
         # idx indicates the number of test case since there is no line number
         # in the script for each test case.
-        for idx, description in enumerate(listed.splitlines()):
+        for idx, line in enumerate(listed.splitlines()):
+            # We are expecting the script to list the test cases in
+            # `<suite_name>;<description>` pattern.
+            script_outputs = line.split(b';', 1)
+            if len(script_outputs) == 2:
+                suite_name, description = script_outputs
+            else:
+                raise ScriptOutputError(script_name, idx, line.decode("utf-8"))
+
             self.process_test_case(descriptions,
-                                   file_name,
+                                   suite_name.decode('utf-8'),
                                    idx,
                                    description.rstrip())
 
@@ -124,8 +149,7 @@
 
             for sh_file in ['ssl-opt.sh', 'compat.sh']:
                 sh_file = os.path.join(directory, sh_file)
-                if os.path.exists(sh_file):
-                    self.collect_from_script(sh_file)
+                self.collect_from_script(sh_file)
 
 class TestDescriptions(TestDescriptionExplorer):
     """Collect the available test cases."""
@@ -202,7 +226,12 @@
         return
     results = Results(options)
     checker = DescriptionChecker(results)
-    checker.walk_all()
+    try:
+        checker.walk_all()
+    except ScriptOutputError as e:
+        results.error(e.script_name, e.idx,
+                      '"{}" should be listed as "<suite_name>;<description>"',
+                      e.line)
     if (results.warnings or results.errors) and not options.quiet:
         sys.stderr.write('{}: {} errors, {} warnings\n'
                          .format(sys.argv[0], results.errors, results.warnings))
diff --git a/tests/src/psa_crypto_stubs.c b/tests/src/psa_crypto_stubs.c
index f3ca850..81d7f4b 100644
--- a/tests/src/psa_crypto_stubs.c
+++ b/tests/src/psa_crypto_stubs.c
@@ -22,4 +22,54 @@
     return PSA_ERROR_COMMUNICATION_FAILURE;
 }
 
+psa_status_t psa_export_key(mbedtls_svc_key_id_t key,
+                            uint8_t *data,
+                            size_t data_size,
+                            size_t *data_length)
+{
+    (void) key;
+    (void) data;
+    (void) data_size;
+    (void) data_length;
+    return PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
+psa_status_t psa_export_public_key(mbedtls_svc_key_id_t key,
+                                   uint8_t *data,
+                                   size_t data_size,
+                                   size_t *data_length)
+{
+    (void) key;
+    (void) data;
+    (void) data_size;
+    (void) data_length;
+    return PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
+psa_status_t psa_get_key_attributes(mbedtls_svc_key_id_t key,
+                                    psa_key_attributes_t *attributes)
+{
+    (void) key;
+    (void) attributes;
+    return PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
+psa_status_t psa_hash_abort(psa_hash_operation_t *operation)
+{
+    (void) operation;
+    return PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
+psa_status_t psa_import_key(const psa_key_attributes_t *attributes,
+                            const uint8_t *data,
+                            size_t data_length,
+                            mbedtls_svc_key_id_t *key)
+{
+    (void) attributes;
+    (void) data;
+    (void) data_length;
+    (void) key;
+    return PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
 #endif /* MBEDTLS_PSA_CRYPTO_CLIENT && !MBEDTLS_PSA_CRYPTO_C */
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index fd2fc0a..0e86368 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -1629,7 +1629,7 @@
     fi
 
     if [ "$LIST_TESTS" -gt 0 ]; then
-        printf "%s\n" "$NAME"
+        printf "%s\n" "${TEST_SUITE_NAME:-ssl-opt};$NAME"
         return
     fi
 
@@ -13532,6 +13532,61 @@
             -s "key exchange mode: psk_ephemeral" \
             -s "found pre_shared_key extension"
 
+requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 \
+                             MBEDTLS_SSL_CLI_C MBEDTLS_SSL_SRV_C \
+                             MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_HAVE_TIME \
+                             MBEDTLS_DEBUG_C \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED
+requires_any_configs_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
+run_test    "TLS 1.3 m->m: NewSessionTicket: Ticket lifetime max value (7d)" \
+            "$P_SRV debug_level=1 crt_file=data_files/server5.crt key_file=data_files/server5.key ticket_timeout=604800 tickets=1" \
+            "$P_CLI reco_mode=1 reconnect=1" \
+            0 \
+            -c "Protocol is TLSv1.3" \
+            -c "HTTP/1.0 200 OK" \
+            -c "got new session ticket" \
+            -c "Reconnecting with saved session... ok" \
+            -s "Protocol is TLSv1.3" \
+            -S "Ticket lifetime (604800) is greater than 7 days."
+
+requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 \
+                             MBEDTLS_SSL_CLI_C MBEDTLS_SSL_SRV_C \
+                             MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_HAVE_TIME \
+                             MBEDTLS_DEBUG_C \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED
+requires_any_configs_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
+run_test    "TLS 1.3 m->m: NewSessionTicket: Ticket lifetime too long (7d + 1s)" \
+            "$P_SRV debug_level=1 crt_file=data_files/server5.crt key_file=data_files/server5.key ticket_timeout=604801 tickets=1" \
+            "$P_CLI reco_mode=1 reconnect=1" \
+            1 \
+            -c "Protocol is TLSv1.3" \
+            -C "HTTP/1.0 200 OK" \
+            -C "got new session ticket" \
+            -C "Reconnecting with saved session... ok" \
+            -S "Protocol is TLSv1.3" \
+            -s "Ticket lifetime (604801) is greater than 7 days."
+
+requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 \
+                             MBEDTLS_SSL_CLI_C MBEDTLS_SSL_SRV_C \
+                             MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_HAVE_TIME \
+                             MBEDTLS_DEBUG_C \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED
+requires_any_configs_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
+run_test    "TLS 1.3 m->m: NewSessionTicket: ticket lifetime=0" \
+            "$P_SRV debug_level=2 crt_file=data_files/server5.crt key_file=data_files/server5.key ticket_timeout=0 tickets=1" \
+            "$P_CLI debug_level=2 reco_mode=1 reconnect=1" \
+            1 \
+            -c "Protocol is TLSv1.3" \
+            -c "HTTP/1.0 200 OK" \
+            -c "Discard new session ticket" \
+            -C "got new session ticket" \
+            -c "Reconnecting with saved session... failed" \
+            -s "Protocol is TLSv1.3" \
+            -s "<= write new session ticket"
+
 requires_openssl_tls1_3_with_compatible_ephemeral
 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 e29667d..2fe4997 100644
--- a/tests/suites/test_suite_ssl.function
+++ b/tests/suites/test_suite_ssl.function
@@ -2404,7 +2404,7 @@
      * corrupt them bit-by-bit. */
     for (cur_byte = 0; cur_byte < sizeof(should_corrupt_byte); cur_byte++) {
         int cur_bit;
-        unsigned char * const byte = &serialized_session[cur_byte];
+        unsigned char *const byte = &serialized_session[cur_byte];
 
         if (should_corrupt_byte[cur_byte] == 0) {
             continue;
@@ -3858,6 +3858,7 @@
         MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1,
         MBEDTLS_SSL_IANA_TLS_GROUP_NONE
     };
+    uint8_t client_random[MBEDTLS_CLIENT_HELLO_RANDOM_LEN];
 
     mbedtls_platform_zeroize(&client_ep, sizeof(client_ep));
     mbedtls_platform_zeroize(&server_ep, sizeof(server_ep));
@@ -3995,9 +3996,16 @@
                         if (!client_ep.ssl.handshake->hello_retry_request_flag) {
                             TEST_EQUAL(client_ep.ssl.early_data_state,
                                        MBEDTLS_SSL_EARLY_DATA_STATE_CAN_WRITE);
+                            memcpy(client_random,
+                                   client_ep.ssl.handshake->randbytes,
+                                   MBEDTLS_CLIENT_HELLO_RANDOM_LEN);
                         } else {
                             TEST_EQUAL(client_ep.ssl.early_data_state,
                                        MBEDTLS_SSL_EARLY_DATA_STATE_REJECTED);
+                            TEST_MEMORY_COMPARE(client_random,
+                                                MBEDTLS_CLIENT_HELLO_RANDOM_LEN,
+                                                client_ep.ssl.handshake->randbytes,
+                                                MBEDTLS_CLIENT_HELLO_RANDOM_LEN);
                         }
                         break;