Merge pull request #8822 from daverodgman/sha3-perf

SHA-3 performance & code size
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 38806d9..179c3f6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -34,9 +34,15 @@
 cmake_policy(SET CMP0012 NEW)
 
 if(TEST_CPP)
-    project("Mbed TLS" LANGUAGES C CXX)
+    project("Mbed TLS"
+        LANGUAGES C CXX
+        VERSION 3.5.2
+    )
 else()
-    project("Mbed TLS" LANGUAGES C)
+    project("Mbed TLS"
+        LANGUAGES C
+        VERSION 3.5.2
+    )
 endif()
 
 include(GNUInstallDirs)
@@ -283,6 +289,8 @@
 
 add_subdirectory(library)
 
+add_subdirectory(pkgconfig)
+
 #
 # The C files in tests/src directory contain test code shared among test suites
 # and programs. This shared test code is compiled and linked to test suites and
diff --git a/ChangeLog.d/8799.txt b/ChangeLog.d/8799.txt
new file mode 100644
index 0000000..50e7c11
--- /dev/null
+++ b/ChangeLog.d/8799.txt
@@ -0,0 +1,3 @@
+Bugfix
+   * mbedtls_pem_read_buffer() now performs a check on the padding data of
+     decrypted keys and it rejects invalid ones.
diff --git a/ChangeLog.d/8824.txt b/ChangeLog.d/8824.txt
new file mode 100644
index 0000000..6d6bcb7
--- /dev/null
+++ b/ChangeLog.d/8824.txt
@@ -0,0 +1,8 @@
+Bugfix
+   * Fix mbedtls_pk_sign(), mbedtls_pk_verify(), mbedtls_pk_decrypt() and
+     mbedtls_pk_encrypt() on non-opaque RSA keys to honor the padding mode in
+     the RSA context. Before, if MBEDTLS_USE_PSA_CRYPTO was enabled and the
+     RSA context was configured for PKCS#1 v2.1 (PSS/OAEP), the sign/verify
+     functions performed a PKCS#1 v1.5 signature instead and the
+     encrypt/decrypt functions returned an error. Fixes #8824.
+
diff --git a/ChangeLog.d/8825.txt b/ChangeLog.d/8825.txt
new file mode 100644
index 0000000..914bd08
--- /dev/null
+++ b/ChangeLog.d/8825.txt
@@ -0,0 +1,6 @@
+Features
+   * mbedtls_psa_get_random() is always available as soon as
+     MBEDTLS_PSA_CRYPTO_CLIENT is enabled at build time and psa_crypto_init() is
+     called at runtime. This together with MBEDTLS_PSA_RANDOM_STATE can be
+     used as random number generator function (f_rng) and context (p_rng) in
+     legacy functions.
diff --git a/ChangeLog.d/8848.txt b/ChangeLog.d/8848.txt
new file mode 100644
index 0000000..71bb7e3
--- /dev/null
+++ b/ChangeLog.d/8848.txt
@@ -0,0 +1,6 @@
+Removals
+   * Temporary function mbedtls_pk_wrap_as_opaque() is removed. To mimic the
+     same behavior mbedtls_pk_get_psa_attributes() and
+     mbedtls_pk_import_into_psa() can be used to import a PK key into PSA,
+     while mbedtls_pk_setup_opaque() can be used to wrap a PSA key into a opaque
+     PK context.
diff --git a/ChangeLog.d/add_get_ecp_group_id.txt b/ChangeLog.d/add_get_ecp_group_id.txt
new file mode 100644
index 0000000..3328062
--- /dev/null
+++ b/ChangeLog.d/add_get_ecp_group_id.txt
@@ -0,0 +1,3 @@
+Features
+   * Add new accessor to expose the private group id member of
+     `mbedtls_ecdh_context` structure.
diff --git a/ChangeLog.d/benchmark-ecdh.txt b/ChangeLog.d/benchmark-ecdh.txt
new file mode 100644
index 0000000..ef243b8
--- /dev/null
+++ b/ChangeLog.d/benchmark-ecdh.txt
@@ -0,0 +1,3 @@
+Features
+   * The benchmark program now reports times for both ephemeral and static
+     ECDH in all ECDH configurations.
diff --git a/ChangeLog.d/domain_parameters.txt b/ChangeLog.d/domain_parameters.txt
new file mode 100644
index 0000000..d860cc4
--- /dev/null
+++ b/ChangeLog.d/domain_parameters.txt
@@ -0,0 +1,9 @@
+New deprecations
+   * In the PSA API, domain parameters are no longer used for anything.
+     They are deprecated and will be removed in a future version of the
+     library.
+
+Removals
+   * In the PSA API, the experimental way to encode the public exponent of
+     an RSA key as a domain parameter is no longer supported. Use
+     psa_generate_key_ext() instead.
diff --git a/ChangeLog.d/ecp_write_key.txt b/ChangeLog.d/ecp_write_key.txt
new file mode 100644
index 0000000..73354c8
--- /dev/null
+++ b/ChangeLog.d/ecp_write_key.txt
@@ -0,0 +1,8 @@
+Features
+   * The new function mbedtls_ecp_write_key_ext() is similar to
+     mbedtls_ecp_write_key(), but can be used without separately calculating
+     the output length.
+
+New deprecations
+   * mbedtls_ecp_write_key() is deprecated in favor of
+     mbedtls_ecp_write_key_ext().
diff --git a/ChangeLog.d/fix-ssl-session-serialization-config.txt b/ChangeLog.d/fix-ssl-session-serialization-config.txt
new file mode 100644
index 0000000..ca1cc81
--- /dev/null
+++ b/ChangeLog.d/fix-ssl-session-serialization-config.txt
@@ -0,0 +1,4 @@
+Bugfix
+   * Fix missing bitflags in SSL session serialization headers. Their absence
+     allowed SSL sessions saved in one configuration to be loaded in a
+     different, incompatible configuration.
diff --git a/ChangeLog.d/gcm-large-tables.txt b/ChangeLog.d/gcm-large-tables.txt
new file mode 100644
index 0000000..f9bba5b
--- /dev/null
+++ b/ChangeLog.d/gcm-large-tables.txt
@@ -0,0 +1,4 @@
+Features
+    * Add support for 8-bit GCM tables for Shoup's algorithm to speedup GCM
+      operations when hardware accelerated AES is not present. Improves
+      performance by around 30% on 64-bit Intel; 125% on Armv7-M.
diff --git a/ChangeLog.d/gen-key-segfault.txt b/ChangeLog.d/gen-key-segfault.txt
new file mode 100644
index 0000000..fefc702
--- /dev/null
+++ b/ChangeLog.d/gen-key-segfault.txt
@@ -0,0 +1,3 @@
+Bugfix
+   * Avoid segmentation fault caused by releasing not initialized
+     entropy resource in gen_key example. Fixes #8809.
diff --git a/ChangeLog.d/get_ticket_creation_time.txt b/ChangeLog.d/get_ticket_creation_time.txt
new file mode 100644
index 0000000..7b5166c
--- /dev/null
+++ b/ChangeLog.d/get_ticket_creation_time.txt
@@ -0,0 +1,3 @@
+Features
+   * Add getter (mbedtls_ssl_session_get_ticket_creation_time()) to access
+     `mbedtls_ssl_session.ticket_creation_time`.
diff --git a/ChangeLog.d/mbedtls_pk_import_into_psa.txt b/ChangeLog.d/mbedtls_pk_import_into_psa.txt
new file mode 100644
index 0000000..c294f44
--- /dev/null
+++ b/ChangeLog.d/mbedtls_pk_import_into_psa.txt
@@ -0,0 +1,4 @@
+Features
+   * The new functions mbedtls_pk_get_psa_attributes() and
+     mbedtls_pk_import_into_psa() provide a uniform way to create a PSA
+     key from a PK key.
diff --git a/ChangeLog.d/pkg-config-files-addition.txt b/ChangeLog.d/pkg-config-files-addition.txt
new file mode 100644
index 0000000..e459470
--- /dev/null
+++ b/ChangeLog.d/pkg-config-files-addition.txt
@@ -0,0 +1,4 @@
+Features
+   * Add pc files for pkg-config, e.g.:
+     pkg-config --cflags --libs (mbedtls|mbedcrypto|mbedx509)
+
diff --git a/ChangeLog.d/psa_generate_key_ext.txt b/ChangeLog.d/psa_generate_key_ext.txt
new file mode 100644
index 0000000..8340f01
--- /dev/null
+++ b/ChangeLog.d/psa_generate_key_ext.txt
@@ -0,0 +1,3 @@
+Features
+   * The new function psa_generate_key_ext() allows generating an RSA
+     key pair with a custom public exponent.
diff --git a/ChangeLog.d/rsa-bitlen.txt b/ChangeLog.d/rsa-bitlen.txt
new file mode 100644
index 0000000..bcd185f
--- /dev/null
+++ b/ChangeLog.d/rsa-bitlen.txt
@@ -0,0 +1,7 @@
+Bugfix
+   * Fix mbedtls_pk_get_bitlen() for RSA keys whose size is not a
+     multiple of 8. Fixes #868.
+
+Features
+   * The new function mbedtls_rsa_get_bitlen() returns the length of the modulus
+     in bits, i.e. the key size for an RSA key.
diff --git a/ChangeLog.d/use_exp_mod_core.txt b/ChangeLog.d/use_exp_mod_core.txt
new file mode 100644
index 0000000..8f7193a
--- /dev/null
+++ b/ChangeLog.d/use_exp_mod_core.txt
@@ -0,0 +1,6 @@
+Changes
+   * mbedtls_mpi_exp_mod and code that uses it, notably RSA and DHM operations,
+     have changed their speed/memory compromise as part of a proactive security
+     improvement. The new default value of MBEDTLS_MPI_WINDOW_SIZE roughly
+     preserves the current speed, at the expense of increasing memory
+     consumption.
diff --git a/ChangeLog.d/x509-add-ca_istrue.txt b/ChangeLog.d/x509-add-ca_istrue.txt
new file mode 100644
index 0000000..c950dbc
--- /dev/null
+++ b/ChangeLog.d/x509-add-ca_istrue.txt
@@ -0,0 +1,5 @@
+Features
+   * Add new accessor to expose the `MBEDTLS_PRIVATE(ca_istrue)` member of
+     `mbedtls_x509_crt` structure. This requires setting
+     the MBEDTLS_X509_EXT_BASIC_CONSTRAINTS bit in the certificate's
+     ext_types field.
diff --git a/docs/driver-only-builds.md b/docs/driver-only-builds.md
index f59420e..4095d8e 100644
--- a/docs/driver-only-builds.md
+++ b/docs/driver-only-builds.md
@@ -105,7 +105,28 @@
 - for code that uses only the PSA Crypto API: `PSA_WANT_ALG_xxx` from
   `psa/crypto.h`;
 - for code that uses non-PSA crypto APIs: `MBEDTLS_MD_CAN_xxx` from
-  `mbedtls/md.h`.
+  `mbedtls/config_adjust_legacy_crypto.h`.
+
+### HMAC
+
+In addition to accelerated hash operations, it is also possible to accelerate
+HMAC by enabling and accelerating:
+- HMAC algorithm and key type, i.e. `[PSA_WANT|MBEDTLS_PSA_ACCEL]_ALG_HMAC` and
+  `[PSA_WANT|MBEDTLS_PSA_ACCEL]KEY_TYPE_HMAC`.
+- Required hash algorithm(s) as explained in [Hashes](#hashes) section.
+
+In such a build it is possible to disable legacy HMAC support by disabling
+`MBEDTLS_MD_C` and still getting crypto operations, X.509 and TLS to work as
+usual. Exceptions are:
+- As mentioned in [Hashes](#hashes) direct calls to legacy lo-level hash APIs
+  (`mbedtls_sha256()` etc.) will not be possible for the legacy modules that
+  are disabled.
+- Legacy HMAC support (`mbedtls_md_hmac_xxx()`) won't be possible.
+- `MBEDTLS_PKCS[5|7]_C`, `MBEDTLS_HMAC_DRBG_C` and `MBEDTLS_HKDF_C` since they
+  depend on the legacy implementation of HMAC.
+  - disabling HMAC_DRBG_C cause deterministic ECDSA (i.e.
+  `MBEDTLS_DETERMINISTIC_ECDSA` on the legacy side and 
+  `PSA_WANT_ALG_DETERMINISTIC_ECDSA` on the PSA one) to be not available.
 
 Elliptic-curve cryptography (ECC)
 ---------------------------------
diff --git a/docs/psa-driver-example-and-guide.md b/docs/psa-driver-example-and-guide.md
index d041723..aa825ad 100644
--- a/docs/psa-driver-example-and-guide.md
+++ b/docs/psa-driver-example-and-guide.md
@@ -157,11 +157,11 @@
 
 ```
 #if defined (MBEDTLS_PSA_P256M_DRIVER_ENABLED)
-            if( PSA_KEY_TYPE_IS_ECC( attributes->core.type ) &&
+            if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) &&
                 PSA_ALG_IS_ECDSA(alg) &&
                 !PSA_ALG_ECDSA_IS_DETERMINISTIC( alg ) &&
-                PSA_KEY_TYPE_ECC_GET_FAMILY(attributes->core.type) == PSA_ECC_FAMILY_SECP_R1 &&
-                attributes->core.bits == 256 )
+                PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)) == PSA_ECC_FAMILY_SECP_R1 &&
+                psa_get_key_bits(attributes) == 256 )
             {
                 status = p256_transparent_sign_hash( attributes,
                                                      key_buffer,
diff --git a/docs/psa-transition.md b/docs/psa-transition.md
index e89128c..94b57eb 100644
--- a/docs/psa-transition.md
+++ b/docs/psa-transition.md
@@ -845,7 +845,6 @@
 
 ```
 unsigned char buf[PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS)];
-size_t length = PSA_BITS_TO_BYTES(mbedtls_pk_bitlen(&pk));
 mbedtls_ecp_keypair *ec = mbedtls_pk_ec(&pk);
 psa_ecc_curve_t curve;
 {
@@ -862,7 +861,8 @@
     mbedtls_ecp_point_free(&Q);
     mbedtls_mpi_free(&d);
 }
-mbedtls_ecp_write_key(ec, buf, length);
+size_t length;
+mbedtls_ecp_write_key_ext(ec, &length, buf, sizeof(buf));
 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
 psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(curve));
 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_... | ...);
@@ -900,8 +900,8 @@
 // Omitted: fill ec with key material
 // (the public key will not be used and does not need to be set)
 unsigned char buf[PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS)];
-size_t length = PSA_BITS_TO_BYTES(mbedtls_pk_bitlen(&pk));
-mbedtls_ecp_write_key(&ec, buf, length);
+size_t length;
+mbedtls_ecp_write_key_ext(&ec, &length, buf, sizeof(buf));
 psa_ecc_curve_t curve = ...; // need to determine the curve family manually
 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
 psa_set_key_attributes(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(curve));
@@ -1300,7 +1300,7 @@
 The PSA API is a cryptography API, not an arithmetic API. As a consequence, there is no PSA equivalent for the ECC arithmetic functionality exposed by `ecp.h`:
 
 * Manipulation of point objects and input-output: the type `mbedtls_ecp_point` and functions operating on it (`mbedtls_ecp_point_xxx`, `mbedtls_ecp_copy`, `mbedtls_ecp_{set,is}_zero`, `mbedtls_ecp_tls_{read,write}_point`). Note that the PSA export format for public keys corresponds to the uncompressed point format (`MBEDTLS_ECP_PF_UNCOMPRESSED`), so [`psa_import_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga0336ea76bf30587ab204a8296462327b), [`psa_export_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga668e35be8d2852ad3feeef74ac6f75bf) and [`psa_export_public_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1gaf22ae73312217aaede2ea02cdebb6062) are equivalent to `mbedtls_ecp_point_read_binary` and `mbedtls_ecp_point_write_binary` for uncompressed points. The PSA API does not currently support compressed points, but it is likely that such support will be added in the future.
-* Manipulation of key pairs as such, with a bridge to bignum arithmetic (`mbedtls_ecp_keypair` type, `mbedtls_ecp_export`). However, the PSA export format for ECC private keys used by [`psa_import_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga0336ea76bf30587ab204a8296462327b), [`psa_export_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga668e35be8d2852ad3feeef74ac6f75bf) is the same as the format used by `mbedtls_ecp_read_key` and `mbedtls_ecp_write_key`.
+* Manipulation of key pairs as such, with a bridge to bignum arithmetic (`mbedtls_ecp_keypair` type, `mbedtls_ecp_export`). However, the PSA export format for ECC private keys used by [`psa_import_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga0336ea76bf30587ab204a8296462327b), [`psa_export_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga668e35be8d2852ad3feeef74ac6f75bf) is the same as the format used by `mbedtls_ecp_read_key` and `mbedtls_ecp_write_key_ext`.
 * Elliptic curve arithmetic (`mbedtls_ecp_mul`, `mbedtls_ecp_muladd` and their restartable variants).
 
 ### Additional information about RSA
diff --git a/include/mbedtls/bignum.h b/include/mbedtls/bignum.h
index 931e06d..71d7b97 100644
--- a/include/mbedtls/bignum.h
+++ b/include/mbedtls/bignum.h
@@ -51,15 +51,15 @@
 
 #if !defined(MBEDTLS_MPI_WINDOW_SIZE)
 /*
- * Maximum window size used for modular exponentiation. Default: 2
+ * Maximum window size used for modular exponentiation. Default: 3
  * Minimum value: 1. Maximum value: 6.
  *
  * Result is an array of ( 2 ** MBEDTLS_MPI_WINDOW_SIZE ) MPIs used
- * for the sliding window calculation. (So 64 by default)
+ * for the sliding window calculation. (So 8 by default)
  *
  * Reduction in size, reduces speed.
  */
-#define MBEDTLS_MPI_WINDOW_SIZE                           2        /**< Maximum window size used. */
+#define MBEDTLS_MPI_WINDOW_SIZE                           3        /**< Maximum window size used. */
 #endif /* !MBEDTLS_MPI_WINDOW_SIZE */
 
 #if !defined(MBEDTLS_MPI_MAX_SIZE)
diff --git a/include/mbedtls/build_info.h b/include/mbedtls/build_info.h
index 2f336ba..99a449b 100644
--- a/include/mbedtls/build_info.h
+++ b/include/mbedtls/build_info.h
@@ -158,7 +158,8 @@
  *   (e.g. MBEDTLS_MD_LIGHT)
  */
 #if defined(MBEDTLS_PSA_CRYPTO_CONFIG) /* PSA_WANT_xxx influences MBEDTLS_xxx */ || \
-    defined(MBEDTLS_PSA_CRYPTO_C) /* MBEDTLS_xxx influences PSA_WANT_xxx */
+    defined(MBEDTLS_PSA_CRYPTO_C) /* MBEDTLS_xxx influences PSA_WANT_xxx */ || \
+    defined(MBEDTLS_PSA_CRYPTO_CLIENT) /* The same as the previous, but with separation only */
 #include "mbedtls/config_psa.h"
 #endif
 
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index a7a346f..b3c038d 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -85,7 +85,7 @@
 #endif /* some curve accelerated */
 
 #if defined(MBEDTLS_CTR_DRBG_C) && !(defined(MBEDTLS_AES_C) || \
-    (defined(MBEDTLS_PSA_CRYPTO_C) && defined(PSA_WANT_KEY_TYPE_AES) && \
+    (defined(MBEDTLS_PSA_CRYPTO_CLIENT) && defined(PSA_WANT_KEY_TYPE_AES) && \
     defined(PSA_WANT_ALG_ECB_NO_PADDING)))
 #error "MBEDTLS_CTR_DRBG_C defined, but not all prerequisites"
 #endif
@@ -207,10 +207,6 @@
 #error "MBEDTLS_ECP_C defined (or a subset enabled), but not all prerequisites"
 #endif
 
-#if defined(MBEDTLS_PK_PARSE_C) && !defined(MBEDTLS_ASN1_PARSE_C)
-#error "MBEDTLS_PK_PARSE_C defined, but not all prerequisites"
-#endif
-
 #if defined(MBEDTLS_ENTROPY_C) && \
     !(defined(MBEDTLS_MD_CAN_SHA512) || defined(MBEDTLS_MD_CAN_SHA256))
 #error "MBEDTLS_ENTROPY_C defined, but not all prerequisites"
@@ -401,7 +397,7 @@
 #endif
 
 #if defined(MBEDTLS_LMS_C) &&                                          \
-    ! ( defined(MBEDTLS_PSA_CRYPTO_C) && defined(PSA_WANT_ALG_SHA_256) )
+    ! ( defined(MBEDTLS_PSA_CRYPTO_CLIENT) && defined(PSA_WANT_ALG_SHA_256) )
 #error "MBEDTLS_LMS_C requires MBEDTLS_PSA_CRYPTO_C and PSA_WANT_ALG_SHA_256"
 #endif
 
@@ -436,11 +432,17 @@
 #error "MBEDTLS_PK_C defined, but not all prerequisites"
 #endif
 
-#if defined(MBEDTLS_PK_PARSE_C) && !defined(MBEDTLS_PK_C)
+#if defined(MBEDTLS_PK_PARSE_C) && \
+    (!defined(MBEDTLS_ASN1_PARSE_C) || \
+     !defined(MBEDTLS_OID_C)        || \
+     !defined(MBEDTLS_PK_C))
 #error "MBEDTLS_PK_PARSE_C defined, but not all prerequisites"
 #endif
 
-#if defined(MBEDTLS_PK_WRITE_C) && !defined(MBEDTLS_PK_C)
+#if defined(MBEDTLS_PK_WRITE_C) && \
+    (!defined(MBEDTLS_ASN1_WRITE_C) || \
+     !defined(MBEDTLS_OID_C)        || \
+     !defined(MBEDTLS_PK_C))
 #error "MBEDTLS_PK_WRITE_C defined, but not all prerequisites"
 #endif
 
@@ -789,7 +791,7 @@
  * Note: for dependencies common with TLS 1.2 (running handshake hash),
  * see MBEDTLS_SSL_TLS_C. */
 #if defined(MBEDTLS_SSL_PROTO_TLS1_3) && \
-    !(defined(MBEDTLS_PSA_CRYPTO_C) && \
+    !(defined(MBEDTLS_PSA_CRYPTO_CLIENT) && \
       defined(PSA_WANT_ALG_HKDF_EXTRACT) && \
       defined(PSA_WANT_ALG_HKDF_EXPAND) && \
       (defined(PSA_WANT_ALG_SHA_256) || defined(PSA_WANT_ALG_SHA_384)))
@@ -985,7 +987,7 @@
 #endif
 #undef MBEDTLS_THREADING_IMPL // temporary macro defined above
 
-#if defined(MBEDTLS_USE_PSA_CRYPTO) && !defined(MBEDTLS_PSA_CRYPTO_C)
+#if defined(MBEDTLS_USE_PSA_CRYPTO) && !defined(MBEDTLS_PSA_CRYPTO_CLIENT)
 #error "MBEDTLS_USE_PSA_CRYPTO defined, but not all prerequisites"
 #endif
 
diff --git a/include/mbedtls/config_adjust_ssl.h b/include/mbedtls/config_adjust_ssl.h
index 5dd331c..39c7b3b 100644
--- a/include/mbedtls/config_adjust_ssl.h
+++ b/include/mbedtls/config_adjust_ssl.h
@@ -34,6 +34,10 @@
 #undef MBEDTLS_SSL_PROTO_DTLS
 #endif
 
+#if !(defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_SESSION_TICKETS))
+#undef MBEDTLS_SSL_TICKET_C
+#endif
+
 #if !defined(MBEDTLS_SSL_PROTO_DTLS)
 #undef MBEDTLS_SSL_DTLS_ANTI_REPLAY
 #undef MBEDTLS_SSL_DTLS_CONNECTION_ID
diff --git a/include/mbedtls/ecdh.h b/include/mbedtls/ecdh.h
index 792db79..a0909d6 100644
--- a/include/mbedtls/ecdh.h
+++ b/include/mbedtls/ecdh.h
@@ -142,6 +142,19 @@
 mbedtls_ecdh_context;
 
 /**
+ * \brief          Return the ECP group for provided context.
+ *
+ * \note           To access group specific fields, users should use
+ *                 `mbedtls_ecp_curve_info_from_grp_id` or
+ *                 `mbedtls_ecp_group_load` on the extracted `group_id`.
+ *
+ * \param ctx      The ECDH context to parse. This must not be \c NULL.
+ *
+ * \return         The \c mbedtls_ecp_group_id of the context.
+ */
+mbedtls_ecp_group_id mbedtls_ecdh_get_grp_id(mbedtls_ecdh_context *ctx);
+
+/**
  * \brief          Check whether a given group can be used for ECDH.
  *
  * \param gid      The ECP group ID to check.
diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h
index 76aef32..d8f73ae 100644
--- a/include/mbedtls/ecp.h
+++ b/include/mbedtls/ecp.h
@@ -24,6 +24,7 @@
 #include "mbedtls/private_access.h"
 
 #include "mbedtls/build_info.h"
+#include "mbedtls/platform_util.h"
 
 #include "mbedtls/bignum.h"
 
@@ -1327,28 +1328,84 @@
 int mbedtls_ecp_read_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key,
                          const unsigned char *buf, size_t buflen);
 
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+/**
+ * \brief           This function exports an elliptic curve private key.
+ *
+ * \deprecated      Note that although this function accepts an output
+ *                  buffer that is smaller or larger than the key, most key
+ *                  import interfaces require the output to have exactly
+ *                  key's nominal length. It is generally simplest to
+ *                  pass the key's nominal length as \c buflen, after
+ *                  checking that the output buffer is large enough.
+ *                  See the description of the \p buflen parameter for
+ *                  how to calculate the nominal length.
+ *                  To avoid this difficulty, use mbedtls_ecp_write_key_ext()
+ *                  instead.
+ *                  mbedtls_ecp_write_key() is deprecated and will be
+ *                  removed in a future version of the library.
+ *
+ * \note            If the private key was not set in \p key,
+ *                  the output is unspecified. Future versions
+ *                  may return an error in that case.
+ *
+ * \param key       The private key.
+ * \param buf       The output buffer for containing the binary representation
+ *                  of the key.
+ *                  For Weierstrass curves, this is the big-endian
+ *                  representation, padded with null bytes at the beginning
+ *                  to reach \p buflen bytes.
+ *                  For Montgomery curves, this is the standard byte string
+ *                  representation (which is little-endian), padded with
+ *                  null bytes at the end to reach \p buflen bytes.
+ * \param buflen    The total length of the buffer in bytes.
+ *                  The length of the output is
+ *                  (`grp->nbits` + 7) / 8 bytes
+ *                  where `grp->nbits` is the private key size in bits.
+ *                  For Weierstrass keys, if the output buffer is smaller,
+ *                  leading zeros are trimmed to fit if possible. For
+ *                  Montgomery keys, the output buffer must always be large
+ *                  enough for the nominal length.
+ *
+ * \return          \c 0 on success.
+ * \return          #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL or
+ *                  #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if the \p key
+ *                  representation is larger than the available space in \p buf.
+ * \return          Another negative error code on different kinds of failure.
+ */
+int MBEDTLS_DEPRECATED mbedtls_ecp_write_key(mbedtls_ecp_keypair *key,
+                                             unsigned char *buf, size_t buflen);
+#endif /* MBEDTLS_DEPRECATED_REMOVED */
+
 /**
  * \brief           This function exports an elliptic curve private key.
  *
  * \param key       The private key.
+ * \param olen      On success, the length of the private key.
+ *                  This is always (`grp->nbits` + 7) / 8 bytes
+ *                  where `grp->nbits` is the private key size in bits.
  * \param buf       The output buffer for containing the binary representation
- *                  of the key. (Big endian integer for Weierstrass curves, byte
- *                  string for Montgomery curves.)
+ *                  of the key.
  * \param buflen    The total length of the buffer in bytes.
+ *                  #MBEDTLS_ECP_MAX_BYTES is always sufficient.
  *
  * \return          \c 0 on success.
  * \return          #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the \p key
-                    representation is larger than the available space in \p buf.
- * \return          #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the operation for
- *                  the group is not implemented.
+ *                  representation is larger than the available space in \p buf.
+ * \return          #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if no private key is
+ *                  set in \p key.
  * \return          Another negative error code on different kinds of failure.
  */
-int mbedtls_ecp_write_key(mbedtls_ecp_keypair *key,
-                          unsigned char *buf, size_t buflen);
+int mbedtls_ecp_write_key_ext(const mbedtls_ecp_keypair *key,
+                              size_t *olen, unsigned char *buf, size_t buflen);
 
 /**
  * \brief           This function exports an elliptic curve public key.
  *
+ * \note            If the public key was not set in \p key,
+ *                  the output is unspecified. Future versions
+ *                  may return an error in that case.
+ *
  * \param key       The public key.
  * \param format    The point format. This must be either
  *                  #MBEDTLS_ECP_PF_COMPRESSED or #MBEDTLS_ECP_PF_UNCOMPRESSED.
@@ -1431,6 +1488,10 @@
  *                  Each of the output parameters can be a null pointer
  *                  if you do not need that parameter.
  *
+ * \note            If the private key or the public key was not set in \p key,
+ *                  the corresponding output is unspecified. Future versions
+ *                  may return an error in that case.
+ *
  * \param key       The key pair to export from.
  * \param grp       Slot for exported ECP group.
  *                  It must either be null or point to an initialized ECP group.
diff --git a/include/mbedtls/gcm.h b/include/mbedtls/gcm.h
index 631b392..98faa43 100644
--- a/include/mbedtls/gcm.h
+++ b/include/mbedtls/gcm.h
@@ -46,6 +46,12 @@
 
 #if !defined(MBEDTLS_GCM_ALT)
 
+#if defined(MBEDTLS_GCM_LARGE_TABLE)
+#define MBEDTLS_GCM_HTABLE_SIZE 256
+#else
+#define MBEDTLS_GCM_HTABLE_SIZE 16
+#endif
+
 /**
  * \brief          The GCM context structure.
  */
@@ -53,18 +59,18 @@
 #if defined(MBEDTLS_BLOCK_CIPHER_C)
     mbedtls_block_cipher_context_t MBEDTLS_PRIVATE(block_cipher_ctx);  /*!< The cipher context used. */
 #else
-    mbedtls_cipher_context_t MBEDTLS_PRIVATE(cipher_ctx);  /*!< The cipher context used. */
+    mbedtls_cipher_context_t MBEDTLS_PRIVATE(cipher_ctx);    /*!< The cipher context used. */
 #endif
-    uint64_t MBEDTLS_PRIVATE(HL)[16];                      /*!< Precalculated HTable low. */
-    uint64_t MBEDTLS_PRIVATE(HH)[16];                      /*!< Precalculated HTable high. */
-    uint64_t MBEDTLS_PRIVATE(len);                         /*!< The total length of the encrypted data. */
-    uint64_t MBEDTLS_PRIVATE(add_len);                     /*!< The total length of the additional data. */
-    unsigned char MBEDTLS_PRIVATE(base_ectr)[16];          /*!< The first ECTR for tag. */
-    unsigned char MBEDTLS_PRIVATE(y)[16];                  /*!< The Y working value. */
-    unsigned char MBEDTLS_PRIVATE(buf)[16];                /*!< The buf working value. */
-    int MBEDTLS_PRIVATE(mode);                             /*!< The operation to perform:
-                                                            #MBEDTLS_GCM_ENCRYPT or
-                                                            #MBEDTLS_GCM_DECRYPT. */
+    uint64_t MBEDTLS_PRIVATE(H)[MBEDTLS_GCM_HTABLE_SIZE][2]; /*!< Precalculated HTable. */
+    uint64_t MBEDTLS_PRIVATE(len);                           /*!< The total length of the encrypted data. */
+    uint64_t MBEDTLS_PRIVATE(add_len);                       /*!< The total length of the additional data. */
+    unsigned char MBEDTLS_PRIVATE(base_ectr)[16];            /*!< The first ECTR for tag. */
+    unsigned char MBEDTLS_PRIVATE(y)[16];                    /*!< The Y working value. */
+    unsigned char MBEDTLS_PRIVATE(buf)[16];                  /*!< The buf working value. */
+    unsigned char MBEDTLS_PRIVATE(mode);                     /*!< The operation to perform:
+                                                              #MBEDTLS_GCM_ENCRYPT or
+                                                              #MBEDTLS_GCM_DECRYPT. */
+    unsigned char MBEDTLS_PRIVATE(acceleration);             /*!< The acceleration to use. */
 }
 mbedtls_gcm_context;
 
diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h
index 6a5828c..7cf4153 100644
--- a/include/mbedtls/mbedtls_config.h
+++ b/include/mbedtls/mbedtls_config.h
@@ -2801,6 +2801,22 @@
 #define MBEDTLS_GCM_C
 
 /**
+ * \def MBEDTLS_GCM_LARGE_TABLE
+ *
+ * Enable large pre-computed tables for  Galois/Counter Mode (GCM).
+ * Can significantly increase throughput on systems without GCM hardware
+ * acceleration (e.g., AESNI, AESCE).
+ *
+ * The mbedtls_gcm_context size will increase by 3840 bytes.
+ * The code size will increase by roughly 344 bytes.
+ *
+ * Module:  library/gcm.c
+ *
+ * Requires: MBEDTLS_GCM_C
+ */
+//#define MBEDTLS_GCM_LARGE_TABLE
+
+/**
  * \def MBEDTLS_HKDF_C
  *
  * Enable the HKDF algorithm (RFC 5869).
@@ -3059,7 +3075,7 @@
  * Caller:  library/x509_crt.c
  *          library/x509_csr.c
  *
- * Requires: MBEDTLS_PK_C
+ * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_OID_C, MBEDTLS_PK_C
  *
  * Uncomment to enable generic public key parse functions.
  */
@@ -3073,7 +3089,7 @@
  * Module:  library/pkwrite.c
  * Caller:  library/x509write.c
  *
- * Requires: MBEDTLS_PK_C
+ * Requires: MBEDTLS_ASN1_WRITE_C, MBEDTLS_OID_C, MBEDTLS_PK_C
  *
  * Uncomment to enable generic public key write functions.
  */
diff --git a/include/mbedtls/pem.h b/include/mbedtls/pem.h
index cc617a9..3c6a28d 100644
--- a/include/mbedtls/pem.h
+++ b/include/mbedtls/pem.h
@@ -73,11 +73,11 @@
  * \param data      source data to look in (must be nul-terminated)
  * \param pwd       password for decryption (can be NULL)
  * \param pwdlen    length of password
- * \param use_len   destination for total length used (set after header is
- *                  correctly read, so unless you get
+ * \param use_len   destination for total length used from data buffer. It is
+ *                  set after header is correctly read, so unless you get
  *                  MBEDTLS_ERR_PEM_BAD_INPUT_DATA or
  *                  MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT, use_len is
- *                  the length to skip)
+ *                  the length to skip.
  *
  * \note            Attempts to check password correctness by verifying if
  *                  the decrypted text starts with an ASN.1 sequence of
diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h
index 66f3901..d83152c 100644
--- a/include/mbedtls/pk.h
+++ b/include/mbedtls/pk.h
@@ -181,13 +181,6 @@
 #define MBEDTLS_PK_USE_PSA_EC_DATA
 #endif
 
-/* Helper symbol to state that the PK module has support for EC keys. This
- * can either be provided through the legacy ECP solution or through the
- * PSA friendly MBEDTLS_PK_USE_PSA_EC_DATA. */
-#if defined(MBEDTLS_PK_USE_PSA_EC_DATA) || defined(MBEDTLS_ECP_C)
-#define MBEDTLS_PK_HAVE_ECC_KEYS
-#endif /* MBEDTLS_PK_USE_PSA_EC_DATA || MBEDTLS_ECP_C */
-
 /**
  * \brief           Types for interfacing with the debug module
  */
@@ -491,20 +484,20 @@
  * \brief           Determine valid PSA attributes that can be used to
  *                  import a key into PSA.
  *
- *                  The attributes determined by this function are suitable
- *                  for calling mbedtls_pk_import_into_psa() to create
- *                  a PSA key with the same key material.
+ * The attributes determined by this function are suitable
+ * for calling mbedtls_pk_import_into_psa() to create
+ * a PSA key with the same key material.
  *
- *                  The typical flow of operations involving this function is
- *                  ```
- *                  psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
- *                  int ret = mbedtls_pk_get_psa_attributes(pk, &attributes);
- *                  if (ret != 0) ...; // error handling omitted
- *                  // Tweak attributes if desired
- *                  psa_key_id_t key_id = 0;
- *                  ret = mbedtls_pk_import_into_psa(pk, &attributes, &key_id);
- *                  if (ret != 0) ...; // error handling omitted
- *                  ```
+ * The typical flow of operations involving this function is
+ * ```
+ * psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ * int ret = mbedtls_pk_get_psa_attributes(pk, &attributes);
+ * if (ret != 0) ...; // error handling omitted
+ * // Tweak attributes if desired
+ * psa_key_id_t key_id = 0;
+ * ret = mbedtls_pk_import_into_psa(pk, &attributes, &key_id);
+ * if (ret != 0) ...; // error handling omitted
+ * ```
  *
  * \note            This function does not support RSA-alt contexts
  *                  (set up with mbedtls_pk_setup_rsa_alt()).
@@ -599,6 +592,53 @@
 int mbedtls_pk_get_psa_attributes(const mbedtls_pk_context *pk,
                                   psa_key_usage_t usage,
                                   psa_key_attributes_t *attributes);
+
+/**
+ * \brief           Import a key into the PSA key store.
+ *
+ * This function is equivalent to calling psa_import_key()
+ * with the key material from \p pk.
+ *
+ * The typical way to use this function is:
+ * -# Call mbedtls_pk_get_psa_attributes() to obtain
+ *    attributes for the given key.
+ * -# If desired, modify the attributes, for example:
+ *     - To create a persistent key, call
+ *       psa_set_key_identifier() and optionally
+ *       psa_set_key_lifetime().
+ *     - To import only the public part of a key pair:
+ *
+ *           psa_set_key_type(&attributes,
+ *                            PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(
+ *                                psa_get_key_type(&attributes)));
+ *     - Restrict the key usage if desired.
+ * -# Call mbedtls_pk_import_into_psa().
+ *
+ * \note            This function does not support RSA-alt contexts
+ *                  (set up with mbedtls_pk_setup_rsa_alt()).
+ *
+ * \param[in] pk    The PK context to use. It must have been set up.
+ *                  It can either contain a key pair or just a public key.
+ * \param[in] attributes
+ *                  The attributes to use for the new key. They must be
+ *                  compatible with \p pk. In particular, the key type
+ *                  must match the content of \p pk.
+ *                  If \p pk contains a key pair, the key type in
+ *                  attributes can be either the key pair type or the
+ *                  corresponding public key type (to import only the
+ *                  public part).
+ * \param[out] key_id
+ *                  On success, the identifier of the newly created key.
+ *                  On error, this is #MBEDTLS_SVC_KEY_ID_INIT.
+ *
+ * \return          0 on success.
+ *                  #MBEDTLS_ERR_PK_TYPE_MISMATCH if \p pk does not contain
+ *                  a key of the type identified in \p attributes.
+ *                  Another error code on other failures.
+ */
+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 */
 
 /**
@@ -619,14 +659,17 @@
  * \param sig       Signature to verify
  * \param sig_len   Signature length
  *
+ * \note            For keys of type #MBEDTLS_PK_RSA, the signature algorithm is
+ *                  either PKCS#1 v1.5 or PSS (accepting any salt length),
+ *                  depending on the padding mode in the underlying RSA context.
+ *                  For a pk object constructed by parsing, this is PKCS#1 v1.5
+ *                  by default. Use mbedtls_pk_verify_ext() to explicitly select
+ *                  a different algorithm.
+ *
  * \return          0 on success (signature is valid),
  *                  #MBEDTLS_ERR_PK_SIG_LEN_MISMATCH if there is a valid
  *                  signature in \p sig but its length is less than \p sig_len,
  *                  or a specific error code.
- *
- * \note            For RSA keys, the default padding type is PKCS#1 v1.5.
- *                  Use \c mbedtls_pk_verify_ext( MBEDTLS_PK_RSASSA_PSS, ... )
- *                  to verify RSASSA_PSS signatures.
  */
 int mbedtls_pk_verify(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
                       const unsigned char *hash, size_t hash_len,
@@ -713,11 +756,15 @@
  * \param f_rng     RNG function, must not be \c NULL.
  * \param p_rng     RNG parameter
  *
- * \return          0 on success, or a specific error code.
+ * \note            For keys of type #MBEDTLS_PK_RSA, the signature algorithm is
+ *                  either PKCS#1 v1.5 or PSS (using the largest possible salt
+ *                  length up to the hash length), depending on the padding mode
+ *                  in the underlying RSA context. For a pk object constructed
+ *                  by parsing, this is PKCS#1 v1.5 by default. Use
+ *                  mbedtls_pk_verify_ext() to explicitly select a different
+ *                  algorithm.
  *
- * \note            For RSA keys, the default padding type is PKCS#1 v1.5.
- *                  There is no interface in the PK module to make RSASSA-PSS
- *                  signatures yet.
+ * \return          0 on success, or a specific error code.
  *
  * \note            For RSA, md_alg may be MBEDTLS_MD_NONE if hash_len != 0.
  *                  For ECDSA, md_alg may never be MBEDTLS_MD_NONE.
@@ -813,7 +860,10 @@
  * \param f_rng     RNG function, must not be \c NULL.
  * \param p_rng     RNG parameter
  *
- * \note            For RSA keys, the default padding type is PKCS#1 v1.5.
+ * \note            For keys of type #MBEDTLS_PK_RSA, the signature algorithm is
+ *                  either PKCS#1 v1.5 or OAEP, depending on the padding mode in
+ *                  the underlying RSA context. For a pk object constructed by
+ *                  parsing, this is PKCS#1 v1.5 by default.
  *
  * \return          0 on success, or a specific error code.
  */
@@ -834,9 +884,12 @@
  * \param f_rng     RNG function, must not be \c NULL.
  * \param p_rng     RNG parameter
  *
- * \note            \p f_rng is used for padding generation.
+ * \note            For keys of type #MBEDTLS_PK_RSA, the signature algorithm is
+ *                  either PKCS#1 v1.5 or OAEP, depending on the padding mode in
+ *                  the underlying RSA context. For a pk object constructed by
+ *                  parsing, this is PKCS#1 v1.5 by default.
  *
- * \note            For RSA keys, the default padding type is PKCS#1 v1.5.
+ * \note            \p f_rng is used for padding generation.
  *
  * \return          0 on success, or a specific error code.
  */
@@ -1159,33 +1212,6 @@
                             const mbedtls_pk_context *key);
 #endif /* MBEDTLS_PK_WRITE_C */
 
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-/**
- * \brief           Turn an EC or RSA key into an opaque one.
- *
- * \warning         This is a temporary utility function for tests. It might
- *                  change or be removed at any time without notice.
- *
- * \param pk        Input: the EC or RSA key to import to a PSA key.
- *                  Output: a PK context wrapping that PSA key.
- * \param key       Output: a PSA key identifier.
- *                  It's the caller's responsibility to call
- *                  psa_destroy_key() on that key identifier after calling
- *                  mbedtls_pk_free() on the PK context.
- * \param alg       The algorithm to allow for use with that key.
- * \param usage     The usage to allow for use with that key.
- * \param alg2      The secondary algorithm to allow for use with that key.
- *
- * \return          \c 0 if successful.
- * \return          An Mbed TLS error code otherwise.
- */
-int mbedtls_pk_wrap_as_opaque(mbedtls_pk_context *pk,
-                              mbedtls_svc_key_id_t *key,
-                              psa_algorithm_t alg,
-                              psa_key_usage_t usage,
-                              psa_algorithm_t alg2);
-#endif /* MBEDTLS_USE_PSA_CRYPTO */
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/mbedtls/psa_util.h b/include/mbedtls/psa_util.h
index 984f031..c78cc23 100644
--- a/include/mbedtls/psa_util.h
+++ b/include/mbedtls/psa_util.h
@@ -21,44 +21,24 @@
  * otherwise error codes would be unknown in test_suite_psa_crypto_util.data.*/
 #include <mbedtls/asn1write.h>
 
-#if defined(MBEDTLS_PSA_CRYPTO_C)
-
-/* Expose whatever RNG the PSA subsystem uses to applications using the
- * mbedtls_xxx API. The declarations and definitions here need to be
- * consistent with the implementation in library/psa_crypto_random_impl.h.
- * See that file for implementation documentation. */
-
-
-/* The type of a `f_rng` random generator function that many library functions
- * take.
- *
- * This type name is not part of the Mbed TLS stable API. It may be renamed
- * or moved without warning.
- */
-typedef int mbedtls_f_rng_t(void *p_rng, unsigned char *output, size_t output_size);
-
-#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+#if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
 
 /** The random generator function for the PSA subsystem.
  *
  * This function is suitable as the `f_rng` random generator function
- * parameter of many `mbedtls_xxx` functions. Use #MBEDTLS_PSA_RANDOM_STATE
- * to obtain the \p p_rng parameter.
+ * parameter of many `mbedtls_xxx` functions.
  *
  * The implementation of this function depends on the configuration of the
  * library.
  *
- * \note Depending on the configuration, this may be a function or
- *       a pointer to a function.
- *
  * \note This function may only be used if the PSA crypto subsystem is active.
  *       This means that you must call psa_crypto_init() before any call to
  *       this function, and you must not call this function after calling
  *       mbedtls_psa_crypto_free().
  *
- * \param p_rng         The random generator context. This must be
- *                      #MBEDTLS_PSA_RANDOM_STATE. No other state is
- *                      supported.
+ * \param p_rng         This parameter is only kept for backward compatibility
+ *                      reasons with legacy `f_rng` functions and it's ignored.
+ *                      Set to #MBEDTLS_PSA_RANDOM_STATE or NULL.
  * \param output        The buffer to fill. It must have room for
  *                      \c output_size bytes.
  * \param output_size   The number of bytes to write to \p output.
@@ -80,32 +60,11 @@
 
 /** The random generator state for the PSA subsystem.
  *
- * This macro expands to an expression which is suitable as the `p_rng`
- * random generator state parameter of many `mbedtls_xxx` functions.
- * It must be used in combination with the random generator function
- * mbedtls_psa_get_random().
- *
- * The implementation of this macro depends on the configuration of the
- * library. Do not make any assumption on its nature.
+ * This macro always expands to NULL because the `p_rng` parameter is unused
+ * in mbedtls_psa_get_random(), but it's kept for interface's backward
+ * compatibility.
  */
-#define MBEDTLS_PSA_RANDOM_STATE NULL
-
-#else /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */
-
-#if defined(MBEDTLS_CTR_DRBG_C)
-#include "mbedtls/ctr_drbg.h"
-typedef mbedtls_ctr_drbg_context mbedtls_psa_drbg_context_t;
-static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_ctr_drbg_random;
-#elif defined(MBEDTLS_HMAC_DRBG_C)
-#include "mbedtls/hmac_drbg.h"
-typedef mbedtls_hmac_drbg_context mbedtls_psa_drbg_context_t;
-static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_hmac_drbg_random;
-#endif
-extern mbedtls_psa_drbg_context_t *const mbedtls_psa_random_state;
-
-#define MBEDTLS_PSA_RANDOM_STATE mbedtls_psa_random_state
-
-#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */
+#define MBEDTLS_PSA_RANDOM_STATE    NULL
 
 /** \defgroup psa_tls_helpers TLS helper functions
  * @{
@@ -180,7 +139,7 @@
 {
     return (mbedtls_md_type_t) (psa_alg & PSA_ALG_HASH_MASK);
 }
-#endif /* MBEDTLS_PSA_CRYPTO_C */
+#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */
 
 #if defined(MBEDTLS_PSA_UTIL_HAVE_ECDSA)
 
diff --git a/include/mbedtls/rsa.h b/include/mbedtls/rsa.h
index 9136375..c1e76b3 100644
--- a/include/mbedtls/rsa.h
+++ b/include/mbedtls/rsa.h
@@ -427,6 +427,16 @@
                            mbedtls_mpi *DP, mbedtls_mpi *DQ, mbedtls_mpi *QP);
 
 /**
+ * \brief          This function retrieves the length of the RSA modulus in bits.
+ *
+ * \param ctx      The initialized RSA context.
+ *
+ * \return         The length of the RSA modulus in bits.
+ *
+ */
+size_t mbedtls_rsa_get_bitlen(const mbedtls_rsa_context *ctx);
+
+/**
  * \brief          This function retrieves the length of RSA modulus in Bytes.
  *
  * \param ctx      The initialized RSA context.
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index e0cd79d..9a66663 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -734,6 +734,51 @@
 }
 mbedtls_ssl_states;
 
+/*
+ * Early data status, client side only.
+ */
+
+#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C)
+typedef enum {
+/*
+ * The client has not sent the first ClientHello yet, it is unknown if the
+ * client will send an early data indication extension or not.
+ */
+    MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN,
+
+/*
+ * See documentation of mbedtls_ssl_get_early_data_status().
+ */
+    MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT,
+    MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED,
+    MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED,
+
+/*
+ * The client has sent an early data indication extension in its first
+ * ClientHello, it has not received the response (ServerHello or
+ * HelloRetryRequest) from the server yet. The transform to protect early data
+ * is not set and early data cannot be sent yet.
+ */
+    MBEDTLS_SSL_EARLY_DATA_STATUS_SENT,
+
+/*
+ * The client has sent an early data indication extension in its first
+ * ClientHello, it has not received the response (ServerHello or
+ * HelloRetryRequest) from the server yet. The transform to protect early data
+ * has been set and early data can be written now.
+ */
+    MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE,
+
+/*
+ * The client has sent an early data indication extension in its first
+ * ClientHello, the server has accepted them and the client has received the
+ * server Finished message. It cannot send early data to the server anymore.
+ */
+    MBEDTLS_SSL_EARLY_DATA_STATUS_SERVER_FINISHED_RECEIVED,
+} mbedtls_ssl_early_data_status;
+
+#endif /* MBEDTLS_SSL_EARLY_DATA && MBEDTLS_SSL_CLI_C */
+
 /**
  * \brief          Callback type: send data on the network.
  *
@@ -1224,6 +1269,7 @@
 #endif /* MBEDTLS_SSL_RECORD_SIZE_LIMIT */
 
     unsigned char MBEDTLS_PRIVATE(exported);
+    uint8_t MBEDTLS_PRIVATE(endpoint);          /*!< 0: client, 1: server */
 
     /** TLS version negotiated in the session. Used if and when renegotiating
      *  or resuming a session instead of the configured minor TLS version.
@@ -1257,26 +1303,41 @@
     uint32_t MBEDTLS_PRIVATE(ticket_lifetime);   /*!< ticket lifetime hint    */
 #endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
 
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_SRV_C) && \
+    defined(MBEDTLS_HAVE_TIME)
+    /*! When a ticket is created by a TLS server as part of an established TLS
+     *  session, the ticket creation time may need to be saved for the ticket
+     *  module to be able to check the ticket age when the ticket is used.
+     *  That's the purpose of this field.
+     *  Before creating a new ticket, an Mbed TLS server set this field with
+     *  its current time in milliseconds. This time may then be saved in the
+     *  session ticket data by the session ticket writing function and
+     *  recovered by the ticket parsing function later when the ticket is used.
+     *  The ticket module may then use this time to compute the ticket age and
+     *  determine if it has expired or not.
+     *  The Mbed TLS implementations of the session ticket writing and parsing
+     *  functions save and retrieve the ticket creation time as part of the
+     *  session ticket data. The session ticket parsing function relies on
+     *  the mbedtls_ssl_session_get_ticket_creation_time() API to get the
+     *  ticket creation time from the session ticket data.
+     */
+    mbedtls_ms_time_t MBEDTLS_PRIVATE(ticket_creation_time);
+#endif
+
 #if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS)
-    uint8_t MBEDTLS_PRIVATE(endpoint);          /*!< 0: client, 1: server */
-    uint8_t MBEDTLS_PRIVATE(ticket_flags);      /*!< Ticket flags */
-    uint32_t MBEDTLS_PRIVATE(ticket_age_add);               /*!< Randomly generated value used to obscure the age of the ticket */
-    uint8_t MBEDTLS_PRIVATE(resumption_key_len);            /*!< resumption_key length */
+    uint32_t MBEDTLS_PRIVATE(ticket_age_add);     /*!< Randomly generated value used to obscure the age of the ticket */
+    uint8_t MBEDTLS_PRIVATE(ticket_flags);        /*!< Ticket flags */
+    uint8_t MBEDTLS_PRIVATE(resumption_key_len);  /*!< resumption_key length */
     unsigned char MBEDTLS_PRIVATE(resumption_key)[MBEDTLS_SSL_TLS1_3_TICKET_RESUMPTION_KEY_LEN];
 
 #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && defined(MBEDTLS_SSL_CLI_C)
     char *MBEDTLS_PRIVATE(hostname);             /*!< host name binded with tickets */
 #endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION && MBEDTLS_SSL_CLI_C */
 
-#if defined(MBEDTLS_HAVE_TIME)
-#if defined(MBEDTLS_SSL_CLI_C)
-    mbedtls_ms_time_t MBEDTLS_PRIVATE(ticket_reception_time);   /*!< time when ticket was received. */
+#if defined(MBEDTLS_HAVE_TIME) && defined(MBEDTLS_SSL_CLI_C)
+    /*! Time in milliseconds when the last ticket was received. */
+    mbedtls_ms_time_t MBEDTLS_PRIVATE(ticket_reception_time);
 #endif
-#if defined(MBEDTLS_SSL_SRV_C)
-    mbedtls_ms_time_t MBEDTLS_PRIVATE(ticket_creation_time);    /*!< time when ticket was created. */
-#endif
-#endif /* MBEDTLS_HAVE_TIME */
-
 #endif /*  MBEDTLS_SSL_PROTO_TLS1_3 && MBEDTLS_SSL_SESSION_TICKETS */
 
 #if defined(MBEDTLS_SSL_EARLY_DATA)
@@ -1657,33 +1718,29 @@
 #endif /* MBEDTLS_SSL_RENEGOTIATION */
 
     /**
-     *  Maximum TLS version to be negotiated, then negotiated TLS version.
+     * Maximum TLS version to be negotiated, then negotiated TLS version.
      *
-     *  It is initialized as the configured maximum TLS version to be
-     *  negotiated by mbedtls_ssl_setup().
+     * It is initialized as the configured maximum TLS version to be
+     * negotiated by mbedtls_ssl_setup().
      *
-     *  When renegotiating or resuming a session, it is overwritten in the
-     *  ClientHello writing preparation stage with the previously negotiated
-     *  TLS version.
+     * When renegotiating or resuming a session, it is overwritten in the
+     * ClientHello writing preparation stage with the previously negotiated
+     * TLS version.
      *
-     *  On client side, it is updated to the TLS version selected by the server
-     *  for the handshake when the ServerHello is received.
+     * On client side, it is updated to the TLS version selected by the server
+     * for the handshake when the ServerHello is received.
      *
-     *  On server side, it is updated to the TLS version the server selects for
-     *  the handshake when the ClientHello is received.
+     * On server side, it is updated to the TLS version the server selects for
+     * the handshake when the ClientHello is received.
      */
     mbedtls_ssl_protocol_version MBEDTLS_PRIVATE(tls_version);
 
 #if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C)
     /**
-     *  Status of the negotiation of the use of early data.
-     *  See the documentation of mbedtls_ssl_get_early_data_status() for more
-     *  information.
-     *
-     *  Reset to #MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT when the context is
-     *  reset.
+     * Status of the negotiation of the use of early data. Reset to
+     * MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN when the context is reset.
      */
-    int MBEDTLS_PRIVATE(early_data_status);
+    mbedtls_ssl_early_data_status MBEDTLS_PRIVATE(early_data_status);
 #endif
 
     unsigned MBEDTLS_PRIVATE(badmac_seen);       /*!< records with a bad MAC received    */
@@ -1802,7 +1859,8 @@
                                                          *   within a single datagram.  */
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 
-#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_SRV_C)
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+#if defined(MBEDTLS_SSL_SRV_C)
     /*
      * One of:
      * MBEDTLS_SSL_EARLY_DATA_NO_DISCARD
@@ -1811,6 +1869,8 @@
      */
     uint8_t MBEDTLS_PRIVATE(discard_early_data_record);
 #endif
+    uint32_t MBEDTLS_PRIVATE(total_early_data_size); /*!< Number of received/written early data bytes */
+#endif /* MBEDTLS_SSL_EARLY_DATA */
 
     /*
      * Record layer (outgoing data)
@@ -2630,6 +2690,34 @@
                                          mbedtls_ssl_ticket_write_t *f_ticket_write,
                                          mbedtls_ssl_ticket_parse_t *f_ticket_parse,
                                          void *p_ticket);
+
+#if defined(MBEDTLS_HAVE_TIME)
+/**
+ * \brief Get the creation time of a session ticket.
+ *
+ * \note See the documentation of \c ticket_creation_time for information about
+ *       the intended usage of this function.
+ *
+ * \param session  SSL session
+ * \param ticket_creation_time  On exit, holds the ticket creation time in
+ *                              milliseconds.
+ *
+ * \return         0 on success,
+ *                 MBEDTLS_ERR_SSL_BAD_INPUT_DATA if an input is not valid.
+ */
+static inline int mbedtls_ssl_session_get_ticket_creation_time(
+    mbedtls_ssl_session *session, mbedtls_ms_time_t *ticket_creation_time)
+{
+    if (session == NULL || ticket_creation_time == NULL ||
+        session->MBEDTLS_PRIVATE(endpoint) != MBEDTLS_SSL_IS_SERVER) {
+        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+    }
+
+    *ticket_creation_time = session->MBEDTLS_PRIVATE(ticket_creation_time);
+
+    return 0;
+}
+#endif /* MBEDTLS_HAVE_TIME */
 #endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_SRV_C */
 
 /**
@@ -4737,7 +4825,7 @@
  * \param ssl      The SSL context representing the connection for which to
  *                 to export a session structure for later resumption.
  * \param session  The target structure in which to store the exported session.
- *                 This must have been initialized with mbedtls_ssl_init_session()
+ *                 This must have been initialized with mbedtls_ssl_session_init()
  *                 but otherwise be unused.
  *
  * \note           This function can handle a variety of mechanisms for session
@@ -5106,10 +5194,6 @@
 
 #if defined(MBEDTLS_SSL_EARLY_DATA)
 
-#define MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT  0
-#define MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED  1
-#define MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED  2
-
 #if defined(MBEDTLS_SSL_SRV_C)
 /**
  * \brief          Read at most 'len' bytes of early data
@@ -5162,17 +5246,43 @@
  * \brief          Try to write exactly 'len' application data bytes while
  *                 performing the handshake (early data).
  *
+ * \warning        Early data is defined in the TLS 1.3 specification, RFC 8446.
+ *                 IMPORTANT NOTE from section 2.3 of the specification:
+ *
+ *                 The security properties for 0-RTT data are weaker than
+ *                 those for other kinds of TLS data. Specifically:
+ *                 - This data is not forward secret, as it is encrypted
+ *                   solely under keys derived using the offered PSK.
+ *                 - There are no guarantees of non-replay between connections.
+ *                   Protection against replay for ordinary TLS 1.3 1-RTT data
+ *                   is provided via the server's Random value, but 0-RTT data
+ *                   does not depend on the ServerHello and therefore has
+ *                   weaker guarantees. This is especially relevant if the
+ *                   data is authenticated either with TLS client
+ *                   authentication or inside the application protocol. The
+ *                   same warnings apply to any use of the
+ *                   early_exporter_master_secret.
+ *
  * \note           This function behaves mainly as mbedtls_ssl_write(). The
  *                 specification of mbedtls_ssl_write() relevant to TLS 1.3
  *                 (thus not the parts specific to (D)TLS1.2) applies to this
- *                 function and the present documentation is restricted to the
- *                 differences with mbedtls_ssl_write().
+ *                 function and the present documentation is mainly restricted
+ *                 to the differences with mbedtls_ssl_write(). One noticeable
+ *                 difference though is that mbedtls_ssl_write() aims to
+ *                 complete the handshake before to write application data
+ *                 while mbedtls_ssl_write_early() aims to drive the handshake
+ *                 just past the point where it is not possible to send early
+ *                 data anymore.
  *
  * \param ssl      SSL context
  * \param buf      buffer holding the data
  * \param len      how many bytes must be written
  *
- * \return         One additional specific return value:
+ * \return         The (non-negative) number of bytes actually written if
+ *                 successful (may be less than \p len).
+ *
+ * \return         One additional specific error code compared to
+ *                 mbedtls_ssl_write():
  *                 #MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA.
  *
  *                 #MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA is returned when it
@@ -5193,9 +5303,11 @@
  *                 already completed.
  *
  *                 It is not possible to write early data for the SSL context
- *                 \p ssl but this does not preclude for using it with
+ *                 \p ssl and any subsequent call to this API will return this
+ *                 error code. But this does not preclude for using it with
  *                 mbedtls_ssl_write(), mbedtls_ssl_read() or
- *                 mbedtls_ssl_handshake().
+ *                 mbedtls_ssl_handshake() and the handshake can be
+ *                 completed by calling one of these APIs.
  *
  * \note           This function may write early data only if the SSL context
  *                 has been configured for the handshake with a PSK for which
diff --git a/include/mbedtls/ssl_ticket.h b/include/mbedtls/ssl_ticket.h
index 6d59c12..5842049 100644
--- a/include/mbedtls/ssl_ticket.h
+++ b/include/mbedtls/ssl_ticket.h
@@ -50,6 +50,10 @@
 #if defined(MBEDTLS_HAVE_TIME)
     mbedtls_time_t MBEDTLS_PRIVATE(generation_time); /*!< key generation timestamp (seconds) */
 #endif
+    /*! Lifetime of the key in seconds. This is also the lifetime of the
+     *  tickets created under that key.
+     */
+    uint32_t MBEDTLS_PRIVATE(lifetime);
 #if !defined(MBEDTLS_USE_PSA_CRYPTO)
     mbedtls_cipher_context_t MBEDTLS_PRIVATE(ctx);   /*!< context for auth enc/decryption    */
 #else
diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h
index be63612..453f598 100644
--- a/include/mbedtls/x509.h
+++ b/include/mbedtls/x509.h
@@ -322,9 +322,151 @@
  */
 int mbedtls_x509_dn_gets(char *buf, size_t size, const mbedtls_x509_name *dn);
 
+/**
+ * \brief            Convert the certificate DN string \p name into
+ *                   a linked list of mbedtls_x509_name (equivalent to
+ *                   mbedtls_asn1_named_data).
+ *
+ * \note             This function allocates a linked list, and places the head
+ *                   pointer in \p head. This list must later be freed by a
+ *                   call to mbedtls_asn1_free_named_data_list().
+ *
+ * \param[out] head  Address in which to store the pointer to the head of the
+ *                   allocated list of mbedtls_x509_name
+ * \param[in] name   The string representation of a DN to convert
+ *
+ * \return           0 on success, or a negative error code.
+ */
 int mbedtls_x509_string_to_names(mbedtls_asn1_named_data **head, const char *name);
 
 /**
+ * \brief          Return the next relative DN in an X509 name.
+ *
+ * \note           Intended use is to compare function result to dn->next
+ *                 in order to detect boundaries of multi-valued RDNs.
+ *
+ * \param dn       Current node in the X509 name
+ *
+ * \return         Pointer to the first attribute-value pair of the
+ *                 next RDN in sequence, or NULL if end is reached.
+ */
+static inline mbedtls_x509_name *mbedtls_x509_dn_get_next(
+    mbedtls_x509_name *dn)
+{
+    while (dn->MBEDTLS_PRIVATE(next_merged) && dn->next != NULL) {
+        dn = dn->next;
+    }
+    return dn->next;
+}
+
+/**
+ * \brief          Store the certificate serial in printable form into buf;
+ *                 no more than size characters will be written.
+ *
+ * \param buf      Buffer to write to
+ * \param size     Maximum size of buffer
+ * \param serial   The X509 serial to represent
+ *
+ * \return         The length of the string written (not including the
+ *                 terminated nul byte), or a negative error code.
+ */
+int mbedtls_x509_serial_gets(char *buf, size_t size, const mbedtls_x509_buf *serial);
+
+/**
+ * \brief          Compare pair of mbedtls_x509_time.
+ *
+ * \param t1       mbedtls_x509_time to compare
+ * \param t2       mbedtls_x509_time to compare
+ *
+ * \return         < 0 if t1 is before t2
+ *                   0 if t1 equals t2
+ *                 > 0 if t1 is after t2
+ */
+int mbedtls_x509_time_cmp(const mbedtls_x509_time *t1, const mbedtls_x509_time *t2);
+
+#if defined(MBEDTLS_HAVE_TIME_DATE)
+/**
+ * \brief          Fill mbedtls_x509_time with provided mbedtls_time_t.
+ *
+ * \param tt       mbedtls_time_t to convert
+ * \param now      mbedtls_x509_time to fill with converted mbedtls_time_t
+ *
+ * \return         \c 0 on success
+ * \return         A non-zero return value on failure.
+ */
+int mbedtls_x509_time_gmtime(mbedtls_time_t tt, mbedtls_x509_time *now);
+#endif /* MBEDTLS_HAVE_TIME_DATE */
+
+/**
+ * \brief          Check a given mbedtls_x509_time against the system time
+ *                 and tell if it's in the past.
+ *
+ * \note           Intended usage is "if( is_past( valid_to ) ) ERROR".
+ *                 Hence the return value of 1 if on internal errors.
+ *
+ * \param to       mbedtls_x509_time to check
+ *
+ * \return         1 if the given time is in the past or an error occurred,
+ *                 0 otherwise.
+ */
+int mbedtls_x509_time_is_past(const mbedtls_x509_time *to);
+
+/**
+ * \brief          Check a given mbedtls_x509_time against the system time
+ *                 and tell if it's in the future.
+ *
+ * \note           Intended usage is "if( is_future( valid_from ) ) ERROR".
+ *                 Hence the return value of 1 if on internal errors.
+ *
+ * \param from     mbedtls_x509_time to check
+ *
+ * \return         1 if the given time is in the future or an error occurred,
+ *                 0 otherwise.
+ */
+int mbedtls_x509_time_is_future(const mbedtls_x509_time *from);
+
+/**
+ * \brief          This function parses an item in the SubjectAlternativeNames
+ *                 extension. Please note that this function might allocate
+ *                 additional memory for a subject alternative name, thus
+ *                 mbedtls_x509_free_subject_alt_name has to be called
+ *                 to dispose of this additional memory afterwards.
+ *
+ * \param san_buf  The buffer holding the raw data item of the subject
+ *                 alternative name.
+ * \param san      The target structure to populate with the parsed presentation
+ *                 of the subject alternative name encoded in \p san_buf.
+ *
+ * \note           Supported GeneralName types, as defined in RFC 5280:
+ *                 "rfc822Name", "dnsName", "directoryName",
+ *                 "uniformResourceIdentifier" and "hardware_module_name"
+ *                 of type "otherName", as defined in RFC 4108.
+ *
+ * \note           This function should be called on a single raw data of
+ *                 subject alternative name. For example, after successful
+ *                 certificate parsing, one must iterate on every item in the
+ *                 \c crt->subject_alt_names sequence, and pass it to
+ *                 this function.
+ *
+ * \warning        The target structure contains pointers to the raw data of the
+ *                 parsed certificate, and its lifetime is restricted by the
+ *                 lifetime of the certificate.
+ *
+ * \return         \c 0 on success
+ * \return         #MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE for an unsupported
+ *                 SAN type.
+ * \return         Another negative value for any other failure.
+ */
+int mbedtls_x509_parse_subject_alt_name(const mbedtls_x509_buf *san_buf,
+                                        mbedtls_x509_subject_alternative_name *san);
+/**
+ * \brief          Unallocate all data related to subject alternative name
+ *
+ * \param san      SAN structure - extra memory owned by this structure will be freed
+ */
+void mbedtls_x509_free_subject_alt_name(mbedtls_x509_subject_alternative_name *san);
+
+/**
  * \brief          This function parses a CN string as an IP address.
  *
  * \param cn       The CN string to parse. CN string MUST be null-terminated.
diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h
index 3f1a1e7..1ce0d23 100644
--- a/include/mbedtls/x509_crt.h
+++ b/include/mbedtls/x509_crt.h
@@ -916,6 +916,18 @@
     return ctx->MBEDTLS_PRIVATE(ext_types) & ext_type;
 }
 
+/**
+ * \brief               Access the ca_istrue field
+ *
+ * \param[in] crt       Certificate to be queried, must not be \c NULL
+ *
+ * \return              \c 1 if this a CA certificate \c 0 otherwise.
+ * \return              MBEDTLS_ERR_X509_INVALID_EXTENSIONS if the certificate does not contain
+ *                      the Optional Basic Constraint extension.
+ *
+ */
+int mbedtls_x509_crt_get_ca_istrue(const mbedtls_x509_crt *crt);
+
 /** \} name Structures and functions for parsing and writing X.509 certificates */
 
 #if defined(MBEDTLS_X509_CRT_WRITE_C)
diff --git a/include/psa/crypto.h b/include/psa/crypto.h
index fe10ee0..73889e0 100644
--- a/include/psa/crypto.h
+++ b/include/psa/crypto.h
@@ -119,8 +119,9 @@
  * value in the structure.
  * The persistent key will be written to storage when the attribute
  * structure is passed to a key creation function such as
- * psa_import_key(), psa_generate_key(),
- * psa_key_derivation_output_key() or psa_copy_key().
+ * psa_import_key(), psa_generate_key(), psa_generate_key_ext(),
+ * psa_key_derivation_output_key(), psa_key_derivation_output_key_ext()
+ * or psa_copy_key().
  *
  * This function may be declared as `static` (i.e. without external
  * linkage). This function may be provided as a function-like macro,
@@ -163,8 +164,9 @@
  * value in the structure.
  * The persistent key will be written to storage when the attribute
  * structure is passed to a key creation function such as
- * psa_import_key(), psa_generate_key(),
- * psa_key_derivation_output_key() or psa_copy_key().
+ * psa_import_key(), psa_generate_key(), psa_generate_key_ext(),
+ * psa_key_derivation_output_key(), psa_key_derivation_output_key_ext()
+ * or psa_copy_key().
  *
  * This function may be declared as `static` (i.e. without external
  * linkage). This function may be provided as a function-like macro,
@@ -3226,7 +3228,8 @@
  *    psa_key_derivation_set_capacity(). You may do this before, in the middle
  *    of or after providing inputs. For some algorithms, this step is mandatory
  *    because the output depends on the maximum capacity.
- * -# To derive a key, call psa_key_derivation_output_key().
+ * -# To derive a key, call psa_key_derivation_output_key() or
+ *    psa_key_derivation_output_key_ext().
  *    To derive a byte string for a different purpose, call
  *    psa_key_derivation_output_bytes().
  *    Successive calls to these functions use successive output bytes
@@ -3449,7 +3452,8 @@
  * \note Once all inputs steps are completed, the operations will allow:
  * - psa_key_derivation_output_bytes() if each input was either a direct input
  *   or  a key with #PSA_KEY_USAGE_DERIVE set;
- * - psa_key_derivation_output_key() if the input for step
+ * - psa_key_derivation_output_key() or psa_key_derivation_output_key_ext()
+ *   if the input for step
  *   #PSA_KEY_DERIVATION_INPUT_SECRET or #PSA_KEY_DERIVATION_INPUT_PASSWORD
  *   was from a key slot with #PSA_KEY_USAGE_DERIVE and each other input was
  *   either a direct input or a key with #PSA_KEY_USAGE_DERIVE set;
@@ -3697,6 +3701,11 @@
  * Future versions of this specification may include additional restrictions
  * on the derived key based on the attributes and strength of the secret key.
  *
+ * \note This function is equivalent to calling
+ *       psa_key_derivation_output_key_ext()
+ *       with the production parameters #PSA_KEY_PRODUCTION_PARAMETERS_INIT
+ *       and `params_data_length == 0` (i.e. `params->data` is empty).
+ *
  * \param[in] attributes    The attributes for the new key.
  *                          If the key type to be created is
  *                          #PSA_KEY_TYPE_PASSWORD_HASH then the algorithm in
@@ -3750,6 +3759,83 @@
     psa_key_derivation_operation_t *operation,
     mbedtls_svc_key_id_t *key);
 
+/** Derive a key from an ongoing key derivation operation with custom
+ *  production parameters.
+ *
+ * See the description of psa_key_derivation_out_key() for the operation of
+ * this function with the default production parameters.
+ * Mbed TLS currently does not currently support any non-default production
+ * parameters.
+ *
+ * \note This function is experimental and may change in future minor
+ *       versions of Mbed TLS.
+ *
+ * \param[in] attributes    The attributes for the new key.
+ *                          If the key type to be created is
+ *                          #PSA_KEY_TYPE_PASSWORD_HASH then the algorithm in
+ *                          the policy must be the same as in the current
+ *                          operation.
+ * \param[in,out] operation The key derivation operation object to read from.
+ * \param[in] params        Customization parameters for the key derivation.
+ *                          When this is #PSA_KEY_PRODUCTION_PARAMETERS_INIT
+ *                          with \p params_data_length = 0,
+ *                          this function is equivalent to
+ *                          psa_key_derivation_output_key().
+ *                          Mbed TLS currently only supports the default
+ *                          production parameters, i.e.
+ *                          #PSA_KEY_PRODUCTION_PARAMETERS_INIT,
+ *                          for all key types.
+ * \param params_data_length
+ *                          Length of `params->data` in bytes.
+ * \param[out] key          On success, an identifier for the newly created
+ *                          key. For persistent keys, this is the key
+ *                          identifier defined in \p attributes.
+ *                          \c 0 on failure.
+ *
+ * \retval #PSA_SUCCESS
+ *         Success.
+ *         If the key is persistent, the key material and the key's metadata
+ *         have been saved to persistent storage.
+ * \retval #PSA_ERROR_ALREADY_EXISTS
+ *         This is an attempt to create a persistent key, and there is
+ *         already a persistent key with the given identifier.
+ * \retval #PSA_ERROR_INSUFFICIENT_DATA
+ *         There was not enough data to create the desired key.
+ *         Note that in this case, no output is written to the output buffer.
+ *         The operation's capacity is set to 0, thus subsequent calls to
+ *         this function will not succeed, even with a smaller output buffer.
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ *         The key type or key size is not supported, either by the
+ *         implementation in general or in this particular location.
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ *         The provided key attributes are not valid for the operation.
+ * \retval #PSA_ERROR_NOT_PERMITTED
+ *         The #PSA_KEY_DERIVATION_INPUT_SECRET or
+ *         #PSA_KEY_DERIVATION_INPUT_PASSWORD input was not provided through a
+ *         key; or one of the inputs was a key whose policy didn't allow
+ *         #PSA_KEY_USAGE_DERIVE.
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
+ * \retval #PSA_ERROR_INSUFFICIENT_STORAGE \emptydescription
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
+ * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ * \retval #PSA_ERROR_DATA_INVALID \emptydescription
+ * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription
+ * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The operation state is not valid (it must be active and completed
+ *         all required input steps), or the library has not been previously
+ *         initialized by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_key_derivation_output_key_ext(
+    const psa_key_attributes_t *attributes,
+    psa_key_derivation_operation_t *operation,
+    const psa_key_production_parameters_t *params,
+    size_t params_data_length,
+    mbedtls_svc_key_id_t *key);
+
 /** Compare output data from a key derivation operation to an expected value.
  *
  * This function calculates output bytes from a key derivation algorithm and
@@ -3835,7 +3921,8 @@
  *                          and the permitted algorithm must match the
  *                          operation. The value of this key was likely
  *                          computed by a previous call to
- *                          psa_key_derivation_output_key().
+ *                          psa_key_derivation_output_key() or
+ *                          psa_key_derivation_output_key_ext().
  *
  * \retval #PSA_SUCCESS \emptydescription
  * \retval #PSA_ERROR_INVALID_SIGNATURE
@@ -4003,6 +4090,10 @@
  *   between 2^{n-1} and 2^n where n is the bit size specified in the
  *   attributes.
  *
+ * \note This function is equivalent to calling psa_generate_key_ext()
+ *       with the production parameters #PSA_KEY_PRODUCTION_PARAMETERS_INIT
+ *       and `params_data_length == 0` (i.e. `params->data` is empty).
+ *
  * \param[in] attributes    The attributes for the new key.
  * \param[out] key          On success, an identifier for the newly created
  *                          key. For persistent keys, this is the key
@@ -4035,6 +4126,60 @@
 psa_status_t psa_generate_key(const psa_key_attributes_t *attributes,
                               mbedtls_svc_key_id_t *key);
 
+/**
+ * \brief Generate a key or key pair using custom production parameters.
+ *
+ * See the description of psa_generate_key() for the operation of this
+ * function with the default production parameters. In addition, this function
+ * supports the following production customizations, described in more detail
+ * in the documentation of ::psa_key_production_parameters_t:
+ *
+ * - RSA keys: generation with a custom public exponent.
+ *
+ * \note This function is experimental and may change in future minor
+ *       versions of Mbed TLS.
+ *
+ * \param[in] attributes    The attributes for the new key.
+ * \param[in] params        Customization parameters for the key generation.
+ *                          When this is #PSA_KEY_PRODUCTION_PARAMETERS_INIT
+ *                          with \p params_data_length = 0,
+ *                          this function is equivalent to
+ *                          psa_generate_key().
+ * \param params_data_length
+ *                          Length of `params->data` in bytes.
+ * \param[out] key          On success, an identifier for the newly created
+ *                          key. For persistent keys, this is the key
+ *                          identifier defined in \p attributes.
+ *                          \c 0 on failure.
+ *
+ * \retval #PSA_SUCCESS
+ *         Success.
+ *         If the key is persistent, the key material and the key's metadata
+ *         have been saved to persistent storage.
+ * \retval #PSA_ERROR_ALREADY_EXISTS
+ *         This is an attempt to create a persistent key, and there is
+ *         already a persistent key with the given identifier.
+ * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription
+ * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
+ * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY \emptydescription
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
+ * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ * \retval #PSA_ERROR_INSUFFICIENT_STORAGE \emptydescription
+ * \retval #PSA_ERROR_DATA_INVALID \emptydescription
+ * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription
+ * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The library has not been previously initialized by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_generate_key_ext(const psa_key_attributes_t *attributes,
+                                  const psa_key_production_parameters_t *params,
+                                  size_t params_data_length,
+                                  mbedtls_svc_key_id_t *key);
+
 /**@}*/
 
 /** \defgroup interruptible_hash Interruptible sign/verify hash
diff --git a/include/psa/crypto_compat.h b/include/psa/crypto_compat.h
index f896fae..2a226c0 100644
--- a/include/psa/crypto_compat.h
+++ b/include/psa/crypto_compat.h
@@ -146,6 +146,83 @@
  */
 psa_status_t psa_close_key(psa_key_handle_t handle);
 
+/** \addtogroup attributes
+ * @{
+ */
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+/** Custom Diffie-Hellman group.
+ *
+ * Mbed TLS does not support custom DH groups.
+ *
+ * \deprecated This value is not useful, so this macro will be removed in
+ *             a future version of the library.
+ */
+#define PSA_DH_FAMILY_CUSTOM                                            \
+    ((psa_dh_family_t) MBEDTLS_DEPRECATED_NUMERIC_CONSTANT(0x7e))
+
+/**
+ * \brief Set domain parameters for a key.
+ *
+ * \deprecated  Mbed TLS no longer supports any domain parameters.
+ *              This function only does the equivalent of
+ *              psa_set_key_type() and will be removed in a future version
+ *              of the library.
+ *
+ * \param[in,out] attributes    Attribute structure where \p type will be set.
+ * \param type                  Key type (a \c PSA_KEY_TYPE_XXX value).
+ * \param[in] data              Ignored.
+ * \param data_length           Must be 0.
+ *
+ * \retval #PSA_SUCCESS \emptydescription
+ * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription
+ */
+static inline psa_status_t MBEDTLS_DEPRECATED psa_set_key_domain_parameters(
+    psa_key_attributes_t *attributes,
+    psa_key_type_t type, const uint8_t *data, size_t data_length)
+{
+    (void) data;
+    if (data_length != 0) {
+        return PSA_ERROR_NOT_SUPPORTED;
+    }
+    psa_set_key_type(attributes, type);
+    return PSA_SUCCESS;
+}
+
+/**
+ * \brief Get domain parameters for a key.
+ *
+ * \deprecated  Mbed TLS no longer supports any domain parameters.
+ *              This function alwaya has an empty output and will be
+ *              removed in a future version of the library.
+
+ * \param[in] attributes        Ignored.
+ * \param[out] data             Ignored.
+ * \param data_size             Ignored.
+ * \param[out] data_length      Set to 0.
+ *
+ * \retval #PSA_SUCCESS \emptydescription
+ */
+static inline psa_status_t MBEDTLS_DEPRECATED psa_get_key_domain_parameters(
+    const psa_key_attributes_t *attributes,
+    uint8_t *data, size_t data_size, size_t *data_length)
+{
+    (void) attributes;
+    (void) data;
+    (void) data_size;
+    *data_length = 0;
+    return PSA_SUCCESS;
+}
+
+/** Safe output buffer size for psa_get_key_domain_parameters().
+ *
+ */
+#define PSA_KEY_DOMAIN_PARAMETERS_SIZE(key_type, key_bits)      \
+    MBEDTLS_DEPRECATED_NUMERIC_CONSTANT(1u)
+#endif /* MBEDTLS_DEPRECATED_REMOVED */
+
+/**@}*/
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h
index 10a23f6..6ed1f6c 100644
--- a/include/psa/crypto_extra.h
+++ b/include/psa/crypto_extra.h
@@ -59,7 +59,7 @@
     psa_key_attributes_t *attributes,
     psa_algorithm_t alg2)
 {
-    attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(policy).MBEDTLS_PRIVATE(alg2) = alg2;
+    attributes->MBEDTLS_PRIVATE(policy).MBEDTLS_PRIVATE(alg2) = alg2;
 }
 
 /** Retrieve the enrollment algorithm policy from key attributes.
@@ -71,7 +71,7 @@
 static inline psa_algorithm_t psa_get_key_enrollment_algorithm(
     const psa_key_attributes_t *attributes)
 {
-    return attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(policy).MBEDTLS_PRIVATE(alg2);
+    return attributes->MBEDTLS_PRIVATE(policy).MBEDTLS_PRIVATE(alg2);
 }
 
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
@@ -129,7 +129,7 @@
     psa_key_attributes_t *attributes,
     psa_key_slot_number_t slot_number)
 {
-    attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(flags) |= MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER;
+    attributes->MBEDTLS_PRIVATE(has_slot_number) = 1;
     attributes->MBEDTLS_PRIVATE(slot_number) = slot_number;
 }
 
@@ -142,8 +142,7 @@
 static inline void psa_clear_key_slot_number(
     psa_key_attributes_t *attributes)
 {
-    attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(flags) &=
-        ~MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER;
+    attributes->MBEDTLS_PRIVATE(has_slot_number) = 0;
 }
 
 /** Register a key that is already present in a secure element.
@@ -409,140 +408,11 @@
  * @{
  */
 
-/** Custom Diffie-Hellman group.
- *
- * For keys of type #PSA_KEY_TYPE_DH_PUBLIC_KEY(#PSA_DH_FAMILY_CUSTOM) or
- * #PSA_KEY_TYPE_DH_KEY_PAIR(#PSA_DH_FAMILY_CUSTOM), the group data comes
- * from domain parameters set by psa_set_key_domain_parameters().
- */
-#define PSA_DH_FAMILY_CUSTOM             ((psa_dh_family_t) 0x7e)
-
 /** PAKE operation stages. */
 #define PSA_PAKE_OPERATION_STAGE_SETUP 0
 #define PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS 1
 #define PSA_PAKE_OPERATION_STAGE_COMPUTATION 2
 
-/**
- * \brief Set domain parameters for a key.
- *
- * Some key types require additional domain parameters in addition to
- * the key type identifier and the key size. Use this function instead
- * of psa_set_key_type() when you need to specify domain parameters.
- *
- * The format for the required domain parameters varies based on the key type.
- * Mbed TLS supports the following key type with domain parameters:
- *
- * - For RSA keys (#PSA_KEY_TYPE_RSA_PUBLIC_KEY or #PSA_KEY_TYPE_RSA_KEY_PAIR),
- *   the domain parameter data consists of the public exponent,
- *   represented as a big-endian integer with no leading zeros.
- *   This information is used when generating an RSA key pair.
- *   When importing a key, the public exponent is read from the imported
- *   key data and the exponent recorded in the attribute structure is ignored.
- *   As an exception, the public exponent 65537 is represented by an empty
- *   byte string.
- *
- * \note This function may allocate memory or other resources.
- *       Once you have called this function on an attribute structure,
- *       you must call psa_reset_key_attributes() to free these resources.
- *
- * \note This is an experimental extension to the interface. It may change
- *       in future versions of the library.
- *
- * \note Due to an implementation limitation, domain parameters are ignored
- *       for keys that are managed by a driver.
- *
- * \param[in,out] attributes    Attribute structure where the specified domain
- *                              parameters will be stored.
- *                              If this function fails, the content of
- *                              \p attributes is not modified.
- * \param type                  Key type (a \c PSA_KEY_TYPE_XXX value).
- * \param[in] data              Buffer containing the key domain parameters.
- *                              The content of this buffer is interpreted
- *                              according to \p type as described above.
- * \param data_length           Size of the \p data buffer in bytes.
- *
- * \retval #PSA_SUCCESS \emptydescription
- * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription
- * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription
- * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
- */
-#if !defined(PSA_SET_KEY_DOMAIN_PARAMETERS)
-#define PSA_SET_KEY_DOMAIN_PARAMETERS
-psa_status_t psa_set_key_domain_parameters(psa_key_attributes_t *attributes,
-                                           psa_key_type_t type,
-                                           const uint8_t *data,
-                                           size_t data_length);
-#endif /* PSA_SET_KEY_DOMAIN_PARAMETERS */
-
-/**
- * \brief Get domain parameters for a key.
- *
- * Get the domain parameters for a key with this function, if any. The format
- * of the domain parameters written to \p data is specified in the
- * documentation for psa_set_key_domain_parameters().
- *
- * \note This is an experimental extension to the interface. It may change
- *       in future versions of the library.
- *
- * \note Due to an implementation limitation, domain parameters are not
- *       supported with keys that are managed by a driver.
- *
- * \param[in] attributes        The key attribute structure to query.
- * \param[out] data             On success, the key domain parameters.
- * \param data_size             Size of the \p data buffer in bytes.
- *                              The buffer is guaranteed to be large
- *                              enough if its size in bytes is at least
- *                              the value given by
- *                              PSA_KEY_DOMAIN_PARAMETERS_SIZE().
- * \param[out] data_length      On success, the number of bytes
- *                              that make up the key domain parameters data.
- *
- * \retval #PSA_SUCCESS \emptydescription
- * \retval #PSA_ERROR_BUFFER_TOO_SMALL \emptydescription
- * \retval #PSA_ERROR_NOT_SUPPORTED
- *         The key is managed by a driver.
- */
-psa_status_t psa_get_key_domain_parameters(
-    const psa_key_attributes_t *attributes,
-    uint8_t *data,
-    size_t data_size,
-    size_t *data_length);
-
-/** Safe output buffer size for psa_get_key_domain_parameters().
- *
- * This macro returns a compile-time constant if its arguments are
- * compile-time constants.
- *
- * \warning This function may call its arguments multiple times or
- *          zero times, so you should not pass arguments that contain
- *          side effects.
- *
- * \note This is an experimental extension to the interface. It may change
- *       in future versions of the library.
- *
- * \param key_type  A supported key type.
- * \param key_bits  The size of the key in bits.
- *
- * \return If the parameters are valid and supported, return
- *         a buffer size in bytes that guarantees that
- *         psa_get_key_domain_parameters() will not fail with
- *         #PSA_ERROR_BUFFER_TOO_SMALL.
- *         If the parameters are a valid combination that is not supported
- *         by the implementation, this macro shall return either a
- *         sensible size or 0.
- *         If the parameters are not valid, the
- *         return value is unspecified.
- */
-#define PSA_KEY_DOMAIN_PARAMETERS_SIZE(key_type, key_bits)              \
-    (PSA_KEY_TYPE_IS_RSA(key_type) ? sizeof(int) :                      \
-     PSA_KEY_TYPE_IS_DH(key_type) ? PSA_DH_KEY_DOMAIN_PARAMETERS_SIZE(key_bits) : \
-     PSA_KEY_TYPE_IS_DSA(key_type) ? PSA_DSA_KEY_DOMAIN_PARAMETERS_SIZE(key_bits) : \
-     0)
-#define PSA_DH_KEY_DOMAIN_PARAMETERS_SIZE(key_bits)     \
-    (4 + (PSA_BITS_TO_BYTES(key_bits) + 5) * 3 /*without optional parts*/)
-#define PSA_DSA_KEY_DOMAIN_PARAMETERS_SIZE(key_bits)    \
-    (4 + (PSA_BITS_TO_BYTES(key_bits) + 5) * 2 /*p, g*/ + 34 /*q*/)
-
 /**@}*/
 
 
diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h
index 34d072b..3913551 100644
--- a/include/psa/crypto_struct.h
+++ b/include/psa/crypto_struct.h
@@ -223,6 +223,22 @@
     return v;
 }
 
+struct psa_key_production_parameters_s {
+    /* Future versions may add other fields in this structure. */
+    uint32_t flags;
+    uint8_t data[];
+};
+
+/** The default production parameters for key generation or key derivation.
+ *
+ * Calling psa_generate_key_ext() or psa_key_derivation_output_key_ext()
+ * with `params=PSA_KEY_PRODUCTION_PARAMETERS_INIT` and
+ * `params_data_length == 0` is equivalent to
+ * calling psa_generate_key() or psa_key_derivation_output_key()
+ * respectively.
+ */
+#define PSA_KEY_PRODUCTION_PARAMETERS_INIT { 0 }
+
 struct psa_key_policy_s {
     psa_key_usage_t MBEDTLS_PRIVATE(usage);
     psa_algorithm_t MBEDTLS_PRIVATE(alg);
@@ -250,35 +266,15 @@
  * conditionals. */
 #define PSA_MAX_KEY_BITS 0xfff8
 
-/** A mask of flags that can be stored in key attributes.
- *
- * This type is also used internally to store flags in slots. Internal
- * flags are defined in library/psa_crypto_core.h. Internal flags may have
- * the same value as external flags if they are properly handled during
- * key creation and in psa_get_key_attributes.
- */
-typedef uint16_t psa_key_attributes_flag_t;
-
-#define MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER     \
-    ((psa_key_attributes_flag_t) 0x0001)
-
-/* A mask of key attribute flags used externally only.
- * Only meant for internal checks inside the library. */
-#define MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY (      \
-        MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER |    \
-        0)
-
-/* A mask of key attribute flags used both internally and externally.
- * Currently there aren't any. */
-#define MBEDTLS_PSA_KA_MASK_DUAL_USE (          \
-        0)
-
-typedef struct {
+struct psa_key_attributes_s {
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+    psa_key_slot_number_t MBEDTLS_PRIVATE(slot_number);
+    int MBEDTLS_PRIVATE(has_slot_number);
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
     psa_key_type_t MBEDTLS_PRIVATE(type);
     psa_key_bits_t MBEDTLS_PRIVATE(bits);
     psa_key_lifetime_t MBEDTLS_PRIVATE(lifetime);
     psa_key_policy_t MBEDTLS_PRIVATE(policy);
-    psa_key_attributes_flag_t MBEDTLS_PRIVATE(flags);
     /* This type has a different layout in the client view wrt the
      * service view of the key id, i.e. in service view usually is
      * expected to have MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER defined
@@ -291,45 +287,18 @@
      * struct
      */
     mbedtls_svc_key_id_t MBEDTLS_PRIVATE(id);
-} psa_core_key_attributes_t;
-
-#define PSA_CORE_KEY_ATTRIBUTES_INIT { PSA_KEY_TYPE_NONE, 0,            \
-                                       PSA_KEY_LIFETIME_VOLATILE,       \
-                                       PSA_KEY_POLICY_INIT, 0,          \
-                                       MBEDTLS_SVC_KEY_ID_INIT }
-
-struct psa_key_attributes_s {
-#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
-    psa_key_slot_number_t MBEDTLS_PRIVATE(slot_number);
-#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
-    /* Unlike normal buffers, there are three cases for domain_parameters
-     * and domain_parameters_size:
-     * - domain_parameters_size == SIZE_MAX && domain_parameters == NULL:
-     *   Access to domain parameters is not supported for this key.
-     *   This is a hack which should not exist, intended for keys managed
-     *   by a driver, because drivers don't support domain parameters.
-     * - domain_parameters_size == 0 && domain_parameters == NULL:
-     *   The domain parameters are empty.
-     * - domain_parameters_size > 0 &&
-     *   domain_parameters == valid pointer to domain_parameters_size bytes:
-     *   The domain parameters are non-empty.
-     */
-    void *MBEDTLS_PRIVATE(domain_parameters);
-    size_t MBEDTLS_PRIVATE(domain_parameters_size);
-    /* With client/service separation, struct psa_key_attributes_s is
-     * marshalled through a transport channel between the client and
-     * service side implementation of the PSA Crypto APIs, thus having
-     * the mbedtls_svc_key_id_t id as the last field of this structure
-     * allows for a more efficient marshalling/unmarshalling of parameters
-     */
-    psa_core_key_attributes_t MBEDTLS_PRIVATE(core);
 };
 
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
-#define PSA_KEY_ATTRIBUTES_INIT { 0, NULL, 0, PSA_CORE_KEY_ATTRIBUTES_INIT }
+#define PSA_KEY_ATTRIBUTES_MAYBE_SLOT_NUMBER 0, 0,
 #else
-#define PSA_KEY_ATTRIBUTES_INIT { NULL, 0, PSA_CORE_KEY_ATTRIBUTES_INIT }
+#define PSA_KEY_ATTRIBUTES_MAYBE_SLOT_NUMBER
 #endif
+#define PSA_KEY_ATTRIBUTES_INIT { PSA_KEY_ATTRIBUTES_MAYBE_SLOT_NUMBER \
+                                      PSA_KEY_TYPE_NONE, 0,            \
+                                      PSA_KEY_LIFETIME_VOLATILE,       \
+                                      PSA_KEY_POLICY_INIT,             \
+                                      MBEDTLS_SVC_KEY_ID_INIT }
 
 static inline struct psa_key_attributes_s psa_key_attributes_init(void)
 {
@@ -340,12 +309,12 @@
 static inline void psa_set_key_id(psa_key_attributes_t *attributes,
                                   mbedtls_svc_key_id_t key)
 {
-    psa_key_lifetime_t lifetime = attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(lifetime);
+    psa_key_lifetime_t lifetime = attributes->MBEDTLS_PRIVATE(lifetime);
 
-    attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(id) = key;
+    attributes->MBEDTLS_PRIVATE(id) = key;
 
     if (PSA_KEY_LIFETIME_IS_VOLATILE(lifetime)) {
-        attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(lifetime) =
+        attributes->MBEDTLS_PRIVATE(lifetime) =
             PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
                 PSA_KEY_LIFETIME_PERSISTENT,
                 PSA_KEY_LIFETIME_GET_LOCATION(lifetime));
@@ -355,26 +324,26 @@
 static inline mbedtls_svc_key_id_t psa_get_key_id(
     const psa_key_attributes_t *attributes)
 {
-    return attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(id);
+    return attributes->MBEDTLS_PRIVATE(id);
 }
 
 #ifdef MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
 static inline void mbedtls_set_key_owner_id(psa_key_attributes_t *attributes,
                                             mbedtls_key_owner_id_t owner)
 {
-    attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(id).MBEDTLS_PRIVATE(owner) = owner;
+    attributes->MBEDTLS_PRIVATE(id).MBEDTLS_PRIVATE(owner) = owner;
 }
 #endif
 
 static inline void psa_set_key_lifetime(psa_key_attributes_t *attributes,
                                         psa_key_lifetime_t lifetime)
 {
-    attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(lifetime) = lifetime;
+    attributes->MBEDTLS_PRIVATE(lifetime) = lifetime;
     if (PSA_KEY_LIFETIME_IS_VOLATILE(lifetime)) {
 #ifdef MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
-        attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(id).MBEDTLS_PRIVATE(key_id) = 0;
+        attributes->MBEDTLS_PRIVATE(id).MBEDTLS_PRIVATE(key_id) = 0;
 #else
-        attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(id) = 0;
+        attributes->MBEDTLS_PRIVATE(id) = 0;
 #endif
     }
 }
@@ -382,7 +351,7 @@
 static inline psa_key_lifetime_t psa_get_key_lifetime(
     const psa_key_attributes_t *attributes)
 {
-    return attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(lifetime);
+    return attributes->MBEDTLS_PRIVATE(lifetime);
 }
 
 static inline void psa_extend_key_usage_flags(psa_key_usage_t *usage_flags)
@@ -400,72 +369,53 @@
                                            psa_key_usage_t usage_flags)
 {
     psa_extend_key_usage_flags(&usage_flags);
-    attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(policy).MBEDTLS_PRIVATE(usage) = usage_flags;
+    attributes->MBEDTLS_PRIVATE(policy).MBEDTLS_PRIVATE(usage) = usage_flags;
 }
 
 static inline psa_key_usage_t psa_get_key_usage_flags(
     const psa_key_attributes_t *attributes)
 {
-    return attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(policy).MBEDTLS_PRIVATE(usage);
+    return attributes->MBEDTLS_PRIVATE(policy).MBEDTLS_PRIVATE(usage);
 }
 
 static inline void psa_set_key_algorithm(psa_key_attributes_t *attributes,
                                          psa_algorithm_t alg)
 {
-    attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(policy).MBEDTLS_PRIVATE(alg) = alg;
+    attributes->MBEDTLS_PRIVATE(policy).MBEDTLS_PRIVATE(alg) = alg;
 }
 
 static inline psa_algorithm_t psa_get_key_algorithm(
     const psa_key_attributes_t *attributes)
 {
-    return attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(policy).MBEDTLS_PRIVATE(alg);
+    return attributes->MBEDTLS_PRIVATE(policy).MBEDTLS_PRIVATE(alg);
 }
 
-/* This function is declared in crypto_extra.h, which comes after this
- * header file, but we need the function here, so repeat the declaration. */
-#if !defined(PSA_SET_KEY_DOMAIN_PARAMETERS)
-#define PSA_SET_KEY_DOMAIN_PARAMETERS
-psa_status_t psa_set_key_domain_parameters(psa_key_attributes_t *attributes,
-                                           psa_key_type_t type,
-                                           const uint8_t *data,
-                                           size_t data_length);
-#endif /* PSA_SET_KEY_DOMAIN_PARAMETERS */
-
 static inline void psa_set_key_type(psa_key_attributes_t *attributes,
                                     psa_key_type_t type)
 {
-    if (attributes->MBEDTLS_PRIVATE(domain_parameters) == NULL) {
-        /* Common case: quick path */
-        attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(type) = type;
-    } else {
-        /* Call the bigger function to free the old domain parameters.
-         * Ignore any errors which may arise due to type requiring
-         * non-default domain parameters, since this function can't
-         * report errors. */
-        (void) psa_set_key_domain_parameters(attributes, type, NULL, 0);
-    }
+    attributes->MBEDTLS_PRIVATE(type) = type;
 }
 
 static inline psa_key_type_t psa_get_key_type(
     const psa_key_attributes_t *attributes)
 {
-    return attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(type);
+    return attributes->MBEDTLS_PRIVATE(type);
 }
 
 static inline void psa_set_key_bits(psa_key_attributes_t *attributes,
                                     size_t bits)
 {
     if (bits > PSA_MAX_KEY_BITS) {
-        attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(bits) = PSA_KEY_BITS_TOO_LARGE;
+        attributes->MBEDTLS_PRIVATE(bits) = PSA_KEY_BITS_TOO_LARGE;
     } else {
-        attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(bits) = (psa_key_bits_t) bits;
+        attributes->MBEDTLS_PRIVATE(bits) = (psa_key_bits_t) bits;
     }
 }
 
 static inline size_t psa_get_key_bits(
     const psa_key_attributes_t *attributes)
 {
-    return attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(bits);
+    return attributes->MBEDTLS_PRIVATE(bits);
 }
 
 /**
diff --git a/include/psa/crypto_types.h b/include/psa/crypto_types.h
index e2ebd8a..31ea686 100644
--- a/include/psa/crypto_types.h
+++ b/include/psa/crypto_types.h
@@ -455,6 +455,30 @@
  */
 typedef uint16_t psa_key_derivation_step_t;
 
+/** \brief Custom parameters for key generation or key derivation.
+ *
+ * This is a structure type with at least the following fields:
+ *
+ * - \c flags: an unsigned integer type. 0 for the default production parameters.
+ * - \c data: a flexible array of bytes.
+ *
+ * The interpretation of this structure depend on the type of the
+ * created key.
+ *
+ * - #PSA_KEY_TYPE_RSA_KEY_PAIR:
+ *     - \c flags: must be 0.
+ *     - \c data: the public exponent, in little-endian order.
+ *       This must be an odd integer and must not be 1.
+ *       Implementations must support 65535, should support 3 and may
+ *       support other values.
+ *       When not using a driver, Mbed TLS supports values up to \c INT_MAX.
+ *       If this is empty or if the custom production parameters are omitted
+ *       altogether, the default value 65537 is used.
+ * - Other key types: reserved for future use. \c flags must be 0.
+ *
+ */
+typedef struct psa_key_production_parameters_s psa_key_production_parameters_t;
+
 /**@}*/
 
 #endif /* PSA_CRYPTO_TYPES_H */
diff --git a/include/psa/crypto_values.h b/include/psa/crypto_values.h
index f311acb..1d678db 100644
--- a/include/psa/crypto_values.h
+++ b/include/psa/crypto_values.h
@@ -413,7 +413,7 @@
     ((type) | PSA_KEY_TYPE_CATEGORY_FLAG_PAIR)
 /** The public key type corresponding to a key pair type.
  *
- * You may also pass a key pair type as \p type, it will be left unchanged.
+ * You may also pass a public key type as \p type, it will be left unchanged.
  *
  * \param type      A public key type or key pair type.
  *
diff --git a/library/aesce.c b/library/aesce.c
index eaaa5b5..6a9e0a1 100644
--- a/library/aesce.c
+++ b/library/aesce.c
@@ -334,7 +334,7 @@
      *   - Section 5, Nr = Nk + 6
      *   - Section 5.2, the length of round keys is Nb*(Nr+1)
      */
-    const uint32_t key_len_in_words = key_bit_length / 32;  /* Nk */
+    const size_t key_len_in_words = key_bit_length / 32;    /* Nk */
     const size_t round_key_len_in_words = 4;                /* Nb */
     const size_t rounds_needed = key_len_in_words + 6;      /* Nr */
     const size_t round_keys_len_in_words =
diff --git a/library/bignum.c b/library/bignum.c
index d3d72ab..c45fd5b 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -37,6 +37,19 @@
 
 #include "mbedtls/platform.h"
 
+
+
+/*
+ * Conditionally select an MPI sign in constant time.
+ * (MPI sign is the field s in mbedtls_mpi. It is unsigned short and only 1 and -1 are valid
+ * values.)
+ */
+static inline signed short mbedtls_ct_mpi_sign_if(mbedtls_ct_condition_t cond,
+                                                  signed short sign1, signed short sign2)
+{
+    return (signed short) mbedtls_ct_uint_if(cond, sign1 + 1, sign2 + 1) - 1;
+}
+
 /*
  * Compare signed values in constant time
  */
@@ -112,7 +125,7 @@
     {
         mbedtls_ct_condition_t do_assign = mbedtls_ct_bool(assign);
 
-        X->s = (int) mbedtls_ct_uint_if(do_assign, Y->s, X->s);
+        X->s = mbedtls_ct_mpi_sign_if(do_assign, Y->s, X->s);
 
         mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, do_assign);
 
@@ -149,8 +162,8 @@
     MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n));
 
     s = X->s;
-    X->s = (int) mbedtls_ct_uint_if(do_swap, Y->s, X->s);
-    Y->s = (int) mbedtls_ct_uint_if(do_swap, s, Y->s);
+    X->s = mbedtls_ct_mpi_sign_if(do_swap, Y->s, X->s);
+    Y->s = mbedtls_ct_mpi_sign_if(do_swap, s, Y->s);
 
     mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, do_swap);
 
@@ -288,8 +301,7 @@
  * This function is not constant-time. Leading zeros in Y may be removed.
  *
  * Ensure that X does not shrink. This is not guaranteed by the public API,
- * but some code in the bignum module relies on this property, for example
- * in mbedtls_mpi_exp_mod().
+ * but some code in the bignum module might still rely on this property.
  */
 int mbedtls_mpi_copy(mbedtls_mpi *X, const mbedtls_mpi *Y)
 {
@@ -1598,98 +1610,11 @@
     return 0;
 }
 
-static void mpi_montg_init(mbedtls_mpi_uint *mm, const mbedtls_mpi *N)
-{
-    *mm = mbedtls_mpi_core_montmul_init(N->p);
-}
-
-/** Montgomery multiplication: A = A * B * R^-1 mod N  (HAC 14.36)
- *
- * \param[in,out]   A   One of the numbers to multiply.
- *                      It must have at least as many limbs as N
- *                      (A->n >= N->n), and any limbs beyond n are ignored.
- *                      On successful completion, A contains the result of
- *                      the multiplication A * B * R^-1 mod N where
- *                      R = (2^ciL)^n.
- * \param[in]       B   One of the numbers to multiply.
- *                      It must be nonzero and must not have more limbs than N
- *                      (B->n <= N->n).
- * \param[in]       N   The modulus. \p N must be odd.
- * \param           mm  The value calculated by `mpi_montg_init(&mm, N)`.
- *                      This is -N^-1 mod 2^ciL.
- * \param[in,out]   T   A bignum for temporary storage.
- *                      It must be at least twice the limb size of N plus 1
- *                      (T->n >= 2 * N->n + 1).
- *                      Its initial content is unused and
- *                      its final content is indeterminate.
- *                      It does not get reallocated.
- */
-static void mpi_montmul(mbedtls_mpi *A, const mbedtls_mpi *B,
-                        const mbedtls_mpi *N, mbedtls_mpi_uint mm,
-                        mbedtls_mpi *T)
-{
-    mbedtls_mpi_core_montmul(A->p, A->p, B->p, B->n, N->p, N->n, mm, T->p);
-}
-
-/*
- * Montgomery reduction: A = A * R^-1 mod N
- *
- * See mpi_montmul() regarding constraints and guarantees on the parameters.
- */
-static void mpi_montred(mbedtls_mpi *A, const mbedtls_mpi *N,
-                        mbedtls_mpi_uint mm, mbedtls_mpi *T)
-{
-    mbedtls_mpi_uint z = 1;
-    mbedtls_mpi U;
-    U.n = 1;
-    U.s = 1;
-    U.p = &z;
-
-    mpi_montmul(A, &U, N, mm, T);
-}
-
-/**
- * Select an MPI from a table without leaking the index.
- *
- * This is functionally equivalent to mbedtls_mpi_copy(R, T[idx]) except it
- * reads the entire table in order to avoid leaking the value of idx to an
- * attacker able to observe memory access patterns.
- *
- * \param[out] R        Where to write the selected MPI.
- * \param[in] T         The table to read from.
- * \param[in] T_size    The number of elements in the table.
- * \param[in] idx       The index of the element to select;
- *                      this must satisfy 0 <= idx < T_size.
- *
- * \return \c 0 on success, or a negative error code.
- */
-static int mpi_select(mbedtls_mpi *R, const mbedtls_mpi *T, size_t T_size, size_t idx)
-{
-    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-
-    for (size_t i = 0; i < T_size; i++) {
-        MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(R, &T[i],
-                                                     (unsigned char) mbedtls_ct_uint_eq(i, idx)));
-    }
-cleanup:
-    return ret;
-}
-
-/*
- * Sliding-window exponentiation: X = A^E mod N  (HAC 14.85)
- */
 int mbedtls_mpi_exp_mod(mbedtls_mpi *X, const mbedtls_mpi *A,
                         const mbedtls_mpi *E, const mbedtls_mpi *N,
                         mbedtls_mpi *prec_RR)
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    size_t window_bitsize;
-    size_t i, j, nblimbs;
-    size_t bufsize, nbits;
-    size_t exponent_bits_in_window = 0;
-    mbedtls_mpi_uint ei, mm, state;
-    mbedtls_mpi RR, T, W[(size_t) 1 << MBEDTLS_MPI_WINDOW_SIZE], WW, Apos;
-    int neg;
 
     if (mbedtls_mpi_cmp_int(N, 0) <= 0 || (N->p[0] & 1) == 0) {
         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
@@ -1705,261 +1630,88 @@
     }
 
     /*
-     * Init temps and window size
+     * Ensure that the exponent that we are passing to the core is not NULL.
      */
-    mpi_montg_init(&mm, N);
-    mbedtls_mpi_init(&RR); mbedtls_mpi_init(&T);
-    mbedtls_mpi_init(&Apos);
-    mbedtls_mpi_init(&WW);
-    memset(W, 0, sizeof(W));
-
-    i = mbedtls_mpi_bitlen(E);
-
-    window_bitsize = (i > 671) ? 6 : (i > 239) ? 5 :
-                     (i >  79) ? 4 : (i >  23) ? 3 : 1;
-
-#if (MBEDTLS_MPI_WINDOW_SIZE < 6)
-    if (window_bitsize > MBEDTLS_MPI_WINDOW_SIZE) {
-        window_bitsize = MBEDTLS_MPI_WINDOW_SIZE;
+    if (E->n == 0) {
+        ret = mbedtls_mpi_lset(X, 1);
+        return ret;
     }
-#endif
-
-    const size_t w_table_used_size = (size_t) 1 << window_bitsize;
 
     /*
-     * This function is not constant-trace: its memory accesses depend on the
-     * exponent value. To defend against timing attacks, callers (such as RSA
-     * and DHM) should use exponent blinding. However this is not enough if the
-     * adversary can find the exponent in a single trace, so this function
-     * takes extra precautions against adversaries who can observe memory
-     * access patterns.
-     *
-     * This function performs a series of multiplications by table elements and
-     * squarings, and we want the prevent the adversary from finding out which
-     * table element was used, and from distinguishing between multiplications
-     * and squarings. Firstly, when multiplying by an element of the window
-     * W[i], we do a constant-trace table lookup to obfuscate i. This leaves
-     * squarings as having a different memory access patterns from other
-     * multiplications. So secondly, we put the accumulator in the table as
-     * well, and also do a constant-trace table lookup to multiply by the
-     * accumulator which is W[x_index].
-     *
-     * This way, all multiplications take the form of a lookup-and-multiply.
-     * The number of lookup-and-multiply operations inside each iteration of
-     * the main loop still depends on the bits of the exponent, but since the
-     * other operations in the loop don't have an easily recognizable memory
-     * trace, an adversary is unlikely to be able to observe the exact
-     * patterns.
-     *
-     * An adversary may still be able to recover the exponent if they can
-     * observe both memory accesses and branches. However, branch prediction
-     * exploitation typically requires many traces of execution over the same
-     * data, which is defeated by randomized blinding.
+     * Allocate working memory for mbedtls_mpi_core_exp_mod()
      */
-    const size_t x_index = 0;
-    mbedtls_mpi_init(&W[x_index]);
-
-    j = N->n + 1;
-    /* All W[i] including the accumulator must have at least N->n limbs for
-     * the mpi_montmul() and mpi_montred() calls later. Here we ensure that
-     * W[1] and the accumulator W[x_index] are large enough. later we'll grow
-     * other W[i] to the same length. They must not be shrunk midway through
-     * this function!
-     */
-    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[x_index], j));
-    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[1],  j));
-    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&T, j * 2));
-
-    /*
-     * Compensate for negative A (and correct at the end)
-     */
-    neg = (A->s == -1);
-    if (neg) {
-        MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Apos, A));
-        Apos.s = 1;
-        A = &Apos;
+    size_t T_limbs = mbedtls_mpi_core_exp_mod_working_limbs(N->n, E->n);
+    mbedtls_mpi_uint *T = (mbedtls_mpi_uint *) mbedtls_calloc(T_limbs, sizeof(mbedtls_mpi_uint));
+    if (T == NULL) {
+        return MBEDTLS_ERR_MPI_ALLOC_FAILED;
     }
 
+    mbedtls_mpi RR;
+    mbedtls_mpi_init(&RR);
+
     /*
      * If 1st call, pre-compute R^2 mod N
      */
     if (prec_RR == NULL || prec_RR->p == NULL) {
-        MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&RR, 1));
-        MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&RR, N->n * 2 * biL));
-        MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&RR, &RR, N));
+        MBEDTLS_MPI_CHK(mbedtls_mpi_core_get_mont_r2_unsafe(&RR, N));
 
         if (prec_RR != NULL) {
-            memcpy(prec_RR, &RR, sizeof(mbedtls_mpi));
+            *prec_RR = RR;
         }
     } else {
-        memcpy(&RR, prec_RR, sizeof(mbedtls_mpi));
+        MBEDTLS_MPI_CHK(mbedtls_mpi_grow(prec_RR, N->n));
+        RR = *prec_RR;
     }
 
     /*
-     * W[1] = A * R^2 * R^-1 mod N = A * R mod N
+     * To preserve constness we need to make a copy of A. Using X for this to
+     * save memory.
      */
-    if (mbedtls_mpi_cmp_mpi(A, N) >= 0) {
-        MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&W[1], A, N));
-        /* This should be a no-op because W[1] is already that large before
-         * mbedtls_mpi_mod_mpi(), but it's necessary to avoid an overflow
-         * in mpi_montmul() below, so let's make sure. */
-        MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[1], N->n + 1));
-    } else {
-        MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&W[1], A));
-    }
-
-    /* Note that this is safe because W[1] always has at least N->n limbs
-     * (it grew above and was preserved by mbedtls_mpi_copy()). */
-    mpi_montmul(&W[1], &RR, N, mm, &T);
+    MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
 
     /*
-     * W[x_index] = R^2 * R^-1 mod N = R mod N
+     * Compensate for negative A (and correct at the end).
      */
-    MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&W[x_index], &RR));
-    mpi_montred(&W[x_index], N, mm, &T);
+    X->s = 1;
 
-
-    if (window_bitsize > 1) {
-        /*
-         * W[i] = W[1] ^ i
-         *
-         * The first bit of the sliding window is always 1 and therefore we
-         * only need to store the second half of the table.
-         *
-         * (There are two special elements in the table: W[0] for the
-         * accumulator/result and W[1] for A in Montgomery form. Both of these
-         * are already set at this point.)
-         */
-        j = w_table_used_size / 2;
-
-        MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[j], N->n + 1));
-        MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&W[j], &W[1]));
-
-        for (i = 0; i < window_bitsize - 1; i++) {
-            mpi_montmul(&W[j], &W[j], N, mm, &T);
-        }
-
-        /*
-         * W[i] = W[i - 1] * W[1]
-         */
-        for (i = j + 1; i < w_table_used_size; i++) {
-            MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[i], N->n + 1));
-            MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&W[i], &W[i - 1]));
-
-            mpi_montmul(&W[i], &W[1], N, mm, &T);
-        }
+    /*
+     * Make sure that X is in a form that is safe for consumption by
+     * the core functions.
+     *
+     * - The core functions will not touch the limbs of X above N->n. The
+     *   result will be correct if those limbs are 0, which the mod call
+     *   ensures.
+     * - Also, X must have at least as many limbs as N for the calls to the
+     *   core functions.
+     */
+    if (mbedtls_mpi_cmp_mpi(X, N) >= 0) {
+        MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(X, X, N));
     }
+    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, N->n));
 
-    nblimbs = E->n;
-    bufsize = 0;
-    nbits   = 0;
-    state   = 0;
-
-    while (1) {
-        if (bufsize == 0) {
-            if (nblimbs == 0) {
-                break;
-            }
-
-            nblimbs--;
-
-            bufsize = sizeof(mbedtls_mpi_uint) << 3;
-        }
-
-        bufsize--;
-
-        ei = (E->p[nblimbs] >> bufsize) & 1;
-
-        /*
-         * skip leading 0s
-         */
-        if (ei == 0 && state == 0) {
-            continue;
-        }
-
-        if (ei == 0 && state == 1) {
-            /*
-             * out of window, square W[x_index]
-             */
-            MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size, x_index));
-            mpi_montmul(&W[x_index], &WW, N, mm, &T);
-            continue;
-        }
-
-        /*
-         * add ei to current window
-         */
-        state = 2;
-
-        nbits++;
-        exponent_bits_in_window |= (ei << (window_bitsize - nbits));
-
-        if (nbits == window_bitsize) {
-            /*
-             * W[x_index] = W[x_index]^window_bitsize R^-1 mod N
-             */
-            for (i = 0; i < window_bitsize; i++) {
-                MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size,
-                                           x_index));
-                mpi_montmul(&W[x_index], &WW, N, mm, &T);
-            }
-
-            /*
-             * W[x_index] = W[x_index] * W[exponent_bits_in_window] R^-1 mod N
-             */
-            MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size,
-                                       exponent_bits_in_window));
-            mpi_montmul(&W[x_index], &WW, N, mm, &T);
-
-            state--;
-            nbits = 0;
-            exponent_bits_in_window = 0;
-        }
+    /*
+     * Convert to and from Montgomery around mbedtls_mpi_core_exp_mod().
+     */
+    {
+        mbedtls_mpi_uint mm = mbedtls_mpi_core_montmul_init(N->p);
+        mbedtls_mpi_core_to_mont_rep(X->p, X->p, N->p, N->n, mm, RR.p, T);
+        mbedtls_mpi_core_exp_mod(X->p, X->p, N->p, N->n, E->p, E->n, RR.p, T);
+        mbedtls_mpi_core_from_mont_rep(X->p, X->p, N->p, N->n, mm, T);
     }
 
     /*
-     * process the remaining bits
+     * Correct for negative A.
      */
-    for (i = 0; i < nbits; i++) {
-        MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size, x_index));
-        mpi_montmul(&W[x_index], &WW, N, mm, &T);
+    if (A->s == -1 && (E->p[0] & 1) != 0) {
+        mbedtls_ct_condition_t is_x_non_zero = mbedtls_mpi_core_check_zero_ct(X->p, X->n);
+        X->s = mbedtls_ct_mpi_sign_if(is_x_non_zero, -1, 1);
 
-        exponent_bits_in_window <<= 1;
-
-        if ((exponent_bits_in_window & ((size_t) 1 << window_bitsize)) != 0) {
-            MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size, 1));
-            mpi_montmul(&W[x_index], &WW, N, mm, &T);
-        }
+        MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(X, N, X));
     }
 
-    /*
-     * W[x_index] = A^E * R * R^-1 mod N = A^E mod N
-     */
-    mpi_montred(&W[x_index], N, mm, &T);
-
-    if (neg && E->n != 0 && (E->p[0] & 1) != 0) {
-        W[x_index].s = -1;
-        MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&W[x_index], N, &W[x_index]));
-    }
-
-    /*
-     * Load the result in the output variable.
-     */
-    MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, &W[x_index]));
-
 cleanup:
 
-    /* The first bit of the sliding window is always 1 and therefore the first
-     * half of the table was unused. */
-    for (i = w_table_used_size/2; i < w_table_used_size; i++) {
-        mbedtls_mpi_free(&W[i]);
-    }
-
-    mbedtls_mpi_free(&W[x_index]);
-    mbedtls_mpi_free(&W[1]);
-    mbedtls_mpi_free(&T);
-    mbedtls_mpi_free(&Apos);
-    mbedtls_mpi_free(&WW);
+    mbedtls_mpi_zeroize_and_free(T, T_limbs);
 
     if (prec_RR == NULL || prec_RR->p == NULL) {
         mbedtls_mpi_free(&RR);
diff --git a/library/bignum_core.c b/library/bignum_core.c
index dfed60d..1a3e0b9 100644
--- a/library/bignum_core.c
+++ b/library/bignum_core.c
@@ -856,16 +856,17 @@
     return c;
 }
 
-mbedtls_mpi_uint mbedtls_mpi_core_check_zero_ct(const mbedtls_mpi_uint *A,
-                                                size_t limbs)
+mbedtls_ct_condition_t mbedtls_mpi_core_check_zero_ct(const mbedtls_mpi_uint *A,
+                                                      size_t limbs)
 {
+    volatile const mbedtls_mpi_uint *force_read_A = A;
     mbedtls_mpi_uint bits = 0;
 
     for (size_t i = 0; i < limbs; i++) {
-        bits |= A[i];
+        bits |= force_read_A[i];
     }
 
-    return bits;
+    return mbedtls_ct_bool(bits);
 }
 
 void mbedtls_mpi_core_to_mont_rep(mbedtls_mpi_uint *X,
diff --git a/library/bignum_core.h b/library/bignum_core.h
index b56be0a..92c8d47 100644
--- a/library/bignum_core.h
+++ b/library/bignum_core.h
@@ -662,11 +662,11 @@
  * \param[in] A   The MPI to test.
  * \param limbs   Number of limbs in \p A.
  *
- * \return        0 if `A == 0`
- *                non-0 (may be any value) if `A != 0`.
+ * \return        MBEDTLS_CT_FALSE if `A == 0`
+ *                MBEDTLS_CT_TRUE  if `A != 0`.
  */
-mbedtls_mpi_uint mbedtls_mpi_core_check_zero_ct(const mbedtls_mpi_uint *A,
-                                                size_t limbs);
+mbedtls_ct_condition_t mbedtls_mpi_core_check_zero_ct(const mbedtls_mpi_uint *A,
+                                                      size_t limbs);
 
 /**
  * \brief          Returns the number of limbs of working memory required for
diff --git a/library/ecdh.c b/library/ecdh.c
index 52b1617..b276c6a 100644
--- a/library/ecdh.c
+++ b/library/ecdh.c
@@ -144,6 +144,15 @@
 #endif
 }
 
+mbedtls_ecp_group_id mbedtls_ecdh_get_grp_id(mbedtls_ecdh_context *ctx)
+{
+#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
+    return ctx->MBEDTLS_PRIVATE(grp).id;
+#else
+    return ctx->MBEDTLS_PRIVATE(grp_id);
+#endif
+}
+
 /*
  * Initialize context
  */
diff --git a/library/ecp.c b/library/ecp.c
index 758d54b..427059b 100644
--- a/library/ecp.c
+++ b/library/ecp.c
@@ -3302,10 +3302,11 @@
 /*
  * Write a private key.
  */
+#if !defined MBEDTLS_DEPRECATED_REMOVED
 int mbedtls_ecp_write_key(mbedtls_ecp_keypair *key,
                           unsigned char *buf, size_t buflen)
 {
-    int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
 
 #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
     if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) {
@@ -3332,6 +3333,39 @@
 
     return ret;
 }
+#endif /* MBEDTLS_DEPRECATED_REMOVED */
+
+int mbedtls_ecp_write_key_ext(const mbedtls_ecp_keypair *key,
+                              size_t *olen, unsigned char *buf, size_t buflen)
+{
+    size_t len = (key->grp.nbits + 7) / 8;
+    if (len > buflen) {
+        /* For robustness, ensure *olen <= buflen even on error. */
+        *olen = 0;
+        return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
+    }
+    *olen = len;
+
+    /* Private key not set */
+    if (key->d.n == 0) {
+        return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+    }
+
+#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
+    if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) {
+        return mbedtls_mpi_write_binary_le(&key->d, buf, len);
+    }
+#endif
+
+#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
+    if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) {
+        return mbedtls_mpi_write_binary(&key->d, buf, len);
+    }
+#endif
+
+    /* Private key set but no recognized curve type? This shouldn't happen. */
+    return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+}
 
 /*
  * Write a public key.
diff --git a/library/gcm.c b/library/gcm.c
index 033cb59..90c1d1d 100644
--- a/library/gcm.c
+++ b/library/gcm.c
@@ -41,6 +41,12 @@
 
 #if !defined(MBEDTLS_GCM_ALT)
 
+/* Used to select the acceleration mechanism */
+#define MBEDTLS_GCM_ACC_SMALLTABLE  0
+#define MBEDTLS_GCM_ACC_LARGETABLE  1
+#define MBEDTLS_GCM_ACC_AESNI       2
+#define MBEDTLS_GCM_ACC_AESCE       3
+
 /*
  * Initialize a context
  */
@@ -49,6 +55,39 @@
     memset(ctx, 0, sizeof(mbedtls_gcm_context));
 }
 
+static inline void gcm_set_acceleration(mbedtls_gcm_context *ctx)
+{
+#if defined(MBEDTLS_GCM_LARGE_TABLE)
+    ctx->acceleration = MBEDTLS_GCM_ACC_LARGETABLE;
+#else
+    ctx->acceleration = MBEDTLS_GCM_ACC_SMALLTABLE;
+#endif
+
+#if defined(MBEDTLS_AESNI_HAVE_CODE)
+    /* With CLMUL support, we need only h, not the rest of the table */
+    if (mbedtls_aesni_has_support(MBEDTLS_AESNI_CLMUL)) {
+        ctx->acceleration = MBEDTLS_GCM_ACC_AESNI;
+    }
+#endif
+
+#if defined(MBEDTLS_AESCE_HAVE_CODE)
+    if (MBEDTLS_AESCE_HAS_SUPPORT()) {
+        ctx->acceleration = MBEDTLS_GCM_ACC_AESCE;
+    }
+#endif
+}
+
+static inline void gcm_gen_table_rightshift(uint64_t dst[2], const uint64_t src[2])
+{
+    uint8_t *u8Dst = (uint8_t *) dst;
+    uint8_t *u8Src = (uint8_t *) src;
+
+    MBEDTLS_PUT_UINT64_BE(MBEDTLS_GET_UINT64_BE(&src[1], 0) >> 1, &dst[1], 0);
+    u8Dst[8] |= (u8Src[7] & 0x01) << 7;
+    MBEDTLS_PUT_UINT64_BE(MBEDTLS_GET_UINT64_BE(&src[0], 0) >> 1, &dst[0], 0);
+    u8Dst[0] ^= (u8Src[15] & 0x01) ? 0xE1 : 0;
+}
+
 /*
  * Precompute small multiples of H, that is set
  *      HH[i] || HL[i] = H times i,
@@ -60,11 +99,8 @@
 static int gcm_gen_table(mbedtls_gcm_context *ctx)
 {
     int ret, i, j;
-    uint64_t hi, lo;
-    uint64_t vl, vh;
-    unsigned char h[16];
-
-    memset(h, 0, 16);
+    uint64_t u64h[2] = { 0 };
+    uint8_t *h = (uint8_t *) u64h;
 
 #if defined(MBEDTLS_BLOCK_CIPHER_C)
     ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, h, h);
@@ -76,53 +112,48 @@
         return ret;
     }
 
-    /* pack h as two 64-bits ints, big-endian */
-    hi = MBEDTLS_GET_UINT32_BE(h,  0);
-    lo = MBEDTLS_GET_UINT32_BE(h,  4);
-    vh = (uint64_t) hi << 32 | lo;
+    gcm_set_acceleration(ctx);
 
-    hi = MBEDTLS_GET_UINT32_BE(h,  8);
-    lo = MBEDTLS_GET_UINT32_BE(h,  12);
-    vl = (uint64_t) hi << 32 | lo;
+    /* MBEDTLS_GCM_HTABLE_SIZE/2 = 1000 corresponds to 1 in GF(2^128) */
+    ctx->H[MBEDTLS_GCM_HTABLE_SIZE/2][0] = u64h[0];
+    ctx->H[MBEDTLS_GCM_HTABLE_SIZE/2][1] = u64h[1];
 
-    /* 8 = 1000 corresponds to 1 in GF(2^128) */
-    ctx->HL[8] = vl;
-    ctx->HH[8] = vh;
-
+    switch (ctx->acceleration) {
 #if defined(MBEDTLS_AESNI_HAVE_CODE)
-    /* With CLMUL support, we need only h, not the rest of the table */
-    if (mbedtls_aesni_has_support(MBEDTLS_AESNI_CLMUL)) {
-        return 0;
-    }
+        case MBEDTLS_GCM_ACC_AESNI:
+            return 0;
 #endif
 
 #if defined(MBEDTLS_AESCE_HAVE_CODE)
-    if (MBEDTLS_AESCE_HAS_SUPPORT()) {
-        return 0;
-    }
+        case MBEDTLS_GCM_ACC_AESCE:
+            return 0;
 #endif
 
-    /* 0 corresponds to 0 in GF(2^128) */
-    ctx->HH[0] = 0;
-    ctx->HL[0] = 0;
+        default:
+            /* 0 corresponds to 0 in GF(2^128) */
+            ctx->H[0][0] = 0;
+            ctx->H[0][1] = 0;
 
-    for (i = 4; i > 0; i >>= 1) {
-        uint32_t T = (vl & 1) * 0xe1000000U;
-        vl  = (vh << 63) | (vl >> 1);
-        vh  = (vh >> 1) ^ ((uint64_t) T << 32);
+            for (i = MBEDTLS_GCM_HTABLE_SIZE/4; i > 0; i >>= 1) {
+                gcm_gen_table_rightshift(ctx->H[i], ctx->H[i*2]);
+            }
 
-        ctx->HL[i] = vl;
-        ctx->HH[i] = vh;
-    }
+#if !defined(MBEDTLS_GCM_LARGE_TABLE)
+            /* pack elements of H as 64-bits ints, big-endian */
+            for (i = MBEDTLS_GCM_HTABLE_SIZE/2; i > 0; i >>= 1) {
+                MBEDTLS_PUT_UINT64_BE(ctx->H[i][0], &ctx->H[i][0], 0);
+                MBEDTLS_PUT_UINT64_BE(ctx->H[i][1], &ctx->H[i][1], 0);
+            }
+#endif
 
-    for (i = 2; i <= 8; i *= 2) {
-        uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i;
-        vh = *HiH;
-        vl = *HiL;
-        for (j = 1; j < i; j++) {
-            HiH[j] = vh ^ ctx->HH[j];
-            HiL[j] = vl ^ ctx->HL[j];
-        }
+            for (i = 2; i < MBEDTLS_GCM_HTABLE_SIZE; i <<= 1) {
+                for (j = 1; j < i; j++) {
+                    mbedtls_xor_no_simd((unsigned char *) ctx->H[i+j],
+                                        (unsigned char *) ctx->H[i],
+                                        (unsigned char *) ctx->H[j],
+                                        16);
+                }
+            }
     }
 
     return 0;
@@ -181,6 +212,80 @@
     return 0;
 }
 
+#if defined(MBEDTLS_GCM_LARGE_TABLE)
+static const uint16_t last8[256] = {
+    0x0000, 0xc201, 0x8403, 0x4602, 0x0807, 0xca06, 0x8c04, 0x4e05,
+    0x100e, 0xd20f, 0x940d, 0x560c, 0x1809, 0xda08, 0x9c0a, 0x5e0b,
+    0x201c, 0xe21d, 0xa41f, 0x661e, 0x281b, 0xea1a, 0xac18, 0x6e19,
+    0x3012, 0xf213, 0xb411, 0x7610, 0x3815, 0xfa14, 0xbc16, 0x7e17,
+    0x4038, 0x8239, 0xc43b, 0x063a, 0x483f, 0x8a3e, 0xcc3c, 0x0e3d,
+    0x5036, 0x9237, 0xd435, 0x1634, 0x5831, 0x9a30, 0xdc32, 0x1e33,
+    0x6024, 0xa225, 0xe427, 0x2626, 0x6823, 0xaa22, 0xec20, 0x2e21,
+    0x702a, 0xb22b, 0xf429, 0x3628, 0x782d, 0xba2c, 0xfc2e, 0x3e2f,
+    0x8070, 0x4271, 0x0473, 0xc672, 0x8877, 0x4a76, 0x0c74, 0xce75,
+    0x907e, 0x527f, 0x147d, 0xd67c, 0x9879, 0x5a78, 0x1c7a, 0xde7b,
+    0xa06c, 0x626d, 0x246f, 0xe66e, 0xa86b, 0x6a6a, 0x2c68, 0xee69,
+    0xb062, 0x7263, 0x3461, 0xf660, 0xb865, 0x7a64, 0x3c66, 0xfe67,
+    0xc048, 0x0249, 0x444b, 0x864a, 0xc84f, 0x0a4e, 0x4c4c, 0x8e4d,
+    0xd046, 0x1247, 0x5445, 0x9644, 0xd841, 0x1a40, 0x5c42, 0x9e43,
+    0xe054, 0x2255, 0x6457, 0xa656, 0xe853, 0x2a52, 0x6c50, 0xae51,
+    0xf05a, 0x325b, 0x7459, 0xb658, 0xf85d, 0x3a5c, 0x7c5e, 0xbe5f,
+    0x00e1, 0xc2e0, 0x84e2, 0x46e3, 0x08e6, 0xcae7, 0x8ce5, 0x4ee4,
+    0x10ef, 0xd2ee, 0x94ec, 0x56ed, 0x18e8, 0xdae9, 0x9ceb, 0x5eea,
+    0x20fd, 0xe2fc, 0xa4fe, 0x66ff, 0x28fa, 0xeafb, 0xacf9, 0x6ef8,
+    0x30f3, 0xf2f2, 0xb4f0, 0x76f1, 0x38f4, 0xfaf5, 0xbcf7, 0x7ef6,
+    0x40d9, 0x82d8, 0xc4da, 0x06db, 0x48de, 0x8adf, 0xccdd, 0x0edc,
+    0x50d7, 0x92d6, 0xd4d4, 0x16d5, 0x58d0, 0x9ad1, 0xdcd3, 0x1ed2,
+    0x60c5, 0xa2c4, 0xe4c6, 0x26c7, 0x68c2, 0xaac3, 0xecc1, 0x2ec0,
+    0x70cb, 0xb2ca, 0xf4c8, 0x36c9, 0x78cc, 0xbacd, 0xfccf, 0x3ece,
+    0x8091, 0x4290, 0x0492, 0xc693, 0x8896, 0x4a97, 0x0c95, 0xce94,
+    0x909f, 0x529e, 0x149c, 0xd69d, 0x9898, 0x5a99, 0x1c9b, 0xde9a,
+    0xa08d, 0x628c, 0x248e, 0xe68f, 0xa88a, 0x6a8b, 0x2c89, 0xee88,
+    0xb083, 0x7282, 0x3480, 0xf681, 0xb884, 0x7a85, 0x3c87, 0xfe86,
+    0xc0a9, 0x02a8, 0x44aa, 0x86ab, 0xc8ae, 0x0aaf, 0x4cad, 0x8eac,
+    0xd0a7, 0x12a6, 0x54a4, 0x96a5, 0xd8a0, 0x1aa1, 0x5ca3, 0x9ea2,
+    0xe0b5, 0x22b4, 0x64b6, 0xa6b7, 0xe8b2, 0x2ab3, 0x6cb1, 0xaeb0,
+    0xf0bb, 0x32ba, 0x74b8, 0xb6b9, 0xf8bc, 0x3abd, 0x7cbf, 0xbebe
+};
+
+static void gcm_mult_largetable(uint8_t *output, const uint8_t *x, uint64_t H[256][2])
+{
+    int i;
+    uint64_t u64z[2];
+    uint16_t *u16z = (uint16_t *) u64z;
+    uint8_t *u8z = (uint8_t *) u64z;
+    uint8_t rem;
+
+    u64z[0] = 0;
+    u64z[1] = 0;
+
+    if (MBEDTLS_IS_BIG_ENDIAN) {
+        for (i = 15; i > 0; i--) {
+            mbedtls_xor_no_simd(u8z, u8z, (uint8_t *) H[x[i]], 16);
+            rem = u8z[15];
+
+            u64z[1] >>= 8;
+            u8z[8] = u8z[7];
+            u64z[0] >>= 8;
+
+            u16z[0] ^= MBEDTLS_GET_UINT16_LE(&last8[rem], 0);
+        }
+    } else {
+        for (i = 15; i > 0; i--) {
+            mbedtls_xor_no_simd(u8z, u8z, (uint8_t *) H[x[i]], 16);
+            rem = u8z[15];
+
+            u64z[1] <<= 8;
+            u8z[8] = u8z[7];
+            u64z[0] <<= 8;
+
+            u16z[0] ^= last8[rem];
+        }
+    }
+
+    mbedtls_xor_no_simd(output, u8z, (uint8_t *) H[x[0]], 16);
+}
+#else
 /*
  * Shoup's method for multiplication use this table with
  *      last4[x] = x times P^128
@@ -194,6 +299,47 @@
     0x9180, 0x8da0, 0xa9c0, 0xb5e0
 };
 
+static void gcm_mult_smalltable(uint8_t *output, const uint8_t *x, uint64_t H[16][2])
+{
+    int i = 0;
+    unsigned char lo, hi, rem;
+    uint64_t u64z[2];
+    const uint64_t *pu64z = NULL;
+    uint8_t *u8z = (uint8_t *) u64z;
+
+    lo = x[15] & 0xf;
+    hi = (x[15] >> 4) & 0xf;
+
+    pu64z = H[lo];
+
+    rem = (unsigned char) pu64z[1] & 0xf;
+    u64z[1] = (pu64z[0] << 60) | (pu64z[1] >> 4);
+    u64z[0] = (pu64z[0] >> 4);
+    u64z[0] ^= (uint64_t) last4[rem] << 48;
+    mbedtls_xor_no_simd(u8z, u8z, (uint8_t *) H[hi], 16);
+
+    for (i = 14; i >= 0; i--) {
+        lo = x[i] & 0xf;
+        hi = (x[i] >> 4) & 0xf;
+
+        rem = (unsigned char) u64z[1] & 0xf;
+        u64z[1] = (u64z[0] << 60) | (u64z[1] >> 4);
+        u64z[0] = (u64z[0] >> 4);
+        u64z[0] ^= (uint64_t) last4[rem] << 48;
+        mbedtls_xor_no_simd(u8z, u8z, (uint8_t *) H[lo], 16);
+
+        rem = (unsigned char) u64z[1] & 0xf;
+        u64z[1] = (u64z[0] << 60) | (u64z[1] >> 4);
+        u64z[0] = (u64z[0] >> 4);
+        u64z[0] ^= (uint64_t) last4[rem] << 48;
+        mbedtls_xor_no_simd(u8z, u8z, (uint8_t *) H[hi], 16);
+    }
+
+    MBEDTLS_PUT_UINT64_BE(u64z[0], output, 0);
+    MBEDTLS_PUT_UINT64_BE(u64z[1], output, 8);
+}
+#endif
+
 /*
  * Sets output to x times H using the precomputed tables.
  * x and output are seen as elements of GF(2^128) as in [MGV].
@@ -201,71 +347,31 @@
 static void gcm_mult(mbedtls_gcm_context *ctx, const unsigned char x[16],
                      unsigned char output[16])
 {
-    int i = 0;
-    unsigned char lo, hi, rem;
-    uint64_t zh, zl;
-
+    switch (ctx->acceleration) {
 #if defined(MBEDTLS_AESNI_HAVE_CODE)
-    if (mbedtls_aesni_has_support(MBEDTLS_AESNI_CLMUL)) {
-        unsigned char h[16];
-
-        /* mbedtls_aesni_gcm_mult needs big-endian input */
-        MBEDTLS_PUT_UINT32_BE(ctx->HH[8] >> 32, h,  0);
-        MBEDTLS_PUT_UINT32_BE(ctx->HH[8],       h,  4);
-        MBEDTLS_PUT_UINT32_BE(ctx->HL[8] >> 32, h,  8);
-        MBEDTLS_PUT_UINT32_BE(ctx->HL[8],       h, 12);
-
-        mbedtls_aesni_gcm_mult(output, x, h);
-        return;
-    }
-#endif /* MBEDTLS_AESNI_HAVE_CODE */
-
-#if defined(MBEDTLS_AESCE_HAVE_CODE)
-    if (MBEDTLS_AESCE_HAS_SUPPORT()) {
-        unsigned char h[16];
-
-        /* mbedtls_aesce_gcm_mult needs big-endian input */
-        MBEDTLS_PUT_UINT32_BE(ctx->HH[8] >> 32, h,  0);
-        MBEDTLS_PUT_UINT32_BE(ctx->HH[8],       h,  4);
-        MBEDTLS_PUT_UINT32_BE(ctx->HL[8] >> 32, h,  8);
-        MBEDTLS_PUT_UINT32_BE(ctx->HL[8],       h, 12);
-
-        mbedtls_aesce_gcm_mult(output, x, h);
-        return;
-    }
+        case MBEDTLS_GCM_ACC_AESNI:
+            mbedtls_aesni_gcm_mult(output, x, (uint8_t *) ctx->H[MBEDTLS_GCM_HTABLE_SIZE/2]);
+            break;
 #endif
 
-    lo = x[15] & 0xf;
+#if defined(MBEDTLS_AESCE_HAVE_CODE)
+        case MBEDTLS_GCM_ACC_AESCE:
+            mbedtls_aesce_gcm_mult(output, x, (uint8_t *) ctx->H[MBEDTLS_GCM_HTABLE_SIZE/2]);
+            break;
+#endif
 
-    zh = ctx->HH[lo];
-    zl = ctx->HL[lo];
-
-    for (i = 15; i >= 0; i--) {
-        lo = x[i] & 0xf;
-        hi = (x[i] >> 4) & 0xf;
-
-        if (i != 15) {
-            rem = (unsigned char) zl & 0xf;
-            zl = (zh << 60) | (zl >> 4);
-            zh = (zh >> 4);
-            zh ^= (uint64_t) last4[rem] << 48;
-            zh ^= ctx->HH[lo];
-            zl ^= ctx->HL[lo];
-
-        }
-
-        rem = (unsigned char) zl & 0xf;
-        zl = (zh << 60) | (zl >> 4);
-        zh = (zh >> 4);
-        zh ^= (uint64_t) last4[rem] << 48;
-        zh ^= ctx->HH[hi];
-        zl ^= ctx->HL[hi];
+#if defined(MBEDTLS_GCM_LARGE_TABLE)
+        case MBEDTLS_GCM_ACC_LARGETABLE:
+            gcm_mult_largetable(output, x, ctx->H);
+            break;
+#else
+        case MBEDTLS_GCM_ACC_SMALLTABLE:
+            gcm_mult_smalltable(output, x, ctx->H);
+            break;
+#endif
     }
 
-    MBEDTLS_PUT_UINT32_BE(zh >> 32, output, 0);
-    MBEDTLS_PUT_UINT32_BE(zh, output, 4);
-    MBEDTLS_PUT_UINT32_BE(zl >> 32, output, 8);
-    MBEDTLS_PUT_UINT32_BE(zl, output, 12);
+    return;
 }
 
 int mbedtls_gcm_starts(mbedtls_gcm_context *ctx,
diff --git a/library/lms.c b/library/lms.c
index 08fe753..8d3cae0 100644
--- a/library/lms.c
+++ b/library/lms.c
@@ -65,7 +65,8 @@
 #define H_TREE_HEIGHT_MAX                  10
 #define MERKLE_TREE_NODE_AM(type)          ((size_t) 1 << (MBEDTLS_LMS_H_TREE_HEIGHT(type) + 1u))
 #define MERKLE_TREE_LEAF_NODE_AM(type)     ((size_t) 1 << MBEDTLS_LMS_H_TREE_HEIGHT(type))
-#define MERKLE_TREE_INTERNAL_NODE_AM(type) ((size_t) 1 << MBEDTLS_LMS_H_TREE_HEIGHT(type))
+#define MERKLE_TREE_INTERNAL_NODE_AM(type) ((unsigned int) \
+                                            (1u << MBEDTLS_LMS_H_TREE_HEIGHT(type)))
 
 #define D_CONST_LEN           (2)
 static const unsigned char D_LEAF_CONSTANT_BYTES[D_CONST_LEN] = { 0x82, 0x82 };
diff --git a/library/pem.c b/library/pem.c
index 539134c..0fee5df 100644
--- a/library/pem.c
+++ b/library/pem.c
@@ -240,6 +240,29 @@
 }
 #endif /* MBEDTLS_AES_C */
 
+#if defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C)
+static int pem_check_pkcs_padding(unsigned char *input, size_t input_len, size_t *data_len)
+{
+    /* input_len > 0 is guaranteed by mbedtls_pem_read_buffer(). */
+    size_t pad_len = input[input_len - 1];
+    size_t i;
+
+    if (pad_len > input_len) {
+        return MBEDTLS_ERR_PEM_PASSWORD_MISMATCH;
+    }
+
+    *data_len = input_len - pad_len;
+
+    for (i = *data_len; i < input_len; i++) {
+        if (input[i] != pad_len) {
+            return MBEDTLS_ERR_PEM_PASSWORD_MISMATCH;
+        }
+    }
+
+    return 0;
+}
+#endif /* MBEDTLS_DES_C || MBEDTLS_AES_C */
+
 #endif /* PEM_RFC1421 */
 
 int mbedtls_pem_read_buffer(mbedtls_pem_context *ctx, const char *header, const char *footer,
@@ -389,6 +412,10 @@
         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PEM_INVALID_DATA, ret);
     }
 
+    if (len == 0) {
+        return MBEDTLS_ERR_PEM_BAD_INPUT_DATA;
+    }
+
     if ((buf = mbedtls_calloc(1, len)) == NULL) {
         return MBEDTLS_ERR_PEM_ALLOC_FAILED;
     }
@@ -426,20 +453,20 @@
 #endif /* MBEDTLS_AES_C */
 
         if (ret != 0) {
-            mbedtls_free(buf);
+            mbedtls_zeroize_and_free(buf, len);
             return ret;
         }
 
-        /*
-         * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3
-         * length bytes (allow 4 to be sure) in all known use cases.
-         *
-         * Use that as a heuristic to try to detect password mismatches.
-         */
-        if (len <= 2 || buf[0] != 0x30 || buf[1] > 0x83) {
+        /* Check PKCS padding and update data length based on padding info.
+         * This can be used to detect invalid padding data and password
+         * mismatches. */
+        size_t unpadded_len;
+        ret = pem_check_pkcs_padding(buf, len, &unpadded_len);
+        if (ret != 0) {
             mbedtls_zeroize_and_free(buf, len);
-            return MBEDTLS_ERR_PEM_PASSWORD_MISMATCH;
+            return ret;
         }
+        len = unpadded_len;
 #else
         mbedtls_zeroize_and_free(buf, len);
         return MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE;
diff --git a/library/pk.c b/library/pk.c
index 1b481e1..003ef4a 100644
--- a/library/pk.c
+++ b/library/pk.c
@@ -18,10 +18,8 @@
 
 #if defined(MBEDTLS_RSA_C)
 #include "mbedtls/rsa.h"
-#if defined(MBEDTLS_PKCS1_V21) && !defined(MBEDTLS_USE_PSA_CRYPTO)
 #include "rsa_internal.h"
 #endif
-#endif
 #if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
 #include "mbedtls/ecp.h"
 #endif
@@ -385,7 +383,7 @@
 {
     if (mbedtls_rsa_get_padding_mode(rsa) == MBEDTLS_RSA_PKCS_V21) {
         if (want_crypt) {
-            mbedtls_md_type_t md_type = mbedtls_rsa_get_md_alg(rsa);
+            mbedtls_md_type_t md_type = (mbedtls_md_type_t) mbedtls_rsa_get_md_alg(rsa);
             return PSA_ALG_RSA_OAEP(mbedtls_md_psa_alg_from_type(md_type));
         } else {
             return PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_ANY_HASH);
@@ -579,6 +577,279 @@
 
     return 0;
 }
+
+#if defined(MBEDTLS_PK_USE_PSA_EC_DATA) || defined(MBEDTLS_USE_PSA_CRYPTO)
+static psa_status_t export_import_into_psa(mbedtls_svc_key_id_t old_key_id,
+                                           const psa_key_attributes_t *attributes,
+                                           mbedtls_svc_key_id_t *new_key_id)
+{
+    unsigned char key_buffer[PSA_EXPORT_KEY_PAIR_MAX_SIZE];
+    size_t key_length = 0;
+    psa_status_t status = psa_export_key(old_key_id,
+                                         key_buffer, sizeof(key_buffer),
+                                         &key_length);
+    if (status != PSA_SUCCESS) {
+        return status;
+    }
+    status = psa_import_key(attributes, key_buffer, key_length, new_key_id);
+    mbedtls_platform_zeroize(key_buffer, key_length);
+    return status;
+}
+
+static int copy_into_psa(mbedtls_svc_key_id_t old_key_id,
+                         const psa_key_attributes_t *attributes,
+                         mbedtls_svc_key_id_t *new_key_id)
+{
+    /* Normally, we prefer copying: it's more efficient and works even
+     * for non-exportable keys. */
+    psa_status_t status = psa_copy_key(old_key_id, attributes, new_key_id);
+    if (status == PSA_ERROR_NOT_PERMITTED /*missing COPY usage*/ ||
+        status == PSA_ERROR_INVALID_ARGUMENT /*incompatible policy*/) {
+        /* There are edge cases where copying won't work, but export+import
+         * might:
+         * - If the old key does not allow PSA_KEY_USAGE_COPY.
+         * - If the old key's usage does not allow what attributes wants.
+         *   Because the key was intended for use in the pk module, and may
+         *   have had a policy chosen solely for what pk needs rather than
+         *   based on a detailed understanding of PSA policies, we are a bit
+         *   more liberal than psa_copy_key() here.
+         */
+        /* Here we need to check that the types match, otherwise we risk
+         * importing nonsensical data. */
+        psa_key_attributes_t old_attributes = PSA_KEY_ATTRIBUTES_INIT;
+        status = psa_get_key_attributes(old_key_id, &old_attributes);
+        if (status != PSA_SUCCESS) {
+            return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+        }
+        psa_key_type_t old_type = psa_get_key_type(&old_attributes);
+        psa_reset_key_attributes(&old_attributes);
+        if (old_type != psa_get_key_type(attributes)) {
+            return MBEDTLS_ERR_PK_TYPE_MISMATCH;
+        }
+        status = export_import_into_psa(old_key_id, attributes, new_key_id);
+    }
+    return PSA_PK_TO_MBEDTLS_ERR(status);
+}
+#endif /* MBEDTLS_PK_USE_PSA_EC_DATA || MBEDTLS_USE_PSA_CRYPTO */
+
+static int import_pair_into_psa(const mbedtls_pk_context *pk,
+                                const psa_key_attributes_t *attributes,
+                                mbedtls_svc_key_id_t *key_id)
+{
+    switch (mbedtls_pk_get_type(pk)) {
+#if defined(MBEDTLS_RSA_C)
+        case MBEDTLS_PK_RSA:
+        {
+            if (psa_get_key_type(attributes) != PSA_KEY_TYPE_RSA_KEY_PAIR) {
+                return MBEDTLS_ERR_PK_TYPE_MISMATCH;
+            }
+            unsigned char key_buffer[
+                PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(PSA_VENDOR_RSA_MAX_KEY_BITS)];
+            unsigned char *const key_end = key_buffer + sizeof(key_buffer);
+            unsigned char *key_data = key_end;
+            int ret = mbedtls_rsa_write_key(mbedtls_pk_rsa(*pk),
+                                            key_buffer, &key_data);
+            if (ret < 0) {
+                return ret;
+            }
+            size_t key_length = key_end - key_data;
+            ret = PSA_PK_TO_MBEDTLS_ERR(psa_import_key(attributes,
+                                                       key_data, key_length,
+                                                       key_id));
+            mbedtls_platform_zeroize(key_data, key_length);
+            return ret;
+        }
+#endif /* MBEDTLS_RSA_C */
+
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
+        case MBEDTLS_PK_ECKEY:
+        case MBEDTLS_PK_ECKEY_DH:
+        case MBEDTLS_PK_ECDSA:
+        {
+            /* We need to check the curve family, otherwise the import could
+             * succeed with nonsensical data.
+             * We don't check the bit-size: it's optional in attributes,
+             * and if it's specified, psa_import_key() will know from the key
+             * data length and will check that the bit-size matches. */
+            psa_key_type_t to_type = psa_get_key_type(attributes);
+#if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
+            psa_ecc_family_t from_family = pk->ec_family;
+#else /* MBEDTLS_PK_USE_PSA_EC_DATA */
+            const mbedtls_ecp_keypair *ec = mbedtls_pk_ec_ro(*pk);
+            size_t from_bits = 0;
+            psa_ecc_family_t from_family = mbedtls_ecc_group_to_psa(ec->grp.id,
+                                                                    &from_bits);
+#endif /* MBEDTLS_PK_USE_PSA_EC_DATA */
+            if (to_type != PSA_KEY_TYPE_ECC_KEY_PAIR(from_family)) {
+                return MBEDTLS_ERR_PK_TYPE_MISMATCH;
+            }
+
+#if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
+            if (mbedtls_svc_key_id_is_null(pk->priv_id)) {
+                /* We have a public key and want a key pair. */
+                return MBEDTLS_ERR_PK_TYPE_MISMATCH;
+            }
+            return copy_into_psa(pk->priv_id, attributes, key_id);
+#else /* MBEDTLS_PK_USE_PSA_EC_DATA */
+            if (ec->d.n == 0) {
+                /* Private key not set. Assume the input is a public key only.
+                 * (The other possibility is that it's an incomplete object
+                 * where the group is set but neither the public key nor
+                 * the private key. This is not possible through ecp.h
+                 * functions, so we don't bother reporting a more suitable
+                 * error in that case.) */
+                return MBEDTLS_ERR_PK_TYPE_MISMATCH;
+            }
+            unsigned char key_buffer[PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS)];
+            size_t key_length = 0;
+            int ret = mbedtls_ecp_write_key_ext(ec, &key_length,
+                                                key_buffer, sizeof(key_buffer));
+            if (ret < 0) {
+                return ret;
+            }
+            ret = PSA_PK_TO_MBEDTLS_ERR(psa_import_key(attributes,
+                                                       key_buffer, key_length,
+                                                       key_id));
+            mbedtls_platform_zeroize(key_buffer, key_length);
+            return ret;
+#endif /* MBEDTLS_PK_USE_PSA_EC_DATA */
+        }
+#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+        case MBEDTLS_PK_OPAQUE:
+            return copy_into_psa(pk->priv_id, attributes, key_id);
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+        default:
+            return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+    }
+}
+
+static int import_public_into_psa(const mbedtls_pk_context *pk,
+                                  const psa_key_attributes_t *attributes,
+                                  mbedtls_svc_key_id_t *key_id)
+{
+    psa_key_type_t psa_type = psa_get_key_type(attributes);
+
+#if defined(MBEDTLS_RSA_C) ||                                           \
+    (defined(MBEDTLS_PK_HAVE_ECC_KEYS) && !defined(MBEDTLS_PK_USE_PSA_EC_DATA)) || \
+    defined(MBEDTLS_USE_PSA_CRYPTO)
+    unsigned char key_buffer[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
+#endif
+    unsigned char *key_data = NULL;
+    size_t key_length = 0;
+
+    switch (mbedtls_pk_get_type(pk)) {
+#if defined(MBEDTLS_RSA_C)
+        case MBEDTLS_PK_RSA:
+        {
+            if (psa_type != PSA_KEY_TYPE_RSA_PUBLIC_KEY) {
+                return MBEDTLS_ERR_PK_TYPE_MISMATCH;
+            }
+            unsigned char *const key_end = key_buffer + sizeof(key_buffer);
+            key_data = key_end;
+            int ret = mbedtls_rsa_write_pubkey(mbedtls_pk_rsa(*pk),
+                                               key_buffer, &key_data);
+            if (ret < 0) {
+                return ret;
+            }
+            key_length = (size_t) ret;
+            break;
+        }
+#endif /*MBEDTLS_RSA_C */
+
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
+        case MBEDTLS_PK_ECKEY:
+        case MBEDTLS_PK_ECKEY_DH:
+        case MBEDTLS_PK_ECDSA:
+        {
+            /* We need to check the curve family, otherwise the import could
+             * succeed with nonsensical data.
+             * We don't check the bit-size: it's optional in attributes,
+             * and if it's specified, psa_import_key() will know from the key
+             * data length and will check that the bit-size matches. */
+#if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
+            if (psa_type != PSA_KEY_TYPE_ECC_PUBLIC_KEY(pk->ec_family)) {
+                return MBEDTLS_ERR_PK_TYPE_MISMATCH;
+            }
+            key_data = (unsigned char *) pk->pub_raw;
+            key_length = pk->pub_raw_len;
+#else /* MBEDTLS_PK_USE_PSA_EC_DATA */
+            const mbedtls_ecp_keypair *ec = mbedtls_pk_ec_ro(*pk);
+            size_t from_bits = 0;
+            psa_ecc_family_t from_family = mbedtls_ecc_group_to_psa(ec->grp.id,
+                                                                    &from_bits);
+            if (psa_type != PSA_KEY_TYPE_ECC_PUBLIC_KEY(from_family)) {
+                return MBEDTLS_ERR_PK_TYPE_MISMATCH;
+            }
+            int ret = mbedtls_ecp_write_public_key(
+                ec, MBEDTLS_ECP_PF_UNCOMPRESSED,
+                &key_length, key_buffer, sizeof(key_buffer));
+            if (ret < 0) {
+                return ret;
+            }
+            key_data = key_buffer;
+#endif /* MBEDTLS_PK_USE_PSA_EC_DATA */
+            break;
+        }
+#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+        case MBEDTLS_PK_OPAQUE:
+        {
+            psa_key_attributes_t old_attributes = PSA_KEY_ATTRIBUTES_INIT;
+            psa_status_t status =
+                psa_get_key_attributes(pk->priv_id, &old_attributes);
+            if (status != PSA_SUCCESS) {
+                return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+            }
+            psa_key_type_t old_type = psa_get_key_type(&old_attributes);
+            psa_reset_key_attributes(&old_attributes);
+            if (psa_type != PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(old_type)) {
+                return MBEDTLS_ERR_PK_TYPE_MISMATCH;
+            }
+            status = psa_export_public_key(pk->priv_id,
+                                           key_buffer, sizeof(key_buffer),
+                                           &key_length);
+            if (status != PSA_SUCCESS) {
+                return PSA_PK_TO_MBEDTLS_ERR(status);
+            }
+            key_data = key_buffer;
+            break;
+        }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+        default:
+            return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+    }
+
+    return PSA_PK_TO_MBEDTLS_ERR(psa_import_key(attributes,
+                                                key_data, key_length,
+                                                key_id));
+}
+
+int mbedtls_pk_import_into_psa(const mbedtls_pk_context *pk,
+                               const psa_key_attributes_t *attributes,
+                               mbedtls_svc_key_id_t *key_id)
+{
+    /* Set the output immediately so that it won't contain garbage even
+     * if we error out before calling psa_import_key(). */
+    *key_id = MBEDTLS_SVC_KEY_ID_INIT;
+
+#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT)
+    if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_RSA_ALT) {
+        return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
+    }
+#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */
+
+    int want_public = PSA_KEY_TYPE_IS_PUBLIC_KEY(psa_get_key_type(attributes));
+    if (want_public) {
+        return import_public_into_psa(pk, attributes, key_id);
+    } else {
+        return import_pair_into_psa(pk, attributes, key_id);
+    }
+}
 #endif /* MBEDTLS_PSA_CRYPTO_C */
 
 /*
@@ -911,9 +1182,32 @@
     }
 
     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_status_t status;
 
-        status = psa_sign_hash(ctx->priv_id, PSA_ALG_RSA_PSS(psa_md_alg),
+        status = psa_get_key_attributes(ctx->priv_id, &key_attr);
+        if (status != PSA_SUCCESS) {
+            return PSA_PK_RSA_TO_MBEDTLS_ERR(status);
+        }
+        psa_alg = psa_get_key_algorithm(&key_attr);
+        psa_enrollment_alg = psa_get_key_enrollment_algorithm(&key_attr);
+        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)) {
+            sign_alg = psa_enrollment_alg;
+        } else {
+            /* The opaque key has no RSA PSS algorithm associated. */
+            return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+        }
+        /* Adjust the hashing algorithm. */
+        sign_alg = (sign_alg & ~PSA_ALG_HASH_MASK) | PSA_ALG_GET_HASH(psa_md_alg);
+
+        status = psa_sign_hash(ctx->priv_id, sign_alg,
                                hash, hash_len,
                                sig, sig_size, sig_len);
         return PSA_PK_RSA_TO_MBEDTLS_ERR(status);
@@ -1080,124 +1374,4 @@
     return ctx->pk_info->type;
 }
 
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-/*
- * Load the key to a PSA key slot,
- * then turn the PK context into a wrapper for that key slot.
- *
- * Currently only works for EC & RSA private keys.
- */
-int mbedtls_pk_wrap_as_opaque(mbedtls_pk_context *pk,
-                              mbedtls_svc_key_id_t *key,
-                              psa_algorithm_t alg,
-                              psa_key_usage_t usage,
-                              psa_algorithm_t alg2)
-{
-#if !defined(MBEDTLS_PK_HAVE_ECC_KEYS) && !defined(MBEDTLS_RSA_C)
-    ((void) pk);
-    ((void) key);
-    ((void) alg);
-    ((void) usage);
-    ((void) alg2);
-#else /* !MBEDTLS_PK_HAVE_ECC_KEYS && !MBEDTLS_RSA_C */
-#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
-    if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_ECKEY) {
-        size_t d_len;
-        psa_ecc_family_t curve_id;
-        psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-        psa_key_type_t key_type;
-        size_t bits;
-        psa_status_t status;
-
-        /* export the private key material in the format PSA wants */
-#if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
-        unsigned char d[MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH];
-        status = psa_export_key(pk->priv_id, d, sizeof(d), &d_len);
-        if (status != PSA_SUCCESS) {
-            return psa_pk_status_to_mbedtls(status);
-        }
-
-        curve_id = pk->ec_family;
-        bits = pk->ec_bits;
-#else /* MBEDTLS_PK_USE_PSA_EC_DATA */
-        unsigned char d[MBEDTLS_ECP_MAX_BYTES];
-        mbedtls_ecp_keypair *ec = mbedtls_pk_ec_rw(*pk);
-        int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-
-        d_len = PSA_BITS_TO_BYTES(ec->grp.nbits);
-        if ((ret = mbedtls_ecp_write_key(ec, d, d_len)) != 0) {
-            return ret;
-        }
-
-        curve_id = mbedtls_ecc_group_to_psa(ec->grp.id, &bits);
-#endif /* MBEDTLS_PK_USE_PSA_EC_DATA */
-        key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(curve_id);
-
-        /* prepare the key attributes */
-        psa_set_key_type(&attributes, key_type);
-        psa_set_key_bits(&attributes, bits);
-        psa_set_key_usage_flags(&attributes, usage);
-        psa_set_key_algorithm(&attributes, alg);
-        if (alg2 != PSA_ALG_NONE) {
-            psa_set_key_enrollment_algorithm(&attributes, alg2);
-        }
-
-        /* import private key into PSA */
-        status = psa_import_key(&attributes, d, d_len, key);
-        mbedtls_platform_zeroize(d, sizeof(d));
-        if (status != PSA_SUCCESS) {
-            return PSA_PK_TO_MBEDTLS_ERR(status);
-        }
-
-        /* make PK context wrap the key slot */
-        mbedtls_pk_free(pk);
-        mbedtls_pk_init(pk);
-
-        return mbedtls_pk_setup_opaque(pk, *key);
-    } else
-#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
-#if defined(MBEDTLS_RSA_C)
-    if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_RSA) {
-        unsigned char buf[MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES];
-        psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-        int key_len;
-        psa_status_t status;
-
-        /* export the private key material in the format PSA wants */
-        key_len = mbedtls_pk_write_key_der(pk, buf, sizeof(buf));
-        if (key_len <= 0) {
-            return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
-        }
-
-        /* prepare the key attributes */
-        psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
-        psa_set_key_bits(&attributes, mbedtls_pk_get_bitlen(pk));
-        psa_set_key_usage_flags(&attributes, usage);
-        psa_set_key_algorithm(&attributes, alg);
-        if (alg2 != PSA_ALG_NONE) {
-            psa_set_key_enrollment_algorithm(&attributes, alg2);
-        }
-
-        /* import private key into PSA */
-        status = psa_import_key(&attributes,
-                                buf + sizeof(buf) - key_len,
-                                key_len, key);
-
-        mbedtls_platform_zeroize(buf, sizeof(buf));
-
-        if (status != PSA_SUCCESS) {
-            return PSA_PK_TO_MBEDTLS_ERR(status);
-        }
-
-        /* make PK context wrap the key slot */
-        mbedtls_pk_free(pk);
-        mbedtls_pk_init(pk);
-
-        return mbedtls_pk_setup_opaque(pk, *key);
-    } else
-#endif /* MBEDTLS_RSA_C */
-#endif /* !MBEDTLS_PK_HAVE_ECC_KEYS && !MBEDTLS_RSA_C */
-    return MBEDTLS_ERR_PK_TYPE_MISMATCH;
-}
-#endif /* MBEDTLS_USE_PSA_CRYPTO */
 #endif /* MBEDTLS_PK_C */
diff --git a/library/pk_internal.h b/library/pk_internal.h
index da6c7f1..f5924ad 100644
--- a/library/pk_internal.h
+++ b/library/pk_internal.h
@@ -17,7 +17,7 @@
 #include "mbedtls/ecp.h"
 #endif
 
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
 #include "psa/crypto.h"
 
 #include "psa_util_internal.h"
@@ -28,7 +28,7 @@
 #define PSA_PK_ECDSA_TO_MBEDTLS_ERR(status) PSA_TO_MBEDTLS_ERR_LIST(status,   \
                                                                     psa_to_pk_ecdsa_errors,        \
                                                                     psa_pk_status_to_mbedtls)
-#endif /* MBEDTLS_USE_PSA_CRYPTO */
+#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */
 
 /* Headers/footers for PEM files */
 #define PEM_BEGIN_PUBLIC_KEY    "-----BEGIN PUBLIC KEY-----"
diff --git a/library/pk_wrap.c b/library/pk_wrap.c
index 2e00d4a..846175e 100644
--- a/library/pk_wrap.c
+++ b/library/pk_wrap.c
@@ -58,7 +58,7 @@
 static size_t rsa_get_bitlen(mbedtls_pk_context *pk)
 {
     const mbedtls_rsa_context *rsa = (const mbedtls_rsa_context *) pk->pk_ctx;
-    return 8 * mbedtls_rsa_get_len(rsa);
+    return mbedtls_rsa_get_bitlen(rsa);
 }
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
@@ -74,8 +74,7 @@
     int key_len;
     unsigned char buf[MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES];
     unsigned char *p = buf + sizeof(buf);
-    psa_algorithm_t psa_alg_md =
-        PSA_ALG_RSA_PKCS1V15_SIGN(mbedtls_md_psa_alg_from_type(md_alg));
+    psa_algorithm_t psa_alg_md;
     size_t rsa_len = mbedtls_rsa_get_len(rsa);
 
 #if SIZE_MAX > UINT_MAX
@@ -84,6 +83,12 @@
     }
 #endif
 
+    if (mbedtls_rsa_get_padding_mode(rsa) == MBEDTLS_RSA_PKCS_V21) {
+        psa_alg_md = PSA_ALG_RSA_PSS(mbedtls_md_psa_alg_from_type(md_alg));
+    } else {
+        psa_alg_md = PSA_ALG_RSA_PKCS1V15_SIGN(mbedtls_md_psa_alg_from_type(md_alg));
+    }
+
     if (sig_len < rsa_len) {
         return MBEDTLS_ERR_RSA_VERIFY_FAILED;
     }
@@ -235,10 +240,14 @@
     if (psa_md_alg == 0) {
         return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
     }
+    psa_algorithm_t psa_alg;
+    if (mbedtls_rsa_get_padding_mode(mbedtls_pk_rsa(*pk)) == MBEDTLS_RSA_PKCS_V21) {
+        psa_alg = PSA_ALG_RSA_PSS(psa_md_alg);
+    } else {
+        psa_alg = PSA_ALG_RSA_PKCS1V15_SIGN(psa_md_alg);
+    }
 
-    return mbedtls_pk_psa_rsa_sign_ext(PSA_ALG_RSA_PKCS1V15_SIGN(
-                                           psa_md_alg),
-                                       pk->pk_ctx, hash, hash_len,
+    return mbedtls_pk_psa_rsa_sign_ext(psa_alg, pk->pk_ctx, hash, hash_len,
                                        sig, sig_size, sig_len);
 }
 #else /* MBEDTLS_USE_PSA_CRYPTO */
@@ -276,6 +285,7 @@
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
     mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_algorithm_t psa_md_alg, decrypt_alg;
     psa_status_t status;
     int key_len;
     unsigned char buf[MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES];
@@ -284,12 +294,6 @@
     ((void) f_rng);
     ((void) p_rng);
 
-#if !defined(MBEDTLS_RSA_ALT)
-    if (rsa->padding != MBEDTLS_RSA_PKCS_V15) {
-        return MBEDTLS_ERR_RSA_INVALID_PADDING;
-    }
-#endif /* !MBEDTLS_RSA_ALT */
-
     if (ilen != mbedtls_rsa_get_len(rsa)) {
         return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
     }
@@ -301,7 +305,13 @@
 
     psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
     psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);
-    psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PKCS1V15_CRYPT);
+    if (mbedtls_rsa_get_padding_mode(rsa) == MBEDTLS_RSA_PKCS_V21) {
+        psa_md_alg = mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) mbedtls_rsa_get_md_alg(rsa));
+        decrypt_alg = PSA_ALG_RSA_OAEP(psa_md_alg);
+    } else {
+        decrypt_alg = PSA_ALG_RSA_PKCS1V15_CRYPT;
+    }
+    psa_set_key_algorithm(&attributes, decrypt_alg);
 
     status = psa_import_key(&attributes,
                             buf + sizeof(buf) - key_len, key_len,
@@ -311,7 +321,7 @@
         goto cleanup;
     }
 
-    status = psa_asymmetric_decrypt(key_id, PSA_ALG_RSA_PKCS1V15_CRYPT,
+    status = psa_asymmetric_decrypt(key_id, decrypt_alg,
                                     input, ilen,
                                     NULL, 0,
                                     output, osize, olen);
@@ -358,6 +368,7 @@
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
     mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_algorithm_t psa_md_alg;
     psa_status_t status;
     int key_len;
     unsigned char buf[MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES];
@@ -366,12 +377,6 @@
     ((void) f_rng);
     ((void) p_rng);
 
-#if !defined(MBEDTLS_RSA_ALT)
-    if (rsa->padding != MBEDTLS_RSA_PKCS_V15) {
-        return MBEDTLS_ERR_RSA_INVALID_PADDING;
-    }
-#endif
-
     if (mbedtls_rsa_get_len(rsa) > osize) {
         return MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE;
     }
@@ -382,7 +387,12 @@
     }
 
     psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
-    psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PKCS1V15_CRYPT);
+    if (mbedtls_rsa_get_padding_mode(rsa) == MBEDTLS_RSA_PKCS_V21) {
+        psa_md_alg = mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) mbedtls_rsa_get_md_alg(rsa));
+        psa_set_key_algorithm(&attributes, PSA_ALG_RSA_OAEP(psa_md_alg));
+    } else {
+        psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PKCS1V15_CRYPT);
+    }
     psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_PUBLIC_KEY);
 
     status = psa_import_key(&attributes,
diff --git a/library/pkwrite.c b/library/pkwrite.c
index b9ddcf1..5e009c5 100644
--- a/library/pkwrite.c
+++ b/library/pkwrite.c
@@ -202,7 +202,7 @@
         mbedtls_ecp_keypair *ec = mbedtls_pk_ec_rw(*pk);
         byte_length = (ec->grp.pbits + 7) / 8;
 
-        ret = mbedtls_ecp_write_key(ec, tmp, byte_length);
+        ret = mbedtls_ecp_write_key_ext(ec, &byte_length, tmp, sizeof(tmp));
         if (ret != 0) {
             goto exit;
         }
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 4a0666b..ec9d115 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -101,11 +101,6 @@
 
 static psa_global_data_t global_data;
 
-#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
-mbedtls_psa_drbg_context_t *const mbedtls_psa_random_state =
-    &global_data.rng.drbg;
-#endif
-
 #define GUARD_MODULE_INITIALIZED        \
     if (global_data.initialized == 0)  \
     return PSA_ERROR_BAD_STATE;
@@ -568,7 +563,7 @@
     size_t *key_buffer_length, size_t *bits)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
-    psa_key_type_t type = attributes->core.type;
+    psa_key_type_t type = attributes->type;
 
     /* zero-length keys are never supported. */
     if (data_length == 0) {
@@ -578,7 +573,7 @@
     if (key_type_is_raw_bytes(type)) {
         *bits = PSA_BYTES_TO_BITS(data_length);
 
-        status = psa_validate_unstructured_key_bit_size(attributes->core.type,
+        status = psa_validate_unstructured_key_bit_size(attributes->type,
                                                         *bits);
         if (status != PSA_SUCCESS) {
             return status;
@@ -909,8 +904,13 @@
  * into a key slot if not already done.
  *
  * On success, the returned key slot has been registered for reading.
- * It is the responsibility of the caller to call psa_unregister_read(slot)
- * when they have finished reading the contents of the slot.
+ * It is the responsibility of the caller to then unregister
+ * once they have finished reading the contents of the slot.
+ * The caller unregisters by calling psa_unregister_read() or
+ * psa_unregister_read_under_mutex(). psa_unregister_read() must be called
+ * if and only if the caller already holds the global key slot mutex
+ * (when mutexes are enabled). psa_unregister_read_under_mutex() encapsulates
+ * the unregister with mutex lock and unlock operations.
  */
 static psa_status_t psa_get_and_lock_key_slot_with_policy(
     mbedtls_svc_key_id_t key,
@@ -954,7 +954,7 @@
 
 error:
     *p_slot = NULL;
-    psa_unregister_read(slot);
+    psa_unregister_read_under_mutex(slot);
 
     return status;
 }
@@ -970,8 +970,13 @@
  * for a cryptographic operation.
  *
  * On success, the returned key slot has been registered for reading.
- * It is the responsibility of the caller to call psa_unregister_read(slot)
- * when they have finished reading the contents of the slot.
+ * It is the responsibility of the caller to then unregister
+ * once they have finished reading the contents of the slot.
+ * The caller unregisters by calling psa_unregister_read() or
+ * psa_unregister_read_under_mutex(). psa_unregister_read() must be called
+ * if and only if the caller already holds the global key slot mutex
+ * (when mutexes are enabled). psa_unregister_read_under_mutex() encapsulates
+ * psa_unregister_read() with mutex lock and unlock operations.
  */
 static psa_status_t psa_get_and_lock_transparent_key_slot_with_policy(
     mbedtls_svc_key_id_t key,
@@ -986,7 +991,7 @@
     }
 
     if (psa_key_lifetime_is_external((*p_slot)->attr.lifetime)) {
-        psa_unregister_read(*p_slot);
+        psa_unregister_read_under_mutex(*p_slot);
         *p_slot = NULL;
         return PSA_ERROR_NOT_SUPPORTED;
     }
@@ -1096,6 +1101,17 @@
      * fully destroyed. */
     PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_lock(
                                     &mbedtls_threading_key_slot_mutex));
+
+    if (slot->state == PSA_SLOT_PENDING_DELETION) {
+        /* Another thread has destroyed the key between us locking the slot
+         * and us gaining the mutex. Unregister from the slot,
+         * and report that the key does not exist. */
+        status = psa_unregister_read(slot);
+
+        PSA_THREADING_CHK_RET(mbedtls_mutex_unlock(
+                                  &mbedtls_threading_key_slot_mutex));
+        return (status == PSA_SUCCESS) ? PSA_ERROR_INVALID_HANDLE : status;
+    }
 #endif
     /* Set the key slot containing the key description's state to
      * PENDING_DELETION. This stops new operations from registering
@@ -1105,10 +1121,10 @@
      * If the key is persistent, we can now delete the copy of the key
      * from memory. If the key is opaque, we require the driver to
      * deal with the deletion. */
-    status = psa_key_slot_state_transition(slot, PSA_SLOT_FULL,
-                                           PSA_SLOT_PENDING_DELETION);
+    overall_status = psa_key_slot_state_transition(slot, PSA_SLOT_FULL,
+                                                   PSA_SLOT_PENDING_DELETION);
 
-    if (status != PSA_SUCCESS) {
+    if (overall_status != PSA_SUCCESS) {
         goto exit;
     }
 
@@ -1201,58 +1217,12 @@
     return overall_status;
 }
 
-#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT) || \
-    defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY)
-static psa_status_t psa_get_rsa_public_exponent(
-    const mbedtls_rsa_context *rsa,
-    psa_key_attributes_t *attributes)
-{
-    mbedtls_mpi mpi;
-    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    uint8_t *buffer = NULL;
-    size_t buflen;
-    mbedtls_mpi_init(&mpi);
-
-    ret = mbedtls_rsa_export(rsa, NULL, NULL, NULL, NULL, &mpi);
-    if (ret != 0) {
-        goto exit;
-    }
-    if (mbedtls_mpi_cmp_int(&mpi, 65537) == 0) {
-        /* It's the default value, which is reported as an empty string,
-         * so there's nothing to do. */
-        goto exit;
-    }
-
-    buflen = mbedtls_mpi_size(&mpi);
-    buffer = mbedtls_calloc(1, buflen);
-    if (buffer == NULL) {
-        ret = MBEDTLS_ERR_MPI_ALLOC_FAILED;
-        goto exit;
-    }
-    ret = mbedtls_mpi_write_binary(&mpi, buffer, buflen);
-    if (ret != 0) {
-        goto exit;
-    }
-    attributes->domain_parameters = buffer;
-    attributes->domain_parameters_size = buflen;
-
-exit:
-    mbedtls_mpi_free(&mpi);
-    if (ret != 0) {
-        mbedtls_free(buffer);
-    }
-    return mbedtls_to_psa_error(ret);
-}
-#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT) ||
-        * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) */
-
 /** Retrieve all the publicly-accessible attributes of a key.
  */
 psa_status_t psa_get_key_attributes(mbedtls_svc_key_id_t key,
                                     psa_key_attributes_t *attributes)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
-    psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot;
 
     psa_reset_key_attributes(attributes);
@@ -1262,9 +1232,7 @@
         return status;
     }
 
-    attributes->core = slot->attr;
-    attributes->core.flags &= (MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY |
-                               MBEDTLS_PSA_KA_MASK_DUAL_USE);
+    *attributes = slot->attr;
 
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
     if (psa_get_se_driver_entry(slot->attr.lifetime) != NULL) {
@@ -1273,55 +1241,7 @@
     }
 #endif /* MBEDTLS_PSA_CRYPTO_SE_C */
 
-    switch (slot->attr.type) {
-#if (defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_IMPORT) && \
-    defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT)) || \
-    defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY)
-        case PSA_KEY_TYPE_RSA_KEY_PAIR:
-        case PSA_KEY_TYPE_RSA_PUBLIC_KEY:
-            /* TODO: This is a temporary situation where domain parameters are deprecated,
-             * but we need it for namely generating an RSA key with a non-default exponent.
-             * This would be improved after https://github.com/Mbed-TLS/mbedtls/issues/6494.
-             */
-            if (!psa_key_lifetime_is_external(slot->attr.lifetime)) {
-                mbedtls_rsa_context *rsa = NULL;
-
-                status = mbedtls_psa_rsa_load_representation(
-                    slot->attr.type,
-                    slot->key.data,
-                    slot->key.bytes,
-                    &rsa);
-                if (status != PSA_SUCCESS) {
-                    break;
-                }
-
-                status = psa_get_rsa_public_exponent(rsa,
-                                                     attributes);
-                mbedtls_rsa_free(rsa);
-                mbedtls_free(rsa);
-            }
-            break;
-#else
-        case PSA_KEY_TYPE_RSA_KEY_PAIR:
-        case PSA_KEY_TYPE_RSA_PUBLIC_KEY:
-            attributes->domain_parameters = NULL;
-            attributes->domain_parameters_size = SIZE_MAX;
-            break;
-#endif /* (defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_IMPORT) && \
-        * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT)) ||
-        * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) */
-        default:
-            /* Nothing else to do. */
-            break;
-    }
-
-    if (status != PSA_SUCCESS) {
-        psa_reset_key_attributes(attributes);
-    }
-
-    unlock_status = psa_unregister_read(slot);
-
-    return (status == PSA_SUCCESS) ? unlock_status : status;
+    return psa_unregister_read_under_mutex(slot);
 }
 
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
@@ -1329,7 +1249,7 @@
     const psa_key_attributes_t *attributes,
     psa_key_slot_number_t *slot_number)
 {
-    if (attributes->core.flags & MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER) {
+    if (attributes->has_slot_number) {
         *slot_number = attributes->slot_number;
         return PSA_SUCCESS;
     } else {
@@ -1359,7 +1279,7 @@
     const uint8_t *key_buffer, size_t key_buffer_size,
     uint8_t *data, size_t data_size, size_t *data_length)
 {
-    psa_key_type_t type = attributes->core.type;
+    psa_key_type_t type = attributes->type;
 
     if (key_type_is_raw_bytes(type) ||
         PSA_KEY_TYPE_IS_RSA(type)   ||
@@ -1408,14 +1328,11 @@
         return status;
     }
 
-    psa_key_attributes_t attributes = {
-        .core = slot->attr
-    };
-    status = psa_driver_wrapper_export_key(&attributes,
+    status = psa_driver_wrapper_export_key(&slot->attr,
                                            slot->key.data, slot->key.bytes,
                                            data, data_size, data_length);
 
-    unlock_status = psa_unregister_read(slot);
+    unlock_status = psa_unregister_read_under_mutex(slot);
 
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
@@ -1428,7 +1345,7 @@
     size_t data_size,
     size_t *data_length)
 {
-    psa_key_type_t type = attributes->core.type;
+    psa_key_type_t type = attributes->type;
 
     if (PSA_KEY_TYPE_IS_PUBLIC_KEY(type) &&
         (PSA_KEY_TYPE_IS_RSA(type) || PSA_KEY_TYPE_IS_ECC(type) ||
@@ -1495,7 +1412,6 @@
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot;
-    psa_key_attributes_t attributes;
 
     /* Reject a zero-length output buffer now, since this can never be a
      * valid key representation. This way we know that data must be a valid
@@ -1521,29 +1437,16 @@
         goto exit;
     }
 
-    attributes = (psa_key_attributes_t) {
-        .core = slot->attr
-    };
     status = psa_driver_wrapper_export_public_key(
-        &attributes, slot->key.data, slot->key.bytes,
+        &slot->attr, slot->key.data, slot->key.bytes,
         data, data_size, data_length);
 
 exit:
-    unlock_status = psa_unregister_read(slot);
+    unlock_status = psa_unregister_read_under_mutex(slot);
 
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
 
-MBEDTLS_STATIC_ASSERT(
-    (MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY & MBEDTLS_PSA_KA_MASK_DUAL_USE) == 0,
-    "One or more key attribute flag is listed as both external-only and dual-use")
-MBEDTLS_STATIC_ASSERT(
-    (PSA_KA_MASK_INTERNAL_ONLY & MBEDTLS_PSA_KA_MASK_DUAL_USE) == 0,
-    "One or more key attribute flag is listed as both internal-only and dual-use")
-MBEDTLS_STATIC_ASSERT(
-    (PSA_KA_MASK_INTERNAL_ONLY & MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY) == 0,
-    "One or more key attribute flag is listed as both internal-only and external-only")
-
 /** Validate that a key policy is internally well-formed.
  *
  * This function only rejects invalid policies. It does not validate the
@@ -1609,7 +1512,7 @@
         }
     }
 
-    status = psa_validate_key_policy(&attributes->core.policy);
+    status = psa_validate_key_policy(&attributes->policy);
     if (status != PSA_SUCCESS) {
         return status;
     }
@@ -1622,12 +1525,6 @@
         return PSA_ERROR_NOT_SUPPORTED;
     }
 
-    /* Reject invalid flags. These should not be reachable through the API. */
-    if (attributes->core.flags & ~(MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY |
-                                   MBEDTLS_PSA_KA_MASK_DUAL_USE)) {
-        return PSA_ERROR_INVALID_ARGUMENT;
-    }
-
     return PSA_SUCCESS;
 }
 
@@ -1679,7 +1576,15 @@
         return status;
     }
 
+#if defined(MBEDTLS_THREADING_C)
+    PSA_THREADING_CHK_RET(mbedtls_mutex_lock(
+                              &mbedtls_threading_key_slot_mutex));
+#endif
     status = psa_reserve_free_key_slot(&volatile_key_id, p_slot);
+#if defined(MBEDTLS_THREADING_C)
+    PSA_THREADING_CHK_RET(mbedtls_mutex_unlock(
+                              &mbedtls_threading_key_slot_mutex));
+#endif
     if (status != PSA_SUCCESS) {
         return status;
     }
@@ -1693,7 +1598,7 @@
      * volatile key identifier associated to the slot returned to contain its
      * definition. */
 
-    slot->attr = attributes->core;
+    slot->attr = *attributes;
     if (PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) {
 #if !defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER)
         slot->attr.id = volatile_key_id;
@@ -1702,13 +1607,6 @@
 #endif
     }
 
-    /* Erase external-only flags from the internal copy. To access
-     * external-only flags, query `attributes`. Thanks to the check
-     * in psa_validate_key_attributes(), this leaves the dual-use
-     * flags and any internal flag that psa_reserve_free_key_slot()
-     * may have set. */
-    slot->attr.flags &= ~MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY;
-
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
     /* For a key in a secure element, we need to do three things
      * when creating or registering a persistent key:
@@ -1735,7 +1633,7 @@
             return status;
         }
 
-        if (!PSA_KEY_LIFETIME_IS_VOLATILE(attributes->core.lifetime)) {
+        if (!PSA_KEY_LIFETIME_IS_VOLATILE(attributes->lifetime)) {
             psa_crypto_prepare_transaction(PSA_CRYPTO_TRANSACTION_CREATE_KEY);
             psa_crypto_transaction.key.lifetime = slot->attr.lifetime;
             psa_crypto_transaction.key.slot = slot_number;
@@ -1799,6 +1697,11 @@
     (void) slot;
     (void) driver;
 
+#if defined(MBEDTLS_THREADING_C)
+    PSA_THREADING_CHK_RET(mbedtls_mutex_lock(
+                              &mbedtls_threading_key_slot_mutex));
+#endif
+
 #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
     if (!PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) {
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
@@ -1838,6 +1741,11 @@
         status = psa_save_se_persistent_data(driver);
         if (status != PSA_SUCCESS) {
             psa_destroy_persistent_key(slot->attr.id);
+
+#if defined(MBEDTLS_THREADING_C)
+            PSA_THREADING_CHK_RET(mbedtls_mutex_unlock(
+                                      &mbedtls_threading_key_slot_mutex));
+#endif
             return status;
         }
         status = psa_crypto_stop_transaction();
@@ -1853,6 +1761,10 @@
         }
     }
 
+#if defined(MBEDTLS_THREADING_C)
+    PSA_THREADING_CHK_RET(mbedtls_mutex_unlock(
+                              &mbedtls_threading_key_slot_mutex));
+#endif
     return status;
 }
 
@@ -1877,6 +1789,13 @@
         return;
     }
 
+#if defined(MBEDTLS_THREADING_C)
+    /* If the lock operation fails we still wipe the slot.
+     * Operations will no longer work after a failed lock,
+     * but we still need to wipe the slot of confidential data. */
+    mbedtls_mutex_lock(&mbedtls_threading_key_slot_mutex);
+#endif
+
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
     /* TODO: If the key has already been created in the secure
      * element, and the failure happened later (when saving metadata
@@ -1895,6 +1814,10 @@
 #endif /* MBEDTLS_PSA_CRYPTO_SE_C */
 
     psa_wipe_key_slot(slot);
+
+#if defined(MBEDTLS_THREADING_C)
+    mbedtls_mutex_unlock(&mbedtls_threading_key_slot_mutex);
+#endif
 }
 
 /** Validate optional attributes during key creation.
@@ -1910,65 +1833,14 @@
     const psa_key_slot_t *slot,
     const psa_key_attributes_t *attributes)
 {
-    if (attributes->core.type != 0) {
-        if (attributes->core.type != slot->attr.type) {
+    if (attributes->type != 0) {
+        if (attributes->type != slot->attr.type) {
             return PSA_ERROR_INVALID_ARGUMENT;
         }
     }
 
-    if (attributes->domain_parameters_size != 0) {
-#if (defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_IMPORT) && \
-        defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT)) || \
-        defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY)
-        if (PSA_KEY_TYPE_IS_RSA(slot->attr.type)) {
-            mbedtls_rsa_context *rsa = NULL;
-            mbedtls_mpi actual, required;
-            int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-
-            psa_status_t status = mbedtls_psa_rsa_load_representation(
-                slot->attr.type,
-                slot->key.data,
-                slot->key.bytes,
-                &rsa);
-            if (status != PSA_SUCCESS) {
-                return status;
-            }
-
-            mbedtls_mpi_init(&actual);
-            mbedtls_mpi_init(&required);
-            ret = mbedtls_rsa_export(rsa,
-                                     NULL, NULL, NULL, NULL, &actual);
-            mbedtls_rsa_free(rsa);
-            mbedtls_free(rsa);
-            if (ret != 0) {
-                goto rsa_exit;
-            }
-            ret = mbedtls_mpi_read_binary(&required,
-                                          attributes->domain_parameters,
-                                          attributes->domain_parameters_size);
-            if (ret != 0) {
-                goto rsa_exit;
-            }
-            if (mbedtls_mpi_cmp_mpi(&actual, &required) != 0) {
-                ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
-            }
-rsa_exit:
-            mbedtls_mpi_free(&actual);
-            mbedtls_mpi_free(&required);
-            if (ret != 0) {
-                return mbedtls_to_psa_error(ret);
-            }
-        } else
-#endif /* (defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_IMPORT) &&
-        *  defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT)) ||
-        * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) */
-        {
-            return PSA_ERROR_INVALID_ARGUMENT;
-        }
-    }
-
-    if (attributes->core.bits != 0) {
-        if (attributes->core.bits != slot->attr.bits) {
+    if (attributes->bits != 0) {
+        if (attributes->bits != slot->attr.bits) {
             return PSA_ERROR_INVALID_ARGUMENT;
         }
     }
@@ -2012,7 +1884,7 @@
      * with storage ( MBEDTLS_PSA_CRYPTO_SE_C ) ),we have to allocate a
      * buffer to hold the imported key material. */
     if (slot->key.data == NULL) {
-        if (psa_key_lifetime_is_external(attributes->core.lifetime)) {
+        if (psa_key_lifetime_is_external(attributes->lifetime)) {
             status = psa_driver_wrapper_get_key_buffer_size_from_key_data(
                 attributes, data, data_length, &storage_size);
             if (status != PSA_SUCCESS) {
@@ -2132,12 +2004,12 @@
      * equal to the ones of the source key. So it is safe to inherit
      * them from the source key now."
      * */
-    actual_attributes.core.bits = source_slot->attr.bits;
-    actual_attributes.core.type = source_slot->attr.type;
+    actual_attributes.bits = source_slot->attr.bits;
+    actual_attributes.type = source_slot->attr.type;
 
 
     status = psa_restrict_key_policy(source_slot->attr.type,
-                                     &actual_attributes.core.policy,
+                                     &actual_attributes.policy,
                                      &source_slot->attr.policy);
     if (status != PSA_SUCCESS) {
         goto exit;
@@ -2166,7 +2038,7 @@
      * - For opaque keys this translates to an invocation of the drivers'
      *   copy_key entry point through the dispatch layer.
      * */
-    if (psa_key_lifetime_is_external(actual_attributes.core.lifetime)) {
+    if (psa_key_lifetime_is_external(actual_attributes.lifetime)) {
         status = psa_driver_wrapper_get_key_buffer_size(&actual_attributes,
                                                         &storage_size);
         if (status != PSA_SUCCESS) {
@@ -2201,7 +2073,7 @@
         psa_fail_key_creation(target_slot, driver);
     }
 
-    unlock_status = psa_unregister_read(source_slot);
+    unlock_status = psa_unregister_read_under_mutex(source_slot);
 
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
@@ -2474,7 +2346,6 @@
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot = NULL;
-    psa_key_attributes_t attributes;
 
     /* A context must be freshly initialized before it can be set up. */
     if (operation->id != 0) {
@@ -2491,11 +2362,7 @@
         goto exit;
     }
 
-    attributes = (psa_key_attributes_t) {
-        .core = slot->attr
-    };
-
-    status = psa_mac_finalize_alg_and_key_validation(alg, &attributes,
+    status = psa_mac_finalize_alg_and_key_validation(alg, &slot->attr,
                                                      &operation->mac_size);
     if (status != PSA_SUCCESS) {
         goto exit;
@@ -2505,13 +2372,13 @@
     /* Dispatch the MAC setup call with validated input */
     if (is_sign) {
         status = psa_driver_wrapper_mac_sign_setup(operation,
-                                                   &attributes,
+                                                   &slot->attr,
                                                    slot->key.data,
                                                    slot->key.bytes,
                                                    alg);
     } else {
         status = psa_driver_wrapper_mac_verify_setup(operation,
-                                                     &attributes,
+                                                     &slot->attr,
                                                      slot->key.data,
                                                      slot->key.bytes,
                                                      alg);
@@ -2522,7 +2389,7 @@
         psa_mac_abort(operation);
     }
 
-    unlock_status = psa_unregister_read(slot);
+    unlock_status = psa_unregister_read_under_mutex(slot);
 
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
@@ -2661,7 +2528,6 @@
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot;
     uint8_t operation_mac_size = 0;
-    psa_key_attributes_t attributes;
 
     status = psa_get_and_lock_key_slot_with_policy(
         key,
@@ -2672,11 +2538,7 @@
         goto exit;
     }
 
-    attributes = (psa_key_attributes_t) {
-        .core = slot->attr
-    };
-
-    status = psa_mac_finalize_alg_and_key_validation(alg, &attributes,
+    status = psa_mac_finalize_alg_and_key_validation(alg, &slot->attr,
                                                      &operation_mac_size);
     if (status != PSA_SUCCESS) {
         goto exit;
@@ -2688,7 +2550,7 @@
     }
 
     status = psa_driver_wrapper_mac_compute(
-        &attributes,
+        &slot->attr,
         slot->key.data, slot->key.bytes,
         alg,
         input, input_length,
@@ -2708,7 +2570,7 @@
 
     psa_wipe_tag_output_buffer(mac, status, mac_size, *mac_length);
 
-    unlock_status = psa_unregister_read(slot);
+    unlock_status = psa_unregister_read_under_mutex(slot);
 
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
@@ -2798,7 +2660,6 @@
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot;
-    psa_key_attributes_t attributes;
 
     *signature_length = 0;
 
@@ -2830,19 +2691,15 @@
         goto exit;
     }
 
-    attributes = (psa_key_attributes_t) {
-        .core = slot->attr
-    };
-
     if (input_is_message) {
         status = psa_driver_wrapper_sign_message(
-            &attributes, slot->key.data, slot->key.bytes,
+            &slot->attr, slot->key.data, slot->key.bytes,
             alg, input, input_length,
             signature, signature_size, signature_length);
     } else {
 
         status = psa_driver_wrapper_sign_hash(
-            &attributes, slot->key.data, slot->key.bytes,
+            &slot->attr, slot->key.data, slot->key.bytes,
             alg, input, input_length,
             signature, signature_size, signature_length);
     }
@@ -2852,7 +2709,7 @@
     psa_wipe_tag_output_buffer(signature, status, signature_size,
                                *signature_length);
 
-    unlock_status = psa_unregister_read(slot);
+    unlock_status = psa_unregister_read_under_mutex(slot);
 
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
@@ -2884,23 +2741,19 @@
         return status;
     }
 
-    psa_key_attributes_t attributes = {
-        .core = slot->attr
-    };
-
     if (input_is_message) {
         status = psa_driver_wrapper_verify_message(
-            &attributes, slot->key.data, slot->key.bytes,
+            &slot->attr, slot->key.data, slot->key.bytes,
             alg, input, input_length,
             signature, signature_length);
     } else {
         status = psa_driver_wrapper_verify_hash(
-            &attributes, slot->key.data, slot->key.bytes,
+            &slot->attr, slot->key.data, slot->key.bytes,
             alg, input, input_length,
             signature, signature_length);
     }
 
-    unlock_status = psa_unregister_read(slot);
+    unlock_status = psa_unregister_read_under_mutex(slot);
 
     return (status == PSA_SUCCESS) ? unlock_status : status;
 
@@ -3006,7 +2859,7 @@
     psa_algorithm_t alg, const uint8_t *hash, size_t hash_length,
     uint8_t *signature, size_t signature_size, size_t *signature_length)
 {
-    if (attributes->core.type == PSA_KEY_TYPE_RSA_KEY_PAIR) {
+    if (attributes->type == PSA_KEY_TYPE_RSA_KEY_PAIR) {
         if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) ||
             PSA_ALG_IS_RSA_PSS(alg)) {
 #if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) || \
@@ -3021,7 +2874,7 @@
         } else {
             return PSA_ERROR_INVALID_ARGUMENT;
         }
-    } else if (PSA_KEY_TYPE_IS_ECC(attributes->core.type)) {
+    } else if (PSA_KEY_TYPE_IS_ECC(attributes->type)) {
         if (PSA_ALG_IS_ECDSA(alg)) {
 #if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
             defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)
@@ -3067,7 +2920,7 @@
     psa_algorithm_t alg, const uint8_t *hash, size_t hash_length,
     const uint8_t *signature, size_t signature_length)
 {
-    if (PSA_KEY_TYPE_IS_RSA(attributes->core.type)) {
+    if (PSA_KEY_TYPE_IS_RSA(attributes->type)) {
         if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) ||
             PSA_ALG_IS_RSA_PSS(alg)) {
 #if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) || \
@@ -3082,7 +2935,7 @@
         } else {
             return PSA_ERROR_INVALID_ARGUMENT;
         }
-    } else if (PSA_KEY_TYPE_IS_ECC(attributes->core.type)) {
+    } else if (PSA_KEY_TYPE_IS_ECC(attributes->type)) {
         if (PSA_ALG_IS_ECDSA(alg)) {
 #if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
             defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)
@@ -3133,7 +2986,6 @@
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot;
-    psa_key_attributes_t attributes;
 
     (void) input;
     (void) input_length;
@@ -3158,16 +3010,12 @@
         goto exit;
     }
 
-    attributes = (psa_key_attributes_t) {
-        .core = slot->attr
-    };
-
     status = psa_driver_wrapper_asymmetric_encrypt(
-        &attributes, slot->key.data, slot->key.bytes,
+        &slot->attr, slot->key.data, slot->key.bytes,
         alg, input, input_length, salt, salt_length,
         output, output_size, output_length);
 exit:
-    unlock_status = psa_unregister_read(slot);
+    unlock_status = psa_unregister_read_under_mutex(slot);
 
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
@@ -3185,7 +3033,6 @@
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot;
-    psa_key_attributes_t attributes;
 
     (void) input;
     (void) input_length;
@@ -3209,17 +3056,13 @@
         goto exit;
     }
 
-    attributes = (psa_key_attributes_t) {
-        .core = slot->attr
-    };
-
     status = psa_driver_wrapper_asymmetric_decrypt(
-        &attributes, slot->key.data, slot->key.bytes,
+        &slot->attr, slot->key.data, slot->key.bytes,
         alg, input, input_length, salt, salt_length,
         output, output_size, output_length);
 
 exit:
-    unlock_status = psa_unregister_read(slot);
+    unlock_status = psa_unregister_read_under_mutex(slot);
 
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
@@ -3283,7 +3126,6 @@
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot;
-    psa_key_attributes_t attributes;
 
     /* Check that start has not been previously called, or operation has not
      * previously errored. */
@@ -3310,14 +3152,10 @@
         goto exit;
     }
 
-    attributes = (psa_key_attributes_t) {
-        .core = slot->attr
-    };
-
     /* Ensure ops count gets reset, in case of operation re-use. */
     operation->num_ops = 0;
 
-    status = psa_driver_wrapper_sign_hash_start(operation, &attributes,
+    status = psa_driver_wrapper_sign_hash_start(operation, &slot->attr,
                                                 slot->key.data,
                                                 slot->key.bytes, alg,
                                                 hash, hash_length);
@@ -3328,7 +3166,7 @@
         psa_sign_hash_abort_internal(operation);
     }
 
-    unlock_status = psa_unregister_read(slot);
+    unlock_status = psa_unregister_read_under_mutex(slot);
 
     if (unlock_status != PSA_SUCCESS) {
         operation->error_occurred = 1;
@@ -3455,14 +3293,10 @@
         return status;
     }
 
-    psa_key_attributes_t attributes = {
-        .core = slot->attr
-    };
-
     /* Ensure ops count gets reset, in case of operation re-use. */
     operation->num_ops = 0;
 
-    status = psa_driver_wrapper_verify_hash_start(operation, &attributes,
+    status = psa_driver_wrapper_verify_hash_start(operation, &slot->attr,
                                                   slot->key.data,
                                                   slot->key.bytes,
                                                   alg, hash, hash_length,
@@ -3473,7 +3307,7 @@
         psa_verify_hash_abort_internal(operation);
     }
 
-    unlock_status = psa_unregister_read(slot);
+    unlock_status = psa_unregister_read_under_mutex(slot);
 
     if (unlock_status != PSA_SUCCESS) {
         operation->error_occurred = 1;
@@ -3597,7 +3431,7 @@
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     size_t required_hash_length;
 
-    if (!PSA_KEY_TYPE_IS_ECC(attributes->core.type)) {
+    if (!PSA_KEY_TYPE_IS_ECC(attributes->type)) {
         return PSA_ERROR_NOT_SUPPORTED;
     }
 
@@ -3614,8 +3448,8 @@
     /* Ensure num_ops is zero'ed in case of context re-use. */
     operation->num_ops = 0;
 
-    status = mbedtls_psa_ecp_load_representation(attributes->core.type,
-                                                 attributes->core.bits,
+    status = mbedtls_psa_ecp_load_representation(attributes->type,
+                                                 attributes->bits,
                                                  key_buffer,
                                                  key_buffer_size,
                                                  &operation->ctx);
@@ -3813,7 +3647,7 @@
     size_t coordinate_bytes = 0;
     size_t required_hash_length = 0;
 
-    if (!PSA_KEY_TYPE_IS_ECC(attributes->core.type)) {
+    if (!PSA_KEY_TYPE_IS_ECC(attributes->type)) {
         return PSA_ERROR_NOT_SUPPORTED;
     }
 
@@ -3832,8 +3666,8 @@
     /* Ensure num_ops is zero'ed in case of context re-use. */
     operation->num_ops = 0;
 
-    status = mbedtls_psa_ecp_load_representation(attributes->core.type,
-                                                 attributes->core.bits,
+    status = mbedtls_psa_ecp_load_representation(attributes->type,
+                                                 attributes->bits,
                                                  key_buffer,
                                                  key_buffer_size,
                                                  &operation->ctx);
@@ -3991,7 +3825,6 @@
     psa_key_usage_t usage = (cipher_operation == MBEDTLS_ENCRYPT ?
                              PSA_KEY_USAGE_ENCRYPT :
                              PSA_KEY_USAGE_DECRYPT);
-    psa_key_attributes_t attributes;
 
     /* A context must be freshly initialized before it can be set up. */
     if (operation->id != 0) {
@@ -4021,20 +3854,16 @@
     }
     operation->default_iv_length = PSA_CIPHER_IV_LENGTH(slot->attr.type, alg);
 
-    attributes = (psa_key_attributes_t) {
-        .core = slot->attr
-    };
-
     /* Try doing the operation through a driver before using software fallback. */
     if (cipher_operation == MBEDTLS_ENCRYPT) {
         status = psa_driver_wrapper_cipher_encrypt_setup(operation,
-                                                         &attributes,
+                                                         &slot->attr,
                                                          slot->key.data,
                                                          slot->key.bytes,
                                                          alg);
     } else {
         status = psa_driver_wrapper_cipher_decrypt_setup(operation,
-                                                         &attributes,
+                                                         &slot->attr,
                                                          slot->key.data,
                                                          slot->key.bytes,
                                                          alg);
@@ -4045,7 +3874,7 @@
         psa_cipher_abort(operation);
     }
 
-    unlock_status = psa_unregister_read(slot);
+    unlock_status = psa_unregister_read_under_mutex(slot);
 
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
@@ -4247,7 +4076,6 @@
     psa_key_slot_t *slot = NULL;
     uint8_t local_iv[PSA_CIPHER_IV_MAX_SIZE];
     size_t default_iv_length = 0;
-    psa_key_attributes_t attributes;
 
     if (!PSA_ALG_IS_CIPHER(alg)) {
         status = PSA_ERROR_INVALID_ARGUMENT;
@@ -4261,10 +4089,6 @@
         goto exit;
     }
 
-    attributes = (psa_key_attributes_t) {
-        .core = slot->attr
-    };
-
     default_iv_length = PSA_CIPHER_IV_LENGTH(slot->attr.type, alg);
     if (default_iv_length > PSA_CIPHER_IV_MAX_SIZE) {
         status = PSA_ERROR_GENERIC_ERROR;
@@ -4284,13 +4108,13 @@
     }
 
     status = psa_driver_wrapper_cipher_encrypt(
-        &attributes, slot->key.data, slot->key.bytes,
+        &slot->attr, slot->key.data, slot->key.bytes,
         alg, local_iv, default_iv_length, input, input_length,
         psa_crypto_buffer_offset(output, default_iv_length),
         output_size - default_iv_length, output_length);
 
 exit:
-    unlock_status = psa_unregister_read(slot);
+    unlock_status = psa_unregister_read_under_mutex(slot);
     if (status == PSA_SUCCESS) {
         status = unlock_status;
     }
@@ -4318,7 +4142,6 @@
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot = NULL;
-    psa_key_attributes_t attributes;
 
     if (!PSA_ALG_IS_CIPHER(alg)) {
         status = PSA_ERROR_INVALID_ARGUMENT;
@@ -4332,10 +4155,6 @@
         goto exit;
     }
 
-    attributes = (psa_key_attributes_t) {
-        .core = slot->attr
-    };
-
     if (alg == PSA_ALG_CCM_STAR_NO_TAG &&
         input_length < PSA_BLOCK_CIPHER_BLOCK_LENGTH(slot->attr.type)) {
         status = PSA_ERROR_INVALID_ARGUMENT;
@@ -4346,12 +4165,12 @@
     }
 
     status = psa_driver_wrapper_cipher_decrypt(
-        &attributes, slot->key.data, slot->key.bytes,
+        &slot->attr, slot->key.data, slot->key.bytes,
         alg, input, input_length,
         output, output_size, output_length);
 
 exit:
-    unlock_status = psa_unregister_read(slot);
+    unlock_status = psa_unregister_read_under_mutex(slot);
     if (status == PSA_SUCCESS) {
         status = unlock_status;
     }
@@ -4455,17 +4274,13 @@
         return status;
     }
 
-    psa_key_attributes_t attributes = {
-        .core = slot->attr
-    };
-
     status = psa_aead_check_nonce_length(alg, nonce_length);
     if (status != PSA_SUCCESS) {
         goto exit;
     }
 
     status = psa_driver_wrapper_aead_encrypt(
-        &attributes, slot->key.data, slot->key.bytes,
+        &slot->attr, slot->key.data, slot->key.bytes,
         alg,
         nonce, nonce_length,
         additional_data, additional_data_length,
@@ -4477,7 +4292,7 @@
     }
 
 exit:
-    psa_unregister_read(slot);
+    psa_unregister_read_under_mutex(slot);
 
     return status;
 }
@@ -4510,17 +4325,13 @@
         return status;
     }
 
-    psa_key_attributes_t attributes = {
-        .core = slot->attr
-    };
-
     status = psa_aead_check_nonce_length(alg, nonce_length);
     if (status != PSA_SUCCESS) {
         goto exit;
     }
 
     status = psa_driver_wrapper_aead_decrypt(
-        &attributes, slot->key.data, slot->key.bytes,
+        &slot->attr, slot->key.data, slot->key.bytes,
         alg,
         nonce, nonce_length,
         additional_data, additional_data_length,
@@ -4532,7 +4343,7 @@
     }
 
 exit:
-    psa_unregister_read(slot);
+    psa_unregister_read_under_mutex(slot);
 
     return status;
 }
@@ -4586,7 +4397,6 @@
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot = NULL;
     psa_key_usage_t key_usage = 0;
-    psa_key_attributes_t attributes;
 
     status = psa_aead_check_algorithm(alg);
     if (status != PSA_SUCCESS) {
@@ -4616,23 +4426,19 @@
         goto exit;
     }
 
-    attributes = (psa_key_attributes_t) {
-        .core = slot->attr
-    };
-
     if ((status = psa_validate_tag_length(alg)) != PSA_SUCCESS) {
         goto exit;
     }
 
     if (is_encrypt) {
         status = psa_driver_wrapper_aead_encrypt_setup(operation,
-                                                       &attributes,
+                                                       &slot->attr,
                                                        slot->key.data,
                                                        slot->key.bytes,
                                                        alg);
     } else {
         status = psa_driver_wrapper_aead_decrypt_setup(operation,
-                                                       &attributes,
+                                                       &slot->attr,
                                                        slot->key.data,
                                                        slot->key.bytes,
                                                        alg);
@@ -4641,10 +4447,10 @@
         goto exit;
     }
 
-    operation->key_type = psa_get_key_type(&attributes);
+    operation->key_type = psa_get_key_type(&slot->attr);
 
 exit:
-    unlock_status = psa_unregister_read(slot);
+    unlock_status = psa_unregister_read_under_mutex(slot);
 
     if (status == PSA_SUCCESS) {
         status = unlock_status;
@@ -5944,7 +5750,6 @@
     size_t bytes = PSA_BITS_TO_BYTES(bits);
     size_t storage_size = bytes;
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
-    psa_key_attributes_t attributes;
 
     if (PSA_KEY_TYPE_IS_PUBLIC_KEY(slot->attr.type)) {
         return PSA_ERROR_INVALID_ARGUMENT;
@@ -5993,12 +5798,9 @@
     }
 
     slot->attr.bits = (psa_key_bits_t) bits;
-    attributes = (psa_key_attributes_t) {
-        .core = slot->attr
-    };
 
-    if (psa_key_lifetime_is_external(attributes.core.lifetime)) {
-        status = psa_driver_wrapper_get_key_buffer_size(&attributes,
+    if (psa_key_lifetime_is_external(slot->attr.lifetime)) {
+        status = psa_driver_wrapper_get_key_buffer_size(&slot->attr,
                                                         &storage_size);
         if (status != PSA_SUCCESS) {
             goto exit;
@@ -6009,7 +5811,7 @@
         goto exit;
     }
 
-    status = psa_driver_wrapper_import_key(&attributes,
+    status = psa_driver_wrapper_import_key(&slot->attr,
                                            data, bytes,
                                            slot->key.data,
                                            slot->key.bytes,
@@ -6023,9 +5825,28 @@
     return status;
 }
 
-psa_status_t psa_key_derivation_output_key(const psa_key_attributes_t *attributes,
-                                           psa_key_derivation_operation_t *operation,
-                                           mbedtls_svc_key_id_t *key)
+static const psa_key_production_parameters_t default_production_parameters =
+    PSA_KEY_PRODUCTION_PARAMETERS_INIT;
+
+int psa_key_production_parameters_are_default(
+    const psa_key_production_parameters_t *params,
+    size_t params_data_length)
+{
+    if (params->flags != 0) {
+        return 0;
+    }
+    if (params_data_length != 0) {
+        return 0;
+    }
+    return 1;
+}
+
+psa_status_t psa_key_derivation_output_key_ext(
+    const psa_key_attributes_t *attributes,
+    psa_key_derivation_operation_t *operation,
+    const psa_key_production_parameters_t *params,
+    size_t params_data_length,
+    mbedtls_svc_key_id_t *key)
 {
     psa_status_t status;
     psa_key_slot_t *slot = NULL;
@@ -6039,6 +5860,10 @@
         return PSA_ERROR_INVALID_ARGUMENT;
     }
 
+    if (!psa_key_production_parameters_are_default(params, params_data_length)) {
+        return PSA_ERROR_INVALID_ARGUMENT;
+    }
+
     if (operation->alg == PSA_ALG_NONE) {
         return PSA_ERROR_BAD_STATE;
     }
@@ -6057,7 +5882,7 @@
 #endif /* MBEDTLS_PSA_CRYPTO_SE_C */
     if (status == PSA_SUCCESS) {
         status = psa_generate_derived_key_internal(slot,
-                                                   attributes->core.bits,
+                                                   attributes->bits,
                                                    operation);
     }
     if (status == PSA_SUCCESS) {
@@ -6070,6 +5895,15 @@
     return status;
 }
 
+psa_status_t psa_key_derivation_output_key(
+    const psa_key_attributes_t *attributes,
+    psa_key_derivation_operation_t *operation,
+    mbedtls_svc_key_id_t *key)
+{
+    return psa_key_derivation_output_key_ext(attributes, operation,
+                                             &default_production_parameters, 0,
+                                             key);
+}
 
 
 /****************************************************************/
@@ -7018,7 +6852,7 @@
                                                slot->key.data,
                                                slot->key.bytes);
 
-    unlock_status = psa_unregister_read(slot);
+    unlock_status = psa_unregister_read_under_mutex(slot);
 
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
@@ -7093,11 +6927,7 @@
         return PSA_ERROR_NOT_SUPPORTED;
     }
 
-    psa_key_attributes_t attributes = {
-        .core = private_key->attr
-    };
-
-    return psa_driver_wrapper_key_agreement(&attributes,
+    return psa_driver_wrapper_key_agreement(&private_key->attr,
                                             private_key->key.data,
                                             private_key->key.bytes, alg,
                                             peer_key, peer_key_length,
@@ -7116,7 +6946,7 @@
                                                size_t peer_key_length)
 {
     psa_status_t status;
-    uint8_t shared_secret[PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE];
+    uint8_t shared_secret[PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE] = { 0 };
     size_t shared_secret_length = 0;
     psa_algorithm_t ka_alg = PSA_ALG_KEY_AGREEMENT_GET_BASE(operation->alg);
 
@@ -7175,7 +7005,7 @@
         }
     }
 
-    unlock_status = psa_unregister_read(slot);
+    unlock_status = psa_unregister_read_under_mutex(slot);
 
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
@@ -7236,7 +7066,7 @@
         *output_length = output_size;
     }
 
-    unlock_status = psa_unregister_read(slot);
+    unlock_status = psa_unregister_read_under_mutex(slot);
 
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
@@ -7279,7 +7109,7 @@
                                MBEDTLS_ENTROPY_SOURCE_STRONG);
 #endif
 
-    mbedtls_psa_drbg_init(MBEDTLS_PSA_RANDOM_STATE);
+    mbedtls_psa_drbg_init(&rng->drbg);
 #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
 }
 
@@ -7290,7 +7120,7 @@
 #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
     memset(rng, 0, sizeof(*rng));
 #else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
-    mbedtls_psa_drbg_free(MBEDTLS_PSA_RANDOM_STATE);
+    mbedtls_psa_drbg_free(&rng->drbg);
     rng->entropy_free(&rng->entropy);
 #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
 }
@@ -7305,7 +7135,7 @@
     return PSA_SUCCESS;
 #else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
     const unsigned char drbg_seed[] = "PSA";
-    int ret = mbedtls_psa_drbg_seed(&rng->entropy,
+    int ret = mbedtls_psa_drbg_seed(&rng->drbg, &rng->entropy,
                                     drbg_seed, sizeof(drbg_seed) - 1);
     return mbedtls_to_psa_error(ret);
 #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
@@ -7335,12 +7165,16 @@
 #else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
 
     while (output_size > 0) {
+        int ret = MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED;
         size_t request_size =
             (output_size > MBEDTLS_PSA_RANDOM_MAX_REQUEST ?
              MBEDTLS_PSA_RANDOM_MAX_REQUEST :
              output_size);
-        int ret = mbedtls_psa_get_random(MBEDTLS_PSA_RANDOM_STATE,
-                                         output, request_size);
+#if defined(MBEDTLS_CTR_DRBG_C)
+        ret = mbedtls_ctr_drbg_random(&global_data.rng.drbg, output, request_size);
+#elif defined(MBEDTLS_HMAC_DRBG_C)
+        ret = mbedtls_hmac_drbg_random(&global_data.rng.drbg, output, request_size);
+#endif /* !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C */
         if (ret != 0) {
             return mbedtls_to_psa_error(ret);
         }
@@ -7351,39 +7185,6 @@
 #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
 }
 
-/* Wrapper function allowing the classic API to use the PSA RNG.
- *
- * `mbedtls_psa_get_random(MBEDTLS_PSA_RANDOM_STATE, ...)` calls
- * `psa_generate_random(...)`. The state parameter is ignored since the
- * PSA API doesn't support passing an explicit state.
- *
- * In the non-external case, psa_generate_random() calls an
- * `mbedtls_xxx_drbg_random` function which has exactly the same signature
- * and semantics as mbedtls_psa_get_random(). As an optimization,
- * instead of doing this back-and-forth between the PSA API and the
- * classic API, psa_crypto_random_impl.h defines `mbedtls_psa_get_random`
- * as a constant function pointer to `mbedtls_xxx_drbg_random`.
- */
-#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
-int mbedtls_psa_get_random(void *p_rng,
-                           unsigned char *output,
-                           size_t output_size)
-{
-    /* This function takes a pointer to the RNG state because that's what
-     * classic mbedtls functions using an RNG expect. The PSA RNG manages
-     * its own state internally and doesn't let the caller access that state.
-     * So we just ignore the state parameter, and in practice we'll pass
-     * NULL. */
-    (void) p_rng;
-    psa_status_t status = psa_generate_random(output, output_size);
-    if (status == PSA_SUCCESS) {
-        return 0;
-    } else {
-        return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
-    }
-}
-#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
-
 #if defined(MBEDTLS_PSA_INJECT_ENTROPY)
 psa_status_t mbedtls_psa_inject_entropy(const uint8_t *seed,
                                         size_t seed_size)
@@ -7466,15 +7267,15 @@
 
 psa_status_t psa_generate_key_internal(
     const psa_key_attributes_t *attributes,
+    const psa_key_production_parameters_t *params, size_t params_data_length,
     uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
-    psa_key_type_t type = attributes->core.type;
+    psa_key_type_t type = attributes->type;
 
-    if ((attributes->domain_parameters == NULL) &&
-        (attributes->domain_parameters_size != 0)) {
-        return PSA_ERROR_INVALID_ARGUMENT;
-    }
+    /* Only used for RSA */
+    (void) params;
+    (void) params_data_length;
 
     if (key_type_is_raw_bytes(type)) {
         status = psa_generate_random(key_buffer, key_buffer_size);
@@ -7492,6 +7293,7 @@
 #if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE)
     if (type == PSA_KEY_TYPE_RSA_KEY_PAIR) {
         return mbedtls_psa_rsa_generate_key(attributes,
+                                            params, params_data_length,
                                             key_buffer,
                                             key_buffer_size,
                                             key_buffer_length);
@@ -7523,8 +7325,10 @@
     return PSA_SUCCESS;
 }
 
-psa_status_t psa_generate_key(const psa_key_attributes_t *attributes,
-                              mbedtls_svc_key_id_t *key)
+psa_status_t psa_generate_key_ext(const psa_key_attributes_t *attributes,
+                                  const psa_key_production_parameters_t *params,
+                                  size_t params_data_length,
+                                  mbedtls_svc_key_id_t *key)
 {
     psa_status_t status;
     psa_key_slot_t *slot = NULL;
@@ -7540,7 +7344,18 @@
     }
 
     /* Reject any attempt to create a public key. */
-    if (PSA_KEY_TYPE_IS_PUBLIC_KEY(attributes->core.type)) {
+    if (PSA_KEY_TYPE_IS_PUBLIC_KEY(attributes->type)) {
+        return PSA_ERROR_INVALID_ARGUMENT;
+    }
+
+#if defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE)
+    if (attributes->type == PSA_KEY_TYPE_RSA_KEY_PAIR) {
+        if (params->flags != 0) {
+            return PSA_ERROR_INVALID_ARGUMENT;
+        }
+    } else
+#endif
+    if (!psa_key_production_parameters_are_default(params, params_data_length)) {
         return PSA_ERROR_INVALID_ARGUMENT;
     }
 
@@ -7555,17 +7370,17 @@
      * with storage ( MBEDTLS_PSA_CRYPTO_SE_C ) ),we have to allocate a
      * buffer to hold the generated key material. */
     if (slot->key.data == NULL) {
-        if (PSA_KEY_LIFETIME_GET_LOCATION(attributes->core.lifetime) ==
+        if (PSA_KEY_LIFETIME_GET_LOCATION(attributes->lifetime) ==
             PSA_KEY_LOCATION_LOCAL_STORAGE) {
             status = psa_validate_key_type_and_size_for_key_generation(
-                attributes->core.type, attributes->core.bits);
+                attributes->type, attributes->bits);
             if (status != PSA_SUCCESS) {
                 goto exit;
             }
 
             key_buffer_size = PSA_EXPORT_KEY_OUTPUT_SIZE(
-                attributes->core.type,
-                attributes->core.bits);
+                attributes->type,
+                attributes->bits);
         } else {
             status = psa_driver_wrapper_get_key_buffer_size(
                 attributes, &key_buffer_size);
@@ -7581,8 +7396,9 @@
     }
 
     status = psa_driver_wrapper_generate_key(attributes,
-                                             slot->key.data, slot->key.bytes, &slot->key.bytes);
-
+                                             params, params_data_length,
+                                             slot->key.data, slot->key.bytes,
+                                             &slot->key.bytes);
     if (status != PSA_SUCCESS) {
         psa_remove_key_data_from_memory(slot);
     }
@@ -7598,6 +7414,14 @@
     return status;
 }
 
+psa_status_t psa_generate_key(const psa_key_attributes_t *attributes,
+                              mbedtls_svc_key_id_t *key)
+{
+    return psa_generate_key_ext(attributes,
+                                &default_production_parameters, 0,
+                                key);
+}
+
 /****************************************************************/
 /* Module setup */
 /****************************************************************/
@@ -7870,7 +7694,6 @@
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot = NULL;
-    psa_key_attributes_t attributes;
     psa_key_type_t type;
 
     if (operation->stage != PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS) {
@@ -7885,11 +7708,7 @@
         goto exit;
     }
 
-    attributes = (psa_key_attributes_t) {
-        .core = slot->attr
-    };
-
-    type = psa_get_key_type(&attributes);
+    type = psa_get_key_type(&slot->attr);
 
     if (type != PSA_KEY_TYPE_PASSWORD &&
         type != PSA_KEY_TYPE_PASSWORD_HASH) {
@@ -7905,12 +7724,13 @@
 
     memcpy(operation->data.inputs.password, slot->key.data, slot->key.bytes);
     operation->data.inputs.password_len = slot->key.bytes;
-    operation->data.inputs.attributes = attributes;
+    operation->data.inputs.attributes = slot->attr;
+
 exit:
     if (status != PSA_SUCCESS) {
         psa_pake_abort(operation);
     }
-    unlock_status = psa_unregister_read(slot);
+    unlock_status = psa_unregister_read_under_mutex(slot);
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
 
diff --git a/library/psa_crypto_aead.c b/library/psa_crypto_aead.c
index 49aa961..a201985 100644
--- a/library/psa_crypto_aead.c
+++ b/library/psa_crypto_aead.c
@@ -33,10 +33,10 @@
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     mbedtls_cipher_id_t cipher_id;
     mbedtls_cipher_mode_t mode;
-    size_t key_bits = attributes->core.bits;
+    size_t key_bits = attributes->bits;
     (void) key_buffer_size;
 
-    status = mbedtls_cipher_values_from_psa(alg, attributes->core.type,
+    status = mbedtls_cipher_values_from_psa(alg, attributes->type,
                                             &key_bits, &mode, &cipher_id);
     if (status != PSA_SUCCESS) {
         return status;
@@ -49,7 +49,7 @@
             /* CCM allows the following tag lengths: 4, 6, 8, 10, 12, 14, 16.
              * The call to mbedtls_ccm_encrypt_and_tag or
              * mbedtls_ccm_auth_decrypt will validate the tag length. */
-            if (PSA_BLOCK_CIPHER_BLOCK_LENGTH(attributes->core.type) != 16) {
+            if (PSA_BLOCK_CIPHER_BLOCK_LENGTH(attributes->type) != 16) {
                 return PSA_ERROR_INVALID_ARGUMENT;
             }
 
@@ -69,7 +69,7 @@
             /* GCM allows the following tag lengths: 4, 8, 12, 13, 14, 15, 16.
              * The call to mbedtls_gcm_crypt_and_tag or
              * mbedtls_gcm_auth_decrypt will validate the tag length. */
-            if (PSA_BLOCK_CIPHER_BLOCK_LENGTH(attributes->core.type) != 16) {
+            if (PSA_BLOCK_CIPHER_BLOCK_LENGTH(attributes->type) != 16) {
                 return PSA_ERROR_INVALID_ARGUMENT;
             }
 
diff --git a/library/psa_crypto_cipher.c b/library/psa_crypto_cipher.c
index 3132854..a45fb0f 100644
--- a/library/psa_crypto_cipher.c
+++ b/library/psa_crypto_cipher.c
@@ -289,14 +289,14 @@
     int ret = 0;
     size_t key_bits;
     const mbedtls_cipher_info_t *cipher_info = NULL;
-    psa_key_type_t key_type = attributes->core.type;
+    psa_key_type_t key_type = attributes->type;
 
     (void) key_buffer_size;
 
     mbedtls_cipher_init(&operation->ctx.cipher);
 
     operation->alg = alg;
-    key_bits = attributes->core.bits;
+    key_bits = attributes->bits;
     cipher_info = mbedtls_cipher_info_from_psa(alg, key_type,
                                                key_bits, NULL);
     if (cipher_info == NULL) {
diff --git a/library/psa_crypto_client.c b/library/psa_crypto_client.c
index 472d3d3..72f671d 100644
--- a/library/psa_crypto_client.c
+++ b/library/psa_crypto_client.c
@@ -16,57 +16,7 @@
 
 void psa_reset_key_attributes(psa_key_attributes_t *attributes)
 {
-    mbedtls_free(attributes->domain_parameters);
     memset(attributes, 0, sizeof(*attributes));
 }
 
-psa_status_t psa_set_key_domain_parameters(psa_key_attributes_t *attributes,
-                                           psa_key_type_t type,
-                                           const uint8_t *data,
-                                           size_t data_length)
-{
-    uint8_t *copy = NULL;
-
-    if (data_length != 0) {
-        copy = mbedtls_calloc(1, data_length);
-        if (copy == NULL) {
-            return PSA_ERROR_INSUFFICIENT_MEMORY;
-        }
-        memcpy(copy, data, data_length);
-    }
-    /* After this point, this function is guaranteed to succeed, so it
-     * can start modifying `*attributes`. */
-
-    if (attributes->domain_parameters != NULL) {
-        mbedtls_free(attributes->domain_parameters);
-        attributes->domain_parameters = NULL;
-        attributes->domain_parameters_size = 0;
-    }
-
-    attributes->domain_parameters = copy;
-    attributes->domain_parameters_size = data_length;
-    attributes->core.type = type;
-    return PSA_SUCCESS;
-}
-
-psa_status_t psa_get_key_domain_parameters(
-    const psa_key_attributes_t *attributes,
-    uint8_t *data, size_t data_size, size_t *data_length)
-{
-    if (attributes->domain_parameters == NULL &&
-        attributes->domain_parameters_size == SIZE_MAX) {
-        return PSA_ERROR_NOT_SUPPORTED;
-    }
-
-    if (attributes->domain_parameters_size > data_size) {
-        return PSA_ERROR_BUFFER_TOO_SMALL;
-    }
-    *data_length = attributes->domain_parameters_size;
-    if (attributes->domain_parameters_size != 0) {
-        memcpy(data, attributes->domain_parameters,
-               attributes->domain_parameters_size);
-    }
-    return PSA_SUCCESS;
-}
-
 #endif /* MBEDTLS_PSA_CRYPTO_CLIENT */
diff --git a/library/psa_crypto_core.h b/library/psa_crypto_core.h
index dc376d7..d4bdf92 100644
--- a/library/psa_crypto_core.h
+++ b/library/psa_crypto_core.h
@@ -59,7 +59,7 @@
  * and metadata for one key.
  */
 typedef struct {
-    psa_core_key_attributes_t attr;
+    psa_key_attributes_t attr;
 
     /*
      * The current state of the key slot, as described in
@@ -89,7 +89,9 @@
      * A function must call psa_register_read(slot) before reading the current
      * contents of the slot for an operation.
      * They then must call psa_unregister_read(slot) once they have finished
-     * reading the current contents of the slot.
+     * reading the current contents of the slot. If the key slot mutex is not
+     * held (when mutexes are enabled), this call must be done via a call to
+     * psa_unregister_read_under_mutex(slot).
      * A function must call psa_key_slot_has_readers(slot) to check if
      * the slot is in use for reading.
      *
@@ -157,11 +159,6 @@
     } while (0);
 #endif
 
-/* A mask of key attribute flags used only internally.
- * Currently there aren't any. */
-#define PSA_KA_MASK_INTERNAL_ONLY (     \
-        0)
-
 /** Test whether a key slot has any registered readers.
  * If multi-threading is enabled, the caller must hold the
  * global key slot mutex.
@@ -175,56 +172,6 @@
     return slot->registered_readers > 0;
 }
 
-/** Retrieve flags from psa_key_slot_t::attr::core::flags.
- *
- * \param[in] slot      The key slot to query.
- * \param mask          The mask of bits to extract.
- *
- * \return The key attribute flags in the given slot,
- *         bitwise-anded with \p mask.
- */
-static inline uint16_t psa_key_slot_get_flags(const psa_key_slot_t *slot,
-                                              uint16_t mask)
-{
-    return slot->attr.flags & mask;
-}
-
-/** Set flags in psa_key_slot_t::attr::core::flags.
- *
- * \param[in,out] slot  The key slot to modify.
- * \param mask          The mask of bits to modify.
- * \param value         The new value of the selected bits.
- */
-static inline void psa_key_slot_set_flags(psa_key_slot_t *slot,
-                                          uint16_t mask,
-                                          uint16_t value)
-{
-    slot->attr.flags = ((~mask & slot->attr.flags) |
-                        (mask & value));
-}
-
-/** Turn on flags in psa_key_slot_t::attr::core::flags.
- *
- * \param[in,out] slot  The key slot to modify.
- * \param mask          The mask of bits to set.
- */
-static inline void psa_key_slot_set_bits_in_flags(psa_key_slot_t *slot,
-                                                  uint16_t mask)
-{
-    slot->attr.flags |= mask;
-}
-
-/** Turn off flags in psa_key_slot_t::attr::core::flags.
- *
- * \param[in,out] slot  The key slot to modify.
- * \param mask          The mask of bits to clear.
- */
-static inline void psa_key_slot_clear_bits(psa_key_slot_t *slot,
-                                           uint16_t mask)
-{
-    slot->attr.flags &= ~mask;
-}
-
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
 /** Get the SE slot number of a key from the key slot storing its description.
  *
@@ -396,6 +343,18 @@
     const uint8_t *key_buffer, size_t key_buffer_size,
     uint8_t *data, size_t data_size, size_t *data_length);
 
+/** Whether a key production parameters structure is the default.
+ *
+ * Calls to a key generation driver with non-default production parameters
+ * require a driver supporting custom production parameters.
+ *
+ * \param[in] params            The key production parameters to check.
+ * \param params_data_length    Size of `params->data` in bytes.
+ */
+int psa_key_production_parameters_are_default(
+    const psa_key_production_parameters_t *params,
+    size_t params_data_length);
+
 /**
  * \brief Generate a key.
  *
@@ -403,6 +362,9 @@
  *       entry point.
  *
  * \param[in]  attributes         The attributes for the key to generate.
+ * \param[in]  params             The production parameters from
+ *                                psa_generate_key_ext().
+ * \param      params_data_length The size of `params->data` in bytes.
  * \param[out] key_buffer         Buffer where the key data is to be written.
  * \param[in]  key_buffer_size    Size of \p key_buffer in bytes.
  * \param[out] key_buffer_length  On success, the number of bytes written in
@@ -417,6 +379,8 @@
  *         The size of \p key_buffer is too small.
  */
 psa_status_t psa_generate_key_internal(const psa_key_attributes_t *attributes,
+                                       const psa_key_production_parameters_t *params,
+                                       size_t params_data_length,
                                        uint8_t *key_buffer,
                                        size_t key_buffer_size,
                                        size_t *key_buffer_length);
diff --git a/library/psa_crypto_ecp.c b/library/psa_crypto_ecp.c
index db08541..95baff6 100644
--- a/library/psa_crypto_ecp.c
+++ b/library/psa_crypto_ecp.c
@@ -216,8 +216,8 @@
     mbedtls_ecp_keypair *ecp = NULL;
 
     /* Parse input */
-    status = mbedtls_psa_ecp_load_representation(attributes->core.type,
-                                                 attributes->core.bits,
+    status = mbedtls_psa_ecp_load_representation(attributes->type,
+                                                 attributes->bits,
                                                  data,
                                                  data_length,
                                                  &ecp);
@@ -225,7 +225,7 @@
         goto exit;
     }
 
-    if (PSA_KEY_TYPE_ECC_GET_FAMILY(attributes->core.type) ==
+    if (PSA_KEY_TYPE_ECC_GET_FAMILY(attributes->type) ==
         PSA_ECC_FAMILY_MONTGOMERY) {
         *bits = ecp->grp.nbits + 1;
     } else {
@@ -235,7 +235,7 @@
     /* Re-export the data to PSA export format. There is currently no support
      * for other input formats then the export format, so this is a 1-1
      * copy operation. */
-    status = mbedtls_psa_ecp_export_key(attributes->core.type,
+    status = mbedtls_psa_ecp_export_key(attributes->type,
                                         ecp,
                                         key_buffer,
                                         key_buffer_size,
@@ -281,20 +281,8 @@
 
         return status;
     } else {
-        if (data_size < PSA_BITS_TO_BYTES(ecp->grp.nbits)) {
-            return PSA_ERROR_BUFFER_TOO_SMALL;
-        }
-
         status = mbedtls_to_psa_error(
-            mbedtls_ecp_write_key(ecp,
-                                  data,
-                                  PSA_BITS_TO_BYTES(ecp->grp.nbits)));
-        if (status == PSA_SUCCESS) {
-            *data_length = PSA_BITS_TO_BYTES(ecp->grp.nbits);
-        } else {
-            memset(data, 0, data_size);
-        }
-
+            mbedtls_ecp_write_key_ext(ecp, data_length, data, data_size));
         return status;
     }
 }
@@ -308,7 +296,7 @@
     mbedtls_ecp_keypair *ecp = NULL;
 
     status = mbedtls_psa_ecp_load_representation(
-        attributes->core.type, attributes->core.bits,
+        attributes->type, attributes->bits,
         key_buffer, key_buffer_size, &ecp);
     if (status != PSA_SUCCESS) {
         return status;
@@ -316,7 +304,7 @@
 
     status = mbedtls_psa_ecp_export_key(
         PSA_KEY_TYPE_ECC_PUBLIC_KEY(
-            PSA_KEY_TYPE_ECC_GET_FAMILY(attributes->core.type)),
+            PSA_KEY_TYPE_ECC_GET_FAMILY(attributes->type)),
         ecp, data, data_size, data_length);
 
     mbedtls_ecp_keypair_free(ecp);
@@ -337,18 +325,14 @@
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
 
     psa_ecc_family_t curve = PSA_KEY_TYPE_ECC_GET_FAMILY(
-        attributes->core.type);
+        attributes->type);
     mbedtls_ecp_group_id grp_id =
-        mbedtls_ecc_group_from_psa(curve, attributes->core.bits);
+        mbedtls_ecc_group_from_psa(curve, attributes->bits);
 
     const mbedtls_ecp_curve_info *curve_info =
         mbedtls_ecp_curve_info_from_grp_id(grp_id);
     mbedtls_ecp_keypair ecp;
 
-    if (attributes->domain_parameters_size != 0) {
-        return PSA_ERROR_NOT_SUPPORTED;
-    }
-
     if (grp_id == MBEDTLS_ECP_DP_NONE || curve_info == NULL) {
         return PSA_ERROR_NOT_SUPPORTED;
     }
@@ -363,14 +347,11 @@
     }
 
     status = mbedtls_to_psa_error(
-        mbedtls_ecp_write_key(&ecp, key_buffer, key_buffer_size));
+        mbedtls_ecp_write_key_ext(&ecp, key_buffer_length,
+                                  key_buffer, key_buffer_size));
 
     mbedtls_ecp_keypair_free(&ecp);
 
-    if (status == PSA_SUCCESS) {
-        *key_buffer_length = key_buffer_size;
-    }
-
     return status;
 }
 #endif /* MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE */
@@ -393,8 +374,8 @@
     size_t curve_bytes;
     mbedtls_mpi r, s;
 
-    status = mbedtls_psa_ecp_load_representation(attributes->core.type,
-                                                 attributes->core.bits,
+    status = mbedtls_psa_ecp_load_representation(attributes->type,
+                                                 attributes->bits,
                                                  key_buffer,
                                                  key_buffer_size,
                                                  &ecp);
@@ -480,8 +461,8 @@
 
     (void) alg;
 
-    status = mbedtls_psa_ecp_load_representation(attributes->core.type,
-                                                 attributes->core.bits,
+    status = mbedtls_psa_ecp_load_representation(attributes->type,
+                                                 attributes->bits,
                                                  key_buffer,
                                                  key_buffer_size,
                                                  &ecp);
@@ -545,14 +526,14 @@
     size_t *shared_secret_length)
 {
     psa_status_t status;
-    if (!PSA_KEY_TYPE_IS_ECC_KEY_PAIR(attributes->core.type) ||
+    if (!PSA_KEY_TYPE_IS_ECC_KEY_PAIR(attributes->type) ||
         !PSA_ALG_IS_ECDH(alg)) {
         return PSA_ERROR_INVALID_ARGUMENT;
     }
     mbedtls_ecp_keypair *ecp = NULL;
     status = mbedtls_psa_ecp_load_representation(
-        attributes->core.type,
-        attributes->core.bits,
+        attributes->type,
+        attributes->bits,
         key_buffer,
         key_buffer_size,
         &ecp);
diff --git a/library/psa_crypto_ffdh.c b/library/psa_crypto_ffdh.c
index 0099d5f..ae38f6d 100644
--- a/library/psa_crypto_ffdh.c
+++ b/library/psa_crypto_ffdh.c
@@ -151,7 +151,7 @@
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     mbedtls_mpi GX, G, X, P;
-    psa_key_type_t type = attributes->core.type;
+    psa_key_type_t type = attributes->type;
 
     if (PSA_KEY_TYPE_IS_PUBLIC_KEY(type)) {
         if (key_buffer_size > data_size) {
@@ -167,7 +167,7 @@
     mbedtls_mpi_init(&GX); mbedtls_mpi_init(&G);
     mbedtls_mpi_init(&X); mbedtls_mpi_init(&P);
 
-    size_t key_len = PSA_BITS_TO_BYTES(attributes->core.bits);
+    size_t key_len = PSA_BITS_TO_BYTES(attributes->bits);
 
     status = mbedtls_psa_ffdh_set_prime_generator(key_len, &P, &G);
 
@@ -283,7 +283,7 @@
     mbedtls_mpi_init(&K);
 
     status = mbedtls_psa_ffdh_set_prime_generator(
-        PSA_BITS_TO_BYTES(attributes->core.bits), &P, &G);
+        PSA_BITS_TO_BYTES(attributes->bits), &P, &G);
 
     if (status != PSA_SUCCESS) {
         goto cleanup;
diff --git a/library/psa_crypto_random_impl.h b/library/psa_crypto_random_impl.h
index 64b8949..533fb2e 100644
--- a/library/psa_crypto_random_impl.h
+++ b/library/psa_crypto_random_impl.h
@@ -1,14 +1,6 @@
 /** \file psa_crypto_random_impl.h
  *
  * \brief PSA crypto random generator implementation abstraction.
- *
- * The definitions here need to be consistent with the declarations
- * in include/psa_util_internal.h. This file contains some redundant
- * declarations to increase the chance that a compiler will detect
- * inconsistencies if one file is changed without updating the other,
- * but not all potential inconsistencies can be enforced, so make sure
- * to check the public declarations and contracts in
- * include/psa_util_internal.h if you modify this file.
  */
 /*
  *  Copyright The Mbed TLS Contributors
@@ -22,22 +14,12 @@
 
 #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
 
-#include <string.h>
-#include <mbedtls/entropy.h> // only for error codes
-#include <psa/crypto.h>
-
 typedef mbedtls_psa_external_random_context_t mbedtls_psa_random_context_t;
 
-/* Trivial wrapper around psa_generate_random(). */
-int mbedtls_psa_get_random(void *p_rng,
-                           unsigned char *output,
-                           size_t output_size);
-
-/* The PSA RNG API doesn't need any externally maintained state. */
-#define MBEDTLS_PSA_RANDOM_STATE NULL
-
 #else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
 
+#include "mbedtls/entropy.h"
+
 /* Choose a DRBG based on configuration and availability */
 #if defined(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE)
 
@@ -67,11 +49,37 @@
 #error "No hash algorithm available for HMAC_DBRG."
 #endif
 
-#else
+#else /* !MBEDTLS_PSA_HMAC_DRBG_MD_TYPE && !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C*/
+
 #error "No DRBG module available for the psa_crypto module."
+
+#endif /* !MBEDTLS_PSA_HMAC_DRBG_MD_TYPE && !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C*/
+
+#if defined(MBEDTLS_CTR_DRBG_C)
+#include "mbedtls/ctr_drbg.h"
+#elif defined(MBEDTLS_HMAC_DRBG_C)
+#include "mbedtls/hmac_drbg.h"
+#endif /* !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C */
+
+/* The maximum number of bytes that mbedtls_psa_get_random() is expected to return. */
+#if defined(MBEDTLS_CTR_DRBG_C)
+#define MBEDTLS_PSA_RANDOM_MAX_REQUEST MBEDTLS_CTR_DRBG_MAX_REQUEST
+#elif defined(MBEDTLS_HMAC_DRBG_C)
+#define MBEDTLS_PSA_RANDOM_MAX_REQUEST MBEDTLS_HMAC_DRBG_MAX_REQUEST
 #endif
 
-#include "mbedtls/entropy.h"
+#if defined(MBEDTLS_CTR_DRBG_C)
+typedef mbedtls_ctr_drbg_context            mbedtls_psa_drbg_context_t;
+#elif defined(MBEDTLS_HMAC_DRBG_C)
+typedef mbedtls_hmac_drbg_context           mbedtls_psa_drbg_context_t;
+#endif /* !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C */
+
+typedef struct {
+    void (* entropy_init)(mbedtls_entropy_context *ctx);
+    void (* entropy_free)(mbedtls_entropy_context *ctx);
+    mbedtls_entropy_context entropy;
+    mbedtls_psa_drbg_context_t drbg;
+} mbedtls_psa_random_context_t;
 
 /** Initialize the PSA DRBG.
  *
@@ -99,63 +107,6 @@
 #endif
 }
 
-/** The type of the PSA random generator context.
- *
- * The random generator context is composed of an entropy context and
- * a DRBG context.
- */
-typedef struct {
-    void (* entropy_init)(mbedtls_entropy_context *ctx);
-    void (* entropy_free)(mbedtls_entropy_context *ctx);
-    mbedtls_entropy_context entropy;
-    mbedtls_psa_drbg_context_t drbg;
-} mbedtls_psa_random_context_t;
-
-/* Defined in include/psa_util_internal.h so that it's visible to
- * application code. The declaration here is redundant, but included
- * as a safety net to make it more likely that a future change that
- * accidentally causes the implementation to diverge from the interface
- * will be noticed. */
-/* Do not include the declaration under MSVC because it doesn't accept it
- * ("error C2370: 'mbedtls_psa_get_random' : redefinition; different storage class").
- * Observed with Visual Studio 2013. A known bug apparently:
- * https://stackoverflow.com/questions/8146541/duplicate-external-static-declarations-not-allowed-in-visual-studio
- */
-#if !defined(_MSC_VER)
-static mbedtls_f_rng_t *const mbedtls_psa_get_random;
-#endif
-
-/** The maximum number of bytes that mbedtls_psa_get_random() is expected to
- * return.
- */
-#if defined(MBEDTLS_CTR_DRBG_C)
-#define MBEDTLS_PSA_RANDOM_MAX_REQUEST MBEDTLS_CTR_DRBG_MAX_REQUEST
-#elif defined(MBEDTLS_HMAC_DRBG_C)
-#define MBEDTLS_PSA_RANDOM_MAX_REQUEST MBEDTLS_HMAC_DRBG_MAX_REQUEST
-#endif
-
-/** A pointer to the PSA DRBG state.
- *
- * This variable is only intended to be used through the macro
- * #MBEDTLS_PSA_RANDOM_STATE.
- */
-/* psa_crypto.c sets this variable to a pointer to the DRBG state in the
- * global PSA crypto state. */
-/* The type `mbedtls_psa_drbg_context_t` is defined in
- * include/psa_util_internal.h so that `mbedtls_psa_random_state` can be
- * declared there and be visible to application code. */
-extern mbedtls_psa_drbg_context_t *const mbedtls_psa_random_state;
-
-/** A pointer to the PSA DRBG state.
- *
- * This macro expands to an expression that is suitable as the \c p_rng
- * parameter to pass to mbedtls_psa_get_random().
- *
- * This macro exists in all configurations where the psa_crypto module is
- * enabled. Its expansion depends on the configuration.
- */
-#define MBEDTLS_PSA_RANDOM_STATE mbedtls_psa_random_state
-
 /** Seed the PSA DRBG.
  *
  * \param entropy       An entropy context to read the seed from.
@@ -167,23 +118,15 @@
  * \return              \c 0 on success.
  * \return              An Mbed TLS error code (\c MBEDTLS_ERR_xxx) on failure.
  */
-static inline int mbedtls_psa_drbg_seed(
-    mbedtls_entropy_context *entropy,
-    const unsigned char *custom, size_t len)
+static inline int mbedtls_psa_drbg_seed(mbedtls_psa_drbg_context_t *drbg_ctx,
+                                        mbedtls_entropy_context *entropy,
+                                        const unsigned char *custom, size_t len)
 {
 #if defined(MBEDTLS_CTR_DRBG_C)
-    return mbedtls_ctr_drbg_seed(MBEDTLS_PSA_RANDOM_STATE,
-                                 mbedtls_entropy_func,
-                                 entropy,
-                                 custom, len);
+    return mbedtls_ctr_drbg_seed(drbg_ctx, mbedtls_entropy_func, entropy, custom, len);
 #elif defined(MBEDTLS_HMAC_DRBG_C)
-    const mbedtls_md_info_t *md_info =
-        mbedtls_md_info_from_type(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE);
-    return mbedtls_hmac_drbg_seed(MBEDTLS_PSA_RANDOM_STATE,
-                                  md_info,
-                                  mbedtls_entropy_func,
-                                  entropy,
-                                  custom, len);
+    const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE);
+    return mbedtls_hmac_drbg_seed(drbg_ctx, md_info, mbedtls_entropy_func, entropy, custom, len);
 #endif
 }
 
diff --git a/library/psa_crypto_rsa.c b/library/psa_crypto_rsa.c
index 4a574d1..2f613b3 100644
--- a/library/psa_crypto_rsa.c
+++ b/library/psa_crypto_rsa.c
@@ -116,7 +116,7 @@
     mbedtls_rsa_context *rsa = NULL;
 
     /* Parse input */
-    status = mbedtls_psa_rsa_load_representation(attributes->core.type,
+    status = mbedtls_psa_rsa_load_representation(attributes->type,
                                                  data,
                                                  data_length,
                                                  &rsa);
@@ -130,7 +130,7 @@
      * representation in the key slot. Export representation in case of RSA is
      * the smallest representation that's allowed as input, so a straight-up
      * allocation of the same size as the input buffer will be large enough. */
-    status = mbedtls_psa_rsa_export_key(attributes->core.type,
+    status = mbedtls_psa_rsa_export_key(attributes->type,
                                         rsa,
                                         key_buffer,
                                         key_buffer_size,
@@ -196,7 +196,7 @@
     mbedtls_rsa_context *rsa = NULL;
 
     status = mbedtls_psa_rsa_load_representation(
-        attributes->core.type, key_buffer, key_buffer_size, &rsa);
+        attributes->type, key_buffer, key_buffer_size, &rsa);
     if (status != PSA_SUCCESS) {
         return status;
     }
@@ -216,26 +216,21 @@
         * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) */
 
 #if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE)
-static psa_status_t psa_rsa_read_exponent(const uint8_t *domain_parameters,
-                                          size_t domain_parameters_size,
+static psa_status_t psa_rsa_read_exponent(const uint8_t *e_bytes,
+                                          size_t e_length,
                                           int *exponent)
 {
     size_t i;
     uint32_t acc = 0;
 
-    if (domain_parameters_size == 0) {
-        *exponent = 65537;
-        return PSA_SUCCESS;
-    }
-
     /* Mbed TLS encodes the public exponent as an int. For simplicity, only
      * support values that fit in a 32-bit integer, which is larger than
      * int on just about every platform anyway. */
-    if (domain_parameters_size > sizeof(acc)) {
+    if (e_length > sizeof(acc)) {
         return PSA_ERROR_NOT_SUPPORTED;
     }
-    for (i = 0; i < domain_parameters_size; i++) {
-        acc = (acc << 8) | domain_parameters[i];
+    for (i = 0; i < e_length; i++) {
+        acc = (acc << 8) | e_bytes[i];
     }
     if (acc > INT_MAX) {
         return PSA_ERROR_NOT_SUPPORTED;
@@ -246,31 +241,33 @@
 
 psa_status_t mbedtls_psa_rsa_generate_key(
     const psa_key_attributes_t *attributes,
+    const psa_key_production_parameters_t *params, size_t params_data_length,
     uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length)
 {
     psa_status_t status;
     mbedtls_rsa_context rsa;
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    int exponent;
+    int exponent = 65537;
 
-    status = psa_rsa_read_exponent(attributes->domain_parameters,
-                                   attributes->domain_parameters_size,
-                                   &exponent);
-    if (status != PSA_SUCCESS) {
-        return status;
+    if (params_data_length != 0) {
+        status = psa_rsa_read_exponent(params->data, params_data_length,
+                                       &exponent);
+        if (status != PSA_SUCCESS) {
+            return status;
+        }
     }
 
     mbedtls_rsa_init(&rsa);
     ret = mbedtls_rsa_gen_key(&rsa,
                               mbedtls_psa_get_random,
                               MBEDTLS_PSA_RANDOM_STATE,
-                              (unsigned int) attributes->core.bits,
+                              (unsigned int) attributes->bits,
                               exponent);
     if (ret != 0) {
         return mbedtls_to_psa_error(ret);
     }
 
-    status = mbedtls_psa_rsa_export_key(attributes->core.type,
+    status = mbedtls_psa_rsa_export_key(attributes->type,
                                         &rsa, key_buffer, key_buffer_size,
                                         key_buffer_length);
     mbedtls_rsa_free(&rsa);
@@ -328,7 +325,7 @@
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     mbedtls_md_type_t md_alg;
 
-    status = mbedtls_psa_rsa_load_representation(attributes->core.type,
+    status = mbedtls_psa_rsa_load_representation(attributes->type,
                                                  key_buffer,
                                                  key_buffer_size,
                                                  &rsa);
@@ -427,7 +424,7 @@
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     mbedtls_md_type_t md_alg;
 
-    status = mbedtls_psa_rsa_load_representation(attributes->core.type,
+    status = mbedtls_psa_rsa_load_representation(attributes->type,
                                                  key_buffer,
                                                  key_buffer_size,
                                                  &rsa);
@@ -539,11 +536,11 @@
     (void) output_size;
     (void) output_length;
 
-    if (PSA_KEY_TYPE_IS_RSA(attributes->core.type)) {
+    if (PSA_KEY_TYPE_IS_RSA(attributes->type)) {
 #if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) || \
         defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP)
         mbedtls_rsa_context *rsa = NULL;
-        status = mbedtls_psa_rsa_load_representation(attributes->core.type,
+        status = mbedtls_psa_rsa_load_representation(attributes->type,
                                                      key_buffer,
                                                      key_buffer_size,
                                                      &rsa);
@@ -635,11 +632,11 @@
 
     *output_length = 0;
 
-    if (attributes->core.type == PSA_KEY_TYPE_RSA_KEY_PAIR) {
+    if (attributes->type == PSA_KEY_TYPE_RSA_KEY_PAIR) {
 #if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) || \
         defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP)
         mbedtls_rsa_context *rsa = NULL;
-        status = mbedtls_psa_rsa_load_representation(attributes->core.type,
+        status = mbedtls_psa_rsa_load_representation(attributes->type,
                                                      key_buffer,
                                                      key_buffer_size,
                                                      &rsa);
diff --git a/library/psa_crypto_rsa.h b/library/psa_crypto_rsa.h
index e4c5caf..ffeef26 100644
--- a/library/psa_crypto_rsa.h
+++ b/library/psa_crypto_rsa.h
@@ -109,6 +109,15 @@
  *       entry point.
  *
  * \param[in]  attributes         The attributes for the RSA key to generate.
+ * \param[in]  params             Production parameters for the key
+ *                                generation. This function only uses
+ *                                `params->data`,
+ *                                which contains the public exponent.
+ *                                This can be a null pointer if
+ *                                \c params_data_length is 0.
+ * \param params_data_length      Length of `params->data` in bytes.
+ *                                This can be 0, in which case the
+ *                                public exponent will be 65537.
  * \param[out] key_buffer         Buffer where the key data is to be written.
  * \param[in]  key_buffer_size    Size of \p key_buffer in bytes.
  * \param[out] key_buffer_length  On success, the number of bytes written in
@@ -123,6 +132,7 @@
  */
 psa_status_t mbedtls_psa_rsa_generate_key(
     const psa_key_attributes_t *attributes,
+    const psa_key_production_parameters_t *params, size_t params_data_length,
     uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length);
 
 /** Sign an already-calculated hash with an RSA private key.
diff --git a/library/psa_crypto_slot_management.c b/library/psa_crypto_slot_management.c
index dc38662..5dee32f 100644
--- a/library/psa_crypto_slot_management.c
+++ b/library/psa_crypto_slot_management.c
@@ -70,6 +70,9 @@
  * On success, the function locks the key slot. It is the responsibility of
  * the caller to unlock the key slot when it does not access it anymore.
  *
+ * If multi-threading is enabled, the caller must hold the
+ * global key slot mutex.
+ *
  * \param key           Key identifier to query.
  * \param[out] p_slot   On success, `*p_slot` contains a pointer to the
  *                      key slot containing the description of the key
@@ -94,16 +97,14 @@
     if (psa_key_id_is_volatile(key_id)) {
         slot = &global_data.key_slots[key_id - PSA_KEY_ID_VOLATILE_MIN];
 
-        /*
-         * Check if both the PSA key identifier key_id and the owner
-         * identifier of key match those of the key slot.
-         *
-         * Note that, if the key slot is not occupied, its PSA key identifier
-         * is equal to zero. This is an invalid value for a PSA key identifier
-         * and thus cannot be equal to the valid PSA key identifier key_id.
-         */
-        status = mbedtls_svc_key_id_equal(key, slot->attr.id) ?
-                 PSA_SUCCESS : PSA_ERROR_DOES_NOT_EXIST;
+        /* Check if both the PSA key identifier key_id and the owner
+         * identifier of key match those of the key slot. */
+        if ((slot->state == PSA_SLOT_FULL) &&
+            (mbedtls_svc_key_id_equal(key, slot->attr.id))) {
+            status = PSA_SUCCESS;
+        } else {
+            status = PSA_ERROR_DOES_NOT_EXIST;
+        }
     } else {
         if (!psa_is_valid_key_id(key, 1)) {
             return PSA_ERROR_INVALID_HANDLE;
@@ -248,11 +249,6 @@
         data = (psa_se_key_data_storage_t *) key_data;
         status = psa_copy_key_material_into_slot(
             slot, data->slot_number, sizeof(data->slot_number));
-
-        if (status == PSA_SUCCESS) {
-            status = psa_key_slot_state_transition(slot, PSA_SLOT_FILLING,
-                                                   PSA_SLOT_FULL);
-        }
         goto exit;
     }
 #endif /* MBEDTLS_PSA_CRYPTO_SE_C */
@@ -262,9 +258,6 @@
         goto exit;
     }
 
-    status = psa_key_slot_state_transition(slot, PSA_SLOT_FILLING,
-                                           PSA_SLOT_FULL);
-
 exit:
     psa_free_persistent_key_data(key_data, key_data_length);
     return status;
@@ -336,10 +329,7 @@
 
     /* Copy actual key length and core attributes into the slot on success */
     slot->key.bytes = key_buffer_length;
-    slot->attr = attributes.core;
-
-    status = psa_key_slot_state_transition(slot, PSA_SLOT_FILLING,
-                                           PSA_SLOT_FULL);
+    slot->attr = attributes;
 exit:
     if (status != PSA_SUCCESS) {
         psa_remove_key_data_from_memory(slot);
@@ -358,12 +348,27 @@
         return PSA_ERROR_BAD_STATE;
     }
 
+#if defined(MBEDTLS_THREADING_C)
+    /* We need to set status as success, otherwise CORRUPTION_DETECTED
+     * would be returned if the lock fails. */
+    status = PSA_SUCCESS;
+    /* If the key is persistent and not loaded, we cannot unlock the mutex
+     * between checking if the key is loaded and setting the slot as FULL,
+     * as otherwise another thread may load and then destroy the key
+     * in the meantime. */
+    PSA_THREADING_CHK_RET(mbedtls_mutex_lock(
+                              &mbedtls_threading_key_slot_mutex));
+#endif
     /*
      * On success, the pointer to the slot is passed directly to the caller
      * thus no need to unlock the key slot here.
      */
     status = psa_get_and_lock_key_slot_in_memory(key, p_slot);
     if (status != PSA_ERROR_DOES_NOT_EXIST) {
+#if defined(MBEDTLS_THREADING_C)
+        PSA_THREADING_CHK_RET(mbedtls_mutex_unlock(
+                                  &mbedtls_threading_key_slot_mutex));
+#endif
         return status;
     }
 
@@ -374,6 +379,10 @@
 
     status = psa_reserve_free_key_slot(&volatile_key_id, p_slot);
     if (status != PSA_SUCCESS) {
+#if defined(MBEDTLS_THREADING_C)
+        PSA_THREADING_CHK_RET(mbedtls_mutex_unlock(
+                                  &mbedtls_threading_key_slot_mutex));
+#endif
         return status;
     }
 
@@ -407,10 +416,15 @@
         status = psa_register_read(*p_slot);
     }
 
-    return status;
 #else /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
-    return PSA_ERROR_INVALID_HANDLE;
+    status = PSA_ERROR_INVALID_HANDLE;
 #endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
+
+#if defined(MBEDTLS_THREADING_C)
+    PSA_THREADING_CHK_RET(mbedtls_mutex_unlock(
+                              &mbedtls_threading_key_slot_mutex));
+#endif
+    return status;
 }
 
 psa_status_t psa_unregister_read(psa_key_slot_t *slot)
@@ -447,6 +461,24 @@
     return PSA_ERROR_CORRUPTION_DETECTED;
 }
 
+psa_status_t psa_unregister_read_under_mutex(psa_key_slot_t *slot)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+#if defined(MBEDTLS_THREADING_C)
+    /* We need to set status as success, otherwise CORRUPTION_DETECTED
+     * would be returned if the lock fails. */
+    status = PSA_SUCCESS;
+    PSA_THREADING_CHK_RET(mbedtls_mutex_lock(
+                              &mbedtls_threading_key_slot_mutex));
+#endif
+    status = psa_unregister_read(slot);
+#if defined(MBEDTLS_THREADING_C)
+    PSA_THREADING_CHK_RET(mbedtls_mutex_unlock(
+                              &mbedtls_threading_key_slot_mutex));
+#endif
+    return status;
+}
+
 psa_status_t psa_validate_key_location(psa_key_lifetime_t lifetime,
                                        psa_se_drv_table_entry_t **p_drv)
 {
@@ -510,7 +542,7 @@
 
     *handle = key;
 
-    return psa_unregister_read(slot);
+    return psa_unregister_read_under_mutex(slot);
 
 #else /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
     (void) key;
diff --git a/library/psa_crypto_slot_management.h b/library/psa_crypto_slot_management.h
index 18a9144..bcfc9d8 100644
--- a/library/psa_crypto_slot_management.h
+++ b/library/psa_crypto_slot_management.h
@@ -107,6 +107,9 @@
  * It is the responsibility of the caller to change the slot's state to
  * PSA_SLOT_EMPTY/FULL once key creation has finished.
  *
+ * If multi-threading is enabled, the caller must hold the
+ * global key slot mutex.
+ *
  * \param[out] volatile_key_id   On success, volatile key identifier
  *                               associated to the returned slot.
  * \param[out] p_slot            On success, a pointer to the slot.
@@ -202,6 +205,27 @@
  */
 psa_status_t psa_unregister_read(psa_key_slot_t *slot);
 
+/** Wrap a call to psa_unregister_read in the global key slot mutex.
+ *
+ * If threading is disabled, this simply calls psa_unregister_read.
+ *
+ * \note To ease the handling of errors in retrieving a key slot
+ *       a NULL input pointer is valid, and the function returns
+ *       successfully without doing anything in that case.
+ *
+ * \param[in] slot  The key slot.
+ * \retval #PSA_SUCCESS
+ *             \p slot is NULL or the key slot reader counter has been
+ *             decremented (and potentially wiped) successfully.
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED
+ *             The slot's state was neither PSA_SLOT_FULL nor
+ *             PSA_SLOT_PENDING_DELETION.
+ *             Or a wipe was attempted and the slot's state was not
+ *             PSA_SLOT_PENDING_DELETION.
+ *             Or registered_readers was equal to 0.
+ */
+psa_status_t psa_unregister_read_under_mutex(psa_key_slot_t *slot);
+
 /** Test whether a lifetime designates a key in an external cryptoprocessor.
  *
  * \param lifetime      The lifetime to test.
diff --git a/library/psa_crypto_storage.c b/library/psa_crypto_storage.c
index 13a3c8a..7d1317b 100644
--- a/library/psa_crypto_storage.c
+++ b/library/psa_crypto_storage.c
@@ -235,7 +235,7 @@
 
 void psa_format_key_data_for_storage(const uint8_t *data,
                                      const size_t data_length,
-                                     const psa_core_key_attributes_t *attr,
+                                     const psa_key_attributes_t *attr,
                                      uint8_t *storage_data)
 {
     psa_persistent_key_storage_format *storage_format =
@@ -267,7 +267,7 @@
                                              size_t storage_data_length,
                                              uint8_t **key_data,
                                              size_t *key_data_length,
-                                             psa_core_key_attributes_t *attr)
+                                             psa_key_attributes_t *attr)
 {
     psa_status_t status;
     const psa_persistent_key_storage_format *storage_format =
@@ -314,7 +314,7 @@
     return PSA_SUCCESS;
 }
 
-psa_status_t psa_save_persistent_key(const psa_core_key_attributes_t *attr,
+psa_status_t psa_save_persistent_key(const psa_key_attributes_t *attr,
                                      const uint8_t *data,
                                      const size_t data_length)
 {
@@ -352,7 +352,7 @@
     mbedtls_zeroize_and_free(key_data, key_data_length);
 }
 
-psa_status_t psa_load_persistent_key(psa_core_key_attributes_t *attr,
+psa_status_t psa_load_persistent_key(psa_key_attributes_t *attr,
                                      uint8_t **data,
                                      size_t *data_length)
 {
diff --git a/library/psa_crypto_storage.h b/library/psa_crypto_storage.h
index b6b5e15..f1ea265 100644
--- a/library/psa_crypto_storage.h
+++ b/library/psa_crypto_storage.h
@@ -93,7 +93,7 @@
  * \retval #PSA_ERROR_DATA_INVALID \emptydescription
  * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription
  */
-psa_status_t psa_save_persistent_key(const psa_core_key_attributes_t *attr,
+psa_status_t psa_save_persistent_key(const psa_key_attributes_t *attr,
                                      const uint8_t *data,
                                      const size_t data_length);
 
@@ -123,7 +123,7 @@
  * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription
  * \retval #PSA_ERROR_DOES_NOT_EXIST \emptydescription
  */
-psa_status_t psa_load_persistent_key(psa_core_key_attributes_t *attr,
+psa_status_t psa_load_persistent_key(psa_key_attributes_t *attr,
                                      uint8_t **data,
                                      size_t *data_length);
 
@@ -163,7 +163,7 @@
  */
 void psa_format_key_data_for_storage(const uint8_t *data,
                                      const size_t data_length,
-                                     const psa_core_key_attributes_t *attr,
+                                     const psa_key_attributes_t *attr,
                                      uint8_t *storage_data);
 
 /**
@@ -186,7 +186,7 @@
                                              size_t storage_data_length,
                                              uint8_t **key_data,
                                              size_t *key_data_length,
-                                             psa_core_key_attributes_t *attr);
+                                             psa_key_attributes_t *attr);
 
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
 /** This symbol is defined if transaction support is required. */
diff --git a/library/psa_util.c b/library/psa_util.c
index fd119bf..4ccc5b0 100644
--- a/library/psa_util.c
+++ b/library/psa_util.c
@@ -18,7 +18,7 @@
 
 #include "psa_util_internal.h"
 
-#if defined(MBEDTLS_PSA_CRYPTO_C)
+#if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
 
 #include <psa/crypto.h>
 
@@ -46,6 +46,7 @@
 #if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA)
 #include <mbedtls/cipher.h>
 #endif
+#include <mbedtls/entropy.h>
 
 /* PSA_SUCCESS is kept at the top of each error table since
  * it's the most common status when everything functions properly. */
@@ -164,6 +165,8 @@
             return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
         case PSA_ERROR_INVALID_ARGUMENT:
             return MBEDTLS_ERR_PK_INVALID_ALG;
+        case PSA_ERROR_NOT_PERMITTED:
+            return MBEDTLS_ERR_PK_TYPE_MISMATCH;
         case PSA_ERROR_INSUFFICIENT_MEMORY:
             return MBEDTLS_ERR_PK_ALLOC_FAILED;
         case PSA_ERROR_BAD_STATE:
@@ -336,7 +339,31 @@
 }
 #endif /* PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY */
 
-#endif /* MBEDTLS_PSA_CRYPTO_C */
+/* Wrapper function allowing the classic API to use the PSA RNG.
+ *
+ * `mbedtls_psa_get_random(MBEDTLS_PSA_RANDOM_STATE, ...)` calls
+ * `psa_generate_random(...)`. The state parameter is ignored since the
+ * PSA API doesn't support passing an explicit state.
+ */
+int mbedtls_psa_get_random(void *p_rng,
+                           unsigned char *output,
+                           size_t output_size)
+{
+    /* This function takes a pointer to the RNG state because that's what
+     * classic mbedtls functions using an RNG expect. The PSA RNG manages
+     * its own state internally and doesn't let the caller access that state.
+     * So we just ignore the state parameter, and in practice we'll pass
+     * NULL. */
+    (void) p_rng;
+    psa_status_t status = psa_generate_random(output, output_size);
+    if (status == PSA_SUCCESS) {
+        return 0;
+    } else {
+        return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
+    }
+}
+
+#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */
 
 #if defined(MBEDTLS_PSA_UTIL_HAVE_ECDSA)
 
diff --git a/library/psa_util_internal.h b/library/psa_util_internal.h
index 3e62d5f..70a08a0 100644
--- a/library/psa_util_internal.h
+++ b/library/psa_util_internal.h
@@ -16,7 +16,7 @@
 
 #include "psa/crypto.h"
 
-#if defined(MBEDTLS_PSA_CRYPTO_C)
+#if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
 
 /*************************************************************************
  * FFDH
@@ -96,5 +96,5 @@
                           sizeof(error_list)/sizeof(error_list[0]),   \
                           fallback_f)
 
-#endif /* MBEDTLS_PSA_CRYPTO_C */
+#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */
 #endif /* MBEDTLS_PSA_UTIL_INTERNAL_H */
diff --git a/library/rsa.c b/library/rsa.c
index f4c0862..5debc69 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -108,8 +108,9 @@
         return ret;
     }
 
-    /* mbedtls_asn1_get_tag() already ensures that len is valid (i.e. p+len <= end)*/
-    end = p + len;
+    if (end != p + len) {
+        return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
+    }
 
     if ((ret = mbedtls_asn1_get_int(&p, end, &version)) != 0) {
         return ret;
@@ -241,8 +242,9 @@
         return ret;
     }
 
-    /* mbedtls_asn1_get_tag() already ensures that len is valid (i.e. p+len <= end)*/
-    end = p + len;
+    if (end != p + len) {
+        return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
+    }
 
     /* Import N */
     if ((ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER)) != 0) {
@@ -1015,6 +1017,14 @@
 }
 
 /*
+ * Get length in bits of RSA modulus
+ */
+size_t mbedtls_rsa_get_bitlen(const mbedtls_rsa_context *ctx)
+{
+    return mbedtls_mpi_bitlen(&ctx->N);
+}
+
+/*
  * Get length in bytes of RSA modulus
  */
 size_t mbedtls_rsa_get_len(const mbedtls_rsa_context *ctx)
diff --git a/library/sha3.c b/library/sha3.c
index 81ea6a8..5738559 100644
--- a/library/sha3.c
+++ b/library/sha3.c
@@ -53,14 +53,35 @@
 
 #define XOR_BYTE 0x6
 
-static const uint64_t rc[24] = {
-    0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000,
-    0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
-    0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
-    0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003,
-    0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a,
-    0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
+/* Precomputed masks for the iota transform.
+ *
+ * Each round uses a 64-bit mask value. In each mask values, only
+ * bits whose position is of the form 2^k-1 can be set, thus only
+ * 7 of 64 bits of the mask need to be known for each mask value.
+ *
+ * We use a compressed encoding of the mask where bits 63, 31 and 15
+ * are moved to bits 4-6. This allows us to make each mask value
+ * 1 byte rather than 8 bytes, saving 7*24 = 168 bytes of data (with
+ * perhaps a little variation due to alignment). Decompressing this
+ * requires a little code, but much less than the savings on the table.
+ *
+ * The impact on performance depends on the platform and compiler.
+ * There's a bit more computation, but less memory bandwidth. A quick
+ * benchmark on x86_64 shows a 7% speed improvement with GCC and a
+ * 5% speed penalty with Clang, compared to the naive uint64_t[24] table.
+ * YMMV.
+ */
+/* Helper macro to set the values of the higher bits in unused low positions */
+#define H(b63, b31, b15) (b63 << 6 | b31 << 5 | b15 << 4)
+static const uint8_t iota_r_packed[24] = {
+    H(0, 0, 0) | 0x01, H(0, 0, 1) | 0x82, H(1, 0, 1) | 0x8a, H(1, 1, 1) | 0x00,
+    H(0, 0, 1) | 0x8b, H(0, 1, 0) | 0x01, H(1, 1, 1) | 0x81, H(1, 0, 1) | 0x09,
+    H(0, 0, 0) | 0x8a, H(0, 0, 0) | 0x88, H(0, 1, 1) | 0x09, H(0, 1, 0) | 0x0a,
+    H(0, 1, 1) | 0x8b, H(1, 0, 0) | 0x8b, H(1, 0, 1) | 0x89, H(1, 0, 1) | 0x03,
+    H(1, 0, 1) | 0x02, H(1, 0, 0) | 0x80, H(0, 0, 1) | 0x0a, H(1, 1, 0) | 0x0a,
+    H(1, 1, 1) | 0x81, H(1, 0, 1) | 0x80, H(0, 1, 0) | 0x01, H(1, 1, 1) | 0x08,
 };
+#undef H
 
 static const uint32_t rho[6] = {
     0x3f022425, 0x1c143a09, 0x2c3d3615, 0x27191713, 0x312b382e, 0x3e030832
@@ -215,7 +236,11 @@
 #endif
 
         /* Iota */
-        s[0] ^= rc[round];
+        /* Decompress the round masks (see definition of rc) */
+        s[0] ^= ((iota_r_packed[round] & 0x40ull) << 57 |
+                 (iota_r_packed[round] & 0x20ull) << 26 |
+                 (iota_r_packed[round] & 0x10ull) << 11 |
+                 (iota_r_packed[round] & 0x8f));
     }
 }
 
diff --git a/library/ssl_client.c b/library/ssl_client.c
index 6d988a8..8892acf 100644
--- a/library/ssl_client.c
+++ b/library/ssl_client.c
@@ -765,11 +765,6 @@
           MBEDTLS_SSL_SESSION_TICKETS &&
           MBEDTLS_HAVE_TIME */
 
-    if (ssl->conf->f_rng == NULL) {
-        MBEDTLS_SSL_DEBUG_MSG(1, ("no RNG provided"));
-        return MBEDTLS_ERR_SSL_NO_RNG;
-    }
-
     /* Bet on the highest configured version if we are not in a TLS 1.2
      * renegotiation or session resumption.
      */
diff --git a/library/ssl_debug_helpers.h b/library/ssl_debug_helpers.h
index 2b0e737..a8e3140 100644
--- a/library/ssl_debug_helpers.h
+++ b/library/ssl_debug_helpers.h
@@ -21,6 +21,10 @@
 
 const char *mbedtls_ssl_states_str(mbedtls_ssl_states in);
 
+#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C)
+const char *mbedtls_ssl_early_data_status_str(mbedtls_ssl_early_data_status in);
+#endif
+
 const char *mbedtls_ssl_protocol_version_str(mbedtls_ssl_protocol_version in);
 
 const char *mbedtls_tls_prf_types_str(mbedtls_tls_prf_types in);
diff --git a/library/ssl_misc.h b/library/ssl_misc.h
index 16cd62e..883b988 100644
--- a/library/ssl_misc.h
+++ b/library/ssl_misc.h
@@ -665,21 +665,21 @@
 #if defined(MBEDTLS_SSL_CLI_C)
     /** Minimum TLS version to be negotiated.
      *
-     *  It is set up in the ClientHello writing preparation stage and used
-     *  throughout the ClientHello writing. Not relevant anymore as soon as
-     *  the protocol version has been negotiated thus as soon as the
-     *  ServerHello is received.
-     *  For a fresh handshake not linked to any previous handshake, it is
-     *  equal to the configured minimum minor version to be negotiated. When
-     *  renegotiating or resuming a session, it is equal to the previously
-     *  negotiated minor version.
+     * It is set up in the ClientHello writing preparation stage and used
+     * throughout the ClientHello writing. Not relevant anymore as soon as
+     * the protocol version has been negotiated thus as soon as the
+     * ServerHello is received.
+     * For a fresh handshake not linked to any previous handshake, it is
+     * equal to the configured minimum minor version to be negotiated. When
+     * renegotiating or resuming a session, it is equal to the previously
+     * negotiated minor version.
      *
-     *  There is no maximum TLS version field in this handshake context.
-     *  From the start of the handshake, we need to define a current protocol
-     *  version for the record layer which we define as the maximum TLS
-     *  version to be negotiated. The `tls_version` field of the SSL context is
-     *  used to store this maximum value until it contains the actual
-     *  negotiated value.
+     * There is no maximum TLS version field in this handshake context.
+     * From the start of the handshake, we need to define a current protocol
+     * version for the record layer which we define as the maximum TLS
+     * version to be negotiated. The `tls_version` field of the SSL context is
+     * used to store this maximum value until it contains the actual
+     * negotiated value.
      */
     mbedtls_ssl_protocol_version min_tls_version;
 #endif
@@ -730,15 +730,29 @@
 #if defined(MBEDTLS_SSL_PROTO_TLS1_3)
     uint8_t key_exchange_mode; /*!< Selected key exchange mode */
 
-    /** Number of HelloRetryRequest messages received/sent from/to the server. */
-    int hello_retry_request_count;
+    /**
+     * Flag indicating if, in the course of the current handshake, an
+     * HelloRetryRequest message has been sent by the server or received by
+     * the client (<> 0) or not (0).
+     */
+    uint8_t hello_retry_request_flag;
+
+#if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE)
+    /**
+     * Flag indicating if, in the course of the current handshake, a dummy
+     * change_cipher_spec (CCS) record has already been sent. Used to send only
+     * one CCS per handshake while not complicating the handshake state
+     * transitions for that purpose.
+     */
+    uint8_t ccs_sent;
+#endif
 
 #if defined(MBEDTLS_SSL_SRV_C)
-    /** selected_group of key_share extension in HelloRetryRequest message. */
-    uint16_t hrr_selected_group;
 #if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_PSK_ENABLED)
     uint8_t tls13_kex_modes; /*!< Key exchange modes supported by the client */
 #endif
+    /** selected_group of key_share extension in HelloRetryRequest message. */
+    uint16_t hrr_selected_group;
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
     uint16_t new_session_tickets_count;         /*!< number of session tickets */
 #endif
@@ -2136,6 +2150,9 @@
                                            unsigned char *buf,
                                            const unsigned char *end,
                                            size_t *out_len);
+
+int mbedtls_ssl_tls13_check_early_data_len(mbedtls_ssl_context *ssl,
+                                           size_t early_data_len);
 #endif /* MBEDTLS_SSL_EARLY_DATA */
 
 #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
diff --git a/library/ssl_msg.c b/library/ssl_msg.c
index c2e64c6..0c71157 100644
--- a/library/ssl_msg.c
+++ b/library/ssl_msg.c
@@ -4005,7 +4005,11 @@
                  MBEDTLS_SSL_EARLY_DATA_TRY_TO_DEPROTECT_AND_DISCARD)) {
                 MBEDTLS_SSL_DEBUG_MSG(
                     3, ("EarlyData: deprotect and discard app data records."));
-                /* TODO: Add max_early_data_size check here, see issue 6347 */
+
+                ret = mbedtls_ssl_tls13_check_early_data_len(ssl, rec->data_len);
+                if (ret != 0) {
+                    return ret;
+                }
                 ret = MBEDTLS_ERR_SSL_CONTINUE_PROCESSING;
             }
 #endif /* MBEDTLS_SSL_EARLY_DATA && MBEDTLS_SSL_SRV_C */
@@ -4129,9 +4133,15 @@
      */
     if (ssl->discard_early_data_record == MBEDTLS_SSL_EARLY_DATA_DISCARD) {
         if (rec->type == MBEDTLS_SSL_MSG_APPLICATION_DATA) {
+
+            ret = mbedtls_ssl_tls13_check_early_data_len(ssl, rec->data_len);
+            if (ret != 0) {
+                return ret;
+            }
+
             MBEDTLS_SSL_DEBUG_MSG(
                 3, ("EarlyData: Ignore application message before 2nd ClientHello"));
-            /* TODO: Add max_early_data_size check here, see issue 6347 */
+
             return MBEDTLS_ERR_SSL_CONTINUE_PROCESSING;
         } else if (rec->type == MBEDTLS_SSL_MSG_HANDSHAKE) {
             ssl->discard_early_data_record = MBEDTLS_SSL_EARLY_DATA_NO_DISCARD;
@@ -6058,6 +6068,94 @@
     return ret;
 }
 
+#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C)
+int mbedtls_ssl_write_early_data(mbedtls_ssl_context *ssl,
+                                 const unsigned char *buf, size_t len)
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    const struct mbedtls_ssl_config *conf;
+    int written_data_len = 0;
+
+    MBEDTLS_SSL_DEBUG_MSG(2, ("=> write early_data"));
+
+    if (ssl == NULL || (conf = ssl->conf) == NULL) {
+        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+    }
+
+    if (conf->endpoint != MBEDTLS_SSL_IS_CLIENT) {
+        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+    }
+
+    if ((!mbedtls_ssl_conf_is_tls13_enabled(conf)) ||
+        (conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) ||
+        (conf->early_data_enabled != MBEDTLS_SSL_EARLY_DATA_ENABLED)) {
+        return MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA;
+    }
+
+    if (ssl->tls_version != MBEDTLS_SSL_VERSION_TLS1_3) {
+        return MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA;
+    }
+
+    /*
+     * If we are at the beginning of the handshake, the early data status being
+     * equal to MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN or
+     * MBEDTLS_SSL_EARLY_DATA_STATUS_SENT advance the handshake just
+     * enough to be able to send early data if possible. That way, we can
+     * guarantee that when starting the handshake with this function we will
+     * send at least one record of early data. Note that when the status is
+     * MBEDTLS_SSL_EARLY_DATA_STATUS_SENT and not yet
+     * MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE, we cannot send early data yet
+     * as the early data outbound transform has not been set as we may have to
+     * first send a dummy CCS in clear.
+     */
+    if ((ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN) ||
+        (ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_SENT)) {
+        while ((ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN) ||
+               (ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_SENT)) {
+            ret = mbedtls_ssl_handshake_step(ssl);
+            if (ret != 0) {
+                MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_handshake_step", ret);
+                return ret;
+            }
+
+            ret = mbedtls_ssl_flush_output(ssl);
+            if (ret != 0) {
+                MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_flush_output", ret);
+                return ret;
+            }
+        }
+    } else {
+        /*
+         * If we are past the point where we can send early data, return
+         * immediatly. Otherwise, progress the handshake as much as possible to
+         * not delay it too much. If we reach a point where we can still send
+         * early data, then we will send some.
+         */
+        if ((ssl->early_data_status != MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE) &&
+            (ssl->early_data_status != MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED)) {
+            return MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA;
+        }
+
+        ret = mbedtls_ssl_handshake(ssl);
+        if ((ret != 0) && (ret != MBEDTLS_ERR_SSL_WANT_READ)) {
+            MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_handshake", ret);
+            return ret;
+        }
+    }
+
+    if ((ssl->early_data_status != MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE) &&
+        (ssl->early_data_status != MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED)) {
+        return MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA;
+    }
+
+    written_data_len = ssl_write_real(ssl, buf, len);
+
+    MBEDTLS_SSL_DEBUG_MSG(2, ("<= write early_data, len=%d", written_data_len));
+
+    return written_data_len;
+}
+#endif /* MBEDTLS_SSL_EARLY_DATA && MBEDTLS_SSL_CLI_C */
+
 /*
  * Notify the peer that the connection is being closed
  */
diff --git a/library/ssl_ticket.c b/library/ssl_ticket.c
index cd730fb..5da3887 100644
--- a/library/ssl_ticket.c
+++ b/library/ssl_ticket.c
@@ -75,6 +75,10 @@
 #if defined(MBEDTLS_HAVE_TIME)
     key->generation_time = mbedtls_time(NULL);
 #endif
+    /* The lifetime of a key is the configured lifetime of the tickets when
+     * the key is created.
+     */
+    key->lifetime = ctx->ticket_lifetime;
 
     if ((ret = ctx->f_rng(ctx->p_rng, key->name, sizeof(key->name))) != 0) {
         return ret;
@@ -116,16 +120,17 @@
 #if !defined(MBEDTLS_HAVE_TIME)
     ((void) ctx);
 #else
-    if (ctx->ticket_lifetime != 0) {
+    mbedtls_ssl_ticket_key * const key = ctx->keys + ctx->active;
+    if (key->lifetime != 0) {
         mbedtls_time_t current_time = mbedtls_time(NULL);
-        mbedtls_time_t key_time = ctx->keys[ctx->active].generation_time;
+        mbedtls_time_t key_time = key->generation_time;
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
         psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
 #endif
 
         if (current_time >= key_time &&
-            (uint64_t) (current_time - key_time) < ctx->ticket_lifetime) {
+            (uint64_t) (current_time - key_time) < key->lifetime) {
             return 0;
         }
 
@@ -198,6 +203,8 @@
 #if defined(MBEDTLS_HAVE_TIME)
     key->generation_time = mbedtls_time(NULL);
 #endif
+    key->lifetime = lifetime;
+
     return 0;
 }
 
@@ -331,7 +338,7 @@
 
     key = &ctx->keys[ctx->active];
 
-    *ticket_lifetime = ctx->ticket_lifetime;
+    *ticket_lifetime = key->lifetime;
 
     memcpy(key_name, key->name, TICKET_KEY_NAME_BYTES);
 
@@ -495,43 +502,22 @@
     }
 
 #if defined(MBEDTLS_HAVE_TIME)
-#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
-    if (session->tls_version == MBEDTLS_SSL_VERSION_TLS1_3) {
-        /* Check for expiration */
-        mbedtls_ms_time_t ticket_age = -1;
-#if defined(MBEDTLS_SSL_SRV_C)
-        if (session->endpoint == MBEDTLS_SSL_IS_SERVER) {
-            ticket_age = mbedtls_ms_time() - session->ticket_creation_time;
-        }
-#endif
-#if defined(MBEDTLS_SSL_CLI_C)
-        if (session->endpoint == MBEDTLS_SSL_IS_CLIENT) {
-            ticket_age = mbedtls_ms_time() - session->ticket_reception_time;
-        }
-#endif
+    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 ticket_lifetime =
-            (mbedtls_ms_time_t) ctx->ticket_lifetime * 1000;
-
-        if (ticket_age < 0 || ticket_age > ticket_lifetime) {
-            ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
-            goto cleanup;
-        }
+    ret = mbedtls_ssl_session_get_ticket_creation_time(session,
+                                                       &ticket_creation_time);
+    if (ret != 0) {
+        goto cleanup;
     }
-#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
-#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
-    if (session->tls_version == MBEDTLS_SSL_VERSION_TLS1_2) {
-        /* Check for expiration */
-        mbedtls_time_t current_time = mbedtls_time(NULL);
 
-        if (current_time < session->start ||
-            (uint32_t) (current_time - session->start) > ctx->ticket_lifetime) {
-            ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
-            goto cleanup;
-        }
+    ticket_age = mbedtls_ms_time() - ticket_creation_time;
+    if (ticket_age < 0 || ticket_age > ticket_lifetime) {
+        ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
+        goto cleanup;
     }
-#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
-#endif /* MBEDTLS_HAVE_TIME */
+#endif
 
 cleanup:
 #if defined(MBEDTLS_THREADING_C)
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 0e9f1fd..1bfd180 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -432,10 +432,6 @@
 static int ssl_calc_finished_tls_sha384(mbedtls_ssl_context *, unsigned char *, int);
 #endif /* MBEDTLS_MD_CAN_SHA384*/
 
-static size_t ssl_tls12_session_save(const mbedtls_ssl_session *session,
-                                     unsigned char *buf,
-                                     size_t buf_len);
-
 MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_tls12_session_load(mbedtls_ssl_session *session,
                                   const unsigned char *buf,
@@ -1100,11 +1096,12 @@
 
 #if defined(MBEDTLS_SSL_EARLY_DATA)
 #if defined(MBEDTLS_SSL_CLI_C)
-    ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT;
+    ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN;
 #endif
 #if defined(MBEDTLS_SSL_SRV_C)
     ssl->discard_early_data_record = MBEDTLS_SSL_EARLY_DATA_NO_DISCARD;
 #endif
+    ssl->total_early_data_size = 0;
 #endif /* MBEDTLS_SSL_EARLY_DATA */
 
     /* Initialize structures */
@@ -1365,6 +1362,11 @@
     }
 #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
 
+    if (ssl->conf->f_rng == NULL) {
+        MBEDTLS_SSL_DEBUG_MSG(1, ("no RNG provided"));
+        return MBEDTLS_ERR_SSL_NO_RNG;
+    }
+
     /* Space for further checks */
 
     return 0;
@@ -2448,290 +2450,6 @@
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)
 
-#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
-/* Serialization of TLS 1.3 sessions:
- *
- *     struct {
- *       opaque hostname<0..2^16-1>;
- *       uint64 ticket_reception_time;
- *       uint32 ticket_lifetime;
- *       opaque ticket<1..2^16-1>;
- *     } ClientOnlyData;
- *
- *     struct {
- *       uint8 endpoint;
- *       uint8 ciphersuite[2];
- *       uint32 ticket_age_add;
- *       uint8 ticket_flags;
- *       opaque resumption_key<0..255>;
- *       uint32 max_early_data_size;
- *       uint16 record_size_limit;
- *       select ( endpoint ) {
- *            case client: ClientOnlyData;
- *            case server: uint64 ticket_creation_time;
- *        };
- *     } serialized_session_tls13;
- *
- */
-#if defined(MBEDTLS_SSL_SESSION_TICKETS)
-MBEDTLS_CHECK_RETURN_CRITICAL
-static int ssl_tls13_session_save(const mbedtls_ssl_session *session,
-                                  unsigned char *buf,
-                                  size_t buf_len,
-                                  size_t *olen)
-{
-    unsigned char *p = buf;
-#if defined(MBEDTLS_SSL_CLI_C) && \
-    defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
-    size_t hostname_len = (session->hostname == NULL) ?
-                          0 : strlen(session->hostname) + 1;
-#endif
-    size_t needed =   1                             /* endpoint */
-                    + 2                             /* ciphersuite */
-                    + 4                             /* ticket_age_add */
-                    + 1                             /* ticket_flags */
-                    + 1;                            /* resumption_key length */
-    *olen = 0;
-
-    if (session->resumption_key_len > MBEDTLS_SSL_TLS1_3_TICKET_RESUMPTION_KEY_LEN) {
-        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-    }
-    needed += session->resumption_key_len;  /* resumption_key */
-
-#if defined(MBEDTLS_SSL_EARLY_DATA)
-    needed += 4;                            /* max_early_data_size */
-#endif
-#if defined(MBEDTLS_SSL_RECORD_SIZE_LIMIT)
-    needed += 2;                            /* record_size_limit */
-#endif /* MBEDTLS_SSL_RECORD_SIZE_LIMIT */
-
-#if defined(MBEDTLS_HAVE_TIME)
-    needed += 8; /* ticket_creation_time or ticket_reception_time */
-#endif
-
-#if defined(MBEDTLS_SSL_CLI_C)
-    if (session->endpoint == MBEDTLS_SSL_IS_CLIENT) {
-#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
-        needed +=  2                        /* hostname_len */
-                  + hostname_len;           /* hostname */
-#endif
-
-        needed +=   4                       /* ticket_lifetime */
-                  + 2;                      /* ticket_len */
-
-        /* Check size_t overflow */
-        if (session->ticket_len > SIZE_MAX - needed) {
-            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-        }
-
-        needed += session->ticket_len;      /* ticket */
-    }
-#endif /* MBEDTLS_SSL_CLI_C */
-
-    *olen = needed;
-    if (needed > buf_len) {
-        return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL;
-    }
-
-    p[0] = session->endpoint;
-    MBEDTLS_PUT_UINT16_BE(session->ciphersuite, p, 1);
-    MBEDTLS_PUT_UINT32_BE(session->ticket_age_add, p, 3);
-    p[7] = session->ticket_flags;
-
-    /* save resumption_key */
-    p[8] = session->resumption_key_len;
-    p += 9;
-    memcpy(p, session->resumption_key, session->resumption_key_len);
-    p += session->resumption_key_len;
-
-#if defined(MBEDTLS_SSL_EARLY_DATA)
-    MBEDTLS_PUT_UINT32_BE(session->max_early_data_size, p, 0);
-    p += 4;
-#endif
-#if defined(MBEDTLS_SSL_RECORD_SIZE_LIMIT)
-    MBEDTLS_PUT_UINT16_BE(session->record_size_limit, p, 0);
-    p += 2;
-#endif /* MBEDTLS_SSL_RECORD_SIZE_LIMIT */
-
-#if defined(MBEDTLS_HAVE_TIME) && defined(MBEDTLS_SSL_SRV_C)
-    if (session->endpoint == MBEDTLS_SSL_IS_SERVER) {
-        MBEDTLS_PUT_UINT64_BE((uint64_t) session->ticket_creation_time, p, 0);
-        p += 8;
-    }
-#endif /* MBEDTLS_HAVE_TIME */
-
-#if defined(MBEDTLS_SSL_CLI_C)
-    if (session->endpoint == MBEDTLS_SSL_IS_CLIENT) {
-#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
-        MBEDTLS_PUT_UINT16_BE(hostname_len, p, 0);
-        p += 2;
-        if (hostname_len > 0) {
-            /* save host name */
-            memcpy(p, session->hostname, hostname_len);
-            p += hostname_len;
-        }
-#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */
-
-#if defined(MBEDTLS_HAVE_TIME)
-        MBEDTLS_PUT_UINT64_BE((uint64_t) session->ticket_reception_time, p, 0);
-        p += 8;
-#endif
-        MBEDTLS_PUT_UINT32_BE(session->ticket_lifetime, p, 0);
-        p += 4;
-
-        MBEDTLS_PUT_UINT16_BE(session->ticket_len, p, 0);
-        p += 2;
-
-        if (session->ticket != NULL && session->ticket_len > 0) {
-            memcpy(p, session->ticket, session->ticket_len);
-            p += session->ticket_len;
-        }
-    }
-#endif /* MBEDTLS_SSL_CLI_C */
-    return 0;
-}
-
-MBEDTLS_CHECK_RETURN_CRITICAL
-static int ssl_tls13_session_load(mbedtls_ssl_session *session,
-                                  const unsigned char *buf,
-                                  size_t len)
-{
-    const unsigned char *p = buf;
-    const unsigned char *end = buf + len;
-
-    if (end - p < 9) {
-        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-    }
-    session->endpoint = p[0];
-    session->ciphersuite = MBEDTLS_GET_UINT16_BE(p, 1);
-    session->ticket_age_add = MBEDTLS_GET_UINT32_BE(p, 3);
-    session->ticket_flags = p[7];
-
-    /* load resumption_key */
-    session->resumption_key_len = p[8];
-    p += 9;
-
-    if (end - p < session->resumption_key_len) {
-        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-    }
-
-    if (sizeof(session->resumption_key) < session->resumption_key_len) {
-        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-    }
-    memcpy(session->resumption_key, p, session->resumption_key_len);
-    p += session->resumption_key_len;
-
-#if defined(MBEDTLS_SSL_EARLY_DATA)
-    if (end - p < 4) {
-        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-    }
-    session->max_early_data_size = MBEDTLS_GET_UINT32_BE(p, 0);
-    p += 4;
-#endif
-#if defined(MBEDTLS_SSL_RECORD_SIZE_LIMIT)
-    if (end - p < 2) {
-        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-    }
-    session->record_size_limit = MBEDTLS_GET_UINT16_BE(p, 0);
-    p += 2;
-#endif /* MBEDTLS_SSL_RECORD_SIZE_LIMIT */
-
-#if defined(MBEDTLS_HAVE_TIME) && defined(MBEDTLS_SSL_SRV_C)
-    if (session->endpoint == MBEDTLS_SSL_IS_SERVER) {
-        if (end - p < 8) {
-            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-        }
-        session->ticket_creation_time = MBEDTLS_GET_UINT64_BE(p, 0);
-        p += 8;
-    }
-#endif /* MBEDTLS_HAVE_TIME */
-
-#if defined(MBEDTLS_SSL_CLI_C)
-    if (session->endpoint == MBEDTLS_SSL_IS_CLIENT) {
-#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
-        size_t hostname_len;
-        /* load host name */
-        if (end - p < 2) {
-            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-        }
-        hostname_len = MBEDTLS_GET_UINT16_BE(p, 0);
-        p += 2;
-
-        if (end - p < (long int) hostname_len) {
-            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-        }
-        if (hostname_len > 0) {
-            session->hostname = mbedtls_calloc(1, hostname_len);
-            if (session->hostname == NULL) {
-                return MBEDTLS_ERR_SSL_ALLOC_FAILED;
-            }
-            memcpy(session->hostname, p, hostname_len);
-            p += hostname_len;
-        }
-#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */
-
-#if defined(MBEDTLS_HAVE_TIME)
-        if (end - p < 8) {
-            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-        }
-        session->ticket_reception_time = MBEDTLS_GET_UINT64_BE(p, 0);
-        p += 8;
-#endif
-        if (end - p < 4) {
-            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-        }
-        session->ticket_lifetime = MBEDTLS_GET_UINT32_BE(p, 0);
-        p += 4;
-
-        if (end - p <  2) {
-            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-        }
-        session->ticket_len = MBEDTLS_GET_UINT16_BE(p, 0);
-        p += 2;
-
-        if (end - p < (long int) session->ticket_len) {
-            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-        }
-        if (session->ticket_len > 0) {
-            session->ticket = mbedtls_calloc(1, session->ticket_len);
-            if (session->ticket == NULL) {
-                return MBEDTLS_ERR_SSL_ALLOC_FAILED;
-            }
-            memcpy(session->ticket, p, session->ticket_len);
-            p += session->ticket_len;
-        }
-    }
-#endif /* MBEDTLS_SSL_CLI_C */
-
-    return 0;
-
-}
-#else /* MBEDTLS_SSL_SESSION_TICKETS */
-MBEDTLS_CHECK_RETURN_CRITICAL
-static int ssl_tls13_session_save(const mbedtls_ssl_session *session,
-                                  unsigned char *buf,
-                                  size_t buf_len,
-                                  size_t *olen)
-{
-    ((void) session);
-    ((void) buf);
-    ((void) buf_len);
-    *olen = 0;
-    return MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
-}
-
-static int ssl_tls13_session_load(const mbedtls_ssl_session *session,
-                                  unsigned char *buf,
-                                  size_t buf_len)
-{
-    ((void) session);
-    ((void) buf);
-    ((void) buf_len);
-    return MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
-}
-#endif /* !MBEDTLS_SSL_SESSION_TICKETS */
-#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
-
 psa_status_t mbedtls_ssl_cipher_to_psa(mbedtls_cipher_type_t mbedtls_cipher_type,
                                        size_t taglen,
                                        psa_algorithm_t *alg,
@@ -3648,6 +3366,630 @@
 }
 #endif /* MBEDTLS_SSL_CLI_C */
 
+#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
+
+/* Serialization of TLS 1.2 sessions
+ *
+ * For more detail, see the description of ssl_session_save().
+ */
+static size_t ssl_tls12_session_save(const mbedtls_ssl_session *session,
+                                     unsigned char *buf,
+                                     size_t buf_len)
+{
+    unsigned char *p = buf;
+    size_t used = 0;
+
+#if defined(MBEDTLS_HAVE_TIME)
+    uint64_t start;
+#endif
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    size_t cert_len;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
+    /*
+     * Time
+     */
+#if defined(MBEDTLS_HAVE_TIME)
+    used += 8;
+
+    if (used <= buf_len) {
+        start = (uint64_t) session->start;
+
+        MBEDTLS_PUT_UINT64_BE(start, p, 0);
+        p += 8;
+    }
+#endif /* MBEDTLS_HAVE_TIME */
+
+    /*
+     * Basic mandatory fields
+     */
+    used += 1 /* id_len */
+            + sizeof(session->id)
+            + sizeof(session->master)
+            + 4; /* verify_result */
+
+    if (used <= buf_len) {
+        *p++ = MBEDTLS_BYTE_0(session->id_len);
+        memcpy(p, session->id, 32);
+        p += 32;
+
+        memcpy(p, session->master, 48);
+        p += 48;
+
+        MBEDTLS_PUT_UINT32_BE(session->verify_result, p, 0);
+        p += 4;
+    }
+
+    /*
+     * Peer's end-entity certificate
+     */
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    if (session->peer_cert == NULL) {
+        cert_len = 0;
+    } else {
+        cert_len = session->peer_cert->raw.len;
+    }
+
+    used += 3 + cert_len;
+
+    if (used <= buf_len) {
+        *p++ = MBEDTLS_BYTE_2(cert_len);
+        *p++ = MBEDTLS_BYTE_1(cert_len);
+        *p++ = MBEDTLS_BYTE_0(cert_len);
+
+        if (session->peer_cert != NULL) {
+            memcpy(p, session->peer_cert->raw.p, cert_len);
+            p += cert_len;
+        }
+    }
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+    if (session->peer_cert_digest != NULL) {
+        used += 1 /* type */ + 1 /* length */ + session->peer_cert_digest_len;
+        if (used <= buf_len) {
+            *p++ = (unsigned char) session->peer_cert_digest_type;
+            *p++ = (unsigned char) session->peer_cert_digest_len;
+            memcpy(p, session->peer_cert_digest,
+                   session->peer_cert_digest_len);
+            p += session->peer_cert_digest_len;
+        }
+    } else {
+        used += 2;
+        if (used <= buf_len) {
+            *p++ = (unsigned char) MBEDTLS_MD_NONE;
+            *p++ = 0;
+        }
+    }
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
+    /*
+     * Session ticket if any, plus associated data
+     */
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+#if defined(MBEDTLS_SSL_CLI_C)
+    if (session->endpoint == MBEDTLS_SSL_IS_CLIENT) {
+        used += 3 + session->ticket_len + 4; /* len + ticket + lifetime */
+
+        if (used <= buf_len) {
+            *p++ = MBEDTLS_BYTE_2(session->ticket_len);
+            *p++ = MBEDTLS_BYTE_1(session->ticket_len);
+            *p++ = MBEDTLS_BYTE_0(session->ticket_len);
+
+            if (session->ticket != NULL) {
+                memcpy(p, session->ticket, session->ticket_len);
+                p += session->ticket_len;
+            }
+
+            MBEDTLS_PUT_UINT32_BE(session->ticket_lifetime, p, 0);
+            p += 4;
+        }
+    }
+#endif /* MBEDTLS_SSL_CLI_C */
+#if defined(MBEDTLS_HAVE_TIME) && defined(MBEDTLS_SSL_SRV_C)
+    if (session->endpoint == MBEDTLS_SSL_IS_SERVER) {
+        used += 8;
+
+        if (used <= buf_len) {
+            MBEDTLS_PUT_UINT64_BE((uint64_t) session->ticket_creation_time, p, 0);
+            p += 8;
+        }
+    }
+#endif /* MBEDTLS_HAVE_TIME && MBEDTLS_SSL_SRV_C */
+#endif /* MBEDTLS_SSL_SESSION_TICKETS */
+
+    /*
+     * Misc extension-related info
+     */
+#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+    used += 1;
+
+    if (used <= buf_len) {
+        *p++ = session->mfl_code;
+    }
+#endif
+
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+    used += 1;
+
+    if (used <= buf_len) {
+        *p++ = MBEDTLS_BYTE_0(session->encrypt_then_mac);
+    }
+#endif
+
+    return used;
+}
+
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_tls12_session_load(mbedtls_ssl_session *session,
+                                  const unsigned char *buf,
+                                  size_t len)
+{
+#if defined(MBEDTLS_HAVE_TIME)
+    uint64_t start;
+#endif
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    size_t cert_len;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
+    const unsigned char *p = buf;
+    const unsigned char * const end = buf + len;
+
+    /*
+     * Time
+     */
+#if defined(MBEDTLS_HAVE_TIME)
+    if (8 > (size_t) (end - p)) {
+        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+    }
+
+    start = MBEDTLS_GET_UINT64_BE(p, 0);
+    p += 8;
+
+    session->start = (time_t) start;
+#endif /* MBEDTLS_HAVE_TIME */
+
+    /*
+     * Basic mandatory fields
+     */
+    if (1 + 32 + 48 + 4 > (size_t) (end - p)) {
+        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+    }
+
+    session->id_len = *p++;
+    memcpy(session->id, p, 32);
+    p += 32;
+
+    memcpy(session->master, p, 48);
+    p += 48;
+
+    session->verify_result = MBEDTLS_GET_UINT32_BE(p, 0);
+    p += 4;
+
+    /* Immediately clear invalid pointer values that have been read, in case
+     * we exit early before we replaced them with valid ones. */
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    session->peer_cert = NULL;
+#else
+    session->peer_cert_digest = NULL;
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
+    session->ticket = NULL;
+#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
+
+    /*
+     * Peer certificate
+     */
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    /* Deserialize CRT from the end of the ticket. */
+    if (3 > (size_t) (end - p)) {
+        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+    }
+
+    cert_len = MBEDTLS_GET_UINT24_BE(p, 0);
+    p += 3;
+
+    if (cert_len != 0) {
+        int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+        if (cert_len > (size_t) (end - p)) {
+            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+        }
+
+        session->peer_cert = mbedtls_calloc(1, sizeof(mbedtls_x509_crt));
+
+        if (session->peer_cert == NULL) {
+            return MBEDTLS_ERR_SSL_ALLOC_FAILED;
+        }
+
+        mbedtls_x509_crt_init(session->peer_cert);
+
+        if ((ret = mbedtls_x509_crt_parse_der(session->peer_cert,
+                                              p, cert_len)) != 0) {
+            mbedtls_x509_crt_free(session->peer_cert);
+            mbedtls_free(session->peer_cert);
+            session->peer_cert = NULL;
+            return ret;
+        }
+
+        p += cert_len;
+    }
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+    /* Deserialize CRT digest from the end of the ticket. */
+    if (2 > (size_t) (end - p)) {
+        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+    }
+
+    session->peer_cert_digest_type = (mbedtls_md_type_t) *p++;
+    session->peer_cert_digest_len  = (size_t) *p++;
+
+    if (session->peer_cert_digest_len != 0) {
+        const mbedtls_md_info_t *md_info =
+            mbedtls_md_info_from_type(session->peer_cert_digest_type);
+        if (md_info == NULL) {
+            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+        }
+        if (session->peer_cert_digest_len != mbedtls_md_get_size(md_info)) {
+            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+        }
+
+        if (session->peer_cert_digest_len > (size_t) (end - p)) {
+            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+        }
+
+        session->peer_cert_digest =
+            mbedtls_calloc(1, session->peer_cert_digest_len);
+        if (session->peer_cert_digest == NULL) {
+            return MBEDTLS_ERR_SSL_ALLOC_FAILED;
+        }
+
+        memcpy(session->peer_cert_digest, p,
+               session->peer_cert_digest_len);
+        p += session->peer_cert_digest_len;
+    }
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
+    /*
+     * Session ticket and associated data
+     */
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+#if defined(MBEDTLS_SSL_CLI_C)
+    if (session->endpoint == MBEDTLS_SSL_IS_CLIENT) {
+        if (3 > (size_t) (end - p)) {
+            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+        }
+
+        session->ticket_len = MBEDTLS_GET_UINT24_BE(p, 0);
+        p += 3;
+
+        if (session->ticket_len != 0) {
+            if (session->ticket_len > (size_t) (end - p)) {
+                return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+            }
+
+            session->ticket = mbedtls_calloc(1, session->ticket_len);
+            if (session->ticket == NULL) {
+                return MBEDTLS_ERR_SSL_ALLOC_FAILED;
+            }
+
+            memcpy(session->ticket, p, session->ticket_len);
+            p += session->ticket_len;
+        }
+
+        if (4 > (size_t) (end - p)) {
+            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+        }
+
+        session->ticket_lifetime = MBEDTLS_GET_UINT32_BE(p, 0);
+        p += 4;
+    }
+#endif /* MBEDTLS_SSL_CLI_C */
+#if defined(MBEDTLS_HAVE_TIME) && defined(MBEDTLS_SSL_SRV_C)
+    if (session->endpoint == MBEDTLS_SSL_IS_SERVER) {
+        if (8 > (size_t) (end - p)) {
+            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+        }
+        session->ticket_creation_time = MBEDTLS_GET_UINT64_BE(p, 0);
+        p += 8;
+    }
+#endif /* MBEDTLS_HAVE_TIME && MBEDTLS_SSL_SRV_C */
+#endif /* MBEDTLS_SSL_SESSION_TICKETS */
+
+    /*
+     * Misc extension-related info
+     */
+#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+    if (1 > (size_t) (end - p)) {
+        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+    }
+
+    session->mfl_code = *p++;
+#endif
+
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+    if (1 > (size_t) (end - p)) {
+        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+    }
+
+    session->encrypt_then_mac = *p++;
+#endif
+
+    /* Done, should have consumed entire buffer */
+    if (p != end) {
+        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+    }
+
+    return 0;
+}
+
+#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+/* Serialization of TLS 1.3 sessions:
+ *
+ * For more detail, see the description of ssl_session_save().
+ */
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_tls13_session_save(const mbedtls_ssl_session *session,
+                                  unsigned char *buf,
+                                  size_t buf_len,
+                                  size_t *olen)
+{
+    unsigned char *p = buf;
+#if defined(MBEDTLS_SSL_CLI_C) && \
+    defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
+    size_t hostname_len = (session->hostname == NULL) ?
+                          0 : strlen(session->hostname) + 1;
+#endif
+    size_t needed =   4  /* ticket_age_add */
+                    + 1  /* ticket_flags */
+                    + 1; /* resumption_key length */
+    *olen = 0;
+
+    if (session->resumption_key_len > MBEDTLS_SSL_TLS1_3_TICKET_RESUMPTION_KEY_LEN) {
+        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+    }
+    needed += session->resumption_key_len;  /* resumption_key */
+
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+    needed += 4;                            /* max_early_data_size */
+#endif
+#if defined(MBEDTLS_SSL_RECORD_SIZE_LIMIT)
+    needed += 2;                            /* record_size_limit */
+#endif /* MBEDTLS_SSL_RECORD_SIZE_LIMIT */
+
+#if defined(MBEDTLS_HAVE_TIME)
+    needed += 8; /* ticket_creation_time or ticket_reception_time */
+#endif
+
+#if defined(MBEDTLS_SSL_CLI_C)
+    if (session->endpoint == MBEDTLS_SSL_IS_CLIENT) {
+#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
+        needed +=  2                        /* hostname_len */
+                  + hostname_len;           /* hostname */
+#endif
+
+        needed +=   4                       /* ticket_lifetime */
+                  + 2;                      /* ticket_len */
+
+        /* Check size_t overflow */
+        if (session->ticket_len > SIZE_MAX - needed) {
+            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+        }
+
+        needed += session->ticket_len;      /* ticket */
+    }
+#endif /* MBEDTLS_SSL_CLI_C */
+
+    *olen = needed;
+    if (needed > buf_len) {
+        return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL;
+    }
+
+    MBEDTLS_PUT_UINT32_BE(session->ticket_age_add, p, 0);
+    p[4] = session->ticket_flags;
+
+    /* save resumption_key */
+    p[5] = session->resumption_key_len;
+    p += 6;
+    memcpy(p, session->resumption_key, session->resumption_key_len);
+    p += session->resumption_key_len;
+
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+    MBEDTLS_PUT_UINT32_BE(session->max_early_data_size, p, 0);
+    p += 4;
+#endif
+#if defined(MBEDTLS_SSL_RECORD_SIZE_LIMIT)
+    MBEDTLS_PUT_UINT16_BE(session->record_size_limit, p, 0);
+    p += 2;
+#endif /* MBEDTLS_SSL_RECORD_SIZE_LIMIT */
+
+#if defined(MBEDTLS_HAVE_TIME) && defined(MBEDTLS_SSL_SRV_C)
+    if (session->endpoint == MBEDTLS_SSL_IS_SERVER) {
+        MBEDTLS_PUT_UINT64_BE((uint64_t) session->ticket_creation_time, p, 0);
+        p += 8;
+    }
+#endif /* MBEDTLS_HAVE_TIME */
+
+#if defined(MBEDTLS_SSL_CLI_C)
+    if (session->endpoint == MBEDTLS_SSL_IS_CLIENT) {
+#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
+        MBEDTLS_PUT_UINT16_BE(hostname_len, p, 0);
+        p += 2;
+        if (hostname_len > 0) {
+            /* save host name */
+            memcpy(p, session->hostname, hostname_len);
+            p += hostname_len;
+        }
+#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */
+
+#if defined(MBEDTLS_HAVE_TIME)
+        MBEDTLS_PUT_UINT64_BE((uint64_t) session->ticket_reception_time, p, 0);
+        p += 8;
+#endif
+        MBEDTLS_PUT_UINT32_BE(session->ticket_lifetime, p, 0);
+        p += 4;
+
+        MBEDTLS_PUT_UINT16_BE(session->ticket_len, p, 0);
+        p += 2;
+
+        if (session->ticket != NULL && session->ticket_len > 0) {
+            memcpy(p, session->ticket, session->ticket_len);
+            p += session->ticket_len;
+        }
+    }
+#endif /* MBEDTLS_SSL_CLI_C */
+    return 0;
+}
+
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_tls13_session_load(mbedtls_ssl_session *session,
+                                  const unsigned char *buf,
+                                  size_t len)
+{
+    const unsigned char *p = buf;
+    const unsigned char *end = buf + len;
+
+    if (end - p < 6) {
+        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+    }
+    session->ticket_age_add = MBEDTLS_GET_UINT32_BE(p, 0);
+    session->ticket_flags = p[4];
+
+    /* load resumption_key */
+    session->resumption_key_len = p[5];
+    p += 6;
+
+    if (end - p < session->resumption_key_len) {
+        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+    }
+
+    if (sizeof(session->resumption_key) < session->resumption_key_len) {
+        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+    }
+    memcpy(session->resumption_key, p, session->resumption_key_len);
+    p += session->resumption_key_len;
+
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+    if (end - p < 4) {
+        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+    }
+    session->max_early_data_size = MBEDTLS_GET_UINT32_BE(p, 0);
+    p += 4;
+#endif
+#if defined(MBEDTLS_SSL_RECORD_SIZE_LIMIT)
+    if (end - p < 2) {
+        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+    }
+    session->record_size_limit = MBEDTLS_GET_UINT16_BE(p, 0);
+    p += 2;
+#endif /* MBEDTLS_SSL_RECORD_SIZE_LIMIT */
+
+#if defined(MBEDTLS_HAVE_TIME) && defined(MBEDTLS_SSL_SRV_C)
+    if (session->endpoint == MBEDTLS_SSL_IS_SERVER) {
+        if (end - p < 8) {
+            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+        }
+        session->ticket_creation_time = MBEDTLS_GET_UINT64_BE(p, 0);
+        p += 8;
+    }
+#endif /* MBEDTLS_HAVE_TIME */
+
+#if defined(MBEDTLS_SSL_CLI_C)
+    if (session->endpoint == MBEDTLS_SSL_IS_CLIENT) {
+#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
+        size_t hostname_len;
+        /* load host name */
+        if (end - p < 2) {
+            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+        }
+        hostname_len = MBEDTLS_GET_UINT16_BE(p, 0);
+        p += 2;
+
+        if (end - p < (long int) hostname_len) {
+            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+        }
+        if (hostname_len > 0) {
+            session->hostname = mbedtls_calloc(1, hostname_len);
+            if (session->hostname == NULL) {
+                return MBEDTLS_ERR_SSL_ALLOC_FAILED;
+            }
+            memcpy(session->hostname, p, hostname_len);
+            p += hostname_len;
+        }
+#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */
+
+#if defined(MBEDTLS_HAVE_TIME)
+        if (end - p < 8) {
+            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+        }
+        session->ticket_reception_time = MBEDTLS_GET_UINT64_BE(p, 0);
+        p += 8;
+#endif
+        if (end - p < 4) {
+            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+        }
+        session->ticket_lifetime = MBEDTLS_GET_UINT32_BE(p, 0);
+        p += 4;
+
+        if (end - p <  2) {
+            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+        }
+        session->ticket_len = MBEDTLS_GET_UINT16_BE(p, 0);
+        p += 2;
+
+        if (end - p < (long int) session->ticket_len) {
+            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+        }
+        if (session->ticket_len > 0) {
+            session->ticket = mbedtls_calloc(1, session->ticket_len);
+            if (session->ticket == NULL) {
+                return MBEDTLS_ERR_SSL_ALLOC_FAILED;
+            }
+            memcpy(session->ticket, p, session->ticket_len);
+            p += session->ticket_len;
+        }
+    }
+#endif /* MBEDTLS_SSL_CLI_C */
+
+    return 0;
+
+}
+#else /* MBEDTLS_SSL_SESSION_TICKETS */
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_tls13_session_save(const mbedtls_ssl_session *session,
+                                  unsigned char *buf,
+                                  size_t buf_len,
+                                  size_t *olen)
+{
+    ((void) session);
+    ((void) buf);
+    ((void) buf_len);
+    *olen = 0;
+    return MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
+}
+
+static int ssl_tls13_session_load(const mbedtls_ssl_session *session,
+                                  unsigned char *buf,
+                                  size_t buf_len)
+{
+    ((void) session);
+    ((void) buf);
+    ((void) buf_len);
+    return MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
+}
+#endif /* !MBEDTLS_SSL_SESSION_TICKETS */
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+
 /*
  * Define ticket header determining Mbed TLS version
  * and structure of the ticket.
@@ -3670,6 +4012,12 @@
 #define SSL_SERIALIZED_SESSION_CONFIG_CRT 0
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+#define SSL_SERIALIZED_SESSION_CONFIG_KEEP_PEER_CRT 1
+#else
+#define SSL_SERIALIZED_SESSION_CONFIG_KEEP_PEER_CRT 0
+#endif /* MBEDTLS_SSL_SESSION_TICKETS */
+
 #if defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_SESSION_TICKETS)
 #define SSL_SERIALIZED_SESSION_CONFIG_CLIENT_TICKET 1
 #else
@@ -3694,12 +4042,34 @@
 #define SSL_SERIALIZED_SESSION_CONFIG_TICKET 0
 #endif /* MBEDTLS_SSL_SESSION_TICKETS */
 
+#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
+#define SSL_SERIALIZED_SESSION_CONFIG_SNI 1
+#else
+#define SSL_SERIALIZED_SESSION_CONFIG_SNI 0
+#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */
+
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+#define SSL_SERIALIZED_SESSION_CONFIG_EARLY_DATA 1
+#else
+#define SSL_SERIALIZED_SESSION_CONFIG_EARLY_DATA 0
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
+#if defined(MBEDTLS_SSL_RECORD_SIZE_LIMIT)
+#define SSL_SERIALIZED_SESSION_CONFIG_RECORD_SIZE 1
+#else
+#define SSL_SERIALIZED_SESSION_CONFIG_RECORD_SIZE 0
+#endif /* MBEDTLS_SSL_RECORD_SIZE_LIMIT */
+
 #define SSL_SERIALIZED_SESSION_CONFIG_TIME_BIT          0
 #define SSL_SERIALIZED_SESSION_CONFIG_CRT_BIT           1
 #define SSL_SERIALIZED_SESSION_CONFIG_CLIENT_TICKET_BIT 2
 #define SSL_SERIALIZED_SESSION_CONFIG_MFL_BIT           3
 #define SSL_SERIALIZED_SESSION_CONFIG_ETM_BIT           4
 #define SSL_SERIALIZED_SESSION_CONFIG_TICKET_BIT        5
+#define SSL_SERIALIZED_SESSION_CONFIG_KEEP_PEER_CRT_BIT 6
+#define SSL_SERIALIZED_SESSION_CONFIG_SNI_BIT           7
+#define SSL_SERIALIZED_SESSION_CONFIG_EARLY_DATA_BIT    8
+#define SSL_SERIALIZED_SESSION_CONFIG_RECORD_SIZE_BIT   9
 
 #define SSL_SERIALIZED_SESSION_CONFIG_BITFLAG                           \
     ((uint16_t) (                                                      \
@@ -3709,7 +4079,14 @@
              SSL_SERIALIZED_SESSION_CONFIG_CLIENT_TICKET_BIT) | \
          (SSL_SERIALIZED_SESSION_CONFIG_MFL << SSL_SERIALIZED_SESSION_CONFIG_MFL_BIT) | \
          (SSL_SERIALIZED_SESSION_CONFIG_ETM << SSL_SERIALIZED_SESSION_CONFIG_ETM_BIT) | \
-         (SSL_SERIALIZED_SESSION_CONFIG_TICKET << SSL_SERIALIZED_SESSION_CONFIG_TICKET_BIT)))
+         (SSL_SERIALIZED_SESSION_CONFIG_TICKET << SSL_SERIALIZED_SESSION_CONFIG_TICKET_BIT) | \
+         (SSL_SERIALIZED_SESSION_CONFIG_KEEP_PEER_CRT << \
+             SSL_SERIALIZED_SESSION_CONFIG_KEEP_PEER_CRT_BIT) | \
+         (SSL_SERIALIZED_SESSION_CONFIG_SNI << SSL_SERIALIZED_SESSION_CONFIG_SNI_BIT) | \
+         (SSL_SERIALIZED_SESSION_CONFIG_EARLY_DATA << \
+             SSL_SERIALIZED_SESSION_CONFIG_EARLY_DATA_BIT) | \
+         (SSL_SERIALIZED_SESSION_CONFIG_RECORD_SIZE << \
+             SSL_SERIALIZED_SESSION_CONFIG_RECORD_SIZE_BIT)))
 
 static const unsigned char ssl_serialized_session_header[] = {
     MBEDTLS_VERSION_MAJOR,
@@ -3723,7 +4100,77 @@
  * Serialize a session in the following format:
  * (in the presentation language of TLS, RFC 8446 section 3)
  *
- *  struct {
+ * TLS 1.2 session:
+ *
+ * struct {
+ * #if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ *    opaque ticket<0..2^24-1>;       // length 0 means no ticket
+ *    uint32 ticket_lifetime;
+ * #endif
+ * } ClientOnlyData;
+ *
+ * struct {
+ * #if defined(MBEDTLS_HAVE_TIME)
+ *    uint64 start_time;
+ * #endif
+ *     uint8 session_id_len;           // at most 32
+ *     opaque session_id[32];
+ *     opaque master[48];              // fixed length in the standard
+ *     uint32 verify_result;
+ * #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
+ *    opaque peer_cert<0..2^24-1>;    // length 0 means no peer cert
+ * #else
+ *    uint8 peer_cert_digest_type;
+ *    opaque peer_cert_digest<0..2^8-1>
+ * #endif
+ *     select (endpoint) {
+ *         case client: ClientOnlyData;
+ *         case server: uint64 ticket_creation_time;
+ *     };
+ * #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+ *    uint8 mfl_code;                 // up to 255 according to standard
+ * #endif
+ * #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+ *    uint8 encrypt_then_mac;         // 0 or 1
+ * #endif
+ * } serialized_session_tls12;
+ *
+ *
+ * TLS 1.3 Session:
+ *
+ * struct {
+ * #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
+ *    opaque hostname<0..2^16-1>;
+ * #endif
+ * #if defined(MBEDTLS_HAVE_TIME)
+ *    uint64 ticket_reception_time;
+ * #endif
+ *    uint32 ticket_lifetime;
+ *    opaque ticket<1..2^16-1>;
+ * } ClientOnlyData;
+ *
+ * struct {
+ *    uint32 ticket_age_add;
+ *    uint8 ticket_flags;
+ *    opaque resumption_key<0..255>;
+ * #if defined(MBEDTLS_SSL_EARLY_DATA)
+ *    uint32 max_early_data_size;
+ * #endif
+ * #if defined(MBEDTLS_SSL_RECORD_SIZE_LIMIT)
+ *    uint16 record_size_limit;
+ * #endif
+ *    select ( endpoint ) {
+ *         case client: ClientOnlyData;
+ * #if defined(MBEDTLS_HAVE_TIME)
+ *         case server: uint64 ticket_creation_time;
+ * #endif
+ *     };
+ * } serialized_session_tls13;
+ *
+ *
+ * SSL session:
+ *
+ * struct {
  *
  *    opaque mbedtls_version[3];   // library version: major, minor, patch
  *    opaque session_format[2];    // library-version specific 16-bit field
@@ -3741,6 +4188,8 @@
  *    uint8_t minor_ver;           // Protocol minor version. Possible values:
  *                                 // - TLS 1.2 (0x0303)
  *                                 // - TLS 1.3 (0x0304)
+ *    uint8_t endpoint;
+ *    uint16_t ciphersuite;
  *
  *    select (serialized_session.tls_version) {
  *
@@ -3787,11 +4236,16 @@
     }
 
     /*
-     * TLS version identifier
+     * TLS version identifier, endpoint, ciphersuite
      */
-    used += 1;
+    used += 1    /* TLS version */
+            + 1  /* endpoint */
+            + 2; /* ciphersuite */
     if (used <= buf_len) {
         *p++ = MBEDTLS_BYTE_0(session->tls_version);
+        *p++ = session->endpoint;
+        MBEDTLS_PUT_UINT16_BE(session->ciphersuite, p, 0);
+        p += 2;
     }
 
     /* Forward to version-specific serialization routine. */
@@ -3874,12 +4328,15 @@
     }
 
     /*
-     * TLS version identifier
+     * TLS version identifier, endpoint, ciphersuite
      */
-    if (1 > (size_t) (end - p)) {
+    if (4 > (size_t) (end - p)) {
         return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
     }
     session->tls_version = (mbedtls_ssl_protocol_version) (0x0300 | *p++);
+    session->endpoint = *p++;
+    session->ciphersuite = MBEDTLS_GET_UINT16_BE(p, 0);
+    p += 2;
 
     /* Dispatch according to TLS version. */
     remaining_len = (size_t) (end - p);
@@ -8948,360 +9405,6 @@
 
 #endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */
 
-/* Serialization of TLS 1.2 sessions:
- *
- * struct {
- *    uint64 start_time;
- *    uint8 ciphersuite[2];           // defined by the standard
- *    uint8 session_id_len;           // at most 32
- *    opaque session_id[32];
- *    opaque master[48];              // fixed length in the standard
- *    uint32 verify_result;
- *    opaque peer_cert<0..2^24-1>;    // length 0 means no peer cert
- *    opaque ticket<0..2^24-1>;       // length 0 means no ticket
- *    uint32 ticket_lifetime;
- *    uint8 mfl_code;                 // up to 255 according to standard
- *    uint8 encrypt_then_mac;         // 0 or 1
- * } serialized_session_tls12;
- *
- */
-static size_t ssl_tls12_session_save(const mbedtls_ssl_session *session,
-                                     unsigned char *buf,
-                                     size_t buf_len)
-{
-    unsigned char *p = buf;
-    size_t used = 0;
-
-#if defined(MBEDTLS_HAVE_TIME)
-    uint64_t start;
-#endif
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
-#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
-    size_t cert_len;
-#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
-
-    /*
-     * Time
-     */
-#if defined(MBEDTLS_HAVE_TIME)
-    used += 8;
-
-    if (used <= buf_len) {
-        start = (uint64_t) session->start;
-
-        MBEDTLS_PUT_UINT64_BE(start, p, 0);
-        p += 8;
-    }
-#endif /* MBEDTLS_HAVE_TIME */
-
-    /*
-     * Basic mandatory fields
-     */
-    used += 2   /* ciphersuite */
-            + 1 /* id_len */
-            + sizeof(session->id)
-            + sizeof(session->master)
-            + 4; /* verify_result */
-
-    if (used <= buf_len) {
-        MBEDTLS_PUT_UINT16_BE(session->ciphersuite, p, 0);
-        p += 2;
-
-        *p++ = MBEDTLS_BYTE_0(session->id_len);
-        memcpy(p, session->id, 32);
-        p += 32;
-
-        memcpy(p, session->master, 48);
-        p += 48;
-
-        MBEDTLS_PUT_UINT32_BE(session->verify_result, p, 0);
-        p += 4;
-    }
-
-    /*
-     * Peer's end-entity certificate
-     */
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
-#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
-    if (session->peer_cert == NULL) {
-        cert_len = 0;
-    } else {
-        cert_len = session->peer_cert->raw.len;
-    }
-
-    used += 3 + cert_len;
-
-    if (used <= buf_len) {
-        *p++ = MBEDTLS_BYTE_2(cert_len);
-        *p++ = MBEDTLS_BYTE_1(cert_len);
-        *p++ = MBEDTLS_BYTE_0(cert_len);
-
-        if (session->peer_cert != NULL) {
-            memcpy(p, session->peer_cert->raw.p, cert_len);
-            p += cert_len;
-        }
-    }
-#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
-    if (session->peer_cert_digest != NULL) {
-        used += 1 /* type */ + 1 /* length */ + session->peer_cert_digest_len;
-        if (used <= buf_len) {
-            *p++ = (unsigned char) session->peer_cert_digest_type;
-            *p++ = (unsigned char) session->peer_cert_digest_len;
-            memcpy(p, session->peer_cert_digest,
-                   session->peer_cert_digest_len);
-            p += session->peer_cert_digest_len;
-        }
-    } else {
-        used += 2;
-        if (used <= buf_len) {
-            *p++ = (unsigned char) MBEDTLS_MD_NONE;
-            *p++ = 0;
-        }
-    }
-#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
-
-    /*
-     * Session ticket if any, plus associated data
-     */
-#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
-    used += 3 + session->ticket_len + 4; /* len + ticket + lifetime */
-
-    if (used <= buf_len) {
-        *p++ = MBEDTLS_BYTE_2(session->ticket_len);
-        *p++ = MBEDTLS_BYTE_1(session->ticket_len);
-        *p++ = MBEDTLS_BYTE_0(session->ticket_len);
-
-        if (session->ticket != NULL) {
-            memcpy(p, session->ticket, session->ticket_len);
-            p += session->ticket_len;
-        }
-
-        MBEDTLS_PUT_UINT32_BE(session->ticket_lifetime, p, 0);
-        p += 4;
-    }
-#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
-
-    /*
-     * Misc extension-related info
-     */
-#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
-    used += 1;
-
-    if (used <= buf_len) {
-        *p++ = session->mfl_code;
-    }
-#endif
-
-#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
-    used += 1;
-
-    if (used <= buf_len) {
-        *p++ = MBEDTLS_BYTE_0(session->encrypt_then_mac);
-    }
-#endif
-
-    return used;
-}
-
-MBEDTLS_CHECK_RETURN_CRITICAL
-static int ssl_tls12_session_load(mbedtls_ssl_session *session,
-                                  const unsigned char *buf,
-                                  size_t len)
-{
-#if defined(MBEDTLS_HAVE_TIME)
-    uint64_t start;
-#endif
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
-#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
-    size_t cert_len;
-#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
-
-    const unsigned char *p = buf;
-    const unsigned char * const end = buf + len;
-
-    /*
-     * Time
-     */
-#if defined(MBEDTLS_HAVE_TIME)
-    if (8 > (size_t) (end - p)) {
-        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-    }
-
-    start = MBEDTLS_GET_UINT64_BE(p, 0);
-    p += 8;
-
-    session->start = (time_t) start;
-#endif /* MBEDTLS_HAVE_TIME */
-
-    /*
-     * Basic mandatory fields
-     */
-    if (2 + 1 + 32 + 48 + 4 > (size_t) (end - p)) {
-        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-    }
-
-    session->ciphersuite = MBEDTLS_GET_UINT16_BE(p, 0);
-    p += 2;
-
-    session->id_len = *p++;
-    memcpy(session->id, p, 32);
-    p += 32;
-
-    memcpy(session->master, p, 48);
-    p += 48;
-
-    session->verify_result = MBEDTLS_GET_UINT32_BE(p, 0);
-    p += 4;
-
-    /* Immediately clear invalid pointer values that have been read, in case
-     * we exit early before we replaced them with valid ones. */
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
-#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
-    session->peer_cert = NULL;
-#else
-    session->peer_cert_digest = NULL;
-#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
-#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
-    session->ticket = NULL;
-#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
-
-    /*
-     * Peer certificate
-     */
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
-#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
-    /* Deserialize CRT from the end of the ticket. */
-    if (3 > (size_t) (end - p)) {
-        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-    }
-
-    cert_len = MBEDTLS_GET_UINT24_BE(p, 0);
-    p += 3;
-
-    if (cert_len != 0) {
-        int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-
-        if (cert_len > (size_t) (end - p)) {
-            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-        }
-
-        session->peer_cert = mbedtls_calloc(1, sizeof(mbedtls_x509_crt));
-
-        if (session->peer_cert == NULL) {
-            return MBEDTLS_ERR_SSL_ALLOC_FAILED;
-        }
-
-        mbedtls_x509_crt_init(session->peer_cert);
-
-        if ((ret = mbedtls_x509_crt_parse_der(session->peer_cert,
-                                              p, cert_len)) != 0) {
-            mbedtls_x509_crt_free(session->peer_cert);
-            mbedtls_free(session->peer_cert);
-            session->peer_cert = NULL;
-            return ret;
-        }
-
-        p += cert_len;
-    }
-#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
-    /* Deserialize CRT digest from the end of the ticket. */
-    if (2 > (size_t) (end - p)) {
-        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-    }
-
-    session->peer_cert_digest_type = (mbedtls_md_type_t) *p++;
-    session->peer_cert_digest_len  = (size_t) *p++;
-
-    if (session->peer_cert_digest_len != 0) {
-        const mbedtls_md_info_t *md_info =
-            mbedtls_md_info_from_type(session->peer_cert_digest_type);
-        if (md_info == NULL) {
-            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-        }
-        if (session->peer_cert_digest_len != mbedtls_md_get_size(md_info)) {
-            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-        }
-
-        if (session->peer_cert_digest_len > (size_t) (end - p)) {
-            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-        }
-
-        session->peer_cert_digest =
-            mbedtls_calloc(1, session->peer_cert_digest_len);
-        if (session->peer_cert_digest == NULL) {
-            return MBEDTLS_ERR_SSL_ALLOC_FAILED;
-        }
-
-        memcpy(session->peer_cert_digest, p,
-               session->peer_cert_digest_len);
-        p += session->peer_cert_digest_len;
-    }
-#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
-
-    /*
-     * Session ticket and associated data
-     */
-#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
-    if (3 > (size_t) (end - p)) {
-        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-    }
-
-    session->ticket_len = MBEDTLS_GET_UINT24_BE(p, 0);
-    p += 3;
-
-    if (session->ticket_len != 0) {
-        if (session->ticket_len > (size_t) (end - p)) {
-            return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-        }
-
-        session->ticket = mbedtls_calloc(1, session->ticket_len);
-        if (session->ticket == NULL) {
-            return MBEDTLS_ERR_SSL_ALLOC_FAILED;
-        }
-
-        memcpy(session->ticket, p, session->ticket_len);
-        p += session->ticket_len;
-    }
-
-    if (4 > (size_t) (end - p)) {
-        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-    }
-
-    session->ticket_lifetime = MBEDTLS_GET_UINT32_BE(p, 0);
-    p += 4;
-#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
-
-    /*
-     * Misc extension-related info
-     */
-#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
-    if (1 > (size_t) (end - p)) {
-        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-    }
-
-    session->mfl_code = *p++;
-#endif
-
-#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
-    if (1 > (size_t) (end - p)) {
-        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-    }
-
-    session->encrypt_then_mac = *p++;
-#endif
-
-    /* Done, should have consumed entire buffer */
-    if (p != end) {
-        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
-    }
-
-    return 0;
-}
 #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
 
 int mbedtls_ssl_validate_ciphersuite(
diff --git a/library/ssl_tls12_client.c b/library/ssl_tls12_client.c
index c1ca60c..eac6a3a 100644
--- a/library/ssl_tls12_client.c
+++ b/library/ssl_tls12_client.c
@@ -1268,6 +1268,7 @@
     ssl->tls_version = (mbedtls_ssl_protocol_version) mbedtls_ssl_read_version(buf,
                                                                                ssl->conf->transport);
     ssl->session_negotiate->tls_version = ssl->tls_version;
+    ssl->session_negotiate->endpoint = ssl->conf->endpoint;
 
     if (ssl->tls_version < ssl->conf->min_tls_version ||
         ssl->tls_version > ssl->conf->max_tls_version) {
diff --git a/library/ssl_tls12_server.c b/library/ssl_tls12_server.c
index f242faa..b49a8ae 100644
--- a/library/ssl_tls12_server.c
+++ b/library/ssl_tls12_server.c
@@ -1161,6 +1161,7 @@
     ssl->tls_version = (mbedtls_ssl_protocol_version) mbedtls_ssl_read_version(buf,
                                                                                ssl->conf->transport);
     ssl->session_negotiate->tls_version = ssl->tls_version;
+    ssl->session_negotiate->endpoint = ssl->conf->endpoint;
 
     if (ssl->tls_version != MBEDTLS_SSL_VERSION_TLS1_2) {
         MBEDTLS_SSL_DEBUG_MSG(1, ("server only supports TLS 1.2"));
@@ -2177,11 +2178,6 @@
     }
 #endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */
 
-    if (ssl->conf->f_rng == NULL) {
-        MBEDTLS_SSL_DEBUG_MSG(1, ("no RNG provided"));
-        return MBEDTLS_ERR_SSL_NO_RNG;
-    }
-
     /*
      *     0  .   0   handshake type
      *     1  .   3   handshake length
@@ -2702,8 +2698,7 @@
                              PSA_KEY_TYPE_ECC_KEY_PAIR(ssl->handshake->xxdh_psa_type));
             psa_set_key_bits(&key_attributes, ssl->handshake->xxdh_psa_bits);
 
-            key_len = PSA_BITS_TO_BYTES(key->grp.pbits);
-            ret = mbedtls_ecp_write_key(key, buf, key_len);
+            ret = mbedtls_ecp_write_key_ext(key, &key_len, buf, sizeof(buf));
             if (ret != 0) {
                 mbedtls_platform_zeroize(buf, sizeof(buf));
                 break;
@@ -4281,6 +4276,9 @@
      * 10 .  9+n ticket content
      */
 
+#if defined(MBEDTLS_HAVE_TIME)
+    ssl->session_negotiate->ticket_creation_time = mbedtls_ms_time();
+#endif
     if ((ret = ssl->conf->f_ticket_write(ssl->conf->p_ticket,
                                          ssl->session_negotiate,
                                          ssl->out_msg + 10,
diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c
index f4987b3..88d6c9e 100644
--- a/library/ssl_tls13_client.c
+++ b/library/ssl_tls13_client.c
@@ -1180,26 +1180,29 @@
 #endif
 
 #if defined(MBEDTLS_SSL_EARLY_DATA)
-    if (mbedtls_ssl_conf_tls13_is_some_psk_enabled(ssl) &&
-        ssl_tls13_early_data_has_valid_ticket(ssl) &&
-        ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_ENABLED &&
-        ssl->handshake->hello_retry_request_count == 0) {
+    /* In the first ClientHello, write the early data indication extension if
+     * necessary and update the early data status.
+     * If an HRR has been received and thus we are currently writing the
+     * second ClientHello, the second ClientHello must not contain an early
+     * data extension and the early data status must stay as it is:
+     * MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT or
+     * MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED.
+     */
+    if (!ssl->handshake->hello_retry_request_flag) {
+        if (mbedtls_ssl_conf_tls13_is_some_psk_enabled(ssl) &&
+            ssl_tls13_early_data_has_valid_ticket(ssl) &&
+            ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_ENABLED) {
+            ret = mbedtls_ssl_tls13_write_early_data_ext(
+                ssl, 0, p, end, &ext_len);
+            if (ret != 0) {
+                return ret;
+            }
+            p += ext_len;
 
-        ret = mbedtls_ssl_tls13_write_early_data_ext(
-            ssl, 0, p, end, &ext_len);
-        if (ret != 0) {
-            return ret;
+            ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_STATUS_SENT;
+        } else {
+            ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT;
         }
-        p += ext_len;
-
-        /* Initializes the status to `rejected`. It will be updated to
-         * `accepted` if the EncryptedExtension message contain an early data
-         * indication extension.
-         */
-        ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED;
-    } else {
-        MBEDTLS_SSL_DEBUG_MSG(2, ("<= skip write early_data extension"));
-        ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT;
     }
 #endif /* MBEDTLS_SSL_EARLY_DATA */
 
@@ -1236,7 +1239,7 @@
     size_t psk_len;
     const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
 
-    if (ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED) {
+    if (ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_SENT) {
         MBEDTLS_SSL_DEBUG_MSG(
             1, ("Set hs psk for early data when writing the first psk"));
 
@@ -1299,6 +1302,7 @@
             1, ("Switch to early data keys for outbound traffic"));
         mbedtls_ssl_set_outbound_transform(
             ssl, ssl->handshake->transform_earlydata);
+        ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE;
 #endif
     }
 #endif /* MBEDTLS_SSL_EARLY_DATA */
@@ -1482,10 +1486,8 @@
         return SSL_SERVER_HELLO_TLS1_2;
     }
 
-#if defined(MBEDTLS_SSL_SESSION_TICKETS)
-    ssl->session_negotiate->endpoint = ssl->conf->endpoint;
     ssl->session_negotiate->tls_version = ssl->tls_version;
-#endif /* MBEDTLS_SSL_SESSION_TICKETS */
+    ssl->session_negotiate->endpoint = ssl->conf->endpoint;
 
     handshake->received_extensions = MBEDTLS_SSL_EXT_MASK_NONE;
 
@@ -1501,7 +1503,7 @@
              * to a HelloRetryRequest), it MUST abort the handshake with an
              * "unexpected_message" alert.
              */
-            if (handshake->hello_retry_request_count > 0) {
+            if (handshake->hello_retry_request_flag) {
                 MBEDTLS_SSL_DEBUG_MSG(1, ("Multiple HRRs received"));
                 MBEDTLS_SSL_PEND_FATAL_ALERT(
                     MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE,
@@ -1523,7 +1525,7 @@
                 return MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER;
             }
 
-            handshake->hello_retry_request_count++;
+            handshake->hello_retry_request_flag = 1;
 
             break;
     }
@@ -1678,7 +1680,7 @@
      * proposed in the HRR, we abort the handshake and send an
      * "illegal_parameter" alert.
      */
-    else if ((!is_hrr) && (handshake->hello_retry_request_count > 0) &&
+    else if ((!is_hrr) && handshake->hello_retry_request_flag &&
              (cipher_suite != ssl->session_negotiate->ciphersuite)) {
         fatal_alert = MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER;
     }
@@ -1971,6 +1973,13 @@
     }
 
     ssl->session_negotiate->ciphersuite = ssl->handshake->ciphersuite_info->id;
+
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+    if (ssl->early_data_status != MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT) {
+        ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED;
+    }
+#endif
+
     return 0;
 }
 
@@ -2230,6 +2239,8 @@
         }
 
         ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED;
+    } else if (ssl->early_data_status != MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT) {
+        ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED;
     }
 #endif
 
@@ -2267,6 +2278,7 @@
 
 }
 
+#if defined(MBEDTLS_SSL_EARLY_DATA)
 /*
  * Handler for MBEDTLS_SSL_END_OF_EARLY_DATA
  *
@@ -2305,6 +2317,32 @@
     return ret;
 }
 
+int mbedtls_ssl_get_early_data_status(mbedtls_ssl_context *ssl)
+{
+    if ((ssl->conf->endpoint != MBEDTLS_SSL_IS_CLIENT) ||
+        (!mbedtls_ssl_is_handshake_over(ssl))) {
+        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+    }
+
+    switch (ssl->early_data_status) {
+        case MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT:
+            return MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT;
+            break;
+
+        case MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED:
+            return MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED;
+            break;
+
+        case MBEDTLS_SSL_EARLY_DATA_STATUS_SERVER_FINISHED_RECEIVED:
+            return MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED;
+            break;
+
+        default:
+            return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
+    }
+}
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
 #if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED)
 /*
  * STATE HANDLING: CertificateRequest
@@ -2567,9 +2605,8 @@
 
 #if defined(MBEDTLS_SSL_EARLY_DATA)
     if (ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED) {
+        ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_STATUS_SERVER_FINISHED_RECEIVED;
         mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_END_OF_EARLY_DATA);
-    } else if (ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED) {
-        mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE);
     } else
 #endif /* MBEDTLS_SSL_EARLY_DATA */
     {
@@ -3028,9 +3065,11 @@
             ret = ssl_tls13_process_server_finished(ssl);
             break;
 
+#if defined(MBEDTLS_SSL_EARLY_DATA)
         case MBEDTLS_SSL_END_OF_EARLY_DATA:
             ret = ssl_tls13_write_end_of_early_data(ssl);
             break;
+#endif
 
         case MBEDTLS_SSL_CLIENT_CERTIFICATE:
             ret = ssl_tls13_write_client_certificate(ssl);
@@ -3060,17 +3099,18 @@
 #if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE)
         case MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO:
             ret = mbedtls_ssl_tls13_write_change_cipher_spec(ssl);
-            if (ret == 0) {
-                mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_CLIENT_HELLO);
+            if (ret != 0) {
+                break;
             }
+            mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_CLIENT_HELLO);
             break;
 
         case MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED:
             ret = mbedtls_ssl_tls13_write_change_cipher_spec(ssl);
-            if (ret == 0) {
-                mbedtls_ssl_handshake_set_state(
-                    ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE);
+            if (ret != 0) {
+                break;
             }
+            mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE);
             break;
 
 #if defined(MBEDTLS_SSL_EARLY_DATA)
@@ -3083,6 +3123,7 @@
                     1, ("Switch to early data keys for outbound traffic"));
                 mbedtls_ssl_set_outbound_transform(
                     ssl, ssl->handshake->transform_earlydata);
+                ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE;
             }
             break;
 #endif /* MBEDTLS_SSL_EARLY_DATA */
diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c
index 959f8e6..d448a05 100644
--- a/library/ssl_tls13_generic.c
+++ b/library/ssl_tls13_generic.c
@@ -1379,6 +1379,12 @@
 
     MBEDTLS_SSL_DEBUG_MSG(2, ("=> write change cipher spec"));
 
+    /* Only one CCS to send. */
+    if (ssl->handshake->ccs_sent) {
+        ret = 0;
+        goto cleanup;
+    }
+
     /* Write CCS message */
     MBEDTLS_SSL_PROC_CHK(ssl_tls13_write_change_cipher_spec_body(
                              ssl, ssl->out_msg,
@@ -1390,6 +1396,8 @@
     /* Dispatch message */
     MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_write_record(ssl, 0));
 
+    ssl->handshake->ccs_sent = 1;
+
 cleanup:
 
     MBEDTLS_SSL_DEBUG_MSG(2, ("<= write change cipher spec"));
@@ -1446,6 +1454,54 @@
 
     return 0;
 }
+
+#if defined(MBEDTLS_SSL_SRV_C)
+int mbedtls_ssl_tls13_check_early_data_len(mbedtls_ssl_context *ssl,
+                                           size_t early_data_len)
+{
+    /*
+     * This function should be called only while an handshake is in progress
+     * and thus a session under negotiation. Add a sanity check to detect a
+     * misuse.
+     */
+    if (ssl->session_negotiate == NULL) {
+        return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
+    }
+
+    /* RFC 8446 section 4.6.1
+     *
+     * A server receiving more than max_early_data_size bytes of 0-RTT data
+     * SHOULD terminate the connection with an "unexpected_message" alert.
+     * Note that if it is still possible to send early_data_len bytes of early
+     * data, it means that early_data_len is smaller than max_early_data_size
+     * (type uint32_t) and can fit in an uint32_t. We use this further
+     * down.
+     */
+    if (early_data_len >
+        (ssl->session_negotiate->max_early_data_size -
+         ssl->total_early_data_size)) {
+
+        MBEDTLS_SSL_DEBUG_MSG(
+            2, ("EarlyData: Too much early data received, %u + %" MBEDTLS_PRINTF_SIZET " > %u",
+                ssl->total_early_data_size, early_data_len,
+                ssl->session_negotiate->max_early_data_size));
+
+        MBEDTLS_SSL_PEND_FATAL_ALERT(
+            MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE,
+            MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE);
+        return MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE;
+    }
+
+    /*
+     * early_data_len has been checked to be less than max_early_data_size
+     * that is uint32_t. Its cast to an uint32_t below is thus safe. We need
+     * the cast to appease some compilers.
+     */
+    ssl->total_early_data_size += (uint32_t) early_data_len;
+
+    return 0;
+}
+#endif /* MBEDTLS_SSL_SRV_C */
 #endif /* MBEDTLS_SSL_EARLY_DATA */
 
 /* Reset SSL context and update hash for handling HRR.
diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c
index 62b117c..887c5c6 100644
--- a/library/ssl_tls13_server.c
+++ b/library/ssl_tls13_server.c
@@ -39,6 +39,63 @@
     return ciphersuite_info;
 }
 
+static void ssl_tls13_select_ciphersuite(
+    mbedtls_ssl_context *ssl,
+    const unsigned char *cipher_suites,
+    const unsigned char *cipher_suites_end,
+    int psk_ciphersuite_id,
+    psa_algorithm_t psk_hash_alg,
+    const mbedtls_ssl_ciphersuite_t **selected_ciphersuite_info)
+{
+    *selected_ciphersuite_info = NULL;
+
+    /*
+     * In a compliant ClientHello the byte-length of the list of ciphersuites
+     * is even and this function relies on this fact. This should have been
+     * checked in the main ClientHello parsing function. Double check here.
+     */
+    if ((cipher_suites_end - cipher_suites) & 1) {
+        return;
+    }
+
+    for (const unsigned char *p = cipher_suites;
+         p < cipher_suites_end; p += 2) {
+        /*
+         * "cipher_suites_end - p is even" is an invariant of the loop. As
+         * cipher_suites_end - p > 0, we have cipher_suites_end - p >= 2 and it
+         * is thus safe to read two bytes.
+         */
+        uint16_t id = MBEDTLS_GET_UINT16_BE(p, 0);
+
+        const mbedtls_ssl_ciphersuite_t *info =
+            ssl_tls13_validate_peer_ciphersuite(ssl, id);
+        if (info == NULL) {
+            continue;
+        }
+
+        /*
+         * If a valid PSK ciphersuite identifier has been passed in, we want
+         * an exact match.
+         */
+        if (psk_ciphersuite_id != 0) {
+            if (id != psk_ciphersuite_id) {
+                continue;
+            }
+        } else if (psk_hash_alg != PSA_ALG_NONE) {
+            if (mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) info->mac) !=
+                psk_hash_alg) {
+                continue;
+            }
+        }
+
+        *selected_ciphersuite_info = info;
+        return;
+    }
+
+    MBEDTLS_SSL_DEBUG_MSG(2, ("No matched ciphersuite, psk_ciphersuite_id=%x, psk_hash_alg=%x",
+                              (unsigned) psk_ciphersuite_id, psk_hash_alg));
+}
+
 #if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_PSK_ENABLED)
 /* From RFC 8446:
  *
@@ -90,8 +147,30 @@
     return 0;
 }
 
-#define SSL_TLS1_3_OFFERED_PSK_NOT_MATCH   1
-#define SSL_TLS1_3_OFFERED_PSK_MATCH       0
+/*
+ * Non-error return values of
+ * ssl_tls13_offered_psks_check_identity_match_ticket() and
+ * ssl_tls13_offered_psks_check_identity_match(). They are positive to
+ * not collide with error codes that are negative. Zero
+ * (SSL_TLS1_3_PSK_IDENTITY_MATCH) in case of success as it may be propagated
+ * up by the callers of this function as a generic success condition.
+ *
+ * The return value SSL_TLS1_3_PSK_IDENTITY_MATCH_BUT_PSK_NOT_USABLE means
+ * that the pre-shared-key identity matches that of a ticket or an externally-
+ * provisioned pre-shared-key. We have thus been able to retrieve the
+ * attributes of the pre-shared-key but at least one of them does not meet
+ * some criteria and the pre-shared-key cannot be used. For example, a ticket
+ * is expired or its version is not TLS 1.3. Note eventually that the return
+ * value SSL_TLS1_3_PSK_IDENTITY_MATCH_BUT_PSK_NOT_USABLE does not have
+ * anything to do with binder check. A binder check is done only when a
+ * suitable pre-shared-key has been selected and only for that selected
+ * pre-shared-key: if the binder check fails, we fail the handshake and we do
+ * not try to find another pre-shared-key for which the binder check would
+ * succeed as recommended by the specification.
+ */
+#define SSL_TLS1_3_PSK_IDENTITY_DOES_NOT_MATCH 2
+#define SSL_TLS1_3_PSK_IDENTITY_MATCH_BUT_PSK_NOT_USABLE 1
+#define SSL_TLS1_3_PSK_IDENTITY_MATCH 0
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
 MBEDTLS_CHECK_RETURN_CRITICAL
@@ -109,7 +188,6 @@
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char *ticket_buffer;
-    unsigned int key_exchanges;
 #if defined(MBEDTLS_HAVE_TIME)
     mbedtls_ms_time_t now;
     mbedtls_ms_time_t server_age;
@@ -123,7 +201,7 @@
 
     /* Ticket parser is not configured, Skip */
     if (ssl->conf->f_ticket_parse == NULL || identity_len == 0) {
-        return 0;
+        return SSL_TLS1_3_PSK_IDENTITY_DOES_NOT_MATCH;
     }
 
     /* We create a copy of the encrypted ticket since the ticket parsing
@@ -133,63 +211,51 @@
      */
     ticket_buffer = mbedtls_calloc(1, identity_len);
     if (ticket_buffer == NULL) {
-        MBEDTLS_SSL_DEBUG_MSG(1, ("buffer too small"));
         return MBEDTLS_ERR_SSL_ALLOC_FAILED;
     }
     memcpy(ticket_buffer, identity, identity_len);
 
-    if ((ret = ssl->conf->f_ticket_parse(ssl->conf->p_ticket,
-                                         session,
-                                         ticket_buffer, identity_len)) != 0) {
-        if (ret == MBEDTLS_ERR_SSL_INVALID_MAC) {
-            MBEDTLS_SSL_DEBUG_MSG(3, ("ticket is not authentic"));
-        } else if (ret == MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED) {
+    ret = ssl->conf->f_ticket_parse(ssl->conf->p_ticket,
+                                    session,
+                                    ticket_buffer, identity_len);
+    switch (ret) {
+        case 0:
+            ret = SSL_TLS1_3_PSK_IDENTITY_MATCH;
+            break;
+
+        case MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED:
             MBEDTLS_SSL_DEBUG_MSG(3, ("ticket is expired"));
-        } else {
+            ret = SSL_TLS1_3_PSK_IDENTITY_MATCH_BUT_PSK_NOT_USABLE;
+            break;
+
+        case MBEDTLS_ERR_SSL_INVALID_MAC:
+            MBEDTLS_SSL_DEBUG_MSG(3, ("ticket is not authentic"));
+            ret = SSL_TLS1_3_PSK_IDENTITY_DOES_NOT_MATCH;
+            break;
+
+        default:
             MBEDTLS_SSL_DEBUG_RET(1, "ticket_parse", ret);
-        }
+            ret = SSL_TLS1_3_PSK_IDENTITY_DOES_NOT_MATCH;
     }
 
     /* We delete the temporary buffer */
     mbedtls_free(ticket_buffer);
 
-    if (ret == 0 && session->tls_version != MBEDTLS_SSL_VERSION_TLS1_3) {
-        MBEDTLS_SSL_DEBUG_MSG(3, ("Ticket TLS version is not 1.3."));
-        /* TODO: Define new return value for this case. */
-        ret = MBEDTLS_ERR_SSL_BAD_PROTOCOL_VERSION;
-    }
-
-    if (ret != 0) {
+    if (ret != SSL_TLS1_3_PSK_IDENTITY_MATCH) {
         goto exit;
     }
 
-    /* RFC 8446 section 4.2.9
-     *
-     * Servers SHOULD NOT send NewSessionTicket with tickets that are not
-     * compatible with the advertised modes; however, if a server does so,
-     * the impact will just be that the client's attempts at resumption fail.
-     *
-     * We regard the ticket with incompatible key exchange modes as not match.
+    /*
+     * The identity matches that of a ticket. Now check that it has suitable
+     * attributes and bet it will not be the case.
      */
-    ret = MBEDTLS_ERR_ERROR_GENERIC_ERROR;
-    MBEDTLS_SSL_PRINT_TICKET_FLAGS(4, session->ticket_flags);
+    ret = SSL_TLS1_3_PSK_IDENTITY_MATCH_BUT_PSK_NOT_USABLE;
 
-    key_exchanges = 0;
-    if (mbedtls_ssl_tls13_session_ticket_allow_psk_ephemeral(session) &&
-        ssl_tls13_key_exchange_is_psk_ephemeral_available(ssl)) {
-        key_exchanges |= MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL;
-    }
-    if (mbedtls_ssl_tls13_session_ticket_allow_psk(session) &&
-        ssl_tls13_key_exchange_is_psk_available(ssl)) {
-        key_exchanges |= MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK;
-    }
-
-    if (key_exchanges == 0) {
-        MBEDTLS_SSL_DEBUG_MSG(3, ("No suitable key exchange mode"));
+    if (session->tls_version != MBEDTLS_SSL_VERSION_TLS1_3) {
+        MBEDTLS_SSL_DEBUG_MSG(3, ("Ticket TLS version is not 1.3."));
         goto exit;
     }
 
-    ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
 #if defined(MBEDTLS_HAVE_TIME)
     now = mbedtls_ms_time();
 
@@ -242,13 +308,15 @@
                 age_diff));
         goto exit;
     }
-
-    ret = 0;
-
 #endif /* MBEDTLS_HAVE_TIME */
 
+    /*
+     * All good, we have found a suitable ticket.
+     */
+    ret = SSL_TLS1_3_PSK_IDENTITY_MATCH;
+
 exit:
-    if (ret != 0) {
+    if (ret != SSL_TLS1_3_PSK_IDENTITY_MATCH) {
         mbedtls_ssl_session_free(session);
     }
 
@@ -273,13 +341,11 @@
     *psk_type = MBEDTLS_SSL_TLS1_3_PSK_EXTERNAL;
 
     MBEDTLS_SSL_DEBUG_BUF(4, "identity", identity, identity_len);
-    ssl->handshake->resume = 0;
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
-    if (ssl_tls13_offered_psks_check_identity_match_ticket(
-            ssl, identity, identity_len, obfuscated_ticket_age,
-            session) == SSL_TLS1_3_OFFERED_PSK_MATCH) {
-        ssl->handshake->resume = 1;
+    ret = ssl_tls13_offered_psks_check_identity_match_ticket(
+        ssl, identity, identity_len, obfuscated_ticket_age, session);
+    if (ret == SSL_TLS1_3_PSK_IDENTITY_MATCH) {
         *psk_type = MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION;
         ret = mbedtls_ssl_set_hs_psk(ssl,
                                      session->resumption_key,
@@ -294,7 +360,9 @@
                               session->resumption_key_len);
         MBEDTLS_SSL_DEBUG_MSG(4, ("ticket: obfuscated_ticket_age: %u",
                                   (unsigned) obfuscated_ticket_age));
-        return SSL_TLS1_3_OFFERED_PSK_MATCH;
+        return SSL_TLS1_3_PSK_IDENTITY_MATCH;
+    } else if (ret == SSL_TLS1_3_PSK_IDENTITY_MATCH_BUT_PSK_NOT_USABLE) {
+        return SSL_TLS1_3_PSK_IDENTITY_MATCH_BUT_PSK_NOT_USABLE;
     }
 #endif /* MBEDTLS_SSL_SESSION_TICKETS */
 
@@ -302,9 +370,9 @@
     if (ssl->conf->f_psk != NULL) {
         if (ssl->conf->f_psk(
                 ssl->conf->p_psk, ssl, identity, identity_len) == 0) {
-            return SSL_TLS1_3_OFFERED_PSK_MATCH;
+            return SSL_TLS1_3_PSK_IDENTITY_MATCH;
         }
-        return SSL_TLS1_3_OFFERED_PSK_NOT_MATCH;
+        return SSL_TLS1_3_PSK_IDENTITY_DOES_NOT_MATCH;
     }
 
     MBEDTLS_SSL_DEBUG_BUF(5, "identity", identity, identity_len);
@@ -318,12 +386,20 @@
             MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_set_hs_psk", ret);
             return ret;
         }
-        return SSL_TLS1_3_OFFERED_PSK_MATCH;
+        return SSL_TLS1_3_PSK_IDENTITY_MATCH;
     }
 
-    return SSL_TLS1_3_OFFERED_PSK_NOT_MATCH;
+    return SSL_TLS1_3_PSK_IDENTITY_DOES_NOT_MATCH;
 }
 
+/*
+ * Non-error return values of ssl_tls13_offered_psks_check_binder_match().
+ * They are positive to not collide with error codes that are negative. Zero
+ * (SSL_TLS1_3_BINDER_MATCH) in case of success as it may be propagated up
+ * by the callers of this function as a generic success condition.
+ */
+#define SSL_TLS1_3_BINDER_DOES_NOT_MATCH 1
+#define SSL_TLS1_3_BINDER_MATCH 0
 MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_tls13_offered_psks_check_binder_match(
     mbedtls_ssl_context *ssl,
@@ -368,100 +444,16 @@
     MBEDTLS_SSL_DEBUG_BUF(3, "psk binder ( received ): ", binder, binder_len);
 
     if (mbedtls_ct_memcmp(server_computed_binder, binder, binder_len) == 0) {
-        return SSL_TLS1_3_OFFERED_PSK_MATCH;
+        return SSL_TLS1_3_BINDER_MATCH;
     }
 
     mbedtls_platform_zeroize(server_computed_binder,
                              sizeof(server_computed_binder));
-    return SSL_TLS1_3_OFFERED_PSK_NOT_MATCH;
-}
-
-MBEDTLS_CHECK_RETURN_CRITICAL
-static int ssl_tls13_select_ciphersuite_for_psk(
-    mbedtls_ssl_context *ssl,
-    const unsigned char *cipher_suites,
-    const unsigned char *cipher_suites_end,
-    uint16_t *selected_ciphersuite,
-    const mbedtls_ssl_ciphersuite_t **selected_ciphersuite_info)
-{
-    psa_algorithm_t psk_hash_alg = PSA_ALG_SHA_256;
-
-    *selected_ciphersuite = 0;
-    *selected_ciphersuite_info = NULL;
-
-    /* RFC 8446, page 55.
-     *
-     * For externally established PSKs, the Hash algorithm MUST be set when the
-     * PSK is established or default to SHA-256 if no such algorithm is defined.
-     *
-     */
-
-    /*
-     * Search for a matching ciphersuite
-     */
-    for (const unsigned char *p = cipher_suites;
-         p < cipher_suites_end; p += 2) {
-        uint16_t cipher_suite;
-        const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
-
-        cipher_suite = MBEDTLS_GET_UINT16_BE(p, 0);
-        ciphersuite_info = ssl_tls13_validate_peer_ciphersuite(ssl,
-                                                               cipher_suite);
-        if (ciphersuite_info == NULL) {
-            continue;
-        }
-
-        /* MAC of selected ciphersuite MUST be same with PSK binder if exist.
-         * Otherwise, client should reject.
-         */
-        if (psk_hash_alg ==
-            mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) ciphersuite_info->mac)) {
-            *selected_ciphersuite = cipher_suite;
-            *selected_ciphersuite_info = ciphersuite_info;
-            return 0;
-        }
-    }
-    MBEDTLS_SSL_DEBUG_MSG(2, ("No matched ciphersuite"));
-    return MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE;
+    return SSL_TLS1_3_BINDER_DOES_NOT_MATCH;
 }
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
 MBEDTLS_CHECK_RETURN_CRITICAL
-static int ssl_tls13_select_ciphersuite_for_resumption(
-    mbedtls_ssl_context *ssl,
-    const unsigned char *cipher_suites,
-    const unsigned char *cipher_suites_end,
-    mbedtls_ssl_session *session,
-    uint16_t *selected_ciphersuite,
-    const mbedtls_ssl_ciphersuite_t **selected_ciphersuite_info)
-{
-
-    *selected_ciphersuite = 0;
-    *selected_ciphersuite_info = NULL;
-    for (const unsigned char *p = cipher_suites; p < cipher_suites_end; p += 2) {
-        uint16_t cipher_suite = MBEDTLS_GET_UINT16_BE(p, 0);
-        const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
-
-        if (cipher_suite != session->ciphersuite) {
-            continue;
-        }
-
-        ciphersuite_info = ssl_tls13_validate_peer_ciphersuite(ssl,
-                                                               cipher_suite);
-        if (ciphersuite_info == NULL) {
-            continue;
-        }
-
-        *selected_ciphersuite = cipher_suite;
-        *selected_ciphersuite_info = ciphersuite_info;
-
-        return 0;
-    }
-
-    return MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE;
-}
-
-MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_tls13_session_copy_ticket(mbedtls_ssl_session *dst,
                                          const mbedtls_ssl_session *src)
 {
@@ -481,6 +473,13 @@
 }
 #endif /* MBEDTLS_SSL_SESSION_TICKETS */
 
+struct psk_attributes {
+    int type;
+    int key_exchange_mode;
+    const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
+};
+#define PSK_ATTRIBUTES_INIT { 0, 0, NULL }
+
 /* Parser for pre_shared_key extension in client hello
  *    struct {
  *        opaque identity<1..2^16-1>;
@@ -507,7 +506,8 @@
     const unsigned char *pre_shared_key_ext,
     const unsigned char *pre_shared_key_ext_end,
     const unsigned char *ciphersuites,
-    const unsigned char *ciphersuites_end)
+    const unsigned char *ciphersuites_end,
+    struct psk_attributes *psk)
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     const unsigned char *identities = pre_shared_key_ext;
@@ -558,9 +558,10 @@
         uint32_t obfuscated_ticket_age;
         const unsigned char *binder;
         size_t binder_len;
-        int psk_type;
-        uint16_t cipher_suite;
-        const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
+        int psk_ciphersuite_id;
+        psa_algorithm_t psk_hash_alg;
+        int allowed_key_exchange_modes;
+
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
         mbedtls_ssl_session session;
         mbedtls_ssl_session_init(&session);
@@ -586,47 +587,74 @@
 
         ret = ssl_tls13_offered_psks_check_identity_match(
             ssl, identity, identity_len, obfuscated_ticket_age,
-            &psk_type, &session);
-        if (ret != SSL_TLS1_3_OFFERED_PSK_MATCH) {
+            &psk->type, &session);
+        if (ret != SSL_TLS1_3_PSK_IDENTITY_MATCH) {
             continue;
         }
 
         MBEDTLS_SSL_DEBUG_MSG(4, ("found matched identity"));
-        switch (psk_type) {
+
+        switch (psk->type) {
             case MBEDTLS_SSL_TLS1_3_PSK_EXTERNAL:
-                ret = ssl_tls13_select_ciphersuite_for_psk(
-                    ssl, ciphersuites, ciphersuites_end,
-                    &cipher_suite, &ciphersuite_info);
+                psk_ciphersuite_id = 0;
+                psk_hash_alg = PSA_ALG_SHA_256;
+                allowed_key_exchange_modes =
+                    MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ALL;
                 break;
-            case MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION:
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
-                ret = ssl_tls13_select_ciphersuite_for_resumption(
-                    ssl, ciphersuites, ciphersuites_end, &session,
-                    &cipher_suite, &ciphersuite_info);
-                if (ret != 0) {
-                    mbedtls_ssl_session_free(&session);
-                }
-#else
-                ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
-#endif
+            case MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION:
+                psk_ciphersuite_id = session.ciphersuite;
+                psk_hash_alg = PSA_ALG_NONE;
+                ssl->session_negotiate->ticket_flags = session.ticket_flags;
+                allowed_key_exchange_modes =
+                    session.ticket_flags &
+                    MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ALL;
                 break;
+#endif
             default:
                 return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
         }
-        if (ret != 0) {
-            /* See below, no cipher_suite available, abort handshake */
+
+        psk->key_exchange_mode = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_NONE;
+
+        if ((allowed_key_exchange_modes &
+             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL) &&
+            ssl_tls13_key_exchange_is_psk_ephemeral_available(ssl)) {
+            psk->key_exchange_mode = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL;
+        } else if ((allowed_key_exchange_modes &
+                    MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK) &&
+                   ssl_tls13_key_exchange_is_psk_available(ssl)) {
+            psk->key_exchange_mode = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK;
+        }
+
+        if (psk->key_exchange_mode == MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_NONE) {
+            MBEDTLS_SSL_DEBUG_MSG(3, ("No suitable PSK key exchange mode"));
+            continue;
+        }
+
+        ssl_tls13_select_ciphersuite(ssl, ciphersuites, ciphersuites_end,
+                                     psk_ciphersuite_id, psk_hash_alg,
+                                     &psk->ciphersuite_info);
+
+        if (psk->ciphersuite_info == NULL) {
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+            mbedtls_ssl_session_free(&session);
+#endif
+            /*
+             * We consider finding a ciphersuite suitable for the PSK as part
+             * of the validation of its binder. Thus if we do not find one, we
+             * abort the handshake with a decrypt_error alert.
+             */
             MBEDTLS_SSL_PEND_FATAL_ALERT(
                 MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR,
                 MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE);
-            MBEDTLS_SSL_DEBUG_RET(
-                2, "ssl_tls13_select_ciphersuite", ret);
-            return ret;
+            return MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE;
         }
 
         ret = ssl_tls13_offered_psks_check_binder_match(
-            ssl, binder, binder_len, psk_type,
-            mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) ciphersuite_info->mac));
-        if (ret != SSL_TLS1_3_OFFERED_PSK_MATCH) {
+            ssl, binder, binder_len, psk->type,
+            mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) psk->ciphersuite_info->mac));
+        if (ret != SSL_TLS1_3_BINDER_MATCH) {
             /* For security reasons, the handshake should be aborted when we
              * fail to validate a binder value. See RFC 8446 section 4.2.11.2
              * and appendix E.6. */
@@ -644,13 +672,8 @@
 
         matched_identity = identity_id;
 
-        /* Update handshake parameters */
-        ssl->handshake->ciphersuite_info = ciphersuite_info;
-        ssl->session_negotiate->ciphersuite = cipher_suite;
-        MBEDTLS_SSL_DEBUG_MSG(2, ("overwrite ciphersuite: %04x - %s",
-                                  cipher_suite, ciphersuite_info->name));
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
-        if (psk_type == MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION) {
+        if (psk->type == MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION) {
             ret = ssl_tls13_session_copy_ticket(ssl->session_negotiate,
                                                 &session);
             mbedtls_ssl_session_free(&session);
@@ -676,7 +699,7 @@
         return ret;
     }
     if (matched_identity == -1) {
-        MBEDTLS_SSL_DEBUG_MSG(3, ("No matched PSK or ticket."));
+        MBEDTLS_SSL_DEBUG_MSG(3, ("No usable PSK or ticket."));
         return MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY;
     }
 
@@ -1003,21 +1026,29 @@
 
 #if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_PSK_ENABLED)
 MBEDTLS_CHECK_RETURN_CRITICAL
-static int ssl_tls13_ticket_is_kex_mode_permitted(mbedtls_ssl_context *ssl,
-                                                  unsigned int kex_mode)
+static int ssl_tls13_key_exchange_is_psk_available(mbedtls_ssl_context *ssl)
 {
-#if defined(MBEDTLS_SSL_SESSION_TICKETS)
-    if (ssl->handshake->resume) {
-        if (!mbedtls_ssl_tls13_session_ticket_has_flags(
-                ssl->session_negotiate, kex_mode)) {
-            return 0;
-        }
-    }
+#if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED)
+    return mbedtls_ssl_conf_tls13_is_psk_enabled(ssl) &&
+           mbedtls_ssl_tls13_is_psk_supported(ssl) &&
+           ssl_tls13_client_hello_has_exts_for_psk_key_exchange(ssl);
 #else
     ((void) ssl);
-    ((void) kex_mode);
+    return 0;
 #endif
-    return 1;
+}
+
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_tls13_key_exchange_is_psk_ephemeral_available(mbedtls_ssl_context *ssl)
+{
+#if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED)
+    return mbedtls_ssl_conf_tls13_is_psk_ephemeral_enabled(ssl) &&
+           mbedtls_ssl_tls13_is_psk_ephemeral_supported(ssl) &&
+           ssl_tls13_client_hello_has_exts_for_psk_ephemeral_key_exchange(ssl);
+#else
+    ((void) ssl);
+    return 0;
+#endif
 }
 #endif /* MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_PSK_ENABLED */
 
@@ -1033,83 +1064,6 @@
 #endif
 }
 
-MBEDTLS_CHECK_RETURN_CRITICAL
-static int ssl_tls13_key_exchange_is_psk_available(mbedtls_ssl_context *ssl)
-{
-#if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED)
-    return ssl_tls13_ticket_is_kex_mode_permitted(
-        ssl, MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK) &&
-           mbedtls_ssl_conf_tls13_is_psk_enabled(ssl) &&
-           mbedtls_ssl_tls13_is_psk_supported(ssl) &&
-           ssl_tls13_client_hello_has_exts_for_psk_key_exchange(ssl);
-#else
-    ((void) ssl);
-    return 0;
-#endif
-}
-
-MBEDTLS_CHECK_RETURN_CRITICAL
-static int ssl_tls13_key_exchange_is_psk_ephemeral_available(mbedtls_ssl_context *ssl)
-{
-#if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED)
-    return ssl_tls13_ticket_is_kex_mode_permitted(
-        ssl, MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL) &&
-           mbedtls_ssl_conf_tls13_is_psk_ephemeral_enabled(ssl) &&
-           mbedtls_ssl_tls13_is_psk_ephemeral_supported(ssl) &&
-           ssl_tls13_client_hello_has_exts_for_psk_ephemeral_key_exchange(ssl);
-#else
-    ((void) ssl);
-    return 0;
-#endif
-}
-
-static int ssl_tls13_determine_key_exchange_mode(mbedtls_ssl_context *ssl)
-{
-    /*
-     * Determine the key exchange algorithm to use.
-     * There are three types of key exchanges supported in TLS 1.3:
-     * - (EC)DH with ECDSA,
-     * - (EC)DH with PSK,
-     * - plain PSK.
-     *
-     * The PSK-based key exchanges may additionally be used with 0-RTT.
-     *
-     * Our built-in order of preference is
-     *  1 ) (EC)DHE-PSK Mode ( psk_ephemeral )
-     *  2 ) Certificate Mode ( ephemeral )
-     *  3 ) Plain PSK Mode ( psk )
-     */
-
-    ssl->handshake->key_exchange_mode =
-        MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_NONE;
-
-    if (ssl_tls13_key_exchange_is_psk_ephemeral_available(ssl)) {
-        ssl->handshake->key_exchange_mode =
-            MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL;
-        MBEDTLS_SSL_DEBUG_MSG(2, ("key exchange mode: psk_ephemeral"));
-    } else
-    if (ssl_tls13_key_exchange_is_ephemeral_available(ssl)) {
-        ssl->handshake->key_exchange_mode =
-            MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL;
-        MBEDTLS_SSL_DEBUG_MSG(2, ("key exchange mode: ephemeral"));
-    } else
-    if (ssl_tls13_key_exchange_is_psk_available(ssl)) {
-        ssl->handshake->key_exchange_mode =
-            MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK;
-        MBEDTLS_SSL_DEBUG_MSG(2, ("key exchange mode: psk"));
-    } else {
-        MBEDTLS_SSL_DEBUG_MSG(
-            1,
-            ("ClientHello message misses mandatory extensions."));
-        MBEDTLS_SSL_PEND_FATAL_ALERT(MBEDTLS_SSL_ALERT_MSG_MISSING_EXTENSION,
-                                     MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER);
-        return MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER;
-    }
-
-    return 0;
-
-}
-
 #if defined(MBEDTLS_X509_CRT_PARSE_C) && \
     defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED)
 
@@ -1301,6 +1255,8 @@
     int no_usable_share_for_key_agreement = 0;
 
 #if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_PSK_ENABLED)
+    int got_psk = 0;
+    struct psk_attributes psk = PSK_ATTRIBUTES_INIT;
     const unsigned char *pre_shared_key_ext = NULL;
     const unsigned char *pre_shared_key_ext_end = NULL;
 #endif
@@ -1437,12 +1393,8 @@
      * We negotiate TLS 1.3.
      */
     ssl->tls_version = MBEDTLS_SSL_VERSION_TLS1_3;
-
-#if defined(MBEDTLS_SSL_SESSION_TICKETS)
-    /* Store minor version for later use with ticket serialization. */
     ssl->session_negotiate->tls_version = MBEDTLS_SSL_VERSION_TLS1_3;
     ssl->session_negotiate->endpoint = ssl->conf->endpoint;
-#endif
 
     /*
      * We are negotiating the version 1.3 of the protocol. Do what we have
@@ -1468,37 +1420,20 @@
      */
     MBEDTLS_SSL_DEBUG_BUF(3, "client hello, list of cipher suites",
                           cipher_suites, cipher_suites_len);
-    for (const unsigned char *cipher_suites_p = cipher_suites;
-         cipher_suites_p < cipher_suites_end; cipher_suites_p += 2) {
-        uint16_t cipher_suite;
-        const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
 
-        /*
-         * "cipher_suites_end - cipher_suites_p is even" is an invariant of the
-         * loop. As cipher_suites_end - cipher_suites_p > 0, we have
-         * cipher_suites_end - cipher_suites_p >= 2 and it is thus safe to read
-         * two bytes.
-         */
-        cipher_suite = MBEDTLS_GET_UINT16_BE(cipher_suites_p, 0);
-        ciphersuite_info = ssl_tls13_validate_peer_ciphersuite(
-            ssl, cipher_suite);
-        if (ciphersuite_info == NULL) {
-            continue;
-        }
-
-        ssl->session_negotiate->ciphersuite = cipher_suite;
-        handshake->ciphersuite_info = ciphersuite_info;
-        MBEDTLS_SSL_DEBUG_MSG(2, ("selected ciphersuite: %04x - %s",
-                                  cipher_suite,
-                                  ciphersuite_info->name));
-        break;
-    }
+    ssl_tls13_select_ciphersuite(ssl, cipher_suites, cipher_suites_end,
+                                 0, PSA_ALG_NONE, &handshake->ciphersuite_info);
 
     if (handshake->ciphersuite_info == NULL) {
         MBEDTLS_SSL_PEND_FATAL_ALERT(MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE,
                                      MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE);
         return MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE;
     }
+    ssl->session_negotiate->ciphersuite = handshake->ciphersuite_info->id;
+
+    MBEDTLS_SSL_DEBUG_MSG(2, ("selected ciphersuite: %04x - %s",
+                              ((unsigned) handshake->ciphersuite_info->id),
+                              handshake->ciphersuite_info->name));
 
     /* ...
      * opaque legacy_compression_methods<1..2^8-1>;
@@ -1535,7 +1470,7 @@
         const unsigned char *extension_data_end;
         uint32_t allowed_exts = MBEDTLS_SSL_TLS1_3_ALLOWED_EXTS_OF_CH;
 
-        if (ssl->handshake->hello_retry_request_count > 0) {
+        if (ssl->handshake->hello_retry_request_flag) {
             /* Do not accept early data extension in 2nd ClientHello */
             allowed_exts &= ~MBEDTLS_SSL_EXT_MASK(EARLY_DATA);
         }
@@ -1738,10 +1673,11 @@
     /* Update checksum with either
      * - The entire content of the CH message, if no PSK extension is present
      * - The content up to but excluding the PSK extension, if present.
+     * Always parse the pre-shared-key extension when present in the
+     * ClientHello even if some pre-requisites for PSK key exchange modes are
+     * not met. That way we always validate the syntax of the extension.
      */
-    /* If we've settled on a PSK-based exchange, parse PSK identity ext */
-    if (ssl_tls13_key_exchange_is_psk_available(ssl) ||
-        ssl_tls13_key_exchange_is_psk_ephemeral_available(ssl)) {
+    if (handshake->received_extensions & MBEDTLS_SSL_EXT_MASK(PRE_SHARED_KEY)) {
         ret = handshake->update_checksum(ssl, buf,
                                          pre_shared_key_ext - buf);
         if (0 != ret) {
@@ -1752,10 +1688,11 @@
                                                  pre_shared_key_ext,
                                                  pre_shared_key_ext_end,
                                                  cipher_suites,
-                                                 cipher_suites_end);
-        if (ret == MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY) {
-            handshake->received_extensions &= ~MBEDTLS_SSL_EXT_MASK(PRE_SHARED_KEY);
-        } else if (ret != 0) {
+                                                 cipher_suites_end,
+                                                 &psk);
+        if (ret == 0) {
+            got_psk = 1;
+        } else if (ret != MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY) {
             MBEDTLS_SSL_DEBUG_RET(
                 1, "ssl_tls13_parse_pre_shared_key_ext", ret);
             return ret;
@@ -1770,12 +1707,68 @@
         }
     }
 
-    ret = ssl_tls13_determine_key_exchange_mode(ssl);
-    if (ret < 0) {
-        return ret;
+    /*
+     * Determine the key exchange algorithm to use.
+     * There are three types of key exchanges supported in TLS 1.3:
+     * - (EC)DH with ECDSA,
+     * - (EC)DH with PSK,
+     * - plain PSK.
+     *
+     * The PSK-based key exchanges may additionally be used with 0-RTT.
+     *
+     * Our built-in order of preference is
+     *  1 ) (EC)DHE-PSK Mode ( psk_ephemeral )
+     *  2 ) Certificate Mode ( ephemeral )
+     *  3 ) Plain PSK Mode ( psk )
+     */
+#if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_PSK_ENABLED)
+    if (got_psk && (psk.key_exchange_mode ==
+                    MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL)) {
+        handshake->key_exchange_mode =
+            MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL;
+        MBEDTLS_SSL_DEBUG_MSG(2, ("key exchange mode: psk_ephemeral"));
+
+    } else
+#endif
+    if (ssl_tls13_key_exchange_is_ephemeral_available(ssl)) {
+        handshake->key_exchange_mode =
+            MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL;
+        MBEDTLS_SSL_DEBUG_MSG(2, ("key exchange mode: ephemeral"));
+
+    }
+#if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_PSK_ENABLED)
+    else if (got_psk && (psk.key_exchange_mode ==
+                         MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK)) {
+        handshake->key_exchange_mode = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK;
+        MBEDTLS_SSL_DEBUG_MSG(2, ("key exchange mode: psk"));
+    }
+#endif
+    else {
+        MBEDTLS_SSL_DEBUG_MSG(
+            1,
+            ("ClientHello message misses mandatory extensions."));
+        MBEDTLS_SSL_PEND_FATAL_ALERT(MBEDTLS_SSL_ALERT_MSG_MISSING_EXTENSION,
+                                     MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER);
+        return MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER;
     }
 
-    if (ssl->handshake->key_exchange_mode !=
+#if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_PSK_ENABLED)
+    if (handshake->key_exchange_mode &
+        MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ALL) {
+        handshake->ciphersuite_info = psk.ciphersuite_info;
+        ssl->session_negotiate->ciphersuite = psk.ciphersuite_info->id;
+
+        MBEDTLS_SSL_DEBUG_MSG(2, ("Select PSK ciphersuite: %04x - %s",
+                                  ((unsigned) psk.ciphersuite_info->id),
+                                  psk.ciphersuite_info->name));
+
+        if (psk.type == MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION) {
+            handshake->resume = 1;
+        }
+    }
+#endif
+
+    if (handshake->key_exchange_mode !=
         MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK) {
         hrr_required = (no_usable_share_for_key_agreement != 0);
     }
@@ -1977,10 +1970,6 @@
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char *server_randbytes =
         ssl->handshake->randbytes + MBEDTLS_CLIENT_HELLO_RANDOM_LEN;
-    if (ssl->conf->f_rng == NULL) {
-        MBEDTLS_SSL_DEBUG_MSG(1, ("no RNG provided"));
-        return MBEDTLS_ERR_SSL_NO_RNG;
-    }
 
     if ((ret = ssl->conf->f_rng(ssl->conf->p_rng, server_randbytes,
                                 MBEDTLS_SERVER_HELLO_RANDOM_LEN)) != 0) {
@@ -2431,7 +2420,7 @@
 static int ssl_tls13_prepare_hello_retry_request(mbedtls_ssl_context *ssl)
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    if (ssl->handshake->hello_retry_request_count > 0) {
+    if (ssl->handshake->hello_retry_request_flag) {
         MBEDTLS_SSL_DEBUG_MSG(1, ("Too many HRRs"));
         MBEDTLS_SSL_PEND_FATAL_ALERT(MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE,
                                      MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE);
@@ -2478,7 +2467,7 @@
     MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_finish_handshake_msg(ssl, buf_len,
                                                           msg_len));
 
-    ssl->handshake->hello_retry_request_count++;
+    ssl->handshake->hello_retry_request_flag = 1;
 
 #if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE)
     /* The server sends a dummy change_cipher_spec record immediately
@@ -2917,17 +2906,14 @@
     }
 
     if (ssl->in_msgtype == MBEDTLS_SSL_MSG_APPLICATION_DATA) {
-        MBEDTLS_SSL_DEBUG_MSG(3, ("Received early data"));
-        /* RFC 8446 section 4.6.1
-         *
-         * A server receiving more than max_early_data_size bytes of 0-RTT data
-         * SHOULD terminate the connection with an "unexpected_message" alert.
-         *
-         * TODO: Add received data size check here.
-         */
         if (ssl->in_offt == NULL) {
+            MBEDTLS_SSL_DEBUG_MSG(3, ("Received early data"));
             /* Set the reading pointer */
             ssl->in_offt = ssl->in_msg;
+            ret = mbedtls_ssl_tls13_check_early_data_len(ssl, ssl->in_msglen);
+            if (ret != 0) {
+                return ret;
+            }
         }
         return SSL_GOT_EARLY_DATA;
     }
@@ -3132,10 +3118,6 @@
 
     MBEDTLS_SSL_DEBUG_MSG(2, ("=> prepare NewSessionTicket msg"));
 
-#if defined(MBEDTLS_HAVE_TIME)
-    session->ticket_creation_time = mbedtls_ms_time();
-#endif
-
     /* Set ticket_flags depends on the advertised psk key exchange mode */
     mbedtls_ssl_tls13_session_clear_ticket_flags(
         session, MBEDTLS_SSL_TLS1_3_TICKET_FLAGS_MASK);
@@ -3149,6 +3131,7 @@
         ssl->conf->max_early_data_size > 0) {
         mbedtls_ssl_tls13_session_set_ticket_flags(
             session, MBEDTLS_SSL_TLS1_3_TICKET_ALLOW_EARLY_DATA);
+        session->max_early_data_size = ssl->conf->max_early_data_size;
     }
 #endif /* MBEDTLS_SSL_EARLY_DATA */
 
@@ -3270,6 +3253,9 @@
     MBEDTLS_SSL_CHK_BUF_PTR(p, end, 4 + 4 + 1 + ticket_nonce_size + 2);
 
     /* Generate ticket and ticket_lifetime */
+#if defined(MBEDTLS_HAVE_TIME)
+    session->ticket_creation_time = mbedtls_ms_time();
+#endif
     ret = ssl->conf->f_ticket_write(ssl->conf->p_ticket,
                                     session,
                                     p + 9 + ticket_nonce_size + 2,
@@ -3483,9 +3469,10 @@
 
         case MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO:
             ret = mbedtls_ssl_tls13_write_change_cipher_spec(ssl);
-            if (ret == 0) {
-                mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS);
+            if (ret != 0) {
+                break;
             }
+            mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS);
             break;
 #endif /* MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE */
 
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 7f0160a..2fd56fb 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -3290,4 +3290,12 @@
 }
 #endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
 
+int mbedtls_x509_crt_get_ca_istrue(const mbedtls_x509_crt *crt)
+{
+    if ((crt->ext_types & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS) != 0) {
+        return crt->MBEDTLS_PRIVATE(ca_istrue);
+    }
+    return MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+}
+
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
diff --git a/library/x509_internal.h b/library/x509_internal.h
index 15e097a..8a2d2ed 100644
--- a/library/x509_internal.h
+++ b/library/x509_internal.h
@@ -21,133 +21,6 @@
 #include "mbedtls/rsa.h"
 #endif
 
-/**
- * \brief          Return the next relative DN in an X509 name.
- *
- * \note           Intended use is to compare function result to dn->next
- *                 in order to detect boundaries of multi-valued RDNs.
- *
- * \param dn       Current node in the X509 name
- *
- * \return         Pointer to the first attribute-value pair of the
- *                 next RDN in sequence, or NULL if end is reached.
- */
-static inline mbedtls_x509_name *mbedtls_x509_dn_get_next(
-    mbedtls_x509_name *dn)
-{
-    while (dn->MBEDTLS_PRIVATE(next_merged) && dn->next != NULL) {
-        dn = dn->next;
-    }
-    return dn->next;
-}
-
-/**
- * \brief          Store the certificate serial in printable form into buf;
- *                 no more than size characters will be written.
- *
- * \param buf      Buffer to write to
- * \param size     Maximum size of buffer
- * \param serial   The X509 serial to represent
- *
- * \return         The length of the string written (not including the
- *                 terminated nul byte), or a negative error code.
- */
-int mbedtls_x509_serial_gets(char *buf, size_t size, const mbedtls_x509_buf *serial);
-
-/**
- * \brief          Compare pair of mbedtls_x509_time.
- *
- * \param t1       mbedtls_x509_time to compare
- * \param t2       mbedtls_x509_time to compare
- *
- * \return         < 0 if t1 is before t2
- *                   0 if t1 equals t2
- *                 > 0 if t1 is after t2
- */
-int mbedtls_x509_time_cmp(const mbedtls_x509_time *t1, const mbedtls_x509_time *t2);
-
-#if defined(MBEDTLS_HAVE_TIME_DATE)
-/**
- * \brief          Fill mbedtls_x509_time with provided mbedtls_time_t.
- *
- * \param tt       mbedtls_time_t to convert
- * \param now      mbedtls_x509_time to fill with converted mbedtls_time_t
- *
- * \return         \c 0 on success
- * \return         A non-zero return value on failure.
- */
-int mbedtls_x509_time_gmtime(mbedtls_time_t tt, mbedtls_x509_time *now);
-#endif /* MBEDTLS_HAVE_TIME_DATE */
-
-/**
- * \brief          Check a given mbedtls_x509_time against the system time
- *                 and tell if it's in the past.
- *
- * \note           Intended usage is "if( is_past( valid_to ) ) ERROR".
- *                 Hence the return value of 1 if on internal errors.
- *
- * \param to       mbedtls_x509_time to check
- *
- * \return         1 if the given time is in the past or an error occurred,
- *                 0 otherwise.
- */
-int mbedtls_x509_time_is_past(const mbedtls_x509_time *to);
-
-/**
- * \brief          Check a given mbedtls_x509_time against the system time
- *                 and tell if it's in the future.
- *
- * \note           Intended usage is "if( is_future( valid_from ) ) ERROR".
- *                 Hence the return value of 1 if on internal errors.
- *
- * \param from     mbedtls_x509_time to check
- *
- * \return         1 if the given time is in the future or an error occurred,
- *                 0 otherwise.
- */
-int mbedtls_x509_time_is_future(const mbedtls_x509_time *from);
-
-/**
- * \brief          This function parses an item in the SubjectAlternativeNames
- *                 extension. Please note that this function might allocate
- *                 additional memory for a subject alternative name, thus
- *                 mbedtls_x509_free_subject_alt_name has to be called
- *                 to dispose of this additional memory afterwards.
- *
- * \param san_buf  The buffer holding the raw data item of the subject
- *                 alternative name.
- * \param san      The target structure to populate with the parsed presentation
- *                 of the subject alternative name encoded in \p san_buf.
- *
- * \note           Supported GeneralName types, as defined in RFC 5280:
- *                 "rfc822Name", "dnsName", "directoryName",
- *                 "uniformResourceIdentifier" and "hardware_module_name"
- *                 of type "otherName", as defined in RFC 4108.
- *
- * \note           This function should be called on a single raw data of
- *                 subject alternative name. For example, after successful
- *                 certificate parsing, one must iterate on every item in the
- *                 \c crt->subject_alt_names sequence, and pass it to
- *                 this function.
- *
- * \warning        The target structure contains pointers to the raw data of the
- *                 parsed certificate, and its lifetime is restricted by the
- *                 lifetime of the certificate.
- *
- * \return         \c 0 on success
- * \return         #MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE for an unsupported
- *                 SAN type.
- * \return         Another negative value for any other failure.
- */
-int mbedtls_x509_parse_subject_alt_name(const mbedtls_x509_buf *san_buf,
-                                        mbedtls_x509_subject_alternative_name *san);
-/**
- * \brief          Unallocate all data related to subject alternative name
- *
- * \param san      SAN structure - extra memory owned by this structure will be freed
- */
-void mbedtls_x509_free_subject_alt_name(mbedtls_x509_subject_alternative_name *san);
-
 int mbedtls_x509_get_name(unsigned char **p, const unsigned char *end,
                           mbedtls_x509_name *cur);
 int mbedtls_x509_get_alg_null(unsigned char **p, const unsigned char *end,
diff --git a/pkgconfig/CMakeLists.txt b/pkgconfig/CMakeLists.txt
new file mode 100644
index 0000000..7dfc043
--- /dev/null
+++ b/pkgconfig/CMakeLists.txt
@@ -0,0 +1,25 @@
+if(NOT DISABLE_PACKAGE_CONFIG_AND_INSTALL)
+  include(JoinPaths.cmake)
+  join_paths(PKGCONFIG_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
+  join_paths(PKGCONFIG_LIBDIR "\${prefix}" "${CMAKE_INSTALL_LIBDIR}")
+
+  #define these manually since minimum CMAKE version is not 3.9 for DESCRIPTION and 3.12 for HOMEPAGE_URL usage in project() below.
+  # Prefix with something that won't clash with newer versions of CMAKE.
+  set(PKGCONFIG_PROJECT_DESCRIPTION "Mbed TLS is a C library that implements cryptographic primitives, X.509 certificate manipulation and the SSL/TLS and DTLS protocols. Its small code footprint makes it suitable for embedded systems.")
+  set(PKGCONFIG_PROJECT_HOMEPAGE_URL "https://www.trustedfirmware.org/projects/mbed-tls/")
+
+  configure_file(mbedcrypto.pc.in mbedcrypto.pc @ONLY)
+    install(FILES
+    ${CMAKE_CURRENT_BINARY_DIR}/mbedcrypto.pc
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
+
+  configure_file(mbedtls.pc.in mbedtls.pc @ONLY)
+    install(FILES
+    ${CMAKE_CURRENT_BINARY_DIR}/mbedtls.pc
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
+
+  configure_file(mbedx509.pc.in mbedx509.pc @ONLY)
+    install(FILES
+    ${CMAKE_CURRENT_BINARY_DIR}/mbedx509.pc
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
+endif()
diff --git a/pkgconfig/JoinPaths.cmake b/pkgconfig/JoinPaths.cmake
new file mode 100644
index 0000000..193caed
--- /dev/null
+++ b/pkgconfig/JoinPaths.cmake
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+# This module provides function for joining paths
+# known from most languages
+#
+# Copyright The Mbed TLS Contributors
+#
+# This script originates from:
+#   - https://github.com/jtojnar/cmake-snips
+# Jan has provided re-licensing under Apache 2.0 and GPL 2.0+ and
+# allowed for the change of Copyright.
+#
+# Modelled after Python’s os.path.join
+# https://docs.python.org/3.7/library/os.path.html#os.path.join
+# Windows not supported
+function(join_paths joined_path first_path_segment)
+    set(temp_path "${first_path_segment}")
+    foreach(current_segment IN LISTS ARGN)
+        if(NOT ("${current_segment}" STREQUAL ""))
+            if(IS_ABSOLUTE "${current_segment}")
+                set(temp_path "${current_segment}")
+            else()
+                set(temp_path "${temp_path}/${current_segment}")
+            endif()
+        endif()
+    endforeach()
+    set(${joined_path} "${temp_path}" PARENT_SCOPE)
+endfunction()
diff --git a/pkgconfig/mbedcrypto.pc.in b/pkgconfig/mbedcrypto.pc.in
new file mode 100644
index 0000000..b35afc1
--- /dev/null
+++ b/pkgconfig/mbedcrypto.pc.in
@@ -0,0 +1,10 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+includedir=@PKGCONFIG_INCLUDEDIR@
+libdir=@PKGCONFIG_LIBDIR@
+
+Name: @PROJECT_NAME@
+Description: @PKGCONFIG_PROJECT_DESCRIPTION@
+URL: @PKGCONFIG_PROJECT_HOMEPAGE_URL@
+Version: @PROJECT_VERSION@
+Cflags: -I"${includedir}"
+Libs: -L"${libdir}" -lmbedcrypto
diff --git a/pkgconfig/mbedtls.pc.in b/pkgconfig/mbedtls.pc.in
new file mode 100644
index 0000000..2bfce80
--- /dev/null
+++ b/pkgconfig/mbedtls.pc.in
@@ -0,0 +1,11 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+includedir=@PKGCONFIG_INCLUDEDIR@
+libdir=@PKGCONFIG_LIBDIR@
+
+Name: @PROJECT_NAME@
+Description: @PKGCONFIG_PROJECT_DESCRIPTION@
+URL: @PKGCONFIG_PROJECT_HOMEPAGE_URL@
+Version: @PROJECT_VERSION@
+Requires.private: mbedcrypto mbedx509
+Cflags: -I"${includedir}"
+Libs: -L"${libdir}" -lmbedtls
diff --git a/pkgconfig/mbedx509.pc.in b/pkgconfig/mbedx509.pc.in
new file mode 100644
index 0000000..0ab2e31
--- /dev/null
+++ b/pkgconfig/mbedx509.pc.in
@@ -0,0 +1,11 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+includedir=@PKGCONFIG_INCLUDEDIR@
+libdir=@PKGCONFIG_LIBDIR@
+
+Name: @PROJECT_NAME@
+Description: @PKGCONFIG_PROJECT_DESCRIPTION@
+URL: @PKGCONFIG_PROJECT_HOMEPAGE_URL@
+Version: @PROJECT_VERSION@
+Requires.private: mbedcrypto
+Cflags: -I"${includedir}"
+Libs: -L"${libdir}" -lmbedx509
diff --git a/programs/fuzz/fuzz_client.c b/programs/fuzz/fuzz_client.c
index d4e1d74..07ca96e 100644
--- a/programs/fuzz/fuzz_client.c
+++ b/programs/fuzz/fuzz_client.c
@@ -1,5 +1,3 @@
-#define MBEDTLS_ALLOW_PRIVATE_ACCESS
-
 #include "mbedtls/ssl.h"
 #include "mbedtls/entropy.h"
 #include "mbedtls/ctr_drbg.h"
diff --git a/programs/fuzz/fuzz_dtlsclient.c b/programs/fuzz/fuzz_dtlsclient.c
index 3659026..6581dcb 100644
--- a/programs/fuzz/fuzz_dtlsclient.c
+++ b/programs/fuzz/fuzz_dtlsclient.c
@@ -1,5 +1,3 @@
-#define MBEDTLS_ALLOW_PRIVATE_ACCESS
-
 #include <string.h>
 #include <stdlib.h>
 #include <stdint.h>
diff --git a/programs/fuzz/fuzz_dtlsserver.c b/programs/fuzz/fuzz_dtlsserver.c
index 1632e9d..fd3e0aa 100644
--- a/programs/fuzz/fuzz_dtlsserver.c
+++ b/programs/fuzz/fuzz_dtlsserver.c
@@ -1,5 +1,3 @@
-#define MBEDTLS_ALLOW_PRIVATE_ACCESS
-
 #include <string.h>
 #include <stdlib.h>
 #include <stdint.h>
@@ -137,7 +135,7 @@
     ret = mbedtls_ssl_handshake(&ssl);
 
     if (ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED) {
-        biomemfuzz.Offset = ssl.next_record_offset;
+        biomemfuzz.Offset = ssl.MBEDTLS_PRIVATE(next_record_offset);
         mbedtls_ssl_session_reset(&ssl);
         mbedtls_ssl_set_bio(&ssl, &biomemfuzz, dummy_send, fuzz_recv, fuzz_recv_timeout);
         if (mbedtls_ssl_set_client_transport_id(&ssl, client_ip, sizeof(client_ip)) != 0) {
diff --git a/programs/fuzz/fuzz_privkey.c b/programs/fuzz/fuzz_privkey.c
index ce75624..7530964 100644
--- a/programs/fuzz/fuzz_privkey.c
+++ b/programs/fuzz/fuzz_privkey.c
@@ -1,5 +1,3 @@
-#define MBEDTLS_ALLOW_PRIVATE_ACCESS
-
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
@@ -73,7 +71,7 @@
         if (mbedtls_pk_get_type(&pk) == MBEDTLS_PK_ECKEY ||
             mbedtls_pk_get_type(&pk) == MBEDTLS_PK_ECKEY_DH) {
             mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(pk);
-            mbedtls_ecp_group_id grp_id = ecp->grp.id;
+            mbedtls_ecp_group_id grp_id = mbedtls_ecp_keypair_get_group_id(ecp);
             const mbedtls_ecp_curve_info *curve_info =
                 mbedtls_ecp_curve_info_from_grp_id(grp_id);
 
diff --git a/programs/fuzz/fuzz_pubkey.c b/programs/fuzz/fuzz_pubkey.c
index 9203b4e..0b153b1 100644
--- a/programs/fuzz/fuzz_pubkey.c
+++ b/programs/fuzz/fuzz_pubkey.c
@@ -1,5 +1,3 @@
-#define MBEDTLS_ALLOW_PRIVATE_ACCESS
-
 #include <stdint.h>
 #include <stdlib.h>
 #include "mbedtls/pk.h"
@@ -49,7 +47,7 @@
         if (mbedtls_pk_get_type(&pk) == MBEDTLS_PK_ECKEY ||
             mbedtls_pk_get_type(&pk) == MBEDTLS_PK_ECKEY_DH) {
             mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(pk);
-            mbedtls_ecp_group_id grp_id = ecp->grp.id;
+            mbedtls_ecp_group_id grp_id = mbedtls_ecp_keypair_get_group_id(ecp);
             const mbedtls_ecp_curve_info *curve_info =
                 mbedtls_ecp_curve_info_from_grp_id(grp_id);
 
@@ -61,9 +59,15 @@
 
             /* It's a public key, so the private value should not have
              * been changed from its initialization to 0. */
-            if (mbedtls_mpi_cmp_int(&ecp->d, 0) != 0) {
+            mbedtls_mpi d;
+            mbedtls_mpi_init(&d);
+            if (mbedtls_ecp_export(ecp, NULL, &d, NULL) != 0) {
                 abort();
             }
+            if (mbedtls_mpi_cmp_int(&d, 0) != 0) {
+                abort();
+            }
+            mbedtls_mpi_free(&d);
         } else
 #endif
         {
diff --git a/programs/fuzz/fuzz_server.c b/programs/fuzz/fuzz_server.c
index e767859..64b35ed 100644
--- a/programs/fuzz/fuzz_server.c
+++ b/programs/fuzz/fuzz_server.c
@@ -1,5 +1,3 @@
-#define MBEDTLS_ALLOW_PRIVATE_ACCESS
-
 #include "mbedtls/ssl.h"
 #include "mbedtls/entropy.h"
 #include "mbedtls/ctr_drbg.h"
diff --git a/programs/fuzz/fuzz_x509crl.c b/programs/fuzz/fuzz_x509crl.c
index 313540d..151db92 100644
--- a/programs/fuzz/fuzz_x509crl.c
+++ b/programs/fuzz/fuzz_x509crl.c
@@ -1,5 +1,3 @@
-#define MBEDTLS_ALLOW_PRIVATE_ACCESS
-
 #include <stdint.h>
 #include "mbedtls/x509_crl.h"
 
diff --git a/programs/fuzz/fuzz_x509crt.c b/programs/fuzz/fuzz_x509crt.c
index 8442090..3eee072 100644
--- a/programs/fuzz/fuzz_x509crt.c
+++ b/programs/fuzz/fuzz_x509crt.c
@@ -1,5 +1,3 @@
-#define MBEDTLS_ALLOW_PRIVATE_ACCESS
-
 #include <stdint.h>
 #include "mbedtls/x509_crt.h"
 
diff --git a/programs/fuzz/fuzz_x509csr.c b/programs/fuzz/fuzz_x509csr.c
index 395d3c2..7946e57 100644
--- a/programs/fuzz/fuzz_x509csr.c
+++ b/programs/fuzz/fuzz_x509csr.c
@@ -1,5 +1,3 @@
-#define MBEDTLS_ALLOW_PRIVATE_ACCESS
-
 #include <stdint.h>
 #include "mbedtls/x509_csr.h"
 
diff --git a/programs/pkey/gen_key.c b/programs/pkey/gen_key.c
index 6914c93..194a5cb 100644
--- a/programs/pkey/gen_key.c
+++ b/programs/pkey/gen_key.c
@@ -249,6 +249,7 @@
     mbedtls_mpi_init(&DQ); mbedtls_mpi_init(&QP);
 #endif /* MBEDTLS_RSA_C */
 
+    mbedtls_entropy_init(&entropy);
     mbedtls_pk_init(&key);
     mbedtls_ctr_drbg_init(&ctr_drbg);
     memset(buf, 0, sizeof(buf));
@@ -336,7 +337,6 @@
     mbedtls_printf("\n  . Seeding the random number generator...");
     fflush(stdout);
 
-    mbedtls_entropy_init(&entropy);
 #if !defined(_WIN32) && defined(MBEDTLS_FS_IO)
     if (opt.use_dev_random) {
         if ((ret = mbedtls_entropy_add_source(&entropy, dev_random_entropy_poll,
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 1b3dedb..332befd 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -52,7 +52,7 @@
 #define DFL_KEY_OPAQUE          0
 #define DFL_KEY_PWD             ""
 #define DFL_PSK                 ""
-#define DFL_EARLY_DATA          ""
+#define DFL_EARLY_DATA          -1
 #define DFL_PSK_OPAQUE          0
 #define DFL_PSK_IDENTITY        "Client_identity"
 #define DFL_ECJPAKE_PW          NULL
@@ -347,9 +347,8 @@
 
 #if defined(MBEDTLS_SSL_EARLY_DATA)
 #define USAGE_EARLY_DATA \
-    "    early_data=%%s      The file path to read early data from\n" \
-    "                        default: \"\" (do nothing)\n"            \
-    "                        option: a file path\n"
+    "    early_data=%%d      default: library default\n" \
+    "                        options: 0 (disabled), 1 (enabled)\n"
 #else
 #define USAGE_EARLY_DATA ""
 #endif /* MBEDTLS_SSL_EARLY_DATA && MBEDTLS_SSL_PROTO_TLS1_3 */
@@ -544,7 +543,7 @@
     int reproducible;           /* make communication reproducible          */
     int skip_close_notify;      /* skip sending the close_notify alert      */
 #if defined(MBEDTLS_SSL_EARLY_DATA)
-    const char *early_data;     /* the path of the file to read early data from */
+    int early_data;             /* early data enablement flag               */
 #endif
     int query_config_mode;      /* whether to read config                   */
     int use_srtp;               /* Support SRTP                             */
@@ -717,9 +716,64 @@
     return ret;
 }
 
+/*
+ * Build HTTP request
+ */
+static int build_http_request(unsigned char *buf, size_t buf_size, size_t *request_len)
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    size_t len, tail_len, request_size;
+
+    ret = mbedtls_snprintf((char *) buf, buf_size, GET_REQUEST, opt.request_page);
+    if (ret < 0) {
+        return ret;
+    }
+
+    len = (size_t) ret;
+    tail_len = strlen(GET_REQUEST_END);
+    if (opt.request_size != DFL_REQUEST_SIZE) {
+        request_size = (size_t) opt.request_size;
+    } else {
+        request_size = len + tail_len;
+    }
+
+    if (request_size > buf_size) {
+        return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL;
+    }
+
+    /* Add padding to GET request to reach opt.request_size in length */
+    if (opt.request_size != DFL_REQUEST_SIZE &&
+        len + tail_len < request_size) {
+        memset(buf + len, 'A', request_size - len - tail_len);
+        len = request_size - tail_len;
+    }
+
+    strncpy((char *) buf + len, GET_REQUEST_END, buf_size - len);
+    len += tail_len;
+
+    /* Truncate if request size is smaller than the "natural" size */
+    if (opt.request_size != DFL_REQUEST_SIZE &&
+        len > request_size) {
+        len = request_size;
+
+        /* Still end with \r\n unless that's really not possible */
+        if (len >= 2) {
+            buf[len - 2] = '\r';
+        }
+        if (len >= 1) {
+            buf[len - 1] = '\n';
+        }
+    }
+
+    *request_len = len;
+
+    return 0;
+}
+
 int main(int argc, char *argv[])
 {
-    int ret = 0, len, tail_len, i, written, frags, retry_left;
+    int ret = 0, i;
+    size_t len, written, frags, retry_left;
     int query_config_ret = 0;
     mbedtls_net_context server_fd;
     io_ctx_t io_ctx;
@@ -742,10 +796,6 @@
     size_t cid_renego_len = 0;
 #endif
 
-#if defined(MBEDTLS_SSL_EARLY_DATA)
-    FILE *early_data_fp = NULL;
-#endif /* MBEDTLS_SSL_EARLY_DATA */
-
 #if defined(MBEDTLS_SSL_ALPN)
     const char *alpn_list[ALPN_LIST_SIZE];
 #endif
@@ -833,7 +883,7 @@
     mbedtls_net_init(&server_fd);
     mbedtls_ssl_init(&ssl);
     mbedtls_ssl_config_init(&conf);
-    memset(&saved_session, 0, sizeof(mbedtls_ssl_session));
+    mbedtls_ssl_session_init(&saved_session);
     rng_init(&rng);
 #if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
     mbedtls_x509_crt_init(&cacert);
@@ -1201,7 +1251,15 @@
 #if defined(MBEDTLS_SSL_PROTO_TLS1_3)
 #if defined(MBEDTLS_SSL_EARLY_DATA)
         else if (strcmp(p, "early_data") == 0) {
-            opt.early_data = q;
+            switch (atoi(q)) {
+                case 0:
+                    opt.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED;
+                    break;
+                case 1:
+                    opt.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED;
+                    break;
+                default: goto usage;
+            }
         }
 #endif /* MBEDTLS_SSL_EARLY_DATA */
 
@@ -1711,11 +1769,10 @@
                                      &psa_alg, &psa_alg2,
                                      &usage,
                                      mbedtls_pk_get_type(&pkey)) == 0) {
-            ret = mbedtls_pk_wrap_as_opaque(&pkey, &key_slot, psa_alg,
-                                            usage, psa_alg2);
+            ret = pk_wrap_as_opaque(&pkey, psa_alg, psa_alg2, usage, &key_slot);
             if (ret != 0) {
                 mbedtls_printf(" failed\n  !  "
-                               "mbedtls_pk_wrap_as_opaque returned -0x%x\n\n",
+                               "mbedtls_pk_get_psa_attributes returned -0x%x\n\n",
                                (unsigned int)  -ret);
                 goto exit;
             }
@@ -1968,16 +2025,9 @@
     }
 
 #if defined(MBEDTLS_SSL_EARLY_DATA)
-    int early_data_enabled = MBEDTLS_SSL_EARLY_DATA_DISABLED;
-    if (strlen(opt.early_data) > 0) {
-        if ((early_data_fp = fopen(opt.early_data, "rb")) == NULL) {
-            mbedtls_printf("failed\n  ! Cannot open '%s' for reading.\n",
-                           opt.early_data);
-            goto exit;
-        }
-        early_data_enabled = MBEDTLS_SSL_EARLY_DATA_ENABLED;
+    if (opt.early_data != DFL_EARLY_DATA) {
+        mbedtls_ssl_conf_early_data(&conf, opt.early_data);
     }
-    mbedtls_ssl_conf_early_data(&conf, early_data_enabled);
 #endif /* MBEDTLS_SSL_EARLY_DATA */
 
     if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
@@ -2448,32 +2498,9 @@
     mbedtls_printf("  > Write to server:");
     fflush(stdout);
 
-    len = mbedtls_snprintf((char *) buf, sizeof(buf) - 1, GET_REQUEST,
-                           opt.request_page);
-    tail_len = (int) strlen(GET_REQUEST_END);
-
-    /* Add padding to GET request to reach opt.request_size in length */
-    if (opt.request_size != DFL_REQUEST_SIZE &&
-        len + tail_len < opt.request_size) {
-        memset(buf + len, 'A', opt.request_size - len - tail_len);
-        len += opt.request_size - len - tail_len;
-    }
-
-    strncpy((char *) buf + len, GET_REQUEST_END, sizeof(buf) - len - 1);
-    len += tail_len;
-
-    /* Truncate if request size is smaller than the "natural" size */
-    if (opt.request_size != DFL_REQUEST_SIZE &&
-        len > opt.request_size) {
-        len = opt.request_size;
-
-        /* Still end with \r\n unless that's really not possible */
-        if (len >= 2) {
-            buf[len - 2] = '\r';
-        }
-        if (len >= 1) {
-            buf[len - 1] = '\n';
-        }
+    ret = build_http_request(buf, sizeof(buf) - 1, &len);
+    if (ret != 0) {
+        goto exit;
     }
 
     if (opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM) {
@@ -2545,8 +2572,11 @@
     }
 
     buf[written] = '\0';
-    mbedtls_printf(" %d bytes written in %d fragments\n\n%s\n",
-                   written, frags, (char *) buf);
+    mbedtls_printf(
+        " %" MBEDTLS_PRINTF_SIZET " bytes written in %" MBEDTLS_PRINTF_SIZET " fragments\n\n%s\n",
+        written,
+        frags,
+        (char *) buf);
 
     /* Send a non-empty request if request_size == 0 */
     if (len == 0) {
@@ -2653,7 +2683,9 @@
 
             len = ret;
             buf[len] = '\0';
-            mbedtls_printf("  < Read from server: %d bytes read\n\n%s", len, (char *) buf);
+            mbedtls_printf("  < Read from server: %" MBEDTLS_PRINTF_SIZET " bytes read\n\n%s",
+                           len,
+                           (char *) buf);
             fflush(stdout);
             /* End of message should be detected according to the syntax of the
              * application protocol (eg HTTP), just use a dummy test here. */
@@ -2712,7 +2744,9 @@
 
         len = ret;
         buf[len] = '\0';
-        mbedtls_printf("  < Read from server: %d bytes read\n\n%s", len, (char *) buf);
+        mbedtls_printf("  < Read from server: %" MBEDTLS_PRINTF_SIZET " bytes read\n\n%s",
+                       len,
+                       (char *) buf);
         ret = 0;
     }
 
@@ -3002,6 +3036,54 @@
             goto exit;
         }
 
+        ret = build_http_request(buf, sizeof(buf) - 1, &len);
+        if (ret != 0) {
+            goto exit;
+        }
+
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+        if (ssl.conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_ENABLED) {
+            frags = 0;
+            written = 0;
+            do {
+                while ((ret = mbedtls_ssl_write_early_data(&ssl, buf + written,
+                                                           len - written)) < 0) {
+                    if (ret == MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA) {
+                        goto end_of_early_data;
+                    }
+                    if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
+                        ret != MBEDTLS_ERR_SSL_WANT_WRITE &&
+                        ret != MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) {
+                        mbedtls_printf(" failed\n  ! mbedtls_ssl_write returned -0x%x\n\n",
+                                       (unsigned int) -ret);
+                        goto exit;
+                    }
+
+                    /* For event-driven IO, wait for socket to become available */
+                    if (opt.event == 1 /* level triggered IO */) {
+#if defined(MBEDTLS_TIMING_C)
+                        idle(&server_fd, &timer, ret);
+#else
+                        idle(&server_fd, ret);
+#endif
+                    }
+                }
+
+                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);
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
         while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
             if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
                 ret != MBEDTLS_ERR_SSL_WANT_WRITE &&
@@ -3035,12 +3117,6 @@
     mbedtls_ssl_config_free(&conf);
     mbedtls_ssl_session_free(&saved_session);
 
-#if defined(MBEDTLS_SSL_EARLY_DATA)
-    if (early_data_fp != NULL) {
-        fclose(early_data_fp);
-    }
-#endif
-
     if (session_data != NULL) {
         mbedtls_platform_zeroize(session_data, session_data_len);
     }
diff --git a/programs/ssl/ssl_context_info.c b/programs/ssl/ssl_context_info.c
index c3ae942..ee2cdb7 100644
--- a/programs/ssl/ssl_context_info.c
+++ b/programs/ssl/ssl_context_info.c
@@ -5,8 +5,6 @@
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
-#define MBEDTLS_ALLOW_PRIVATE_ACCESS
-
 #include "mbedtls/build_info.h"
 #include "mbedtls/debug.h"
 #include "mbedtls/platform.h"
@@ -551,23 +549,23 @@
         const mbedtls_md_info_t *md_info;
 #endif
 
-        printf("\tciphersuite    : %s\n", ciphersuite_info->name);
-        printf("\tcipher flags   : 0x%02X\n", ciphersuite_info->flags);
+        printf("\tciphersuite    : %s\n", mbedtls_ssl_ciphersuite_get_name(ciphersuite_info));
+        printf("\tcipher flags   : 0x%02X\n", ciphersuite_info->MBEDTLS_PRIVATE(flags));
 
 #if defined(MBEDTLS_CIPHER_C)
         const mbedtls_cipher_info_t *cipher_info;
-        cipher_info = mbedtls_cipher_info_from_type(ciphersuite_info->cipher);
+        cipher_info = mbedtls_cipher_info_from_type(ciphersuite_info->MBEDTLS_PRIVATE(cipher));
         if (cipher_info == NULL) {
             printf_err("Cannot find cipher info\n");
         } else {
-            printf("\tcipher         : %s\n", cipher_info->name);
+            printf("\tcipher         : %s\n", mbedtls_cipher_info_get_name(cipher_info));
         }
 #else /* MBEDTLS_CIPHER_C */
-        printf("\tcipher type     : %d\n", ciphersuite_info->cipher);
+        printf("\tcipher type     : %d\n", ciphersuite_info->MBEDTLS_PRIVATE(cipher));
 #endif /* MBEDTLS_CIPHER_C */
 
 #if defined(MBEDTLS_MD_C)
-        md_info = mbedtls_md_info_from_type(ciphersuite_info->mac);
+        md_info = mbedtls_md_info_from_type(ciphersuite_info->MBEDTLS_PRIVATE(mac));
         if (md_info == NULL) {
             printf_err("Cannot find Message-Digest info\n");
         } else {
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 48b2282..f00a111 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -1420,7 +1420,6 @@
             return MBEDTLS_ERR_SSL_INVALID_MAC;
         case 2:
             return MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
-#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
         case 3:
             /* Creation time in the future. */
             session->ticket_creation_time = mbedtls_ms_time() + 1000;
@@ -1430,6 +1429,7 @@
             session->ticket_creation_time = mbedtls_ms_time() -
                                             (7 * 24 * 3600 * 1000 + 1000);
             break;
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
         case 5:
             /* Ticket is valid, but client age is below the lower bound of the tolerance window. */
             session->ticket_age_add += MBEDTLS_SSL_TLS1_3_TICKET_AGE_TOLERANCE + 4 * 1000;
@@ -2708,12 +2708,10 @@
                                      &psa_alg, &psa_alg2,
                                      &psa_usage,
                                      mbedtls_pk_get_type(&pkey)) == 0) {
-            ret = mbedtls_pk_wrap_as_opaque(&pkey, &key_slot,
-                                            psa_alg, psa_usage, psa_alg2);
-
+            ret = pk_wrap_as_opaque(&pkey, psa_alg, psa_alg2, psa_usage, &key_slot);
             if (ret != 0) {
                 mbedtls_printf(" failed\n  !  "
-                               "mbedtls_pk_wrap_as_opaque returned -0x%x\n\n",
+                               "pk_wrap_as_opaque returned -0x%x\n\n",
                                (unsigned int)  -ret);
                 goto exit;
             }
@@ -2727,12 +2725,10 @@
                                      &psa_alg, &psa_alg2,
                                      &psa_usage,
                                      mbedtls_pk_get_type(&pkey2)) == 0) {
-            ret = mbedtls_pk_wrap_as_opaque(&pkey2, &key_slot2,
-                                            psa_alg, psa_usage, psa_alg2);
-
+            ret = pk_wrap_as_opaque(&pkey2, psa_alg, psa_alg2, psa_usage, &key_slot2);
             if (ret != 0) {
                 mbedtls_printf(" failed\n  !  "
-                               "mbedtls_pk_wrap_as_opaque returned -0x%x\n\n",
+                               "mbedtls_pk_get_psa_attributes returned -0x%x\n\n",
                                (unsigned int)  -ret);
                 goto exit;
             }
diff --git a/programs/ssl/ssl_test_lib.c b/programs/ssl/ssl_test_lib.c
index a65332a..17d36b7 100644
--- a/programs/ssl/ssl_test_lib.c
+++ b/programs/ssl/ssl_test_lib.c
@@ -8,7 +8,6 @@
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
-#define MBEDTLS_ALLOW_PRIVATE_ACCESS
 
 #include "ssl_test_lib.h"
 
@@ -275,6 +274,37 @@
 
     return 0;
 }
+
+#if defined(MBEDTLS_PK_C)
+int pk_wrap_as_opaque(mbedtls_pk_context *pk, psa_algorithm_t psa_alg, psa_algorithm_t psa_alg2,
+                      psa_key_usage_t psa_usage, mbedtls_svc_key_id_t *key_id)
+{
+    int ret;
+    psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
+
+    ret = mbedtls_pk_get_psa_attributes(pk, PSA_KEY_USAGE_SIGN_HASH, &key_attr);
+    if (ret != 0) {
+        return ret;
+    }
+    psa_set_key_usage_flags(&key_attr, psa_usage);
+    psa_set_key_algorithm(&key_attr, psa_alg);
+    if (psa_alg2 != PSA_ALG_NONE) {
+        psa_set_key_enrollment_algorithm(&key_attr, psa_alg2);
+    }
+    ret = mbedtls_pk_import_into_psa(pk, &key_attr, key_id);
+    if (ret != 0) {
+        return ret;
+    }
+    mbedtls_pk_free(pk);
+    mbedtls_pk_init(pk);
+    ret = mbedtls_pk_setup_opaque(pk, *key_id);
+    if (ret != 0) {
+        return ret;
+    }
+
+    return 0;
+}
+#endif /* MBEDTLS_PK_C */
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
 #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
diff --git a/programs/ssl/ssl_test_lib.h b/programs/ssl/ssl_test_lib.h
index d06e099..1da2dfb 100644
--- a/programs/ssl/ssl_test_lib.h
+++ b/programs/ssl/ssl_test_lib.h
@@ -235,6 +235,31 @@
                              psa_algorithm_t *psa_alg2,
                              psa_key_usage_t *usage,
                              mbedtls_pk_type_t key_type);
+
+#if defined(MBEDTLS_PK_C)
+/** Turn a non-opaque PK context into an opaque one with folowing steps:
+ * - extract the key data and attributes from the PK context.
+ * - import the key material into PSA.
+ * - free the provided PK context and re-initilize it as an opaque PK context
+ *   wrapping the PSA key imported in the above step.
+ *
+ * \param[in/out] pk    On input the non-opaque PK context which contains the
+ *                      key to be wrapped. On output the re-initialized PK
+ *                      context which represents the opaque version of the one
+ *                      provided as input.
+ * \param[in] psa_alg   The primary algorithm that will be associated to the
+ *                      PSA key.
+ * \param[in] psa_alg2  The enrollment algorithm that will be associated to the
+ *                      PSA key.
+ * \param[in] psa_usage The PSA key usage policy.
+ * \param[out] key_id   The PSA key identifier of the imported key.
+ *
+ * \return              \c 0 on sucess.
+ * \return              \c -1 on failure.
+ */
+int pk_wrap_as_opaque(mbedtls_pk_context *pk, psa_algorithm_t psa_alg, psa_algorithm_t psa_alg2,
+                      psa_key_usage_t psa_usage, mbedtls_svc_key_id_t *key_id);
+#endif /* MBEDTLS_PK_C */
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
diff --git a/programs/test/benchmark.c b/programs/test/benchmark.c
index 8fa5d62..93c1729 100644
--- a/programs/test/benchmark.c
+++ b/programs/test/benchmark.c
@@ -5,8 +5,6 @@
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
-#define MBEDTLS_ALLOW_PRIVATE_ACCESS
-
 #include "mbedtls/build_info.h"
 
 #include "mbedtls/platform.h"
@@ -1188,141 +1186,44 @@
     }
 #endif
 
-#if defined(MBEDTLS_ECDH_C) && defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
-    if (todo.ecdh) {
-        mbedtls_ecdh_context ecdh;
-        mbedtls_mpi z;
-        const mbedtls_ecp_curve_info montgomery_curve_list[] = {
-#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED)
-            { MBEDTLS_ECP_DP_CURVE25519, 0, 0, "Curve25519" },
-#endif
-#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED)
-            { MBEDTLS_ECP_DP_CURVE448, 0, 0, "Curve448" },
-#endif
-            { MBEDTLS_ECP_DP_NONE, 0, 0, 0 }
-        };
-        const mbedtls_ecp_curve_info *curve_info;
-        size_t olen;
-        const mbedtls_ecp_curve_info *selected_montgomery_curve_list =
-            montgomery_curve_list;
-
-        if (curve_list == (const mbedtls_ecp_curve_info *) &single_curve) {
-            mbedtls_ecp_group grp;
-
-            mbedtls_ecp_group_init(&grp);
-            if (mbedtls_ecp_group_load(&grp, curve_list->grp_id) != 0) {
-                mbedtls_exit(1);
-            }
-            if (mbedtls_ecp_get_type(&grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) {
-                selected_montgomery_curve_list = single_curve;
-            } else { /* empty list */
-                selected_montgomery_curve_list = single_curve + 1;
-            }
-            mbedtls_ecp_group_free(&grp);
-        }
-
-        for (curve_info = curve_list;
-             curve_info->grp_id != MBEDTLS_ECP_DP_NONE;
-             curve_info++) {
-            if (!mbedtls_ecdh_can_do(curve_info->grp_id)) {
-                continue;
-            }
-
-            mbedtls_ecdh_init(&ecdh);
-
-            CHECK_AND_CONTINUE(mbedtls_ecp_group_load(&ecdh.grp, curve_info->grp_id));
-            CHECK_AND_CONTINUE(mbedtls_ecdh_make_public(&ecdh, &olen, buf, sizeof(buf),
-                                                        myrand, NULL));
-            CHECK_AND_CONTINUE(mbedtls_ecp_copy(&ecdh.Qp, &ecdh.Q));
-
-            mbedtls_snprintf(title, sizeof(title), "ECDHE-%s",
-                             curve_info->name);
-            TIME_PUBLIC(title, "handshake",
-                        CHECK_AND_CONTINUE(mbedtls_ecdh_make_public(&ecdh, &olen, buf, sizeof(buf),
-                                                                    myrand, NULL));
-                        CHECK_AND_CONTINUE(mbedtls_ecdh_calc_secret(&ecdh, &olen, buf, sizeof(buf),
-                                                                    myrand, NULL)));
-            mbedtls_ecdh_free(&ecdh);
-        }
-
-        /* Montgomery curves need to be handled separately */
-        for (curve_info = selected_montgomery_curve_list;
-             curve_info->grp_id != MBEDTLS_ECP_DP_NONE;
-             curve_info++) {
-            mbedtls_ecdh_init(&ecdh);
-            mbedtls_mpi_init(&z);
-
-            CHECK_AND_CONTINUE(mbedtls_ecp_group_load(&ecdh.grp, curve_info->grp_id));
-            CHECK_AND_CONTINUE(mbedtls_ecdh_gen_public(&ecdh.grp, &ecdh.d, &ecdh.Qp, myrand, NULL));
-
-            mbedtls_snprintf(title, sizeof(title), "ECDHE-%s",
-                             curve_info->name);
-            TIME_PUBLIC(title, "handshake",
-                        CHECK_AND_CONTINUE(mbedtls_ecdh_gen_public(&ecdh.grp, &ecdh.d, &ecdh.Q,
-                                                                   myrand, NULL));
-                        CHECK_AND_CONTINUE(mbedtls_ecdh_compute_shared(&ecdh.grp, &z, &ecdh.Qp,
-                                                                       &ecdh.d,
-                                                                       myrand, NULL)));
-
-            mbedtls_ecdh_free(&ecdh);
-            mbedtls_mpi_free(&z);
-        }
-
-        for (curve_info = curve_list;
-             curve_info->grp_id != MBEDTLS_ECP_DP_NONE;
-             curve_info++) {
-            if (!mbedtls_ecdh_can_do(curve_info->grp_id)) {
-                continue;
-            }
-
-            mbedtls_ecdh_init(&ecdh);
-
-            CHECK_AND_CONTINUE(mbedtls_ecp_group_load(&ecdh.grp, curve_info->grp_id));
-            CHECK_AND_CONTINUE(mbedtls_ecdh_make_public(&ecdh, &olen, buf, sizeof(buf),
-                                                        myrand, NULL));
-            CHECK_AND_CONTINUE(mbedtls_ecp_copy(&ecdh.Qp, &ecdh.Q));
-            CHECK_AND_CONTINUE(mbedtls_ecdh_make_public(&ecdh, &olen, buf, sizeof(buf),
-                                                        myrand, NULL));
-
-            mbedtls_snprintf(title, sizeof(title), "ECDH-%s",
-                             curve_info->name);
-            TIME_PUBLIC(title, "handshake",
-                        CHECK_AND_CONTINUE(mbedtls_ecdh_calc_secret(&ecdh, &olen, buf, sizeof(buf),
-                                                                    myrand, NULL)));
-            mbedtls_ecdh_free(&ecdh);
-        }
-
-        /* Montgomery curves need to be handled separately */
-        for (curve_info = selected_montgomery_curve_list;
-             curve_info->grp_id != MBEDTLS_ECP_DP_NONE;
-             curve_info++) {
-            mbedtls_ecdh_init(&ecdh);
-            mbedtls_mpi_init(&z);
-
-            CHECK_AND_CONTINUE(mbedtls_ecp_group_load(&ecdh.grp, curve_info->grp_id));
-            CHECK_AND_CONTINUE(mbedtls_ecdh_gen_public(&ecdh.grp, &ecdh.d, &ecdh.Qp,
-                                                       myrand, NULL));
-            CHECK_AND_CONTINUE(mbedtls_ecdh_gen_public(&ecdh.grp, &ecdh.d, &ecdh.Q, myrand, NULL));
-
-            mbedtls_snprintf(title, sizeof(title), "ECDH-%s",
-                             curve_info->name);
-            TIME_PUBLIC(title, "handshake",
-                        CHECK_AND_CONTINUE(mbedtls_ecdh_compute_shared(&ecdh.grp, &z, &ecdh.Qp,
-                                                                       &ecdh.d,
-                                                                       myrand, NULL)));
-
-            mbedtls_ecdh_free(&ecdh);
-            mbedtls_mpi_free(&z);
-        }
-    }
-#endif
-
 #if defined(MBEDTLS_ECDH_C)
     if (todo.ecdh) {
         mbedtls_ecdh_context ecdh_srv, ecdh_cli;
         unsigned char buf_srv[BUFSIZE], buf_cli[BUFSIZE];
         const mbedtls_ecp_curve_info *curve_info;
-        size_t olen;
+        size_t params_len, publen, seclen;
+
+        for (curve_info = curve_list;
+             curve_info->grp_id != MBEDTLS_ECP_DP_NONE;
+             curve_info++) {
+            if (!mbedtls_ecdh_can_do(curve_info->grp_id)) {
+                continue;
+            }
+
+            mbedtls_ecdh_init(&ecdh_srv);
+
+            CHECK_AND_CONTINUE(mbedtls_ecdh_setup(&ecdh_srv, curve_info->grp_id));
+            CHECK_AND_CONTINUE(mbedtls_ecdh_make_params(&ecdh_srv, &params_len, buf_srv,
+                                                        sizeof(buf_srv), myrand, NULL));
+
+            mbedtls_snprintf(title, sizeof(title), "ECDHE-%s", curve_info->name);
+            TIME_PUBLIC(title,
+                        "ephemeral handshake",
+                        const unsigned char *p_srv = buf_srv;
+                        mbedtls_ecdh_init(&ecdh_cli);
+
+                        CHECK_AND_CONTINUE(mbedtls_ecdh_read_params(&ecdh_cli, &p_srv,
+                                                                    p_srv + params_len));
+                        CHECK_AND_CONTINUE(mbedtls_ecdh_make_public(&ecdh_cli, &publen, buf_cli,
+                                                                    sizeof(buf_cli), myrand, NULL));
+
+                        CHECK_AND_CONTINUE(mbedtls_ecdh_calc_secret(&ecdh_cli, &seclen, buf_cli,
+                                                                    sizeof(buf_cli), myrand, NULL));
+                        mbedtls_ecdh_free(&ecdh_cli);
+                        );
+
+            mbedtls_ecdh_free(&ecdh_srv);
+        }
 
         for (curve_info = curve_list;
              curve_info->grp_id != MBEDTLS_ECP_DP_NONE;
@@ -1334,31 +1235,26 @@
             mbedtls_ecdh_init(&ecdh_srv);
             mbedtls_ecdh_init(&ecdh_cli);
 
-            mbedtls_snprintf(title, sizeof(title), "ECDHE-%s", curve_info->name);
+            CHECK_AND_CONTINUE(mbedtls_ecdh_setup(&ecdh_srv, curve_info->grp_id));
+            CHECK_AND_CONTINUE(mbedtls_ecdh_make_params(&ecdh_srv, &params_len, buf_srv,
+                                                        sizeof(buf_srv), myrand, NULL));
+
+            const unsigned char *p_srv = buf_srv;
+            CHECK_AND_CONTINUE(mbedtls_ecdh_read_params(&ecdh_cli, &p_srv,
+                                                        p_srv + params_len));
+            CHECK_AND_CONTINUE(mbedtls_ecdh_make_public(&ecdh_cli, &publen, buf_cli,
+                                                        sizeof(buf_cli), myrand, NULL));
+
+
+            mbedtls_snprintf(title, sizeof(title), "ECDH-%s", curve_info->name);
             TIME_PUBLIC(title,
-                        "full handshake",
-                        const unsigned char *p_srv = buf_srv;
-
-                        CHECK_AND_CONTINUE(mbedtls_ecdh_setup(&ecdh_srv, curve_info->grp_id));
-                        CHECK_AND_CONTINUE(mbedtls_ecdh_make_params(&ecdh_srv, &olen, buf_srv,
-                                                                    sizeof(buf_srv), myrand, NULL));
-
-                        CHECK_AND_CONTINUE(mbedtls_ecdh_read_params(&ecdh_cli, &p_srv,
-                                                                    p_srv + olen));
-                        CHECK_AND_CONTINUE(mbedtls_ecdh_make_public(&ecdh_cli, &olen, buf_cli,
+                        "static handshake",
+                        CHECK_AND_CONTINUE(mbedtls_ecdh_calc_secret(&ecdh_cli, &seclen, buf_cli,
                                                                     sizeof(buf_cli), myrand, NULL));
-
-                        CHECK_AND_CONTINUE(mbedtls_ecdh_read_public(&ecdh_srv, buf_cli, olen));
-                        CHECK_AND_CONTINUE(mbedtls_ecdh_calc_secret(&ecdh_srv, &olen, buf_srv,
-                                                                    sizeof(buf_srv), myrand, NULL));
-
-                        CHECK_AND_CONTINUE(mbedtls_ecdh_calc_secret(&ecdh_cli, &olen, buf_cli,
-                                                                    sizeof(buf_cli), myrand, NULL));
-                        mbedtls_ecdh_free(&ecdh_cli);
-
-                        mbedtls_ecdh_free(&ecdh_srv);
                         );
 
+            mbedtls_ecdh_free(&ecdh_cli);
+            mbedtls_ecdh_free(&ecdh_srv);
         }
     }
 #endif
diff --git a/programs/test/metatest.c b/programs/test/metatest.c
index 8e798cd..5a45f71 100644
--- a/programs/test/metatest.c
+++ b/programs/test/metatest.c
@@ -26,7 +26,6 @@
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
-#define MBEDTLS_ALLOW_PRIVATE_ACCESS
 
 #include <mbedtls/platform.h>
 #include <mbedtls/platform_util.h>
diff --git a/programs/test/selftest.c b/programs/test/selftest.c
index e132e4c..043209b 100644
--- a/programs/test/selftest.c
+++ b/programs/test/selftest.c
@@ -5,8 +5,6 @@
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
-#define MBEDTLS_ALLOW_PRIVATE_ACCESS
-
 #include "mbedtls/build_info.h"
 
 #include "mbedtls/entropy.h"
diff --git a/programs/test/udp_proxy.c b/programs/test/udp_proxy.c
index c6b56ec..beaa8bd 100644
--- a/programs/test/udp_proxy.c
+++ b/programs/test/udp_proxy.c
@@ -11,7 +11,6 @@
  * example of good general usage.
  */
 
-#define MBEDTLS_ALLOW_PRIVATE_ACCESS
 
 #include "mbedtls/build_info.h"
 
diff --git a/programs/x509/cert_req.c b/programs/x509/cert_req.c
index 6ae43a9..dcfd176 100644
--- a/programs/x509/cert_req.c
+++ b/programs/x509/cert_req.c
@@ -14,7 +14,8 @@
 #if !defined(MBEDTLS_X509_CSR_WRITE_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \
     !defined(MBEDTLS_PK_PARSE_C) || !defined(MBEDTLS_MD_CAN_SHA256) || \
     !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_CTR_DRBG_C) || \
-    !defined(MBEDTLS_PEM_WRITE_C) || !defined(MBEDTLS_FS_IO)
+    !defined(MBEDTLS_PEM_WRITE_C) || !defined(MBEDTLS_FS_IO) || \
+    !defined(MBEDTLS_MD_C)
 int main(void)
 {
     mbedtls_printf("MBEDTLS_X509_CSR_WRITE_C and/or MBEDTLS_FS_IO and/or "
diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c
index bf25c4c..0b2575e 100644
--- a/programs/x509/cert_write.c
+++ b/programs/x509/cert_write.c
@@ -15,7 +15,7 @@
     !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_FS_IO) || \
     !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_CTR_DRBG_C) || \
     !defined(MBEDTLS_ERROR_C) || !defined(MBEDTLS_MD_CAN_SHA256) || \
-    !defined(MBEDTLS_PEM_WRITE_C)
+    !defined(MBEDTLS_PEM_WRITE_C) || !defined(MBEDTLS_MD_C)
 int main(void)
 {
     mbedtls_printf("MBEDTLS_X509_CRT_WRITE_C and/or MBEDTLS_X509_CRT_PARSE_C and/or "
diff --git a/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.h.jinja b/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.h.jinja
index 924b08c..8b91f0b 100644
--- a/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.h.jinja
+++ b/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.h.jinja
@@ -122,7 +122,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -196,7 +196,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -266,7 +266,7 @@
     const psa_drv_se_t *drv;
     psa_drv_se_context_t *drv_context;
 
-    if( psa_get_se_driver( attributes->core.lifetime, &drv, &drv_context ) )
+    if( psa_get_se_driver( psa_get_key_lifetime(attributes), &drv, &drv_context ) )
     {
         if( drv->asymmetric == NULL ||
             drv->asymmetric->p_sign == NULL )
@@ -283,7 +283,7 @@
 
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -306,11 +306,11 @@
                 return( status );
 #endif /* PSA_CRYPTO_DRIVER_TEST */
 #if defined (MBEDTLS_PSA_P256M_DRIVER_ENABLED)
-            if( PSA_KEY_TYPE_IS_ECC( attributes->core.type ) &&
+            if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) &&
                 PSA_ALG_IS_ECDSA(alg) &&
                 !PSA_ALG_ECDSA_IS_DETERMINISTIC( alg ) &&
-                PSA_KEY_TYPE_ECC_GET_FAMILY(attributes->core.type) == PSA_ECC_FAMILY_SECP_R1 &&
-                attributes->core.bits == 256 )
+                PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)) == PSA_ECC_FAMILY_SECP_R1 &&
+                psa_get_key_bits(attributes) == 256 )
             {
                 status = p256_transparent_sign_hash( attributes,
                                                      key_buffer,
@@ -370,7 +370,7 @@
     const psa_drv_se_t *drv;
     psa_drv_se_context_t *drv_context;
 
-    if( psa_get_se_driver( attributes->core.lifetime, &drv, &drv_context ) )
+    if( psa_get_se_driver( psa_get_key_lifetime(attributes), &drv, &drv_context ) )
     {
         if( drv->asymmetric == NULL ||
             drv->asymmetric->p_verify == NULL )
@@ -387,7 +387,7 @@
 
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -410,11 +410,11 @@
                 return( status );
 #endif /* PSA_CRYPTO_DRIVER_TEST */
 #if defined (MBEDTLS_PSA_P256M_DRIVER_ENABLED)
-            if( PSA_KEY_TYPE_IS_ECC( attributes->core.type ) &&
+            if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) &&
                 PSA_ALG_IS_ECDSA(alg) &&
                 !PSA_ALG_ECDSA_IS_DETERMINISTIC( alg ) &&
-                PSA_KEY_TYPE_ECC_GET_FAMILY(attributes->core.type) == PSA_ECC_FAMILY_SECP_R1 &&
-                attributes->core.bits == 256 )
+                PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)) == PSA_ECC_FAMILY_SECP_R1 &&
+                psa_get_key_bits(attributes) == 256 )
             {
                 status = p256_transparent_verify_hash( attributes,
                                                        key_buffer,
@@ -517,7 +517,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(
-                                                    attributes->core.lifetime );
+                                                    psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -609,7 +609,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(
-                                                    attributes->core.lifetime );
+                                                    psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -707,8 +707,8 @@
     size_t *key_buffer_size )
 {
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
-    psa_key_type_t key_type = attributes->core.type;
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
+    psa_key_type_t key_type = psa_get_key_type(attributes);
 
     *key_buffer_size = 0;
     switch( location )
@@ -731,18 +731,33 @@
 
 static inline psa_status_t psa_driver_wrapper_generate_key(
     const psa_key_attributes_t *attributes,
+    const psa_key_production_parameters_t *params, size_t params_data_length,
     uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length )
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION(attributes->core.lifetime);
+        PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(attributes));
+
+#if defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE)
+    int is_default_production =
+        psa_key_production_parameters_are_default(params, params_data_length);
+    if( location != PSA_KEY_LOCATION_LOCAL_STORAGE && !is_default_production )
+    {
+        /* We don't support passing custom production parameters
+         * to drivers yet. */
+        return PSA_ERROR_NOT_SUPPORTED;
+    }
+#else
+    int is_default_production = 1;
+    (void) is_default_production;
+#endif
 
     /* Try dynamically-registered SE interface first */
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
     const psa_drv_se_t *drv;
     psa_drv_se_context_t *drv_context;
 
-    if( psa_get_se_driver( attributes->core.lifetime, &drv, &drv_context ) )
+    if( psa_get_se_driver( psa_get_key_lifetime(attributes), &drv, &drv_context ) )
     {
         size_t pubkey_length = 0; /* We don't support this feature yet */
         if( drv->key_management == NULL ||
@@ -762,8 +777,11 @@
     {
         case PSA_KEY_LOCATION_LOCAL_STORAGE:
 #if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
-            /* Transparent drivers are limited to generating asymmetric keys */
-            if( PSA_KEY_TYPE_IS_ASYMMETRIC( attributes->core.type ) )
+            /* Transparent drivers are limited to generating asymmetric keys. */
+            /* We don't support passing custom production parameters
+             * to drivers yet. */
+            if( PSA_KEY_TYPE_IS_ASYMMETRIC( psa_get_key_type(attributes) ) &&
+                is_default_production )
             {
             /* Cycle through all known transparent accelerators */
 #if defined(PSA_CRYPTO_DRIVER_TEST)
@@ -775,9 +793,9 @@
                     break;
 #endif /* PSA_CRYPTO_DRIVER_TEST */
 #if defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED)
-                if( PSA_KEY_TYPE_IS_ECC( attributes->core.type ) &&
-                    attributes->core.type == PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1) &&
-                    attributes->core.bits == 256 )
+                if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) &&
+                    psa_get_key_type(attributes) == PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1) &&
+                    psa_get_key_bits(attributes) == 256 )
                 {
                     status = p256_transparent_generate_key( attributes,
                                                             key_buffer,
@@ -793,7 +811,8 @@
 
             /* Software fallback */
             status = psa_generate_key_internal(
-                attributes, key_buffer, key_buffer_size, key_buffer_length );
+                attributes, params, params_data_length,
+                key_buffer, key_buffer_size, key_buffer_length );
             break;
 
         /* Add cases for opaque driver here */
@@ -843,7 +862,7 @@
     const psa_drv_se_t *drv;
     psa_drv_se_context_t *drv_context;
 
-    if( psa_get_se_driver( attributes->core.lifetime, &drv, &drv_context ) )
+    if( psa_get_se_driver( psa_get_key_lifetime(attributes), &drv, &drv_context ) )
     {
         if( drv->key_management == NULL ||
             drv->key_management->p_import == NULL )
@@ -920,7 +939,7 @@
     const psa_drv_se_t *drv;
     psa_drv_se_context_t *drv_context;
 
-    if( psa_get_se_driver( attributes->core.lifetime, &drv, &drv_context ) )
+    if( psa_get_se_driver( psa_get_key_lifetime(attributes), &drv, &drv_context ) )
     {
         if( ( drv->key_management == NULL   ) ||
             ( drv->key_management->p_export == NULL ) )
@@ -975,13 +994,13 @@
 {% endmacro %}
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
     const psa_drv_se_t *drv;
     psa_drv_se_context_t *drv_context;
 
-    if( psa_get_se_driver( attributes->core.lifetime, &drv, &drv_context ) )
+    if( psa_get_se_driver( psa_get_key_lifetime(attributes), &drv, &drv_context ) )
     {
         /* Copying to a secure element is not implemented yet. */
         return( PSA_ERROR_NOT_SUPPORTED );
@@ -1025,7 +1044,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -1115,7 +1134,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -1192,7 +1211,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -1265,7 +1284,7 @@
 {
     psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -1665,7 +1684,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -1717,7 +1736,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -1766,7 +1785,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -1814,7 +1833,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -2150,7 +2169,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -2214,7 +2233,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -2286,7 +2305,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -2486,7 +2505,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -2544,7 +2563,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -2608,7 +2627,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
-        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+        PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
 
     switch( location )
     {
@@ -2626,10 +2645,10 @@
                 return( status );
 #endif /* PSA_CRYPTO_DRIVER_TEST */
 #if defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED)
-            if( PSA_KEY_TYPE_IS_ECC( attributes->core.type ) &&
+            if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) &&
                 PSA_ALG_IS_ECDH(alg) &&
-                PSA_KEY_TYPE_ECC_GET_FAMILY(attributes->core.type) == PSA_ECC_FAMILY_SECP_R1 &&
-                attributes->core.bits == 256 )
+                PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)) == PSA_ECC_FAMILY_SECP_R1 &&
+                psa_get_key_bits(attributes) == 256 )
             {
                 status = p256_transparent_key_agreement( attributes,
                                                          key_buffer,
diff --git a/scripts/data_files/driver_templates/psa_crypto_driver_wrappers_no_static.c.jinja b/scripts/data_files/driver_templates/psa_crypto_driver_wrappers_no_static.c.jinja
index 2aae628..261cd2a 100644
--- a/scripts/data_files/driver_templates/psa_crypto_driver_wrappers_no_static.c.jinja
+++ b/scripts/data_files/driver_templates/psa_crypto_driver_wrappers_no_static.c.jinja
@@ -88,9 +88,9 @@
     const psa_key_attributes_t *attributes,
     size_t *key_buffer_size )
 {
-    psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
-    psa_key_type_t key_type = attributes->core.type;
-    size_t key_bits = attributes->core.bits;
+    psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
+    psa_key_type_t key_type = psa_get_key_type(attributes);
+    size_t key_bits = psa_get_key_bits(attributes);
 
     *key_buffer_size = 0;
     switch( location )
@@ -144,7 +144,7 @@
     const psa_drv_se_t *drv;
     psa_drv_se_context_t *drv_context;
 
-    if( psa_get_se_driver( attributes->core.lifetime, &drv, &drv_context ) )
+    if( psa_get_se_driver( psa_get_key_lifetime(attributes), &drv, &drv_context ) )
     {
         if( ( drv->key_management == NULL ) ||
             ( drv->key_management->p_export_public == NULL ) )
@@ -203,7 +203,7 @@
 key_buffer_size,
 key_buffer_length
 {% endmacro %}
-    psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+    psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
     switch( location )
     {
 #if defined(PSA_CRYPTO_DRIVER_TEST)
diff --git a/tests/include/test/drivers/config_test_driver.h b/tests/include/test/drivers/config_test_driver.h
index 4eb27f0..ec8bcb6 100644
--- a/tests/include/test/drivers/config_test_driver.h
+++ b/tests/include/test/drivers/config_test_driver.h
@@ -40,5 +40,7 @@
 //#define MBEDTLS_MD_C
 //#define MBEDTLS_PEM_PARSE_C
 //#define MBEDTLS_BASE64_C
+//#define MBEDTLS_THREADING_C
+//#define MBEDTLS_THREADING_PTHREAD
 
 #endif /* MBEDTLS_CONFIG_H */
diff --git a/tests/include/test/psa_exercise_key.h b/tests/include/test/psa_exercise_key.h
index a658d17..44f5c08 100644
--- a/tests/include/test/psa_exercise_key.h
+++ b/tests/include/test/psa_exercise_key.h
@@ -14,21 +14,17 @@
 
 #include <psa/crypto.h>
 
+#if defined(MBEDTLS_PK_C)
+#include <mbedtls/pk.h>
+#endif
+
 /** \def KNOWN_SUPPORTED_HASH_ALG
  *
  * A hash algorithm that is known to be supported.
  *
  * This is used in some smoke tests.
  */
-#if defined(PSA_WANT_ALG_MD5)
-#define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_MD5
-/* PSA_WANT_ALG_RIPEMD160 omitted. This is necessary for the sake of
- * exercise_signature_key() because Mbed TLS doesn't support RIPEMD160
- * in RSA PKCS#1v1.5 signatures. A RIPEMD160-only configuration would be
- * implausible anyway. */
-#elif defined(PSA_WANT_ALG_SHA_1)
-#define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_SHA_1
-#elif defined(PSA_WANT_ALG_SHA_256)
+#if defined(PSA_WANT_ALG_SHA_256)
 #define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_SHA_256
 #elif defined(PSA_WANT_ALG_SHA_384)
 #define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_SHA_384
@@ -36,6 +32,14 @@
 #define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_SHA_512
 #elif defined(PSA_WANT_ALG_SHA3_256)
 #define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_SHA3_256
+#elif defined(PSA_WANT_ALG_SHA_1)
+#define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_SHA_1
+#elif defined(PSA_WANT_ALG_MD5)
+#define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_MD5
+/* PSA_WANT_ALG_RIPEMD160 omitted. This is necessary for the sake of
+ * exercise_signature_key() because Mbed TLS doesn't support RIPEMD160
+ * in RSA PKCS#1v1.5 signatures. A RIPEMD160-only configuration would be
+ * implausible anyway. */
 #else
 #undef KNOWN_SUPPORTED_HASH_ALG
 #endif
@@ -221,4 +225,37 @@
 psa_key_usage_t mbedtls_test_psa_usage_to_exercise(psa_key_type_t type,
                                                    psa_algorithm_t alg);
 
+/** Whether the specified algorithm can be exercised.
+ *
+ * \note This function is solely based on the algorithm and does not
+ *       consider potential issues with the compatibility of a key.
+ *       The idea is that you already have a key, so you know that the
+ *       key type is supported, and you want to exercise the key but
+ *       only if the algorithm given in its policy is enabled in the
+ *       compile-time configuration.
+ *
+ * \note This function currently only supports signature algorithms
+ *       (including wildcards).
+ *       TODO: a more general mechanism, which should be automatically
+ *       generated and possibly available as a library function?
+ */
+int mbedtls_test_can_exercise_psa_algorithm(psa_algorithm_t alg);
+
+#if defined(MBEDTLS_PK_C)
+/** PK-PSA key consistency test.
+ *
+ * This function tests that the pk context and the PSA key are
+ * consistent. At a minimum:
+ *
+ * - The two objects must contain keys of the same type,
+ *   or a key pair and a public key of the matching type.
+ * - The two objects must have the same public key.
+ *
+ * \retval 0 The key failed the consistency tests.
+ * \retval 1 The key passed the consistency tests.
+ */
+int mbedtls_test_key_consistency_psa_pk(mbedtls_svc_key_id_t psa_key,
+                                        const mbedtls_pk_context *pk);
+#endif /* MBEDTLS_PK_C */
+
 #endif /* PSA_EXERCISE_KEY_H */
diff --git a/tests/include/test/ssl_helpers.h b/tests/include/test/ssl_helpers.h
index 1f41966..335386b 100644
--- a/tests/include/test/ssl_helpers.h
+++ b/tests/include/test/ssl_helpers.h
@@ -85,6 +85,7 @@
 
 typedef struct mbedtls_test_handshake_test_options {
     const char *cipher;
+    uint16_t *group_list;
     mbedtls_ssl_protocol_version client_min_version;
     mbedtls_ssl_protocol_version client_max_version;
     mbedtls_ssl_protocol_version server_min_version;
@@ -112,6 +113,8 @@
     void (*srv_log_fun)(void *, int, const char *, int, const char *);
     void (*cli_log_fun)(void *, int, const char *, int, const char *);
     int resize_buffers;
+    int early_data;
+    int max_early_data_size;
 #if defined(MBEDTLS_SSL_CACHE_C)
     mbedtls_ssl_cache_context *cache;
 #endif
@@ -194,6 +197,13 @@
 #endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
 
 /*
+ * Random number generator aimed for TLS unitary tests. Its main purpose is to
+ * simplify the set-up of a random number generator for TLS
+ * unitary tests: no need to set up a good entropy source for example.
+ */
+int mbedtls_test_random(void *p_rng, unsigned char *output, size_t output_len);
+
+/*
  * This function can be passed to mbedtls to receive output logs from it. In
  * this case, it will count the instances of a mbedtls_test_ssl_log_pattern
  * in the received logged messages.
@@ -440,8 +450,7 @@
     mbedtls_test_handshake_test_options *options,
     mbedtls_test_message_socket_context *dtls_context,
     mbedtls_test_ssl_message_queue *input_queue,
-    mbedtls_test_ssl_message_queue *output_queue,
-    uint16_t *group_list);
+    mbedtls_test_ssl_message_queue *output_queue);
 
 /*
  * Deinitializes endpoint represented by \p ep.
@@ -531,6 +540,7 @@
  */
 int mbedtls_test_ssl_tls12_populate_session(mbedtls_ssl_session *session,
                                             int ticket_len,
+                                            int endpoint_type,
                                             const char *crt_file);
 
 #if defined(MBEDTLS_SSL_PROTO_TLS1_3)
@@ -599,6 +609,15 @@
                               unsigned char *buf, size_t len);
 #endif /* MBEDTLS_SSL_SESSION_TICKETS */
 
+#if defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_SRV_C) && \
+    defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS) && \
+    defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+int mbedtls_test_get_tls13_ticket(
+    mbedtls_test_handshake_test_options *client_options,
+    mbedtls_test_handshake_test_options *server_options,
+    mbedtls_ssl_session *session);
+#endif
+
 #define ECJPAKE_TEST_PWD        "bla"
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
diff --git a/tests/opt-testcases/tls13-kex-modes.sh b/tests/opt-testcases/tls13-kex-modes.sh
index 4581bc5..49f06e0 100755
--- a/tests/opt-testcases/tls13-kex-modes.sh
+++ b/tests/opt-testcases/tls13-kex-modes.sh
@@ -23,7 +23,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -s "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -41,7 +41,7 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -78,7 +78,7 @@
             -S "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -s "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -96,7 +96,7 @@
             -s "found pre_shared_key extension" \
             -S "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -133,7 +133,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -S "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -s "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -151,7 +151,7 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -S "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -188,7 +188,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -s "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -206,7 +206,7 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -261,7 +261,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -S "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -s "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -280,7 +280,7 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -S "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -319,7 +319,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -s "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -338,7 +338,7 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -377,7 +377,7 @@
             -S "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -s "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -396,7 +396,7 @@
             -s "found pre_shared_key extension" \
             -S "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -435,7 +435,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -S "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -s "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -454,7 +454,7 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -S "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -s "key exchange mode: ephemeral"
@@ -493,7 +493,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -s "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -512,7 +512,7 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -s "key exchange mode: ephemeral"
@@ -550,8 +550,9 @@
             -s "found pre_shared_key extension" \
             -S "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
+            -s "No suitable PSK key exchange mode" \
             -S "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -s "key exchange mode: ephemeral"
@@ -572,7 +573,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -S "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -s "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -592,7 +593,7 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -S "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -s "key exchange mode: ephemeral"
@@ -633,7 +634,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -s "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -653,7 +654,7 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -s "key exchange mode: ephemeral"
@@ -694,7 +695,7 @@
             -S "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -s "key exchange mode: ephemeral"
@@ -733,8 +734,9 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -S "Found PSK KEX MODE" \
+            -s "No suitable PSK key exchange mode" \
             -S "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -s "key exchange mode: ephemeral"
@@ -754,7 +756,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -s "key exchange mode: ephemeral"
@@ -793,7 +795,7 @@
             -S "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -s "key exchange mode: ephemeral"
@@ -921,7 +923,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -s "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -938,7 +940,7 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -973,7 +975,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -S "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -s "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -990,7 +992,7 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -S "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -1025,7 +1027,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -s "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -1042,7 +1044,7 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -1078,7 +1080,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -S "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -s "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -1096,7 +1098,7 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -S "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -1133,7 +1135,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -s "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -1151,7 +1153,7 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -1188,7 +1190,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -S "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -s "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -1206,7 +1208,7 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -S "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -s "key exchange mode: ephemeral"
@@ -1243,7 +1245,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -s "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -1261,7 +1263,7 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -s "key exchange mode: ephemeral"
@@ -1299,7 +1301,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -S "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -s "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -1318,7 +1320,7 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -S "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -s "key exchange mode: ephemeral"
@@ -1357,7 +1359,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -s "key exchange mode: psk_ephemeral"  \
             -S "key exchange mode: ephemeral"
@@ -1376,7 +1378,7 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -s "key exchange mode: ephemeral"
@@ -1413,8 +1415,9 @@
             -s "found pre_shared_key extension" \
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -S "Found PSK KEX MODE" \
+            -s "No suitable PSK key exchange mode" \
             -S "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -s "key exchange mode: ephemeral"
@@ -1433,7 +1436,7 @@
             -s "Found PSK_EPHEMERAL KEX MODE" \
             -s "Found PSK KEX MODE" \
             -s "Pre shared key found" \
-            -S "No matched PSK or ticket" \
+            -S "No usable PSK or ticket" \
             -S "key exchange mode: psk$"  \
             -S "key exchange mode: psk_ephemeral"  \
             -s "key exchange mode: ephemeral"
@@ -1580,7 +1583,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket"
+            -s "No usable PSK or ticket"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_config_enabled MBEDTLS_SSL_SRV_C
@@ -1665,7 +1668,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -s "ClientHello message misses mandatory extensions."
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
@@ -1711,7 +1714,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -s "ClientHello message misses mandatory extensions."
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
@@ -1769,7 +1772,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -s "ClientHello message misses mandatory extensions."
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
@@ -1827,7 +1830,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket"
+            -s "No usable PSK or ticket"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_config_enabled MBEDTLS_SSL_SRV_C
@@ -1870,7 +1873,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -s "ClientHello message misses mandatory extensions."
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
@@ -1916,7 +1919,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_config_enabled MBEDTLS_SSL_SRV_C
@@ -2047,7 +2050,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket"
+            -s "No usable PSK or ticket"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_config_enabled MBEDTLS_SSL_SRV_C
@@ -2106,7 +2109,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -s "key exchange mode: ephemeral"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
@@ -2152,7 +2155,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -s "ClientHello message misses mandatory extensions."
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
@@ -2199,7 +2202,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -s "key exchange mode: ephemeral"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
@@ -2288,7 +2291,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -s "ClientHello message misses mandatory extensions."
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
@@ -2348,7 +2351,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket"
+            -s "No usable PSK or ticket"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_config_enabled MBEDTLS_SSL_SRV_C
@@ -2392,7 +2395,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -s "ClientHello message misses mandatory extensions."
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
@@ -2438,7 +2441,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket"
+            -s "No usable PSK or ticket"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_config_enabled MBEDTLS_SSL_SRV_C
@@ -2485,7 +2488,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -s "ClientHello message misses mandatory extensions."
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
@@ -2532,7 +2535,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -s "ClientHello message misses mandatory extensions."
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
@@ -2595,7 +2598,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -c "Selected key exchange mode: ephemeral" \
             -c "HTTP/1.0 200 OK"
 
@@ -2643,7 +2646,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -s "ClientHello message misses mandatory extensions."
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
@@ -2690,7 +2693,7 @@
             -c "client hello, adding pre_shared_key extension, omitting PSK binder list" \
             -c "client hello, adding psk_key_exchange_modes extension" \
             -c "client hello, adding PSK binder list" \
-            -s "No matched PSK or ticket" \
+            -s "No usable PSK or ticket" \
             -s "key exchange mode: ephemeral"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
diff --git a/tests/opt-testcases/tls13-misc.sh b/tests/opt-testcases/tls13-misc.sh
index 4e6bf87..066fa3f 100755
--- a/tests/opt-testcases/tls13-misc.sh
+++ b/tests/opt-testcases/tls13-misc.sh
@@ -263,7 +263,7 @@
 run_test    "TLS 1.3 m->G: EarlyData: basic check, good" \
             "$G_NEXT_SRV -d 10 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:+CIPHER-ALL:+ECDHE-PSK:+PSK \
                          --earlydata --maxearlydata 16384 --disable-client-cert" \
-            "$P_CLI debug_level=4 early_data=$EARLY_DATA_INPUT reco_mode=1 reconnect=1 reco_delay=900" \
+            "$P_CLI debug_level=4 early_data=1 reco_mode=1 reconnect=1 reco_delay=900" \
             0 \
             -c "received max_early_data_size: 16384" \
             -c "Reconnecting with saved session" \
@@ -285,9 +285,34 @@
                              MBEDTLS_SSL_EARLY_DATA
 requires_any_configs_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED \
                              MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED
+run_test    "TLS 1.3 m->G: EarlyData: write early data, good" \
+            "$G_NEXT_SRV -d 10 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:+CIPHER-ALL:+ECDHE-PSK:+PSK --earlydata --disable-client-cert" \
+            "$P_CLI debug_level=4 early_data=1 reco_mode=1 reconnect=1 reco_delay=900" \
+            0 \
+            -c "Reconnecting with saved session" \
+            -c "NewSessionTicket: early_data(42) extension received." \
+            -c "ClientHello: early_data(42) extension exists." \
+            -c "EncryptedExtensions: early_data(42) extension received." \
+            -c "EncryptedExtensions: early_data(42) extension exists." \
+            -c "<= write early_data" \
+            -c "<= write EndOfEarlyData" \
+            -s "Parsing extension 'Early Data/42' (0 bytes)" \
+            -s "Sending extension Early Data/42 (0 bytes)" \
+            -s "END OF EARLY DATA (5) was received." \
+            -s "early data accepted" \
+            -s "decrypted early data with length"
+
+requires_gnutls_tls1_3
+requires_config_enabled MBEDTLS_DEBUG_C
+requires_config_enabled MBEDTLS_SSL_CLI_C
+requires_all_configs_enabled MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED \
+                             MBEDTLS_SSL_EARLY_DATA
+requires_any_configs_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED
 run_test    "TLS 1.3 m->G: EarlyData: no early_data in NewSessionTicket, good" \
             "$G_NEXT_SRV -d 10 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:+CIPHER-ALL:+ECDHE-PSK:+PSK --disable-client-cert" \
-            "$P_CLI debug_level=4 early_data=$EARLY_DATA_INPUT reco_mode=1 reconnect=1" \
+            "$P_CLI debug_level=4 early_data=1 reco_mode=1 reconnect=1" \
             0 \
             -c "Reconnecting with saved session" \
             -C "NewSessionTicket: early_data(42) extension received." \
@@ -328,8 +353,8 @@
          -s "key exchange mode: ephemeral" \
          -S "key exchange mode: psk_ephemeral" \
          -S "key exchange mode: psk$" \
-         -s "No suitable key exchange mode" \
-         -s "No matched PSK or ticket"
+         -s "No suitable PSK key exchange mode" \
+         -s "No usable PSK or ticket"
 
 requires_all_configs_enabled MBEDTLS_SSL_SESSION_TICKETS \
                              MBEDTLS_SSL_SRV_C MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C \
@@ -340,7 +365,7 @@
          "$P_CLI debug_level=4 tls13_kex_modes=psk_or_ephemeral reconnect=1" \
          0 \
          -c "Pre-configured PSK number = 1" \
-         -S "No suitable key exchange mode" \
+         -S "No suitable PSK key exchange mode" \
          -s "found matched identity"
 
 requires_all_configs_enabled MBEDTLS_SSL_SESSION_TICKETS \
@@ -356,8 +381,8 @@
          -s "key exchange mode: ephemeral" \
          -S "key exchange mode: psk_ephemeral" \
          -S "key exchange mode: psk$" \
-         -s "No suitable key exchange mode" \
-         -s "No matched PSK or ticket"
+         -s "No suitable PSK key exchange mode" \
+         -s "No usable PSK or ticket"
 
 requires_all_configs_enabled MBEDTLS_SSL_SESSION_TICKETS \
                              MBEDTLS_SSL_SRV_C MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C \
@@ -368,7 +393,7 @@
          "$P_CLI debug_level=4 tls13_kex_modes=psk_or_ephemeral reconnect=1" \
          0 \
          -c "Pre-configured PSK number = 1" \
-         -S "No suitable key exchange mode" \
+         -S "No suitable PSK key exchange mode" \
          -s "found matched identity"
 
 requires_all_configs_enabled MBEDTLS_SSL_SESSION_TICKETS \
@@ -384,8 +409,8 @@
          -s "key exchange mode: ephemeral" \
          -S "key exchange mode: psk_ephemeral" \
          -S "key exchange mode: psk$" \
-         -s "No suitable key exchange mode" \
-         -s "No matched PSK or ticket"
+         -s "No suitable PSK key exchange mode" \
+         -s "No usable PSK or ticket"
 
 requires_all_configs_enabled MBEDTLS_SSL_SESSION_TICKETS \
                              MBEDTLS_SSL_SRV_C MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C \
@@ -400,8 +425,8 @@
          -s "key exchange mode: ephemeral" \
          -S "key exchange mode: psk_ephemeral" \
          -S "key exchange mode: psk$" \
-         -s "No suitable key exchange mode" \
-         -s "No matched PSK or ticket"
+         -s "No suitable PSK key exchange mode" \
+         -s "No usable PSK or ticket"
 
 requires_all_configs_enabled MBEDTLS_SSL_SESSION_TICKETS \
                              MBEDTLS_SSL_SRV_C MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C \
@@ -412,7 +437,7 @@
          "$P_CLI debug_level=4 tls13_kex_modes=ephemeral_all reconnect=1" \
          0 \
          -c "Pre-configured PSK number = 1" \
-         -S "No suitable key exchange mode" \
+         -S "No suitable PSK key exchange mode" \
          -s "found matched identity" \
          -s "key exchange mode: psk_ephemeral"
 
@@ -425,7 +450,7 @@
          "$P_CLI debug_level=4 tls13_kex_modes=ephemeral_all reconnect=1" \
          0 \
          -c "Pre-configured PSK number = 1" \
-         -S "No suitable key exchange mode" \
+         -S "No suitable PSK key exchange mode" \
          -s "found matched identity" \
          -s "key exchange mode: psk_ephemeral"
 
@@ -443,8 +468,8 @@
          -s "key exchange mode: ephemeral" \
          -S "key exchange mode: psk_ephemeral" \
          -S "key exchange mode: psk$" \
-         -s "No suitable key exchange mode" \
-         -s "No matched PSK or ticket"
+         -s "No suitable PSK key exchange mode" \
+         -s "No usable PSK or ticket"
 
 requires_all_configs_enabled MBEDTLS_SSL_SESSION_TICKETS \
                              MBEDTLS_SSL_SRV_C MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C \
@@ -456,7 +481,7 @@
          "$P_CLI debug_level=4 tls13_kex_modes=all reconnect=1" \
          0 \
          -c "Pre-configured PSK number = 1" \
-         -S "No suitable key exchange mode" \
+         -S "No suitable PSK key exchange mode" \
          -s "found matched identity"
 
 requires_all_configs_enabled MBEDTLS_SSL_SESSION_TICKETS \
@@ -469,7 +494,7 @@
          "$P_CLI debug_level=4 tls13_kex_modes=all reconnect=1" \
          0 \
          -c "Pre-configured PSK number = 1" \
-         -S "No suitable key exchange mode" \
+         -S "No suitable PSK key exchange mode" \
          -s "found matched identity" \
          -s "key exchange mode: psk_ephemeral"
 
@@ -483,7 +508,7 @@
          "$P_CLI debug_level=4 tls13_kex_modes=all reconnect=1" \
          0 \
          -c "Pre-configured PSK number = 1" \
-         -S "No suitable key exchange mode" \
+         -S "No suitable PSK key exchange mode" \
          -s "found matched identity" \
          -s "key exchange mode: psk_ephemeral"
 
@@ -510,3 +535,18 @@
          -s "$( tail -1 $EARLY_DATA_INPUT )"                                \
          -s "200 early data bytes read"                                     \
          -s "106 early data bytes read"
+
+requires_all_configs_enabled MBEDTLS_SSL_EARLY_DATA MBEDTLS_SSL_SESSION_TICKETS \
+                             MBEDTLS_SSL_CLI_C MBEDTLS_SSL_SRV_C \
+                             MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED
+run_test "TLS 1.3 m->m: Ephemeral over PSK kex with early data enabled" \
+         "$P_SRV force_version=tls13 debug_level=4 max_early_data_size=1024" \
+         "$P_CLI debug_level=4 early_data=1 tls13_kex_modes=psk_or_ephemeral reco_mode=1 reconnect=1" \
+         0 \
+         -s "key exchange mode: ephemeral" \
+         -S "key exchange mode: psk" \
+         -s "found matched identity" \
+         -s "EarlyData: rejected, not a session resumption" \
+         -C "EncryptedExtensions: early_data(42) extension exists."
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 2b51f9e..21071bd 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -212,10 +212,21 @@
     # defined in this script whose name starts with "component_".
     ALL_COMPONENTS=$(compgen -A function component_ | sed 's/component_//')
 
-    # Delay determinig SUPPORTED_COMPONENTS until the command line options have a chance to override
+    # Delay determining SUPPORTED_COMPONENTS until the command line options have a chance to override
     # the commands set by the environment
 }
 
+setup_quiet_wrappers()
+{
+    # Pick up "quiet" wrappers for make and cmake, which don't output very much
+    # unless there is an error. This reduces logging overhead in the CI.
+    #
+    # Note that the cmake wrapper breaks unless we use an absolute path here.
+    if [[ -e ${PWD}/tests/scripts/quiet ]]; then
+        export PATH=${PWD}/tests/scripts/quiet:$PATH
+    fi
+}
+
 # Test whether the component $1 is included in the command line patterns.
 is_component_included()
 {
@@ -889,6 +900,16 @@
     # Dynamic secure element support is a deprecated feature and needs to be disabled here.
     # This is done to have the same form of psa_key_attributes_s for libdriver and library.
     scripts/config.py unset MBEDTLS_PSA_CRYPTO_SE_C
+
+    # If threading is enabled on the normal build, then we need to enable it in the drivers as well,
+    # otherwise we will end up running multithreaded tests without mutexes to protect them.
+    if scripts/config.py get MBEDTLS_THREADING_C; then
+        scripts/config.py -f "$CONFIG_TEST_DRIVER_H" set MBEDTLS_THREADING_C
+    fi
+
+    if scripts/config.py get MBEDTLS_THREADING_PTHREAD; then
+        scripts/config.py -f "$CONFIG_TEST_DRIVER_H" set MBEDTLS_THREADING_PTHREAD
+    fi
 }
 
 # When called with no parameter this function disables all builtin curves.
@@ -1089,6 +1110,8 @@
     echo "MBEDTLS_ECP_RESTARTABLE" >> $expected
     # No PSA equivalent - needed by some init tests
     echo "MBEDTLS_ENTROPY_NV_SEED" >> $expected
+    # No PSA equivalent - required to run threaded tests.
+    echo "MBEDTLS_THREADING_PTHREAD" >> $expected
 
     # Compare reality with expectation.
     # We want an exact match, to ensure the above list remains up-to-date.
@@ -2177,6 +2200,8 @@
     scripts/config.py full
     scripts/config.py set MBEDTLS_THREADING_C
     scripts/config.py set MBEDTLS_THREADING_PTHREAD
+    # Self-tests do not currently use multiple threads.
+    scripts/config.py unset MBEDTLS_SELF_TEST
 
     CC=clang cmake -D CMAKE_BUILD_TYPE:String=TSan .
     make
@@ -3691,6 +3716,75 @@
     tests/ssl-opt.sh
 }
 
+# Auxiliary function to build config for hashes with and without drivers
+config_psa_crypto_hmac_use_psa () {
+    driver_only="$1"
+    # start with config full for maximum coverage (also enables USE_PSA)
+    helper_libtestdriver1_adjust_config "full"
+
+    if [ "$driver_only" -eq 1 ]; then
+        # Disable MD_C in order to disable the builtin support for HMAC. MD_LIGHT
+        # is still enabled though (for ENTROPY_C among others).
+        scripts/config.py unset MBEDTLS_MD_C
+        # Disable also the builtin hashes since they are supported by the driver
+        # and MD module is able to perform PSA dispathing.
+        scripts/config.py unset-all MBEDTLS_SHA
+        scripts/config.py unset MBEDTLS_MD5_C
+        scripts/config.py unset MBEDTLS_RIPEMD160_C
+    fi
+
+    # Direct dependencies of MD_C. We disable them also in the reference
+    # component to work with the same set of features.
+    scripts/config.py unset MBEDTLS_PKCS7_C
+    scripts/config.py unset MBEDTLS_PKCS5_C
+    scripts/config.py unset MBEDTLS_HMAC_DRBG_C
+    scripts/config.py unset MBEDTLS_HKDF_C
+    # Dependencies of HMAC_DRBG
+    scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC
+    scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_ALG_DETERMINISTIC_ECDSA
+}
+
+component_test_psa_crypto_config_accel_hmac() {
+    msg "test: full with accelerated hmac"
+
+    loc_accel_list="ALG_HMAC KEY_TYPE_HMAC \
+                    ALG_MD5 ALG_RIPEMD160 ALG_SHA_1 \
+                    ALG_SHA_224 ALG_SHA_256 ALG_SHA_384 ALG_SHA_512 \
+                    ALG_SHA3_224 ALG_SHA3_256 ALG_SHA3_384 ALG_SHA3_512"
+
+    # Configure
+    # ---------
+
+    config_psa_crypto_hmac_use_psa 1
+
+    # Build
+    # -----
+
+    helper_libtestdriver1_make_drivers "$loc_accel_list"
+
+    helper_libtestdriver1_make_main "$loc_accel_list"
+
+    # Ensure that built-in support for HMAC is disabled.
+    not grep mbedtls_md_hmac library/md.o
+
+    # Run the tests
+    # -------------
+
+    msg "test: full with accelerated hmac"
+    make test
+}
+
+component_test_psa_crypto_config_reference_hmac() {
+    msg "test: full without accelerated hmac"
+
+    config_psa_crypto_hmac_use_psa 0
+
+    make
+
+    msg "test: full without accelerated hmac"
+    make test
+}
+
 component_test_psa_crypto_config_accel_des () {
     msg "test: MBEDTLS_PSA_CRYPTO_CONFIG with accelerated DES"
 
@@ -4987,6 +5081,19 @@
     programs/test/selftest
 }
 
+component_test_gcm_largetable () {
+    msg "build: default config + GCM_LARGE_TABLE - AESNI_C - AESCE_C"
+    scripts/config.py set MBEDTLS_GCM_LARGE_TABLE
+    scripts/config.py unset MBEDTLS_PADLOCK_C
+    scripts/config.py unset MBEDTLS_AESNI_C
+    scripts/config.py unset MBEDTLS_AESCE_C
+
+    make CFLAGS='-O2 -Werror -Wall -Wextra'
+
+    msg "test: default config - GCM_LARGE_TABLE - AESNI_C - AESCE_C"
+    make test
+}
+
 component_test_aes_fewer_tables () {
     msg "build: default config with AES_FEWER_TABLES enabled"
     scripts/config.py set MBEDTLS_AES_FEWER_TABLES
@@ -6291,6 +6398,7 @@
 pre_initialize_variables
 pre_parse_command_line "$@"
 
+setup_quiet_wrappers
 pre_check_git
 pre_restore_files
 pre_back_up
diff --git a/tests/scripts/analyze_outcomes.py b/tests/scripts/analyze_outcomes.py
index 8c7f21f..5b4deb6 100755
--- a/tests/scripts/analyze_outcomes.py
+++ b/tests/scripts/analyze_outcomes.py
@@ -240,6 +240,44 @@
             }
         }
     },
+    'analyze_driver_vs_reference_hmac': {
+        'test_function': do_analyze_driver_vs_reference,
+        'args': {
+            'component_ref': 'test_psa_crypto_config_reference_hmac',
+            'component_driver': 'test_psa_crypto_config_accel_hmac',
+            'ignored_suites': [
+                # These suites require legacy hash support, which is disabled
+                # in the accelerated component.
+                'shax', 'mdx',
+                # This suite tests builtins directly, but these are missing
+                # in the accelerated case.
+                'psa_crypto_low_hash.generated',
+            ],
+            'ignored_tests': {
+                'test_suite_md': [
+                    # Builtin HMAC is not supported in the accelerate component.
+                    re.compile('.*HMAC.*'),
+                    # Following tests make use of functions which are not available
+                    # when MD_C is disabled, as it happens in the accelerated
+                    # test component.
+                    re.compile('generic .* Hash file .*'),
+                    'MD list',
+                ],
+                'test_suite_md.psa': [
+                    # "legacy only" tests require hash algorithms to be NOT
+                    # accelerated, but this of course false for the accelerated
+                    # test component.
+                    re.compile('PSA dispatch .* legacy only'),
+                ],
+                'test_suite_platform': [
+                    # Incompatible with sanitizers (e.g. ASan). If the driver
+                    # component uses a sanitizer but the reference component
+                    # doesn't, we have a PASS vs SKIP mismatch.
+                    'Check mbedtls_calloc overallocation',
+                ],
+            }
+        }
+    },
     'analyze_driver_vs_reference_cipher_aead_cmac': {
         'test_function': do_analyze_driver_vs_reference,
         'args': {
@@ -532,6 +570,11 @@
                     re.compile(r'mbedtls_ct_zeroize_if .*'),
                     re.compile(r'mbedtls_ct_memmove_left .*')
                 ],
+                'test_suite_psa_crypto': [
+                    # We don't support generate_key_ext entry points
+                    # in drivers yet.
+                    re.compile(r'PSA generate key ext: RSA, e=.*'),
+                ],
             }
         }
     },
@@ -576,8 +619,7 @@
                 'test_suite_pem': [
                     # Following tests require AES_C, but this is diabled in the
                     # accelerated component.
-                    'PEM read (AES-128-CBC + invalid iv)',
-                    'PEM read (malformed PEM AES-128-CBC)',
+                    re.compile('PEM read .*AES.*'),
                     'PEM read (unknown encryption algorithm)',
                 ],
                 'test_suite_error': [
diff --git a/tests/scripts/check_files.py b/tests/scripts/check_files.py
index 65fbc9f..4483f55 100755
--- a/tests/scripts/check_files.py
+++ b/tests/scripts/check_files.py
@@ -173,6 +173,8 @@
         b'sh': 'sh',
     }
 
+    path_exemptions = re.compile(r'tests/scripts/quiet/.*')
+
     def is_valid_shebang(self, first_line, filepath):
         m = re.match(self._shebang_re, first_line)
         if not m:
diff --git a/tests/scripts/depends.py b/tests/scripts/depends.py
index 1a84531..1990cd2 100755
--- a/tests/scripts/depends.py
+++ b/tests/scripts/depends.py
@@ -199,7 +199,10 @@
         success = True
         for command in self.commands:
             log_command(command)
-            ret = subprocess.call(command)
+            env = os.environ.copy()
+            if 'MBEDTLS_TEST_CONFIGURATION' in env:
+                env['MBEDTLS_TEST_CONFIGURATION'] += '-' + self.name
+            ret = subprocess.call(command, env=env)
             if ret != 0:
                 if command[0] not in ['make', options.make_command]:
                     log_line('*** [{}] Error {}'.format(' '.join(command), ret))
diff --git a/tests/scripts/quiet/cmake b/tests/scripts/quiet/cmake
new file mode 100755
index 0000000..930931d
--- /dev/null
+++ b/tests/scripts/quiet/cmake
@@ -0,0 +1,19 @@
+#! /usr/bin/env bash
+#
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+#
+# This swallows the output of the wrapped tool, unless there is an error.
+# This helps reduce excess logging in the CI.
+
+# If you are debugging a build / CI issue, you can get complete unsilenced logs
+# by un-commenting the following line (or setting VERBOSE_LOGS in your environment):
+
+# export VERBOSE_LOGS=1
+
+# don't silence invocations containing these arguments
+export NO_SILENCE=" --version "
+
+export TOOL="cmake"
+
+exec "$(dirname "$0")/quiet.sh" "$@"
diff --git a/tests/scripts/quiet/make b/tests/scripts/quiet/make
new file mode 100755
index 0000000..d022551
--- /dev/null
+++ b/tests/scripts/quiet/make
@@ -0,0 +1,19 @@
+#! /usr/bin/env bash
+#
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+#
+# This swallows the output of the wrapped tool, unless there is an error.
+# This helps reduce excess logging in the CI.
+
+# If you are debugging a build / CI issue, you can get complete unsilenced logs
+# by un-commenting the following line (or setting VERBOSE_LOGS in your environment):
+
+# export VERBOSE_LOGS=1
+
+# don't silence invocations containing these arguments
+export NO_SILENCE=" --version | test "
+
+export TOOL="make"
+
+exec "$(dirname "$0")/quiet.sh" "$@"
diff --git a/tests/scripts/quiet/quiet.sh b/tests/scripts/quiet/quiet.sh
new file mode 100755
index 0000000..30ee569
--- /dev/null
+++ b/tests/scripts/quiet/quiet.sh
@@ -0,0 +1,75 @@
+# -*-mode: sh; sh-shell: bash -*-
+#
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+#
+# This swallows the output of the wrapped tool, unless there is an error.
+# This helps reduce excess logging in the CI.
+
+# If you are debugging a build / CI issue, you can get complete unsilenced logs
+# by un-commenting the following line (or setting VERBOSE_LOGS in your environment):
+#
+# VERBOSE_LOGS=1
+#
+# This script provides most of the functionality for the adjacent make and cmake
+# wrappers.
+#
+# It requires two variables to be set:
+#
+# TOOL       - the name of the tool that is being wrapped (with no path), e.g. "make"
+#
+# NO_SILENCE - a regex that describes the commandline arguments for which output will not
+#              be silenced, e.g. " --version | test ". In this example, "make lib test" will
+#              not be silent, but "make lib" will be.
+
+# Locate original tool
+TOOL_WITH_PATH=$(dirname "$0")/$TOOL
+ORIGINAL_TOOL=$(type -ap "${TOOL}" | grep -v -Fx "$TOOL_WITH_PATH" | head -n1)
+
+print_quoted_args() {
+    # similar to printf '%q' "$@"
+    # but produce more human-readable results for common/simple cases like "a b"
+    for a in "$@"; do
+        # Get bash to quote the string
+        printf -v q '%q' "$a"
+        simple_pattern="^([-[:alnum:]_+./:@]+=)?([^']*)$"
+        if [[ "$a" != "$q" && $a =~ $simple_pattern ]]; then
+            # a requires some quoting (a != q), but has no single quotes, so we can
+            # simplify the quoted form - e.g.:
+            #   a b        -> 'a b'
+            #   CFLAGS=a b -> CFLAGS='a b'
+            q="${BASH_REMATCH[1]}'${BASH_REMATCH[2]}'"
+        fi
+        printf " %s" "$q"
+    done
+}
+
+if [[ ! " $* " =~ " --version " ]]; then
+    # Display the command being invoked - if it succeeds, this is all that will
+    # be displayed. Don't do this for invocations with --version, because
+    # this output is often parsed by scripts, so we don't want to modify it.
+    printf %s "${TOOL}"    1>&2
+    print_quoted_args "$@" 1>&2
+    echo                   1>&2
+fi
+
+if [[ " $@ " =~ $NO_SILENCE || -n "${VERBOSE_LOGS}" ]]; then
+    # Run original command with no output supression
+    exec "${ORIGINAL_TOOL}" "$@"
+else
+    # Run original command and capture output & exit status
+    TMPFILE=$(mktemp "quiet-${TOOL}.XXXXXX")
+    "${ORIGINAL_TOOL}" "$@" > "${TMPFILE}" 2>&1
+    EXIT_STATUS=$?
+
+    if [[ $EXIT_STATUS -ne 0 ]]; then
+        # On error, display the full output
+        cat "${TMPFILE}"
+    fi
+
+    # Remove tmpfile
+    rm "${TMPFILE}"
+
+    # Propagate the exit status
+    exit $EXIT_STATUS
+fi
diff --git a/tests/src/drivers/test_driver_key_management.c b/tests/src/drivers/test_driver_key_management.c
index a3d532d..866b31e 100644
--- a/tests/src/drivers/test_driver_key_management.c
+++ b/tests/src/drivers/test_driver_key_management.c
@@ -225,10 +225,13 @@
         defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE)
         return libtestdriver1_mbedtls_psa_rsa_generate_key(
             (const libtestdriver1_psa_key_attributes_t *) attributes,
+            NULL, 0, /* We don't support custom e in the test driver yet */
             key, key_size, key_length);
 #elif defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE)
         return mbedtls_psa_rsa_generate_key(
-            attributes, key, key_size, key_length);
+            attributes,
+            NULL, 0, /* We don't support custom e in the test driver yet */
+            key, key_size, key_length);
 #endif
     } else if (PSA_KEY_TYPE_IS_DH(psa_get_key_type(attributes))
                && PSA_KEY_TYPE_IS_KEY_PAIR(psa_get_key_type(attributes))) {
diff --git a/tests/src/drivers/test_driver_signature.c b/tests/src/drivers/test_driver_signature.c
index 00dd3e2..4fca5d1 100644
--- a/tests/src/drivers/test_driver_signature.c
+++ b/tests/src/drivers/test_driver_signature.c
@@ -49,7 +49,7 @@
     size_t signature_size,
     size_t *signature_length)
 {
-    if (attributes->core.type == PSA_KEY_TYPE_RSA_KEY_PAIR) {
+    if (attributes->type == PSA_KEY_TYPE_RSA_KEY_PAIR) {
         if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) ||
             PSA_ALG_IS_RSA_PSS(alg)) {
 #if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
@@ -71,7 +71,7 @@
         } else {
             return PSA_ERROR_INVALID_ARGUMENT;
         }
-    } else if (PSA_KEY_TYPE_IS_ECC(attributes->core.type)) {
+    } else if (PSA_KEY_TYPE_IS_ECC(attributes->type)) {
         if (PSA_ALG_IS_ECDSA(alg)) {
 #if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
             (defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
@@ -116,7 +116,7 @@
     const uint8_t *signature,
     size_t signature_length)
 {
-    if (PSA_KEY_TYPE_IS_RSA(attributes->core.type)) {
+    if (PSA_KEY_TYPE_IS_RSA(attributes->type)) {
         if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) ||
             PSA_ALG_IS_RSA_PSS(alg)) {
 #if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
@@ -138,7 +138,7 @@
         } else {
             return PSA_ERROR_INVALID_ARGUMENT;
         }
-    } else if (PSA_KEY_TYPE_IS_ECC(attributes->core.type)) {
+    } else if (PSA_KEY_TYPE_IS_ECC(attributes->type)) {
         if (PSA_ALG_IS_ECDSA(alg)) {
 #if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
             (defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
diff --git a/tests/src/helpers.c b/tests/src/helpers.c
index da0b54a..2433422 100644
--- a/tests/src/helpers.c
+++ b/tests/src/helpers.c
@@ -31,7 +31,16 @@
 #endif /* MBEDTLS_THREADING_C */
 
 /*----------------------------------------------------------------------------*/
-/* Mbedtls Test Info accessors */
+/* Mbedtls Test Info accessors
+ *
+ * NOTE - there are two types of accessors here: public accessors and internal
+ * accessors. The public accessors have prototypes in helpers.h and lock
+ * mbedtls_test_info_mutex (if mutexes are enabled). The _internal accessors,
+ * which are expected to be used from this module *only*, do not lock the mutex.
+ * These are designed to be called from within public functions which already
+ * hold the mutex. The main reason for this difference is the need to set
+ * multiple test data values atomically (without releasing the mutex) to prevent
+ * race conditions. */
 
 mbedtls_test_result_t mbedtls_test_get_result(void)
 {
@@ -50,8 +59,8 @@
     return result;
 }
 
-void mbedtls_test_set_result(mbedtls_test_result_t result, const char *test,
-                             int line_no, const char *filename)
+static void mbedtls_test_set_result_internal(mbedtls_test_result_t result, const char *test,
+                                             int line_no, const char *filename)
 {
     /* Internal function only - mbedtls_test_info_mutex should be held prior
      * to calling this function. */
@@ -144,7 +153,7 @@
     return step;
 }
 
-void mbedtls_test_reset_step(void)
+static void mbedtls_test_reset_step_internal(void)
 {
     /* Internal function only - mbedtls_test_info_mutex should be held prior
      * to calling this function. */
@@ -178,7 +187,7 @@
 #endif /* MBEDTLS_THREADING_C */
 }
 
-void mbedtls_test_set_line1(const char *line)
+static void mbedtls_test_set_line1_internal(const char *line)
 {
     /* Internal function only - mbedtls_test_info_mutex should be held prior
      * to calling this function. */
@@ -203,7 +212,7 @@
 #endif /* MBEDTLS_THREADING_C */
 }
 
-void mbedtls_test_set_line2(const char *line)
+static void mbedtls_test_set_line2_internal(const char *line)
 {
     /* Internal function only - mbedtls_test_info_mutex should be held prior
      * to calling this function. */
@@ -219,7 +228,19 @@
 #if defined(MBEDTLS_TEST_MUTEX_USAGE)
 const char *mbedtls_test_get_mutex_usage_error(void)
 {
-    return mbedtls_test_info.mutex_usage_error;
+    const char *usage_error;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    usage_error = mbedtls_test_info.mutex_usage_error;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    return usage_error;
 }
 
 void mbedtls_test_set_mutex_usage_error(const char *msg)
@@ -255,7 +276,7 @@
     return test_case_uses_negative_0;
 }
 
-void mbedtls_test_set_case_uses_negative_0(unsigned uses)
+static void mbedtls_test_set_case_uses_negative_0_internal(unsigned uses)
 {
     /* Internal function only - mbedtls_test_info_mutex should be held prior
      * to calling this function. */
@@ -341,18 +362,26 @@
     return 0;
 }
 
+static void mbedtls_test_fail_internal(const char *test, int line_no, const char *filename)
+{
+    /* Internal function only - mbedtls_test_info_mutex should be held prior
+     * to calling this function. */
+
+    /* Don't use accessor, we already hold mutex. */
+    if (mbedtls_test_info.result != MBEDTLS_TEST_RESULT_FAILED) {
+        /* If we have already recorded the test as having failed then don't
+         * overwrite any previous information about the failure. */
+        mbedtls_test_set_result_internal(MBEDTLS_TEST_RESULT_FAILED, test, line_no, filename);
+    }
+}
+
 void mbedtls_test_fail(const char *test, int line_no, const char *filename)
 {
 #ifdef MBEDTLS_THREADING_C
     mbedtls_mutex_lock(&mbedtls_test_info_mutex);
 #endif /* MBEDTLS_THREADING_C */
 
-    /* Don't use accessor, we already hold mutex. */
-    if (mbedtls_test_info.result != MBEDTLS_TEST_RESULT_FAILED) {
-        /* If we have already recorded the test as having failed then don't
-         * overwrite any previous information about the failure. */
-        mbedtls_test_set_result(MBEDTLS_TEST_RESULT_FAILED, test, line_no, filename);
-    }
+    mbedtls_test_fail_internal(test, line_no, filename);
 
 #ifdef MBEDTLS_THREADING_C
     mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
@@ -365,7 +394,7 @@
     mbedtls_mutex_lock(&mbedtls_test_info_mutex);
 #endif /* MBEDTLS_THREADING_C */
 
-    mbedtls_test_set_result(MBEDTLS_TEST_RESULT_SKIPPED, test, line_no, filename);
+    mbedtls_test_set_result_internal(MBEDTLS_TEST_RESULT_SKIPPED, test, line_no, filename);
 
 #ifdef MBEDTLS_THREADING_C
     mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
@@ -378,13 +407,13 @@
     mbedtls_mutex_lock(&mbedtls_test_info_mutex);
 #endif /* MBEDTLS_THREADING_C */
 
-    mbedtls_test_set_result(MBEDTLS_TEST_RESULT_SUCCESS, 0, 0, 0);
-    mbedtls_test_reset_step();
-    mbedtls_test_set_line1(NULL);
-    mbedtls_test_set_line2(NULL);
+    mbedtls_test_set_result_internal(MBEDTLS_TEST_RESULT_SUCCESS, 0, 0, 0);
+    mbedtls_test_reset_step_internal();
+    mbedtls_test_set_line1_internal(NULL);
+    mbedtls_test_set_line2_internal(NULL);
 
 #if defined(MBEDTLS_BIGNUM_C)
-    mbedtls_test_set_case_uses_negative_0(0);
+    mbedtls_test_set_case_uses_negative_0_internal(0);
 #endif
 
 #ifdef MBEDTLS_THREADING_C
@@ -412,15 +441,15 @@
          * overwrite any previous information about the failure. */
 
         char buf[MBEDTLS_TEST_LINE_LENGTH];
-        mbedtls_test_fail(test, line_no, filename);
+        mbedtls_test_fail_internal(test, line_no, filename);
         (void) mbedtls_snprintf(buf, sizeof(buf),
                                 "lhs = 0x%016llx = %lld",
                                 value1, (long long) value1);
-        mbedtls_test_set_line1(buf);
+        mbedtls_test_set_line1_internal(buf);
         (void) mbedtls_snprintf(buf, sizeof(buf),
                                 "rhs = 0x%016llx = %lld",
                                 value2, (long long) value2);
-        mbedtls_test_set_line2(buf);
+        mbedtls_test_set_line2_internal(buf);
     }
 
 #ifdef MBEDTLS_THREADING_C
@@ -450,15 +479,15 @@
          * overwrite any previous information about the failure. */
 
         char buf[MBEDTLS_TEST_LINE_LENGTH];
-        mbedtls_test_fail(test, line_no, filename);
+        mbedtls_test_fail_internal(test, line_no, filename);
         (void) mbedtls_snprintf(buf, sizeof(buf),
                                 "lhs = 0x%016llx = %llu",
                                 value1, value1);
-        mbedtls_test_set_line1(buf);
+        mbedtls_test_set_line1_internal(buf);
         (void) mbedtls_snprintf(buf, sizeof(buf),
                                 "rhs = 0x%016llx = %llu",
                                 value2, value2);
-        mbedtls_test_set_line2(buf);
+        mbedtls_test_set_line2_internal(buf);
     }
 
 #ifdef MBEDTLS_THREADING_C
@@ -488,15 +517,15 @@
          * overwrite any previous information about the failure. */
 
         char buf[MBEDTLS_TEST_LINE_LENGTH];
-        mbedtls_test_fail(test, line_no, filename);
+        mbedtls_test_fail_internal(test, line_no, filename);
         (void) mbedtls_snprintf(buf, sizeof(buf),
                                 "lhs = 0x%016llx = %lld",
                                 (unsigned long long) value1, value1);
-        mbedtls_test_set_line1(buf);
+        mbedtls_test_set_line1_internal(buf);
         (void) mbedtls_snprintf(buf, sizeof(buf),
                                 "rhs = 0x%016llx = %lld",
                                 (unsigned long long) value2, value2);
-        mbedtls_test_set_line2(buf);
+        mbedtls_test_set_line2_internal(buf);
     }
 
 #ifdef MBEDTLS_THREADING_C
diff --git a/tests/src/psa_crypto_stubs.c b/tests/src/psa_crypto_stubs.c
new file mode 100644
index 0000000..f3ca850
--- /dev/null
+++ b/tests/src/psa_crypto_stubs.c
@@ -0,0 +1,25 @@
+/** \file psa_crypto_stubs.c
+ *
+ * \brief Stub functions when MBEDTLS_PSA_CRYPTO_CLIENT is enabled but
+ *        MBEDTLS_PSA_CRYPTO_C is disabled.
+ */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <psa/crypto.h>
+
+#if defined(MBEDTLS_PSA_CRYPTO_CLIENT) && !defined(MBEDTLS_PSA_CRYPTO_C)
+
+psa_status_t psa_generate_random(uint8_t *output,
+                                 size_t output_size)
+{
+    (void) output;
+    (void) output_size;
+
+    return PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
+#endif /* MBEDTLS_PSA_CRYPTO_CLIENT && !MBEDTLS_PSA_CRYPTO_C */
diff --git a/tests/src/psa_exercise_key.c b/tests/src/psa_exercise_key.c
index 560b711..7b81052 100644
--- a/tests/src/psa_exercise_key.c
+++ b/tests/src/psa_exercise_key.c
@@ -20,6 +20,16 @@
 #include <psa_crypto_slot_management.h>
 #include <test/psa_crypto_helpers.h>
 
+#if defined(MBEDTLS_PK_C)
+#include <pk_internal.h>
+#endif
+#if defined(MBEDTLS_ECP_C)
+#include <mbedtls/ecp.h>
+#endif
+#if defined(MBEDTLS_RSA_C)
+#include <rsa_internal.h>
+#endif
+
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
 static int lifetime_is_dynamic_secure_element(psa_key_lifetime_t lifetime)
 {
@@ -283,23 +293,25 @@
                                   psa_key_usage_t usage,
                                   psa_algorithm_t alg)
 {
+    /* If the policy allows signing with any hash, just pick one. */
+    psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH(alg);
+    if (PSA_ALG_IS_SIGN_HASH(alg) && hash_alg == PSA_ALG_ANY_HASH &&
+        usage & (PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH |
+                 PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE)) {
+#if defined(KNOWN_SUPPORTED_HASH_ALG)
+        hash_alg = KNOWN_SUPPORTED_HASH_ALG;
+        alg ^= PSA_ALG_ANY_HASH ^ hash_alg;
+#else
+        TEST_FAIL("No hash algorithm for hash-and-sign testing");
+#endif
+    }
+
     if (usage & (PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH) &&
         PSA_ALG_IS_SIGN_HASH(alg)) {
         unsigned char payload[PSA_HASH_MAX_SIZE] = { 1 };
         size_t payload_length = 16;
         unsigned char signature[PSA_SIGNATURE_MAX_SIZE] = { 0 };
         size_t signature_length = sizeof(signature);
-        psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH(alg);
-
-        /* If the policy allows signing with any hash, just pick one. */
-        if (PSA_ALG_IS_SIGN_HASH(alg) && hash_alg == PSA_ALG_ANY_HASH) {
-    #if defined(KNOWN_SUPPORTED_HASH_ALG)
-            hash_alg = KNOWN_SUPPORTED_HASH_ALG;
-            alg ^= PSA_ALG_ANY_HASH ^ hash_alg;
-    #else
-            TEST_FAIL("No hash algorithm for hash-and-sign testing");
-    #endif
-        }
 
         /* Some algorithms require the payload to have the size of
          * the hash encoded in the algorithm. Use this input size
@@ -362,8 +374,10 @@
                                               psa_key_usage_t usage,
                                               psa_algorithm_t alg)
 {
-    unsigned char plaintext[256] = "Hello, world...";
-    unsigned char ciphertext[256] = "(wabblewebblewibblewobblewubble)";
+    unsigned char plaintext[PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE] =
+        "Hello, world...";
+    unsigned char ciphertext[PSA_ASYMMETRIC_ENCRYPT_OUTPUT_MAX_SIZE] =
+        "(wabblewebblewibblewobblewubble)";
     size_t ciphertext_length = sizeof(ciphertext);
     size_t plaintext_length = 16;
 
@@ -1005,4 +1019,142 @@
 
 }
 
+int mbedtls_test_can_exercise_psa_algorithm(psa_algorithm_t alg)
+{
+    /* Reject algorithms that we know are not supported. Default to
+     * attempting exercise, so that if an algorithm is missing from this
+     * function, the result will be a test failure and not silently
+     * omitting exercise. */
+#if !defined(PSA_WANT_ALG_RSA_PKCS1V15_CRYPT)
+    if (alg == PSA_ALG_RSA_PKCS1V15_CRYPT) {
+        return 0;
+    }
+#endif
+#if !defined(PSA_WANT_ALG_RSA_PKCS1V15_SIGN)
+    if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg)) {
+        return 0;
+    }
+#endif
+#if !defined(PSA_WANT_ALG_RSA_PSS)
+    if (PSA_ALG_IS_RSA_PSS_STANDARD_SALT(alg)) {
+        return 0;
+    }
+#endif
+#if !defined(PSA_WANT_ALG_RSA_PSS_ANY_SALT)
+    if (PSA_ALG_IS_RSA_PSS_ANY_SALT(alg)) {
+        return 0;
+    }
+#endif
+#if !defined(PSA_WANT_ALG_ECDSA)
+    if (PSA_ALG_IS_ECDSA(alg)) {
+        return 0;
+    }
+#endif
+#if !defined(PSA_WANT_ALG_DETERMINISTIC_ECDSA)
+    if (PSA_ALG_IS_DETERMINISTIC_ECDSA(alg)) {
+        return 0;
+    }
+#endif
+#if !defined(PSA_WANT_ALG_ECDH)
+    if (PSA_ALG_IS_ECDH(alg)) {
+        return 0;
+    }
+#endif
+    (void) alg;
+    return 1;
+}
+
+#if defined(MBEDTLS_PK_C)
+int mbedtls_test_key_consistency_psa_pk(mbedtls_svc_key_id_t psa_key,
+                                        const mbedtls_pk_context *pk)
+{
+    psa_key_attributes_t psa_attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_attributes_t pk_attributes = PSA_KEY_ATTRIBUTES_INIT;
+    int ok = 0;
+
+    PSA_ASSERT(psa_get_key_attributes(psa_key, &psa_attributes));
+    psa_key_type_t psa_type = psa_get_key_type(&psa_attributes);
+    mbedtls_pk_type_t pk_type = mbedtls_pk_get_type(pk);
+
+    TEST_ASSERT(PSA_KEY_TYPE_IS_PUBLIC_KEY(psa_type) ||
+                PSA_KEY_TYPE_IS_KEY_PAIR(psa_type));
+    TEST_EQUAL(psa_get_key_bits(&psa_attributes), mbedtls_pk_get_bitlen(pk));
+
+    uint8_t pk_public_buffer[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
+    const uint8_t *pk_public = NULL;
+    size_t pk_public_length = 0;
+
+    switch (pk_type) {
+#if defined(MBEDTLS_RSA_C)
+        case MBEDTLS_PK_RSA:
+            TEST_ASSERT(PSA_KEY_TYPE_IS_RSA(psa_type));
+            const mbedtls_rsa_context *rsa = mbedtls_pk_rsa(*pk);
+            uint8_t *const end = pk_public_buffer + sizeof(pk_public_buffer);
+            uint8_t *cursor = end;
+            TEST_LE_U(1, mbedtls_rsa_write_pubkey(rsa,
+                                                  pk_public_buffer, &cursor));
+            pk_public = cursor;
+            pk_public_length = end - pk_public;
+            break;
+#endif
+
+#if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
+        case MBEDTLS_PK_ECKEY:
+        case MBEDTLS_PK_ECKEY_DH:
+        case MBEDTLS_PK_ECDSA:
+            TEST_ASSERT(PSA_KEY_TYPE_IS_ECC(psa_type));
+            TEST_EQUAL(PSA_KEY_TYPE_ECC_GET_FAMILY(psa_type), pk->ec_family);
+            pk_public = pk->pub_raw;
+            pk_public_length = pk->pub_raw_len;
+            break;
+#endif /* MBEDTLS_PK_USE_PSA_EC_DATA */
+
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) && !defined(MBEDTLS_PK_USE_PSA_EC_DATA)
+        case MBEDTLS_PK_ECKEY:
+        case MBEDTLS_PK_ECKEY_DH:
+        case MBEDTLS_PK_ECDSA:
+            TEST_ASSERT(PSA_KEY_TYPE_IS_ECC(psa_get_key_type(&psa_attributes)));
+            const mbedtls_ecp_keypair *ec = mbedtls_pk_ec_ro(*pk);
+            TEST_EQUAL(mbedtls_ecp_write_public_key(
+                           ec, MBEDTLS_ECP_PF_UNCOMPRESSED, &pk_public_length,
+                           pk_public_buffer, sizeof(pk_public_buffer)), 0);
+            pk_public = pk_public_buffer;
+            break;
+#endif /* MBEDTLS_PK_HAVE_ECC_KEYS && !MBEDTLS_PK_USE_PSA_EC_DATA */
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+        case MBEDTLS_PK_OPAQUE:
+            PSA_ASSERT(psa_get_key_attributes(pk->priv_id, &pk_attributes));
+            psa_key_type_t pk_psa_type = psa_get_key_type(&pk_attributes);
+            TEST_EQUAL(PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(psa_type),
+                       PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(pk_psa_type));
+            PSA_ASSERT(psa_export_public_key(psa_key,
+                                             pk_public_buffer,
+                                             sizeof(pk_public_buffer),
+                                             &pk_public_length));
+            pk_public = pk_public_buffer;
+            break;
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+        default:
+            TEST_FAIL("pk type not supported");
+    }
+
+    uint8_t psa_public[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
+    size_t psa_public_length = 0;
+    PSA_ASSERT(psa_export_public_key(psa_key,
+                                     psa_public, sizeof(psa_public),
+                                     &psa_public_length));
+    TEST_MEMORY_COMPARE(pk_public, pk_public_length,
+                        psa_public, psa_public_length);
+
+    ok = 1;
+
+exit:
+    psa_reset_key_attributes(&psa_attributes);
+    psa_reset_key_attributes(&pk_attributes);
+    return ok;
+}
+#endif /* MBEDTLS_PK_C */
+
 #endif /* MBEDTLS_PSA_CRYPTO_C */
diff --git a/tests/src/test_helpers/ssl_helpers.c b/tests/src/test_helpers/ssl_helpers.c
index 980c192..56e03f1 100644
--- a/tests/src/test_helpers/ssl_helpers.c
+++ b/tests/src/test_helpers/ssl_helpers.c
@@ -12,9 +12,7 @@
 #include "mbedtls/psa_util.h"
 
 #if defined(MBEDTLS_SSL_TLS_C)
-#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
-static int rng_seed = 0xBEEF;
-static int rng_get(void *p_rng, unsigned char *output, size_t output_len)
+int mbedtls_test_random(void *p_rng, unsigned char *output, size_t output_len)
 {
     (void) p_rng;
     for (size_t i = 0; i < output_len; i++) {
@@ -23,7 +21,6 @@
 
     return 0;
 }
-#endif
 
 void mbedtls_test_ssl_log_analyzer(void *ctx, int level,
                                    const char *file, int line,
@@ -46,39 +43,32 @@
     mbedtls_test_handshake_test_options *opts)
 {
 #if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+    static int rng_seed = 0xBEEF;
+
     srand(rng_seed);
     rng_seed += 0xD0;
 #endif
+
+    memset(opts, 0, sizeof(*opts));
+
     opts->cipher = "";
     opts->client_min_version = MBEDTLS_SSL_VERSION_UNKNOWN;
     opts->client_max_version = MBEDTLS_SSL_VERSION_UNKNOWN;
     opts->server_min_version = MBEDTLS_SSL_VERSION_UNKNOWN;
     opts->server_max_version = MBEDTLS_SSL_VERSION_UNKNOWN;
     opts->expected_negotiated_version = MBEDTLS_SSL_VERSION_TLS1_3;
-    opts->expected_handshake_result = 0;
-    opts->expected_ciphersuite = 0;
     opts->pk_alg = MBEDTLS_PK_RSA;
-    opts->opaque_alg = 0;
-    opts->opaque_alg2 = 0;
-    opts->opaque_usage = 0;
-    opts->psk_str = NULL;
-    opts->dtls = 0;
     opts->srv_auth_mode = MBEDTLS_SSL_VERIFY_NONE;
-    opts->serialize = 0;
     opts->mfl = MBEDTLS_SSL_MAX_FRAG_LEN_NONE;
     opts->cli_msg_len = 100;
     opts->srv_msg_len = 100;
     opts->expected_cli_fragments = 1;
     opts->expected_srv_fragments = 1;
-    opts->renegotiate = 0;
     opts->legacy_renegotiation = MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION;
-    opts->srv_log_obj = NULL;
-    opts->cli_log_obj = NULL;
-    opts->srv_log_fun = NULL;
-    opts->cli_log_fun = NULL;
     opts->resize_buffers = 1;
+    opts->early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED;
+    opts->max_early_data_size = -1;
 #if defined(MBEDTLS_SSL_CACHE_C)
-    opts->cache = NULL;
     TEST_CALLOC(opts->cache, 1);
     mbedtls_ssl_cache_init(opts->cache);
 #if defined(MBEDTLS_HAVE_TIME)
@@ -695,9 +685,20 @@
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     if (opaque_alg != 0) {
-        TEST_EQUAL(mbedtls_pk_wrap_as_opaque(cert->pkey, &key_slot,
-                                             opaque_alg, opaque_usage,
-                                             opaque_alg2), 0);
+        psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
+        /* Use a fake key usage to get a successful initial guess for the PSA attributes. */
+        TEST_EQUAL(mbedtls_pk_get_psa_attributes(cert->pkey, PSA_KEY_USAGE_SIGN_HASH,
+                                                 &key_attr), 0);
+        /* Then manually usage, alg and alg2 as requested by the test. */
+        psa_set_key_usage_flags(&key_attr, opaque_usage);
+        psa_set_key_algorithm(&key_attr, opaque_alg);
+        if (opaque_alg2 != PSA_ALG_NONE) {
+            psa_set_key_enrollment_algorithm(&key_attr, opaque_alg2);
+        }
+        TEST_EQUAL(mbedtls_pk_import_into_psa(cert->pkey, &key_attr, &key_slot), 0);
+        mbedtls_pk_free(cert->pkey);
+        mbedtls_pk_init(cert->pkey);
+        TEST_EQUAL(mbedtls_pk_setup_opaque(cert->pkey, key_slot), 0);
     }
 #else
     (void) opaque_alg;
@@ -733,8 +734,7 @@
     mbedtls_test_handshake_test_options *options,
     mbedtls_test_message_socket_context *dtls_context,
     mbedtls_test_ssl_message_queue *input_queue,
-    mbedtls_test_ssl_message_queue *output_queue,
-    uint16_t *group_list)
+    mbedtls_test_ssl_message_queue *output_queue)
 {
     int ret = -1;
     uintptr_t user_data_n;
@@ -755,7 +755,7 @@
 
     mbedtls_ssl_init(&(ep->ssl));
     mbedtls_ssl_config_init(&(ep->conf));
-    mbedtls_ssl_conf_rng(&(ep->conf), rng_get, NULL);
+    mbedtls_ssl_conf_rng(&(ep->conf), mbedtls_test_random, NULL);
 
     TEST_ASSERT(mbedtls_ssl_conf_get_user_data_p(&ep->conf) == NULL);
     TEST_EQUAL(mbedtls_ssl_conf_get_user_data_n(&ep->conf), 0);
@@ -818,12 +818,23 @@
         }
     }
 
-    if (group_list != NULL) {
-        mbedtls_ssl_conf_groups(&(ep->conf), group_list);
+    if (options->group_list != NULL) {
+        mbedtls_ssl_conf_groups(&(ep->conf), options->group_list);
     }
 
     mbedtls_ssl_conf_authmode(&(ep->conf), MBEDTLS_SSL_VERIFY_REQUIRED);
 
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+    mbedtls_ssl_conf_early_data(&(ep->conf), options->early_data);
+#if defined(MBEDTLS_SSL_SRV_C)
+    if (endpoint_type == MBEDTLS_SSL_IS_SERVER &&
+        (options->max_early_data_size >= 0)) {
+        mbedtls_ssl_conf_max_early_data_size(&(ep->conf),
+                                             options->max_early_data_size);
+    }
+#endif
+#endif
+
 #if defined(MBEDTLS_SSL_CACHE_C) && defined(MBEDTLS_SSL_SRV_C)
     if (endpoint_type == MBEDTLS_SSL_IS_SERVER && options->cache != NULL) {
         mbedtls_ssl_conf_session_cache(&(ep->conf), options->cache,
@@ -1653,12 +1664,20 @@
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
 int mbedtls_test_ssl_tls12_populate_session(mbedtls_ssl_session *session,
                                             int ticket_len,
+                                            int endpoint_type,
                                             const char *crt_file)
 {
+    (void) ticket_len;
+
 #if defined(MBEDTLS_HAVE_TIME)
     session->start = mbedtls_time(NULL) - 42;
 #endif
     session->tls_version = MBEDTLS_SSL_VERSION_TLS1_2;
+
+    TEST_ASSERT(endpoint_type == MBEDTLS_SSL_IS_CLIENT ||
+                endpoint_type == MBEDTLS_SSL_IS_SERVER);
+
+    session->endpoint = endpoint_type;
     session->ciphersuite = 0xabcd;
     session->id_len = sizeof(session->id);
     memset(session->id, 66, session->id_len);
@@ -1724,7 +1743,8 @@
 #endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED && MBEDTLS_FS_IO */
     session->verify_result = 0xdeadbeef;
 
-#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+#if defined(MBEDTLS_SSL_CLI_C)
     if (ticket_len != 0) {
         session->ticket = mbedtls_calloc(1, ticket_len);
         if (session->ticket == NULL) {
@@ -1734,9 +1754,14 @@
     }
     session->ticket_len = ticket_len;
     session->ticket_lifetime = 86401;
-#else
-    (void) ticket_len;
+#endif /* MBEDTLS_SSL_CLI_C */
+
+#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_HAVE_TIME)
+    if (session->endpoint == MBEDTLS_SSL_IS_SERVER) {
+        session->ticket_creation_time = mbedtls_ms_time() - 42;
+    }
 #endif
+#endif /* MBEDTLS_SSL_SESSION_TICKETS */
 
 #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
     session->mfl_code = 1;
@@ -1745,6 +1770,7 @@
     session->encrypt_then_mac = 1;
 #endif
 
+exit:
     return 0;
 }
 #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
@@ -2006,7 +2032,7 @@
                                                    MBEDTLS_SSL_IS_CLIENT,
                                                    options, &client_context,
                                                    &client_queue,
-                                                   &server_queue, NULL) == 0);
+                                                   &server_queue) == 0);
 #if defined(MBEDTLS_TIMING_C)
         mbedtls_ssl_set_timer_cb(&client.ssl, &timer_client,
                                  mbedtls_timing_set_delay,
@@ -2016,7 +2042,7 @@
         TEST_ASSERT(mbedtls_test_ssl_endpoint_init(&client,
                                                    MBEDTLS_SSL_IS_CLIENT,
                                                    options, NULL, NULL,
-                                                   NULL, NULL) == 0);
+                                                   NULL) == 0);
     }
 
     if (strlen(options->cipher) > 0) {
@@ -2029,7 +2055,7 @@
                                                    MBEDTLS_SSL_IS_SERVER,
                                                    options, &server_context,
                                                    &server_queue,
-                                                   &client_queue, NULL) == 0);
+                                                   &client_queue) == 0);
 #if defined(MBEDTLS_TIMING_C)
         mbedtls_ssl_set_timer_cb(&server.ssl, &timer_server,
                                  mbedtls_timing_set_delay,
@@ -2038,7 +2064,7 @@
     } else {
         TEST_ASSERT(mbedtls_test_ssl_endpoint_init(&server,
                                                    MBEDTLS_SSL_IS_SERVER,
-                                                   options, NULL, NULL, NULL,
+                                                   options, NULL, NULL,
                                                    NULL) == 0);
     }
 
@@ -2462,4 +2488,60 @@
     return mbedtls_ssl_session_load(session, buf, len);
 }
 #endif /* MBEDTLS_SSL_SESSION_TICKETS */
+
+#if defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_SRV_C) && \
+    defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS) && \
+    defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+int mbedtls_test_get_tls13_ticket(
+    mbedtls_test_handshake_test_options *client_options,
+    mbedtls_test_handshake_test_options *server_options,
+    mbedtls_ssl_session *session)
+{
+    int ret = -1;
+    unsigned char buf[64];
+    mbedtls_test_ssl_endpoint client_ep, server_ep;
+
+    mbedtls_platform_zeroize(&client_ep, sizeof(client_ep));
+    mbedtls_platform_zeroize(&server_ep, sizeof(server_ep));
+
+    ret = mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT,
+                                         client_options, NULL, NULL, NULL);
+    TEST_EQUAL(ret, 0);
+
+    ret = mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER,
+                                         server_options, NULL, NULL, NULL);
+    TEST_EQUAL(ret, 0);
+
+    mbedtls_ssl_conf_session_tickets_cb(&server_ep.conf,
+                                        mbedtls_test_ticket_write,
+                                        mbedtls_test_ticket_parse,
+                                        NULL);
+
+    ret = mbedtls_test_mock_socket_connect(&(client_ep.socket),
+                                           &(server_ep.socket), 1024);
+    TEST_EQUAL(ret, 0);
+
+    TEST_EQUAL(mbedtls_test_move_handshake_to_state(
+                   &(server_ep.ssl), &(client_ep.ssl),
+                   MBEDTLS_SSL_HANDSHAKE_OVER), 0);
+
+    TEST_EQUAL(server_ep.ssl.handshake->new_session_tickets_count, 0);
+
+    do {
+        ret = mbedtls_ssl_read(&(client_ep.ssl), buf, sizeof(buf));
+    } while (ret != MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET);
+
+    ret = mbedtls_ssl_get_session(&(client_ep.ssl), session);
+    TEST_EQUAL(ret, 0);
+
+exit:
+    mbedtls_test_ssl_endpoint_free(&client_ep, NULL);
+    mbedtls_test_ssl_endpoint_free(&server_ep, NULL);
+
+    return ret;
+}
+#endif /* MBEDTLS_SSL_CLI_C && MBEDTLS_SSL_SRV_C &&
+          MBEDTLS_SSL_PROTO_TLS1_3 && MBEDTLS_SSL_SESSION_TICKETS &&
+          MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+
 #endif /* MBEDTLS_SSL_TLS_C */
diff --git a/tests/src/threading_helpers.c b/tests/src/threading_helpers.c
index ff0c712..c1686c2 100644
--- a/tests/src/threading_helpers.c
+++ b/tests/src/threading_helpers.c
@@ -317,22 +317,26 @@
 
 void mbedtls_test_mutex_usage_check(void)
 {
-    if (live_mutexes != 0) {
-        /* A positive number (more init than free) means that a mutex resource
-         * is leaking (on platforms where a mutex consumes more than the
-         * mbedtls_threading_mutex_t object itself). The rare case of a
-         * negative number means a missing init somewhere. */
-        mbedtls_fprintf(stdout, "[mutex: %d leaked] ", live_mutexes);
-        live_mutexes = 0;
-        mbedtls_test_set_mutex_usage_error("missing free");
+    if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
+        if (live_mutexes != 0) {
+            /* A positive number (more init than free) means that a mutex resource
+             * is leaking (on platforms where a mutex consumes more than the
+             * mbedtls_threading_mutex_t object itself). The (hopefully) rare
+             * case of a negative number means a missing init somewhere. */
+            mbedtls_fprintf(stdout, "[mutex: %d leaked] ", live_mutexes);
+            live_mutexes = 0;
+            mbedtls_test_set_mutex_usage_error("missing free");
+        }
+        if (mbedtls_test_get_mutex_usage_error() != NULL &&
+            mbedtls_test_get_result() != MBEDTLS_TEST_RESULT_FAILED) {
+            /* Functionally, the test passed. But there was a mutex usage error,
+             * so mark the test as failed after all. */
+            mbedtls_test_fail("Mutex usage error", __LINE__, __FILE__);
+        }
+        mbedtls_test_set_mutex_usage_error(NULL);
+
+        mutex_functions.unlock(&mbedtls_test_mutex_mutex);
     }
-    if (mbedtls_test_get_mutex_usage_error() != NULL &&
-        mbedtls_test_get_result() != MBEDTLS_TEST_RESULT_FAILED) {
-        /* Functionally, the test passed. But there was a mutex usage error,
-         * so mark the test as failed after all. */
-        mbedtls_test_fail("Mutex usage error", __LINE__, __FILE__);
-    }
-    mbedtls_test_set_mutex_usage_error(NULL);
 }
 
 void mbedtls_test_mutex_usage_end(void)
diff --git a/tests/suites/test_suite_bignum.function b/tests/suites/test_suite_bignum.function
index 50be2d2..f3a64e1 100644
--- a/tests/suites/test_suite_bignum.function
+++ b/tests/suites/test_suite_bignum.function
@@ -966,6 +966,45 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void mpi_exp_mod_min_RR(char *input_A, char *input_E,
+                        char *input_N, char *input_X,
+                        int exp_result)
+{
+    mbedtls_mpi A, E, N, RR, Z, X;
+    int res;
+    mbedtls_mpi_init(&A); mbedtls_mpi_init(&E); mbedtls_mpi_init(&N);
+    mbedtls_mpi_init(&RR); mbedtls_mpi_init(&Z); mbedtls_mpi_init(&X);
+
+    TEST_EQUAL(mbedtls_test_read_mpi(&A, input_A), 0);
+    TEST_EQUAL(mbedtls_test_read_mpi(&E, input_E), 0);
+    TEST_EQUAL(mbedtls_test_read_mpi(&N, input_N), 0);
+    TEST_EQUAL(mbedtls_test_read_mpi(&X, input_X), 0);
+
+    TEST_EQUAL(mbedtls_mpi_core_get_mont_r2_unsafe(&RR, &N), 0);
+    TEST_EQUAL(mbedtls_mpi_shrink(&RR, 0), 0);
+    /* The objective of this test is to check that exp_mod defends
+     * against a smaller RR. */
+    TEST_LE_U(RR.n, N.n - 1);
+
+    res = mbedtls_mpi_exp_mod(&Z, &A, &E, &N, &RR);
+    /* We know that exp_mod internally needs RR to be as large as N.
+     * Validate that it is the case now, otherwise there was probably
+     * a buffer overread. */
+    TEST_EQUAL(RR.n, N.n);
+
+    TEST_EQUAL(res, exp_result);
+    if (res == 0) {
+        TEST_EQUAL(sign_is_valid(&Z), 1);
+        TEST_EQUAL(mbedtls_mpi_cmp_mpi(&Z, &X), 0);
+    }
+
+exit:
+    mbedtls_mpi_free(&A); mbedtls_mpi_free(&E); mbedtls_mpi_free(&N);
+    mbedtls_mpi_free(&RR); mbedtls_mpi_free(&Z); mbedtls_mpi_free(&X);
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void mpi_exp_mod(char *input_A, char *input_E,
                  char *input_N, char *input_X,
                  int exp_result)
diff --git a/tests/suites/test_suite_bignum.misc.data b/tests/suites/test_suite_bignum.misc.data
index c53e42a..eb55dbe 100644
--- a/tests/suites/test_suite_bignum.misc.data
+++ b/tests/suites/test_suite_bignum.misc.data
@@ -1362,6 +1362,9 @@
 Test mbedtls_mpi_exp_mod: 10 ^ 0 (1 limb) mod 9
 mpi_exp_mod:"0a":"00":"09":"1":0
 
+Test mbedtls_mpi_exp_mod: -3 ^ 3 mod 27
+mpi_exp_mod:"-3":"3":"1b":"1b":0
+
 Test mbedtls_mpi_exp_mod: MAX_SIZE exponent
 mpi_exp_mod_size:2:MBEDTLS_MPI_MAX_SIZE:10:"":0
 
@@ -1391,6 +1394,14 @@
 depends_on:MPI_MAX_BITS_LARGER_THAN_792
 mpi_exp_mod:"-9f13012cd92aa72fb86ac8879d2fde4f7fd661aaae43a00971f081cc60ca277059d5c37e89652e2af2585d281d66ef6a9d38a117e9608e9e7574cd142dc55278838a2161dd56db9470d4c1da2d5df15a908ee2eb886aaa890f23be16de59386663a12f1afbb325431a3e835e3fd89b98b96a6f77382f458ef9a37e1f84a03045c8676ab55291a94c2228ea15448ee96b626b998":"40a54d1b9e86789f06d9607fb158672d64867665c73ee9abb545fc7a785634b354c7bae5b962ce8040cf45f2c1f3d3659b2ee5ede17534c8fc2ec85c815e8df1fe7048d12c90ee31b88a68a081f17f0d8ce5f4030521e9400083bcea73a429031d4ca7949c2000d597088e0c39a6014d8bf962b73bb2e8083bd0390a4e00b9b3":"eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3":"21acc7199e1b90f9b4844ffe12c19f00ec548c5d32b21c647d48b6015d8eb9ec9db05b4f3d44db4227a2b5659c1a7cceb9d5fa8fa60376047953ce7397d90aaeb7465e14e820734f84aa52ad0fc66701bcbb991d57715806a11531268e1e83dd48288c72b424a6287e9ce4e5cc4db0dd67614aecc23b0124a5776d36e5c89483":0
 
+Test mbedtls_mpi_exp_mod (N.n=3, RR.n=1 on 32 bit)
+depends_on:MBEDTLS_HAVE_INT32
+mpi_exp_mod_min_RR:"10":"2":"10000000100000001":"100":0
+
+Test mbedtls_mpi_exp_mod (N.n=3, RR.n=1 on 64 bit)
+depends_on:MBEDTLS_HAVE_INT64
+mpi_exp_mod_min_RR:"10":"2":"100000000000000010000000000000001":"100":0
+
 Base test GCD #1
 mpi_gcd:"2b5":"261":"15"
 
diff --git a/tests/suites/test_suite_debug.function b/tests/suites/test_suite_debug.function
index eeefc95..70e7bad 100644
--- a/tests/suites/test_suite_debug.function
+++ b/tests/suites/test_suite_debug.function
@@ -2,6 +2,7 @@
 #include "debug_internal.h"
 #include "string.h"
 #include "mbedtls/pk.h"
+#include <test/ssl_helpers.h>
 
 struct buffer_data {
     char buf[2000];
@@ -65,11 +66,12 @@
     memset(buffer.buf, 0, 2000);
     buffer.ptr = buffer.buf;
 
-    mbedtls_ssl_config_defaults(&conf,
-                                MBEDTLS_SSL_IS_CLIENT,
-                                MBEDTLS_SSL_TRANSPORT_STREAM,
-                                MBEDTLS_SSL_PRESET_DEFAULT);
-
+    TEST_EQUAL(mbedtls_ssl_config_defaults(&conf,
+                                           MBEDTLS_SSL_IS_CLIENT,
+                                           MBEDTLS_SSL_TRANSPORT_STREAM,
+                                           MBEDTLS_SSL_PRESET_DEFAULT),
+               0);
+    mbedtls_ssl_conf_rng(&conf, mbedtls_test_random, NULL);
     mbedtls_ssl_conf_dbg(&conf, string_debug, &buffer);
 
     TEST_ASSERT(mbedtls_ssl_setup(&ssl, &conf) == 0);
@@ -103,11 +105,12 @@
     memset(buffer.buf, 0, 2000);
     buffer.ptr = buffer.buf;
 
-    mbedtls_ssl_config_defaults(&conf,
-                                MBEDTLS_SSL_IS_CLIENT,
-                                MBEDTLS_SSL_TRANSPORT_STREAM,
-                                MBEDTLS_SSL_PRESET_DEFAULT);
-
+    TEST_EQUAL(mbedtls_ssl_config_defaults(&conf,
+                                           MBEDTLS_SSL_IS_CLIENT,
+                                           MBEDTLS_SSL_TRANSPORT_STREAM,
+                                           MBEDTLS_SSL_PRESET_DEFAULT),
+               0);
+    mbedtls_ssl_conf_rng(&conf, mbedtls_test_random, NULL);
     mbedtls_ssl_conf_dbg(&conf, string_debug, &buffer);
 
     TEST_ASSERT(mbedtls_ssl_setup(&ssl, &conf) == 0);
@@ -138,11 +141,12 @@
     memset(buffer.buf, 0, 2000);
     buffer.ptr = buffer.buf;
 
-    mbedtls_ssl_config_defaults(&conf,
-                                MBEDTLS_SSL_IS_CLIENT,
-                                MBEDTLS_SSL_TRANSPORT_STREAM,
-                                MBEDTLS_SSL_PRESET_DEFAULT);
-
+    TEST_EQUAL(mbedtls_ssl_config_defaults(&conf,
+                                           MBEDTLS_SSL_IS_CLIENT,
+                                           MBEDTLS_SSL_TRANSPORT_STREAM,
+                                           MBEDTLS_SSL_PRESET_DEFAULT),
+               0);
+    mbedtls_ssl_conf_rng(&conf, mbedtls_test_random, NULL);
     mbedtls_ssl_conf_dbg(&conf, string_debug, &buffer);
 
     TEST_ASSERT(mbedtls_ssl_setup(&ssl, &conf) == 0);
@@ -175,11 +179,12 @@
     memset(buffer.buf, 0, 2000);
     buffer.ptr = buffer.buf;
 
-    mbedtls_ssl_config_defaults(&conf,
-                                MBEDTLS_SSL_IS_CLIENT,
-                                MBEDTLS_SSL_TRANSPORT_STREAM,
-                                MBEDTLS_SSL_PRESET_DEFAULT);
-
+    TEST_EQUAL(mbedtls_ssl_config_defaults(&conf,
+                                           MBEDTLS_SSL_IS_CLIENT,
+                                           MBEDTLS_SSL_TRANSPORT_STREAM,
+                                           MBEDTLS_SSL_PRESET_DEFAULT),
+               0);
+    mbedtls_ssl_conf_rng(&conf, mbedtls_test_random, NULL);
     mbedtls_ssl_conf_dbg(&conf, string_debug, &buffer);
 
     TEST_ASSERT(mbedtls_ssl_setup(&ssl, &conf) == 0);
@@ -214,11 +219,12 @@
     memset(buffer.buf, 0, 2000);
     buffer.ptr = buffer.buf;
 
-    mbedtls_ssl_config_defaults(&conf,
-                                MBEDTLS_SSL_IS_CLIENT,
-                                MBEDTLS_SSL_TRANSPORT_STREAM,
-                                MBEDTLS_SSL_PRESET_DEFAULT);
-
+    TEST_EQUAL(mbedtls_ssl_config_defaults(&conf,
+                                           MBEDTLS_SSL_IS_CLIENT,
+                                           MBEDTLS_SSL_TRANSPORT_STREAM,
+                                           MBEDTLS_SSL_PRESET_DEFAULT),
+               0);
+    mbedtls_ssl_conf_rng(&conf, mbedtls_test_random, NULL);
     mbedtls_ssl_conf_dbg(&conf, string_debug, &buffer);
 
     TEST_ASSERT(mbedtls_ssl_setup(&ssl, &conf) == 0);
diff --git a/tests/suites/test_suite_ecdh.data b/tests/suites/test_suite_ecdh.data
index cc58432..8d06067 100644
--- a/tests/suites/test_suite_ecdh.data
+++ b/tests/suites/test_suite_ecdh.data
@@ -100,3 +100,19 @@
 ECDH get_params with mismatched groups: their SECP256R1, our BP256R1
 depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_BP256R1_ENABLED
 ecdh_exchange_get_params_fail:MBEDTLS_ECP_DP_BP256R1:"1234567812345678123456781234567812345678123456781234567812345678":MBEDTLS_ECP_DP_SECP256R1:"04dad0b65394221cf9b051e1feca5787d098dfe637fc90b9ef945d0c37725811805271a0461cdb8252d61f1c456fa3e59ab1f45b33accf5f58389e0577b8990bb3":1:MBEDTLS_ERR_ECP_BAD_INPUT_DATA
+
+Context get ECP Group #1
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecdh_context_grp:MBEDTLS_ECP_DP_SECP256R1
+
+Context get ECP Group #2
+depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED
+ecdh_primitive_random:MBEDTLS_ECP_DP_SECP384R1
+
+Context get ECP Group #3
+depends_on:MBEDTLS_ECP_DP_SECP521R1_ENABLED
+ecdh_primitive_random:MBEDTLS_ECP_DP_SECP521R1
+
+Context get ECP Group #4
+depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED
+ecdh_primitive_random:MBEDTLS_ECP_DP_CURVE448
diff --git a/tests/suites/test_suite_ecdh.function b/tests/suites/test_suite_ecdh.function
index cc193da..300916f 100644
--- a/tests/suites/test_suite_ecdh.function
+++ b/tests/suites/test_suite_ecdh.function
@@ -464,3 +464,20 @@
     mbedtls_ecp_keypair_free(&their_key);
 }
 /* END_CASE */
+
+/* BEGIN_CASE */
+void ecdh_context_grp(int id)
+{
+    mbedtls_ecdh_context srv;
+
+    mbedtls_ecdh_init(&srv);
+    TEST_ASSERT(mbedtls_ecdh_setup(&srv, id) == 0);
+
+    /* Test the retrieved group id matches/*/
+    TEST_ASSERT((int) mbedtls_ecdh_get_grp_id(&srv) == id);
+
+exit:
+    mbedtls_ecdh_free(&srv);
+
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_ecp.data b/tests/suites/test_suite_ecp.data
index 01fdc47..fd63657 100644
--- a/tests/suites/test_suite_ecp.data
+++ b/tests/suites/test_suite_ecp.data
@@ -736,6 +736,261 @@
 depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
 mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"70076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c6a":0:1
 
+ECP write key: secp256r1, nominal
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":32:0
+
+ECP write key: secp256r1, output longer by 1
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":33:0
+
+ECP write key: secp256r1, output longer by 32
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":64:0
+
+ECP write key: secp256r1, output longer by 33
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":65:0
+
+ECP write key: secp256r1, output short by 1
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":31:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
+
+ECP write key: secp256r1, output_size=1
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":1:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
+
+ECP write key: secp256r1, output_size=0
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":0:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
+
+ECP write key: secp256r1, top byte = 0, output_size=32
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":32:0
+
+ECP write key: secp256r1, top byte = 0, output_size=31 (fits)
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":31:0
+
+ECP write key: secp256r1, top byte = 0, output_size=30 (too small)
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":30:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
+
+ECP write key: secp256r1, mostly-0 key, output_size=32
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"0000000000000000000000000000000000000000000000000000000000000001":32:0
+
+ECP write key: secp256r1, mostly-0 key, output_size=31 (fits)
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"0000000000000000000000000000000000000000000000000000000000000001":31:0
+
+ECP write key: secp256r1, mostly-0 key, output_size=1 (fits)
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"0000000000000000000000000000000000000000000000000000000000000001":1:0
+
+ECP write key: secp384r1, nominal
+depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":48:0
+
+ECP write key: secp384r1, output longer by 1
+depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":49:0
+
+ECP write key: secp384r1, output longer by 48
+depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":96:0
+
+ECP write key: secp384r1, output longer by 49
+depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":97:0
+
+ECP write key: secp384r1, output short by 1
+depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":47:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
+
+ECP write key: secp384r1, output_size=1
+depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":1:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
+
+ECP write key: secp384r1, output_size=0
+depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":0:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
+
+ECP write key: Curve25519, nominal
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":32:0
+
+ECP write key: Curve25519, output longer by 1
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":33:0
+
+ECP write key: Curve25519, output longer by 32
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":64:0
+
+ECP write key: Curve25519, output longer by 33
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":65:0
+
+ECP write key: Curve25519, output short by 1
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":31:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key: Curve25519, output_size=1
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":1:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key: Curve25519, output_size=0
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":0:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key: Curve25519, mostly-0 key, output_size=32
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"0000000000000000000000000000000000000000000000000000000000000040":32:0
+
+ECP write key: Curve25519, mostly-0 key, output_size=31
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"0000000000000000000000000000000000000000000000000000000000000040":31:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key: Curve448, nominal
+depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":56:0
+
+ECP write key: Curve448, output longer by 1
+depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":57:0
+
+ECP write key: Curve448, output longer by 32
+depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":112:0
+
+ECP write key: Curve448, output longer by 33
+depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":113:0
+
+ECP write key: Curve448, output short by 1
+depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":55:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key: Curve448, output_size=1
+depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":1:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key: Curve448, output_size=0
+depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":0:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key: Curve448, mostly-0 key, output_size=56
+depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080":56:0
+
+ECP write key: Curve448, mostly-0 key, output_size=55
+depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED
+ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080":55:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key ext: secp256r1, nominal
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":32:0
+
+ECP write key ext: secp256r1, output longer by 1
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":33:0
+
+ECP write key ext: secp256r1, output short by 1
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":31:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key ext: secp256r1, output_size=0
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":0:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key ext: secp256r1, top byte = 0, output_size=32
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":32:0
+
+ECP write key ext: secp256r1, top byte = 0, output_size=31
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":31:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key ext: secp256r1, top byte = 0, output_size=30
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":30:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key ext: secp256r1, mostly-0 key, output_size=32
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"0000000000000000000000000000000000000000000000000000000000000001":32:0
+
+ECP write key ext: secp256r1, mostly-0 key, output_size=1
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"0000000000000000000000000000000000000000000000000000000000000001":1:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key ext: secp256r1, private key not set
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"":32:MBEDTLS_ERR_ECP_BAD_INPUT_DATA
+
+ECP write key ext: secp384r1, nominal
+depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":48:0
+
+ECP write key ext: secp384r1, output longer by 1
+depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":49:0
+
+ECP write key ext: secp384r1, output short by 1
+depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":47:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key ext: Curve25519, nominal
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":32:0
+
+ECP write key ext: Curve25519, output longer by 1
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":33:0
+
+ECP write key ext: Curve25519, output short by 1
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":31:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key ext: Curve25519, output_size=0
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":0:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key ext: Curve25519, mostly-0 key, output_size=32
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE25519:"0000000000000000000000000000000000000000000000000000000000000040":32:0
+
+ECP write key ext: Curve25519, mostly-0 key, output_size=31
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE25519:"0000000000000000000000000000000000000000000000000000000000000040":31:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key ext: Curve25519, private key not set
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE25519:"":32:MBEDTLS_ERR_ECP_BAD_INPUT_DATA
+
+ECP write key ext: Curve448, nominal
+depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":56:0
+
+ECP write key ext: Curve448, output longer by 1
+depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":57:0
+
+ECP write key ext: Curve448, output short by 1
+depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":55:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key ext: Curve448, mostly-0 key, output_size=56
+depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE448:"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080":56:0
+
+ECP write key ext: Curve448, mostly-0 key, output_size=55
+depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED
+ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE448:"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080":55:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
+ECP write key ext: group not set
+ecp_write_key_ext:MBEDTLS_ECP_DP_NONE:"":32:MBEDTLS_ERR_ECP_BAD_INPUT_DATA
+
 ECP mod p192 small (more than 192 bits, less limbs than 2 * 192 bits)
 depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED:MBEDTLS_ECP_NIST_OPTIM
 ecp_fast_mod:MBEDTLS_ECP_DP_SECP192R1:"0100000000000103010000000000010201000000000001010100000000000100"
diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function
index 295fe7f..9b5c86f 100644
--- a/tests/suites/test_suite_ecp.function
+++ b/tests/suites/test_suite_ecp.function
@@ -1204,29 +1204,46 @@
         TEST_EQUAL(mbedtls_mpi_cmp_int(&key.Q.Y, 2), 0);
         TEST_EQUAL(mbedtls_mpi_cmp_int(&key.Q.Z, 3), 0);
 
-        if (canonical) {
+        if (canonical && in_key->len == (key.grp.nbits + 7) / 8) {
             unsigned char buf[MBEDTLS_ECP_MAX_BYTES];
+            size_t length = 0xdeadbeef;
 
-            ret = mbedtls_ecp_write_key(&key, buf, in_key->len);
-            TEST_ASSERT(ret == 0);
+            TEST_EQUAL(mbedtls_ecp_write_key_ext(&key,
+                                                 &length, buf, in_key->len), 0);
+            TEST_MEMORY_COMPARE(in_key->x, in_key->len,
+                                buf, length);
 
+#if defined(MBEDTLS_TEST_DEPRECATED)
+            memset(buf, 0, sizeof(buf));
+            TEST_EQUAL(mbedtls_ecp_write_key(&key, buf, in_key->len), 0);
             TEST_MEMORY_COMPARE(in_key->x, in_key->len,
                                 buf, in_key->len);
+#endif /* MBEDTLS_TEST_DEPRECATED */
         } else {
             unsigned char export1[MBEDTLS_ECP_MAX_BYTES];
             unsigned char export2[MBEDTLS_ECP_MAX_BYTES];
 
-            ret = mbedtls_ecp_write_key(&key, export1, in_key->len);
-            TEST_ASSERT(ret == 0);
+            size_t length1 = 0xdeadbeef;
+            TEST_EQUAL(mbedtls_ecp_write_key_ext(&key, &length1,
+                                                 export1, sizeof(export1)), 0);
+            TEST_EQUAL(mbedtls_ecp_read_key(grp_id, &key2, export1, length1),
+                       expected);
+            size_t length2 = 0xdeadbeef;
+            TEST_EQUAL(mbedtls_ecp_write_key_ext(&key2, &length2,
+                                                 export2, sizeof(export2)), 0);
+            TEST_MEMORY_COMPARE(export1, length1,
+                                export2, length2);
 
-            ret = mbedtls_ecp_read_key(grp_id, &key2, export1, in_key->len);
-            TEST_ASSERT(ret == expected);
-
-            ret = mbedtls_ecp_write_key(&key2, export2, in_key->len);
-            TEST_ASSERT(ret == 0);
-
+#if defined(MBEDTLS_TEST_DEPRECATED)
+            memset(export1, 0, sizeof(export1));
+            memset(export2, 0, sizeof(export2));
+            TEST_EQUAL(mbedtls_ecp_write_key(&key, export1, in_key->len), 0);
+            TEST_EQUAL(mbedtls_ecp_read_key(grp_id, &key2, export1, in_key->len),
+                       expected);
+            TEST_EQUAL(mbedtls_ecp_write_key(&key2, export2, in_key->len), 0);
             TEST_MEMORY_COMPARE(export1, in_key->len,
                                 export2, in_key->len);
+#endif /* MBEDTLS_TEST_DEPRECATED */
         }
     }
 
@@ -1236,6 +1253,102 @@
 }
 /* END_CASE */
 
+/* BEGIN_CASE depends_on:MBEDTLS_TEST_DEPRECATED */
+void ecp_write_key(int grp_id, data_t *in_key,
+                   int exported_size, int expected_ret)
+{
+    mbedtls_ecp_keypair key;
+    mbedtls_ecp_keypair_init(&key);
+    unsigned char *exported = NULL;
+
+    TEST_EQUAL(mbedtls_ecp_read_key(grp_id, &key, in_key->x, in_key->len), 0);
+
+    TEST_CALLOC(exported, exported_size);
+    TEST_EQUAL(mbedtls_ecp_write_key(&key, exported, exported_size),
+               expected_ret);
+
+    if (expected_ret == 0) {
+        size_t length = (key.grp.nbits + 7) / 8;
+        const unsigned char *key_start = NULL;
+        const unsigned char *zeros_start = NULL;
+        switch (mbedtls_ecp_get_type(&key.grp)) {
+            case MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS:
+                if ((size_t) exported_size < length) {
+                    length = exported_size;
+                }
+                key_start = exported + exported_size - length;
+                zeros_start = exported;
+                break;
+            case MBEDTLS_ECP_TYPE_MONTGOMERY:
+                TEST_LE_U(length, exported_size);
+                key_start = exported;
+                zeros_start = exported + length;
+                break;
+            default:
+                TEST_FAIL("Unknown ECP curve type");
+                break;
+        }
+
+        if (length < in_key->len) {
+            /* Shorter output (only possible with Weierstrass keys) */
+            for (size_t i = 0; i < in_key->len - length; i++) {
+                mbedtls_test_set_step(i);
+                TEST_EQUAL(in_key->x[i], 0);
+            }
+            TEST_MEMORY_COMPARE(in_key->x + in_key->len - length, length,
+                                key_start, length);
+        } else {
+            TEST_MEMORY_COMPARE(in_key->x, in_key->len,
+                                key_start, length);
+            for (size_t i = 0; i < exported_size - length; i++) {
+                mbedtls_test_set_step(i);
+                TEST_EQUAL(zeros_start[i], 0);
+            }
+        }
+    }
+
+exit:
+    mbedtls_ecp_keypair_free(&key);
+    mbedtls_free(exported);
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void ecp_write_key_ext(int grp_id, data_t *in_key,
+                       int exported_size, int expected_ret)
+{
+    mbedtls_ecp_keypair key;
+    mbedtls_ecp_keypair_init(&key);
+    unsigned char *exported = NULL;
+
+    if (in_key->len != 0) {
+        TEST_EQUAL(mbedtls_ecp_read_key(grp_id, &key, in_key->x, in_key->len), 0);
+    } else if (grp_id != MBEDTLS_ECP_DP_NONE) {
+        TEST_EQUAL(mbedtls_ecp_group_load(&key.grp, grp_id), 0);
+    }
+
+    TEST_CALLOC(exported, exported_size);
+    size_t olen = 0xdeadbeef;
+    TEST_EQUAL(mbedtls_ecp_write_key_ext(&key, &olen, exported, exported_size),
+               expected_ret);
+
+    if (expected_ret == 0) {
+        TEST_EQUAL(olen, (key.grp.nbits + 7) / 8);
+        TEST_LE_U(olen, MBEDTLS_ECP_MAX_BYTES);
+        TEST_MEMORY_COMPARE(in_key->x, in_key->len,
+                            exported, olen);
+    } else {
+        /* Robustness check: even in the error case, insist that olen is less
+         * than the buffer size. */
+        TEST_LE_U(olen, exported_size);
+    }
+
+exit:
+    mbedtls_ecp_keypair_free(&key);
+    mbedtls_free(exported);
+}
+/* END_CASE */
+
 /* BEGIN_CASE depends_on:MBEDTLS_TEST_HOOKS:MBEDTLS_ECP_MONTGOMERY_ENABLED:MBEDTLS_ECP_LIGHT */
 void genkey_mx_known_answer(int bits, data_t *seed, data_t *expected)
 {
diff --git a/tests/suites/test_suite_entropy.function b/tests/suites/test_suite_entropy.function
index ed9f3ac..5ac65fc 100644
--- a/tests/suites/test_suite_entropy.function
+++ b/tests/suites/test_suite_entropy.function
@@ -447,7 +447,7 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE depends_on:MBEDTLS_MD_C:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_PLATFORM_NV_SEED_ALT */
+/* BEGIN_CASE depends_on:MBEDTLS_MD_LIGHT:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_PLATFORM_NV_SEED_ALT */
 void entropy_nv_seed(data_t *read_seed)
 {
 #if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR)
diff --git a/tests/suites/test_suite_pem.data b/tests/suites/test_suite_pem.data
index a4dff45..007ba10 100644
--- a/tests/suites/test_suite_pem.data
+++ b/tests/suites/test_suite_pem.data
@@ -22,6 +22,9 @@
 PEM read (unencrypted, valid)
 mbedtls_pem_read_buffer:"^":"$":"^\nTWJlZCBUTFM=\n$":"":0:"4d62656420544c53"
 
+PEM read (unencrypted, empty content)
+mbedtls_pem_read_buffer:"-----BEGIN EC PRIVATE KEY-----":"-----END EC PRIVATE KEY-----":"-----BEGIN EC PRIVATE KEY-----\n\n-----END EC PRIVATE KEY-----":"":MBEDTLS_ERR_PEM_BAD_INPUT_DATA:""
+
 PEM read (DES-EDE3-CBC + invalid iv)
 depends_on:MBEDTLS_MD_CAN_MD5:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_DES_C
 mbedtls_pem_read_buffer:"^":"$":"^\nProc-Type\: 4,ENCRYPTED\nDEK-Info\: DES-EDE3-CBC,00$":"pwd":MBEDTLS_ERR_PEM_INVALID_ENC_IV:""
@@ -49,3 +52,35 @@
 PEM read (malformed PEM AES-128-CBC)
 depends_on:MBEDTLS_MD_CAN_MD5:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC
 mbedtls_pem_read_buffer:"-----BEGIN EC PRIVATE KEY-----":"-----END EC PRIVATE KEY-----":"-----BEGIN EC PRIVATE KEY-----\nProc-Type\: 4,ENCRYPTED\nDEK-Info\: AES-128-CBC,AA94892A169FA426AA94892A169FA426\n\nMAAA\n-----END EC PRIVATE KEY-----":"pwd":MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH:""
+
+# The output sequence's length is not multiple of block size (16 bytes). This
+# proves that the pem_context->len value is properly updated based on the SEQUENCE
+# length read from the decoded ASN.1 data (i.e. extra padding, if any, is ignored).
+PEM read (valid EC key encoded with AES-128-CBC)
+depends_on:MBEDTLS_MD_CAN_MD5:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC
+mbedtls_pem_read_buffer:"-----BEGIN EC PRIVATE KEY-----":"-----END EC PRIVATE KEY-----":"-----BEGIN EC PRIVATE KEY-----\nProc-Type\: 4,ENCRYPTED\nDEK-Info\: AES-128-CBC,151F851B6A7F3FBDAA5B7173117D0127\n\nLw+0OM+0Bwcl+ls/vxQbLrVshGc7bsNPvvtj2sJeMFFEq3V1mj/IO++0KK/CDhMH\nh6CZPsmgVOeM5uFpqYaq0fJbUduN2eDMWszWRm0SFkY=\n-----END EC PRIVATE KEY-----":"pwdpwd":0:"3041020101040f00d8023c809afd45e426d1a4dbe0ffa00706052b81040004a1220320000400da1ecfa53d528237625e119e2e0500d2eb671724f16deb6a63749516b7"
+
+# The text "hello world" together with some invalid padding data is encoded
+# with AES-128-CBC in order to test padding validation.
+# Since PBKDF1 isn't supported in OpenSSL, here's the steps:
+# 1. generate the key (password="password";  IV=0x3132333435363738 in hex or "12345678" as string)
+#       echo -n "password12345678" | openssl md5
+# 2. encode data
+#   echo -n -e "\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x01\x02\x03\x04\x05" | openssl aes-128-cbc -e -base64 -p -K "bbb0ddff1b944b3cc68eaaeb7ac20099" -iv "3132333435363738" -nopad
+PEM read (AES-128-CBC, invalid padding data)
+depends_on:MBEDTLS_MD_CAN_MD5:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC
+mbedtls_pem_read_buffer:"-----BEGIN EC PRIVATE KEY-----":"-----END EC PRIVATE KEY-----":"-----BEGIN EC PRIVATE KEY-----\nProc-Type\: 4,ENCRYPTED\nDEK-Info\: AES-128-CBC,31323334353637380000000000000000\n\n333hxynfxEdXrSHQfIabxQ==\n-----END EC PRIVATE KEY-----":"password":MBEDTLS_ERR_PEM_PASSWORD_MISMATCH:""
+
+# Padding data (0x11) is larger than AES block size (16).
+# Generated with:
+#   echo -n -e "\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x11\x11\x11\x11\x11" | openssl aes-128-cbc -e -base64 -p -K "bbb0ddff1b944b3cc68eaaeb7ac20099" -iv "3132333435363738" -nopad
+PEM read (AES-128-CBC, padding data is larger than AES block length)
+depends_on:MBEDTLS_MD_CAN_MD5:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC
+mbedtls_pem_read_buffer:"-----BEGIN EC PRIVATE KEY-----":"-----END EC PRIVATE KEY-----":"-----BEGIN EC PRIVATE KEY-----\nProc-Type\: 4,ENCRYPTED\nDEK-Info\: AES-128-CBC,31323334353637380000000000000000\n\n5wA/XVXHuMsQAAOGFQmK0g==\n-----END EC PRIVATE KEY-----":"password":MBEDTLS_ERR_PEM_PASSWORD_MISMATCH:""
+
+# Padding data (0x9) is larger than DES block size (8).
+# Generated with:
+#   echo -n -e "\x68\x65\x6c\x6c\x6f\x09\x09\x09" | openssl des-cbc -e -base64 -p -K "bbb0ddff1b944b3cc68eaaeb7ac20099" -iv "3132333435363738" -nopad
+PEM read (DES-CBC, padding data is larger than DES block length)
+depends_on:MBEDTLS_MD_CAN_MD5:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC
+mbedtls_pem_read_buffer:"-----BEGIN EC PRIVATE KEY-----":"-----END EC PRIVATE KEY-----":"-----BEGIN EC PRIVATE KEY-----\nProc-Type\: 4,ENCRYPTED\nDEK-Info\: DES-CBC,3132333435363738\n\n6a+B2WineBM=\n-----END EC PRIVATE KEY-----":"password":MBEDTLS_ERR_PEM_PASSWORD_MISMATCH:""
diff --git a/tests/suites/test_suite_pk.data b/tests/suites/test_suite_pk.data
index 3414958..989235d 100644
--- a/tests/suites/test_suite_pk.data
+++ b/tests/suites/test_suite_pk.data
@@ -10,7 +10,21 @@
 
 PK utils: RSA Minimum key
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME
-pk_utils:MBEDTLS_PK_RSA:MBEDTLS_RSA_GEN_KEY_MIN_BITS:MBEDTLS_RSA_GEN_KEY_MIN_BITS:(MBEDTLS_RSA_GEN_KEY_MIN_BITS /8):"RSA"
+pk_utils:MBEDTLS_PK_RSA:MBEDTLS_RSA_GEN_KEY_MIN_BITS:MBEDTLS_RSA_GEN_KEY_MIN_BITS:(MBEDTLS_RSA_GEN_KEY_MIN_BITS + 7) / 8:"RSA"
+
+# mbedtls_rsa_gen_key() only supports even sizes, so we don't test min+1,
+# min+3, etc.
+PK utils: RSA Minimum key + 2 bits
+depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME
+pk_utils:MBEDTLS_PK_RSA:MBEDTLS_RSA_GEN_KEY_MIN_BITS + 2:MBEDTLS_RSA_GEN_KEY_MIN_BITS + 2:(MBEDTLS_RSA_GEN_KEY_MIN_BITS + 2 + 7) / 8:"RSA"
+
+PK utils: RSA Minimum key + 4 bits
+depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME
+pk_utils:MBEDTLS_PK_RSA:MBEDTLS_RSA_GEN_KEY_MIN_BITS + 4:MBEDTLS_RSA_GEN_KEY_MIN_BITS + 4:(MBEDTLS_RSA_GEN_KEY_MIN_BITS + 4 + 7) / 8:"RSA"
+
+PK utils: RSA Minimum key + 6 bits
+depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME
+pk_utils:MBEDTLS_PK_RSA:MBEDTLS_RSA_GEN_KEY_MIN_BITS + 6:MBEDTLS_RSA_GEN_KEY_MIN_BITS + 6:(MBEDTLS_RSA_GEN_KEY_MIN_BITS + 6 + 7) / 8:"RSA"
 
 PK utils: ECKEY SECP192R1
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_ECP_HAVE_SECP192R1
@@ -312,13 +326,33 @@
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME
 pk_can_do_ext:0:MBEDTLS_PK_RSA:0:0:0:1024:PSA_ALG_RSA_PSS(PSA_ALG_SHA_256):PSA_KEY_USAGE_SIGN_HASH:1
 
-RSA verify test vector #1 (good)
+RSA verify test vector: PKCS1v1.5 (explicit), SHA1, good
 depends_on:MBEDTLS_MD_CAN_SHA1:MBEDTLS_PKCS1_V15
-pk_rsa_verify_test_vec:"6a8a1f225703fe39753c1017b43eec9e070a70b1":MBEDTLS_MD_SHA1:1024:"e28a13548525e5f36dccb24ecb7cc332cc689dfd64012604c9c7816d72a16c3f5fcdc0e86e7c03280b1c69b586ce0cd8aec722cc73a5d3b730310bf7dfebdc77ce5d94bbc369dc18a2f7b07bd505ab0f82224aef09fdc1e5063234255e0b3c40a52e9e8ae60898eb88a766bdd788fe9493d8fd86bcdd2884d5c06216c65469e5":"3":"5abc01f5de25b70867ff0c24e222c61f53c88daf42586fddcd56f3c4588f074be3c328056c063388688b6385a8167957c6e5355a510e005b8a851d69c96b36ec6036644078210e5d7d326f96365ee0648882921492bc7b753eb9c26cdbab37555f210df2ca6fec1b25b463d38b81c0dcea202022b04af5da58aa03d77be949b7":0
+pk_rsa_verify_test_vec:"6a8a1f225703fe39753c1017b43eec9e070a70b1":MBEDTLS_RSA_PKCS_V15:MBEDTLS_MD_SHA1:1024:"e28a13548525e5f36dccb24ecb7cc332cc689dfd64012604c9c7816d72a16c3f5fcdc0e86e7c03280b1c69b586ce0cd8aec722cc73a5d3b730310bf7dfebdc77ce5d94bbc369dc18a2f7b07bd505ab0f82224aef09fdc1e5063234255e0b3c40a52e9e8ae60898eb88a766bdd788fe9493d8fd86bcdd2884d5c06216c65469e5":"3":"5abc01f5de25b70867ff0c24e222c61f53c88daf42586fddcd56f3c4588f074be3c328056c063388688b6385a8167957c6e5355a510e005b8a851d69c96b36ec6036644078210e5d7d326f96365ee0648882921492bc7b753eb9c26cdbab37555f210df2ca6fec1b25b463d38b81c0dcea202022b04af5da58aa03d77be949b7":0
 
-RSA verify test vector #2 (bad)
+RSA verify test vector: PKCS1v1.5 (default), SHA1, good
 depends_on:MBEDTLS_MD_CAN_SHA1:MBEDTLS_PKCS1_V15
-pk_rsa_verify_test_vec:"9f294f0c7b32da6221a3ef83654322038e8968fa":MBEDTLS_MD_SHA1:1024:"e28a13548525e5f36dccb24ecb7cc332cc689dfd64012604c9c7816d72a16c3f5fcdc0e86e7c03280b1c69b586ce0cd8aec722cc73a5d3b730310bf7dfebdc77ce5d94bbc369dc18a2f7b07bd505ab0f82224aef09fdc1e5063234255e0b3c40a52e9e8ae60898eb88a766bdd788fe9493d8fd86bcdd2884d5c06216c65469e5":"3":"3203b7647fb7e345aa457681e5131777f1adc371f2fba8534928c4e52ef6206a856425d6269352ecbf64db2f6ad82397768cafdd8cd272e512d617ad67992226da6bc291c31404c17fd4b7e2beb20eff284a44f4d7af47fd6629e2c95809fa7f2241a04f70ac70d3271bb13258af1ed5c5988c95df7fa26603515791075feccd":MBEDTLS_ERR_RSA_VERIFY_FAILED
+pk_rsa_verify_test_vec:"6a8a1f225703fe39753c1017b43eec9e070a70b1":-1:MBEDTLS_MD_SHA1:1024:"e28a13548525e5f36dccb24ecb7cc332cc689dfd64012604c9c7816d72a16c3f5fcdc0e86e7c03280b1c69b586ce0cd8aec722cc73a5d3b730310bf7dfebdc77ce5d94bbc369dc18a2f7b07bd505ab0f82224aef09fdc1e5063234255e0b3c40a52e9e8ae60898eb88a766bdd788fe9493d8fd86bcdd2884d5c06216c65469e5":"3":"5abc01f5de25b70867ff0c24e222c61f53c88daf42586fddcd56f3c4588f074be3c328056c063388688b6385a8167957c6e5355a510e005b8a851d69c96b36ec6036644078210e5d7d326f96365ee0648882921492bc7b753eb9c26cdbab37555f210df2ca6fec1b25b463d38b81c0dcea202022b04af5da58aa03d77be949b7":0
+
+RSA verify test vector: PKCS1v1.5, SHA1, wrong signature
+depends_on:MBEDTLS_MD_CAN_SHA1:MBEDTLS_PKCS1_V15
+pk_rsa_verify_test_vec:"6a8a1f225703fe39753c1017b43eec9e070a70b1":MBEDTLS_RSA_PKCS_V15:MBEDTLS_MD_SHA1:1024:"e28a13548525e5f36dccb24ecb7cc332cc689dfd64012604c9c7816d72a16c3f5fcdc0e86e7c03280b1c69b586ce0cd8aec722cc73a5d3b730310bf7dfebdc77ce5d94bbc369dc18a2f7b07bd505ab0f82224aef09fdc1e5063234255e0b3c40a52e9e8ae60898eb88a766bdd788fe9493d8fd86bcdd2884d5c06216c65469e5":"3":"5abc01f5de25b70867ff0c24e222c61f53c88daf42586fddcd56f3c4588f074be3c328056c063388688b6385a8167957c6e5355a510e005b8a851d69c96b36ec6036644078210e5d7d326f96365ee0648882921492bc7b753eb9c26cdbab37555f210df2ca6fec1b25b463d38b81c0dcea202022b04af5da58aa03d77be949b8":MBEDTLS_ERR_RSA_VERIFY_FAILED
+
+RSA verify test vector: PSS, SHA1, good
+depends_on:MBEDTLS_MD_CAN_SHA1:MBEDTLS_PKCS1_V21
+pk_rsa_verify_test_vec:"37b66ae0445843353d47ecb0b4fd14c110e62d6a":MBEDTLS_RSA_PKCS_V21:MBEDTLS_MD_SHA1:1024:"a2ba40ee07e3b2bd2f02ce227f36a195024486e49c19cb41bbbdfbba98b22b0e577c2eeaffa20d883a76e65e394c69d4b3c05a1e8fadda27edb2a42bc000fe888b9b32c22d15add0cd76b3e7936e19955b220dd17d4ea904b1ec102b2e4de7751222aa99151024c7cb41cc5ea21d00eeb41f7c800834d2c6e06bce3bce7ea9a5":"010001":"8daa627d3de7595d63056c7ec659e54406f10610128baae821c8b2a0f3936d54dc3bdce46689f6b7951bb18e840542769718d5715d210d85efbb596192032c42be4c29972c856275eb6d5a45f05f51876fc6743deddd28caec9bb30ea99e02c3488269604fe497f74ccd7c7fca1671897123cbd30def5d54a2b5536ad90a747e":0
+
+RSA verify test vector: PSS, SHA1, wrong signature
+depends_on:MBEDTLS_MD_CAN_SHA1:MBEDTLS_PKCS1_V21
+pk_rsa_verify_test_vec:"37b66ae0445843353d47ecb0b4fd14c110e62d6a":MBEDTLS_RSA_PKCS_V21:MBEDTLS_MD_SHA1:1024:"a2ba40ee07e3b2bd2f02ce227f36a195024486e49c19cb41bbbdfbba98b22b0e577c2eeaffa20d883a76e65e394c69d4b3c05a1e8fadda27edb2a42bc000fe888b9b32c22d15add0cd76b3e7936e19955b220dd17d4ea904b1ec102b2e4de7751222aa99151024c7cb41cc5ea21d00eeb41f7c800834d2c6e06bce3bce7ea9a5":"010001":"8daa627d3de7595d63056c7ec659e54406f10610128baae821c8b2a0f3936d54dc3bdce46689f6b7951bb18e840542769718d5715d210d85efbb596192032c42be4c29972c856275eb6d5a45f05f51876fc6743deddd28caec9bb30ea99e02c3488269604fe497f74ccd7c7fca1671897123cbd30def5d54a2b5536ad90a747f":MBEDTLS_ERR_RSA_VERIFY_FAILED
+
+RSA verify test vector: PSS, SHA1, signature is PKCS1v1.5
+depends_on:MBEDTLS_MD_CAN_SHA1:MBEDTLS_PKCS1_V21
+pk_rsa_verify_test_vec:"6a8a1f225703fe39753c1017b43eec9e070a70b1":MBEDTLS_RSA_PKCS_V21:MBEDTLS_MD_SHA1:1024:"e28a13548525e5f36dccb24ecb7cc332cc689dfd64012604c9c7816d72a16c3f5fcdc0e86e7c03280b1c69b586ce0cd8aec722cc73a5d3b730310bf7dfebdc77ce5d94bbc369dc18a2f7b07bd505ab0f82224aef09fdc1e5063234255e0b3c40a52e9e8ae60898eb88a766bdd788fe9493d8fd86bcdd2884d5c06216c65469e5":"3":"5abc01f5de25b70867ff0c24e222c61f53c88daf42586fddcd56f3c4588f074be3c328056c063388688b6385a8167957c6e5355a510e005b8a851d69c96b36ec6036644078210e5d7d326f96365ee0648882921492bc7b753eb9c26cdbab37555f210df2ca6fec1b25b463d38b81c0dcea202022b04af5da58aa03d77be949b7":MBEDTLS_ERR_RSA_VERIFY_FAILED
+
+RSA verify test vector: PKCS1v1.5, SHA1, signature is PSS
+depends_on:MBEDTLS_MD_CAN_SHA1:MBEDTLS_PKCS1_V15
+pk_rsa_verify_test_vec:"37b66ae0445843353d47ecb0b4fd14c110e62d6a":MBEDTLS_RSA_PKCS_V15:MBEDTLS_MD_SHA1:1024:"a2ba40ee07e3b2bd2f02ce227f36a195024486e49c19cb41bbbdfbba98b22b0e577c2eeaffa20d883a76e65e394c69d4b3c05a1e8fadda27edb2a42bc000fe888b9b32c22d15add0cd76b3e7936e19955b220dd17d4ea904b1ec102b2e4de7751222aa99151024c7cb41cc5ea21d00eeb41f7c800834d2c6e06bce3bce7ea9a5":"010001":"8daa627d3de7595d63056c7ec659e54406f10610128baae821c8b2a0f3936d54dc3bdce46689f6b7951bb18e840542769718d5715d210d85efbb596192032c42be4c29972c856275eb6d5a45f05f51876fc6743deddd28caec9bb30ea99e02c3488269604fe497f74ccd7c7fca1671897123cbd30def5d54a2b5536ad90a747e":MBEDTLS_ERR_RSA_VERIFY_FAILED
 
 ECDSA verify test vector #1 (good)
 depends_on:MBEDTLS_ECP_HAVE_SECP192R1
@@ -370,51 +404,79 @@
 
 ECDSA sign-verify: SECP192R1
 depends_on:MBEDTLS_PK_CAN_ECDSA_VERIFY:MBEDTLS_PK_CAN_ECDSA_SIGN:MBEDTLS_ECP_HAVE_SECP192R1
-pk_sign_verify:MBEDTLS_PK_ECDSA:MBEDTLS_ECP_DP_SECP192R1:0:0
+pk_sign_verify:MBEDTLS_PK_ECDSA:MBEDTLS_ECP_DP_SECP192R1:0:0:0:0
 
 ECDSA sign-verify: SECP256R1
 depends_on:MBEDTLS_PK_CAN_ECDSA_VERIFY:MBEDTLS_PK_CAN_ECDSA_SIGN:MBEDTLS_ECP_HAVE_SECP256R1
-pk_sign_verify:MBEDTLS_PK_ECDSA:MBEDTLS_ECP_DP_SECP256R1:0:0
+pk_sign_verify:MBEDTLS_PK_ECDSA:MBEDTLS_ECP_DP_SECP256R1:0:0:0:0
 
 ECDSA sign-verify: SECP384R1
 depends_on:MBEDTLS_PK_CAN_ECDSA_VERIFY:MBEDTLS_PK_CAN_ECDSA_SIGN:MBEDTLS_ECP_HAVE_SECP384R1
-pk_sign_verify:MBEDTLS_PK_ECDSA:MBEDTLS_ECP_DP_SECP384R1:0:0
+pk_sign_verify:MBEDTLS_PK_ECDSA:MBEDTLS_ECP_DP_SECP384R1:0:0:0:0
 
 ECDSA sign-verify: SECP521R1
 depends_on:MBEDTLS_PK_CAN_ECDSA_VERIFY:MBEDTLS_PK_CAN_ECDSA_SIGN:MBEDTLS_ECP_HAVE_SECP521R1
-pk_sign_verify:MBEDTLS_PK_ECDSA:MBEDTLS_ECP_DP_SECP521R1:0:0
+pk_sign_verify:MBEDTLS_PK_ECDSA:MBEDTLS_ECP_DP_SECP521R1:0:0:0:0
 
 ECDSA sign-verify: BP256R1
 depends_on:MBEDTLS_PK_CAN_ECDSA_VERIFY:MBEDTLS_ECP_HAVE_BP256R1
-pk_sign_verify:MBEDTLS_PK_ECDSA:MBEDTLS_ECP_DP_BP256R1:0:0
+pk_sign_verify:MBEDTLS_PK_ECDSA:MBEDTLS_ECP_DP_BP256R1:0:0:0:0
 
 ECDSA sign-verify: BP512R1
 depends_on:MBEDTLS_PK_CAN_ECDSA_VERIFY:MBEDTLS_ECP_HAVE_BP512R1
-pk_sign_verify:MBEDTLS_PK_ECDSA:MBEDTLS_ECP_DP_BP512R1:0:0
+pk_sign_verify:MBEDTLS_PK_ECDSA:MBEDTLS_ECP_DP_BP512R1:0:0:0:0
 
 EC(DSA) sign-verify: SECP192R1
 depends_on:MBEDTLS_PK_CAN_ECDSA_VERIFY:MBEDTLS_PK_CAN_ECDSA_SIGN:MBEDTLS_ECP_HAVE_SECP192R1
-pk_sign_verify:MBEDTLS_PK_ECKEY:MBEDTLS_ECP_DP_SECP192R1:0:0
+pk_sign_verify:MBEDTLS_PK_ECKEY:MBEDTLS_ECP_DP_SECP192R1:0:0:0:0
 
 EC_DH (no) sign-verify: SECP192R1
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_ECP_HAVE_SECP192R1
-pk_sign_verify:MBEDTLS_PK_ECKEY_DH:MBEDTLS_ECP_DP_SECP192R1:MBEDTLS_ERR_PK_TYPE_MISMATCH:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_sign_verify:MBEDTLS_PK_ECKEY_DH:MBEDTLS_ECP_DP_SECP192R1:0:0:MBEDTLS_ERR_PK_TYPE_MISMATCH:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
-RSA sign-verify
-depends_on:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_GENPRIME:MBEDTLS_RSA_GEN_KEY_MIN_BITS >= 512
-pk_sign_verify:MBEDTLS_PK_RSA:MBEDTLS_RSA_GEN_KEY_MIN_BITS:0:0
+RSA sign-verify, PKCS1v1.5, SHA1
+depends_on:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_GENPRIME:MBEDTLS_RSA_GEN_KEY_MIN_BITS >= 512:MBEDTLS_MD_CAN_SHA1
+pk_sign_verify:MBEDTLS_PK_RSA:MBEDTLS_RSA_GEN_KEY_MIN_BITS:MBEDTLS_RSA_PKCS_V15:MBEDTLS_MD_SHA1:0:0
+
+RSA sign-verify, PKCS1v2.1, SHA1
+depends_on:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V21:MBEDTLS_GENPRIME:MBEDTLS_RSA_GEN_KEY_MIN_BITS >= 512:MBEDTLS_MD_CAN_SHA1
+pk_sign_verify:MBEDTLS_PK_RSA:MBEDTLS_RSA_GEN_KEY_MIN_BITS:MBEDTLS_RSA_PKCS_V21:MBEDTLS_MD_SHA1:0:0
+
+RSA sign-verify, PKCS1v1.5, SHA256
+depends_on:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_GENPRIME:MBEDTLS_RSA_GEN_KEY_MIN_BITS >= 512:MBEDTLS_MD_CAN_SHA256
+pk_sign_verify:MBEDTLS_PK_RSA:MBEDTLS_RSA_GEN_KEY_MIN_BITS:MBEDTLS_RSA_PKCS_V15:MBEDTLS_MD_SHA256:0:0
+
+RSA sign-verify, PKCS1v2.1, SHA256
+depends_on:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V21:MBEDTLS_GENPRIME:MBEDTLS_RSA_GEN_KEY_MIN_BITS >= 512:MBEDTLS_MD_CAN_SHA256
+pk_sign_verify:MBEDTLS_PK_RSA:MBEDTLS_RSA_GEN_KEY_MIN_BITS:MBEDTLS_RSA_PKCS_V21:MBEDTLS_MD_SHA256:0:0
 
 RSA encrypt-decrypt test
 depends_on:MBEDTLS_PKCS1_V15
 pk_rsa_encrypt_decrypt_test:"4E636AF98E40F3ADCFCCB698F4E80B9F":2048:"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"3":0
 
-RSA decrypt test vector #1
+RSA decrypt test vector - PKCS1v1.5
 depends_on:MBEDTLS_PKCS1_V15
-pk_rsa_decrypt_test_vec:"a42eda41e56235e666e7faaa77100197f657288a1bf183e4820f0c37ce2c456b960278d6003e0bbcd4be4a969f8e8fd9231e1f492414f00ed09844994c86ec32db7cde3bec7f0c3dbf6ae55baeb2712fa609f5fc3207a824eb3dace31849cd6a6084318523912bccb84cf42e3c6d6d1685131d69bb545acec827d2b0dfdd5568b7dcc4f5a11d6916583fefa689d367f8c9e1d95dcd2240895a9470b0c1730f97cd6e8546860bd254801769f54be96e16362ddcbf34d56035028890199e0f48db38642cb66a4181e028a6443a404fea284ce02b4614b683367d40874e505611d23142d49f06feea831d52d347b13610b413c4efc43a6de9f0b08d2a951dc503b6":2048:"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"3":"4E636AF98E40F3ADCFCCB698F4E80B9F":0
+pk_rsa_decrypt_test_vec:"28818cb14236ad18f4527e7f1f7633e96cef021bc3234475d7f61e88702b6335b42a352ed3f3267ac7c3e9ba4af17e45096c63eefd8d9a7cb42dfc52fffb2f5b8afb305b46312c2eb50634123b4437a2287ac57b7509d59a583fb741989a49f32625e9267b4641a6607b7303d35c68489db53c8d387b620d0d46a852e72ea43c":1024:MBEDTLS_RSA_PKCS_V15:MBEDTLS_MD_NONE:"eecfae81b1b9b3c908810b10a1b5600199eb9f44aef4fda493b81a9e3d84f632124ef0236e5d1e3b7e28fae7aa040a2d5b252176459d1f397541ba2a58fb6599":"c97fb1f027f453f6341233eaaad1d9353f6c42d08866b1d05a0f2035028b9d869840b41666b42e92ea0da3b43204b5cfce3352524d0416a5a441e700af461503":"bbf82f090682ce9c2338ac2b9da871f7368d07eed41043a440d6b6f07454f51fb8dfbaaf035c02ab61ea48ceeb6fcd4876ed520d60e1ec4619719d8a5b8b807fafb8e0a3dfc737723ee6b4b7d93a2584ee6a649d060953748834b2454598394ee0aab12d7b61a51f527a9a41f6c1687fe2537298ca2a8f5946f8e5fd091dbdcb":"11":"d436e99569fd32a7c8a05bbc90d32c49":0
 
-RSA decrypt test vector #2
+RSA decrypt test vector - PKCS1v1.5, corrupted encrypted data
 depends_on:MBEDTLS_PKCS1_V15
-pk_rsa_decrypt_test_vec:"a42eda41e56235e666e7faaa77100197f657288a1bf183e4820f0c37ce2c456b960278d6003e0bbcd4be4a969f8e8fd9231e1f492414f00ed09844994c86ec32db7cde3bec7f0c3dbf6ae55baeb2712fa609f5fc3207a824eb3dace31849cd6a6084318523912bccb84cf42e3c6d6d1685131d69bb545acec827d2b0dfdd5568b7dcc4f5a11d6916583fefa689d367f8c9e1d95dcd2240895a9470b0c1730f97cd6e8546860bd254801769f54be96e16362ddcbf34d56035028890199e0f48db38642cb66a4181e028a6443a404feb284ce02b4614b683367d40874e505611d23142d49f06feea831d52d347b13610b413c4efc43a6de9f0b08d2a951dc503b6":2048:"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"3":"4E636AF98E40F3ADCFCCB698F4E80B9F":MBEDTLS_ERR_RSA_INVALID_PADDING
+pk_rsa_decrypt_test_vec:"28818cb14236ad18f4527e7f1f7633e96cef021bc3234475d7f61e88702b6335b42a352ed3f3267ac7c3e9ba4af17e45096c63eefd8d9a7cb42dfc52fffb2f5b8afb305b46312c2eb50634123b4437a2287ac57b7509d59a583fb741989a49f32625e9267b4641a6607b7303d35c68489db53c8d387b620d0d46a852e72ea43d":1024:MBEDTLS_RSA_PKCS_V15:MBEDTLS_MD_NONE:"eecfae81b1b9b3c908810b10a1b5600199eb9f44aef4fda493b81a9e3d84f632124ef0236e5d1e3b7e28fae7aa040a2d5b252176459d1f397541ba2a58fb6599":"c97fb1f027f453f6341233eaaad1d9353f6c42d08866b1d05a0f2035028b9d869840b41666b42e92ea0da3b43204b5cfce3352524d0416a5a441e700af461503":"bbf82f090682ce9c2338ac2b9da871f7368d07eed41043a440d6b6f07454f51fb8dfbaaf035c02ab61ea48ceeb6fcd4876ed520d60e1ec4619719d8a5b8b807fafb8e0a3dfc737723ee6b4b7d93a2584ee6a649d060953748834b2454598394ee0aab12d7b61a51f527a9a41f6c1687fe2537298ca2a8f5946f8e5fd091dbdcb":"11":"d436e99569fd32a7c8a05bbc90d32c49":MBEDTLS_ERR_RSA_INVALID_PADDING
+
+RSA decrypt test vector - PKCS1v2.1
+depends_on:MBEDTLS_PKCS1_V21:MBEDTLS_MD_CAN_SHA1
+pk_rsa_decrypt_test_vec:"1253e04dc0a5397bb44a7ab87e9bf2a039a33d1e996fc82a94ccd30074c95df763722017069e5268da5d1c0b4f872cf653c11df82314a67968dfeae28def04bb6d84b1c31d654a1970e5783bd6eb96a024c2ca2f4a90fe9f2ef5c9c140e5bb48da9536ad8700c84fc9130adea74e558d51a74ddf85d8b50de96838d6063e0955":1024:MBEDTLS_RSA_PKCS_V21:MBEDTLS_MD_SHA1:"eecfae81b1b9b3c908810b10a1b5600199eb9f44aef4fda493b81a9e3d84f632124ef0236e5d1e3b7e28fae7aa040a2d5b252176459d1f397541ba2a58fb6599":"c97fb1f027f453f6341233eaaad1d9353f6c42d08866b1d05a0f2035028b9d869840b41666b42e92ea0da3b43204b5cfce3352524d0416a5a441e700af461503":"bbf82f090682ce9c2338ac2b9da871f7368d07eed41043a440d6b6f07454f51fb8dfbaaf035c02ab61ea48ceeb6fcd4876ed520d60e1ec4619719d8a5b8b807fafb8e0a3dfc737723ee6b4b7d93a2584ee6a649d060953748834b2454598394ee0aab12d7b61a51f527a9a41f6c1687fe2537298ca2a8f5946f8e5fd091dbdcb":"11":"d436e99569fd32a7c8a05bbc90d32c49":0
+
+RSA decrypt test vector - PKCS1v2.1, corrupted encrypted data
+depends_on:MBEDTLS_PKCS1_V21:MBEDTLS_MD_CAN_SHA1
+pk_rsa_decrypt_test_vec:"1253e04dc0a5397bb44a7ab87e9bf2a039a33d1e996fc82a94ccd30074c95df763722017069e5268da5d1c0b4f872cf653c11df82314a67968dfeae28def04bb6d84b1c31d654a1970e5783bd6eb96a024c2ca2f4a90fe9f2ef5c9c140e5bb48da9536ad8700c84fc9130adea74e558d51a74ddf85d8b50de96838d6063e0956":1024:MBEDTLS_RSA_PKCS_V21:MBEDTLS_MD_SHA1:"eecfae81b1b9b3c908810b10a1b5600199eb9f44aef4fda493b81a9e3d84f632124ef0236e5d1e3b7e28fae7aa040a2d5b252176459d1f397541ba2a58fb6599":"c97fb1f027f453f6341233eaaad1d9353f6c42d08866b1d05a0f2035028b9d869840b41666b42e92ea0da3b43204b5cfce3352524d0416a5a441e700af461503":"bbf82f090682ce9c2338ac2b9da871f7368d07eed41043a440d6b6f07454f51fb8dfbaaf035c02ab61ea48ceeb6fcd4876ed520d60e1ec4619719d8a5b8b807fafb8e0a3dfc737723ee6b4b7d93a2584ee6a649d060953748834b2454598394ee0aab12d7b61a51f527a9a41f6c1687fe2537298ca2a8f5946f8e5fd091dbdcb":"11":"d436e99569fd32a7c8a05bbc90d32c49":MBEDTLS_ERR_RSA_INVALID_PADDING
+
+RSA decrypt test vector - PKCS1v1.5, but data is PKCS1v2.1 encrypted
+depends_on:MBEDTLS_PKCS1_V15
+pk_rsa_decrypt_test_vec:"1253e04dc0a5397bb44a7ab87e9bf2a039a33d1e996fc82a94ccd30074c95df763722017069e5268da5d1c0b4f872cf653c11df82314a67968dfeae28def04bb6d84b1c31d654a1970e5783bd6eb96a024c2ca2f4a90fe9f2ef5c9c140e5bb48da9536ad8700c84fc9130adea74e558d51a74ddf85d8b50de96838d6063e0955":1024:MBEDTLS_RSA_PKCS_V15:MBEDTLS_MD_NONE:"eecfae81b1b9b3c908810b10a1b5600199eb9f44aef4fda493b81a9e3d84f632124ef0236e5d1e3b7e28fae7aa040a2d5b252176459d1f397541ba2a58fb6599":"c97fb1f027f453f6341233eaaad1d9353f6c42d08866b1d05a0f2035028b9d869840b41666b42e92ea0da3b43204b5cfce3352524d0416a5a441e700af461503":"bbf82f090682ce9c2338ac2b9da871f7368d07eed41043a440d6b6f07454f51fb8dfbaaf035c02ab61ea48ceeb6fcd4876ed520d60e1ec4619719d8a5b8b807fafb8e0a3dfc737723ee6b4b7d93a2584ee6a649d060953748834b2454598394ee0aab12d7b61a51f527a9a41f6c1687fe2537298ca2a8f5946f8e5fd091dbdcb":"11":"d436e99569fd32a7c8a05bbc90d32c49":MBEDTLS_ERR_RSA_INVALID_PADDING
+
+RSA decrypt test vector - PKCS1v2.1, but data is PKCS1v1.5 encrypted
+depends_on:MBEDTLS_PKCS1_V21:MBEDTLS_MD_CAN_SHA1
+pk_rsa_decrypt_test_vec:"28818cb14236ad18f4527e7f1f7633e96cef021bc3234475d7f61e88702b6335b42a352ed3f3267ac7c3e9ba4af17e45096c63eefd8d9a7cb42dfc52fffb2f5b8afb305b46312c2eb50634123b4437a2287ac57b7509d59a583fb741989a49f32625e9267b4641a6607b7303d35c68489db53c8d387b620d0d46a852e72ea43c":1024:MBEDTLS_RSA_PKCS_V21:MBEDTLS_MD_SHA1:"eecfae81b1b9b3c908810b10a1b5600199eb9f44aef4fda493b81a9e3d84f632124ef0236e5d1e3b7e28fae7aa040a2d5b252176459d1f397541ba2a58fb6599":"c97fb1f027f453f6341233eaaad1d9353f6c42d08866b1d05a0f2035028b9d869840b41666b42e92ea0da3b43204b5cfce3352524d0416a5a441e700af461503":"bbf82f090682ce9c2338ac2b9da871f7368d07eed41043a440d6b6f07454f51fb8dfbaaf035c02ab61ea48ceeb6fcd4876ed520d60e1ec4619719d8a5b8b807fafb8e0a3dfc737723ee6b4b7d93a2584ee6a649d060953748834b2454598394ee0aab12d7b61a51f527a9a41f6c1687fe2537298ca2a8f5946f8e5fd091dbdcb":"11":"d436e99569fd32a7c8a05bbc90d32c49":MBEDTLS_ERR_RSA_INVALID_PADDING
 
 RSA Opaque decrypt test vector #1
 depends_on:MBEDTLS_PKCS1_V15
@@ -682,311 +744,311 @@
 pk_psa_wrap_sign_ext:MBEDTLS_PK_RSA:2048:MBEDTLS_PK_RSASSA_PSS:MBEDTLS_MD_SHA512
 
 PSA attributes for pk: NONE (bad)
-pk_get_psa_attributes_fail:MBEDTLS_PK_NONE:0:PSA_KEY_USAGE_SIGN_MESSAGE:MBEDTLS_ERR_PK_BAD_INPUT_DATA
+pk_get_psa_attributes_fail:MBEDTLS_PK_NONE:FROM_PUBLIC:PSA_KEY_USAGE_SIGN_MESSAGE:MBEDTLS_ERR_PK_BAD_INPUT_DATA
 
 # There is a (negative) test for pk_type=MBEDTLS_PK_RSA_ALT in pk_rsa_alt().
 
 # Bad usage due to not specifying sign/crypt/derive.
 PSA attributes for pk: RSA usage=0 (bad)
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:1:0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:FROM_PAIR:0:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 # Bad usage due to not specifying sign/crypt/derive.
 PSA attributes for pk: RSA usage=EXPORT (bad)
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:1:PSA_KEY_USAGE_EXPORT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:FROM_PAIR:PSA_KEY_USAGE_EXPORT:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 # This usage could make sense, but is not currently supported.
 PSA attributes for pk: RSA usage=DECRYPT|EXPORT (bad)
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:1:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_EXPORT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:FROM_PAIR:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_EXPORT:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 # Bad usage due to specifying more than one of sign/crypt/derive.
 PSA attributes for pk: RSA usage=DECRYPT|SIGN_MESSAGE (bad)
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:1:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_SIGN_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:FROM_PAIR:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_SIGN_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 # This usage could make sense, but is not currently supported.
 PSA attributes for pk: RSA usage=SIGN_MESSAGE|SIGN_HASH (bad)
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:1:PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_SIGN_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:FROM_PAIR:PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_SIGN_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 # This usage could make sense, but is not currently supported.
 PSA attributes for pk: RSA usage=SIGN_MESSAGE|VERIFY_MESSAGE (bad)
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:1:PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:FROM_PAIR:PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: RSA v15 pair DECRYPT
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes:MBEDTLS_PK_RSA:1:PSA_KEY_USAGE_DECRYPT:1:PSA_ALG_RSA_PKCS1V15_CRYPT
+pk_get_psa_attributes:MBEDTLS_PK_RSA:FROM_PAIR:PSA_KEY_USAGE_DECRYPT:1:PSA_ALG_RSA_PKCS1V15_CRYPT
 
 PSA attributes for pk: RSA v21 SHA-256 pair DECRYPT
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V21:MBEDTLS_MD_CAN_SHA256
-pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_SHA256:1:PSA_KEY_USAGE_DECRYPT:1:PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256)
+pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_SHA256:FROM_PAIR:PSA_KEY_USAGE_DECRYPT:1:PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256)
 
 PSA attributes for pk: RSA v21 SHA-512 pair DECRYPT
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V21:MBEDTLS_MD_CAN_SHA512
-pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_SHA512:1:PSA_KEY_USAGE_DECRYPT:1:PSA_ALG_RSA_OAEP(PSA_ALG_SHA_512)
+pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_SHA512:FROM_PAIR:PSA_KEY_USAGE_DECRYPT:1:PSA_ALG_RSA_OAEP(PSA_ALG_SHA_512)
 
 PSA attributes for pk: RSA v15 pair->public ENCRYPT
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes:MBEDTLS_PK_RSA:1:PSA_KEY_USAGE_ENCRYPT:0:PSA_ALG_RSA_PKCS1V15_CRYPT
+pk_get_psa_attributes:MBEDTLS_PK_RSA:FROM_PAIR:PSA_KEY_USAGE_ENCRYPT:0:PSA_ALG_RSA_PKCS1V15_CRYPT
 
 PSA attributes for pk: RSA v21 SHA-256 pair->public ENCRYPT
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V21:MBEDTLS_MD_CAN_SHA256
-pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_SHA256:1:PSA_KEY_USAGE_ENCRYPT:0:PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256)
+pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_SHA256:FROM_PAIR:PSA_KEY_USAGE_ENCRYPT:0:PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256)
 
 PSA attributes for pk: RSA v21 SHA-512 pair->public ENCRYPT
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V21:MBEDTLS_MD_CAN_SHA512
-pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_SHA512:1:PSA_KEY_USAGE_ENCRYPT:0:PSA_ALG_RSA_OAEP(PSA_ALG_SHA_512)
+pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_SHA512:FROM_PAIR:PSA_KEY_USAGE_ENCRYPT:0:PSA_ALG_RSA_OAEP(PSA_ALG_SHA_512)
 
 PSA attributes for pk: RSA v15 public ENCRYPT
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes:MBEDTLS_PK_RSA:0:PSA_KEY_USAGE_ENCRYPT:0:PSA_ALG_RSA_PKCS1V15_CRYPT
+pk_get_psa_attributes:MBEDTLS_PK_RSA:FROM_PUBLIC:PSA_KEY_USAGE_ENCRYPT:0:PSA_ALG_RSA_PKCS1V15_CRYPT
 
 PSA attributes for pk: RSA v21 SHA-256 public ENCRYPT
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V21:MBEDTLS_MD_CAN_SHA256
-pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_SHA256:0:PSA_KEY_USAGE_ENCRYPT:0:PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256)
+pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_SHA256:FROM_PUBLIC:PSA_KEY_USAGE_ENCRYPT:0:PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256)
 
 PSA attributes for pk: RSA v21 SHA-512 public ENCRYPT
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V21:MBEDTLS_MD_CAN_SHA512
-pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_SHA512:0:PSA_KEY_USAGE_ENCRYPT:0:PSA_ALG_RSA_OAEP(PSA_ALG_SHA_512)
+pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_SHA512:FROM_PUBLIC:PSA_KEY_USAGE_ENCRYPT:0:PSA_ALG_RSA_OAEP(PSA_ALG_SHA_512)
 
 PSA attributes for pk: RSA v15 public DECRYPT (bad)
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:0:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:FROM_PUBLIC:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: RSA v15 pair SIGN_MESSAGE
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes:MBEDTLS_PK_RSA:1:PSA_KEY_USAGE_SIGN_MESSAGE:1:PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH)
+pk_get_psa_attributes:MBEDTLS_PK_RSA:FROM_PAIR:PSA_KEY_USAGE_SIGN_MESSAGE:1:PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: RSA v21 SHA-256 pair SIGN_MESSAGE
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V21
-pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_NONE:1:PSA_KEY_USAGE_SIGN_MESSAGE:1:PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_ANY_HASH)
+pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_NONE:FROM_PAIR:PSA_KEY_USAGE_SIGN_MESSAGE:1:PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: RSA v15 pair SIGN_HASH
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes:MBEDTLS_PK_RSA:1:PSA_KEY_USAGE_SIGN_HASH:1:PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH)
+pk_get_psa_attributes:MBEDTLS_PK_RSA:FROM_PAIR:PSA_KEY_USAGE_SIGN_HASH:1:PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: RSA v21 SHA-256 pair SIGN_HASH
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V21
-pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_NONE:1:PSA_KEY_USAGE_SIGN_HASH:1:PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_ANY_HASH)
+pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_NONE:FROM_PAIR:PSA_KEY_USAGE_SIGN_HASH:1:PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: RSA v15 pair->public VERIFY_MESSAGE
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes:MBEDTLS_PK_RSA:1:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH)
+pk_get_psa_attributes:MBEDTLS_PK_RSA:FROM_PAIR:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: RSA v21 SHA-256 pair->public VERIFY_MESSAGE
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V21
-pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_NONE:1:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_ANY_HASH)
+pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_NONE:FROM_PAIR:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: RSA v15 pair->public VERIFY_HASH
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes:MBEDTLS_PK_RSA:1:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH)
+pk_get_psa_attributes:MBEDTLS_PK_RSA:FROM_PAIR:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: RSA v21 SHA-256 pair->public VERIFY_HASH
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V21
-pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_NONE:1:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_ANY_HASH)
+pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_NONE:FROM_PAIR:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: RSA v15 public VERIFY_MESSAGE
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes:MBEDTLS_PK_RSA:0:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH)
+pk_get_psa_attributes:MBEDTLS_PK_RSA:FROM_PUBLIC:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: RSA v21 SHA-256 public VERIFY_MESSAGE
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V21
-pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_NONE:0:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_ANY_HASH)
+pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_NONE:FROM_PUBLIC:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: RSA v15 public VERIFY_HASH
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes:MBEDTLS_PK_RSA:0:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH)
+pk_get_psa_attributes:MBEDTLS_PK_RSA:FROM_PUBLIC:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: RSA v21 SHA-256 public VERIFY_HASH
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V21
-pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_NONE:0:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_ANY_HASH)
+pk_rsa_v21_get_psa_attributes:MBEDTLS_MD_NONE:FROM_PUBLIC:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: RSA v15 public SIGN_MESSAGE (bad)
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:0:PSA_KEY_USAGE_SIGN_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:FROM_PUBLIC:PSA_KEY_USAGE_SIGN_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: RSA v15 public SIGN_HASH (bad)
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:0:PSA_KEY_USAGE_SIGN_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:FROM_PUBLIC:PSA_KEY_USAGE_SIGN_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: RSA v15 pair DERIVE (bad)
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:1:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:FROM_PAIR:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: RSA v15 public DERIVE (bad)
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15
-pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:0:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:FROM_PUBLIC:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY pair DECRYPT (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:1:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:FROM_PAIR:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY_DH pair DECRYPT (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:1:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:FROM_PAIR:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECDSA pair DECRYPT (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:MBEDTLS_PK_CAN_ECDSA_SOME
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:1:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:FROM_PAIR:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY public DECRYPT (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:0:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:FROM_PUBLIC:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY_DH public DECRYPT (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:0:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:FROM_PUBLIC:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECDSA public DECRYPT (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:MBEDTLS_PK_CAN_ECDSA_SOME
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:0:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:FROM_PUBLIC:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY pair ENCRYPT (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:1:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:FROM_PAIR:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY_DH pair ENCRYPT (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:1:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:FROM_PAIR:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECDSA pair ENCRYPT (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:MBEDTLS_PK_CAN_ECDSA_SOME
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:1:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:FROM_PAIR:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY public ENCRYPT (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:0:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:FROM_PUBLIC:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY_DH public ENCRYPT (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:0:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:FROM_PUBLIC:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECDSA public ENCRYPT (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:MBEDTLS_PK_CAN_ECDSA_SOME
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:0:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:FROM_PUBLIC:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY pair DERIVE
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes:MBEDTLS_PK_ECKEY:1:PSA_KEY_USAGE_DERIVE:1:PSA_ALG_ECDH
+pk_get_psa_attributes:MBEDTLS_PK_ECKEY:FROM_PAIR:PSA_KEY_USAGE_DERIVE:1:PSA_ALG_ECDH
 
 PSA attributes for pk: ECKEY_DH pair DERIVE
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes:MBEDTLS_PK_ECKEY_DH:1:PSA_KEY_USAGE_DERIVE:1:PSA_ALG_ECDH
+pk_get_psa_attributes:MBEDTLS_PK_ECKEY_DH:FROM_PAIR:PSA_KEY_USAGE_DERIVE:1:PSA_ALG_ECDH
 
 PSA attributes for pk: ECDSA pair DERIVE (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:MBEDTLS_PK_CAN_ECDSA_SOME
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:1:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:FROM_PAIR:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY public DERIVE (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:0:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:FROM_PUBLIC:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY_DH public DERIVE (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:0:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:FROM_PUBLIC:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECDSA public DERIVE (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:MBEDTLS_PK_CAN_ECDSA_SOME
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:0:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:FROM_PUBLIC:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY pair SIGN_MESSAGE
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes:MBEDTLS_PK_ECKEY:1:PSA_KEY_USAGE_SIGN_MESSAGE:1:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+pk_get_psa_attributes:MBEDTLS_PK_ECKEY:FROM_PAIR:PSA_KEY_USAGE_SIGN_MESSAGE:1:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: ECDSA pair SIGN_MESSAGE
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:MBEDTLS_PK_CAN_ECDSA_SOME
-pk_get_psa_attributes:MBEDTLS_PK_ECDSA:1:PSA_KEY_USAGE_SIGN_MESSAGE:1:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+pk_get_psa_attributes:MBEDTLS_PK_ECDSA:FROM_PAIR:PSA_KEY_USAGE_SIGN_MESSAGE:1:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: ECKEY pair SIGN_HASH
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes:MBEDTLS_PK_ECKEY:1:PSA_KEY_USAGE_SIGN_HASH:1:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+pk_get_psa_attributes:MBEDTLS_PK_ECKEY:FROM_PAIR:PSA_KEY_USAGE_SIGN_HASH:1:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: ECDSA pair SIGN_HASH
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:MBEDTLS_PK_CAN_ECDSA_SOME
-pk_get_psa_attributes:MBEDTLS_PK_ECDSA:1:PSA_KEY_USAGE_SIGN_HASH:1:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+pk_get_psa_attributes:MBEDTLS_PK_ECDSA:FROM_PAIR:PSA_KEY_USAGE_SIGN_HASH:1:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: ECKEY pair->public VERIFY_MESSAGE
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes:MBEDTLS_PK_ECKEY:1:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+pk_get_psa_attributes:MBEDTLS_PK_ECKEY:FROM_PAIR:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: ECDSA pair->public VERIFY_MESSAGE
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:MBEDTLS_PK_CAN_ECDSA_SOME
-pk_get_psa_attributes:MBEDTLS_PK_ECDSA:1:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+pk_get_psa_attributes:MBEDTLS_PK_ECDSA:FROM_PAIR:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: ECKEY pair->public VERIFY_HASH
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes:MBEDTLS_PK_ECKEY:1:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+pk_get_psa_attributes:MBEDTLS_PK_ECKEY:FROM_PAIR:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: ECDSA pair->public VERIFY_HASH
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:MBEDTLS_PK_CAN_ECDSA_SOME
-pk_get_psa_attributes:MBEDTLS_PK_ECDSA:1:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+pk_get_psa_attributes:MBEDTLS_PK_ECDSA:FROM_PAIR:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: ECKEY public VERIFY_MESSAGE
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes:MBEDTLS_PK_ECKEY:0:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+pk_get_psa_attributes:MBEDTLS_PK_ECKEY:FROM_PUBLIC:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: ECDSA public VERIFY_MESSAGE
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:MBEDTLS_PK_CAN_ECDSA_SOME
-pk_get_psa_attributes:MBEDTLS_PK_ECDSA:0:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+pk_get_psa_attributes:MBEDTLS_PK_ECDSA:FROM_PUBLIC:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: ECKEY public VERIFY_HASH
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes:MBEDTLS_PK_ECKEY:0:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+pk_get_psa_attributes:MBEDTLS_PK_ECKEY:FROM_PUBLIC:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: ECDSA public VERIFY_HASH
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:MBEDTLS_PK_CAN_ECDSA_SOME
-pk_get_psa_attributes:MBEDTLS_PK_ECDSA:0:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+pk_get_psa_attributes:MBEDTLS_PK_ECDSA:FROM_PUBLIC:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
 
 PSA attributes for pk: ECKEY public SIGN_MESSAGE (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:0:PSA_KEY_USAGE_SIGN_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:FROM_PUBLIC:PSA_KEY_USAGE_SIGN_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECDSA public SIGN_MESSAGE (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:MBEDTLS_PK_CAN_ECDSA_SOME
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:0:PSA_KEY_USAGE_SIGN_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:FROM_PUBLIC:PSA_KEY_USAGE_SIGN_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY public SIGN_HASH (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:0:PSA_KEY_USAGE_SIGN_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:FROM_PUBLIC:PSA_KEY_USAGE_SIGN_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECDSA public SIGN_HASH (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:MBEDTLS_PK_CAN_ECDSA_SOME
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:0:PSA_KEY_USAGE_SIGN_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:FROM_PUBLIC:PSA_KEY_USAGE_SIGN_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY_DH pair SIGN_MESSAGE (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:1:PSA_KEY_USAGE_SIGN_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:FROM_PAIR:PSA_KEY_USAGE_SIGN_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY_DH pair SIGN_HASH (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:1:PSA_KEY_USAGE_SIGN_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:FROM_PAIR:PSA_KEY_USAGE_SIGN_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY_DH pair VERIFY_MESSAGE (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:1:PSA_KEY_USAGE_VERIFY_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:FROM_PAIR:PSA_KEY_USAGE_VERIFY_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY_DH pair VERIFY_HASH (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:1:PSA_KEY_USAGE_VERIFY_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:FROM_PAIR:PSA_KEY_USAGE_VERIFY_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY_DH public SIGN_MESSAGE (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:0:PSA_KEY_USAGE_SIGN_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:FROM_PUBLIC:PSA_KEY_USAGE_SIGN_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY_DH public SIGN_HASH (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:0:PSA_KEY_USAGE_SIGN_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:FROM_PUBLIC:PSA_KEY_USAGE_SIGN_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY_DH public VERIFY_MESSAGE (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:0:PSA_KEY_USAGE_VERIFY_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:FROM_PUBLIC:PSA_KEY_USAGE_VERIFY_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: ECKEY_DH public VERIFY_HASH (bad)
 depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
-pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:0:PSA_KEY_USAGE_VERIFY_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:FROM_PUBLIC:PSA_KEY_USAGE_VERIFY_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 PSA attributes for pk: opaque RSA pair, 0 & SIGN_MESSAGE (bad policy)
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME
@@ -1004,8 +1066,23 @@
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME
 pk_get_psa_attributes_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_DECRYPT:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_USAGE_SIGN_MESSAGE:0:1:PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_DECRYPT
 
+# For a PK_OPAQUE key with a key pair type output,
+# mbedtls_pk_import_into_psa() requires the key to be copyable or exportable.
+# Try all combinations of COPY/not, EXPORT/not.
 PSA attributes for pk: opaque RSA pair, SIGN|... & SIGN_MESSAGE
 depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME
+pk_get_psa_attributes_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE | PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_USAGE_SIGN_MESSAGE:0:1:PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE | PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT
+
+PSA attributes for pk: opaque RSA pair, SIGN|EXPORT|... & SIGN_MESSAGE
+depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME
+pk_get_psa_attributes_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE | PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_USAGE_SIGN_MESSAGE:0:1:PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE | PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT
+
+PSA attributes for pk: opaque RSA pair, SIGN|COPY|... & SIGN_MESSAGE
+depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME
+pk_get_psa_attributes_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE | PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_USAGE_SIGN_MESSAGE:0:1:PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE | PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT
+
+PSA attributes for pk: opaque RSA pair, SIGN|COPY|EXPORT... & SIGN_MESSAGE
+depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME
 pk_get_psa_attributes_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE | PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_USAGE_SIGN_MESSAGE:0:1:PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE | PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT
 
 PSA attributes for pk: opaque RSA pair, SIGN_MESSAGE & SIGN_HASH (bad policy)
@@ -1109,3 +1186,268 @@
 PSA attributes for pk: opaque ECC pair->public, ENCRYPT & ENCRYPT (bad)
 depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:PSA_WANT_ECC_SECP_R1_256
 pk_get_psa_attributes_opaque:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):256:PSA_KEY_USAGE_ENCRYPT:PSA_ALG_ECDSA_ANY:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH:0:0
+
+PSA import into PSA: RSA pair to ECC (bad)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME
+pk_import_into_psa_fail:MBEDTLS_PK_RSA:FROM_PAIR:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: RSA public to RSA pair (bad)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME
+pk_import_into_psa_fail:MBEDTLS_PK_RSA:FROM_PUBLIC:PSA_KEY_TYPE_RSA_KEY_PAIR:0:MBEDTLS_ERR_RSA_BAD_INPUT_DATA
+
+# MBEDTLS_ERR_PK_INVALID_ALG is the error that results from our translation
+# of PSA errors. In this case MBEDTLS_ERR_PK_TYPE_MISMATCH would probably
+# be more appropriate. (Applies to all the RSA "different bits" test cases.)
+PSA import into PSA: RSA pair to different bits (bad)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME
+pk_import_into_psa_fail:MBEDTLS_PK_RSA:FROM_PAIR:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS + 8:MBEDTLS_ERR_PK_INVALID_ALG
+
+PSA import into PSA: RSA public to different bits (bad)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME
+pk_import_into_psa_fail:MBEDTLS_PK_RSA:FROM_PUBLIC:PSA_KEY_TYPE_RSA_PUBLIC_KEY:MBEDTLS_RSA_GEN_KEY_MIN_BITS + 8:MBEDTLS_ERR_PK_INVALID_ALG
+
+PSA import into PSA: RSA private to public, different bits (bad)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME
+pk_import_into_psa_fail:MBEDTLS_PK_RSA:FROM_PAIR:PSA_KEY_TYPE_RSA_PUBLIC_KEY:MBEDTLS_RSA_GEN_KEY_MIN_BITS + 8:MBEDTLS_ERR_PK_INVALID_ALG
+
+PSA import into PSA: ECKEY pair to RSA (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
+pk_import_into_psa_fail:MBEDTLS_PK_ECKEY:FROM_PAIR:PSA_KEY_TYPE_RSA_KEY_PAIR:0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECKEY_DH pair to RSA (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
+pk_import_into_psa_fail:MBEDTLS_PK_ECKEY_DH:FROM_PAIR:PSA_KEY_TYPE_RSA_KEY_PAIR:0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECDSA pair to RSA (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:MBEDTLS_PK_CAN_ECDSA_SOME
+pk_import_into_psa_fail:MBEDTLS_PK_ECDSA:FROM_PAIR:PSA_KEY_TYPE_RSA_KEY_PAIR:0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECKEY pair to different curve (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_FAMILIES
+pk_import_into_psa_fail:MBEDTLS_PK_ECKEY:FROM_PAIR:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ANOTHER_FAMILY):0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECKEY_DH pair to different curve (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_FAMILIES
+pk_import_into_psa_fail:MBEDTLS_PK_ECKEY_DH:FROM_PAIR:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ANOTHER_FAMILY):0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECDSA pair to different curve (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_FAMILIES:MBEDTLS_PK_CAN_ECDSA_SOME
+pk_import_into_psa_fail:MBEDTLS_PK_ECDSA:FROM_PAIR:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ANOTHER_FAMILY):0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECKEY pair to public, different curve (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_FAMILIES
+pk_import_into_psa_fail:MBEDTLS_PK_ECKEY:FROM_PAIR:PSA_KEY_TYPE_ECC_PUBLIC_KEY(MBEDTLS_TEST_PSA_ECC_ANOTHER_FAMILY):0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECKEY_DH pair to public, different curve (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_FAMILIES
+pk_import_into_psa_fail:MBEDTLS_PK_ECKEY_DH:FROM_PAIR:PSA_KEY_TYPE_ECC_PUBLIC_KEY(MBEDTLS_TEST_PSA_ECC_ANOTHER_FAMILY):0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECDSA pair to public, different curve (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_FAMILIES:MBEDTLS_PK_CAN_ECDSA_SOME
+pk_import_into_psa_fail:MBEDTLS_PK_ECDSA:FROM_PAIR:PSA_KEY_TYPE_ECC_PUBLIC_KEY(MBEDTLS_TEST_PSA_ECC_ANOTHER_FAMILY):0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECKEY public to different curve (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_FAMILIES
+pk_import_into_psa_fail:MBEDTLS_PK_ECKEY:FROM_PUBLIC:PSA_KEY_TYPE_ECC_PUBLIC_KEY(MBEDTLS_TEST_PSA_ECC_ANOTHER_FAMILY):0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECKEY_DH public to different curve (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_FAMILIES
+pk_import_into_psa_fail:MBEDTLS_PK_ECKEY_DH:FROM_PUBLIC:PSA_KEY_TYPE_ECC_PUBLIC_KEY(MBEDTLS_TEST_PSA_ECC_ANOTHER_FAMILY):0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECDSA public to different curve (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_FAMILIES:MBEDTLS_PK_CAN_ECDSA_SOME
+pk_import_into_psa_fail:MBEDTLS_PK_ECDSA:FROM_PUBLIC:PSA_KEY_TYPE_ECC_PUBLIC_KEY(MBEDTLS_TEST_PSA_ECC_ANOTHER_FAMILY):0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECKEY pair to different bits (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_BITS
+pk_import_into_psa_fail:MBEDTLS_PK_ECKEY:FROM_PAIR:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS):MBEDTLS_TEST_PSA_ECC_ANOTHER_CURVE_BITS:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECKEY_DH pair to different bits (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_BITS
+pk_import_into_psa_fail:MBEDTLS_PK_ECKEY_DH:FROM_PAIR:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS):MBEDTLS_TEST_PSA_ECC_ANOTHER_CURVE_BITS:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECDSA pair to different bits (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_BITS:MBEDTLS_PK_CAN_ECDSA_SOME
+pk_import_into_psa_fail:MBEDTLS_PK_ECDSA:FROM_PAIR:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS):MBEDTLS_TEST_PSA_ECC_ANOTHER_CURVE_BITS:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECKEY public to different bits (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_BITS
+pk_import_into_psa_fail:MBEDTLS_PK_ECKEY:FROM_PUBLIC:PSA_KEY_TYPE_ECC_PUBLIC_KEY(MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS):MBEDTLS_TEST_PSA_ECC_ANOTHER_CURVE_BITS:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECKEY_DH public to different bits (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_BITS
+pk_import_into_psa_fail:MBEDTLS_PK_ECKEY_DH:FROM_PUBLIC:PSA_KEY_TYPE_ECC_PUBLIC_KEY(MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS):MBEDTLS_TEST_PSA_ECC_ANOTHER_CURVE_BITS:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECDSA public to different bits (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_BITS:MBEDTLS_PK_CAN_ECDSA_SOME
+pk_import_into_psa_fail:MBEDTLS_PK_ECDSA:FROM_PUBLIC:PSA_KEY_TYPE_ECC_PUBLIC_KEY(MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS):MBEDTLS_TEST_PSA_ECC_ANOTHER_CURVE_BITS:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECKEY private to public, different bits (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_BITS
+pk_import_into_psa_fail:MBEDTLS_PK_ECKEY:FROM_PAIR:PSA_KEY_TYPE_ECC_PUBLIC_KEY(MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS):MBEDTLS_TEST_PSA_ECC_ANOTHER_CURVE_BITS:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECKEY_DH private to public, different bits (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_BITS
+pk_import_into_psa_fail:MBEDTLS_PK_ECKEY_DH:FROM_PAIR:PSA_KEY_TYPE_ECC_PUBLIC_KEY(MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS):MBEDTLS_TEST_PSA_ECC_ANOTHER_CURVE_BITS:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECDSA private to public, different bits (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_BITS:MBEDTLS_PK_CAN_ECDSA_SOME
+pk_import_into_psa_fail:MBEDTLS_PK_ECDSA:FROM_PAIR:PSA_KEY_TYPE_ECC_PUBLIC_KEY(MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS):MBEDTLS_TEST_PSA_ECC_ANOTHER_CURVE_BITS:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECKEY public to pair (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
+pk_import_into_psa_fail:MBEDTLS_PK_ECKEY:FROM_PUBLIC:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECKEY_DH public to pair (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
+pk_import_into_psa_fail:MBEDTLS_PK_ECKEY_DH:FROM_PUBLIC:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: ECDSA public to pair (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:MBEDTLS_PK_CAN_ECDSA_SOME
+pk_import_into_psa_fail:MBEDTLS_PK_ECDSA:FROM_PUBLIC:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: opaque RSA, COPY (ok)
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
+pk_import_into_psa_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:0
+
+PSA import into PSA: opaque RSA, EXPORT (ok)
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
+pk_import_into_psa_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:0
+
+PSA import into PSA: opaque RSA, no COPY/EXPORT (bad)
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
+pk_import_into_psa_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+# Detail that isn't precisely documented: since this copies the key,
+# the new key has the intersection of the usage flags.
+PSA import into PSA: opaque RSA, COPY|EXPORT, different usage (restricted)
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
+pk_import_into_psa_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:0
+
+# Detail that isn't precisely documented: since this copies the key,
+# the new key has the intersection of the usage flags.
+PSA import into PSA: opaque RSA, COPY, different usage (restricted)
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
+pk_import_into_psa_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:0
+
+# Detail that isn't precisely documented: since this exports the key,
+# the new key has all the requested usage flags.
+PSA import into PSA: opaque RSA, EXPORT, different usage (ok)
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
+pk_import_into_psa_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:0
+
+PSA import into PSA: opaque RSA, COPY|EXPORT, different algorithm (ok)
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
+pk_import_into_psa_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256):0
+
+PSA import into PSA: opaque RSA, COPY, different algorithm (bad)
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
+pk_import_into_psa_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256):MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: opaque RSA, EXPORT, different algorithm (ok)
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
+pk_import_into_psa_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256):0
+
+PSA import into PSA: opaque RSA, implicit bits (ok)
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
+pk_import_into_psa_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_TYPE_RSA_KEY_PAIR:0:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:0
+
+PSA import into PSA: opaque RSA, different bits (bad)
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
+pk_import_into_psa_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS + 8:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: opaque RSA, different type (bad)
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
+pk_import_into_psa_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:0:PSA_KEY_TYPE_HMAC:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: opaque RSA to public (ok)
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
+pk_import_into_psa_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_TYPE_RSA_PUBLIC_KEY:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:0
+
+PSA import into PSA: opaque RSA to public, implicit bits (ok)
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
+pk_import_into_psa_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_TYPE_RSA_PUBLIC_KEY:0:PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:0
+
+# MBEDTLS_ERR_PK_INVALID_ALG is the error that results from our translation
+# of PSA errors. In this case MBEDTLS_ERR_PK_TYPE_MISMATCH would probably
+# be more appropriate.
+PSA import into PSA: opaque RSA to public, different bits (bad)
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
+pk_import_into_psa_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_TYPE_RSA_PUBLIC_KEY:MBEDTLS_RSA_GEN_KEY_MIN_BITS + 8:PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:MBEDTLS_ERR_PK_INVALID_ALG
+
+PSA import into PSA: opaque ECC, COPY (ok)
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:PSA_WANT_ALG_ECDSA
+pk_import_into_psa_opaque:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):0
+
+PSA import into PSA: opaque ECC, EXPORT (ok)
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:PSA_WANT_ALG_ECDSA
+pk_import_into_psa_opaque:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):0
+
+PSA import into PSA: opaque ECC, no COPY/EXPORT (bad)
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:PSA_WANT_ALG_ECDSA
+pk_import_into_psa_opaque:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+# Detail that isn't precisely documented: since this copies the key,
+# the new key has the intersection of the usage flags.
+PSA import into PSA: opaque ECC, COPY|EXPORT, different usage (restricted)
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:PSA_WANT_ALG_ECDSA
+pk_import_into_psa_opaque:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):0
+
+# Detail that isn't precisely documented: since this copies the key,
+# the new key has the intersection of the usage flags.
+PSA import into PSA: opaque ECC, COPY, different usage (restricted)
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:PSA_WANT_ALG_ECDSA
+pk_import_into_psa_opaque:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):0
+
+# Detail that isn't precisely documented: since this exports the key,
+# the new key has all the requested usage flags.
+PSA import into PSA: opaque ECC, EXPORT, different usage (ok)
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:PSA_WANT_ALG_ECDSA
+pk_import_into_psa_opaque:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):0
+
+PSA import into PSA: opaque ECC, COPY|EXPORT, different algorithm (ok)
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:PSA_WANT_ALG_ECDSA
+pk_import_into_psa_opaque:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256):0
+
+PSA import into PSA: opaque ECC, COPY, different algorithm (bad)
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:PSA_WANT_ALG_ECDSA
+pk_import_into_psa_opaque:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256):MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: opaque ECC, EXPORT, different algorithm (ok)
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:PSA_WANT_ALG_ECDSA
+pk_import_into_psa_opaque:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256):0
+
+PSA import into PSA: opaque ECC, implicit bits (ok)
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:PSA_WANT_ALG_ECDSA
+pk_import_into_psa_opaque:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):0:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):0
+
+PSA import into PSA: opaque ECC, different bits (bad)
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:PSA_WANT_ALG_ECDSA
+pk_import_into_psa_opaque:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS + 8:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: opaque ECC, different type (bad)
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:PSA_WANT_ALG_ECDSA
+pk_import_into_psa_opaque:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:0:PSA_KEY_TYPE_HMAC:MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: opaque ECC, different family (bad)
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_FAMILIES:PSA_WANT_ALG_ECDSA
+pk_import_into_psa_opaque:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:0:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ANOTHER_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA import into PSA: opaque ECC to public (ok)
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:PSA_WANT_ALG_ECDSA
+pk_import_into_psa_opaque:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_KEY_TYPE_ECC_PUBLIC_KEY(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):0
+
+PSA import into PSA: opaque ECC to public, implicit bits (ok)
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:PSA_WANT_ALG_ECDSA
+pk_import_into_psa_opaque:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_KEY_TYPE_ECC_PUBLIC_KEY(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):0:PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):0
+
+# MBEDTLS_ERR_PK_INVALID_ALG is the error that results from our translation
+# of PSA errors. In this case MBEDTLS_ERR_PK_TYPE_MISMATCH would probably
+# be more appropriate.
+PSA import into PSA: opaque ECC to public, different bits (bad)
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:PSA_WANT_ALG_ECDSA
+pk_import_into_psa_opaque:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_KEY_TYPE_ECC_PUBLIC_KEY(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS + 8:PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):MBEDTLS_ERR_PK_INVALID_ALG
+
+PSA import into PSA: opaque ECC to public, different family (bad)
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:MBEDTLS_TEST_PSA_ECC_HAVE_TWO_FAMILIES:PSA_WANT_ALG_ECDSA
+pk_import_into_psa_opaque:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:0:PSA_KEY_TYPE_ECC_PUBLIC_KEY(MBEDTLS_TEST_PSA_ECC_ANOTHER_FAMILY):MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:0:MBEDTLS_ERR_PK_TYPE_MISMATCH
diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function
index 2574307..3d75ad0 100644
--- a/tests/suites/test_suite_pk.function
+++ b/tests/suites/test_suite_pk.function
@@ -19,12 +19,21 @@
 #include "psa/crypto.h"
 #include "mbedtls/psa_util.h"
 
+#include <test/psa_exercise_key.h>
+
 /* Used for properly sizing the key buffer in pk_genkey_ec() */
 #include "psa_util_internal.h"
 
 #define RSA_KEY_SIZE   MBEDTLS_RSA_GEN_KEY_MIN_BITS
 #define RSA_KEY_LEN   (MBEDTLS_RSA_GEN_KEY_MIN_BITS/8)
 
+#if defined(MBEDTLS_RSA_C) ||                                           \
+    defined(MBEDTLS_PK_RSA_ALT_SUPPORT) ||                              \
+    defined(MBEDTLS_ECDSA_C) ||                                         \
+    defined(MBEDTLS_USE_PSA_CRYPTO)
+#define PK_CAN_SIGN_SOME
+#endif
+
 /* MBEDTLS_TEST_PK_PSA_SIGN is enabled when:
  * - The build has PK_[PARSE/WRITE]_C for RSA or ECDSA signature.
  * - The build has built-in ECC and ECDSA signature.
@@ -36,28 +45,126 @@
 #define MBEDTLS_TEST_PK_PSA_SIGN
 #endif
 
-/* MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE is enabled when PSA supports
- * at least one elliptic curve. This is distinct from
- * PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY because that symbol can be enabled even
- * when there are no curves. This happens in particular in a configuration
- * with MBEDTLS_PSA_CRYPTO_CONFIG disabled and where the only legacy curve
- * is secp224k1, which is not supported in PSA. */
 #if defined(MBEDTLS_PSA_CRYPTO_C) && defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY)
-#if defined(PSA_WANT_ECC_BRAINPOOL_P_R1_256) || \
-    defined(PSA_WANT_ECC_BRAINPOOL_P_R1_384) || \
-    defined(PSA_WANT_ECC_BRAINPOOL_P_R1_512) || \
-    defined(PSA_WANT_ECC_MONTGOMERY_255) || \
-    defined(PSA_WANT_ECC_MONTGOMERY_448) || \
-    defined(PSA_WANT_ECC_SECP_K1_192) || \
-    defined(PSA_WANT_ECC_SECP_K1_224) || \
-    defined(PSA_WANT_ECC_SECP_K1_256) || \
-    defined(PSA_WANT_ECC_SECP_R1_192) || \
-    defined(PSA_WANT_ECC_SECP_R1_224) || \
-    defined(PSA_WANT_ECC_SECP_R1_256) || \
-    defined(PSA_WANT_ECC_SECP_R1_384) || \
-    defined(PSA_WANT_ECC_SECP_R1_521)
+/* Pick an elliptic curve that's supported by PSA. Note that the curve is
+ * not guaranteed to be supported by the ECP module.
+ *
+ * This should always find a curve if ECC is enabled in the build, except in
+ * one edge case: in a build with MBEDTLS_PSA_CRYPTO_CONFIG disabled and
+ * where the only legacy curve is secp224k1, which is not supported in PSA,
+ * PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY ends up enabled but PSA does not
+ * support any curve.
+ */
+
+/* First try all the curves that can do both ECDSA and ECDH, then try
+ * the ECDH-only curves. (There are no curves that can do ECDSA but not ECDH.)
+ * This way, if ECDSA is enabled then the curve that's selected here will
+ * be ECDSA-capable, and likewise for ECDH. */
+#if defined(PSA_WANT_ECC_SECP_R1_192)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_R1
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 192
+#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_SECP192R1
+#elif defined(PSA_WANT_ECC_SECP_R1_224)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_R1
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 224
+#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_SECP224R1
+#elif defined(PSA_WANT_ECC_SECP_R1_256)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_R1
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 256
+#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_SECP256R1
+#elif defined(PSA_WANT_ECC_SECP_R1_384)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_R1
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 384
+#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_SECP384R1
+#elif defined(PSA_WANT_ECC_SECP_R1_521)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_R1
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 521
+#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_SECP521R1
+#elif defined(PSA_WANT_ECC_SECP_K1_192)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_K1
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 192
+#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_SECP192K1
+#elif defined(PSA_WANT_ECC_SECP_K1_224)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_K1
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 224
+#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_SECP224K1
+#elif defined(PSA_WANT_ECC_SECP_K1_256)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_K1
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 256
+#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_SECP256K1
+#elif defined(PSA_WANT_ECC_BRAINPOOL_P_R1_256)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_BRAINPOOL_P_R1
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 256
+#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_BP256R1
+#elif defined(PSA_WANT_ECC_BRAINPOOL_P_R1_384)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_BRAINPOOL_P_R1
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 384
+#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_BP384R1
+#elif defined(PSA_WANT_ECC_BRAINPOOL_P_R1_512)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_BRAINPOOL_P_R1
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 512
+#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_BP512R1
+#elif defined(PSA_WANT_ECC_MONTGOMERY_255)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_MONTGOMERY
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 255
+#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_CURVE25519
+#elif defined(PSA_WANT_ECC_MONTGOMERY_448)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_MONTGOMERY
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 448
+#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_CURVE448
+#endif /* curve selection */
+
+#if defined(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY)
 #define MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE
 #endif
+
+/* Pick a second curve, for tests that need two supported curves of the
+ * same size. For simplicity, we only handle a subset of configurations,
+ * and both curves will support both ECDH and ECDSA. */
+#if defined(PSA_WANT_ECC_SECP_R1_192) && defined(PSA_WANT_ECC_SECP_K1_192)
+/* Identical redefinition of the ONE macros, to confirm that they have
+ * the values we expect here. */
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_R1
+#define MBEDTLS_TEST_PSA_ECC_ANOTHER_FAMILY PSA_ECC_FAMILY_SECP_K1
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 192
+#define MBEDTLS_TEST_PSA_ECC_HAVE_TWO_FAMILIES
+#elif defined(PSA_WANT_ECC_SECP_R1_256) && defined(PSA_WANT_ECC_SECP_K1_256)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_R1
+#define MBEDTLS_TEST_PSA_ECC_ANOTHER_FAMILY PSA_ECC_FAMILY_SECP_K1
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 256
+#define MBEDTLS_TEST_PSA_ECC_HAVE_TWO_FAMILIES
+#endif
+
+/* Pick a second bit-size, for tests that need two supported curves of the
+ * same family. For simplicity, we only handle a subset of configurations,
+ * and both curves will support both ECDH and ECDSA. */
+#if defined(PSA_WANT_ECC_SECP_R1_192) && defined(PSA_WANT_ECC_SECP_R1_256)
+/* Identical redefinition of the ONE macros, to confirm that they have
+ * the values we expect here. */
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_R1
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 192
+#define MBEDTLS_TEST_PSA_ECC_ANOTHER_CURVE_BITS 256
+#define MBEDTLS_TEST_PSA_ECC_HAVE_TWO_BITS
+#elif defined(PSA_WANT_ECC_SECP_R1_256) && defined(PSA_WANT_ECC_SECP_R1_384)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_R1
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 256
+#define MBEDTLS_TEST_PSA_ECC_ANOTHER_CURVE_BITS 384
+#define MBEDTLS_TEST_PSA_ECC_HAVE_TWO_BITS
+#endif
+
+#endif /* defined(MBEDTLS_PSA_CRYPTO_C) && defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) */
+
+/* Always define the macros so that we can use them in test data. */
+#if !defined(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY 0
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 0
+#define MBEDTLS_TEST_ECP_DP_ONE_CURVE 0
+#endif
+#if !defined(MBEDTLS_TEST_PSA_ECC_ANOTHER_FAMILY)
+#define MBEDTLS_TEST_PSA_ECC_ANOTHER_FAMILY 0
+#endif
+#if !defined(MBEDTLS_TEST_PSA_ECC_ANOTHER_CURVE_BITS)
+#define MBEDTLS_TEST_PSA_ECC_ANOTHER_CURVE_BITS 0
 #endif
 
 #if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
@@ -75,14 +182,31 @@
 
     psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(curve));
     psa_set_key_bits(&key_attr, curve_bits);
-    psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_EXPORT |
-                            PSA_KEY_USAGE_SIGN_HASH |
-                            PSA_KEY_USAGE_SIGN_MESSAGE);
+    psa_key_usage_t usage = PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_COPY;
+    psa_algorithm_t sign_alg = 0;
+    psa_algorithm_t derive_alg = 0;
+    if (mbedtls_pk_get_type(pk) != MBEDTLS_PK_ECDSA) {
+        usage |= PSA_KEY_USAGE_DERIVE;
+        derive_alg = PSA_ALG_ECDH;
+    }
+    if (mbedtls_pk_get_type(pk) != MBEDTLS_PK_ECKEY_DH &&
+        curve != PSA_ECC_FAMILY_MONTGOMERY) {
+        usage |= PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE;
 #if defined(MBEDTLS_ECDSA_DETERMINISTIC)
-    psa_set_key_algorithm(&key_attr, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_ANY_HASH));
+        sign_alg = PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_ANY_HASH);
 #else
-    psa_set_key_algorithm(&key_attr, PSA_ALG_ECDSA(PSA_ALG_ANY_HASH));
+        sign_alg = PSA_ALG_ECDSA(PSA_ALG_ANY_HASH);
 #endif
+    }
+    if (derive_alg != 0) {
+        psa_set_key_algorithm(&key_attr, derive_alg);
+        if (sign_alg != 0) {
+            psa_set_key_enrollment_algorithm(&key_attr, sign_alg);
+        }
+    } else {
+        psa_set_key_algorithm(&key_attr, sign_alg);
+    }
+    psa_set_key_usage_flags(&key_attr, usage);
 
     status = psa_generate_key(&key_attr, &pk->priv_id);
     if (status != PSA_SUCCESS) {
@@ -211,42 +335,11 @@
 }
 #endif /* MBEDTLS_RSA_C */
 
-#if defined(MBEDTLS_PSA_CRYPTO_C) && defined(MBEDTLS_PK_HAVE_ECC_KEYS)
-static mbedtls_ecp_group_id ecc_pick_grp_id(void)
-{
-#if defined(MBEDTLS_ECP_LIGHT)
-    return mbedtls_ecp_grp_id_list()[0];
-#elif defined(PSA_WANT_ECC_SECP_R1_192)
-    return MBEDTLS_ECP_DP_SECP192R1;
-#elif defined(PSA_WANT_ECC_SECP_R1_224)
-    return MBEDTLS_ECP_DP_SECP224R1;
-#elif defined(PSA_WANT_ECC_SECP_R1_256)
-    return MBEDTLS_ECP_DP_SECP256R1;
-#elif defined(PSA_WANT_ECC_SECP_R1_384)
-    return MBEDTLS_ECP_DP_SECP384R1;
-#elif defined(PSA_WANT_ECC_SECP_R1_521)
-    return MBEDTLS_ECP_DP_SECP521R1;
-#elif defined(PSA_WANT_ECC_SECP_K1_192)
-    return MBEDTLS_ECP_DP_SECP192K1;
-#elif defined(PSA_WANT_ECC_SECP_K1_224)
-    return MBEDTLS_ECP_DP_SECP224K1;
-#elif defined(PSA_WANT_ECC_SECP_K1_256)
-    return MBEDTLS_ECP_DP_SECP256K1;
-#elif defined(PSA_WANT_ECC_BRAINPOOL_P_R1_256)
-    return MBEDTLS_ECP_DP_BP256R1;
-#elif defined(PSA_WANT_ECC_BRAINPOOL_P_R1_384)
-    return MBEDTLS_ECP_DP_BP384R1;
-#elif defined(PSA_WANT_ECC_BRAINPOOL_P_R1_512)
-    return MBEDTLS_ECP_DP_BP512R1;
-#elif defined(PSA_WANT_ECC_MONTGOMERY_255)
-    return MBEDTLS_ECP_DP_CURVE25519;
-#elif defined(PSA_WANT_ECC_MONTGOMERY_448)
-    return MBEDTLS_ECP_DP_CURVE448;
-#else
-    return 0;
-#endif
-}
-#endif /* defined(MBEDTLS_PSA_CRYPTO_C) && defined(MBEDTLS_PK_HAVE_ECC_KEYS) */
+typedef enum {
+    /* The values are compatible with thinking of "from pair" as a boolean. */
+    FROM_PUBLIC = 0,
+    FROM_PAIR = 1
+} from_pair_t;
 
 #if defined(MBEDTLS_PSA_CRYPTO_C)
 static int pk_setup_for_type(mbedtls_pk_type_t pk_type, int want_pair,
@@ -291,7 +384,7 @@
         case MBEDTLS_PK_ECKEY_DH:
         case MBEDTLS_PK_ECDSA:
         {
-            mbedtls_ecp_group_id grp_id = ecc_pick_grp_id();
+            mbedtls_ecp_group_id grp_id = MBEDTLS_TEST_ECP_DP_ONE_CURVE;
             size_t bits;
             *psa_type = PSA_KEY_TYPE_ECC_KEY_PAIR(mbedtls_ecc_group_to_psa(grp_id, &bits));
             TEST_EQUAL(pk_genkey(pk, grp_id), 0);
@@ -341,7 +434,7 @@
  */
 mbedtls_svc_key_id_t pk_psa_genkey_ecc(void)
 {
-    mbedtls_svc_key_id_t key;
+    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
     const psa_key_type_t type =
         PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1);
@@ -363,7 +456,7 @@
  */
 mbedtls_svc_key_id_t pk_psa_genkey_rsa(void)
 {
-    mbedtls_svc_key_id_t key;
+    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
     const psa_key_type_t type = PSA_KEY_TYPE_RSA_KEY_PAIR;
     const size_t bits = 1024;
@@ -389,7 +482,7 @@
 void pk_psa_utils(int key_is_rsa)
 {
     mbedtls_pk_context pk, pk2;
-    mbedtls_svc_key_id_t key;
+    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
 
     const char * const name = "Opaque";
@@ -427,7 +520,7 @@
     TEST_ASSERT(strcmp(mbedtls_pk_get_name(&pk), name) == 0);
 
     TEST_ASSERT(mbedtls_pk_get_bitlen(&pk) == bitlen);
-    TEST_ASSERT(mbedtls_pk_get_len(&pk) == bitlen / 8);
+    TEST_ASSERT(mbedtls_pk_get_len(&pk) == (bitlen + 7) / 8);
 
     if (key_is_rsa) {
         TEST_ASSERT(mbedtls_pk_can_do(&pk, MBEDTLS_PK_ECKEY) == 0);
@@ -681,7 +774,7 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE depends_on:MBEDTLS_PK_WRITE_C */
+/* BEGIN_CASE depends_on:MBEDTLS_PK_WRITE_C:MBEDTLS_PK_PARSE_C */
 void valid_parameters_pkwrite(data_t *key_data)
 {
     mbedtls_pk_context pk;
@@ -743,6 +836,7 @@
     mbedtls_pk_context pub, prv, alt;
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     mbedtls_svc_key_id_t opaque_key_id = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_key_attributes_t opaque_key_attr = PSA_KEY_ATTRIBUTES_INIT;
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
     mbedtls_pk_init(&pub);
@@ -780,9 +874,13 @@
 #endif
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     if (mbedtls_pk_get_type(&prv) == MBEDTLS_PK_ECKEY) {
-        TEST_EQUAL(mbedtls_pk_wrap_as_opaque(&prv, &opaque_key_id,
-                                             PSA_ALG_ANY_HASH,
-                                             PSA_KEY_USAGE_EXPORT, 0), 0);
+        /* Turn the prv PK context into an opaque one.*/
+        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&prv, PSA_KEY_USAGE_SIGN_HASH,
+                                                 &opaque_key_attr), 0);
+        TEST_EQUAL(mbedtls_pk_import_into_psa(&prv, &opaque_key_attr, &opaque_key_id), 0);
+        mbedtls_pk_free(&prv);
+        mbedtls_pk_init(&prv);
+        TEST_EQUAL(mbedtls_pk_setup_opaque(&prv, opaque_key_id), 0);
         TEST_EQUAL(mbedtls_pk_check_pair(&pub, &prv, mbedtls_test_rnd_std_rand,
                                          NULL), ret);
     }
@@ -800,9 +898,9 @@
 /* END_CASE */
 
 /* BEGIN_CASE depends_on:MBEDTLS_RSA_C */
-void pk_rsa_verify_test_vec(data_t *message_str, int digest, int mod,
-                            char *input_N, char *input_E,
-                            data_t *result_str, int result)
+void pk_rsa_verify_test_vec(data_t *message_str, int padding, int digest,
+                            int mod, char *input_N, char *input_E,
+                            data_t *result_str, int expected_result)
 {
     mbedtls_rsa_context *rsa;
     mbedtls_pk_context pk;
@@ -817,28 +915,54 @@
 #endif
 
     mbedtls_pk_init(&pk);
-    USE_PSA_INIT();
+    MD_OR_USE_PSA_INIT();
 
     TEST_ASSERT(mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) == 0);
     rsa = mbedtls_pk_rsa(pk);
 
-    rsa->len = mod / 8;
+    rsa->len = (mod + 7) / 8;
+    if (padding >= 0) {
+        TEST_EQUAL(mbedtls_rsa_set_padding(rsa, padding, MBEDTLS_MD_NONE), 0);
+    }
+
     TEST_ASSERT(mbedtls_test_read_mpi(&rsa->N, input_N) == 0);
     TEST_ASSERT(mbedtls_test_read_mpi(&rsa->E, input_E) == 0);
 
-    TEST_ASSERT(mbedtls_pk_verify(&pk, digest, message_str->x, 0,
-                                  result_str->x, mbedtls_pk_get_len(&pk)) == result);
+    int actual_result;
+    actual_result = mbedtls_pk_verify(&pk, digest, message_str->x, 0,
+                                      result_str->x, mbedtls_pk_get_len(&pk));
+#if !defined(MBEDTLS_USE_PSA_CRYPTO)
+    if (actual_result == MBEDTLS_ERR_RSA_INVALID_PADDING &&
+        expected_result == MBEDTLS_ERR_RSA_VERIFY_FAILED) {
+        /* Tolerate INVALID_PADDING error for an invalid signature with
+         * the legacy API (but not with PSA). */
+    } else
+#endif
+    {
+        TEST_EQUAL(actual_result, expected_result);
+    }
 
-    TEST_ASSERT(mbedtls_pk_verify_restartable(&pk, digest, message_str->x, 0,
-                                              result_str->x, mbedtls_pk_get_len(
-                                                  &pk), rs_ctx) == result);
+    actual_result = mbedtls_pk_verify_restartable(&pk, digest, message_str->x, 0,
+                                                  result_str->x,
+                                                  mbedtls_pk_get_len(&pk),
+                                                  rs_ctx);
+#if !defined(MBEDTLS_USE_PSA_CRYPTO)
+    if (actual_result == MBEDTLS_ERR_RSA_INVALID_PADDING &&
+        expected_result == MBEDTLS_ERR_RSA_VERIFY_FAILED) {
+        /* Tolerate INVALID_PADDING error for an invalid signature with
+         * the legacy API (but not with PSA). */
+    } else
+#endif
+    {
+        TEST_EQUAL(actual_result, expected_result);
+    }
 
 exit:
 #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
     mbedtls_pk_restart_free(rs_ctx);
 #endif
     mbedtls_pk_free(&pk);
-    USE_PSA_DONE();
+    MD_OR_USE_PSA_DONE();
 }
 /* END_CASE */
 
@@ -862,7 +986,7 @@
     TEST_ASSERT(mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) == 0);
     rsa = mbedtls_pk_rsa(pk);
 
-    rsa->len = mod / 8;
+    rsa->len = (mod + 7) / 8;
     TEST_ASSERT(mbedtls_test_read_mpi(&rsa->N, input_N) == 0);
     TEST_ASSERT(mbedtls_test_read_mpi(&rsa->E, input_E) == 0);
 
@@ -1026,8 +1150,9 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE depends_on:MBEDTLS_MD_CAN_SHA256 */
-void pk_sign_verify(int type, int curve_or_keybits, int sign_ret, int verify_ret)
+/* BEGIN_CASE depends_on:MBEDTLS_MD_CAN_SHA256:PK_CAN_SIGN_SOME */
+void pk_sign_verify(int type, int curve_or_keybits, int rsa_padding, int rsa_md_alg,
+                    int sign_ret, int verify_ret)
 {
     mbedtls_pk_context pk;
     size_t sig_len;
@@ -1055,6 +1180,15 @@
     TEST_ASSERT(mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(type)) == 0);
     TEST_ASSERT(pk_genkey(&pk, curve_or_keybits) == 0);
 
+#if defined(MBEDTLS_RSA_C)
+    if (type == MBEDTLS_PK_RSA) {
+        TEST_ASSERT(mbedtls_rsa_set_padding(mbedtls_pk_rsa(pk), rsa_padding, rsa_md_alg) == 0);
+    }
+#else
+    (void) rsa_padding;
+    (void) rsa_md_alg;
+#endif /* MBEDTLS_RSA_C */
+
     TEST_ASSERT(mbedtls_pk_sign_restartable(&pk, MBEDTLS_MD_SHA256,
                                             hash, hash_len,
                                             sig, sizeof(sig), &sig_len,
@@ -1143,7 +1277,7 @@
     rsa = mbedtls_pk_rsa(pk);
 
     /* load public key */
-    rsa->len = mod / 8;
+    rsa->len = (mod + 7) / 8;
     TEST_ASSERT(mbedtls_test_read_mpi(&rsa->N, input_N) == 0);
     TEST_ASSERT(mbedtls_test_read_mpi(&rsa->E, input_E) == 0);
 
@@ -1169,9 +1303,12 @@
     TEST_ASSERT(mbedtls_test_read_mpi(&P, input_P) == 0);
     TEST_ASSERT(mbedtls_test_read_mpi(&Q, input_Q) == 0);
     TEST_ASSERT(mbedtls_rsa_import(rsa, &N, &P, &Q, NULL, &E) == 0);
-    TEST_ASSERT(mbedtls_rsa_get_len(rsa) == (size_t) (mod / 8));
+    TEST_EQUAL(mbedtls_rsa_get_len(rsa), (mod + 7) / 8);
     TEST_ASSERT(mbedtls_rsa_complete(rsa) == 0);
 
+    TEST_EQUAL(mbedtls_pk_get_len(&pk), (mod + 7) / 8);
+    TEST_EQUAL(mbedtls_pk_get_bitlen(&pk), mod);
+
     memset(result, 0, sizeof(result));
     rlen = 0;
     TEST_ASSERT(mbedtls_pk_decrypt(&pk, output, olen,
@@ -1191,7 +1328,7 @@
 /* END_CASE */
 
 /* BEGIN_CASE depends_on:MBEDTLS_RSA_C */
-void pk_rsa_decrypt_test_vec(data_t *cipher, int mod,
+void pk_rsa_decrypt_test_vec(data_t *cipher, int mod, int padding, int md_alg,
                              char *input_P, char *input_Q,
                              char *input_N, char *input_E,
                              data_t *clear, int ret)
@@ -1206,7 +1343,7 @@
     mbedtls_pk_init(&pk);
     mbedtls_mpi_init(&N); mbedtls_mpi_init(&P);
     mbedtls_mpi_init(&Q); mbedtls_mpi_init(&E);
-    USE_PSA_INIT();
+    MD_OR_USE_PSA_INIT();
 
     memset(&rnd_info,  0, sizeof(mbedtls_test_rnd_pseudo_info));
 
@@ -1222,9 +1359,17 @@
     TEST_ASSERT(mbedtls_test_read_mpi(&P, input_P) == 0);
     TEST_ASSERT(mbedtls_test_read_mpi(&Q, input_Q) == 0);
     TEST_ASSERT(mbedtls_rsa_import(rsa, &N, &P, &Q, NULL, &E) == 0);
-    TEST_ASSERT(mbedtls_rsa_get_len(rsa) == (size_t) (mod / 8));
+    TEST_EQUAL(mbedtls_rsa_get_len(rsa), (mod + 7) / 8);
     TEST_ASSERT(mbedtls_rsa_complete(rsa) == 0);
 
+    TEST_EQUAL(mbedtls_pk_get_bitlen(&pk), mod);
+    TEST_EQUAL(mbedtls_pk_get_len(&pk), (mod + 7) / 8);
+
+    /* set padding mode */
+    if (padding >= 0) {
+        TEST_EQUAL(mbedtls_rsa_set_padding(rsa, padding, md_alg), 0);
+    }
+
     /* decryption test */
     memset(output, 0, sizeof(output));
     olen = 0;
@@ -1240,7 +1385,7 @@
     mbedtls_mpi_free(&N); mbedtls_mpi_free(&P);
     mbedtls_mpi_free(&Q); mbedtls_mpi_free(&E);
     mbedtls_pk_free(&pk);
-    USE_PSA_DONE();
+    MD_OR_USE_PSA_DONE();
 }
 /* END_CASE */
 
@@ -1255,7 +1400,8 @@
     mbedtls_mpi N, P, Q, E;
     mbedtls_rsa_context *rsa;
     mbedtls_pk_context pk;
-    mbedtls_svc_key_id_t key_id;
+    mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
     size_t olen;
 
     mbedtls_pk_init(&pk);
@@ -1278,14 +1424,17 @@
     TEST_EQUAL(mbedtls_test_read_mpi(&P, input_P), 0);
     TEST_EQUAL(mbedtls_test_read_mpi(&Q, input_Q), 0);
     TEST_EQUAL(mbedtls_rsa_import(rsa, &N, &P, &Q, NULL, &E), 0);
-    TEST_EQUAL(mbedtls_rsa_get_len(rsa), (size_t) (mod / 8));
+    TEST_EQUAL(mbedtls_rsa_get_len(rsa), (mod + 7) / 8);
     TEST_EQUAL(mbedtls_rsa_complete(rsa), 0);
 
     /* Turn PK context into an opaque one. */
-    TEST_EQUAL(mbedtls_pk_wrap_as_opaque(&pk, &key_id,
-                                         PSA_ALG_RSA_PKCS1V15_CRYPT,
-                                         PSA_KEY_USAGE_DECRYPT,
-                                         PSA_ALG_NONE), 0);
+    TEST_EQUAL(mbedtls_pk_get_psa_attributes(&pk, PSA_KEY_USAGE_DECRYPT, &key_attr), 0);
+    TEST_EQUAL(mbedtls_pk_import_into_psa(&pk, &key_attr, &key_id), 0);
+    mbedtls_pk_free(&pk);
+    mbedtls_pk_init(&pk);
+    TEST_EQUAL(mbedtls_pk_setup_opaque(&pk, key_id), 0);
+
+    TEST_EQUAL(mbedtls_pk_get_bitlen(&pk), mod);
 
     /* decryption test */
     memset(output, 0, sizeof(output));
@@ -1439,6 +1588,9 @@
                                              PSA_KEY_USAGE_ENCRYPT,
                                              &attributes),
                MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE);
+    mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
+    TEST_EQUAL(mbedtls_pk_import_into_psa(&alt, &attributes, &key_id),
+               MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE);
 #endif /* MBEDTLS_PSA_CRYPTO_C */
 
     /* Test signature */
@@ -1490,10 +1642,9 @@
     unsigned char pkey_legacy[200];
     unsigned char pkey_psa[200];
     unsigned char *pkey_legacy_start, *pkey_psa_start;
-    psa_algorithm_t alg_psa;
     size_t sig_len, klen_legacy, klen_psa;
     int ret;
-    mbedtls_svc_key_id_t key_id;
+    mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
 
     /*
@@ -1515,7 +1666,6 @@
         TEST_ASSERT(mbedtls_rsa_gen_key(mbedtls_pk_rsa(pk),
                                         mbedtls_test_rnd_std_rand, NULL,
                                         curve_or_keybits, 3) == 0);
-        alg_psa = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256);
     } else
 #endif /* MBEDTLS_RSA_C && MBEDTLS_GENPRIME */
 #if defined(MBEDTLS_PK_CAN_ECDSA_SIGN)
@@ -1526,8 +1676,6 @@
         TEST_ASSERT(mbedtls_pk_setup(&pk,
                                      mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) == 0);
         TEST_ASSERT(pk_genkey(&pk, grpid) == 0);
-
-        alg_psa = PSA_ALG_ECDSA(PSA_ALG_SHA_256);
     } else
 #endif /* MBEDTLS_PK_CAN_ECDSA_SIGN */
     {
@@ -1554,9 +1702,11 @@
 #endif /* MBEDTLS_PK_WRITE_C */
 
     /* Turn PK context into an opaque one. */
-    TEST_ASSERT(mbedtls_pk_wrap_as_opaque(&pk, &key_id, alg_psa,
-                                          PSA_KEY_USAGE_SIGN_HASH,
-                                          PSA_ALG_NONE) == 0);
+    TEST_EQUAL(mbedtls_pk_get_psa_attributes(&pk, PSA_KEY_USAGE_SIGN_HASH, &attributes), 0);
+    TEST_EQUAL(mbedtls_pk_import_into_psa(&pk, &attributes, &key_id), 0);
+    mbedtls_pk_free(&pk);
+    mbedtls_pk_init(&pk);
+    TEST_EQUAL(mbedtls_pk_setup_opaque(&pk, key_id), 0);
 
     PSA_ASSERT(psa_get_key_attributes(key_id, &attributes));
     TEST_EQUAL(psa_get_key_type(&attributes), (psa_key_type_t) psa_type);
@@ -1676,13 +1826,13 @@
 {
     mbedtls_pk_context pk;
     size_t sig_len, pkey_len;
-    mbedtls_svc_key_id_t key_id;
+    mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
     unsigned char sig[MBEDTLS_PK_SIGNATURE_MAX_SIZE];
     unsigned char pkey[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
     unsigned char *pkey_start;
     unsigned char hash[PSA_HASH_MAX_SIZE];
     psa_algorithm_t psa_md_alg = mbedtls_md_psa_alg_from_type(md_alg);
-    psa_algorithm_t psa_alg;
     size_t hash_len = PSA_HASH_LENGTH(psa_md_alg);
     void const *options = NULL;
     mbedtls_pk_rsassa_pss_options rsassa_pss_options;
@@ -1699,6 +1849,10 @@
                                    mbedtls_test_rnd_std_rand, NULL,
                                    key_bits, 3), 0);
 
+    if (key_pk_type == MBEDTLS_PK_RSASSA_PSS) {
+        mbedtls_rsa_set_padding(mbedtls_pk_rsa(pk), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_NONE);
+    }
+
     /* Export underlying public key for re-importing in a legacy context. */
     ret = mbedtls_pk_write_pubkey_der(&pk, pkey, sizeof(pkey));
     TEST_ASSERT(ret >= 0);
@@ -1707,18 +1861,12 @@
     /* mbedtls_pk_write_pubkey_der() writes backwards in the data buffer. */
     pkey_start = pkey + sizeof(pkey) - pkey_len;
 
-    if (key_pk_type == MBEDTLS_PK_RSA) {
-        psa_alg = PSA_ALG_RSA_PKCS1V15_SIGN(psa_md_alg);
-    } else if (key_pk_type == MBEDTLS_PK_RSASSA_PSS) {
-        psa_alg = PSA_ALG_RSA_PSS(psa_md_alg);
-    } else {
-        TEST_ASSUME(!"PK key type not supported in this configuration");
-    }
-
     /* Turn PK context into an opaque one. */
-    TEST_EQUAL(mbedtls_pk_wrap_as_opaque(&pk, &key_id, psa_alg,
-                                         PSA_KEY_USAGE_SIGN_HASH,
-                                         PSA_ALG_NONE), 0);
+    TEST_EQUAL(mbedtls_pk_get_psa_attributes(&pk, PSA_KEY_USAGE_SIGN_HASH, &key_attr), 0);
+    TEST_EQUAL(mbedtls_pk_import_into_psa(&pk, &key_attr, &key_id), 0);
+    mbedtls_pk_free(&pk);
+    mbedtls_pk_init(&pk);
+    TEST_EQUAL(mbedtls_pk_setup_opaque(&pk, key_id), 0);
 
     memset(hash, 0x2a, sizeof(hash));
     memset(sig, 0, sizeof(sig));
@@ -1757,6 +1905,7 @@
     mbedtls_pk_init(&pk);
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
     psa_key_usage_t usage = usage_arg;
+    mbedtls_svc_key_id_t new_key_id = MBEDTLS_SVC_KEY_ID_INIT;
 
     PSA_INIT();
 
@@ -1797,9 +1946,15 @@
     TEST_EQUAL(psa_get_key_algorithm(&attributes), expected_alg);
     TEST_EQUAL(psa_get_key_enrollment_algorithm(&attributes), PSA_ALG_NONE);
 
+    TEST_EQUAL(mbedtls_pk_import_into_psa(&pk, &attributes, &new_key_id), 0);
+    if (!mbedtls_test_key_consistency_psa_pk(new_key_id, &pk)) {
+        goto exit;
+    }
+
 exit:
     mbedtls_pk_free(&pk);
     psa_reset_key_attributes(&attributes);
+    psa_destroy_key(new_key_id);
     PSA_DONE();
 }
 /* END_CASE */
@@ -1813,6 +1968,7 @@
     mbedtls_pk_init(&pk);
     psa_key_usage_t usage = usage_arg;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    mbedtls_svc_key_id_t new_key_id = MBEDTLS_SVC_KEY_ID_INIT;
 
     PSA_INIT();
 
@@ -1838,9 +1994,15 @@
     TEST_EQUAL(psa_get_key_algorithm(&attributes), expected_alg);
     TEST_EQUAL(psa_get_key_enrollment_algorithm(&attributes), PSA_ALG_NONE);
 
+    TEST_EQUAL(mbedtls_pk_import_into_psa(&pk, &attributes, &new_key_id), 0);
+    if (!mbedtls_test_key_consistency_psa_pk(new_key_id, &pk)) {
+        goto exit;
+    }
+
 exit:
     mbedtls_pk_free(&pk);
     psa_reset_key_attributes(&attributes);
+    psa_destroy_key(new_key_id);
     PSA_DONE();
 }
 /* END_CASE */
@@ -1881,13 +2043,14 @@
     mbedtls_pk_context pk;
     mbedtls_pk_init(&pk);
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-    mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
+    mbedtls_svc_key_id_t old_key_id = MBEDTLS_SVC_KEY_ID_INIT;
     psa_key_type_t from_type = from_type_arg;
     size_t bits = from_bits_arg;
     psa_key_usage_t from_usage = from_usage_arg;
     psa_algorithm_t alg = from_alg_arg;
     psa_key_usage_t usage = usage_arg;
     psa_key_usage_t expected_usage = expected_usage_arg;
+    mbedtls_svc_key_id_t new_key_id = MBEDTLS_SVC_KEY_ID_INIT;
 
     PSA_INIT();
 
@@ -1897,8 +2060,8 @@
     psa_set_key_algorithm(&attributes, alg);
     psa_set_key_enrollment_algorithm(&attributes, 42);
     //TODO: test with persistent key
-    PSA_ASSERT(psa_generate_key(&attributes, &key_id));
-    TEST_EQUAL(mbedtls_pk_setup_opaque(&pk, key_id), 0);
+    PSA_ASSERT(psa_generate_key(&attributes, &old_key_id));
+    TEST_EQUAL(mbedtls_pk_setup_opaque(&pk, old_key_id), 0);
 
     psa_key_type_t expected_psa_type =
         to_pair ? from_type : PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(from_type);
@@ -1915,12 +2078,124 @@
         TEST_EQUAL(psa_get_key_usage_flags(&attributes), expected_usage);
         TEST_EQUAL(psa_get_key_algorithm(&attributes), alg);
         TEST_EQUAL(psa_get_key_enrollment_algorithm(&attributes), PSA_ALG_NONE);
+
+        int expected_import_ret = 0;
+        if (to_pair &&
+            !(from_usage & (PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_EXPORT))) {
+            expected_import_ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
+        }
+        TEST_EQUAL(mbedtls_pk_import_into_psa(&pk, &attributes, &new_key_id),
+                   expected_import_ret);
+        if (expected_import_ret == 0) {
+            if (!mbedtls_test_key_consistency_psa_pk(new_key_id, &pk)) {
+                goto exit;
+            }
+        }
     }
 
 exit:
     mbedtls_pk_free(&pk);
-    psa_destroy_key(key_id);
+    psa_destroy_key(old_key_id);
+    psa_destroy_key(new_key_id);
     psa_reset_key_attributes(&attributes);
     PSA_DONE();
 }
 /* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C */
+void pk_import_into_psa_fail(int pk_type, int from_pair,
+                             int type_arg, int bits_arg,
+                             int expected_ret)
+{
+    mbedtls_pk_context pk;
+    mbedtls_pk_init(&pk);
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_type_t type = type_arg;
+    size_t bits = bits_arg;
+    mbedtls_svc_key_id_t key_id = mbedtls_svc_key_id_make(0, 42);
+
+    PSA_INIT();
+
+    psa_key_type_t expected_psa_type;
+    TEST_EQUAL(pk_setup_for_type(pk_type, from_pair,
+                                 &pk, &expected_psa_type), 0);
+
+    psa_set_key_type(&attributes, type);
+    psa_set_key_bits(&attributes, bits);
+
+    TEST_EQUAL(mbedtls_pk_import_into_psa(&pk, &attributes, &key_id),
+               expected_ret);
+    TEST_ASSERT(mbedtls_svc_key_id_equal(key_id, MBEDTLS_SVC_KEY_ID_INIT));
+
+exit:
+    psa_destroy_key(key_id);
+    mbedtls_pk_free(&pk);
+    psa_reset_key_attributes(&attributes);
+    PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_USE_PSA_CRYPTO */
+void pk_import_into_psa_opaque(int from_type, int from_bits,
+                               int from_usage, int from_alg,
+                               int to_type, int to_bits,
+                               int to_usage, int to_alg,
+                               int expected_ret)
+{
+    mbedtls_pk_context pk;
+    mbedtls_pk_init(&pk);
+    psa_key_attributes_t from_attributes = PSA_KEY_ATTRIBUTES_INIT;
+    mbedtls_svc_key_id_t from_key_id = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_key_attributes_t to_attributes = PSA_KEY_ATTRIBUTES_INIT;
+    mbedtls_svc_key_id_t to_key_id = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_key_attributes_t actual_attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+    PSA_INIT();
+
+    psa_set_key_type(&from_attributes, from_type);
+    psa_set_key_bits(&from_attributes, from_bits);
+    psa_set_key_usage_flags(&from_attributes, from_usage);
+    psa_set_key_algorithm(&from_attributes, from_alg);
+    PSA_ASSERT(psa_generate_key(&from_attributes, &from_key_id));
+    TEST_EQUAL(mbedtls_pk_setup_opaque(&pk, from_key_id), 0);
+
+    psa_set_key_type(&to_attributes, to_type);
+    psa_set_key_bits(&to_attributes, to_bits);
+    psa_set_key_usage_flags(&to_attributes, to_usage);
+    psa_set_key_algorithm(&to_attributes, to_alg);
+
+    TEST_EQUAL(mbedtls_pk_import_into_psa(&pk, &to_attributes, &to_key_id),
+               expected_ret);
+
+    if (expected_ret == 0) {
+        PSA_ASSERT(psa_get_key_attributes(to_key_id, &actual_attributes));
+        TEST_EQUAL(to_type, psa_get_key_type(&actual_attributes));
+        if (to_bits != 0) {
+            TEST_EQUAL(to_bits, psa_get_key_bits(&actual_attributes));
+        }
+        TEST_EQUAL(to_alg, psa_get_key_algorithm(&actual_attributes));
+        psa_key_usage_t expected_usage = to_usage;
+        if (expected_usage & PSA_KEY_USAGE_SIGN_HASH) {
+            expected_usage |= PSA_KEY_USAGE_SIGN_MESSAGE;
+        }
+        if (expected_usage & PSA_KEY_USAGE_VERIFY_HASH) {
+            expected_usage |= PSA_KEY_USAGE_VERIFY_MESSAGE;
+        }
+        TEST_EQUAL(expected_usage, psa_get_key_usage_flags(&actual_attributes));
+        if (!mbedtls_test_key_consistency_psa_pk(to_key_id, &pk)) {
+            goto exit;
+        }
+    } else {
+        TEST_ASSERT(mbedtls_svc_key_id_equal(to_key_id, MBEDTLS_SVC_KEY_ID_INIT));
+    }
+
+exit:
+    mbedtls_pk_free(&pk);
+    psa_destroy_key(from_key_id);
+    psa_destroy_key(to_key_id);
+    psa_reset_key_attributes(&from_attributes);
+    psa_reset_key_attributes(&to_attributes);
+    psa_reset_key_attributes(&actual_attributes);
+    PSA_DONE();
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_pkparse.data b/tests/suites/test_suite_pkparse.data
index 707da7f..1650f51 100644
--- a/tests/suites/test_suite_pkparse.data
+++ b/tests/suites/test_suite_pkparse.data
@@ -914,6 +914,22 @@
 depends_on:MBEDTLS_AES_C:MBEDTLS_MD_CAN_SHA384:MBEDTLS_PKCS5_C:MBEDTLS_CIPHER_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH
 pk_parse_keyfile_rsa:"data_files/rsa_pkcs8_pbes2_pbkdf2_2048_aes256cbc_sha384.der":"PolarSSLTest":0
 
+Parse RSA Key #100.1 (512-bit)
+depends_on:MBEDTLS_PEM_C
+pk_parse_keyfile_rsa:"data_files/rsa512.key":"":0
+
+Parse RSA Key #100.1 (521-bit)
+depends_on:MBEDTLS_PEM_C
+pk_parse_keyfile_rsa:"data_files/rsa521.key":"":0
+
+Parse RSA Key #100.1 (522-bit)
+depends_on:MBEDTLS_PEM_C
+pk_parse_keyfile_rsa:"data_files/rsa522.key":"":0
+
+Parse RSA Key #100.1 (528-bit)
+depends_on:MBEDTLS_PEM_C
+pk_parse_keyfile_rsa:"data_files/rsa528.key":"":0
+
 Parse Public RSA Key #1 (PKCS#8 wrapped)
 depends_on:MBEDTLS_PEM_PARSE_C
 pk_parse_public_keyfile_rsa:"data_files/rsa_pkcs8_2048_public.pem":0
diff --git a/tests/suites/test_suite_pkparse.function b/tests/suites/test_suite_pkparse.function
index 14afef6..7dc8413 100644
--- a/tests/suites/test_suite_pkparse.function
+++ b/tests/suites/test_suite_pkparse.function
@@ -6,10 +6,91 @@
 #include "mbedtls/psa_util.h"
 #include "pk_internal.h"
 
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+#include "test/psa_exercise_key.h"
+#endif
+
 #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C)
 #define HAVE_mbedtls_pk_parse_key_pkcs8_encrypted_der
 #endif
 
+#if defined(MBEDTLS_PSA_CRYPTO_C) && defined(MBEDTLS_FS_IO)
+static int test_psa_bridge(const mbedtls_pk_context *ctx,
+                           psa_key_usage_t usage_flag)
+{
+    switch (usage_flag) {
+        case PSA_KEY_USAGE_SIGN_HASH:
+            mbedtls_test_set_step(0);
+            break;
+        case PSA_KEY_USAGE_SIGN_MESSAGE:
+            mbedtls_test_set_step(1);
+            break;
+        case PSA_KEY_USAGE_DECRYPT:
+            mbedtls_test_set_step(2);
+            break;
+        case PSA_KEY_USAGE_DERIVE:
+            mbedtls_test_set_step(3);
+            break;
+        case PSA_KEY_USAGE_VERIFY_HASH:
+            mbedtls_test_set_step(4);
+            break;
+        case PSA_KEY_USAGE_VERIFY_MESSAGE:
+            mbedtls_test_set_step(5);
+            break;
+        case PSA_KEY_USAGE_ENCRYPT:
+            mbedtls_test_set_step(6);
+            break;
+    }
+
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    mbedtls_svc_key_id_t psa_key = MBEDTLS_SVC_KEY_ID_INIT;
+    int ok = 0;
+
+    TEST_EQUAL(mbedtls_pk_get_psa_attributes(ctx, usage_flag, &attributes), 0);
+    TEST_EQUAL(mbedtls_pk_import_into_psa(ctx, &attributes, &psa_key), 0);
+    if (!mbedtls_test_key_consistency_psa_pk(psa_key, ctx)) {
+        goto exit;
+    }
+
+    psa_algorithm_t exercise_usage = psa_get_key_usage_flags(&attributes);
+    psa_algorithm_t exercise_alg = psa_get_key_algorithm(&attributes);
+    if (mbedtls_test_can_exercise_psa_algorithm(exercise_alg)) {
+        TEST_ASSERT(mbedtls_test_psa_exercise_key(psa_key,
+                                                  exercise_usage,
+                                                  exercise_alg));
+    }
+
+    mbedtls_test_set_step((unsigned long) -1);
+    ok = 1;
+
+exit:
+    psa_destroy_key(psa_key);
+    psa_reset_key_attributes(&attributes);
+    return ok;
+}
+
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
+/* Whether a pk key can do ECDSA. Opaque keys are not supported since this
+ * test suite does not create opaque keys. */
+static int pk_can_ecdsa(const mbedtls_pk_context *ctx)
+{
+    /* Check whether we have an EC key. Unfortunately this also accepts
+     * keys on Montgomery curves, which can only do ECDH, so we'll have
+     * to dig further. */
+    if (!mbedtls_pk_can_do(ctx, MBEDTLS_PK_ECDSA)) {
+        return 0;
+    }
+#if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
+    return ctx->ec_family != PSA_ECC_FAMILY_MONTGOMERY;
+#elif defined(MBEDTLS_ECDSA_C)
+    return mbedtls_ecdsa_can_do(mbedtls_pk_ec_ro(*ctx)->grp.id);
+#else
+    return 0;
+#endif
+}
+#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
+#endif /* MBEDTLS_PSA_CRYPTO_C &&  && MBEDTLS_FS_IO */
+
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -42,37 +123,24 @@
         rsa = mbedtls_pk_rsa(ctx);
         TEST_EQUAL(mbedtls_rsa_check_privkey(rsa), 0);
 
+        size_t bitlen = mbedtls_rsa_get_bitlen(rsa);
+        TEST_EQUAL(mbedtls_pk_get_bitlen(&ctx), bitlen);
+        TEST_EQUAL(mbedtls_pk_get_len(&ctx), (bitlen + 7) / 8);
+
 #if defined(MBEDTLS_PSA_CRYPTO_C)
-        psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&ctx,
-                                                 PSA_KEY_USAGE_SIGN_HASH,
-                                                 &attributes), 0);
-        psa_reset_key_attributes(&attributes);
-        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&ctx,
-                                                 PSA_KEY_USAGE_SIGN_MESSAGE,
-                                                 &attributes), 0);
-        psa_reset_key_attributes(&attributes);
-        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&ctx,
-                                                 PSA_KEY_USAGE_DECRYPT,
-                                                 &attributes), 0);
-        psa_reset_key_attributes(&attributes);
-        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&ctx,
-                                                 PSA_KEY_USAGE_VERIFY_HASH,
-                                                 &attributes), 0);
-        psa_reset_key_attributes(&attributes);
-        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&ctx,
-                                                 PSA_KEY_USAGE_VERIFY_MESSAGE,
-                                                 &attributes), 0);
-        psa_reset_key_attributes(&attributes);
-        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&ctx,
-                                                 PSA_KEY_USAGE_ENCRYPT,
-                                                 &attributes), 0);
+        PSA_INIT();
+        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_SIGN_HASH));
+        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_SIGN_MESSAGE));
+        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_DECRYPT));
+        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_VERIFY_HASH));
+        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_VERIFY_MESSAGE));
+        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_ENCRYPT));
 #endif
     }
 
 exit:
     mbedtls_pk_free(&ctx);
-    MD_PSA_DONE();
+    PSA_DONE();
 }
 
 /* END_CASE */
@@ -96,25 +164,21 @@
         rsa = mbedtls_pk_rsa(ctx);
         TEST_EQUAL(mbedtls_rsa_check_pubkey(rsa), 0);
 
+        size_t bitlen = mbedtls_rsa_get_bitlen(rsa);
+        TEST_EQUAL(mbedtls_pk_get_bitlen(&ctx), bitlen);
+        TEST_EQUAL(mbedtls_pk_get_len(&ctx), (bitlen + 7) / 8);
+
 #if defined(MBEDTLS_PSA_CRYPTO_C)
-        psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&ctx,
-                                                 PSA_KEY_USAGE_ENCRYPT,
-                                                 &attributes), 0);
-        psa_reset_key_attributes(&attributes);
-        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&ctx,
-                                                 PSA_KEY_USAGE_VERIFY_HASH,
-                                                 &attributes), 0);
-        psa_reset_key_attributes(&attributes);
-        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&ctx,
-                                                 PSA_KEY_USAGE_VERIFY_MESSAGE,
-                                                 &attributes), 0);
+        PSA_INIT();
+        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_VERIFY_HASH));
+        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_VERIFY_MESSAGE));
+        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_ENCRYPT));
 #endif
     }
 
 exit:
     mbedtls_pk_free(&ctx);
-    MD_PSA_DONE();
+    PSA_DONE();
 }
 /* END_CASE */
 
@@ -144,20 +208,17 @@
 #endif
 
 #if defined(MBEDTLS_PSA_CRYPTO_C)
-        psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&ctx,
-                                                 PSA_KEY_USAGE_VERIFY_HASH,
-                                                 &attributes), 0);
-        psa_reset_key_attributes(&attributes);
-        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&ctx,
-                                                 PSA_KEY_USAGE_VERIFY_MESSAGE,
-                                                 &attributes), 0);
+        PSA_INIT();
+        if (pk_can_ecdsa(&ctx)) {
+            TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_VERIFY_HASH));
+            TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_VERIFY_MESSAGE));
+        }
 #endif
     }
 
 exit:
     mbedtls_pk_free(&ctx);
-    MD_OR_USE_PSA_DONE();
+    PSA_DONE();
 }
 /* END_CASE */
 
@@ -185,32 +246,20 @@
 #endif
 
 #if defined(MBEDTLS_PSA_CRYPTO_C)
-        psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&ctx,
-                                                 PSA_KEY_USAGE_SIGN_HASH,
-                                                 &attributes), 0);
-        psa_reset_key_attributes(&attributes);
-        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&ctx,
-                                                 PSA_KEY_USAGE_SIGN_MESSAGE,
-                                                 &attributes), 0);
-        psa_reset_key_attributes(&attributes);
-        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&ctx,
-                                                 PSA_KEY_USAGE_DERIVE,
-                                                 &attributes), 0);
-        psa_reset_key_attributes(&attributes);
-        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&ctx,
-                                                 PSA_KEY_USAGE_VERIFY_HASH,
-                                                 &attributes), 0);
-        psa_reset_key_attributes(&attributes);
-        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&ctx,
-                                                 PSA_KEY_USAGE_VERIFY_MESSAGE,
-                                                 &attributes), 0);
+        PSA_INIT();
+        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_DERIVE));
+        if (pk_can_ecdsa(&ctx)) {
+            TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_SIGN_HASH));
+            TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_SIGN_MESSAGE));
+            TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_VERIFY_HASH));
+            TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_VERIFY_MESSAGE));
+        }
 #endif
     }
 
 exit:
     mbedtls_pk_free(&ctx);
-    MD_OR_USE_PSA_DONE();
+    PSA_DONE();
 }
 /* END_CASE */
 
diff --git a/tests/suites/test_suite_pkwrite.function b/tests/suites/test_suite_pkwrite.function
index c760090..735c125 100644
--- a/tests/suites/test_suite_pkwrite.function
+++ b/tests/suites/test_suite_pkwrite.function
@@ -75,6 +75,7 @@
     size_t buf_len, check_buf_len;
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     mbedtls_svc_key_id_t opaque_id = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
     USE_PSA_INIT();
@@ -117,10 +118,13 @@
     /* Verify that pk_write works also for opaque private keys */
     if (!is_public_key) {
         memset(buf, 0, check_buf_len);
-        TEST_EQUAL(mbedtls_pk_wrap_as_opaque(&key, &opaque_id,
-                                             PSA_ALG_NONE,
-                                             PSA_KEY_USAGE_EXPORT,
-                                             PSA_ALG_NONE), 0);
+        /* Turn the key PK context into an opaque one.
+         * Note: set some practical usage for the key to make get_psa_attributes() happy. */
+        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&key, PSA_KEY_USAGE_SIGN_MESSAGE, &key_attr), 0);
+        TEST_EQUAL(mbedtls_pk_import_into_psa(&key, &key_attr, &opaque_id), 0);
+        mbedtls_pk_free(&key);
+        mbedtls_pk_init(&key);
+        TEST_EQUAL(mbedtls_pk_setup_opaque(&key, opaque_id), 0);
         start_buf = buf;
         buf_len = check_buf_len;
         TEST_EQUAL(pk_write_any_key(&key, &start_buf, &buf_len, is_public_key,
@@ -172,6 +176,7 @@
     size_t pub_key_len = 0;
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     mbedtls_svc_key_id_t opaque_key_id = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
     mbedtls_pk_init(&priv_key);
@@ -194,9 +199,12 @@
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     mbedtls_platform_zeroize(derived_key_raw, derived_key_len);
 
-    TEST_EQUAL(mbedtls_pk_wrap_as_opaque(&priv_key, &opaque_key_id,
-                                         PSA_ALG_NONE, PSA_KEY_USAGE_EXPORT,
-                                         PSA_ALG_NONE), 0);
+    /* Turn the priv_key PK context into an opaque one. */
+    TEST_EQUAL(mbedtls_pk_get_psa_attributes(&priv_key, PSA_KEY_USAGE_SIGN_HASH, &key_attr), 0);
+    TEST_EQUAL(mbedtls_pk_import_into_psa(&priv_key, &key_attr, &opaque_key_id), 0);
+    mbedtls_pk_free(&priv_key);
+    mbedtls_pk_init(&priv_key);
+    TEST_EQUAL(mbedtls_pk_setup_opaque(&priv_key, opaque_key_id), 0);
 
     TEST_EQUAL(mbedtls_pk_write_pubkey_der(&priv_key, derived_key_raw,
                                            derived_key_len), pub_key_len);
diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data
index 34af94a..b633c6f 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -104,9 +104,9 @@
 depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT
 import_export:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:0:1024:-1:PSA_ERROR_BUFFER_TOO_SMALL:1
 
-PSA import/export RSA keypair: trailing garbage ignored
+PSA import/export RSA keypair: trailing garbage rejected
 depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT
-import_export:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b2400":PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:0:1024:-1:PSA_SUCCESS:0
+import_with_data:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b2400":PSA_KEY_TYPE_RSA_KEY_PAIR:1024:PSA_ERROR_INVALID_ARGUMENT
 
 PSA import/export RSA public key: good, 1024-bit, opaque
 depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY:PSA_CRYPTO_DRIVER_TEST
@@ -156,9 +156,9 @@
 depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT:PSA_CRYPTO_DRIVER_TEST
 import_export:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( PSA_KEY_PERSISTENCE_VOLATILE, TEST_DRIVER_LOCATION ):1024:-1:PSA_ERROR_BUFFER_TOO_SMALL:1
 
-PSA import/export RSA keypair: trailing garbage ignored, opaque
+PSA import/export RSA keypair: trailing garbage rejected, opaque
 depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT:PSA_CRYPTO_DRIVER_TEST
-import_export:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b2400":PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( PSA_KEY_PERSISTENCE_VOLATILE, TEST_DRIVER_LOCATION ):1024:-1:PSA_SUCCESS:0
+import_with_data:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b2400":PSA_KEY_TYPE_RSA_KEY_PAIR:1024:PSA_ERROR_INVALID_ARGUMENT
 
 PSA import RSA keypair: truncated
 depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT
@@ -6870,6 +6870,18 @@
 depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH
 derive_key_type:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:"706173737764":"01":"73616c74":PSA_KEY_TYPE_AES:256:"28e288c6345bb5ecf7ca70274208a3ba0f1148b5868537d5e09d3ee6813b1f52"
 
+PSA key derivation: default params -> AES-128
+depends_on:PSA_WANT_ALG_HKDF:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_AES
+derive_key_ext:PSA_ALG_HKDF(PSA_ALG_SHA_256):"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":"000102030405060708090a0b0c":"f0f1f2f3f4f5f6f7f8f9":PSA_KEY_TYPE_AES:128:0:"":PSA_SUCCESS:"3cb25f25faacd57a90434f64d0362f2a"
+
+PSA key derivation: params.flags=1 -> AES-128
+depends_on:PSA_WANT_ALG_HKDF:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_AES
+derive_key_ext:PSA_ALG_HKDF(PSA_ALG_SHA_256):"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":"000102030405060708090a0b0c":"f0f1f2f3f4f5f6f7f8f9":PSA_KEY_TYPE_AES:128:1:"":PSA_ERROR_INVALID_ARGUMENT:""
+
+PSA key derivation: params.data non-empty -> AES-128
+depends_on:PSA_WANT_ALG_HKDF:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_AES
+derive_key_ext:PSA_ALG_HKDF(PSA_ALG_SHA_256):"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":"000102030405060708090a0b0c":"f0f1f2f3f4f5f6f7f8f9":PSA_KEY_TYPE_AES:128:0:"2a":PSA_ERROR_INVALID_ARGUMENT:""
+
 PSA key derivation: invalid type (0)
 depends_on:PSA_WANT_ALG_HKDF:PSA_WANT_ALG_SHA_256
 derive_key:PSA_ALG_HKDF(PSA_ALG_SHA_256):"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":"000102030405060708090a0b0c":"f0f1f2f3f4f5f6f7f8f9":PSA_KEY_TYPE_NONE:128:PSA_ERROR_NOT_SUPPORTED:0
@@ -7419,24 +7431,6 @@
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:PSA_WANT_ECC_MONTGOMERY_448
 generate_key:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):448:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_DERIVE:PSA_ALG_ECDH:PSA_SUCCESS:0
 
-PSA generate key: RSA, default e
-generate_key_rsa:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:"":PSA_SUCCESS
-
-PSA generate key: RSA, e=3
-generate_key_rsa:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:"03":PSA_SUCCESS
-
-PSA generate key: RSA, e=65537
-generate_key_rsa:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:"010001":PSA_SUCCESS
-
-PSA generate key: RSA, e=513
-generate_key_rsa:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:"0201":PSA_SUCCESS
-
-PSA generate key: RSA, e=1
-generate_key_rsa:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:"01":PSA_ERROR_INVALID_ARGUMENT
-
-PSA generate key: RSA, e=2
-generate_key_rsa:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:"02":PSA_ERROR_INVALID_ARGUMENT
-
 PSA generate key: FFDH, 2048 bits, good
 depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE:PSA_WANT_DH_RFC7919_2048
 generate_key:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):2048:PSA_KEY_USAGE_EXPORT:PSA_ALG_FFDH:PSA_SUCCESS:0
@@ -7461,6 +7455,230 @@
 depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE
 generate_key:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):1024:PSA_KEY_USAGE_EXPORT:PSA_ALG_FFDH:PSA_ERROR_NOT_SUPPORTED:0
 
+PSA generate key ext: RSA, params.flags=1
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE
+generate_key_ext:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:0:1:"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA generate key ext: RSA, empty e
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT
+generate_key_ext:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_RSA_PKCS1V15_CRYPT:0:"":PSA_SUCCESS
+
+PSA generate key ext: RSA, e=3
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT
+generate_key_ext:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_RSA_PKCS1V15_CRYPT:0:"03":PSA_SUCCESS
+
+PSA generate key ext: RSA, e=3 with leading zeros
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT
+generate_key_ext:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_RSA_PKCS1V15_CRYPT:0:"000003":PSA_SUCCESS
+
+# TODO: currently errors with NOT_SUPPORTED because e is converted to an int
+# and the conversion errors out if there are too many digits without checking
+# for leading zeros. This is a very minor bug. Re-enable this test when this
+# bug is fixed.
+#PSA generate key ext: RSA, e=3 with many leading zeros
+#depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT
+#generate_key_ext:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_RSA_PKCS1V15_CRYPT:0:"0000000000000000000000000000000003":PSA_SUCCESS
+
+PSA generate key ext: RSA, e=513
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT
+generate_key_ext:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_RSA_PKCS1V15_CRYPT:0:"0201":PSA_SUCCESS
+
+PSA generate key ext: RSA, e=65537
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT
+generate_key_ext:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_RSA_PKCS1V15_CRYPT:0:"010001":PSA_SUCCESS
+
+PSA generate key ext: RSA, e=2^31-1
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT:INT_MAX>=0x7fffffff
+generate_key_ext:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_RSA_PKCS1V15_CRYPT:0:"7fffffff":PSA_SUCCESS
+
+PSA generate key ext: RSA, e=2^31+3 (too large for built-in RSA)
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE:!MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_KEY_PAIR_GENERATE:INT_MAX<=0x7fffffff
+generate_key_ext:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:0:0:"80000003":PSA_ERROR_NOT_SUPPORTED
+
+PSA generate key ext: RSA, e=2^64+3 (too large for built-in RSA)
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE:!MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_KEY_PAIR_GENERATE:INT_MAX<=0xffffffffffffffff
+generate_key_ext:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:0:0:"010000000000000003":PSA_ERROR_NOT_SUPPORTED
+
+PSA generate key ext: RSA, e=1
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE
+generate_key_ext:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:0:0:"01":PSA_ERROR_INVALID_ARGUMENT
+
+PSA generate key ext: RSA, e=0
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE
+generate_key_ext:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:0:0:"00":PSA_ERROR_INVALID_ARGUMENT
+
+PSA generate key ext: RSA, e=2
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE
+generate_key_ext:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:0:0:"02":PSA_ERROR_INVALID_ARGUMENT
+
+# Check that with a driver, we reject a custom e as unsupported,
+# as opposed to silently using the default e.
+# When we add proper driver support, remove this test case and remove
+# the dependency on MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE from
+# the positive/invalid_argument test cases.
+PSA generate key ext: RSA, e=3 with driver and no fallback (not yet supported)
+depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:!MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE
+generate_key_ext:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:0:0:"03":PSA_ERROR_NOT_SUPPORTED
+
+PSA generate key ext: ECC, flags=0
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_ECDH
+generate_key_ext:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):256:PSA_KEY_USAGE_DERIVE:PSA_ALG_ECDH:0:"":PSA_SUCCESS
+
+PSA generate key ext: ECC, flags=1
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_ECDH
+generate_key_ext:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):256:PSA_KEY_USAGE_DERIVE:PSA_ALG_ECDH:1:"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA generate key ext: ECC, params.data non-empty
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_ECDH
+generate_key_ext:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):256:PSA_KEY_USAGE_DERIVE:PSA_ALG_ECDH:0:"2a":PSA_ERROR_INVALID_ARGUMENT
+
+PSA concurrent key generation: bad type (RSA public key)
+depends_on:PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_RSA_PUBLIC_KEY:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:PSA_KEY_USAGE_EXPORT:0:PSA_ERROR_INVALID_ARGUMENT:0:8:5
+
+PSA concurrent key generation: raw data, 0 bits: invalid argument
+depends_on:MBEDTLS_THREADING_PTHREAD
+# The spec allows either INVALID_ARGUMENT or NOT_SUPPORTED
+concurrently_generate_keys:PSA_KEY_TYPE_RAW_DATA:0:PSA_KEY_USAGE_EXPORT:0:PSA_ERROR_INVALID_ARGUMENT:0:8:5
+
+PSA concurrent key generation: raw data, 7 bits: invalid argument
+depends_on:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_RAW_DATA:7:PSA_KEY_USAGE_EXPORT:0:PSA_ERROR_INVALID_ARGUMENT:0:8:5
+
+PSA concurrent key generation: raw data, 8 bits
+depends_on:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_RAW_DATA:8:PSA_KEY_USAGE_EXPORT:0:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation- raw data, 9 bits: invalid argument
+depends_on:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_RAW_DATA:9:PSA_KEY_USAGE_EXPORT:0:PSA_ERROR_INVALID_ARGUMENT:0:8:5
+
+PSA concurrent key generation: raw data, (MBEDTLS_CTR_DRBG_MAX_REQUEST + 1) * 8 bits
+depends_on:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_RAW_DATA:(MBEDTLS_CTR_DRBG_MAX_REQUEST + 1) * 8:PSA_KEY_USAGE_EXPORT:0:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: raw data, (2 * MBEDTLS_CTR_DRBG_MAX_REQUEST + 1) * 8 bits
+depends_on:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_RAW_DATA:(2 * MBEDTLS_CTR_DRBG_MAX_REQUEST + 1) * 8:PSA_KEY_USAGE_EXPORT:0:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: raw data, 65528 bits (large key, ok if it fits)
+depends_on:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_RAW_DATA:65528:PSA_KEY_USAGE_EXPORT:0:PSA_SUCCESS:1:8:5
+
+PSA concurrent key generation: raw data, 65536 bits (not supported)
+depends_on:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_RAW_DATA:65536:PSA_KEY_USAGE_EXPORT:0:PSA_ERROR_NOT_SUPPORTED:0:8:5
+
+PSA concurrent key generation: AES, 128 bits, CTR
+depends_on:PSA_WANT_ALG_CTR:PSA_WANT_KEY_TYPE_AES:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_AES:128:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_CTR:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: AES, 128 bits, GCM
+depends_on:PSA_WANT_ALG_GCM:PSA_WANT_KEY_TYPE_AES:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_AES:128:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_GCM:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: DES, 64 bits, CBC-nopad
+depends_on:PSA_WANT_ALG_CBC_NO_PADDING:PSA_WANT_KEY_TYPE_DES:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_DES:64:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_CBC_NO_PADDING:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: DES, 128 bits, CBC-nopad
+depends_on:PSA_WANT_ALG_CBC_NO_PADDING:PSA_WANT_KEY_TYPE_DES:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_DES:128:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_CBC_NO_PADDING:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: DES, 192 bits, CBC-nopad
+depends_on:PSA_WANT_ALG_CBC_NO_PADDING:PSA_WANT_KEY_TYPE_DES:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_DES:192:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_CBC_NO_PADDING:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: invalid key size: AES, 64 bits
+depends_on:PSA_WANT_ALG_CTR:PSA_WANT_KEY_TYPE_AES:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_AES:64:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_CTR:PSA_ERROR_INVALID_ARGUMENT:0:8:5
+
+PSA concurrent key generation: RSA, minimum allowed key size, good, sign (PKCS#1 v1.5)
+depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS > 128:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: RSA, 1032 bits, good, sign (PKCS#1 v1.5)
+depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS <= 1032:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_RSA_KEY_PAIR:1032:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: RSA, 1024 bits, good, sign (PSS SHA-256)
+depends_on:PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS <= 1024:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_RSA_KEY_PAIR:1024:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_RSA_PSS(PSA_ALG_SHA_256):PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: RSA, 1024 bits, good, sign (PSS-any-salt SHA-256)
+depends_on:PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS <= 1024:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_RSA_KEY_PAIR:1024:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_SHA_256):PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: RSA, minimum allowed key size, good, encrypt (PKCS#1 v1.5)
+depends_on:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS >= 256:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS <= 2048:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_RSA_PKCS1V15_CRYPT:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: RSA, 1024 bits, good, encrypt (OAEP SHA-256)
+depends_on:PSA_WANT_ALG_RSA_OAEP:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS <= 1024:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_RSA_KEY_PAIR:1024:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256):PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: RSA, 0 bits: invalid
+depends_on:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:MBEDTLS_THREADING_PTHREAD
+# The spec allows either INVALID_ARGUMENT or NOT_SUPPORTED
+concurrently_generate_keys:PSA_KEY_TYPE_RSA_KEY_PAIR:0:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_RSA_PKCS1V15_CRYPT:PSA_ERROR_INVALID_ARGUMENT:0:8:5
+
+PSA concurrent key generation: RSA, size not multiple of 8: not supported
+depends_on:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS + 62:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_RSA_PKCS1V15_CRYPT:PSA_ERROR_NOT_SUPPORTED:0:8:5
+
+PSA concurrent key generation: RSA, size not multiple of 2: not supported
+depends_on:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS + 63:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_RSA_PKCS1V15_CRYPT:PSA_ERROR_NOT_SUPPORTED:0:8:5
+
+PSA concurrent key generation: RSA, maximum size exceeded
+depends_on:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_VENDOR_RSA_MAX_KEY_BITS+8:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_RSA_PKCS1V15_CRYPT:PSA_ERROR_NOT_SUPPORTED:0:8:5
+
+PSA concurrent key generation: ECC, SECP256R1, good
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:PSA_WANT_ECC_SECP_R1_256:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):256:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_ECDSA_ANY:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: ECC, SECP256R1, incorrect bit size
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_SECP_R1_256:MBEDTLS_THREADING_PTHREAD
+# INVALID_ARGUMENT would make more sense, but our code as currently structured
+# doesn't fully relate the curve with its size.
+concurrently_generate_keys:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):128:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_ECDSA_ANY:PSA_ERROR_NOT_SUPPORTED:0:8:5
+
+PSA concurrent key generation: ECC, Curve25519, good
+depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:PSA_WANT_ECC_MONTGOMERY_255:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):255:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_DERIVE:PSA_ALG_ECDH:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: ECC, Curve448, good
+depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:PSA_WANT_ECC_MONTGOMERY_448:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):448:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_DERIVE:PSA_ALG_ECDH:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: FFDH, 2048 bits, good
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE:PSA_WANT_DH_RFC7919_2048:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):2048:PSA_KEY_USAGE_EXPORT:PSA_ALG_FFDH:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: FFDH, 3072 bits, good
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE:PSA_WANT_DH_RFC7919_3072:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):3072:PSA_KEY_USAGE_EXPORT:PSA_ALG_FFDH:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: FFDH, 4096 bits, good
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE:PSA_WANT_DH_RFC7919_4096:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):4096:PSA_KEY_USAGE_EXPORT:PSA_ALG_FFDH:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: FFDH, 6144 bits, good
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE:PSA_WANT_DH_RFC7919_6144:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):6144:PSA_KEY_USAGE_EXPORT:PSA_ALG_FFDH:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: FFDH, 8192 bits, good
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE:PSA_WANT_DH_RFC7919_8192:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):8192:PSA_KEY_USAGE_EXPORT:PSA_ALG_FFDH:PSA_SUCCESS:0:8:5
+
+PSA concurrent key generation: FFDH, 1024 bits, invalid bits
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE:MBEDTLS_THREADING_PTHREAD
+concurrently_generate_keys:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):1024:PSA_KEY_USAGE_EXPORT:PSA_ALG_FFDH:PSA_ERROR_NOT_SUPPORTED:0:8:5
+
+Key production parameters initializers
+key_production_parameters_init:
+
 PSA import persistent key: raw data, 8 bits
 depends_on:MBEDTLS_PSA_CRYPTO_STORAGE_C
 persistent_key_load_key_from_storage:"2a":PSA_KEY_TYPE_RAW_DATA:8:PSA_KEY_USAGE_EXPORT:0:IMPORT_KEY
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index 95e7a2d..1141597 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -28,6 +28,10 @@
 #define TEST_DRIVER_LOCATION 0x7fffff
 #endif
 
+#if defined(MBEDTLS_THREADING_PTHREAD)
+#include "mbedtls/threading.h"
+#endif
+
 /* If this comes up, it's a bug in the test code or in the test data. */
 #define UNUSED 0xdeadbeef
 
@@ -1255,6 +1259,144 @@
 }
 #endif /* MBEDTLS_ECP_RESTARTABLE */
 
+#if defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE)
+static int rsa_test_e(mbedtls_svc_key_id_t key,
+                      size_t bits,
+                      const data_t *e_arg)
+{
+    uint8_t *exported = NULL;
+    size_t exported_size =
+        PSA_EXPORT_KEY_OUTPUT_SIZE(PSA_KEY_TYPE_RSA_PUBLIC_KEY, bits);
+    size_t exported_length = SIZE_MAX;
+    int ok = 0;
+
+    TEST_CALLOC(exported, exported_size);
+    PSA_ASSERT(psa_export_public_key(key,
+                                     exported, exported_size,
+                                     &exported_length));
+    uint8_t *p = exported;
+    uint8_t *end = exported + exported_length;
+    size_t len;
+    /*   RSAPublicKey ::= SEQUENCE {
+     *      modulus            INTEGER,    -- n
+     *      publicExponent     INTEGER  }  -- e
+     */
+    TEST_EQUAL(0, mbedtls_asn1_get_tag(&p, end, &len,
+                                       MBEDTLS_ASN1_SEQUENCE |
+                                       MBEDTLS_ASN1_CONSTRUCTED));
+    TEST_ASSERT(mbedtls_test_asn1_skip_integer(&p, end, bits, bits, 1));
+    TEST_EQUAL(0, mbedtls_asn1_get_tag(&p, end, &len,
+                                       MBEDTLS_ASN1_INTEGER));
+    if (len >= 1 && p[0] == 0) {
+        ++p;
+        --len;
+    }
+    if (e_arg->len == 0) {
+        TEST_EQUAL(len, 3);
+        TEST_EQUAL(p[0], 1);
+        TEST_EQUAL(p[1], 0);
+        TEST_EQUAL(p[2], 1);
+    } else {
+        const uint8_t *expected = e_arg->x;
+        size_t expected_len = e_arg->len;
+        while (expected_len > 0 && *expected == 0) {
+            ++expected;
+            --expected_len;
+        }
+        TEST_MEMORY_COMPARE(p, len, expected, expected_len);
+    }
+    ok = 1;
+
+exit:
+    mbedtls_free(exported);
+    return ok;
+}
+#endif /* PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE */
+
+static int setup_key_production_parameters(
+    psa_key_production_parameters_t **params, size_t *params_data_length,
+    int flags_arg, const data_t *params_data)
+{
+    *params_data_length = params_data->len;
+    /* If there are N bytes of padding at the end of
+     * psa_key_production_parameters_t, then it's enough to allocate
+     * MIN(sizeof(psa_key_production_parameters_t),
+     *     offsetof(psa_key_production_parameters_t, data) + params_data_length).
+     *
+     * For simplicity, here, we allocate up to N more bytes than necessary.
+     * In practice, the current layout of psa_key_production_parameters_t
+     * makes padding extremely unlikely, so we don't worry about testing
+     * that the library code doesn't try to access these extra N bytes.
+     */
+    *params = mbedtls_calloc(1, sizeof(**params) + *params_data_length);
+    TEST_ASSERT(*params != NULL);
+    (*params)->flags = (uint32_t) flags_arg;
+    memcpy((*params)->data, params_data->x, params_data->len);
+    return 1;
+exit:
+    return 0;
+}
+
+#if defined(MBEDTLS_THREADING_PTHREAD)
+typedef struct generate_key_context {
+    psa_key_type_t type;
+    psa_key_usage_t usage;
+    size_t bits;
+    psa_algorithm_t alg;
+    psa_status_t expected_status;
+    psa_key_attributes_t *attributes;
+    int is_large_key;
+    int reps;
+}
+generate_key_context;
+void *thread_generate_key(void *ctx)
+{
+    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_key_attributes_t got_attributes = PSA_KEY_ATTRIBUTES_INIT;
+    generate_key_context *gkc = (struct generate_key_context *) ctx;
+
+    /* If there are race conditions, it is likely the case that they do not
+     * arise every time the code runs. We repeat the code to increase the
+     * chance that any race conditions will be hit. */
+    for (int n = 0; n < gkc->reps; n++) {
+        /* Generate a key */
+        psa_status_t status = psa_generate_key(gkc->attributes, &key);
+
+        if (gkc->is_large_key > 0) {
+            TEST_ASSUME(status != PSA_ERROR_INSUFFICIENT_MEMORY);
+        }
+
+        TEST_EQUAL(status, gkc->expected_status);
+        if (gkc->expected_status != PSA_SUCCESS) {
+            PSA_ASSERT(psa_destroy_key(key));
+            goto exit;
+        }
+
+        /* Test the key information */
+        PSA_ASSERT(psa_get_key_attributes(key, &got_attributes));
+        TEST_EQUAL(psa_get_key_type(&got_attributes), gkc->type);
+        TEST_EQUAL(psa_get_key_bits(&got_attributes), gkc->bits);
+
+        /* Do something with the key according
+         * to its type and permitted usage. */
+        if (!mbedtls_test_psa_exercise_key(key, gkc->usage, gkc->alg)) {
+            psa_destroy_key(key);
+            goto exit;
+        }
+        psa_reset_key_attributes(&got_attributes);
+
+        PSA_ASSERT(psa_destroy_key(key));
+    }
+exit:
+    /*
+     * Key attributes may have been returned by psa_get_key_attributes()
+     * thus reset them as required.
+     */
+    psa_reset_key_attributes(&got_attributes);
+    return NULL;
+}
+#endif /* MBEDTLS_THREADING_PTHREAD */
+
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -9255,6 +9397,81 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void derive_key_ext(int alg_arg,
+                    data_t *key_data,
+                    data_t *input1,
+                    data_t *input2,
+                    int key_type_arg, int bits_arg,
+                    int flags_arg,
+                    data_t *params_data,
+                    psa_status_t expected_status,
+                    data_t *expected_export)
+{
+    mbedtls_svc_key_id_t base_key = MBEDTLS_SVC_KEY_ID_INIT;
+    mbedtls_svc_key_id_t derived_key = MBEDTLS_SVC_KEY_ID_INIT;
+    const psa_algorithm_t alg = alg_arg;
+    const psa_key_type_t key_type = key_type_arg;
+    const size_t bits = bits_arg;
+    psa_key_production_parameters_t *params = NULL;
+    size_t params_data_length = 0;
+    psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT;
+    const size_t export_buffer_size =
+        PSA_EXPORT_KEY_OUTPUT_SIZE(key_type, bits);
+    uint8_t *export_buffer = NULL;
+    psa_key_attributes_t base_attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_attributes_t derived_attributes = PSA_KEY_ATTRIBUTES_INIT;
+    size_t export_length;
+
+    TEST_CALLOC(export_buffer, export_buffer_size);
+    PSA_ASSERT(psa_crypto_init());
+
+    psa_set_key_usage_flags(&base_attributes, PSA_KEY_USAGE_DERIVE);
+    psa_set_key_algorithm(&base_attributes, alg);
+    psa_set_key_type(&base_attributes, PSA_KEY_TYPE_DERIVE);
+    PSA_ASSERT(psa_import_key(&base_attributes, key_data->x, key_data->len,
+                              &base_key));
+
+    if (mbedtls_test_psa_setup_key_derivation_wrap(
+            &operation, base_key, alg,
+            input1->x, input1->len,
+            input2->x, input2->len,
+            PSA_KEY_DERIVATION_UNLIMITED_CAPACITY) == 0) {
+        goto exit;
+    }
+
+    psa_set_key_usage_flags(&derived_attributes, PSA_KEY_USAGE_EXPORT);
+    psa_set_key_algorithm(&derived_attributes, 0);
+    psa_set_key_type(&derived_attributes, key_type);
+    psa_set_key_bits(&derived_attributes, bits);
+    if (!setup_key_production_parameters(&params, &params_data_length,
+                                         flags_arg, params_data)) {
+        goto exit;
+    }
+
+    TEST_EQUAL(psa_key_derivation_output_key_ext(&derived_attributes, &operation,
+                                                 params, params_data_length,
+                                                 &derived_key),
+               expected_status);
+
+    if (expected_status == PSA_SUCCESS) {
+        PSA_ASSERT(psa_export_key(derived_key,
+                                  export_buffer, export_buffer_size,
+                                  &export_length));
+        TEST_MEMORY_COMPARE(export_buffer, export_length,
+                            expected_export->x, expected_export->len);
+    }
+
+exit:
+    mbedtls_free(export_buffer);
+    mbedtls_free(params);
+    psa_key_derivation_abort(&operation);
+    psa_destroy_key(base_key);
+    psa_destroy_key(derived_key);
+    PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void derive_key(int alg_arg,
                 data_t *key_data, data_t *input1, data_t *input2,
                 int type_arg, int bits_arg,
@@ -9630,6 +9847,59 @@
 }
 /* END_CASE */
 
+#if defined MBEDTLS_THREADING_PTHREAD
+
+/* BEGIN_CASE depends_on:MBEDTLS_THREADING_PTHREAD */
+void concurrently_generate_keys(int type_arg,
+                                int bits_arg,
+                                int usage_arg,
+                                int alg_arg,
+                                int expected_status_arg,
+                                int is_large_key_arg,
+                                int arg_thread_count,
+                                int reps_arg)
+{
+    size_t thread_count = (size_t) arg_thread_count;
+    mbedtls_test_thread_t *threads = NULL;
+    generate_key_context gkc;
+    gkc.type = type_arg;
+    gkc.usage = usage_arg;
+    gkc.bits = bits_arg;
+    gkc.alg = alg_arg;
+    gkc.expected_status = expected_status_arg;
+    gkc.is_large_key = is_large_key_arg;
+    gkc.reps = reps_arg;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+    PSA_ASSERT(psa_crypto_init());
+
+    psa_set_key_usage_flags(&attributes, usage_arg);
+    psa_set_key_algorithm(&attributes, alg_arg);
+    psa_set_key_type(&attributes, type_arg);
+    psa_set_key_bits(&attributes, bits_arg);
+    gkc.attributes = &attributes;
+
+    TEST_CALLOC(threads, sizeof(mbedtls_test_thread_t) * thread_count);
+
+    /* Split threads to generate key then destroy key. */
+    for (size_t i = 0; i < thread_count; i++) {
+        TEST_EQUAL(
+            mbedtls_test_thread_create(&threads[i], thread_generate_key,
+                                       (void *) &gkc), 0);
+    }
+
+    /* Join threads. */
+    for (size_t i = 0; i < thread_count; i++) {
+        TEST_EQUAL(mbedtls_test_thread_join(&threads[i]), 0);
+    }
+
+exit:
+    mbedtls_free(threads);
+    PSA_DONE();
+}
+/* END_CASE */
+#endif
+
 /* BEGIN_CASE */
 void generate_key(int type_arg,
                   int bits_arg,
@@ -9687,71 +9957,57 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_CRYPT:PSA_WANT_ALG_RSA_PKCS1V15_SIGN */
-void generate_key_rsa(int bits_arg,
-                      data_t *e_arg,
+/* BEGIN_CASE */
+void generate_key_ext(int type_arg,
+                      int bits_arg,
+                      int usage_arg,
+                      int alg_arg,
+                      int flags_arg,
+                      data_t *params_data,
                       int expected_status_arg)
 {
     mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
-    psa_key_type_t type = PSA_KEY_TYPE_RSA_KEY_PAIR;
+    psa_key_type_t type = type_arg;
+    psa_key_usage_t usage = usage_arg;
     size_t bits = bits_arg;
-    psa_key_usage_t usage = PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT;
-    psa_algorithm_t alg = PSA_ALG_RSA_PKCS1V15_SIGN_RAW;
+    psa_algorithm_t alg = alg_arg;
     psa_status_t expected_status = expected_status_arg;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-    uint8_t *exported = NULL;
-    size_t exported_size =
-        PSA_EXPORT_KEY_OUTPUT_SIZE(PSA_KEY_TYPE_RSA_PUBLIC_KEY, bits);
-    size_t exported_length = SIZE_MAX;
-    uint8_t *e_read_buffer = NULL;
-    int is_default_public_exponent = 0;
-    size_t e_read_size = PSA_KEY_DOMAIN_PARAMETERS_SIZE(type, bits);
-    size_t e_read_length = SIZE_MAX;
-
-    if (e_arg->len == 0 ||
-        (e_arg->len == 3 &&
-         e_arg->x[0] == 1 && e_arg->x[1] == 0 && e_arg->x[2] == 1)) {
-        is_default_public_exponent = 1;
-        e_read_size = 0;
-    }
-    TEST_CALLOC(e_read_buffer, e_read_size);
-    TEST_CALLOC(exported, exported_size);
+    psa_key_production_parameters_t *params = NULL;
+    size_t params_data_length = 0;
+    psa_key_attributes_t got_attributes = PSA_KEY_ATTRIBUTES_INIT;
 
     PSA_ASSERT(psa_crypto_init());
 
     psa_set_key_usage_flags(&attributes, usage);
     psa_set_key_algorithm(&attributes, alg);
-    PSA_ASSERT(psa_set_key_domain_parameters(&attributes, type,
-                                             e_arg->x, e_arg->len));
+    psa_set_key_type(&attributes, type);
     psa_set_key_bits(&attributes, bits);
 
+    if (!setup_key_production_parameters(&params, &params_data_length,
+                                         flags_arg, params_data)) {
+        goto exit;
+    }
+
     /* Generate a key */
-    TEST_EQUAL(psa_generate_key(&attributes, &key), expected_status);
+    psa_status_t status = psa_generate_key_ext(&attributes,
+                                               params, params_data_length,
+                                               &key);
+
+    TEST_EQUAL(status, expected_status);
     if (expected_status != PSA_SUCCESS) {
         goto exit;
     }
 
     /* Test the key information */
-    PSA_ASSERT(psa_get_key_attributes(key, &attributes));
-    TEST_EQUAL(psa_get_key_type(&attributes), type);
-    TEST_EQUAL(psa_get_key_bits(&attributes), bits);
-    psa_status_t status = psa_get_key_domain_parameters(&attributes,
-                                                        e_read_buffer, e_read_size,
-                                                        &e_read_length);
+    PSA_ASSERT(psa_get_key_attributes(key, &got_attributes));
+    TEST_EQUAL(psa_get_key_type(&got_attributes), type);
+    TEST_EQUAL(psa_get_key_bits(&got_attributes), bits);
 
-
-#if (defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_IMPORT) && \
-    defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT)) || \
-    defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY)
-    if (is_default_public_exponent) {
-        TEST_EQUAL(e_read_length, 0);
-    } else {
-        TEST_EQUAL(status, PSA_SUCCESS);
-        TEST_MEMORY_COMPARE(e_read_buffer, e_read_length, e_arg->x, e_arg->len);
+#if defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE)
+    if (type == PSA_KEY_TYPE_RSA_KEY_PAIR) {
+        TEST_ASSERT(rsa_test_e(key, bits, params_data));
     }
-#else
-    (void) is_default_public_exponent;
-    TEST_EQUAL(status, PSA_ERROR_NOT_SUPPORTED);
 #endif
 
     /* Do something with the key according to its type and permitted usage. */
@@ -9759,49 +10015,27 @@
         goto exit;
     }
 
-    /* Export the key and check the public exponent. */
-    PSA_ASSERT(psa_export_public_key(key,
-                                     exported, exported_size,
-                                     &exported_length));
-    {
-        uint8_t *p = exported;
-        uint8_t *end = exported + exported_length;
-        size_t len;
-        /*   RSAPublicKey ::= SEQUENCE {
-         *      modulus            INTEGER,    -- n
-         *      publicExponent     INTEGER  }  -- e
-         */
-        TEST_EQUAL(0, mbedtls_asn1_get_tag(&p, end, &len,
-                                           MBEDTLS_ASN1_SEQUENCE |
-                                           MBEDTLS_ASN1_CONSTRUCTED));
-        TEST_ASSERT(mbedtls_test_asn1_skip_integer(&p, end, bits, bits, 1));
-        TEST_EQUAL(0, mbedtls_asn1_get_tag(&p, end, &len,
-                                           MBEDTLS_ASN1_INTEGER));
-        if (len >= 1 && p[0] == 0) {
-            ++p;
-            --len;
-        }
-        if (e_arg->len == 0) {
-            TEST_EQUAL(len, 3);
-            TEST_EQUAL(p[0], 1);
-            TEST_EQUAL(p[1], 0);
-            TEST_EQUAL(p[2], 1);
-        } else {
-            TEST_MEMORY_COMPARE(p, len, e_arg->x, e_arg->len);
-        }
-    }
-
 exit:
     /*
-     * Key attributes may have been returned by psa_get_key_attributes() or
-     * set by psa_set_key_domain_parameters() thus reset them as required.
+     * Key attributes may have been returned by psa_get_key_attributes()
+     * thus reset them as required.
      */
-    psa_reset_key_attributes(&attributes);
-
+    psa_reset_key_attributes(&got_attributes);
+    mbedtls_free(params);
     psa_destroy_key(key);
     PSA_DONE();
-    mbedtls_free(e_read_buffer);
-    mbedtls_free(exported);
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void key_production_parameters_init()
+{
+    psa_key_production_parameters_t init = PSA_KEY_PRODUCTION_PARAMETERS_INIT;
+    psa_key_production_parameters_t zero;
+    memset(&zero, 0, sizeof(zero));
+
+    TEST_EQUAL(init.flags, 0);
+    TEST_EQUAL(zero.flags, 0);
 }
 /* END_CASE */
 
diff --git a/tests/suites/test_suite_psa_crypto_persistent_key.function b/tests/suites/test_suite_psa_crypto_persistent_key.function
index c4e4c7d..ea8cb6b 100644
--- a/tests/suites/test_suite_psa_crypto_persistent_key.function
+++ b/tests/suites/test_suite_psa_crypto_persistent_key.function
@@ -61,7 +61,7 @@
 
     TEST_CALLOC(file_data, file_data_length);
     psa_format_key_data_for_storage(key_data->x, key_data->len,
-                                    &attributes.core,
+                                    &attributes,
                                     file_data);
 
     TEST_MEMORY_COMPARE(expected_file_data->x, expected_file_data->len,
@@ -90,7 +90,7 @@
 
     status = psa_parse_key_data_from_storage(file_data->x, file_data->len,
                                              &key_data, &key_data_length,
-                                             &attributes.core);
+                                             &attributes);
 
     TEST_EQUAL(status, expected_status);
     if (status != PSA_SUCCESS) {
diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal.function b/tests/suites/test_suite_psa_crypto_se_driver_hal.function
index 8e96984..e3681ba 100644
--- a/tests/suites/test_suite_psa_crypto_se_driver_hal.function
+++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.function
@@ -952,7 +952,7 @@
     psa_set_key_slot_number(&attributes, min_slot);
 
     if (PSA_KEY_LIFETIME_IS_VOLATILE(lifetime)) {
-        attributes.core.id = returned_id;
+        attributes.id = returned_id;
     } else {
         psa_set_key_id(&attributes, returned_id);
     }
diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal_mocks.function b/tests/suites/test_suite_psa_crypto_se_driver_hal_mocks.function
index 6f28f93..b6d3a34 100644
--- a/tests/suites/test_suite_psa_crypto_se_driver_hal_mocks.function
+++ b/tests/suites/test_suite_psa_crypto_se_driver_hal_mocks.function
@@ -359,19 +359,19 @@
 
     if (mock_alloc_return_value == PSA_SUCCESS) {
         TEST_ASSERT(mbedtls_svc_key_id_equal(
-                        mock_import_data.attributes.core.id, id));
+                        mock_import_data.attributes.id, id));
     } else {
         TEST_ASSERT(MBEDTLS_SVC_KEY_ID_GET_KEY_ID(
-                        mock_import_data.attributes.core.id) == 0);
+                        mock_import_data.attributes.id) == 0);
         TEST_ASSERT(MBEDTLS_SVC_KEY_ID_GET_OWNER_ID(
-                        mock_import_data.attributes.core.id) == 0);
+                        mock_import_data.attributes.id) == 0);
     }
 
-    TEST_ASSERT(mock_import_data.attributes.core.lifetime ==
+    TEST_ASSERT(mock_import_data.attributes.lifetime ==
                 (mock_alloc_return_value == PSA_SUCCESS ? lifetime : 0));
-    TEST_ASSERT(mock_import_data.attributes.core.policy.usage ==
+    TEST_ASSERT(mock_import_data.attributes.policy.usage ==
                 (mock_alloc_return_value == PSA_SUCCESS ? PSA_KEY_USAGE_EXPORT : 0));
-    TEST_ASSERT(mock_import_data.attributes.core.type ==
+    TEST_ASSERT(mock_import_data.attributes.type ==
                 (mock_alloc_return_value == PSA_SUCCESS ? PSA_KEY_TYPE_RAW_DATA : 0));
 
     if (expected_result == PSA_SUCCESS) {
@@ -474,19 +474,19 @@
 
     if (mock_alloc_return_value == PSA_SUCCESS) {
         TEST_ASSERT(mbedtls_svc_key_id_equal(
-                        mock_generate_data.attributes.core.id, id));
+                        mock_generate_data.attributes.id, id));
     } else {
         TEST_ASSERT(MBEDTLS_SVC_KEY_ID_GET_KEY_ID(
-                        mock_generate_data.attributes.core.id) == 0);
+                        mock_generate_data.attributes.id) == 0);
         TEST_ASSERT(MBEDTLS_SVC_KEY_ID_GET_OWNER_ID(
-                        mock_generate_data.attributes.core.id) == 0);
+                        mock_generate_data.attributes.id) == 0);
     }
 
-    TEST_ASSERT(mock_generate_data.attributes.core.lifetime ==
+    TEST_ASSERT(mock_generate_data.attributes.lifetime ==
                 (mock_alloc_return_value == PSA_SUCCESS ? lifetime : 0));
-    TEST_ASSERT(mock_generate_data.attributes.core.policy.usage ==
+    TEST_ASSERT(mock_generate_data.attributes.policy.usage ==
                 (mock_alloc_return_value == PSA_SUCCESS ? PSA_KEY_USAGE_EXPORT : 0));
-    TEST_ASSERT(mock_generate_data.attributes.core.type ==
+    TEST_ASSERT(mock_generate_data.attributes.type ==
                 (mock_alloc_return_value == PSA_SUCCESS ? PSA_KEY_TYPE_RAW_DATA : 0));
 
     if (expected_result == PSA_SUCCESS) {
diff --git a/tests/suites/test_suite_psa_crypto_slot_management.function b/tests/suites/test_suite_psa_crypto_slot_management.function
index 8564d35..94f26f6 100644
--- a/tests/suites/test_suite_psa_crypto_slot_management.function
+++ b/tests/suites/test_suite_psa_crypto_slot_management.function
@@ -458,7 +458,7 @@
          * PSA key attributes APIs thus accessing to the attributes
          * directly.
          */
-        attributes.core.id = id;
+        attributes.id = id;
     } else {
         psa_set_key_id(&attributes, id);
     }
@@ -992,7 +992,7 @@
      * Check that we can now access the persistent key again.
      */
     PSA_ASSERT(psa_get_key_attributes(persistent_key, &attributes));
-    TEST_ASSERT(mbedtls_svc_key_id_equal(attributes.core.id,
+    TEST_ASSERT(mbedtls_svc_key_id_equal(attributes.id,
                                          persistent_key));
 
     /*
diff --git a/tests/suites/test_suite_rsa.data b/tests/suites/test_suite_rsa.data
index b89d158..b52c7dc 100644
--- a/tests/suites/test_suite_rsa.data
+++ b/tests/suites/test_suite_rsa.data
@@ -468,58 +468,160 @@
 mbedtls_rsa_deduce_primes:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"3":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
 
 RSA Import (N,P,Q,D,E)
-mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"3":0:1:0:0
+mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"3":2048:0:1:0:0
 
 RSA Import (N,P,Q,D,E), inconsistent
-mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC3672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"3":0:1:MBEDTLS_ERR_RSA_KEY_CHECK_FAILED:0
+mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC3672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"3":2048:0:1:MBEDTLS_ERR_RSA_KEY_CHECK_FAILED:0
 
 RSA Import (N,P,Q,D,E), successive
-mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"3":1:1:0:0
+mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"3":2048:1:1:0:0
 
 RSA Import (N,P,Q,D,E), successive, inconsistent
-mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC3672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"3":1:1:MBEDTLS_ERR_RSA_KEY_CHECK_FAILED:0
+mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC3672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"3":2048:1:1:MBEDTLS_ERR_RSA_KEY_CHECK_FAILED:0
 
 RSA Import (-,P,Q,D,E)
-mbedtls_rsa_import:"":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"3":0:1:0:0
+mbedtls_rsa_import:"":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"3":2048:0:1:0:0
 
 RSA Import (-,P,Q,D,E), successive
-mbedtls_rsa_import:"":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"3":1:1:0:0
+mbedtls_rsa_import:"":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"3":2048:1:1:0:0
 
 RSA Import (N,-,-,D,E)
-mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"":"":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"3":0:1:0:0
+mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"":"":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"3":2048:0:1:0:0
 
 RSA Import (N,-,-,D,E), successive
-mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"":"":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"3":1:1:0:0
+mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"":"":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"3":2048:1:1:0:0
 
 RSA Import (N,P,Q,-,E)
-mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"":"3":0:1:0:0
+mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"":"3":2048:0:1:0:0
 
 RSA Import (N,P,Q,-,E), successive
-mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"":"3":1:1:0:0
+mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"":"3":2048:1:1:0:0
 
 RSA Import (-,P,Q,-,E)
-mbedtls_rsa_import:"":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"":"3":0:1:0:0
+mbedtls_rsa_import:"":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"":"3":2048:0:1:0:0
 
 RSA Import (-,P,Q,-,E), successive
-mbedtls_rsa_import:"":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"":"3":1:1:0:0
+mbedtls_rsa_import:"":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"":"3":2048:1:1:0:0
 
 RSA Import (N,-,Q,-,E)
-mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"":"3":0:1:0:MBEDTLS_ERR_RSA_BAD_INPUT_DATA
+mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"":"3":2048:0:1:0:MBEDTLS_ERR_RSA_BAD_INPUT_DATA
 
 RSA Import (N,-,Q,-,E), successive
-mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"":"3":1:1:0:MBEDTLS_ERR_RSA_BAD_INPUT_DATA
+mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"":"3":2048:1:1:0:MBEDTLS_ERR_RSA_BAD_INPUT_DATA
 
 RSA Import (N,-,-,-,E), complete public key
-mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"":"":"":"3":0:0:0:0
+mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"":"":"":"3":2048:0:0:0:0
 
 RSA Import (N,-,-,-,E), complete public key, successive
-mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"":"":"":"3":1:0:0:0
+mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"":"":"":"3":2048:1:0:0:0
 
 RSA Import (N,-,-,-,E), complete public key, corrupted
-mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"":"":"":"4":0:0:MBEDTLS_ERR_RSA_KEY_CHECK_FAILED:0
+mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"":"":"":"4":2048:0:0:MBEDTLS_ERR_RSA_KEY_CHECK_FAILED:0
 
 RSA Import (N,-,-,-,E), complete public key, successive, corrupted
-mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"":"":"":"4":1:0:MBEDTLS_ERR_RSA_KEY_CHECK_FAILED:0
+mbedtls_rsa_import:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"":"":"":"4":2048:1:0:MBEDTLS_ERR_RSA_KEY_CHECK_FAILED:0
+
+RSA Import (N,P,Q,D,E) 512-bit complete pair
+mbedtls_rsa_import:"cbc23c9751d5b0dc4f7ea5f871d6e31d7fb8a414eacfa006cf9c782385ce177b2a41b52cd80ddf75c4f14ffb679c388b4d0fe828413c2b8dd651e5039b2e14b3":"fbf724e9d31cb074dd117e96c4f9ad8ff6b4fe6dc72c7b9bc5af370c0833314d":"cf057bde49ab3cc354d731c03925e4cb34d7ecc41335948bca6d3438a0e35dff":"5705d006f8a68170b66aeacb9f231dc0bd89c85a3ea70a3b9e73bf43bca3f69699bfd123ec6fc533d3163dc8645d1e45342ad38b110659e96656f4763ec318f1":"10001":512:0:1:0:0
+
+RSA Import (N,-,-,-,E) 512-bit public
+mbedtls_rsa_import:"cbc23c9751d5b0dc4f7ea5f871d6e31d7fb8a414eacfa006cf9c782385ce177b2a41b52cd80ddf75c4f14ffb679c388b4d0fe828413c2b8dd651e5039b2e14b3":"":"":"":"10001":512:0:0:0:0
+
+RSA Import (N,P,Q,D,E) 513-bit complete pair
+mbedtls_rsa_import:"16798857c4718f9367a715b29038d042ea41686a457279db149d4da54146262305da39b02b764f2b56902e4c45425c2c3f404da82f86d8ed3b067da70899c5149":"18486f2d2df61d10ebe578caff5142047cae635909946b57c33028d35e4abac0b":"ecefea558b614138e773e1cd25380e49a910d6dd4b584457c1bfabf86922f87b":"1c3dbb460e6364b725989f7b321f3213e3a92d3bdce86c970ee05ba13cd4993758140f790489b61188c26354a6b372d32081750cecb84db563ec5724d78388ad":"10001":513:0:1:0:0
+
+RSA Import (N,-,-,-,E) 513-bit public
+mbedtls_rsa_import:"16798857c4718f9367a715b29038d042ea41686a457279db149d4da54146262305da39b02b764f2b56902e4c45425c2c3f404da82f86d8ed3b067da70899c5149":"":"":"":"10001":513:0:0:0:0
+
+RSA Import (N,P,Q,D,E) 514-bit complete pair
+mbedtls_rsa_import:"32f54232899f45a415e7a7728fc744703f4b4466e56d7d6900f125950bb9a42082d2f0162ce1ac9949da5be37af8c20178d79d8ac1ab860d5ed55b14f49d064ab":"1d2cc9d59be8079457a5f28c3e74d1d4c7763acc1a7e725dff09198a5b99d35cf":"1bf23921dfe89a0f681bf10fd27fd2bc914f8888b8addb1d102255e586827b665":"1d9f13ebecb3f8f7790440020831fd4682846e2ea20f13678674a7340caccd0b37ccaf79b7d4005adafb7e6f84e0ff7bbe28a27fd7337cdf100fe63afe967419":"10001":514:0:1:0:0
+
+RSA Import (N,-,-,-,E) 514-bit public
+mbedtls_rsa_import:"32f54232899f45a415e7a7728fc744703f4b4466e56d7d6900f125950bb9a42082d2f0162ce1ac9949da5be37af8c20178d79d8ac1ab860d5ed55b14f49d064ab":"":"":"":"10001":514:0:0:0:0
+
+RSA Import (N,P,Q,D,E) 515-bit complete pair
+mbedtls_rsa_import:"5f47dbe0d15f66c13ce0ff8af2edc7942ef4ff8b6b6e49ef5518ce3754efb5270204cb727c3f325b4a51dc02688eae0a6bfd7549854a7ede8b31f0e4adb835f85":"30c23bf1faf7515ed3e63abcda5b88b6387d213854da798e6662afb09441f192f":"1f4419ac839887606a8d299bc430f8e48f8984ae81982eaf03775fbe1a347bd8b":"5e8416fece5337c84acedb5007a98e4855c85d52fd2ffb91b9b590a2dcd3a8bc88e6e61573daa526a1b37ebae41401e6811d0d1e5458f1a5074178fb274a275a5":"10001":515:0:1:0:0
+
+RSA Import (N,-,-,-,E) 515-bit public
+mbedtls_rsa_import:"5f47dbe0d15f66c13ce0ff8af2edc7942ef4ff8b6b6e49ef5518ce3754efb5270204cb727c3f325b4a51dc02688eae0a6bfd7549854a7ede8b31f0e4adb835f85":"":"":"":"10001":515:0:0:0:0
+
+RSA Import (N,P,Q,D,E) 516-bit complete pair
+mbedtls_rsa_import:"bcc54a5a10ef1a3241c60aeec9c5ec54cd63407ee2b69748ad5ec53d1a3d7fea540811ba0eed19574cad6dca28691e2711fdf0e76d2bc6eec508e7a864ee13b03":"3a83434f8995a87a977f0e15e9b39f55551968a5f3cbaf6f7e0f177215c3a69bb":"339e4b5aef4912382ee5f6dd82c2cb5255e604279477ca22ed0b02cab66a75b59":"60a460bc5b8f0dca4d0226f6b9362b17ff4ea0e6550b45c85f79f560a2de796e35d51da40d1eae356cca05626a3686cee2dbcaa5b71b76ffa0cb313fb4a412f1":"10001":516:0:1:0:0
+
+RSA Import (N,-,-,-,E) 516-bit public
+mbedtls_rsa_import:"bcc54a5a10ef1a3241c60aeec9c5ec54cd63407ee2b69748ad5ec53d1a3d7fea540811ba0eed19574cad6dca28691e2711fdf0e76d2bc6eec508e7a864ee13b03":"":"":"":"10001":516:0:0:0:0
+
+RSA Import (N,P,Q,D,E) 517-bit complete pair
+mbedtls_rsa_import:"1a7b2e3d43f1b3e060d2f598939d0542178feac3310be308f4fd05872ec91048ea79543c0b00e5f61ec8b577ffa33c26bb74c2bc079033f006e6af59ec15cef529":"72e502be06a9fcb3ef64801055d10ecf8ec2b4a9429423813760e4258cf575373":"3b00e49f541091dce4940c9a36f203d195a81c7812111d9a89fc5971f363085f3":"19297286444925e1ce1ea5be94845ebaae28d1a926b164c8de008d8025b46704d77326956f97ceaadc3ebb74f94edbe1b7df5236693e7bb97cdd77b4569420fd01":"10001":517:0:1:0:0
+
+RSA Import (N,-,-,-,E) 517-bit public
+mbedtls_rsa_import:"1a7b2e3d43f1b3e060d2f598939d0542178feac3310be308f4fd05872ec91048ea79543c0b00e5f61ec8b577ffa33c26bb74c2bc079033f006e6af59ec15cef529":"":"":"":"10001":517:0:0:0:0
+
+RSA Import (N,P,Q,D,E) 518-bit complete pair
+mbedtls_rsa_import:"31defca6f97dac931fea5bd182c801b6512065929b327443dad9421379e15b37e33a6d3b11e51bd6905c9df9ec15980e91f10c34607749085456e85c1aad9cae1d":"725f1a4b37008897949b12bc9ba249d60d2df673b5a5367f9b490e79cc798446d":"6fa09a0615754b14f9aa4b5613e60e6d4988437c25b97fc056cb4841931902271":"1bcd08df3439e0d86b7444173966b1bda6dffe7f89d0c88b83169605316e75615c84cf7ea7c9cb16204e67329584d56f1840d247e4b392b627622d2101a2af2781":"10001":518:0:1:0:0
+
+RSA Import (N,-,-,-,E) 518-bit public
+mbedtls_rsa_import:"31defca6f97dac931fea5bd182c801b6512065929b327443dad9421379e15b37e33a6d3b11e51bd6905c9df9ec15980e91f10c34607749085456e85c1aad9cae1d":"":"":"":"10001":518:0:0:0:0
+
+RSA Import (N,P,Q,D,E) 519-bit complete pair
+mbedtls_rsa_import:"6de4c503dd2e6d74d6dbc95bdd85b177f3737c3da6b00860db6585d1026ae043450888773afd259ee52e7c70de86a1d805dec0d201b2cd9d91e5e1f323020b47b5":"f4c3d0904f80c3ee121aa94edda195415ddd21e4503ebbaf294993a649f896251":"72f01bc834d3eae97dea004f8af566b6030362fb3eb1063211d1dd699ece87225":"8361ce69203631864e99d5d28eb517c760b7e101941740ed0b6004ec2d07b9b6982132c9cff11ef49f715b04b6d76edd0e936b05efb4acf2cfdf6ea58f1149b41":"10001":519:0:1:0:0
+
+RSA Import (N,-,-,-,E) 519-bit public
+mbedtls_rsa_import:"6de4c503dd2e6d74d6dbc95bdd85b177f3737c3da6b00860db6585d1026ae043450888773afd259ee52e7c70de86a1d805dec0d201b2cd9d91e5e1f323020b47b5":"":"":"":"10001":519:0:0:0:0
+
+RSA Import (N,P,Q,D,E) 520-bit complete pair
+mbedtls_rsa_import:"c27fbd5b63f60f14b6fbbda29444aa6639cef01ec2b89b607ca0e5cf64f4f8ea41131c8c2a0204099b2030c8b155553404464fb351a7b44e77138412164997de31":"feb75ab38c05618105c1d7f1459475520cb64d8b477804f6f48b2bcc44ca6c147":"c37ab0c657015601027454c1e45d4abc85f7177d0757312b2811d4dc46f1b60c7":"4b4d2365a79cd317e5042fd62aeb2ec1a72dec1f2caa4655a3cab34e893aa2c81c06e18bd79a0d247dc109ab540c7eb6bf8ef27f02de66e4d8dc511bff7ce33c15":"10001":520:0:1:0:0
+
+RSA Import (N,-,-,-,E) 520-bit public
+mbedtls_rsa_import:"c27fbd5b63f60f14b6fbbda29444aa6639cef01ec2b89b607ca0e5cf64f4f8ea41131c8c2a0204099b2030c8b155553404464fb351a7b44e77138412164997de31":"":"":"":"10001":520:0:0:0:0
+
+RSA Import (N,P,Q,D,E) 521-bit complete pair
+mbedtls_rsa_import:"1993ce720408e69a459c96df92b90040b88b0f7234c46b96413d177ed08e562c9b7ed7c1fb351cafc4028d3d9a9792e35ddb8a3770cc5cf7011f778f78e75ff60af":"1f2d345a210b5f085447d9534abe78d77e820dddbb24b2eb334b7c6ba91634a0f9":"d205f332807775231b96e06f47e7c0cec8981f41c6b6e6a96eafdbc40773b20e7":"15ec8c594efc122ecadc9eb6a59dce89aba607676db3b044eb46e28ce15820a5b984349a7b74a9f86c17a8503f29c0cc5b3f68790653bce30d8b0a5ba7730a16b1":"10001":521:0:1:0:0
+
+RSA Import (N,-,-,-,E) 521-bit public
+mbedtls_rsa_import:"1993ce720408e69a459c96df92b90040b88b0f7234c46b96413d177ed08e562c9b7ed7c1fb351cafc4028d3d9a9792e35ddb8a3770cc5cf7011f778f78e75ff60af":"":"":"":"10001":521:0:0:0:0
+
+RSA Import (N,P,Q,D,E) 522-bit complete pair
+mbedtls_rsa_import:"2eeccbdf4fb0385fefd27583bdc9ac8b99e57fd6acf0c71010ae65ee0531dbf45686bb737a2a64124ab2f695a73394f7d5dd2ba7a668d872684cb49e12a7d6a49ad":"1c5785f5108bb49e43ee0b3d7261eb0efe10334ac101893a59d67e79fb3f640951":"1a7da635573970c989ca4aaa051d3a51641eed09516f8200d15effb86c3082a39d":"1e2042a744c6f2fa8cc28655a5140425c010fa68fdb0bb6c51f95551619e68034d128406fa6fc7ccd5d35a493ee8ecf98b9e987fed18353ff7e0d50ae0b65f2b841":"10001":522:0:1:0:0
+
+RSA Import (N,-,-,-,E) 522-bit public
+mbedtls_rsa_import:"2eeccbdf4fb0385fefd27583bdc9ac8b99e57fd6acf0c71010ae65ee0531dbf45686bb737a2a64124ab2f695a73394f7d5dd2ba7a668d872684cb49e12a7d6a49ad":"":"":"":"10001":522:0:0:0:0
+
+RSA Import (N,P,Q,D,E) 523-bit complete pair
+mbedtls_rsa_import:"6a8c9774b37c37d6f6c95aaf60ab27ebb426a26cd6b22fa44fe1e09f4fa47abeac2d1f84aaff436ef3f07801c617a1f990ca4ece42388d1493723ee9768730d8799":"36f10cb3d7fa6af6616991827dd988fd0687761243126e563a24977d95b3075855":"1f0771656d359a2d4907ded0e0471e27242a59f89e30a4e21fc3cffb5da3dd4635":"4cafcdde87c452e85c0d06410dc1826509ef789dff5496279bfb05d183dfed1c452fda00deb3b345fc31cd255aa1c7e2f19e50191793a7b16e6340f0723e0d5ad11":"10001":523:0:1:0:0
+
+RSA Import (N,-,-,-,E) 523-bit public
+mbedtls_rsa_import:"6a8c9774b37c37d6f6c95aaf60ab27ebb426a26cd6b22fa44fe1e09f4fa47abeac2d1f84aaff436ef3f07801c617a1f990ca4ece42388d1493723ee9768730d8799":"":"":"":"10001":523:0:0:0:0
+
+RSA Import (N,P,Q,D,E) 524-bit complete pair
+mbedtls_rsa_import:"c04c05bc77eca9c05702402622b3855ac150a737132c66d6900dc8f512e752f32ce3c777d51da5cca9105b7f8f57da571cec42a450d49e43ea359538acb3610dacf":"3f78102778bec177c9bb4f313a29afbb9c2d0089539f57aeb2976b59d17b1de699":"3079f8628b827258bb785cd0bb40623207ecf6194e65871571bf004bf0c537f5a7":"9c161921de060fd3bbcc6bdd8895474d5f54e425e43e4a4b272ac94f844498241d41f7ee7a6b90775cf5a73b3ce3015b15620494130e9198550cb3f07bdba184ac1":"10001":524:0:1:0:0
+
+RSA Import (N,-,-,-,E) 524-bit public
+mbedtls_rsa_import:"c04c05bc77eca9c05702402622b3855ac150a737132c66d6900dc8f512e752f32ce3c777d51da5cca9105b7f8f57da571cec42a450d49e43ea359538acb3610dacf":"":"":"":"10001":524:0:0:0:0
+
+RSA Import (N,P,Q,D,E) 525-bit complete pair
+mbedtls_rsa_import:"18197b4f054a0347a8e81576cf16fdb5d22ce9bb71b11df029c30e047b418ebb4b2d759f8c72f9b24a79b46ddeeeadb17b197911442f6e7bf3ea2106752e901c64fb":"676ee11f6bb61d7094148bb326d0267eb7a105549d72d360707001af8e03ecc6dd":"3ba5a5ba28f8adee0883947963c037e3a2c9e557b3edc5cca35b155e63ed3ae1b7":"d75e61ecbe87c0e817427d0f57874fb224a7dbe79912114ac6ecb1c8bafa146512b1b728d2d860e96fd283ae981ebb3272647841cdd254a5e1f075eb17df596e2c9":"10001":525:0:1:0:0
+
+RSA Import (N,-,-,-,E) 525-bit public
+mbedtls_rsa_import:"18197b4f054a0347a8e81576cf16fdb5d22ce9bb71b11df029c30e047b418ebb4b2d759f8c72f9b24a79b46ddeeeadb17b197911442f6e7bf3ea2106752e901c64fb":"":"":"":"10001":525:0:0:0:0
+
+RSA Import (N,P,Q,D,E) 526-bit complete pair
+mbedtls_rsa_import:"2de74b63625125b31a3d4ae2719d74dae2a0dacb84f220c295e8fea55080b3bacad98593ef3dd710a949b84498ba59ac0353f8e6cd4355e9bfc0ddef8ef25ce41309":"766d695ac399679b33cdc68e7bf9b604d922dee04fa60a4aa2fab3263a8b323109":"633a53fef2f6b08daddd9e496625819753284b72f41290dcc8db82e55746555201":"1ff9c25614a29a344cceed5f17edaafcde69567ff6b80382089328ef57488fea49d3e660180107bb0b1770005d814216dbd493fd7aae4891fb2320226615d67e4001":"10001":526:0:1:0:0
+
+RSA Import (N,-,-,-,E) 526-bit public
+mbedtls_rsa_import:"2de74b63625125b31a3d4ae2719d74dae2a0dacb84f220c295e8fea55080b3bacad98593ef3dd710a949b84498ba59ac0353f8e6cd4355e9bfc0ddef8ef25ce41309":"":"":"":"10001":526:0:0:0:0
+
+RSA Import (N,P,Q,D,E) 527-bit complete pair
+mbedtls_rsa_import:"54e6bb611922620e32e0e402446e3a2b8eb1be1f44a750a833ac56635a2aca00fa20cdddf6d185e60623da0ba4dd33011d5df7f7f69d95c98c4ca7fddde08ec209db":"d36b6f6e6828bc2cb35b9b5ecca60ea4d33406b11ff4fafc3b439f3fa9c521733b":"66cdc1ad01f31f5eeafff4774bf4ba95ccb58a5afae6744b560e7181f8b0a119e1":"32e1d958f7044939f33a1ecc5110b2a21a31e21cc13b793665499ab88e78687a2eb19a570263370532aac0c418867027c6275b604899b26f9913a10aaacb7895ddc1":"10001":527:0:1:0:0
+
+RSA Import (N,-,-,-,E) 527-bit public
+mbedtls_rsa_import:"54e6bb611922620e32e0e402446e3a2b8eb1be1f44a750a833ac56635a2aca00fa20cdddf6d185e60623da0ba4dd33011d5df7f7f69d95c98c4ca7fddde08ec209db":"":"":"":"10001":527:0:0:0:0
+
+RSA Import (N,P,Q,D,E) 528-bit complete pair
+mbedtls_rsa_import:"d158d6f8bf79fd0721ad50c08ada2f023bec6970a43cc709dba277046d6e2cfd65b72239c7856c7aea7d40906c4880ce828dc4906d364600cd2dd62a284c9ebfcb59":"ebdbfc4ea38f0dac4032c21663be46d045ce4bec7e6d2d773980fd92ca6aaf0f73":"e33947ec6dccc2ca956495f34923b00a490fdfef67b5332d6f084dccf58191af03":"b2e7b0373e337b1848207c5d3f8c7c15f5adf0e1f1897b33a27e7225d77b0b79b4928fd89ca267c7b334fa39949397a8870a204c9b9e98037bfd8716f0dec4802d3d":"10001":528:0:1:0:0
+
+RSA Import (N,-,-,-,E) 528-bit public
+mbedtls_rsa_import:"d158d6f8bf79fd0721ad50c08ada2f023bec6970a43cc709dba277046d6e2cfd65b72239c7856c7aea7d40906c4880ce828dc4906d364600cd2dd62a284c9ebfcb59":"":"":"":"10001":528:0:0:0:0
 
 RSA Import Raw (N,P,Q,D,E), complete private key
 mbedtls_rsa_import_raw:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"e79a373182bfaa722eb035f772ad2a9464bd842de59432c18bbab3a7dfeae318c9b915ee487861ab665a40bd6cda560152578e8579016c929df99fea05b4d64efca1d543850bc8164b40d71ed7f3fa4105df0fb9b9ad2a18ce182c8a4f4f975bea9aa0b9a1438a27a28e97ac8330ef37383414d1bd64607d6979ac050424fd17":"c6749cbb0db8c5a177672d4728a8b22392b2fc4d3b8361d5c0d5055a1b4e46d821f757c24eef2a51c561941b93b3ace7340074c058c9bb48e7e7414f42c41da4cccb5c2ba91deb30c586b7fb18af12a52995592ad139d3be429add6547e044becedaf31fa3b39421e24ee034fbf367d11f6b8f88ee483d163b431e1654ad3e89":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"03":0:1:0:0
@@ -662,7 +764,7 @@
 rsa_parse_pkcs1_key:0:"3066020100021100cc8ab070369ede72920e5a51523c857102030100010211009a6318982a7231de1894c54aa4909201020900f3058fd8dc484d61020900d7770dbd8b78a2110209009471f14c26428401020813425f060c4b72210208052b93d01747a87c020100":MBEDTLS_ERR_ASN1_LENGTH_MISMATCH
 
 RSA parse private key - correct values, extra integer outside the SEQUENCE
-rsa_parse_pkcs1_key:0:"3063020100021100cc8ab070369ede72920e5a51523c857102030100010211009a6318982a7231de1894c54aa4909201020900f3058fd8dc484d61020900d7770dbd8b78a2110209009471f14c26428401020813425f060c4b72210208052b93d01747a87c020100":0
+rsa_parse_pkcs1_key:0:"3063020100021100cc8ab070369ede72920e5a51523c857102030100010211009a6318982a7231de1894c54aa4909201020900f3058fd8dc484d61020900d7770dbd8b78a2110209009471f14c26428401020813425f060c4b72210208052b93d01747a87c020100":MBEDTLS_ERR_RSA_BAD_INPUT_DATA
 
 RSA parse private key - correct values, n wrong tag
 rsa_parse_pkcs1_key:0:"3063020100FF1100cc8ab070369ede72920e5a51523c857102030100010211009a6318982a7231de1894c54aa4909201020900f3058fd8dc484d61020900d7770dbd8b78a2110209009471f14c26428401020813425f060c4b72210208052b93d01747a87c":MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
@@ -707,7 +809,7 @@
 rsa_parse_pkcs1_key:1:"308189028181009f091e6968b474f76f0e9c237c1d895996ae704b4f6d706acec8d2daac6209bf524aa3f658d0283adba1077f6cbe92e425dcde52290b239cade91be86c88425434986806e85734e159768f3dfea932baaa9409d25bace8ee9dce0cdde0903207299de575ae60feccf0daf82334ab83638539b0da74072f253acea8afc8e66bb70203000000":MBEDTLS_ERR_RSA_BAD_INPUT_DATA
 
 RSA parse public key - wrong sequence length
-rsa_parse_pkcs1_key:1:"308188028181009f091e6968b474f76f0e9c237c1d895996ae704b4f6d706acec8d2daac6209bf524aa3f658d0283adba1077f6cbe92e425dcde52290b239cade91be86c88425434986806e85734e159768f3dfea932baaa9409d25bace8ee9dce0cdde0903207299de575ae60feccf0daf82334ab83638539b0da74072f253acea8afc8e66bb70203010001":MBEDTLS_ERR_ASN1_OUT_OF_DATA
+rsa_parse_pkcs1_key:1:"308188028181009f091e6968b474f76f0e9c237c1d895996ae704b4f6d706acec8d2daac6209bf524aa3f658d0283adba1077f6cbe92e425dcde52290b239cade91be86c88425434986806e85734e159768f3dfea932baaa9409d25bace8ee9dce0cdde0903207299de575ae60feccf0daf82334ab83638539b0da74072f253acea8afc8e66bb70203010001":MBEDTLS_ERR_RSA_BAD_INPUT_DATA
 
 RSA parse public key - wrong modulus length
 rsa_parse_pkcs1_key:1:"308189028180009f091e6968b474f76f0e9c237c1d895996ae704b4f6d706acec8d2daac6209bf524aa3f658d0283adba1077f6cbe92e425dcde52290b239cade91be86c88425434986806e85734e159768f3dfea932baaa9409d25bace8ee9dce0cdde0903207299de575ae60feccf0daf82334ab83638539b0da74072f253acea8afc8e66bb70203010001":MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
@@ -725,7 +827,7 @@
 rsa_parse_pkcs1_key:1:"30818c028181009f091e6968b474f76f0e9c237c1d895996ae704b4f6d706acec8d2daac6209bf524aa3f658d0283adba1077f6cbe92e425dcde52290b239cade91be86c88425434986806e85734e159768f3dfea932baaa9409d25bace8ee9dce0cdde0903207299de575ae60feccf0daf82334ab83638539b0da74072f253acea8afc8e66bb70203010001020100":MBEDTLS_ERR_ASN1_LENGTH_MISMATCH
 
 RSA parse public key - correct values, extra integer outside the SEQUENCE
-rsa_parse_pkcs1_key:1:"308189028181009f091e6968b474f76f0e9c237c1d895996ae704b4f6d706acec8d2daac6209bf524aa3f658d0283adba1077f6cbe92e425dcde52290b239cade91be86c88425434986806e85734e159768f3dfea932baaa9409d25bace8ee9dce0cdde0903207299de575ae60feccf0daf82334ab83638539b0da74072f253acea8afc8e66bb70203010001020100":0
+rsa_parse_pkcs1_key:1:"308189028181009f091e6968b474f76f0e9c237c1d895996ae704b4f6d706acec8d2daac6209bf524aa3f658d0283adba1077f6cbe92e425dcde52290b239cade91be86c88425434986806e85734e159768f3dfea932baaa9409d25bace8ee9dce0cdde0903207299de575ae60feccf0daf82334ab83638539b0da74072f253acea8afc8e66bb70203010001020100":MBEDTLS_ERR_RSA_BAD_INPUT_DATA
 
 RSA priv key write - incremental output buffer size
 rsa_key_write_incremental:0:"3063020100021100cc8ab070369ede72920e5a51523c857102030100010211009a6318982a7231de1894c54aa4909201020900f3058fd8dc484d61020900d7770dbd8b78a2110209009471f14c26428401020813425f060c4b72210208052b93d01747a87c"
diff --git a/tests/suites/test_suite_rsa.function b/tests/suites/test_suite_rsa.function
index 2f70028..e824529 100644
--- a/tests/suites/test_suite_rsa.function
+++ b/tests/suites/test_suite_rsa.function
@@ -183,7 +183,8 @@
     TEST_ASSERT(mbedtls_test_read_mpi(&E, input_E) == 0);
 
     TEST_ASSERT(mbedtls_rsa_import(&ctx, &N, &P, &Q, NULL, &E) == 0);
-    TEST_ASSERT(mbedtls_rsa_get_len(&ctx) == (size_t) (mod / 8));
+    TEST_EQUAL(mbedtls_rsa_get_len(&ctx), (size_t) ((mod + 7) / 8));
+    TEST_EQUAL(mbedtls_rsa_get_bitlen(&ctx), (size_t) mod);
     TEST_ASSERT(mbedtls_rsa_complete(&ctx) == 0);
     TEST_ASSERT(mbedtls_rsa_check_privkey(&ctx) == 0);
 
@@ -221,7 +222,8 @@
     TEST_ASSERT(mbedtls_test_read_mpi(&N, input_N) == 0);
     TEST_ASSERT(mbedtls_test_read_mpi(&E, input_E) == 0);
     TEST_ASSERT(mbedtls_rsa_import(&ctx, &N, NULL, NULL, NULL, &E) == 0);
-    TEST_ASSERT(mbedtls_rsa_get_len(&ctx) == (size_t) (mod / 8));
+    TEST_EQUAL(mbedtls_rsa_get_len(&ctx), (size_t) ((mod + 7) / 8));
+    TEST_EQUAL(mbedtls_rsa_get_bitlen(&ctx), (size_t) mod);
     TEST_ASSERT(mbedtls_rsa_check_pubkey(&ctx) == 0);
 
     TEST_ASSERT(mbedtls_rsa_pkcs1_verify(&ctx, digest, message_str->len, message_str->x,
@@ -262,7 +264,8 @@
     TEST_ASSERT(mbedtls_test_read_mpi(&E, input_E) == 0);
 
     TEST_ASSERT(mbedtls_rsa_import(&ctx, &N, &P, &Q, NULL, &E) == 0);
-    TEST_ASSERT(mbedtls_rsa_get_len(&ctx) == (size_t) (mod / 8));
+    TEST_EQUAL(mbedtls_rsa_get_len(&ctx), (size_t) ((mod + 7) / 8));
+    TEST_EQUAL(mbedtls_rsa_get_bitlen(&ctx), (size_t) mod);
     TEST_ASSERT(mbedtls_rsa_complete(&ctx) == 0);
     TEST_ASSERT(mbedtls_rsa_check_privkey(&ctx) == 0);
 
@@ -305,7 +308,8 @@
     TEST_ASSERT(mbedtls_test_read_mpi(&E, input_E) == 0);
 
     TEST_ASSERT(mbedtls_rsa_import(&ctx, &N, NULL, NULL, NULL, &E) == 0);
-    TEST_ASSERT(mbedtls_rsa_get_len(&ctx) == (size_t) (mod / 8));
+    TEST_EQUAL(mbedtls_rsa_get_len(&ctx), (size_t) ((mod + 7) / 8));
+    TEST_EQUAL(mbedtls_rsa_get_bitlen(&ctx), (size_t) mod);
     TEST_ASSERT(mbedtls_rsa_check_pubkey(&ctx) == 0);
 
 
@@ -341,7 +345,8 @@
     TEST_ASSERT(mbedtls_test_read_mpi(&E, input_E) == 0);
 
     TEST_ASSERT(mbedtls_rsa_import(&ctx, &N, NULL, NULL, NULL, &E) == 0);
-    TEST_ASSERT(mbedtls_rsa_get_len(&ctx) == (size_t) (mod / 8));
+    TEST_EQUAL(mbedtls_rsa_get_len(&ctx), (size_t) ((mod + 7) / 8));
+    TEST_EQUAL(mbedtls_rsa_get_bitlen(&ctx), (size_t) mod);
     TEST_ASSERT(mbedtls_rsa_check_pubkey(&ctx) == 0);
 
 
@@ -382,7 +387,8 @@
     TEST_ASSERT(mbedtls_test_read_mpi(&E, input_E) == 0);
 
     TEST_ASSERT(mbedtls_rsa_import(&ctx, &N, NULL, NULL, NULL, &E) == 0);
-    TEST_ASSERT(mbedtls_rsa_get_len(&ctx) == (size_t) (mod / 8));
+    TEST_EQUAL(mbedtls_rsa_get_len(&ctx), (size_t) ((mod + 7) / 8));
+    TEST_EQUAL(mbedtls_rsa_get_bitlen(&ctx), (size_t) mod);
     TEST_ASSERT(mbedtls_rsa_check_pubkey(&ctx) == 0);
 
 
@@ -432,7 +438,8 @@
     TEST_ASSERT(mbedtls_test_read_mpi(&E, input_E) == 0);
 
     TEST_ASSERT(mbedtls_rsa_import(&ctx, &N, &P, &Q, NULL, &E) == 0);
-    TEST_ASSERT(mbedtls_rsa_get_len(&ctx) == (size_t) (mod / 8));
+    TEST_EQUAL(mbedtls_rsa_get_len(&ctx), (size_t) ((mod + 7) / 8));
+    TEST_EQUAL(mbedtls_rsa_get_bitlen(&ctx), (size_t) mod);
     TEST_ASSERT(mbedtls_rsa_complete(&ctx) == 0);
     TEST_ASSERT(mbedtls_rsa_check_privkey(&ctx) == 0);
 
@@ -477,8 +484,9 @@
     TEST_ASSERT(mbedtls_rsa_import(&ctx, &N, NULL, NULL, NULL, &E) == 0);
 
     /* Check test data consistency */
-    TEST_ASSERT(message_str->len == (size_t) (mod / 8));
-    TEST_ASSERT(mbedtls_rsa_get_len(&ctx) == (size_t) (mod / 8));
+    TEST_EQUAL(message_str->len, (size_t) ((mod + 7) / 8));
+    TEST_EQUAL(mbedtls_rsa_get_len(&ctx), (size_t) ((mod + 7) / 8));
+    TEST_EQUAL(mbedtls_rsa_get_bitlen(&ctx), (size_t) mod);
     TEST_ASSERT(mbedtls_rsa_check_pubkey(&ctx) == 0);
 
     TEST_ASSERT(mbedtls_rsa_public(&ctx, message_str->x, output) == result);
@@ -537,8 +545,9 @@
     TEST_ASSERT(mbedtls_rsa_import(&ctx, &N, &P, &Q, NULL, &E) == 0);
 
     /* Check test data consistency */
-    TEST_ASSERT(message_str->len == (size_t) (mod / 8));
-    TEST_ASSERT(mbedtls_rsa_get_len(&ctx) == (size_t) (mod / 8));
+    TEST_EQUAL(message_str->len, (size_t) ((mod + 7) / 8));
+    TEST_EQUAL(mbedtls_rsa_get_len(&ctx), (size_t) ((mod + 7) / 8));
+    TEST_EQUAL(mbedtls_rsa_get_bitlen(&ctx), (size_t) mod);
     TEST_ASSERT(mbedtls_rsa_complete(&ctx) == 0);
     TEST_ASSERT(mbedtls_rsa_check_privkey(&ctx) == 0);
 
@@ -851,6 +860,7 @@
                         char *input_Q,
                         char *input_D,
                         char *input_E,
+                        int bitlen,
                         int successive,
                         int is_priv,
                         int res_check,
@@ -936,6 +946,9 @@
     /* On expected success, perform some public and private
      * key operations to check if the key is working properly. */
     if (res_complete == 0) {
+        TEST_EQUAL(mbedtls_rsa_get_bitlen(&ctx), bitlen);
+        TEST_EQUAL(mbedtls_rsa_get_len(&ctx), (bitlen + 7) / 8);
+
         if (is_priv) {
             TEST_ASSERT(mbedtls_rsa_check_privkey(&ctx) == res_check);
         } else {
diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data
index 86945cc..c0c816c 100644
--- a/tests/suites/test_suite_ssl.data
+++ b/tests/suites/test_suite_ssl.data
@@ -3274,11 +3274,74 @@
 TLS 1.3 resume session with ticket
 tls13_resume_session_with_ticket
 
-TLS 1.3 early data, reference
-tls13_early_data:TEST_EARLY_DATA_REFERENCE
+TLS 1.3 read early data, early data accepted
+tls13_read_early_data:TEST_EARLY_DATA_ACCEPTED
 
-TLS 1.3 early data, deprotect and discard
-tls13_early_data:TEST_EARLY_DATA_DEPROTECT_AND_DISCARD
+TLS 1.3 read early data, no early data indication
+tls13_read_early_data:TEST_EARLY_DATA_NO_INDICATION_SENT
 
-TLS 1.3 early data, discard after HRR
-tls13_early_data:TEST_EARLY_DATA_DISCARD_AFTER_HRR
+TLS 1.3 read early data, server rejects early data
+tls13_read_early_data:TEST_EARLY_DATA_SERVER_REJECTS
+
+TLS 1.3 read early data, discard after HRR
+tls13_read_early_data:TEST_EARLY_DATA_HRR
+
+TLS 1.3 cli, early data status, early data accepted
+tls13_cli_early_data_status:TEST_EARLY_DATA_ACCEPTED
+
+TLS 1.3 cli, early data status, no early data indication
+tls13_cli_early_data_status:TEST_EARLY_DATA_NO_INDICATION_SENT
+
+TLS 1.3 cli, early data status, server rejects early data
+tls13_cli_early_data_status:TEST_EARLY_DATA_SERVER_REJECTS
+
+TLS 1.3 cli, early data status, hello retry request
+tls13_cli_early_data_status:TEST_EARLY_DATA_HRR
+
+TLS 1.3 write early data, early data accepted
+tls13_write_early_data:TEST_EARLY_DATA_ACCEPTED
+
+TLS 1.3 write early data, no early data indication
+tls13_write_early_data:TEST_EARLY_DATA_NO_INDICATION_SENT
+
+TLS 1.3 write early data, server rejects early data
+tls13_write_early_data:TEST_EARLY_DATA_SERVER_REJECTS
+
+TLS 1.3 write early data, hello retry request
+tls13_write_early_data:TEST_EARLY_DATA_HRR
+
+TLS 1.3 srv, max early data size, dflt, wsz=96
+tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:-1:96
+
+TLS 1.3 srv, max early data size, dflt, wsz=128
+tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:-1:128
+
+TLS 1.3 srv, max early data size, 3, wsz=2
+tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:3:2
+
+TLS 1.3 srv, max early data size, 3, wsz=3
+tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:3:3
+
+TLS 1.3 srv, max early data size, 98, wsz=23
+tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:98:23
+
+TLS 1.3 srv, max early data size, 98, wsz=49
+tls13_srv_max_early_data_size:TEST_EARLY_DATA_ACCEPTED:98:49
+
+TLS 1.3 srv, max early data size, server rejects, dflt, wsz=128
+tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:-1:128
+
+TLS 1.3 srv, max early data size, server rejects, 3, wsz=3
+tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:3:3
+
+TLS 1.3 srv, max early data size, server rejects, 98, wsz=49
+tls13_srv_max_early_data_size:TEST_EARLY_DATA_SERVER_REJECTS:98:49
+
+TLS 1.3 srv, max early data size, HRR, dflt, wsz=128
+tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:-1:128
+
+TLS 1.3 srv, max early data size, HRR, 3, wsz=3
+tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:3:3
+
+TLS 1.3 srv, max early data size, HRR, 98, wsz=49
+tls13_srv_max_early_data_size:TEST_EARLY_DATA_HRR:97:0
diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function
index 8687a4d..6e95817 100644
--- a/tests/suites/test_suite_ssl.function
+++ b/tests/suites/test_suite_ssl.function
@@ -13,9 +13,10 @@
 #define SSL_MESSAGE_QUEUE_INIT      { NULL, 0, 0, 0 }
 
 /* Mnemonics for the early data test scenarios */
-#define TEST_EARLY_DATA_REFERENCE 0
-#define TEST_EARLY_DATA_DEPROTECT_AND_DISCARD 1
-#define TEST_EARLY_DATA_DISCARD_AFTER_HRR 2
+#define TEST_EARLY_DATA_ACCEPTED 0
+#define TEST_EARLY_DATA_NO_INDICATION_SENT 1
+#define TEST_EARLY_DATA_SERVER_REJECTS 2
+#define TEST_EARLY_DATA_HRR 3
 
 #if (!defined(MBEDTLS_SSL_PROTO_TLS1_2)) && \
     defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C) && \
@@ -27,10 +28,8 @@
     defined(MBEDTLS_ECP_HAVE_SECP256R1) && defined(MBEDTLS_ECP_HAVE_SECP384R1) && \
     defined(MBEDTLS_PK_CAN_ECDSA_VERIFY) && defined(MBEDTLS_SSL_SESSION_TICKETS)
 /*
- * The implementation of the function should be based on
- * mbedtls_ssl_write_early_data() eventually. The current version aims at
- * removing the dependency on mbedtls_ssl_write_early_data() for the
- * development and testing of reading early data.
+ * Test function to write early data for negative tests where
+ * mbedtls_ssl_write_early_data() cannot be used.
  */
 static int write_early_data(mbedtls_ssl_context *ssl,
                             unsigned char *buf, size_t len)
@@ -38,7 +37,7 @@
     int ret = mbedtls_ssl_get_max_out_record_payload(ssl);
 
     TEST_ASSERT(ret > 0);
-    TEST_ASSERT(len <= (size_t) ret);
+    TEST_LE_U(len, (size_t) ret);
 
     ret = mbedtls_ssl_flush_output(ssl);
     TEST_EQUAL(ret, 0);
@@ -1173,6 +1172,8 @@
                                             MBEDTLS_SSL_IS_CLIENT,
                                             MBEDTLS_SSL_TRANSPORT_DATAGRAM,
                                             MBEDTLS_SSL_PRESET_DEFAULT) == 0);
+    mbedtls_ssl_conf_rng(&conf, mbedtls_test_random, NULL);
+
     TEST_ASSERT(mbedtls_ssl_setup(&ssl, &conf) == 0);
 
     /* Read previous record numbers */
@@ -1989,7 +1990,6 @@
     USE_PSA_INIT();
 
     /* Prepare a dummy session to work on */
-    ((void) endpoint_type);
     ((void) tls_version);
     ((void) ticket_len);
     ((void) crt_file);
@@ -2003,7 +2003,7 @@
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
     if (tls_version == MBEDTLS_SSL_VERSION_TLS1_2) {
         TEST_ASSERT(mbedtls_test_ssl_tls12_populate_session(
-                        &original, ticket_len, crt_file) == 0);
+                        &original, ticket_len, endpoint_type, crt_file) == 0);
     }
 #endif
 
@@ -2021,28 +2021,16 @@
      * Make sure both session structures are identical
      */
 #if defined(MBEDTLS_HAVE_TIME)
-    switch (tls_version) {
-#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SRV_C)
-        case MBEDTLS_SSL_VERSION_TLS1_3:
-            TEST_ASSERT(original.ticket_creation_time == restored.ticket_creation_time);
-            break;
-#endif
-#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
-        case MBEDTLS_SSL_VERSION_TLS1_2:
-            TEST_ASSERT(original.start == restored.start);
-            break;
-#endif
-
-        default:
-            /* should never happen */
-            TEST_ASSERT(0);
-            break;
+    if (tls_version == MBEDTLS_SSL_VERSION_TLS1_2) {
+        TEST_ASSERT(original.start == restored.start);
     }
-
-
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_SRV_C)
+    TEST_ASSERT(original.ticket_creation_time == restored.ticket_creation_time);
 #endif
+#endif /* MBEDTLS_HAVE_TIME */
 
     TEST_ASSERT(original.tls_version == restored.tls_version);
+    TEST_ASSERT(original.endpoint == restored.endpoint);
     TEST_ASSERT(original.ciphersuite == restored.ciphersuite);
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
     if (tls_version == MBEDTLS_SSL_VERSION_TLS1_2) {
@@ -2101,7 +2089,6 @@
 
 #if defined(MBEDTLS_SSL_PROTO_TLS1_3)
     if (tls_version == MBEDTLS_SSL_VERSION_TLS1_3) {
-        TEST_ASSERT(original.endpoint == restored.endpoint);
         TEST_ASSERT(original.ciphersuite == restored.ciphersuite);
         TEST_ASSERT(original.ticket_age_add == restored.ticket_age_add);
         TEST_ASSERT(original.ticket_flags == restored.ticket_flags);
@@ -2119,11 +2106,6 @@
             original.max_early_data_size == restored.max_early_data_size);
 #endif
 
-#if defined(MBEDTLS_HAVE_TIME) && defined(MBEDTLS_SSL_SRV_C)
-        if (endpoint_type == MBEDTLS_SSL_IS_SERVER) {
-            TEST_ASSERT(original.ticket_creation_time == restored.ticket_creation_time);
-        }
-#endif
 #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
         if (endpoint_type == MBEDTLS_SSL_IS_CLIENT) {
 #if defined(MBEDTLS_HAVE_TIME)
@@ -2171,7 +2153,6 @@
     USE_PSA_INIT();
 
     /* Prepare a dummy session to work on */
-    ((void) endpoint_type);
     ((void) ticket_len);
     ((void) crt_file);
 
@@ -2186,7 +2167,7 @@
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
         case MBEDTLS_SSL_VERSION_TLS1_2:
             TEST_ASSERT(mbedtls_test_ssl_tls12_populate_session(
-                            &session, ticket_len, crt_file) == 0);
+                            &session, ticket_len, endpoint_type, crt_file) == 0);
             break;
 #endif
         default:
@@ -2245,7 +2226,6 @@
     USE_PSA_INIT();
 
     /* Prepare dummy session and get serialized size */
-    ((void) endpoint_type);
     ((void) ticket_len);
     ((void) crt_file);
 
@@ -2259,7 +2239,7 @@
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
         case MBEDTLS_SSL_VERSION_TLS1_2:
             TEST_ASSERT(mbedtls_test_ssl_tls12_populate_session(
-                            &session, ticket_len, crt_file) == 0);
+                            &session, ticket_len, endpoint_type, crt_file) == 0);
             break;
 #endif
         default:
@@ -2305,7 +2285,6 @@
     USE_PSA_INIT();
 
     /* Prepare serialized session data */
-    ((void) endpoint_type);
     ((void) ticket_len);
     ((void) crt_file);
 
@@ -2320,7 +2299,7 @@
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
         case MBEDTLS_SSL_VERSION_TLS1_2:
             TEST_ASSERT(mbedtls_test_ssl_tls12_populate_session(
-                            &session, ticket_len, crt_file) == 0);
+                            &session, ticket_len, endpoint_type, crt_file) == 0);
             break;
 #endif
 
@@ -2377,7 +2356,6 @@
 
     mbedtls_ssl_session_init(&session);
     USE_PSA_INIT();
-    ((void) endpoint_type);
 
     switch (tls_version) {
 #if defined(MBEDTLS_SSL_PROTO_TLS1_3)
@@ -2389,7 +2367,7 @@
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
         case MBEDTLS_SSL_VERSION_TLS1_2:
             TEST_ASSERT(mbedtls_test_ssl_tls12_populate_session(
-                            &session, 0, NULL) == 0);
+                            &session, 0, endpoint_type, NULL) == 0);
 
             break;
 #endif
@@ -2457,7 +2435,7 @@
     MD_OR_USE_PSA_INIT();
 
     ret = mbedtls_test_ssl_endpoint_init(NULL, endpoint_type, &options,
-                                         NULL, NULL, NULL, NULL);
+                                         NULL, NULL, NULL);
     TEST_ASSERT(MBEDTLS_ERR_SSL_BAD_INPUT_DATA == ret);
 
     ret = mbedtls_test_ssl_endpoint_certificate_init(NULL, options.pk_alg,
@@ -2465,7 +2443,7 @@
     TEST_ASSERT(MBEDTLS_ERR_SSL_BAD_INPUT_DATA == ret);
 
     ret = mbedtls_test_ssl_endpoint_init(&ep, endpoint_type, &options,
-                                         NULL, NULL, NULL, NULL);
+                                         NULL, NULL, NULL);
     TEST_ASSERT(ret == 0);
 
 exit:
@@ -2509,14 +2487,14 @@
     mbedtls_platform_zeroize(&second_ep, sizeof(second_ep));
 
     ret = mbedtls_test_ssl_endpoint_init(&base_ep, endpoint_type, &options,
-                                         NULL, NULL, NULL, NULL);
+                                         NULL, NULL, NULL);
     TEST_ASSERT(ret == 0);
 
     ret = mbedtls_test_ssl_endpoint_init(
         &second_ep,
         (endpoint_type == MBEDTLS_SSL_IS_SERVER) ?
         MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
-        &options, NULL, NULL, NULL, NULL);
+        &options, NULL, NULL, NULL);
 
     TEST_ASSERT(ret == 0);
 
@@ -2944,6 +2922,7 @@
     mbedtls_ssl_conf_transport(&conf, transport);
     mbedtls_ssl_conf_min_tls_version(&conf, min_tls_version);
     mbedtls_ssl_conf_max_tls_version(&conf, max_tls_version);
+    mbedtls_ssl_conf_rng(&conf, mbedtls_test_random, NULL);
 
     TEST_ASSERT(mbedtls_ssl_setup(&ssl, &conf) == expected_ssl_setup_result);
     TEST_EQUAL(mbedtls_ssl_conf_get_endpoint(
@@ -2985,6 +2964,8 @@
     mbedtls_ssl_init(&ssl);
     MD_OR_USE_PSA_INIT();
 
+    mbedtls_ssl_conf_rng(&conf, mbedtls_test_random, NULL);
+
     TEST_ASSERT(mbedtls_ssl_setup(&ssl, &conf) == 0);
 
     TEST_ASSERT(ssl.handshake != NULL && ssl.handshake->group_list != NULL);
@@ -3016,6 +2997,7 @@
     mbedtls_ssl_config conf;
     mbedtls_ssl_config_init(&conf);
 
+    mbedtls_ssl_conf_rng(&conf, mbedtls_test_random, NULL);
     mbedtls_ssl_conf_max_tls_version(&conf, MBEDTLS_SSL_VERSION_TLS1_2);
     mbedtls_ssl_conf_min_tls_version(&conf, MBEDTLS_SSL_VERSION_TLS1_2);
 
@@ -3069,11 +3051,10 @@
 
     TEST_ASSERT(mbedtls_test_ssl_endpoint_init(&client, MBEDTLS_SSL_IS_CLIENT,
                                                &options, NULL, NULL,
-                                               NULL, NULL) == 0);
+                                               NULL) == 0);
 
     TEST_ASSERT(mbedtls_test_ssl_endpoint_init(&server, MBEDTLS_SSL_IS_SERVER,
-                                               &options, NULL, NULL, NULL,
-                                               NULL) == 0);
+                                               &options, NULL, NULL, NULL) == 0);
 
     mbedtls_debug_set_threshold(1);
     mbedtls_ssl_conf_dbg(&server.conf, options.srv_log_fun,
@@ -3125,6 +3106,7 @@
                                            MBEDTLS_SSL_TRANSPORT_DATAGRAM,
                                            MBEDTLS_SSL_PRESET_DEFAULT),
                0);
+    mbedtls_ssl_conf_rng(&conf, mbedtls_test_random, NULL);
 
     TEST_EQUAL(mbedtls_ssl_setup(&ssl, &conf), 0);
     TEST_EQUAL(mbedtls_ssl_check_dtls_clihlo_cookie(&ssl, ssl.cli_id,
@@ -3179,6 +3161,7 @@
                                             MBEDTLS_SSL_TRANSPORT_STREAM,
                                             MBEDTLS_SSL_PRESET_DEFAULT)
                 == 0);
+    mbedtls_ssl_conf_rng(&conf, mbedtls_test_random, NULL);
 
     TEST_ASSERT(mbedtls_ssl_setup(&ssl, &conf) == 0);
 
@@ -3248,8 +3231,9 @@
     mbedtls_test_ssl_endpoint client, server;
     mbedtls_psa_stats_t stats;
     size_t free_slots_before = -1;
-    mbedtls_test_handshake_test_options options;
-    mbedtls_test_init_handshake_options(&options);
+    mbedtls_test_handshake_test_options client_options, server_options;
+    mbedtls_test_init_handshake_options(&client_options);
+    mbedtls_test_init_handshake_options(&server_options);
 
     uint16_t iana_tls_group_list[] = { MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1,
                                        MBEDTLS_SSL_IANA_TLS_GROUP_NONE };
@@ -3257,21 +3241,22 @@
     mbedtls_platform_zeroize(&client, sizeof(client));
     mbedtls_platform_zeroize(&server, sizeof(server));
 
-    options.pk_alg = MBEDTLS_PK_ECDSA;
-    options.server_min_version = MBEDTLS_SSL_VERSION_TLS1_2;
-    options.server_max_version = MBEDTLS_SSL_VERSION_TLS1_2;
-
     /* Client side, force SECP256R1 to make one key bitflip fail
      * the raw key agreement. Flipping the first byte makes the
      * required 0x04 identifier invalid. */
+    client_options.pk_alg = MBEDTLS_PK_ECDSA;
+    client_options.group_list = iana_tls_group_list;
     TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&client, MBEDTLS_SSL_IS_CLIENT,
-                                              &options, NULL, NULL,
-                                              NULL, iana_tls_group_list), 0);
+                                              &client_options, NULL, NULL,
+                                              NULL), 0);
 
     /* Server side */
+    server_options.pk_alg = MBEDTLS_PK_ECDSA;
+    server_options.server_min_version = MBEDTLS_SSL_VERSION_TLS1_2;
+    server_options.server_max_version = MBEDTLS_SSL_VERSION_TLS1_2;
     TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&server, MBEDTLS_SSL_IS_SERVER,
-                                              &options, NULL, NULL,
-                                              NULL, NULL), 0);
+                                              &server_options, NULL, NULL,
+                                              NULL), 0);
 
     TEST_EQUAL(mbedtls_test_mock_socket_connect(&(client.socket),
                                                 &(server.socket),
@@ -3307,7 +3292,8 @@
 exit:
     mbedtls_test_ssl_endpoint_free(&client, NULL);
     mbedtls_test_ssl_endpoint_free(&server, NULL);
-    mbedtls_test_free_handshake_options(&options);
+    mbedtls_test_free_handshake_options(&client_options);
+    mbedtls_test_free_handshake_options(&server_options);
 
     MD_OR_USE_PSA_DONE();
 }
@@ -3336,15 +3322,13 @@
 
     client_options.pk_alg = MBEDTLS_PK_ECDSA;
     ret = mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT,
-                                         &client_options, NULL, NULL, NULL,
-                                         NULL);
+                                         &client_options, NULL, NULL, NULL);
     TEST_EQUAL(ret, 0);
 
     mbedtls_test_init_handshake_options(&server_options);
     server_options.pk_alg = MBEDTLS_PK_ECDSA;
     ret = mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER,
-                                         &server_options, NULL, NULL, NULL,
-                                         NULL);
+                                         &server_options, NULL, NULL, NULL);
     TEST_EQUAL(ret, 0);
 
     ret = mbedtls_test_mock_socket_connect(&(client_ep.socket),
@@ -3436,6 +3420,7 @@
                                            MBEDTLS_SSL_IS_CLIENT,
                                            MBEDTLS_SSL_TRANSPORT_STREAM,
                                            MBEDTLS_SSL_PRESET_DEFAULT), 0);
+    mbedtls_ssl_conf_rng(&conf, mbedtls_test_random, NULL);
 
     TEST_EQUAL(mbedtls_ssl_setup(&ssl, &conf), 0);
 
@@ -3572,15 +3557,11 @@
 void tls13_resume_session_with_ticket()
 {
     int ret = -1;
-    unsigned char buf[64];
     mbedtls_test_ssl_endpoint client_ep, server_ep;
     mbedtls_test_handshake_test_options client_options;
     mbedtls_test_handshake_test_options server_options;
     mbedtls_ssl_session saved_session;
 
-    /*
-     * Test set-up
-     */
     mbedtls_platform_zeroize(&client_ep, sizeof(client_ep));
     mbedtls_platform_zeroize(&server_ep, sizeof(server_ep));
     mbedtls_test_init_handshake_options(&client_options);
@@ -3589,16 +3570,27 @@
 
     PSA_INIT();
 
+    /*
+     * Run first handshake to get a ticket from the server.
+     */
     client_options.pk_alg = MBEDTLS_PK_ECDSA;
-    ret = mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT,
-                                         &client_options, NULL, NULL, NULL,
-                                         NULL);
+    server_options.pk_alg = MBEDTLS_PK_ECDSA;
+
+    ret = mbedtls_test_get_tls13_ticket(&client_options, &server_options,
+                                        &saved_session);
     TEST_EQUAL(ret, 0);
 
-    server_options.pk_alg = MBEDTLS_PK_ECDSA;
+    /*
+     * Prepare for handshake with the ticket.
+     */
+    ret = mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT,
+                                         &client_options, NULL, NULL, NULL);
+    TEST_EQUAL(ret, 0);
+
     ret = mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER,
-                                         &server_options, NULL, NULL, NULL,
-                                         NULL);
+                                         &server_options, NULL, NULL, NULL);
+    TEST_EQUAL(ret, 0);
+
     mbedtls_ssl_conf_session_tickets_cb(&server_ep.conf,
                                         mbedtls_test_ticket_write,
                                         mbedtls_test_ticket_parse,
@@ -3609,41 +3601,12 @@
                                            &(server_ep.socket), 1024);
     TEST_EQUAL(ret, 0);
 
-    /*
-     * Run initial handshake: ephemeral key exchange mode, certificate with
-     * SECP256R1 key, CA certificate with SECP384R1 key, ECDSA signature
-     * algorithm. Then, get the ticket sent by the server at the end of its
-     * handshake sequence.
-     */
-    TEST_EQUAL(mbedtls_test_move_handshake_to_state(
-                   &(server_ep.ssl), &(client_ep.ssl),
-                   MBEDTLS_SSL_HANDSHAKE_OVER), 0);
-
-    do {
-        ret = mbedtls_ssl_read(&(client_ep.ssl), buf, sizeof(buf));
-    } while (ret != MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET);
-
-    /*
-     * Save client session and reset the SSL context of the two endpoints.
-     */
-    ret = mbedtls_ssl_get_session(&(client_ep.ssl), &saved_session);
-    TEST_EQUAL(ret, 0);
-
-    ret = mbedtls_ssl_session_reset(&(client_ep.ssl));
-    TEST_EQUAL(ret, 0);
-
-    ret = mbedtls_ssl_session_reset(&(server_ep.ssl));
-    TEST_EQUAL(ret, 0);
-
-    /*
-     * Set saved session on client side and handshake using the ticket
-     * included in that session.
-     */
-
     ret = mbedtls_ssl_set_session(&(client_ep.ssl), &saved_session);
     TEST_EQUAL(ret, 0);
 
     /*
+     * Handshake with ticket.
+     *
      * Run the handshake up to MBEDTLS_SSL_HANDSHAKE_WRAPUP and not
      * MBEDTLS_SSL_HANDSHAKE_OVER to preserve handshake data for the checks
      * below.
@@ -3668,12 +3631,12 @@
 /* END_CASE */
 
 /*
- * The !MBEDTLS_SSL_PROTO_TLS1_2 dependency of tls13_early_data() below is
+ * The !MBEDTLS_SSL_PROTO_TLS1_2 dependency of tls13_read_early_data() below is
  * a temporary workaround to not run the test in Windows-2013 where there is
  * an issue with mbedtls_vsnprintf().
  */
 /* BEGIN_CASE depends_on:!MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_EARLY_DATA:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_DEBUG_C:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED:MBEDTLS_MD_CAN_SHA256:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_ECP_HAVE_SECP384R1:MBEDTLS_PK_CAN_ECDSA_VERIFY:MBEDTLS_SSL_SESSION_TICKETS */
-void tls13_early_data(int scenario)
+void tls13_read_early_data(int scenario)
 {
     int ret = -1;
     unsigned char buf[64];
@@ -3690,9 +3653,6 @@
         MBEDTLS_SSL_IANA_TLS_GROUP_NONE
     };
 
-    /*
-     * Test set-up
-     */
     mbedtls_platform_zeroize(&client_ep, sizeof(client_ep));
     mbedtls_platform_zeroize(&server_ep, sizeof(server_ep));
     mbedtls_test_init_handshake_options(&client_options);
@@ -3701,21 +3661,60 @@
 
     PSA_INIT();
 
-    client_options.pk_alg = MBEDTLS_PK_ECDSA;
-    ret = mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT,
-                                         &client_options, NULL, NULL, NULL,
-                                         group_list);
-    TEST_EQUAL(ret, 0);
-    mbedtls_ssl_conf_early_data(&client_ep.conf, MBEDTLS_SSL_EARLY_DATA_ENABLED);
+    /*
+     * Run first handshake to get a ticket from the server.
+     */
 
+    client_options.pk_alg = MBEDTLS_PK_ECDSA;
+    client_options.group_list = group_list;
+    client_options.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED;
     server_options.pk_alg = MBEDTLS_PK_ECDSA;
+    server_options.group_list = group_list;
+    server_options.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED;
+
+    ret = mbedtls_test_get_tls13_ticket(&client_options, &server_options,
+                                        &saved_session);
+    TEST_EQUAL(ret, 0);
+
+    /*
+     * Prepare for handshake with the ticket.
+     */
+    switch (scenario) {
+        case TEST_EARLY_DATA_ACCEPTED:
+            break;
+
+        case TEST_EARLY_DATA_NO_INDICATION_SENT:
+            client_options.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED;
+            break;
+
+        case TEST_EARLY_DATA_SERVER_REJECTS:
+            mbedtls_debug_set_threshold(3);
+            server_pattern.pattern =
+                "EarlyData: deprotect and discard app data records.";
+            server_options.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED;
+            break;
+
+        case TEST_EARLY_DATA_HRR:
+            mbedtls_debug_set_threshold(3);
+            server_pattern.pattern =
+                "EarlyData: Ignore application message before 2nd ClientHello";
+            server_options.group_list = group_list + 1;
+            break;
+
+        default:
+            TEST_FAIL("Unknown scenario.");
+    }
+
+    ret = mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT,
+                                         &client_options, NULL, NULL, NULL);
+    TEST_EQUAL(ret, 0);
+
     server_options.srv_log_fun = mbedtls_test_ssl_log_analyzer;
     server_options.srv_log_obj = &server_pattern;
     ret = mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER,
-                                         &server_options, NULL, NULL, NULL,
-                                         group_list);
+                                         &server_options, NULL, NULL, NULL);
     TEST_EQUAL(ret, 0);
-    mbedtls_ssl_conf_early_data(&server_ep.conf, MBEDTLS_SSL_EARLY_DATA_ENABLED);
+
     mbedtls_ssl_conf_session_tickets_cb(&server_ep.conf,
                                         mbedtls_test_ticket_write,
                                         mbedtls_test_ticket_parse,
@@ -3725,86 +3724,33 @@
                                            &(server_ep.socket), 1024);
     TEST_EQUAL(ret, 0);
 
-    /*
-     * Run initial handshake: ephemeral key exchange mode, certificate with
-     * SECP256R1 key, CA certificate with SECP384R1 key, ECDSA signature
-     * algorithm. Then, get the ticket sent by the server at the end of its
-     * handshake sequence.
-     */
-    TEST_EQUAL(mbedtls_test_move_handshake_to_state(
-                   &(server_ep.ssl), &(client_ep.ssl),
-                   MBEDTLS_SSL_HANDSHAKE_OVER), 0);
-
-    do {
-        ret = mbedtls_ssl_read(&(client_ep.ssl), buf, sizeof(buf));
-    } while (ret != MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET);
-
-    /*
-     * Save client session and reset the SSL context of the two endpoints.
-     */
-    ret = mbedtls_ssl_get_session(&(client_ep.ssl), &saved_session);
-    TEST_EQUAL(ret, 0);
-
-    ret = mbedtls_ssl_session_reset(&(client_ep.ssl));
-    TEST_EQUAL(ret, 0);
-
-    ret = mbedtls_ssl_session_reset(&(server_ep.ssl));
-    TEST_EQUAL(ret, 0);
-
-    /*
-     * Set saved session on client side and start handshake using the ticket
-     * included in that session.
-     */
-
     ret = mbedtls_ssl_set_session(&(client_ep.ssl), &saved_session);
     TEST_EQUAL(ret, 0);
 
-    switch (scenario) {
-        case TEST_EARLY_DATA_REFERENCE:
-            break;
-
-        case TEST_EARLY_DATA_DEPROTECT_AND_DISCARD:
-            mbedtls_debug_set_threshold(3);
-            server_pattern.pattern =
-                "EarlyData: deprotect and discard app data records.";
-            mbedtls_ssl_conf_early_data(&server_ep.conf,
-                                        MBEDTLS_SSL_EARLY_DATA_DISABLED);
-            break;
-
-        case TEST_EARLY_DATA_DISCARD_AFTER_HRR:
-            mbedtls_debug_set_threshold(3);
-            server_pattern.pattern =
-                "EarlyData: Ignore application message before 2nd ClientHello";
-            mbedtls_ssl_conf_groups(&server_ep.conf, group_list + 1);
-            /*
-             * Need to reset again to reconstruct the group list in the
-             * handshake structure from the configured one.
-             */
-            ret = mbedtls_ssl_session_reset(&(server_ep.ssl));
-            TEST_EQUAL(ret, 0);
-            break;
-
-        default:
-            TEST_FAIL("Unknown scenario.");
-    }
-
+    /*
+     * Handshake with ticket and send early data.
+     */
     TEST_EQUAL(mbedtls_test_move_handshake_to_state(
                    &(client_ep.ssl), &(server_ep.ssl),
                    MBEDTLS_SSL_SERVER_HELLO), 0);
 
-    TEST_ASSERT(client_ep.ssl.early_data_status !=
-                MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT);
+    ret = mbedtls_ssl_write_early_data(&(client_ep.ssl),
+                                       (unsigned char *) early_data,
+                                       early_data_len);
 
-    ret = write_early_data(&(client_ep.ssl), (unsigned char *) early_data,
-                           early_data_len);
-    TEST_EQUAL(ret, early_data_len);
+    if (client_ep.ssl.early_data_status !=
+        MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT) {
+        TEST_EQUAL(ret, early_data_len);
+    } else {
+        TEST_EQUAL(ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA);
+    }
 
     ret = mbedtls_test_move_handshake_to_state(
         &(server_ep.ssl), &(client_ep.ssl),
         MBEDTLS_SSL_HANDSHAKE_WRAPUP);
 
     switch (scenario) {
-        case TEST_EARLY_DATA_REFERENCE:
+        case TEST_EARLY_DATA_ACCEPTED:
             TEST_EQUAL(ret, MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA);
             TEST_EQUAL(server_ep.ssl.handshake->early_data_accepted, 1);
             TEST_EQUAL(mbedtls_ssl_read_early_data(&(server_ep.ssl),
@@ -3812,12 +3758,20 @@
             TEST_MEMORY_COMPARE(buf, early_data_len, early_data, early_data_len);
             break;
 
-        case TEST_EARLY_DATA_DEPROTECT_AND_DISCARD: /* Intentional fallthrough */
-        case TEST_EARLY_DATA_DISCARD_AFTER_HRR:
+        case TEST_EARLY_DATA_NO_INDICATION_SENT:
+            TEST_EQUAL(ret, 0);
+            TEST_EQUAL(server_ep.ssl.handshake->early_data_accepted, 0);
+            break;
+
+        case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */
+        case TEST_EARLY_DATA_HRR:
             TEST_EQUAL(ret, 0);
             TEST_EQUAL(server_ep.ssl.handshake->early_data_accepted, 0);
             TEST_EQUAL(server_pattern.counter, 1);
             break;
+
+        default:
+            TEST_FAIL("Unknown scenario.");
     }
 
     TEST_EQUAL(mbedtls_test_move_handshake_to_state(
@@ -3834,3 +3788,973 @@
     PSA_DONE();
 }
 /* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_SSL_EARLY_DATA:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED:MBEDTLS_MD_CAN_SHA256:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_ECP_HAVE_SECP384R1:MBEDTLS_PK_CAN_ECDSA_VERIFY:MBEDTLS_SSL_SESSION_TICKETS */
+void tls13_cli_early_data_status(int scenario)
+{
+    int ret = -1;
+    mbedtls_test_ssl_endpoint client_ep, server_ep;
+    mbedtls_test_handshake_test_options client_options;
+    mbedtls_test_handshake_test_options server_options;
+    mbedtls_ssl_session saved_session;
+    uint16_t group_list[3] = {
+        MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1,
+        MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1,
+        MBEDTLS_SSL_IANA_TLS_GROUP_NONE
+    };
+
+    mbedtls_platform_zeroize(&client_ep, sizeof(client_ep));
+    mbedtls_platform_zeroize(&server_ep, sizeof(server_ep));
+    mbedtls_test_init_handshake_options(&client_options);
+    mbedtls_test_init_handshake_options(&server_options);
+    mbedtls_ssl_session_init(&saved_session);
+
+    PSA_INIT();
+
+    /*
+     * Run first handshake to get a ticket from the server.
+     */
+    client_options.pk_alg = MBEDTLS_PK_ECDSA;
+    client_options.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED;
+    server_options.pk_alg = MBEDTLS_PK_ECDSA;
+    server_options.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED;
+    if (scenario == TEST_EARLY_DATA_HRR) {
+        client_options.group_list = group_list;
+        server_options.group_list = group_list;
+    }
+
+    ret = mbedtls_test_get_tls13_ticket(&client_options, &server_options,
+                                        &saved_session);
+    TEST_EQUAL(ret, 0);
+
+    /*
+     * Prepare for handshake with the ticket.
+     */
+    switch (scenario) {
+        case TEST_EARLY_DATA_ACCEPTED:
+            break;
+
+        case TEST_EARLY_DATA_NO_INDICATION_SENT:
+            client_options.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED;
+            break;
+
+        case TEST_EARLY_DATA_SERVER_REJECTS:
+            server_options.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED;
+            break;
+
+        case TEST_EARLY_DATA_HRR:
+            server_options.group_list = group_list + 1;
+            break;
+
+        default:
+            TEST_FAIL("Unknown scenario.");
+    }
+
+    ret = mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT,
+                                         &client_options, NULL, NULL, NULL);
+    TEST_EQUAL(ret, 0);
+
+    ret = mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER,
+                                         &server_options, NULL, NULL, NULL);
+    TEST_EQUAL(ret, 0);
+
+    mbedtls_ssl_conf_session_tickets_cb(&server_ep.conf,
+                                        mbedtls_test_ticket_write,
+                                        mbedtls_test_ticket_parse,
+                                        NULL);
+
+    ret = mbedtls_test_mock_socket_connect(&(client_ep.socket),
+                                           &(server_ep.socket), 1024);
+    TEST_EQUAL(ret, 0);
+
+    ret = mbedtls_ssl_set_session(&(client_ep.ssl), &saved_session);
+    TEST_EQUAL(ret, 0);
+
+    /*
+     * Go through the handshake sequence, state by state, checking the early
+     * data status each time.
+     */
+    do {
+        int state = client_ep.ssl.state;
+
+        /* Progress the handshake from at least one state */
+        while (client_ep.ssl.state == state) {
+            ret = mbedtls_ssl_handshake_step(&(client_ep.ssl));
+            TEST_ASSERT((ret == 0) ||
+                        (ret == MBEDTLS_ERR_SSL_WANT_READ) ||
+                        (ret == MBEDTLS_ERR_SSL_WANT_WRITE));
+            if (client_ep.ssl.state != state) {
+                break;
+            }
+            ret = mbedtls_ssl_handshake_step(&(server_ep.ssl));
+            TEST_ASSERT((ret == 0) ||
+                        (ret == MBEDTLS_ERR_SSL_WANT_READ) ||
+                        (ret == MBEDTLS_ERR_SSL_WANT_WRITE));
+        }
+
+        if (client_ep.ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER) {
+            TEST_EQUAL(mbedtls_ssl_get_early_data_status(&(client_ep.ssl)),
+                       MBEDTLS_ERR_SSL_BAD_INPUT_DATA);
+        }
+
+        switch (client_ep.ssl.state) {
+            case MBEDTLS_SSL_CLIENT_HELLO:
+                switch (scenario) {
+                    case TEST_EARLY_DATA_ACCEPTED: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_NO_INDICATION_SENT: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_SERVER_REJECTS:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN);
+                        break;
+
+                    case TEST_EARLY_DATA_HRR:
+                        if (!client_ep.ssl.handshake->hello_retry_request_flag) {
+                            TEST_EQUAL(client_ep.ssl.early_data_status,
+                                       MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN);
+                        } else {
+                            TEST_EQUAL(client_ep.ssl.early_data_status,
+                                       MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED);
+                        }
+                        break;
+
+                    default:
+                        TEST_FAIL("Unknown scenario.");
+                }
+                break;
+
+            case MBEDTLS_SSL_SERVER_HELLO:
+                switch (scenario) {
+                    case TEST_EARLY_DATA_ACCEPTED: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_SERVER_REJECTS:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE);
+                        break;
+
+                    case TEST_EARLY_DATA_NO_INDICATION_SENT:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT);
+                        break;
+
+                    case TEST_EARLY_DATA_HRR:
+                        if (!client_ep.ssl.handshake->hello_retry_request_flag) {
+                            TEST_EQUAL(client_ep.ssl.early_data_status,
+                                       MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE);
+                        } else {
+                            TEST_EQUAL(client_ep.ssl.early_data_status,
+                                       MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED);
+                        }
+                        break;
+
+                    default:
+                        TEST_FAIL("Unknown scenario.");
+                }
+                break;
+
+            case MBEDTLS_SSL_ENCRYPTED_EXTENSIONS:
+                switch (scenario) {
+                    case TEST_EARLY_DATA_ACCEPTED: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_SERVER_REJECTS:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE);
+                        break;
+
+                    case TEST_EARLY_DATA_NO_INDICATION_SENT:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT);
+                        break;
+
+                    case TEST_EARLY_DATA_HRR:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED);
+                        break;
+
+                    default:
+                        TEST_FAIL("Unknown scenario.");
+                }
+                break;
+
+            case MBEDTLS_SSL_SERVER_FINISHED:
+                switch (scenario) {
+                    case TEST_EARLY_DATA_ACCEPTED:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED);
+                        break;
+
+                    case TEST_EARLY_DATA_NO_INDICATION_SENT:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT);
+                        break;
+
+                    case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_HRR:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED);
+                        break;
+
+                    default:
+                        TEST_FAIL("Unknown scenario.");
+                }
+                break;
+
+            case MBEDTLS_SSL_END_OF_EARLY_DATA:
+                TEST_EQUAL(scenario, TEST_EARLY_DATA_ACCEPTED);
+                TEST_EQUAL(client_ep.ssl.early_data_status,
+                           MBEDTLS_SSL_EARLY_DATA_STATUS_SERVER_FINISHED_RECEIVED);
+                break;
+
+            case MBEDTLS_SSL_CLIENT_CERTIFICATE:
+                switch (scenario) {
+                    case TEST_EARLY_DATA_ACCEPTED:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_SERVER_FINISHED_RECEIVED);
+                        break;
+
+                    case TEST_EARLY_DATA_NO_INDICATION_SENT:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT);
+                        break;
+
+                    case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_HRR:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED);
+                        break;
+
+                    default:
+                        TEST_FAIL("Unknown scenario.");
+                }
+                break;
+
+            case MBEDTLS_SSL_CLIENT_FINISHED:
+                switch (scenario) {
+                    case TEST_EARLY_DATA_ACCEPTED:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_SERVER_FINISHED_RECEIVED);
+                        break;
+
+                    case TEST_EARLY_DATA_NO_INDICATION_SENT:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT);
+                        break;
+
+                    case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_HRR:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED);
+                        break;
+
+                    default:
+                        TEST_FAIL("Unknown scenario.");
+                }
+                break;
+
+#if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE)
+            case MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO:
+                switch (scenario) {
+                    case TEST_EARLY_DATA_ACCEPTED: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_HRR:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_SENT);
+                        break;
+
+                    default:
+                        TEST_FAIL("Unexpected or unknown scenario.");
+                }
+                break;
+
+            case MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO:
+                TEST_ASSERT(scenario == TEST_EARLY_DATA_HRR);
+                TEST_EQUAL(client_ep.ssl.early_data_status,
+                           MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED);
+                break;
+
+            case MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED:
+                switch (scenario) {
+                    case TEST_EARLY_DATA_NO_INDICATION_SENT:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT);
+                        break;
+
+                    case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_HRR:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED);
+                        break;
+
+                    default:
+                        TEST_FAIL("Unexpected or unknown scenario.");
+                }
+                break;
+#endif /* MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE */
+
+            case MBEDTLS_SSL_FLUSH_BUFFERS: /* Intentional fallthrough */
+            case MBEDTLS_SSL_HANDSHAKE_WRAPUP: /* Intentional fallthrough */
+            case MBEDTLS_SSL_HANDSHAKE_OVER:
+                switch (scenario) {
+                    case TEST_EARLY_DATA_ACCEPTED:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_SERVER_FINISHED_RECEIVED);
+                        break;
+
+                    case TEST_EARLY_DATA_NO_INDICATION_SENT:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT);
+                        break;
+
+                    case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_HRR:
+                        TEST_EQUAL(client_ep.ssl.early_data_status,
+                                   MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED);
+                        break;
+
+                    default:
+                        TEST_FAIL("Unknown scenario.");
+                }
+                break;
+
+            default:
+                TEST_FAIL("Unexpected state.");
+        }
+    } while (client_ep.ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER);
+
+    ret = mbedtls_ssl_get_early_data_status(&(client_ep.ssl));
+    switch (scenario) {
+        case TEST_EARLY_DATA_ACCEPTED:
+            TEST_EQUAL(ret, MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED);
+            break;
+
+        case TEST_EARLY_DATA_NO_INDICATION_SENT:
+            TEST_EQUAL(ret, MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT);
+            break;
+
+        case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */
+        case TEST_EARLY_DATA_HRR:
+            TEST_EQUAL(ret, MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED);
+            break;
+
+        default:
+            TEST_FAIL("Unknown scenario.");
+    }
+
+    ret = mbedtls_ssl_get_early_data_status(&(server_ep.ssl));
+    TEST_EQUAL(ret, MBEDTLS_ERR_SSL_BAD_INPUT_DATA);
+
+#if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE)
+    TEST_EQUAL(client_ep.ssl.handshake->ccs_sent, 1);
+#endif
+
+exit:
+    mbedtls_test_ssl_endpoint_free(&client_ep, NULL);
+    mbedtls_test_ssl_endpoint_free(&server_ep, NULL);
+    mbedtls_test_free_handshake_options(&client_options);
+    mbedtls_test_free_handshake_options(&server_options);
+    mbedtls_ssl_session_free(&saved_session);
+    PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_SSL_EARLY_DATA:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED:MBEDTLS_MD_CAN_SHA256:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_ECP_HAVE_SECP384R1:MBEDTLS_PK_CAN_ECDSA_VERIFY:MBEDTLS_SSL_SESSION_TICKETS */
+void tls13_write_early_data(int scenario)
+{
+    int ret = -1;
+    mbedtls_test_ssl_endpoint client_ep, server_ep;
+    mbedtls_test_handshake_test_options client_options;
+    mbedtls_test_handshake_test_options server_options;
+    mbedtls_ssl_session saved_session;
+    uint16_t group_list[3] = {
+        MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1,
+        MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1,
+        MBEDTLS_SSL_IANA_TLS_GROUP_NONE
+    };
+    int beyond_first_hello = 0;
+
+    mbedtls_platform_zeroize(&client_ep, sizeof(client_ep));
+    mbedtls_platform_zeroize(&server_ep, sizeof(server_ep));
+    mbedtls_test_init_handshake_options(&client_options);
+    mbedtls_test_init_handshake_options(&server_options);
+    mbedtls_ssl_session_init(&saved_session);
+
+    PSA_INIT();
+
+    /*
+     * Run first handshake to get a ticket from the server.
+     */
+    client_options.pk_alg = MBEDTLS_PK_ECDSA;
+    client_options.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED;
+    server_options.pk_alg = MBEDTLS_PK_ECDSA;
+    server_options.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED;
+    if (scenario == TEST_EARLY_DATA_HRR) {
+        client_options.group_list = group_list;
+        server_options.group_list = group_list;
+    }
+
+    ret = mbedtls_test_get_tls13_ticket(&client_options, &server_options,
+                                        &saved_session);
+    TEST_EQUAL(ret, 0);
+
+    /*
+     * Prepare for handshake with the ticket.
+     */
+    switch (scenario) {
+        case TEST_EARLY_DATA_ACCEPTED:
+            break;
+
+        case TEST_EARLY_DATA_NO_INDICATION_SENT:
+            client_options.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED;
+            break;
+
+        case TEST_EARLY_DATA_SERVER_REJECTS:
+            server_options.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED;
+            break;
+
+        case TEST_EARLY_DATA_HRR:
+            /*
+             * Remove server support for the group negotiated in
+             * mbedtls_test_get_tls13_ticket() forcing a HelloRetryRequest.
+             */
+            server_options.group_list = group_list + 1;
+            break;
+
+        default:
+            TEST_FAIL("Unknown scenario.");
+    }
+
+    ret = mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT,
+                                         &client_options, NULL, NULL, NULL);
+    TEST_EQUAL(ret, 0);
+
+    ret = mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER,
+                                         &server_options, NULL, NULL, NULL);
+    TEST_EQUAL(ret, 0);
+
+    mbedtls_ssl_conf_session_tickets_cb(&server_ep.conf,
+                                        mbedtls_test_ticket_write,
+                                        mbedtls_test_ticket_parse,
+                                        NULL);
+
+    ret = mbedtls_test_mock_socket_connect(&(client_ep.socket),
+                                           &(server_ep.socket), 1024);
+    TEST_EQUAL(ret, 0);
+
+    ret = mbedtls_ssl_set_session(&(client_ep.ssl), &saved_session);
+    TEST_EQUAL(ret, 0);
+
+    /*
+     * Run handshakes going one state further in the handshake sequence at each
+     * loop up to the point where we reach the MBEDTLS_SSL_HANDSHAKE_OVER
+     * state. For each reached handshake state, check the result of the call
+     * to mbedtls_ssl_write_early_data(), make sure we can complete the
+     * handshake successfully and then reset the connection to restart the
+     * handshake from scratch.
+     */
+    do {
+        int client_state = client_ep.ssl.state;
+        int previous_client_state;
+        const char *early_data_string = "This is early data.";
+        const unsigned char *early_data = (const unsigned char *) early_data_string;
+        size_t early_data_len = strlen(early_data_string);
+        int write_early_data_ret, read_early_data_ret;
+        unsigned char read_buf[64];
+
+        write_early_data_ret = mbedtls_ssl_write_early_data(&(client_ep.ssl),
+                                                            early_data,
+                                                            early_data_len);
+
+        if (scenario == TEST_EARLY_DATA_NO_INDICATION_SENT) {
+            TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA);
+            TEST_EQUAL(client_ep.ssl.state, client_state);
+            goto complete_handshake;
+        }
+
+        switch (client_state) {
+            case MBEDTLS_SSL_HELLO_REQUEST: /* Intentional fallthrough */
+            case MBEDTLS_SSL_CLIENT_HELLO:
+                switch (scenario) {
+                    case TEST_EARLY_DATA_ACCEPTED: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_SERVER_REJECTS:
+                        TEST_EQUAL(write_early_data_ret, early_data_len);
+                        TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO);
+                        break;
+
+                    case TEST_EARLY_DATA_HRR:
+                        if (!client_ep.ssl.handshake->hello_retry_request_flag) {
+                            TEST_EQUAL(write_early_data_ret, early_data_len);
+                            TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO);
+                        } else {
+                            beyond_first_hello = 1;
+                            TEST_EQUAL(write_early_data_ret,
+                                       MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA);
+                            TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_CLIENT_HELLO);
+                        }
+                        break;
+
+                    default:
+                        TEST_FAIL("Unknown scenario.");
+                }
+                break;
+
+            case MBEDTLS_SSL_SERVER_HELLO:
+                switch (scenario) {
+                    case TEST_EARLY_DATA_ACCEPTED: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_SERVER_REJECTS:
+                        TEST_EQUAL(write_early_data_ret, early_data_len);
+                        TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO);
+                        break;
+
+                    case TEST_EARLY_DATA_HRR:
+                        if (!client_ep.ssl.handshake->hello_retry_request_flag) {
+                            TEST_EQUAL(write_early_data_ret, early_data_len);
+                            TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO);
+                        } else {
+                            TEST_EQUAL(write_early_data_ret,
+                                       MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA);
+                            TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO);
+                        }
+                        break;
+
+                    default:
+                        TEST_FAIL("Unknown scenario.");
+                }
+                break;
+
+            case MBEDTLS_SSL_ENCRYPTED_EXTENSIONS:
+                switch (scenario) {
+                    case TEST_EARLY_DATA_ACCEPTED: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_SERVER_REJECTS:
+                        TEST_EQUAL(write_early_data_ret, early_data_len);
+                        TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS);
+                        break;
+
+                    case TEST_EARLY_DATA_HRR:
+                        TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA);
+                        TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS);
+                        break;
+
+                    default:
+                        TEST_FAIL("Unknown scenario.");
+                }
+                break;
+
+            case MBEDTLS_SSL_SERVER_FINISHED:
+                switch (scenario) {
+                    case TEST_EARLY_DATA_ACCEPTED:
+                        TEST_EQUAL(write_early_data_ret, early_data_len);
+                        TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_FINISHED);
+                        break;
+
+                    case TEST_EARLY_DATA_SERVER_REJECTS:
+                        TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA);
+                        TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_FINISHED);
+                        break;
+
+                    case TEST_EARLY_DATA_HRR:
+                        TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA);
+                        TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_FINISHED);
+                        break;
+
+                    default:
+                        TEST_FAIL("Unknown scenario.");
+                }
+                break;
+
+            case MBEDTLS_SSL_END_OF_EARLY_DATA:
+                TEST_EQUAL(scenario, TEST_EARLY_DATA_ACCEPTED);
+                TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA);
+                TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_END_OF_EARLY_DATA);
+                break;
+
+#if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE)
+            case MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO:
+                switch (scenario) {
+                    case TEST_EARLY_DATA_ACCEPTED: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_HRR:
+                        TEST_EQUAL(write_early_data_ret, early_data_len);
+                        TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO);
+                        break;
+                    default:
+                        TEST_FAIL("Unknown scenario.");
+                }
+                break;
+
+            case MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO:
+                TEST_EQUAL(scenario, TEST_EARLY_DATA_HRR);
+                TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA);
+                TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO);
+                break;
+
+            case MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED:
+                switch (scenario) {
+                    case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_HRR:
+                        TEST_EQUAL(write_early_data_ret,
+                                   MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA);
+                        TEST_EQUAL(client_ep.ssl.state,
+                                   MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED);
+                        break;
+                    default:
+                        TEST_FAIL("Unexpected or unknown scenario.");
+                }
+                break;
+#endif /* MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE */
+
+            case MBEDTLS_SSL_CLIENT_CERTIFICATE: /* Intentional fallthrough */
+            case MBEDTLS_SSL_CLIENT_FINISHED: /* Intentional fallthrough */
+            case MBEDTLS_SSL_FLUSH_BUFFERS: /* Intentional fallthrough */
+            case MBEDTLS_SSL_HANDSHAKE_WRAPUP: /* Intentional fallthrough */
+            case MBEDTLS_SSL_HANDSHAKE_OVER:
+                switch (scenario) {
+                    case TEST_EARLY_DATA_ACCEPTED: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */
+                    case TEST_EARLY_DATA_HRR:
+                        TEST_EQUAL(write_early_data_ret, MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA);
+                        TEST_EQUAL(client_ep.ssl.state, client_state);
+                        break;
+                    default:
+                        TEST_FAIL("Unknown scenario.");
+                }
+                break;
+
+            default:
+                TEST_FAIL("Unexpected state.");
+        }
+
+complete_handshake:
+        do {
+            ret = mbedtls_test_move_handshake_to_state(
+                &(server_ep.ssl), &(client_ep.ssl),
+                MBEDTLS_SSL_HANDSHAKE_OVER);
+
+            if (ret == MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA) {
+                read_early_data_ret = mbedtls_ssl_read_early_data(
+                    &(server_ep.ssl), read_buf, sizeof(read_buf));
+
+                TEST_EQUAL(read_early_data_ret, early_data_len);
+            }
+        } while (ret == MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA);
+
+        TEST_EQUAL(ret, 0);
+        TEST_EQUAL(mbedtls_test_move_handshake_to_state(
+                       &(client_ep.ssl), &(server_ep.ssl),
+                       MBEDTLS_SSL_HANDSHAKE_OVER), 0);
+
+        mbedtls_test_mock_socket_close(&(client_ep.socket));
+        mbedtls_test_mock_socket_close(&(server_ep.socket));
+
+        ret = mbedtls_ssl_session_reset(&(client_ep.ssl));
+        TEST_EQUAL(ret, 0);
+
+        ret = mbedtls_ssl_set_session(&(client_ep.ssl), &saved_session);
+        TEST_EQUAL(ret, 0);
+
+        ret = mbedtls_ssl_session_reset(&(server_ep.ssl));
+        TEST_EQUAL(ret, 0);
+
+        ret = mbedtls_test_mock_socket_connect(&(client_ep.socket),
+                                               &(server_ep.socket), 1024);
+        TEST_EQUAL(ret, 0);
+
+        previous_client_state = client_state;
+        if (previous_client_state == MBEDTLS_SSL_HANDSHAKE_OVER) {
+            break;
+        }
+
+        /* In case of HRR scenario, once we have been through it, move over
+         * the first ClientHello and ServerHello otherwise we just keep playing
+         * this first part of the handshake with HRR.
+         */
+        if ((scenario == TEST_EARLY_DATA_HRR) && (beyond_first_hello)) {
+            TEST_ASSERT(mbedtls_test_move_handshake_to_state(
+                            &(client_ep.ssl), &(server_ep.ssl),
+                            MBEDTLS_SSL_SERVER_HELLO) == 0);
+            TEST_ASSERT(mbedtls_test_move_handshake_to_state(
+                            &(client_ep.ssl), &(server_ep.ssl),
+                            MBEDTLS_SSL_CLIENT_HELLO) == 0);
+        }
+
+        TEST_EQUAL(mbedtls_test_move_handshake_to_state(
+                       &(client_ep.ssl), &(server_ep.ssl),
+                       previous_client_state), 0);
+
+        /* Progress the handshake from at least one state */
+        while (client_ep.ssl.state == previous_client_state) {
+            ret = mbedtls_ssl_handshake_step(&(client_ep.ssl));
+            TEST_ASSERT((ret == 0) ||
+                        (ret == MBEDTLS_ERR_SSL_WANT_READ) ||
+                        (ret == MBEDTLS_ERR_SSL_WANT_WRITE));
+            if (client_ep.ssl.state != previous_client_state) {
+                break;
+            }
+            ret = mbedtls_ssl_handshake_step(&(server_ep.ssl));
+            TEST_ASSERT((ret == 0) ||
+                        (ret == MBEDTLS_ERR_SSL_WANT_READ) ||
+                        (ret == MBEDTLS_ERR_SSL_WANT_WRITE));
+        }
+    } while (1);
+
+exit:
+    mbedtls_test_ssl_endpoint_free(&client_ep, NULL);
+    mbedtls_test_ssl_endpoint_free(&server_ep, NULL);
+    mbedtls_test_free_handshake_options(&client_options);
+    mbedtls_test_free_handshake_options(&server_options);
+    mbedtls_ssl_session_free(&saved_session);
+    PSA_DONE();
+}
+/* END_CASE */
+
+/*
+ * The !MBEDTLS_SSL_PROTO_TLS1_2 dependency of tls13_early_data() below is
+ * a temporary workaround to not run the test in Windows-2013 where there is
+ * an issue with mbedtls_vsnprintf().
+ */
+/* BEGIN_CASE depends_on:!MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_EARLY_DATA:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_DEBUG_C:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED:MBEDTLS_MD_CAN_SHA256:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_ECP_HAVE_SECP384R1:MBEDTLS_PK_CAN_ECDSA_VERIFY:MBEDTLS_SSL_SESSION_TICKETS */
+void tls13_srv_max_early_data_size(int scenario, int max_early_data_size_arg, int write_size_arg)
+{
+    int ret = -1;
+    mbedtls_test_ssl_endpoint client_ep, server_ep;
+    mbedtls_test_handshake_test_options client_options;
+    mbedtls_test_handshake_test_options server_options;
+    mbedtls_ssl_session saved_session;
+    mbedtls_test_ssl_log_pattern server_pattern = { NULL, 0 };
+    uint16_t group_list[3] = {
+        MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1,
+        MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1,
+        MBEDTLS_SSL_IANA_TLS_GROUP_NONE
+    };
+    char pattern[128];
+    unsigned char *buf_write = NULL;
+    uint32_t write_size = (uint32_t) write_size_arg;
+    unsigned char *buf_read = NULL;
+    uint32_t read_size;
+    uint32_t expanded_early_data_chunk_size = 0;
+    uint32_t written_early_data_size = 0;
+    uint32_t max_early_data_size;
+
+    mbedtls_platform_zeroize(&client_ep, sizeof(client_ep));
+    mbedtls_platform_zeroize(&server_ep, sizeof(server_ep));
+    mbedtls_test_init_handshake_options(&client_options);
+    mbedtls_test_init_handshake_options(&server_options);
+    mbedtls_ssl_session_init(&saved_session);
+    PSA_INIT();
+
+    TEST_CALLOC(buf_write, write_size);
+
+    /*
+     * Allocate a smaller buffer for early data reading to exercise the reading
+     * of data in one record in multiple calls.
+     */
+    read_size = (write_size / 2) + 1;
+    TEST_CALLOC(buf_read, read_size);
+
+    /*
+     * Run first handshake to get a ticket from the server.
+     */
+
+    client_options.pk_alg = MBEDTLS_PK_ECDSA;
+    client_options.group_list = group_list;
+    client_options.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED;
+    server_options.pk_alg = MBEDTLS_PK_ECDSA;
+    server_options.group_list = group_list;
+    server_options.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED;
+    server_options.max_early_data_size = max_early_data_size_arg;
+
+    ret = mbedtls_test_get_tls13_ticket(&client_options, &server_options,
+                                        &saved_session);
+    TEST_EQUAL(ret, 0);
+
+    /*
+     * Prepare for handshake with the ticket.
+     */
+    server_options.srv_log_fun = mbedtls_test_ssl_log_analyzer;
+    server_options.srv_log_obj = &server_pattern;
+    server_pattern.pattern = pattern;
+
+    switch (scenario) {
+        case TEST_EARLY_DATA_ACCEPTED:
+            break;
+
+        case TEST_EARLY_DATA_SERVER_REJECTS:
+            server_options.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED;
+            ret = mbedtls_snprintf(pattern, sizeof(pattern),
+                                   "EarlyData: deprotect and discard app data records.");
+            TEST_ASSERT(ret < (int) sizeof(pattern));
+            mbedtls_debug_set_threshold(3);
+            break;
+
+        case TEST_EARLY_DATA_HRR:
+            /*
+             * Remove server support for the group negotiated in
+             * mbedtls_test_get_tls13_ticket() forcing an HelloRetryRequest.
+             */
+            server_options.group_list = group_list + 1;
+            ret = mbedtls_snprintf(
+                pattern, sizeof(pattern),
+                "EarlyData: Ignore application message before 2nd ClientHello");
+            TEST_ASSERT(ret < (int) sizeof(pattern));
+            mbedtls_debug_set_threshold(3);
+            break;
+
+        default:
+            TEST_FAIL("Unknown scenario.");
+    }
+
+    ret = mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT,
+                                         &client_options, NULL, NULL, NULL);
+    TEST_EQUAL(ret, 0);
+
+    ret = mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER,
+                                         &server_options, NULL, NULL, NULL);
+    TEST_EQUAL(ret, 0);
+
+    mbedtls_ssl_conf_session_tickets_cb(&server_ep.conf,
+                                        mbedtls_test_ticket_write,
+                                        mbedtls_test_ticket_parse,
+                                        NULL);
+
+    ret = mbedtls_test_mock_socket_connect(&(client_ep.socket),
+                                           &(server_ep.socket), 1024);
+    TEST_EQUAL(ret, 0);
+
+    max_early_data_size = saved_session.max_early_data_size;
+
+    ret = mbedtls_ssl_set_session(&(client_ep.ssl), &saved_session);
+    TEST_EQUAL(ret, 0);
+
+    /*
+     * Start an handshake based on the ticket up to the point where early data
+     * can be sent from client side. Then send in a loop as much early data as
+     * possible without going over the maximum permitted size for the ticket.
+     * Finally, do a last writting to go past that maximum permitted size and
+     * check that we detect it.
+     */
+    TEST_EQUAL(mbedtls_test_move_handshake_to_state(
+                   &(client_ep.ssl), &(server_ep.ssl),
+                   MBEDTLS_SSL_SERVER_HELLO), 0);
+
+    TEST_ASSERT(client_ep.ssl.early_data_status !=
+                MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT);
+
+    ret = mbedtls_ssl_handshake(&(server_ep.ssl));
+    TEST_EQUAL(ret, MBEDTLS_ERR_SSL_WANT_READ);
+
+    /*
+     * Write and if possible read as much as possible chunks of write_size
+     * bytes data without getting over the max_early_data_size limit.
+     */
+    do {
+        uint32_t read_early_data_size = 0;
+
+        /*
+         * The contents of the early data are not very important, write a
+         * pattern that varies byte-by-byte and is different for every chunk of
+         * early data.
+         */
+        if ((written_early_data_size + write_size) > max_early_data_size) {
+            break;
+        }
+
+        /*
+         * If the server rejected early data, base the determination of when
+         * to stop the loop on the expanded size (padding and encryption
+         * expansion) of early data on server side and the number of early data
+         * received so far by the server (multiple of the expanded size).
+         */
+        if ((expanded_early_data_chunk_size != 0) &&
+            ((server_ep.ssl.total_early_data_size +
+              expanded_early_data_chunk_size) > max_early_data_size)) {
+            break;
+        }
+
+        for (size_t i = 0; i < write_size; i++) {
+            buf_write[i] = (unsigned char) (written_early_data_size + i);
+        }
+
+        ret = write_early_data(&(client_ep.ssl), buf_write, write_size);
+        TEST_EQUAL(ret, write_size);
+        written_early_data_size += write_size;
+
+        switch (scenario) {
+            case TEST_EARLY_DATA_ACCEPTED:
+                while (read_early_data_size < write_size) {
+                    ret = mbedtls_ssl_handshake(&(server_ep.ssl));
+                    TEST_EQUAL(ret, MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA);
+
+                    ret = mbedtls_ssl_read_early_data(&(server_ep.ssl),
+                                                      buf_read, read_size);
+                    TEST_ASSERT(ret > 0);
+
+                    TEST_MEMORY_COMPARE(buf_read, ret,
+                                        buf_write + read_early_data_size, ret);
+                    read_early_data_size += ret;
+
+                    TEST_EQUAL(server_ep.ssl.total_early_data_size,
+                               written_early_data_size);
+                }
+                break;
+
+            case TEST_EARLY_DATA_SERVER_REJECTS: /* Intentional fallthrough */
+            case TEST_EARLY_DATA_HRR:
+                ret = mbedtls_ssl_handshake(&(server_ep.ssl));
+                /*
+                 * In this write loop we try to always stay below the
+                 * max_early_data_size limit but if max_early_data_size is very
+                 * small we may exceed the max_early_data_size limit on the
+                 * first write. In TEST_EARLY_DATA_SERVER_REJECTS/
+                 * TEST_EARLY_DATA_HRR scenario, this is for sure the case if
+                 * max_early_data_size is smaller than the smallest possible
+                 * inner content/protected record. Take into account this
+                 * possibility here but only for max_early_data_size values
+                 * that are close to write_size. Below, '1' is for the inner
+                 * type byte and '16' is to take into account some AEAD
+                 * expansion (tag, ...).
+                 */
+                if (ret == MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE) {
+                    if (scenario == TEST_EARLY_DATA_SERVER_REJECTS) {
+                        TEST_LE_U(max_early_data_size,
+                                  write_size + 1 +
+                                  MBEDTLS_SSL_CID_TLS1_3_PADDING_GRANULARITY);
+                    } else {
+                        TEST_LE_U(max_early_data_size,
+                                  write_size + 1 + 16 +
+                                  MBEDTLS_SSL_CID_TLS1_3_PADDING_GRANULARITY);
+                    }
+                    goto exit;
+                }
+
+                TEST_ASSERT(ret == MBEDTLS_ERR_SSL_WANT_READ);
+
+                TEST_EQUAL(server_pattern.counter, 1);
+                server_pattern.counter = 0;
+                if (expanded_early_data_chunk_size == 0) {
+                    expanded_early_data_chunk_size = server_ep.ssl.total_early_data_size;
+                }
+                break;
+        }
+        TEST_LE_U(server_ep.ssl.total_early_data_size, max_early_data_size);
+    } while (1);
+
+    mbedtls_debug_set_threshold(3);
+    ret = write_early_data(&(client_ep.ssl), buf_write, write_size);
+    TEST_EQUAL(ret, write_size);
+
+    ret = mbedtls_snprintf(pattern, sizeof(pattern),
+                           "EarlyData: Too much early data received");
+    TEST_ASSERT(ret < (int) sizeof(pattern));
+
+    ret = mbedtls_ssl_handshake(&(server_ep.ssl));
+    TEST_EQUAL(ret, MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE);
+    TEST_EQUAL(server_pattern.counter, 1);
+
+exit:
+    mbedtls_test_ssl_endpoint_free(&client_ep, NULL);
+    mbedtls_test_ssl_endpoint_free(&server_ep, NULL);
+    mbedtls_test_free_handshake_options(&client_options);
+    mbedtls_test_free_handshake_options(&server_options);
+    mbedtls_ssl_session_free(&saved_session);
+    mbedtls_free(buf_write);
+    mbedtls_free(buf_read);
+    mbedtls_debug_set_threshold(0);
+    PSA_DONE();
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index b9ae20c..754660c 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -1774,7 +1774,7 @@
 
 X509 CRT ASN1 (TBS, inv SubPubKeyInfo, inv internal bitstring length)
 depends_on:MBEDTLS_RSA_C:MBEDTLS_MD_CAN_SHA256
-x509parse_crt:"308180306ba0030201008204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a300806001304546573743015300d06092A864886F70D0101010500030400300000300d06092a864886f70d01010b0500030200ff":"":MBEDTLS_ERR_PK_INVALID_PUBKEY + MBEDTLS_ERR_ASN1_OUT_OF_DATA
+x509parse_crt:"308180306ba0030201008204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a300806001304546573743015300d06092A864886F70D0101010500030400300000300d06092a864886f70d01010b0500030200ff":"":MBEDTLS_ERR_PK_INVALID_PUBKEY
 
 X509 CRT ASN1 (TBS, inv SubPubKeyInfo, inv internal bitstring tag)
 depends_on:MBEDTLS_RSA_C:MBEDTLS_MD_CAN_SHA256
@@ -3155,6 +3155,18 @@
 depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256
 x509parse_crt_file:"data_files/parse_input/server5.crt":0
 
+X509 File parse & read the ca_istrue field (Not Set)
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_HAVE_TIME_DATE:MBEDTLS_MD_CAN_SHA1
+mbedtls_x509_get_ca_istrue:"data_files/parse_input/server1.crt":0
+
+X509 File parse & read the ca_istrue field (Set)
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_HAVE_TIME_DATE:MBEDTLS_MD_CAN_SHA1
+mbedtls_x509_get_ca_istrue:"data_files/test-ca.crt":1
+
+X509 File parse & read the ca_istrue field (Legacy Certificate)
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_HAVE_TIME_DATE:MBEDTLS_MD_CAN_SHA1:MBEDTLS_MD_CAN_SHA256
+mbedtls_x509_get_ca_istrue:"data_files/server1-v1.crt":MBEDTLS_ERR_X509_INVALID_EXTENSIONS
+
 X509 Get time (UTC no issues)
 depends_on:MBEDTLS_X509_USE_C
 x509_get_time:MBEDTLS_ASN1_UTC_TIME:"500101000000Z":0:1950:1:1:0:0:0
diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function
index 66477e0..f3ae0f4 100644
--- a/tests/suites/test_suite_x509parse.function
+++ b/tests/suites/test_suite_x509parse.function
@@ -1083,6 +1083,21 @@
 }
 /* END_CASE */
 
+/* BEGIN_CASE depends_on:MBEDTLS_X509_CRT_PARSE_C:MBEDTLS_FS_IO */
+void mbedtls_x509_get_ca_istrue(char *crt_file, int result)
+{
+    mbedtls_x509_crt   crt;
+    mbedtls_x509_crt_init(&crt);
+    USE_PSA_INIT();
+
+    TEST_EQUAL(mbedtls_x509_crt_parse_file(&crt, crt_file), 0);
+    TEST_EQUAL(mbedtls_x509_crt_get_ca_istrue(&crt), result);
+exit:
+    mbedtls_x509_crt_free(&crt);
+    USE_PSA_DONE();
+}
+/* END_CASE */
+
 /* BEGIN_CASE depends_on:MBEDTLS_X509_CRT_PARSE_C */
 void x509parse_crt(data_t *buf, char *result_str, int result)
 {
diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function
index 3d84c72..1db7e1c 100644
--- a/tests/suites/test_suite_x509write.function
+++ b/tests/suites/test_suite_x509write.function
@@ -284,7 +284,7 @@
 {
     mbedtls_pk_context key;
     mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
-    psa_algorithm_t md_alg_psa, alg_psa;
+    psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
     mbedtls_x509write_csr req;
     unsigned char buf[4096];
     int ret;
@@ -297,24 +297,16 @@
 
     memset(&rnd_info, 0x2a, sizeof(mbedtls_test_rnd_pseudo_info));
 
-    md_alg_psa = mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) md_type);
-    TEST_ASSERT(md_alg_psa != MBEDTLS_MD_NONE);
-
     mbedtls_pk_init(&key);
     TEST_ASSERT(mbedtls_pk_parse_keyfile(&key, key_file, NULL,
                                          mbedtls_test_rnd_std_rand, NULL) == 0);
 
-    if (mbedtls_pk_get_type(&key) == MBEDTLS_PK_ECKEY) {
-        alg_psa = PSA_ALG_ECDSA(md_alg_psa);
-    } else if (mbedtls_pk_get_type(&key) == MBEDTLS_PK_RSA) {
-        alg_psa = PSA_ALG_RSA_PKCS1V15_SIGN(md_alg_psa);
-    } else {
-        TEST_ASSUME(!"PK key type not supported in this configuration");
-    }
-
-    TEST_ASSERT(mbedtls_pk_wrap_as_opaque(&key, &key_id, alg_psa,
-                                          PSA_KEY_USAGE_SIGN_HASH,
-                                          PSA_ALG_NONE) == 0);
+    /* Turn the PK context into an opaque one. */
+    TEST_EQUAL(mbedtls_pk_get_psa_attributes(&key, PSA_KEY_USAGE_SIGN_HASH, &key_attr), 0);
+    TEST_EQUAL(mbedtls_pk_import_into_psa(&key, &key_attr, &key_id), 0);
+    mbedtls_pk_free(&key);
+    mbedtls_pk_init(&key);
+    TEST_EQUAL(mbedtls_pk_setup_opaque(&key, key_id), 0);
 
     mbedtls_x509write_csr_set_md_alg(&req, md_type);
     mbedtls_x509write_csr_set_key(&req, &key);
@@ -373,6 +365,7 @@
     mbedtls_test_rnd_pseudo_info rnd_info;
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
 #endif
     mbedtls_pk_type_t issuer_key_type;
     mbedtls_x509_san_list san_ip;
@@ -451,24 +444,14 @@
 #endif
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
-    /* For Opaque PK contexts, wrap key as an Opaque RSA context. */
+    /* Turn the issuer PK context into an opaque one. */
     if (pk_wrap == 2) {
-        psa_algorithm_t alg_psa, md_alg_psa;
-
-        md_alg_psa = mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) md_type);
-        TEST_ASSERT(md_alg_psa != MBEDTLS_MD_NONE);
-
-        if (mbedtls_pk_get_type(&issuer_key) == MBEDTLS_PK_ECKEY) {
-            alg_psa = PSA_ALG_ECDSA(md_alg_psa);
-        } else if (mbedtls_pk_get_type(&issuer_key) == MBEDTLS_PK_RSA) {
-            alg_psa = PSA_ALG_RSA_PKCS1V15_SIGN(md_alg_psa);
-        } else {
-            TEST_ASSUME(!"PK key type not supported in this configuration");
-        }
-
-        TEST_ASSERT(mbedtls_pk_wrap_as_opaque(&issuer_key, &key_id, alg_psa,
-                                              PSA_KEY_USAGE_SIGN_HASH,
-                                              PSA_ALG_NONE) == 0);
+        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&issuer_key, PSA_KEY_USAGE_SIGN_HASH,
+                                                 &key_attr), 0);
+        TEST_EQUAL(mbedtls_pk_import_into_psa(&issuer_key, &key_attr, &key_id), 0);
+        mbedtls_pk_free(&issuer_key);
+        mbedtls_pk_init(&issuer_key);
+        TEST_EQUAL(mbedtls_pk_setup_opaque(&issuer_key, key_id), 0);
     }
 #endif /* MBEDTLS_USE_PSA_CRYPTO */