Merge pull request #4159 from d3zd3z/header-list

Add missing header to cpp_dummy_build.cpp test
diff --git a/ChangeLog.d/drbg-mutex.txt b/ChangeLog.d/drbg-mutex.txt
new file mode 100644
index 0000000..3ac5abf
--- /dev/null
+++ b/ChangeLog.d/drbg-mutex.txt
@@ -0,0 +1,5 @@
+Bugfix
+   * Fix a resource leak in CTR_DRBG and HMAC_DRBG when MBEDTLS_THREADING_C
+     is enabled, on platforms where initializing a mutex allocates resources.
+     This was a regression introduced in the previous release. Reported in
+     #4017, #4045 and #4071.
diff --git a/ChangeLog.d/mbedtls_psa_get_random.txt b/ChangeLog.d/mbedtls_psa_get_random.txt
new file mode 100644
index 0000000..f6e6b09
--- /dev/null
+++ b/ChangeLog.d/mbedtls_psa_get_random.txt
@@ -0,0 +1,9 @@
+Features
+   * Partial implementation of the PSA crypto driver interface: Mbed TLS can
+     now use an external random generator instead of the library's own
+     entropy collection and DRBG code. Enable MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+     and see the documentation of mbedtls_psa_external_get_random() for details.
+   * Applications using both mbedtls_xxx and psa_xxx functions (for example,
+     applications using TLS and MBEDTLS_USE_PSA_CRYPTO) can now use the PSA
+     random generator with mbedtls_xxx functions. See the documentation of
+     mbedtls_psa_get_random() for details.
diff --git a/ChangeLog.d/rsa-mutex.txt b/ChangeLog.d/rsa-mutex.txt
new file mode 100644
index 0000000..2a477a9
--- /dev/null
+++ b/ChangeLog.d/rsa-mutex.txt
@@ -0,0 +1,13 @@
+Bugfix
+   * Ensure that calling mbedtls_rsa_free() or mbedtls_entropy_free()
+     twice is safe. This happens for RSA when some Mbed TLS library functions
+     fail. Such a double-free was not safe when MBEDTLS_THREADING_C was
+     enabled on platforms where freeing a mutex twice is not safe.
+   * Fix a resource leak in a bad-arguments case of mbedtls_rsa_gen_key()
+     when MBEDTLS_THREADING_C is enabled on platforms where initializing
+     a mutex allocates resources.
+
+Default behavior changes
+   * In mbedtls_rsa_context objects, the ver field was formerly documented
+     as always 0. It is now reserved for internal purposes and may take
+     different values.
diff --git a/docs/proposed/psa-conditional-inclusion-c.md b/docs/proposed/psa-conditional-inclusion-c.md
index 52138b1..2ddba7f 100644
--- a/docs/proposed/psa-conditional-inclusion-c.md
+++ b/docs/proposed/psa-conditional-inclusion-c.md
@@ -5,8 +5,6 @@
 
 This is currently a proposal for Mbed TLS. It is not currently on track for standardization in PSA.
 
-Time-stamp: "2020/11/26 09:30:50 GMT"
-
 ## Introduction
 
 ### Purpose of this specification
@@ -86,9 +84,17 @@
 
 For asymmetric cryptography, `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR` determines whether private-key operations are desired, and `PSA_WANT_KEY_TYPE_xxx_PUBLIC_KEY` determines whether public-key operations are desired. `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR` implicitly enables `PSA_WANT_KEY_TYPE_xxx_PUBLIC_KEY`: there is no way to only include private-key operations (which typically saves little code).
 
-#### Configuration symbols for curves
+#### Configuration symbols for elliptic curves
 
-For elliptic curve key types, only the specified curves are included. To include a curve, include a symbol of the form **`PSA_WANT_ECC_family_size`**. For example: `PSA_WANT_ECC_SECP_R1_256` for secp256r1, `PSA_WANT_ECC_MONTGOMERY_CURVE25519`. It is an error to require an ECC key type but no curve, and Mbed TLS will reject this at compile time.
+For elliptic curve key types, only the specified curves are included. To include a curve, include a symbol of the form **`PSA_WANT_ECC_family_size`**. For example: `PSA_WANT_ECC_SECP_R1_256` for secp256r1, `PSA_WANT_ECC_MONTGOMERY_255` for Curve25519. It is an error to require an ECC key type but no curve, and Mbed TLS will reject this at compile time.
+
+Rationale: this is a deviation of the general principle that `PSA_ECC_FAMILY_xxx` would have a corresponding symbol `PSA_WANT_ECC_FAMILY_xxx`. This deviation is justified by the fact that it is very common to wish to include only certain curves in a family, and that can lead to a significant gain in code size.
+
+#### Configuration symbols for Diffie-Hellman groups
+
+There are no configuration symbols for Diffie-Hellman groups (`PSA_DH_GROUP_xxx`).
+
+Rationale: Finite-field Diffie-Hellman code is usually not specialized for any particular group, so reducing the number of available groups at compile time only saves a little code space. Constrained implementations tend to omit FFDH anyway, so the small code size gain is not important.
 
 #### Configuration symbols for algorithms
 
@@ -195,7 +201,7 @@
 
 #### Naming of symbols
 
-The names of [elliptic curve symbols](#configuration-symbols-for-curves) are a bit weird: `SECP_R1_256` instead of `SECP256R1`. Should we make them more classical, but less systematic?
+The names of [elliptic curve symbols](#configuration-symbols-for-elliptic-curves) are a bit weird: `SECP_R1_256` instead of `SECP256R1`, `MONTGOMERY_255` instead of `CURVE25519`. Should we make them more classical, but less systematic?
 
 #### Impossible combinations
 
diff --git a/include/mbedtls/ctr_drbg.h b/include/mbedtls/ctr_drbg.h
index 7f1d232..653fd83 100644
--- a/include/mbedtls/ctr_drbg.h
+++ b/include/mbedtls/ctr_drbg.h
@@ -200,6 +200,13 @@
     void *p_entropy;            /*!< The context for the entropy function. */
 
 #if defined(MBEDTLS_THREADING_C)
+    /* Invariant: the mutex is initialized if and only if f_entropy != NULL.
+     * This means that the mutex is initialized during the initial seeding
+     * in mbedtls_ctr_drbg_seed() and freed in mbedtls_ctr_drbg_free().
+     *
+     * Note that this invariant may change without notice. Do not rely on it
+     * and do not access the mutex directly in application code.
+     */
     mbedtls_threading_mutex_t mutex;
 #endif
 }
@@ -264,6 +271,15 @@
  *   make a second call to \p f_entropy.
  */
 #endif
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note                When Mbed TLS is built with threading support,
+ *                      after this function returns successfully,
+ *                      it is safe to call mbedtls_ctr_drbg_random()
+ *                      from multiple threads. Other operations, including
+ *                      reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
 /**
  * - The \p custom string.
  *
@@ -290,6 +306,8 @@
  *                      the same context unless you call
  *                      mbedtls_ctr_drbg_free() and mbedtls_ctr_drbg_init()
  *                      again first.
+ *                      After a failed call to mbedtls_ctr_drbg_seed(),
+ *                      you must call mbedtls_ctr_drbg_free().
  * \param f_entropy     The entropy callback, taking as arguments the
  *                      \p p_entropy context, the buffer to fill, and the
  *                      length of the buffer.
@@ -405,6 +423,11 @@
  * \brief               This function reseeds the CTR_DRBG context, that is
  *                      extracts data from the entropy source.
  *
+ * \note                This function is not thread-safe. It is not safe
+ *                      to call this function if another thread might be
+ *                      concurrently obtaining random numbers from the same
+ *                      context or updating or reseeding the same context.
+ *
  * \param ctx           The CTR_DRBG context.
  * \param additional    Additional data to add to the state. Can be \c NULL.
  * \param len           The length of the additional data.
@@ -422,6 +445,11 @@
 /**
  * \brief              This function updates the state of the CTR_DRBG context.
  *
+ * \note                This function is not thread-safe. It is not safe
+ *                      to call this function if another thread might be
+ *                      concurrently obtaining random numbers from the same
+ *                      context or updating or reseeding the same context.
+ *
  * \param ctx          The CTR_DRBG context.
  * \param additional   The data to update the state with. This must not be
  *                     \c NULL unless \p add_len is \c 0.
@@ -445,6 +473,11 @@
  * This function automatically reseeds if the reseed counter is exceeded
  * or prediction resistance is enabled.
  *
+ * \note                This function is not thread-safe. It is not safe
+ *                      to call this function if another thread might be
+ *                      concurrently obtaining random numbers from the same
+ *                      context or updating or reseeding the same context.
+ *
  * \param p_rng         The CTR_DRBG context. This must be a pointer to a
  *                      #mbedtls_ctr_drbg_context structure.
  * \param output        The buffer to fill.
@@ -473,8 +506,16 @@
  *
  * This function automatically reseeds if the reseed counter is exceeded
  * or prediction resistance is enabled.
- *
- *
+ */
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note                When Mbed TLS is built with threading support,
+ *                      it is safe to call mbedtls_ctr_drbg_random()
+ *                      from multiple threads. Other operations, including
+ *                      reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
+/**
  * \param p_rng         The CTR_DRBG context. This must be a pointer to a
  *                      #mbedtls_ctr_drbg_context structure.
  * \param output        The buffer to fill.
diff --git a/include/mbedtls/entropy.h b/include/mbedtls/entropy.h
index 5a9c11c..fa0b24f 100644
--- a/include/mbedtls/entropy.h
+++ b/include/mbedtls/entropy.h
@@ -120,13 +120,15 @@
  */
 typedef struct mbedtls_entropy_context
 {
-    int accumulator_started;
+    int accumulator_started; /* 0 after init.
+                              * 1 after the first update.
+                              * -1 after free. */
 #if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR)
     mbedtls_sha512_context  accumulator;
 #else
     mbedtls_sha256_context  accumulator;
 #endif
-    int             source_count;
+    int             source_count; /* Number of entries used in source. */
     mbedtls_entropy_source_state    source[MBEDTLS_ENTROPY_MAX_SOURCES];
 #if defined(MBEDTLS_HAVEGE_C)
     mbedtls_havege_state    havege_data;
diff --git a/include/mbedtls/hmac_drbg.h b/include/mbedtls/hmac_drbg.h
index 9116541..fa33611 100644
--- a/include/mbedtls/hmac_drbg.h
+++ b/include/mbedtls/hmac_drbg.h
@@ -101,6 +101,14 @@
     void *p_entropy;            /*!< context for the entropy function        */
 
 #if defined(MBEDTLS_THREADING_C)
+    /* Invariant: the mutex is initialized if and only if
+     * md_ctx->md_info != NULL. This means that the mutex is initialized
+     * during the initial seeding in mbedtls_hmac_drbg_seed() or
+     * mbedtls_hmac_drbg_seed_buf() and freed in mbedtls_ctr_drbg_free().
+     *
+     * Note that this invariant may change without notice. Do not rely on it
+     * and do not access the mutex directly in application code.
+     */
     mbedtls_threading_mutex_t mutex;
 #endif
 } mbedtls_hmac_drbg_context;
@@ -150,7 +158,17 @@
  * \note                During the initial seeding, this function calls
  *                      the entropy source to obtain a nonce
  *                      whose length is half the entropy length.
- *
+ */
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note                When Mbed TLS is built with threading support,
+ *                      after this function returns successfully,
+ *                      it is safe to call mbedtls_hmac_drbg_random()
+ *                      from multiple threads. Other operations, including
+ *                      reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
+/**
  * \param ctx           HMAC_DRBG context to be seeded.
  * \param md_info       MD algorithm to use for HMAC_DRBG.
  * \param f_entropy     The entropy callback, taking as arguments the
@@ -189,7 +207,17 @@
  *
  * This function is meant for use in algorithms that need a pseudorandom
  * input such as deterministic ECDSA.
- *
+ */
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note                When Mbed TLS is built with threading support,
+ *                      after this function returns successfully,
+ *                      it is safe to call mbedtls_hmac_drbg_random()
+ *                      from multiple threads. Other operations, including
+ *                      reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
+/**
  * \param ctx           HMAC_DRBG context to be initialised.
  * \param md_info       MD algorithm to use for HMAC_DRBG.
  * \param data          Concatenation of the initial entropy string and
@@ -252,6 +280,11 @@
 /**
  * \brief               This function updates the state of the HMAC_DRBG context.
  *
+ * \note                This function is not thread-safe. It is not safe
+ *                      to call this function if another thread might be
+ *                      concurrently obtaining random numbers from the same
+ *                      context or updating or reseeding the same context.
+ *
  * \param ctx           The HMAC_DRBG context.
  * \param additional    The data to update the state with.
  *                      If this is \c NULL, there is no additional data.
@@ -268,6 +301,11 @@
  * \brief               This function reseeds the HMAC_DRBG context, that is
  *                      extracts data from the entropy source.
  *
+ * \note                This function is not thread-safe. It is not safe
+ *                      to call this function if another thread might be
+ *                      concurrently obtaining random numbers from the same
+ *                      context or updating or reseeding the same context.
+ *
  * \param ctx           The HMAC_DRBG context.
  * \param additional    Additional data to add to the state.
  *                      If this is \c NULL, there is no additional data
@@ -293,6 +331,11 @@
  * This function automatically reseeds if the reseed counter is exceeded
  * or prediction resistance is enabled.
  *
+ * \note                This function is not thread-safe. It is not safe
+ *                      to call this function if another thread might be
+ *                      concurrently obtaining random numbers from the same
+ *                      context or updating or reseeding the same context.
+ *
  * \param p_rng         The HMAC_DRBG context. This must be a pointer to a
  *                      #mbedtls_hmac_drbg_context structure.
  * \param output        The buffer to fill.
@@ -322,7 +365,16 @@
  *
  * This function automatically reseeds if the reseed counter is exceeded
  * or prediction resistance is enabled.
- *
+ */
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note                When Mbed TLS is built with threading support,
+ *                      it is safe to call mbedtls_ctr_drbg_random()
+ *                      from multiple threads. Other operations, including
+ *                      reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
+/**
  * \param p_rng         The HMAC_DRBG context. This must be a pointer to a
  *                      #mbedtls_hmac_drbg_context structure.
  * \param output        The buffer to fill.
diff --git a/include/mbedtls/psa_util.h b/include/mbedtls/psa_util.h
index 0b8a216..f18857c 100644
--- a/include/mbedtls/psa_util.h
+++ b/include/mbedtls/psa_util.h
@@ -419,4 +419,90 @@
 
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
+/* 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. */
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+
+/* 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)
+
+/** 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.
+ *
+ * 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 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.
+ *                      This function may fail if \p output_size is too
+ *                      large. It is guaranteed to accept any output size
+ *                      requested by Mbed TLS library functions. The
+ *                      maximum request size depends on the library
+ *                      configuration.
+ *
+ * \return              \c 0 on success.
+ * \return              An `MBEDTLS_ERR_ENTROPY_xxx`,
+ *                      `MBEDTLS_ERR_PLATFORM_xxx,
+ *                      `MBEDTLS_ERR_CTR_DRBG_xxx` or
+ *                      `MBEDTLS_ERR_HMAC_DRBG_xxx` on error.
+ */
+int mbedtls_psa_get_random( void *p_rng,
+                            unsigned char *output,
+                            size_t output_size );
+
+/** 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.
+ */
+#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) */
+
+#endif /* MBEDTLS_PSA_CRYPTO_C */
+
 #endif /* MBEDTLS_PSA_UTIL_H */
diff --git a/include/mbedtls/rsa.h b/include/mbedtls/rsa.h
index 6a31514..701fe8b 100644
--- a/include/mbedtls/rsa.h
+++ b/include/mbedtls/rsa.h
@@ -97,7 +97,10 @@
  */
 typedef struct mbedtls_rsa_context
 {
-    int ver;                    /*!<  Always 0.*/
+    int ver;                    /*!<  Reserved for internal purposes.
+                                 *    Do not set this field in application
+                                 *    code. Its meaning might change without
+                                 *    notice. */
     size_t len;                 /*!<  The size of \p N in Bytes. */
 
     mbedtls_mpi N;              /*!<  The public modulus. */
@@ -127,6 +130,7 @@
                                      mask generating function used in the
                                      EME-OAEP and EMSA-PSS encodings. */
 #if defined(MBEDTLS_THREADING_C)
+    /* Invariant: the mutex is initialized iff ver != 0. */
     mbedtls_threading_mutex_t mutex;    /*!<  Thread-safety mutex. */
 #endif
 }
diff --git a/include/mbedtls/threading.h b/include/mbedtls/threading.h
index 8baf15a..05e27c5 100644
--- a/include/mbedtls/threading.h
+++ b/include/mbedtls/threading.h
@@ -46,6 +46,9 @@
 typedef struct mbedtls_threading_mutex_t
 {
     pthread_mutex_t mutex;
+    /* is_valid is 0 after a failed init or a free, and nonzero after a
+     * successful init. This field is not considered part of the public
+     * API of Mbed TLS and may change without notice. */
     char is_valid;
 } mbedtls_threading_mutex_t;
 #endif
diff --git a/library/ctr_drbg.c b/library/ctr_drbg.c
index 3815dc7..ab52861 100644
--- a/library/ctr_drbg.c
+++ b/library/ctr_drbg.c
@@ -56,10 +56,6 @@
     ctx->reseed_counter = -1;
 
     ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
-
-#if defined(MBEDTLS_THREADING_C)
-    mbedtls_mutex_init( &ctx->mutex );
-#endif
 }
 
 /*
@@ -72,15 +68,14 @@
         return;
 
 #if defined(MBEDTLS_THREADING_C)
-    mbedtls_mutex_free( &ctx->mutex );
+    /* The mutex is initialized iff f_entropy is set. */
+    if( ctx->f_entropy != NULL )
+        mbedtls_mutex_free( &ctx->mutex );
 #endif
     mbedtls_aes_free( &ctx->aes_ctx );
     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ctr_drbg_context ) );
     ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
     ctx->reseed_counter = -1;
-#if defined(MBEDTLS_THREADING_C)
-    mbedtls_mutex_init( &ctx->mutex );
-#endif
 }
 
 void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx,
@@ -464,6 +459,11 @@
 
     memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE );
 
+    /* The mutex is initialized iff f_entropy is set. */
+#if defined(MBEDTLS_THREADING_C)
+    mbedtls_mutex_init( &ctx->mutex );
+#endif
+
     mbedtls_aes_init( &ctx->aes_ctx );
 
     ctx->f_entropy = f_entropy;
diff --git a/library/entropy.c b/library/entropy.c
index db61f16..b9aca86 100644
--- a/library/entropy.c
+++ b/library/entropy.c
@@ -116,6 +116,11 @@
 
 void mbedtls_entropy_free( mbedtls_entropy_context *ctx )
 {
+    /* If the context was already free, don't call free() again.
+     * This is important for mutexes which don't allow double-free. */
+    if( ctx->accumulator_started == -1 )
+        return;
+
 #if defined(MBEDTLS_HAVEGE_C)
     mbedtls_havege_free( &ctx->havege_data );
 #endif
@@ -132,7 +137,7 @@
 #endif
     ctx->source_count = 0;
     mbedtls_platform_zeroize( ctx->source, sizeof( ctx->source ) );
-    ctx->accumulator_started = 0;
+    ctx->accumulator_started = -1;
 }
 
 int mbedtls_entropy_add_source( mbedtls_entropy_context *ctx,
diff --git a/library/entropy_poll.c b/library/entropy_poll.c
index 84b70fe..2c1e093 100644
--- a/library/entropy_poll.c
+++ b/library/entropy_poll.c
@@ -220,13 +220,13 @@
 {
     ((void) data);
     ((void) output);
-    *olen = 0;
 
+    *olen = 0;
     if( len < sizeof(unsigned char) )
         return( 0 );
 
+    output[0] = 0;
     *olen = sizeof(unsigned char);
-
     return( 0 );
 }
 #endif
diff --git a/library/hmac_drbg.c b/library/hmac_drbg.c
index 25a0225..de97068 100644
--- a/library/hmac_drbg.c
+++ b/library/hmac_drbg.c
@@ -54,10 +54,6 @@
     memset( ctx, 0, sizeof( mbedtls_hmac_drbg_context ) );
 
     ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL;
-
-#if defined(MBEDTLS_THREADING_C)
-    mbedtls_mutex_init( &ctx->mutex );
-#endif
 }
 
 /*
@@ -129,6 +125,10 @@
     if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 )
         return( ret );
 
+#if defined(MBEDTLS_THREADING_C)
+    mbedtls_mutex_init( &ctx->mutex );
+#endif
+
     /*
      * Set initial working state.
      * Use the V memory location, which is currently all 0, to initialize the
@@ -254,6 +254,11 @@
     if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 )
         return( ret );
 
+    /* The mutex is initialized iff the md context is set up. */
+#if defined(MBEDTLS_THREADING_C)
+    mbedtls_mutex_init( &ctx->mutex );
+#endif
+
     md_size = mbedtls_md_get_size( md_info );
 
     /*
@@ -421,14 +426,13 @@
         return;
 
 #if defined(MBEDTLS_THREADING_C)
-    mbedtls_mutex_free( &ctx->mutex );
+    /* The mutex is initialized iff the md context is set up. */
+    if( ctx->md_ctx.md_info != NULL )
+        mbedtls_mutex_free( &ctx->mutex );
 #endif
     mbedtls_md_free( &ctx->md_ctx );
     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_hmac_drbg_context ) );
     ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL;
-#if defined(MBEDTLS_THREADING_C)
-    mbedtls_mutex_init( &ctx->mutex );
-#endif
 }
 
 #if defined(MBEDTLS_FS_IO)
diff --git a/library/md.c b/library/md.c
index de77b16..a10a835 100644
--- a/library/md.c
+++ b/library/md.c
@@ -1,5 +1,5 @@
 /**
- * \file mbedtls_md.c
+ * \file md.c
  *
  * \brief Generic message digest wrapper for mbed TLS
  *
diff --git a/library/psa_crypto_random_impl.h b/library/psa_crypto_random_impl.h
index 1232186..3c4c09a 100644
--- a/library/psa_crypto_random_impl.h
+++ b/library/psa_crypto_random_impl.h
@@ -1,6 +1,14 @@
 /** \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/mbedtls/psa_util.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/mbedtls/psa_util.h if you modify this file.
  */
 /*
  *  Copyright The Mbed TLS Contributors
@@ -22,6 +30,8 @@
 #ifndef PSA_CRYPTO_RANDOM_IMPL_H
 #define PSA_CRYPTO_RANDOM_IMPL_H
 
+#include <mbedtls/psa_util.h>
+
 #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
 
 #include <string.h>
@@ -75,14 +85,6 @@
 
 #include "mbedtls/entropy.h"
 
-/** The type of the PSA DRBG context.
- */
-#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
-
 /** Initialize the PSA DRBG.
  *
  * \param p_rng        Pointer to the Mbed TLS DRBG state.
@@ -122,33 +124,18 @@
     mbedtls_psa_drbg_context_t drbg;
 } mbedtls_psa_random_context_t;
 
-/* The type of an Mbed TLS random generator function. This should be
- * part of the public API instead of repeating the type everywhere.
- * For the time being, declare it here. Declaring a type is necessary
- * to define mbedtls_psa_get_random as a variable of a function pointer
- * type without incurring the wrath of check-names.sh. */
-typedef int mbedtls_f_rng_t( void *p_rng, unsigned char *output, size_t output_size );
-
-/** Return random data.
- *
- * This function is suitable as the \p f_rng parameter to Mbed TLS functions
- * that require a random generator. Use #MBEDTLS_PSA_RANDOM_STATE to
- * obtain the \p p_rng parameter.
- *
- * \param p_rng         The DRBG context. This must be
- *                      #MBEDTLS_PSA_RANDOM_STATE.
- * \param output        The buffer to fill.
- * \param output_len    The length of the buffer in bytes.
- *                      It must be at most #MBEDTLS_PSA_RANDOM_MAX_REQUEST.
- *
- * \retval              \c 0 on success.
- * \return              \c MBEDTLS_ERR_xxx_DRBG_xxx or
- *                      \c MBEDTLS_ERR_PLATFORM_xxx on failure.
+/* Defined in include/mbedtls/psa_util.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(MBEDTLS_CTR_DRBG_C)
-static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_ctr_drbg_random;
-#elif defined(MBEDTLS_HMAC_DRBG_C)
-static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_hmac_drbg_random;
+#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
@@ -167,6 +154,9 @@
  */
 /* 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/mbedtls/psa_util.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.
diff --git a/library/rsa.c b/library/rsa.c
index 9fe551d..68a36f2 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -490,6 +490,9 @@
     mbedtls_rsa_set_padding( ctx, padding, hash_id );
 
 #if defined(MBEDTLS_THREADING_C)
+    /* Set ctx->ver to nonzero to indicate that the mutex has been
+     * initialized and will need to be freed. */
+    ctx->ver = 1;
     mbedtls_mutex_init( &ctx->mutex );
 #endif
 }
@@ -537,9 +540,6 @@
     RSA_VALIDATE_RET( ctx != NULL );
     RSA_VALIDATE_RET( f_rng != NULL );
 
-    if( nbits < 128 || exponent < 3 || nbits % 2 != 0 )
-        return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
-
     /*
      * If the modulus is 1024 bit long or shorter, then the security strength of
      * the RSA algorithm is less than or equal to 80 bits and therefore an error
@@ -552,6 +552,12 @@
     mbedtls_mpi_init( &G );
     mbedtls_mpi_init( &L );
 
+    if( nbits < 128 || exponent < 3 || nbits % 2 != 0 )
+    {
+        ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
+        goto cleanup;
+    }
+
     /*
      * find primes P and Q with Q < P so that:
      * 1.  |P-Q| > 2^( nbits / 2 - 100 )
@@ -629,7 +635,9 @@
     if( ret != 0 )
     {
         mbedtls_rsa_free( ctx );
-        return( MBEDTLS_ERR_RSA_KEY_GEN_FAILED + ret );
+        if( ( -ret & ~0x7f ) == 0 )
+            ret = MBEDTLS_ERR_RSA_KEY_GEN_FAILED + ret;
+        return( ret );
     }
 
     return( 0 );
@@ -2481,7 +2489,6 @@
     RSA_VALIDATE_RET( dst != NULL );
     RSA_VALIDATE_RET( src != NULL );
 
-    dst->ver = src->ver;
     dst->len = src->len;
 
     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->N, &src->N ) );
@@ -2540,7 +2547,12 @@
 #endif /* MBEDTLS_RSA_NO_CRT */
 
 #if defined(MBEDTLS_THREADING_C)
-    mbedtls_mutex_free( &ctx->mutex );
+    /* Free the mutex, but only if it hasn't been freed already. */
+    if( ctx->ver != 0 )
+    {
+        mbedtls_mutex_free( &ctx->mutex );
+        ctx->ver = 0;
+    }
 #endif
 }
 
diff --git a/library/threading.c b/library/threading.c
index 2bb932d..2de117f 100644
--- a/library/threading.c
+++ b/library/threading.c
@@ -67,6 +67,12 @@
     if( mutex == NULL )
         return;
 
+    /* A nonzero value of is_valid indicates a successfully initialized
+     * mutex. This is a workaround for not being able to return an error
+     * code for this function. The lock/unlock functions return an error
+     * if is_valid is nonzero. The Mbed TLS unit test code uses this field
+     * to distinguish more states of the mutex; see
+     * tests/src/threading_helpers for details. */
     mutex->is_valid = pthread_mutex_init( &mutex->mutex, NULL ) == 0;
 }
 
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 876555d..d0758bc 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -703,7 +703,7 @@
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     psa_key_id_t key_slot = 0; /* invalid key slot */
 #endif
-#endif
+#endif  /* MBEDTLS_X509_CRT_PARSE_C */
     char *p, *q;
     const int *list;
 #if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
@@ -734,6 +734,10 @@
     mbedtls_memory_buffer_alloc_init( alloc_buf, sizeof(alloc_buf) );
 #endif
 
+#if defined(MBEDTLS_TEST_HOOKS)
+    test_hooks_init( );
+#endif /* MBEDTLS_TEST_HOOKS */
+
     /*
      * Make sure memory references are valid.
      */
@@ -760,10 +764,10 @@
         ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
         goto exit;
     }
+#endif  /* MBEDTLS_USE_PSA_CRYPTO */
 #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
     mbedtls_test_enable_insecure_external_rng( );
 #endif  /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
-#endif  /* MBEDTLS_USE_PSA_CRYPTO */
 
     if( argc == 0 )
     {
@@ -1536,7 +1540,8 @@
     mbedtls_printf( "\n  . Seeding the random number generator..." );
     fflush( stdout );
 
-    if( rng_seed( &rng, opt.reproducible, pers ) != 0 )
+    ret = rng_seed( &rng, opt.reproducible, pers );
+    if( ret != 0 )
         goto exit;
     mbedtls_printf( " ok\n" );
 
@@ -1881,7 +1886,7 @@
 #else
         fprintf( stderr, "Warning: reproducible option used without constant time\n" );
 #endif
-#endif
+#endif  /* MBEDTLS_HAVE_TIME */
     }
     mbedtls_ssl_conf_rng( &conf, rng_get, &rng );
     mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
@@ -1927,7 +1932,7 @@
             goto exit;
         }
     }
-#endif
+#endif  /* MBEDTLS_X509_CRT_PARSE_C */
 
 #if defined(MBEDTLS_ECP_C)
     if( opt.curves != NULL &&
@@ -2999,19 +3004,7 @@
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     psa_destroy_key( key_slot );
 #endif
-#endif
-    mbedtls_ssl_session_free( &saved_session );
-    mbedtls_ssl_free( &ssl );
-    mbedtls_ssl_config_free( &conf );
-    rng_free( &rng );
-    if( session_data != NULL )
-        mbedtls_platform_zeroize( session_data, session_data_len );
-    mbedtls_free( session_data );
-#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
-    if( context_buf != NULL )
-        mbedtls_platform_zeroize( context_buf, context_buf_len );
-    mbedtls_free( context_buf );
-#endif
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
 
 #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) && \
     defined(MBEDTLS_USE_PSA_CRYPTO)
@@ -3034,12 +3027,39 @@
 #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED &&
           MBEDTLS_USE_PSA_CRYPTO */
 
+    mbedtls_ssl_session_free( &saved_session );
+    mbedtls_ssl_free( &ssl );
+    mbedtls_ssl_config_free( &conf );
+    rng_free( &rng );
+    if( session_data != NULL )
+        mbedtls_platform_zeroize( session_data, session_data_len );
+    mbedtls_free( session_data );
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+    if( context_buf != NULL )
+        mbedtls_platform_zeroize( context_buf, context_buf_len );
+    mbedtls_free( context_buf );
+#endif
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    mbedtls_psa_crypto_free( );
+#endif
+
+#if defined(MBEDTLS_TEST_HOOKS)
+    if( test_hooks_failure_detected( ) )
+    {
+        if( ret == 0 )
+            ret = 1;
+        mbedtls_printf( "Test hooks detected errors.\n" );
+    }
+    test_hooks_free( );
+#endif /* MBEDTLS_TEST_HOOKS */
+
 #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
 #if defined(MBEDTLS_MEMORY_DEBUG)
     mbedtls_memory_buffer_alloc_status();
 #endif
     mbedtls_memory_buffer_alloc_free();
-#endif
+#endif  /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */
 
 #if defined(_WIN32)
     if( opt.query_config_mode == DFL_QUERY_CONFIG_MODE )
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 57c053c..bd4dbb6 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -1369,6 +1369,10 @@
 #endif  /* MBEDTLS_MEMORY_DEBUG */
 #endif  /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */
 
+#if defined(MBEDTLS_TEST_HOOKS)
+    test_hooks_init( );
+#endif /* MBEDTLS_TEST_HOOKS */
+
     /*
      * Make sure memory references are valid in case we exit early.
      */
@@ -1412,10 +1416,10 @@
         ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
         goto exit;
     }
+#endif  /* MBEDTLS_USE_PSA_CRYPTO */
 #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
     mbedtls_test_enable_insecure_external_rng( );
 #endif  /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
-#endif  /* MBEDTLS_USE_PSA_CRYPTO */
 
 #if !defined(_WIN32)
     /* Abort cleanly on SIGTERM and SIGINT */
@@ -2295,7 +2299,8 @@
     mbedtls_printf( "\n  . Seeding the random number generator..." );
     fflush( stdout );
 
-    if( rng_seed( &rng, opt.reproducible, pers ) != 0 )
+    ret = rng_seed( &rng, opt.reproducible, pers );
+    if( ret != 0 )
         goto exit;
     mbedtls_printf( " ok\n" );
 
@@ -2683,7 +2688,7 @@
 #else
         fprintf( stderr, "Warning: reproducible option used without constant time\n" );
 #endif
-#endif
+#endif  /* MBEDTLS_HAVE_TIME */
     }
     mbedtls_ssl_conf_rng( &conf, rng_get, &rng );
     mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
@@ -3997,12 +4002,32 @@
     mbedtls_free( context_buf );
 #endif
 
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    mbedtls_psa_crypto_free( );
+#endif
+
+#if defined(MBEDTLS_TEST_HOOKS)
+    /* Let test hooks detect errors such as resource leaks.
+     * Don't do it in query_config mode, because some test code prints
+     * information to stdout and this gets mixed with the regular output. */
+    if( opt.query_config_mode == DFL_QUERY_CONFIG_MODE )
+    {
+        if( test_hooks_failure_detected( ) )
+        {
+            if( ret == 0 )
+                ret = 1;
+            mbedtls_printf( "Test hooks detected errors.\n" );
+        }
+    }
+    test_hooks_free( );
+#endif /* MBEDTLS_TEST_HOOKS */
+
 #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
 #if defined(MBEDTLS_MEMORY_DEBUG)
     mbedtls_memory_buffer_alloc_status();
 #endif
     mbedtls_memory_buffer_alloc_free();
-#endif
+#endif  /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */
 
     if( opt.query_config_mode == DFL_QUERY_CONFIG_MODE )
     {
diff --git a/programs/ssl/ssl_test_lib.c b/programs/ssl/ssl_test_lib.c
index 46cea14..1bb9d61 100644
--- a/programs/ssl/ssl_test_lib.c
+++ b/programs/ssl/ssl_test_lib.c
@@ -22,6 +22,10 @@
 
 #include "ssl_test_lib.h"
 
+#if defined(MBEDTLS_TEST_HOOKS)
+#include "test/helpers.h"
+#endif
+
 #if !defined(MBEDTLS_SSL_TEST_IMPOSSIBLE)
 
 void my_debug( void *ctx, int level,
@@ -46,6 +50,7 @@
     return 0x5af2a056;
 }
 
+#if !defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
 static int dummy_entropy( void *data, unsigned char *output, size_t len )
 {
     size_t i;
@@ -60,9 +65,15 @@
     }
     return( ret );
 }
+#endif
 
 void rng_init( rng_context_t *rng )
 {
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+    (void) rng;
+    psa_crypto_init( );
+#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
+
 #if defined(MBEDTLS_CTR_DRBG_C)
     mbedtls_ctr_drbg_init( &rng->drbg );
 #elif defined(MBEDTLS_HMAC_DRBG_C)
@@ -72,10 +83,31 @@
 #endif
 
     mbedtls_entropy_init( &rng->entropy );
+#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
 }
 
 int rng_seed( rng_context_t *rng, int reproducible, const char *pers )
 {
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    if( reproducible )
+    {
+        mbedtls_fprintf( stderr,
+                         "MBEDTLS_USE_PSA_CRYPTO does not support reproducible mode.\n" );
+        return( -1 );
+    }
+#endif
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+    /* The PSA crypto RNG does its own seeding. */
+    (void) rng;
+    (void) pers;
+    if( reproducible )
+    {
+        mbedtls_fprintf( stderr,
+                         "The PSA RNG does not support reproducible mode.\n" );
+        return( -1 );
+    }
+    return( 0 );
+#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
     int ( *f_entropy )( void *, unsigned char *, size_t ) =
         ( reproducible ? dummy_entropy : mbedtls_entropy_func );
 
@@ -100,9 +132,9 @@
                                       f_entropy, &rng->entropy,
                                       (const unsigned char *) pers,
                                       strlen( pers ) );
-#else
+#else /* !defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_HMAC_DRBG_C) */
 #error "No DRBG available"
-#endif
+#endif /* !defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_HMAC_DRBG_C) */
 
     if( ret != 0 )
     {
@@ -110,12 +142,21 @@
                         (unsigned int) -ret );
         return( ret );
     }
+#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
 
     return( 0 );
 }
 
 void rng_free( rng_context_t *rng )
 {
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+    (void) rng;
+    /* Deinitialize the PSA crypto subsystem. This deactivates all PSA APIs.
+     * This is ok because none of our applications try to do any crypto after
+     * deinitializing the RNG. */
+    mbedtls_psa_crypto_free( );
+#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
+
 #if defined(MBEDTLS_CTR_DRBG_C)
     mbedtls_ctr_drbg_free( &rng->drbg );
 #elif defined(MBEDTLS_HMAC_DRBG_C)
@@ -125,11 +166,18 @@
 #endif
 
     mbedtls_entropy_free( &rng->entropy );
+#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
 }
 
 int rng_get( void *p_rng, unsigned char *output, size_t output_len )
 {
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+    (void) p_rng;
+    return( mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE,
+                                    output, output_len ) );
+#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
     rng_context_t *rng = p_rng;
+
 #if defined(MBEDTLS_CTR_DRBG_C)
     return( mbedtls_ctr_drbg_random( &rng->drbg, output, output_len ) );
 #elif defined(MBEDTLS_HMAC_DRBG_C)
@@ -137,6 +185,8 @@
 #else
 #error "No DRBG available"
 #endif
+
+#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
 }
 
 #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
@@ -275,4 +325,33 @@
     return( 0 );
 }
 
+#if defined(MBEDTLS_TEST_HOOKS)
+
+void test_hooks_init( void )
+{
+    mbedtls_test_info_reset( );
+
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+    mbedtls_test_mutex_usage_init( );
+#endif
+}
+
+int test_hooks_failure_detected( void )
+{
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+    /* Errors are reported via mbedtls_test_info. */
+    mbedtls_test_mutex_usage_check( );
+#endif
+
+    if( mbedtls_test_info.result != MBEDTLS_TEST_RESULT_SUCCESS )
+        return( 1 );
+    return( 0 );
+}
+
+void test_hooks_free( void )
+{
+}
+
+#endif /* MBEDTLS_TEST_HOOKS */
+
 #endif /* !defined(MBEDTLS_SSL_TEST_IMPOSSIBLE) */
diff --git a/programs/ssl/ssl_test_lib.h b/programs/ssl/ssl_test_lib.h
index 861e82a..98751a0 100644
--- a/programs/ssl/ssl_test_lib.h
+++ b/programs/ssl/ssl_test_lib.h
@@ -43,23 +43,33 @@
 #define MBEDTLS_EXIT_FAILURE    EXIT_FAILURE
 #endif
 
-#if !defined(MBEDTLS_ENTROPY_C) ||                          \
-    !defined(MBEDTLS_NET_C) ||                              \
+#undef HAVE_RNG
+#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) &&         \
+    ( defined(MBEDTLS_USE_PSA_CRYPTO) ||                \
+      defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG) )
+#define HAVE_RNG
+#elif defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_CTR_DRBG_C)
+#define HAVE_RNG
+#elif defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_HMAC_DRBG_C) &&     \
+    ( defined(MBEDTLS_SHA256_C) || defined(MBEDTLS_SHA512_C) )
+#define HAVE_RNG
+#endif
+
+#if !defined(MBEDTLS_NET_C) ||                              \
     !defined(MBEDTLS_SSL_TLS_C) ||                          \
     defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER)
 #define MBEDTLS_SSL_TEST_IMPOSSIBLE                             \
-    "MBEDTLS_ENTROPY_C and/or "                                 \
     "MBEDTLS_NET_C and/or "                                     \
     "MBEDTLS_SSL_TLS_C not defined, "                           \
     "and/or MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER defined.\n"
-#elif !( defined(MBEDTLS_CTR_DRBG_C) ||                                 \
-         defined(MBEDTLS_HMAC_DRBG_C) && ( defined(MBEDTLS_SHA256_C) || \
-                                           defined(MBEDTLS_SHA512_C) ) )
-#define MBEDTLS_SSL_TEST_IMPOSSIBLE                                     \
-    "Neither MBEDTLS_CTR_DRBG_C, nor MBEDTLS_HMAC_DRBG_C and a supported hash defined.\n"
+#elif !defined(HAVE_RNG)
+#define MBEDTLS_SSL_TEST_IMPOSSIBLE             \
+    "No random generator is available.\n"
 #else
 #undef MBEDTLS_SSL_TEST_IMPOSSIBLE
 
+#undef HAVE_RNG
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -76,7 +86,7 @@
 #include "mbedtls/timing.h"
 #include "mbedtls/base64.h"
 
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
 #include "psa/crypto.h"
 #include "mbedtls/psa_util.h"
 #endif
@@ -130,10 +140,38 @@
 
 mbedtls_time_t dummy_constant_time( mbedtls_time_t* time );
 
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+/* If MBEDTLS_TEST_USE_PSA_CRYPTO_RNG is defined, the SSL test programs will use
+ * mbedtls_psa_get_random() rather than entropy+DRBG as a random generator.
+ *
+ * The constraints are:
+ * - Without the entropy module, the PSA RNG is the only option.
+ * - Without at least one of the DRBG modules, the PSA RNG is the only option.
+ * - The PSA RNG does not support explicit seeding, so it is incompatible with
+ *   the reproducible mode used by test programs.
+ * - For good overall test coverage, there should be at least one configuration
+ *   where the test programs use the PSA RNG while the PSA RNG is itself based
+ *   on entropy+DRBG, and at least one configuration where the test programs
+ *   do not use the PSA RNG even though it's there.
+ *
+ * A simple choice that meets the constraints is to use the PSA RNG whenever
+ * MBEDTLS_USE_PSA_CRYPTO is enabled. There's no real technical reason the
+ * choice to use the PSA RNG in the test programs and the choice to use
+ * PSA crypto when TLS code needs crypto have to be tied together, but it
+ * happens to be a good match. It's also a good match from an application
+ * perspective: either PSA is preferred for TLS (both for crypto and for
+ * random generation) or it isn't.
+ */
+#define MBEDTLS_TEST_USE_PSA_CRYPTO_RNG
+#endif
+
 /** A context for random number generation (RNG).
  */
 typedef struct
 {
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+    unsigned char dummy;
+#else /* MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
     mbedtls_entropy_context entropy;
 #if defined(MBEDTLS_CTR_DRBG_C)
     mbedtls_ctr_drbg_context drbg;
@@ -142,6 +180,7 @@
 #else
 #error "No DRBG available"
 #endif
+#endif /* MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
 } rng_context_t;
 
 /** Initialize the RNG.
@@ -219,5 +258,37 @@
 #endif
           int idle_reason );
 
+#if defined(MBEDTLS_TEST_HOOKS)
+/** Initialize whatever test hooks are enabled by the compile-time
+ * configuration and make sense for the TLS test programs. */
+void test_hooks_init( void );
+
+/** Check if any test hooks detected a problem.
+ *
+ * If a problem was detected, it's ok for the calling program to keep going,
+ * but it should ultimately exit with an error status.
+ *
+ * \note When implementing a test hook that detects errors on its own
+ *       (as opposed to e.g. leaving the error for a memory sanitizer to
+ *       report), make sure to print a message to standard error either at
+ *       the time the problem is detected or during the execution of this
+ *       function. This function does not indicate what problem was detected,
+ *       so printing a message is the only way to provide feedback in the
+ *       logs of the calling program.
+ *
+ * \return Nonzero if a problem was detected.
+ *         \c 0 if no problem was detected.
+ */
+int test_hooks_failure_detected( void );
+
+/** Free any resources allocated for the sake of test hooks.
+ *
+ * Call this at the end of the program so that resource leak analyzers
+ * don't complain.
+ */
+void test_hooks_free( void );
+
+#endif /* !MBEDTLS_TEST_HOOKS */
+
 #endif /* MBEDTLS_SSL_TEST_IMPOSSIBLE conditions: else */
 #endif /* MBEDTLS_PROGRAMS_SSL_SSL_TEST_LIB_H */
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 13f0593..e2bc420 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -67,6 +67,10 @@
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-function")
 endif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG)
 
+if(CMAKE_COMPILER_IS_CLANG)
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wdocumentation -Wno-documentation-deprecated-sync -Wunreachable-code")
+endif(CMAKE_COMPILER_IS_CLANG)
+
 if(MSVC)
     # If a warning level has been defined, suppress all warnings for test code
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W0")
@@ -153,6 +157,7 @@
 add_test_suite(psa_crypto_se_driver_hal_mocks)
 add_test_suite(psa_crypto_slot_management)
 add_test_suite(psa_its)
+add_test_suite(random)
 add_test_suite(rsa)
 add_test_suite(shax)
 add_test_suite(ssl)
diff --git a/tests/include/test/asn1_helpers.h b/tests/include/test/asn1_helpers.h
new file mode 100644
index 0000000..91ae260
--- /dev/null
+++ b/tests/include/test/asn1_helpers.h
@@ -0,0 +1,50 @@
+/** Helper functions for tests that manipulate ASN.1 data.
+ */
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#ifndef ASN1_HELPERS_H
+#define ASN1_HELPERS_H
+
+#include "test/helpers.h"
+
+/** Skip past an INTEGER in an ASN.1 buffer.
+ *
+ * Mark the current test case as failed in any of the following conditions:
+ * - The buffer does not start with an ASN.1 INTEGER.
+ * - The integer's size or parity does not match the constraints expressed
+ *   through \p min_bits, \p max_bits and \p must_be_odd.
+ *
+ * \param p             Upon entry, `*p` points to the first byte of the
+ *                      buffer to parse.
+ *                      On successful return, `*p` points to the first byte
+ *                      after the parsed INTEGER.
+ *                      On failure, `*p` is unspecified.
+ * \param end           The end of the ASN.1 buffer.
+ * \param min_bits      Fail the test case if the integer does not have at
+ *                      least this many significant bits.
+ * \param max_bits      Fail the test case if the integer has more than
+ *                      this many significant bits.
+ * \param must_be_odd   Fail the test case if the integer is even.
+ *
+ * \return              \c 0 if the test failed, otherwise 1.
+ */
+int mbedtls_test_asn1_skip_integer( unsigned char **p, const unsigned char *end,
+                                    size_t min_bits, size_t max_bits,
+                                    int must_be_odd );
+
+#endif /* ASN1_HELPERS_H */
diff --git a/tests/include/test/helpers.h b/tests/include/test/helpers.h
index 8b56d3a..c3a844b 100644
--- a/tests/include/test/helpers.h
+++ b/tests/include/test/helpers.h
@@ -31,6 +31,11 @@
 #include MBEDTLS_CONFIG_FILE
 #endif
 
+#if defined(MBEDTLS_THREADING_C) && defined(MBEDTLS_THREADING_PTHREAD) && \
+    defined(MBEDTLS_TEST_HOOKS)
+#define MBEDTLS_TEST_MUTEX_USAGE
+#endif
+
 #if defined(MBEDTLS_PLATFORM_C)
 #include "mbedtls/platform.h"
 #else
@@ -63,6 +68,9 @@
     const char *filename;
     int line_no;
     unsigned long step;
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+    const char *mutex_usage_error;
+#endif
 }
 mbedtls_test_info_t;
 extern mbedtls_test_info_t mbedtls_test_info;
@@ -256,8 +264,18 @@
 void mbedtls_test_param_failed_reset_state( void );
 #endif /* MBEDTLS_CHECK_PARAMS */
 
-#if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+#if defined(MBEDTLS_PSA_CRYPTO_C) && defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
 #include "test/fake_external_rng_for_test.h"
 #endif
 
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+/** Permanently activate the mutex usage verification framework. See
+ * threading_helpers.c for information. */
+void mbedtls_test_mutex_usage_init( void );
+
+/** Call this function after executing a test case to check for mutex usage
+ * errors. */
+void mbedtls_test_mutex_usage_check( void );
+#endif /* MBEDTLS_TEST_MUTEX_USAGE */
+
 #endif /* TEST_HELPERS_H */
diff --git a/tests/include/test/macros.h b/tests/include/test/macros.h
index 6930a5d..450bc2c 100644
--- a/tests/include/test/macros.h
+++ b/tests/include/test/macros.h
@@ -321,40 +321,45 @@
     mbedtls_exit( 1 );                                              \
 }
 
+/** \def ARRAY_LENGTH
+ * Return the number of elements of a static or stack array.
+ *
+ * \param array         A value of array (not pointer) type.
+ *
+ * \return The number of elements of the array.
+ */
+/* A correct implementation of ARRAY_LENGTH, but which silently gives
+ * a nonsensical result if called with a pointer rather than an array. */
+#define ARRAY_LENGTH_UNSAFE( array )            \
+    ( sizeof( array ) / sizeof( *( array ) ) )
+
 #if defined(__GNUC__)
 /* Test if arg and &(arg)[0] have the same type. This is true if arg is
  * an array but not if it's a pointer. */
 #define IS_ARRAY_NOT_POINTER( arg )                                     \
     ( ! __builtin_types_compatible_p( __typeof__( arg ),                \
                                       __typeof__( &( arg )[0] ) ) )
-#else
-/* On platforms where we don't know how to implement this check,
- * omit it. Oh well, a non-portable check is better than nothing. */
-#define IS_ARRAY_NOT_POINTER( arg ) 1
-#endif
-
 /* A compile-time constant with the value 0. If `const_expr` is not a
  * compile-time constant with a nonzero value, cause a compile-time error. */
 #define STATIC_ASSERT_EXPR( const_expr )                                \
     ( 0 && sizeof( struct { unsigned int STATIC_ASSERT : 1 - 2 * ! ( const_expr ); } ) )
+
 /* Return the scalar value `value` (possibly promoted). This is a compile-time
  * constant if `value` is. `condition` must be a compile-time constant.
  * If `condition` is false, arrange to cause a compile-time error. */
 #define STATIC_ASSERT_THEN_RETURN( condition, value )   \
     ( STATIC_ASSERT_EXPR( condition ) ? 0 : ( value ) )
 
-#define ARRAY_LENGTH_UNSAFE( array )            \
-    ( sizeof( array ) / sizeof( *( array ) ) )
-/** Return the number of elements of a static or stack array.
- *
- * \param array         A value of array (not pointer) type.
- *
- * \return The number of elements of the array.
- */
 #define ARRAY_LENGTH( array )                                           \
     ( STATIC_ASSERT_THEN_RETURN( IS_ARRAY_NOT_POINTER( array ),         \
                                  ARRAY_LENGTH_UNSAFE( array ) ) )
 
+#else
+/* If we aren't sure the compiler supports our non-standard tricks,
+ * fall back to the unsafe implementation. */
+#define ARRAY_LENGTH( array ) ARRAY_LENGTH_UNSAFE( array )
+#endif
+
 /** Return the smaller of two values.
  *
  * \param x         An integer-valued expression without side effects.
diff --git a/tests/include/test/psa_crypto_helpers.h b/tests/include/test/psa_crypto_helpers.h
index b7dc4b5..9881eae 100644
--- a/tests/include/test/psa_crypto_helpers.h
+++ b/tests/include/test/psa_crypto_helpers.h
@@ -22,11 +22,73 @@
 #define PSA_CRYPTO_HELPERS_H
 
 #include "test/helpers.h"
+
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+
 #include "test/psa_helpers.h"
 
 #include <psa/crypto.h>
 #include <psa_crypto_slot_management.h>
 
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#include "mbedtls/psa_util.h"
+#endif
+
+#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
+
+/* Internal function for #TEST_USES_KEY_ID. Return 1 on success, 0 on failure. */
+int mbedtls_test_uses_key_id( mbedtls_svc_key_id_t key_id );
+
+/** Destroy persistent keys recorded with #TEST_USES_KEY_ID.
+ */
+void mbedtls_test_psa_purge_key_storage( void );
+
+/** Purge the in-memory cache of persistent keys recorded with
+ * #TEST_USES_KEY_ID.
+ *
+ * Call this function before calling PSA_DONE() if it's ok for
+ * persistent keys to still exist at this point.
+ */
+void mbedtls_test_psa_purge_key_cache( void );
+
+/** \def TEST_USES_KEY_ID
+ *
+ * Call this macro in a test function before potentially creating a
+ * persistent key. Test functions that use this mechanism must call
+ * mbedtls_test_psa_purge_key_storage() in their cleanup code.
+ *
+ * This macro records a persistent key identifier as potentially used in the
+ * current test case. Recorded key identifiers will be cleaned up at the end
+ * of the test case, even on failure.
+ *
+ * This macro has no effect on volatile keys. Therefore, it is safe to call
+ * this macro in a test function that creates either volatile or persistent
+ * keys depending on the test data.
+ *
+ * This macro currently has no effect on special identifiers
+ * used to store implementation-specific files.
+ *
+ * Calling this macro multiple times on the same key identifier in the same
+ * test case has no effect.
+ *
+ * This macro can fail the test case if there isn't enough memory to
+ * record the key id.
+ *
+ * \param key_id    The PSA key identifier to record.
+ */
+#define TEST_USES_KEY_ID( key_id )                      \
+    TEST_ASSERT( mbedtls_test_uses_key_id( key_id ) )
+
+#else /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
+
+#define TEST_USES_KEY_ID( key_id ) ( (void) ( key_id ) )
+#define mbedtls_test_psa_purge_key_storage( ) ( (void) 0 )
+#define mbedtls_test_psa_purge_key_cache( ) ( (void) 0 )
+
+#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
+
+#define PSA_INIT( ) PSA_ASSERT( psa_crypto_init( ) )
+
 /** Check for things that have not been cleaned up properly in the
  * PSA subsystem.
  *
@@ -51,13 +113,36 @@
     }                                                                   \
     while( 0 )
 
-/** Shut down the PSA Crypto subsystem. Expect a clean shutdown, with no slots
- * in use.
+/** Shut down the PSA Crypto subsystem and destroy persistent keys.
+ * Expect a clean shutdown, with no slots in use.
+ *
+ * If some key slots are still in use, record the test case as failed,
+ * but continue executing. This macro is suitable (and primarily intended)
+ * for use in the cleanup section of test functions.
+ *
+ * \note Persistent keys must be recorded with #TEST_USES_KEY_ID before
+ *       creating them.
  */
 #define PSA_DONE( )                                                     \
     do                                                                  \
     {                                                                   \
         test_fail_if_psa_leaking( __LINE__, __FILE__ );                 \
+        mbedtls_test_psa_purge_key_storage( );                          \
+        mbedtls_psa_crypto_free( );                                     \
+    }                                                                   \
+    while( 0 )
+
+/** Shut down the PSA Crypto subsystem, allowing persistent keys to survive.
+ * Expect a clean shutdown, with no slots in use.
+ *
+ * If some key slots are still in use, record the test case as failed and
+ * jump to the `exit` label.
+ */
+#define PSA_SESSION_DONE( )                                             \
+    do                                                                  \
+    {                                                                   \
+        mbedtls_test_psa_purge_key_cache( );                            \
+        ASSERT_PSA_PRISTINE( );                                         \
         mbedtls_psa_crypto_free( );                                     \
     }                                                                   \
     while( 0 )
@@ -185,4 +270,29 @@
     }                                                                      \
     while( 0 )
 
+#endif /* MBEDTLS_PSA_CRYPTO_C */
+
+/** \def USE_PSA_INIT
+ *
+ * Call this macro to initialize the PSA subsystem if #MBEDTLS_USE_PSA_CRYPTO
+ * is enabled and do nothing otherwise. If the initialization fails, mark
+ * the test case as failed and jump to the \p exit label.
+ */
+/** \def USE_PSA_DONE
+ *
+ * Call this macro at the end of a test case if you called #USE_PSA_INIT.
+ * This is like #PSA_DONE, except that it does nothing if
+ * #MBEDTLS_USE_PSA_CRYPTO is disabled.
+ */
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#define USE_PSA_INIT( ) PSA_INIT( )
+#define USE_PSA_DONE( ) PSA_DONE( )
+#else /* MBEDTLS_USE_PSA_CRYPTO */
+/* Define empty macros so that we can use them in the preamble and teardown
+ * of every test function that uses PSA conditionally based on
+ * MBEDTLS_USE_PSA_CRYPTO. */
+#define USE_PSA_INIT( ) ( (void) 0 )
+#define USE_PSA_DONE( ) ( (void) 0 )
+#endif /* !MBEDTLS_USE_PSA_CRYPTO */
+
 #endif /* PSA_CRYPTO_HELPERS_H */
diff --git a/tests/include/test/psa_exercise_key.h b/tests/include/test/psa_exercise_key.h
new file mode 100644
index 0000000..57eae58
--- /dev/null
+++ b/tests/include/test/psa_exercise_key.h
@@ -0,0 +1,241 @@
+/** Code to exercise a PSA key object, i.e. validate that it seems well-formed
+ * and can do what it is supposed to do.
+ */
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#ifndef PSA_EXERCISE_KEY_H
+#define PSA_EXERCISE_KEY_H
+
+#include "test/helpers.h"
+#include "test/psa_crypto_helpers.h"
+
+#include <psa/crypto.h>
+
+/** \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_MD2)
+#define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_MD2
+#elif defined(PSA_WANT_ALG_MD4)
+#define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_MD4
+#elif defined(PSA_WANT_ALG_MD5)
+#define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_MD5
+/* MBEDTLS_RIPEMD160_C 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)
+#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
+#elif defined(PSA_WANT_ALG_SHA_512)
+#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
+#else
+#undef KNOWN_SUPPORTED_HASH_ALG
+#endif
+
+/** \def KNOWN_SUPPORTED_BLOCK_CIPHER
+ *
+ * A block cipher that is known to be supported.
+ *
+ * For simplicity's sake, stick to block ciphers with 16-byte blocks.
+ */
+#if defined(MBEDTLS_AES_C)
+#define KNOWN_SUPPORTED_BLOCK_CIPHER PSA_KEY_TYPE_AES
+#elif defined(MBEDTLS_ARIA_C)
+#define KNOWN_SUPPORTED_BLOCK_CIPHER PSA_KEY_TYPE_ARIA
+#elif defined(MBEDTLS_CAMELLIA_C)
+#define KNOWN_SUPPORTED_BLOCK_CIPHER PSA_KEY_TYPE_CAMELLIA
+#undef KNOWN_SUPPORTED_BLOCK_CIPHER
+#endif
+
+/** \def KNOWN_SUPPORTED_MAC_ALG
+ *
+ * A MAC mode that is known to be supported.
+ *
+ * It must either be HMAC with #KNOWN_SUPPORTED_HASH_ALG or
+ * a block cipher-based MAC with #KNOWN_SUPPORTED_BLOCK_CIPHER.
+ *
+ * This is used in some smoke tests.
+ */
+#if defined(KNOWN_SUPPORTED_HASH_ALG) && defined(PSA_WANT_ALG_HMAC)
+#define KNOWN_SUPPORTED_MAC_ALG ( PSA_ALG_HMAC( KNOWN_SUPPORTED_HASH_ALG ) )
+#define KNOWN_SUPPORTED_MAC_KEY_TYPE PSA_KEY_TYPE_HMAC
+#elif defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(MBEDTLS_CMAC_C)
+#define KNOWN_SUPPORTED_MAC_ALG PSA_ALG_CMAC
+#define KNOWN_SUPPORTED_MAC_KEY_TYPE KNOWN_SUPPORTED_BLOCK_CIPHER
+#else
+#undef KNOWN_SUPPORTED_MAC_ALG
+#undef KNOWN_SUPPORTED_MAC_KEY_TYPE
+#endif
+
+/** \def KNOWN_SUPPORTED_BLOCK_CIPHER_ALG
+ *
+ * A cipher algorithm and key type that are known to be supported.
+ *
+ * This is used in some smoke tests.
+ */
+#if defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(MBEDTLS_CIPHER_MODE_CTR)
+#define KNOWN_SUPPORTED_BLOCK_CIPHER_ALG PSA_ALG_CTR
+#elif defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(MBEDTLS_CIPHER_MODE_CBC)
+#define KNOWN_SUPPORTED_BLOCK_CIPHER_ALG PSA_ALG_CBC_NO_PADDING
+#elif defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(MBEDTLS_CIPHER_MODE_CFB)
+#define KNOWN_SUPPORTED_BLOCK_CIPHER_ALG PSA_ALG_CFB
+#elif defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(MBEDTLS_CIPHER_MODE_OFB)
+#define KNOWN_SUPPORTED_BLOCK_CIPHER_ALG PSA_ALG_OFB
+#else
+#undef KNOWN_SUPPORTED_BLOCK_CIPHER_ALG
+#endif
+#if defined(KNOWN_SUPPORTED_BLOCK_CIPHER_ALG)
+#define KNOWN_SUPPORTED_CIPHER_ALG KNOWN_SUPPORTED_BLOCK_CIPHER_ALG
+#define KNOWN_SUPPORTED_CIPHER_KEY_TYPE KNOWN_SUPPORTED_BLOCK_CIPHER
+#elif defined(MBEDTLS_RC4_C)
+#define KNOWN_SUPPORTED_CIPHER_ALG PSA_ALG_RC4
+#define KNOWN_SUPPORTED_CIPHER_KEY_TYPE PSA_KEY_TYPE_RC4
+#else
+#undef KNOWN_SUPPORTED_CIPHER_ALG
+#undef KNOWN_SUPPORTED_CIPHER_KEY_TYPE
+#endif
+
+/** Convenience function to set up a key derivation.
+ *
+ * In case of failure, mark the current test case as failed.
+ *
+ * The inputs \p input1 and \p input2 are, in order:
+ * - HKDF: salt, info.
+ * - TKS 1.2 PRF, TLS 1.2 PSK-to-MS: seed, label.
+ *
+ * \param operation         The operation object to use.
+ *                          It must be in the initialized state.
+ * \param key               The key to use.
+ * \param alg               The algorithm to use.
+ * \param input1            The first input to pass.
+ * \param input1_length     The length of \p input1 in bytes.
+ * \param input2            The first input to pass.
+ * \param input2_length     The length of \p input2 in bytes.
+ * \param capacity          The capacity to set.
+ *
+ * \return                  \c 1 on success, \c 0 on failure.
+ */
+int mbedtls_test_psa_setup_key_derivation_wrap(
+    psa_key_derivation_operation_t* operation,
+    mbedtls_svc_key_id_t key,
+    psa_algorithm_t alg,
+    const unsigned char* input1, size_t input1_length,
+    const unsigned char* input2, size_t input2_length,
+    size_t capacity );
+
+/** Perform a key agreement using the given key pair against its public key
+ * using psa_raw_key_agreement().
+ *
+ * The result is discarded. The purpose of this function is to smoke-test a key.
+ *
+ * In case of failure, mark the current test case as failed.
+ *
+ * \param alg               A key agreement algorithm compatible with \p key.
+ * \param key               A key that allows key agreement with \p alg.
+ *
+ * \return                  \c 1 on success, \c 0 on failure.
+ */
+psa_status_t mbedtls_test_psa_raw_key_agreement_with_self(
+    psa_algorithm_t alg,
+    mbedtls_svc_key_id_t key );
+
+/** Perform a key agreement using the given key pair against its public key
+ * using psa_key_derivation_raw_key().
+ *
+ * The result is discarded. The purpose of this function is to smoke-test a key.
+ *
+ * In case of failure, mark the current test case as failed.
+ *
+ * \param operation         An operation that has been set up for a key
+ *                          agreement algorithm that is compatible with
+ *                          \p key.
+ * \param key               A key pair object that is suitable for a key
+ *                          agreement with \p operation.
+ *
+ * \return                  \c 1 on success, \c 0 on failure.
+ */
+psa_status_t mbedtls_test_psa_key_agreement_with_self(
+    psa_key_derivation_operation_t *operation,
+    mbedtls_svc_key_id_t key );
+
+/** Perform sanity checks on the given key representation.
+ *
+ * If any of the checks fail, mark the current test case as failed.
+ *
+ * The checks depend on the key type.
+ * - All types: check the export size against maximum-size macros.
+ * - DES: parity bits.
+ * - RSA: check the ASN.1 structure and the size and parity of the integers.
+ * - ECC private or public key: exact representation length.
+ * - Montgomery public key: first byte.
+ *
+ * \param type              The key type.
+ * \param bits              The key size in bits.
+ * \param exported          A buffer containing the key representation.
+ * \param exported_length   The length of \p exported in bytes.
+ *
+ * \return                  \c 1 if all checks passed, \c 0 on failure.
+ */
+int mbedtls_test_psa_exported_key_sanity_check(
+    psa_key_type_t type, size_t bits,
+    const uint8_t *exported, size_t exported_length );
+
+/** Do smoke tests on a key.
+ *
+ * Perform one of each operation indicated by \p alg (decrypt/encrypt,
+ * sign/verify, or derivation) that is permitted according to \p usage.
+ * \p usage and \p alg should correspond to the expected policy on the
+ * key.
+ *
+ * Export the key if permitted by \p usage, and check that the output
+ * looks sensible. If \p usage forbids export, check that
+ * \p psa_export_key correctly rejects the attempt. If the key is
+ * asymmetric, also check \p psa_export_public_key.
+ *
+ * If the key fails the tests, this function calls the test framework's
+ * `mbedtls_test_fail` function and returns false. Otherwise this function
+ * returns true. Therefore it should be used as follows:
+ * ```
+ * if( ! exercise_key( ... ) ) goto exit;
+ * ```
+ *
+ * \param key       The key to exercise. It should be capable of performing
+ *                  \p alg.
+ * \param usage     The usage flags to assume.
+ * \param alg       The algorithm to exercise.
+ *
+ * \retval 0 The key failed the smoke tests.
+ * \retval 1 The key passed the smoke tests.
+ */
+int mbedtls_test_psa_exercise_key( mbedtls_svc_key_id_t key,
+                                   psa_key_usage_t usage,
+                                   psa_algorithm_t alg );
+
+psa_key_usage_t mbedtls_test_psa_usage_to_exercise( psa_key_type_t type,
+                                                    psa_algorithm_t alg );
+
+#endif /* PSA_EXERCISE_KEY_H */
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 1036a7c..43742fd 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -922,37 +922,61 @@
     if_build_succeeded tests/context-info.sh
 }
 
-component_test_no_ctr_drbg () {
-    msg "build: Full minus CTR_DRBG"
+component_test_no_ctr_drbg_classic () {
+    msg "build: Full minus CTR_DRBG, classic crypto in TLS"
     scripts/config.py full
     scripts/config.py unset MBEDTLS_CTR_DRBG_C
+    scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO
 
     CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
     make
 
-    msg "test: Full minus CTR_DRBG - main suites"
+    msg "test: Full minus CTR_DRBG, classic crypto - main suites"
     make test
 
     # In this configuration, the TLS test programs use HMAC_DRBG.
     # The SSL tests are slow, so run a small subset, just enough to get
     # confidence that the SSL code copes with HMAC_DRBG.
-    msg "test: Full minus CTR_DRBG - ssl-opt.sh (subset)"
+    msg "test: Full minus CTR_DRBG, classic crypto - ssl-opt.sh (subset)"
     if_build_succeeded tests/ssl-opt.sh -f 'Default\|SSL async private.*delay=\|tickets enabled on server'
 
-    msg "test: Full minus CTR_DRBG - compat.sh (subset)"
+    msg "test: Full minus CTR_DRBG, classic crypto - compat.sh (subset)"
     if_build_succeeded tests/compat.sh -m tls1_2 -t 'ECDSA PSK' -V NO -p OpenSSL
 }
 
-component_test_no_hmac_drbg () {
-    msg "build: Full minus HMAC_DRBG"
+component_test_no_ctr_drbg_use_psa () {
+    msg "build: Full minus CTR_DRBG, PSA crypto in TLS"
     scripts/config.py full
-    scripts/config.py unset MBEDTLS_HMAC_DRBG_C
-    scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG
+    scripts/config.py unset MBEDTLS_CTR_DRBG_C
+    scripts/config.py set MBEDTLS_USE_PSA_CRYPTO
 
     CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
     make
 
-    msg "test: Full minus HMAC_DRBG - main suites"
+    msg "test: Full minus CTR_DRBG, USE_PSA_CRYPTO - main suites"
+    make test
+
+    # In this configuration, the TLS test programs use HMAC_DRBG.
+    # The SSL tests are slow, so run a small subset, just enough to get
+    # confidence that the SSL code copes with HMAC_DRBG.
+    msg "test: Full minus CTR_DRBG, USE_PSA_CRYPTO - ssl-opt.sh (subset)"
+    if_build_succeeded tests/ssl-opt.sh -f 'Default\|SSL async private.*delay=\|tickets enabled on server'
+
+    msg "test: Full minus CTR_DRBG, USE_PSA_CRYPTO - compat.sh (subset)"
+    if_build_succeeded tests/compat.sh -m tls1_2 -t 'ECDSA PSK' -V NO -p OpenSSL
+}
+
+component_test_no_hmac_drbg_classic () {
+    msg "build: Full minus HMAC_DRBG, classic crypto in TLS"
+    scripts/config.py full
+    scripts/config.py unset MBEDTLS_HMAC_DRBG_C
+    scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG
+    scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO
+
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
+
+    msg "test: Full minus HMAC_DRBG, classic crypto - main suites"
     make test
 
     # Normally our ECDSA implementation uses deterministic ECDSA. But since
@@ -960,29 +984,84 @@
     # instead.
     # Test SSL with non-deterministic ECDSA. Only test features that
     # might be affected by how ECDSA signature is performed.
-    msg "test: Full minus HMAC_DRBG - ssl-opt.sh (subset)"
+    msg "test: Full minus HMAC_DRBG, classic crypto - ssl-opt.sh (subset)"
     if_build_succeeded tests/ssl-opt.sh -f 'Default\|SSL async private: sign'
 
     # To save time, only test one protocol version, since this part of
     # the protocol is identical in (D)TLS up to 1.2.
-    msg "test: Full minus HMAC_DRBG - compat.sh (ECDSA)"
+    msg "test: Full minus HMAC_DRBG, classic crypto - compat.sh (ECDSA)"
     if_build_succeeded tests/compat.sh -m tls1_2 -t 'ECDSA'
 }
 
-component_test_psa_external_rng_no_drbg () {
-    msg "build: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG"
+component_test_no_hmac_drbg_use_psa () {
+    msg "build: Full minus HMAC_DRBG, PSA crypto in TLS"
+    scripts/config.py full
+    scripts/config.py unset MBEDTLS_HMAC_DRBG_C
+    scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG
+    scripts/config.py set MBEDTLS_USE_PSA_CRYPTO
+
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
+
+    msg "test: Full minus HMAC_DRBG, USE_PSA_CRYPTO - main suites"
+    make test
+
+    # Normally our ECDSA implementation uses deterministic ECDSA. But since
+    # HMAC_DRBG is disabled in this configuration, randomized ECDSA is used
+    # instead.
+    # Test SSL with non-deterministic ECDSA. Only test features that
+    # might be affected by how ECDSA signature is performed.
+    msg "test: Full minus HMAC_DRBG, USE_PSA_CRYPTO - ssl-opt.sh (subset)"
+    if_build_succeeded tests/ssl-opt.sh -f 'Default\|SSL async private: sign'
+
+    # To save time, only test one protocol version, since this part of
+    # the protocol is identical in (D)TLS up to 1.2.
+    msg "test: Full minus HMAC_DRBG, USE_PSA_CRYPTO - compat.sh (ECDSA)"
+    if_build_succeeded tests/compat.sh -m tls1_2 -t 'ECDSA'
+}
+
+component_test_psa_external_rng_no_drbg_classic () {
+    msg "build: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, classic crypto in TLS"
+    scripts/config.py full
+    scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+    scripts/config.py unset MBEDTLS_ENTROPY_C
+    scripts/config.py unset MBEDTLS_ENTROPY_NV_SEED
+    scripts/config.py unset MBEDTLS_PLATFORM_NV_SEED_ALT
+    scripts/config.py unset MBEDTLS_CTR_DRBG_C
+    scripts/config.py unset MBEDTLS_HMAC_DRBG_C
+    scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG
+    scripts/config.py set MBEDTLS_ECP_NO_INTERNAL_RNG
+    # When MBEDTLS_USE_PSA_CRYPTO is disabled and there is no DRBG,
+    # the SSL test programs don't have an RNG and can't work. Explicitly
+    # make them use the PSA RNG with -DMBEDTLS_TEST_USE_PSA_CRYPTO_RNG.
+    make CFLAGS="$ASAN_CFLAGS -O2 -DMBEDTLS_TEST_USE_PSA_CRYPTO_RNG" LDFLAGS="$ASAN_CFLAGS"
+
+    msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, classic crypto - main suites"
+    make test
+
+    msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, classic crypto - ssl-opt.sh (subset)"
+    if_build_succeeded tests/ssl-opt.sh -f 'Default'
+}
+
+component_test_psa_external_rng_no_drbg_use_psa () {
+    msg "build: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, PSA crypto in TLS"
     scripts/config.py full
     scripts/config.py set MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+    scripts/config.py unset MBEDTLS_ENTROPY_C
+    scripts/config.py unset MBEDTLS_ENTROPY_NV_SEED
+    scripts/config.py unset MBEDTLS_PLATFORM_NV_SEED_ALT
     scripts/config.py unset MBEDTLS_CTR_DRBG_C
     scripts/config.py unset MBEDTLS_HMAC_DRBG_C
     scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG
     scripts/config.py set MBEDTLS_ECP_NO_INTERNAL_RNG
     make CFLAGS="$ASAN_CFLAGS -O2" LDFLAGS="$ASAN_CFLAGS"
 
-    msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG"
+    msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, PSA crypto - main suites"
     make test
 
-    # no SSL tests as they all depend on having a DRBG
+    msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, PSA crypto - ssl-opt.sh (subset)"
+    if_build_succeeded tests/ssl-opt.sh -f 'Default\|opaque'
 }
 
 component_test_psa_external_rng_use_psa_crypto () {
diff --git a/tests/src/asn1_helpers.c b/tests/src/asn1_helpers.c
new file mode 100644
index 0000000..79aa166
--- /dev/null
+++ b/tests/src/asn1_helpers.c
@@ -0,0 +1,74 @@
+/** \file asn1_helpers.c
+ *
+ * \brief Helper functions for tests that manipulate ASN.1 data.
+ */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#include <test/helpers.h>
+#include <test/macros.h>
+
+#if defined(MBEDTLS_ASN1_PARSE_C)
+
+#include <mbedtls/asn1.h>
+
+int mbedtls_test_asn1_skip_integer( unsigned char **p, const unsigned char *end,
+                                    size_t min_bits, size_t max_bits,
+                                    int must_be_odd )
+{
+    size_t len;
+    size_t actual_bits;
+    unsigned char msb;
+    TEST_EQUAL( mbedtls_asn1_get_tag( p, end, &len,
+                                      MBEDTLS_ASN1_INTEGER ),
+                0 );
+
+    /* Check if the retrieved length doesn't extend the actual buffer's size.
+     * It is assumed here, that end >= p, which validates casting to size_t. */
+    TEST_ASSERT( len <= (size_t)( end - *p) );
+
+    /* Tolerate a slight departure from DER encoding:
+     * - 0 may be represented by an empty string or a 1-byte string.
+     * - The sign bit may be used as a value bit. */
+    if( ( len == 1 && ( *p )[0] == 0 ) ||
+        ( len > 1 && ( *p )[0] == 0 && ( ( *p )[1] & 0x80 ) != 0 ) )
+    {
+        ++( *p );
+        --len;
+    }
+    if( min_bits == 0 && len == 0 )
+        return( 1 );
+    msb = ( *p )[0];
+    TEST_ASSERT( msb != 0 );
+    actual_bits = 8 * ( len - 1 );
+    while( msb != 0 )
+    {
+        msb >>= 1;
+        ++actual_bits;
+    }
+    TEST_ASSERT( actual_bits >= min_bits );
+    TEST_ASSERT( actual_bits <= max_bits );
+    if( must_be_odd )
+        TEST_ASSERT( ( ( *p )[len-1] & 1 ) != 0 );
+    *p += len;
+    return( 1 );
+exit:
+    return( 0 );
+}
+
+#endif /* MBEDTLS_ASN1_PARSE_C */
diff --git a/tests/src/fake_external_rng_for_test.c b/tests/src/fake_external_rng_for_test.c
index 98b3fe0..9c2195b 100644
--- a/tests/src/fake_external_rng_for_test.c
+++ b/tests/src/fake_external_rng_for_test.c
@@ -1,4 +1,4 @@
-/** \file psa_crypto_helpers.c
+/** \file fake_external_rng_for_test.c
  *
  * \brief Helper functions to test PSA crypto functionality.
  */
diff --git a/tests/src/psa_crypto_helpers.c b/tests/src/psa_crypto_helpers.c
index cb79a22..f2222cb 100644
--- a/tests/src/psa_crypto_helpers.c
+++ b/tests/src/psa_crypto_helpers.c
@@ -28,6 +28,51 @@
 
 #include <psa/crypto.h>
 
+#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
+
+#include <psa_crypto_storage.h>
+
+static mbedtls_svc_key_id_t key_ids_used_in_test[9];
+static size_t num_key_ids_used;
+
+int mbedtls_test_uses_key_id( mbedtls_svc_key_id_t key_id )
+{
+    size_t i;
+    if( MBEDTLS_SVC_KEY_ID_GET_KEY_ID( key_id ) >
+        PSA_MAX_PERSISTENT_KEY_IDENTIFIER )
+    {
+        /* Don't touch key id values that designate non-key files. */
+        return( 1 );
+    }
+    for( i = 0; i < num_key_ids_used ; i++ )
+    {
+        if( mbedtls_svc_key_id_equal( key_id, key_ids_used_in_test[i] ) )
+            return( 1 );
+    }
+    if( num_key_ids_used == ARRAY_LENGTH( key_ids_used_in_test ) )
+        return( 0 );
+    key_ids_used_in_test[num_key_ids_used] = key_id;
+    ++num_key_ids_used;
+    return( 1 );
+}
+
+void mbedtls_test_psa_purge_key_storage( void )
+{
+    size_t i;
+    for( i = 0; i < num_key_ids_used; i++ )
+        psa_destroy_persistent_key( key_ids_used_in_test[i] );
+    num_key_ids_used = 0;
+}
+
+void mbedtls_test_psa_purge_key_cache( void )
+{
+    size_t i;
+    for( i = 0; i < num_key_ids_used; i++ )
+        psa_purge_key( key_ids_used_in_test[i] );
+}
+
+#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
+
 const char *mbedtls_test_helper_is_psa_leaking( void )
 {
     mbedtls_psa_stats_t stats;
diff --git a/tests/src/psa_exercise_key.c b/tests/src/psa_exercise_key.c
new file mode 100644
index 0000000..9f80d7b
--- /dev/null
+++ b/tests/src/psa_exercise_key.c
@@ -0,0 +1,875 @@
+/** Code to exercise a PSA key object, i.e. validate that it seems well-formed
+ * and can do what it is supposed to do.
+ */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#include <test/helpers.h>
+#include <test/macros.h>
+#include <test/psa_exercise_key.h>
+
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+
+#include <mbedtls/asn1.h>
+#include <psa/crypto.h>
+
+#include <test/asn1_helpers.h>
+#include <test/psa_crypto_helpers.h>
+
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+static int lifetime_is_dynamic_secure_element( psa_key_lifetime_t lifetime )
+{
+    return( PSA_KEY_LIFETIME_GET_LOCATION( lifetime ) !=
+            PSA_KEY_LOCATION_LOCAL_STORAGE );
+}
+#endif
+
+static int check_key_attributes_sanity( mbedtls_svc_key_id_t key )
+{
+    int ok = 0;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_lifetime_t lifetime;
+    mbedtls_svc_key_id_t id;
+    psa_key_type_t type;
+    size_t bits;
+
+    PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
+    lifetime = psa_get_key_lifetime( &attributes );
+    id = psa_get_key_id( &attributes );
+    type = psa_get_key_type( &attributes );
+    bits = psa_get_key_bits( &attributes );
+
+    /* Persistence */
+    if( PSA_KEY_LIFETIME_IS_VOLATILE( lifetime ) )
+    {
+        TEST_ASSERT(
+            ( PSA_KEY_ID_VOLATILE_MIN <=
+              MBEDTLS_SVC_KEY_ID_GET_KEY_ID( id ) ) &&
+            ( MBEDTLS_SVC_KEY_ID_GET_KEY_ID( id ) <=
+              PSA_KEY_ID_VOLATILE_MAX ) );
+    }
+    else
+    {
+        TEST_ASSERT(
+            ( PSA_KEY_ID_USER_MIN <= MBEDTLS_SVC_KEY_ID_GET_KEY_ID( id ) ) &&
+            ( MBEDTLS_SVC_KEY_ID_GET_KEY_ID( id ) <= PSA_KEY_ID_USER_MAX ) );
+    }
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+    /* randomly-generated 64-bit constant, should never appear in test data */
+    psa_key_slot_number_t slot_number = 0xec94d4a5058a1a21;
+    psa_status_t status = psa_get_key_slot_number( &attributes, &slot_number );
+    if( lifetime_is_dynamic_secure_element( lifetime ) )
+    {
+        /* Mbed Crypto currently always exposes the slot number to
+         * applications. This is not mandated by the PSA specification
+         * and may change in future versions. */
+        TEST_EQUAL( status, 0 );
+        TEST_ASSERT( slot_number != 0xec94d4a5058a1a21 );
+    }
+    else
+    {
+        TEST_EQUAL( status, PSA_ERROR_INVALID_ARGUMENT );
+    }
+#endif
+
+    /* Type and size */
+    TEST_ASSERT( type != 0 );
+    TEST_ASSERT( bits != 0 );
+    TEST_ASSERT( bits <= PSA_MAX_KEY_BITS );
+    if( PSA_KEY_TYPE_IS_UNSTRUCTURED( type ) )
+        TEST_ASSERT( bits % 8 == 0 );
+
+    /* MAX macros concerning specific key types */
+    if( PSA_KEY_TYPE_IS_ECC( type ) )
+        TEST_ASSERT( bits <= PSA_VENDOR_ECC_MAX_CURVE_BITS );
+    else if( PSA_KEY_TYPE_IS_RSA( type ) )
+        TEST_ASSERT( bits <= PSA_VENDOR_RSA_MAX_KEY_BITS );
+    TEST_ASSERT( PSA_BLOCK_CIPHER_BLOCK_LENGTH( type ) <= PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE );
+
+    ok = 1;
+
+exit:
+    /*
+     * Key attributes may have been returned by psa_get_key_attributes()
+     * thus reset them as required.
+     */
+    psa_reset_key_attributes( &attributes );
+
+    return( ok );
+}
+
+static int exercise_mac_key( mbedtls_svc_key_id_t key,
+                             psa_key_usage_t usage,
+                             psa_algorithm_t alg )
+{
+    psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT;
+    const unsigned char input[] = "foo";
+    unsigned char mac[PSA_MAC_MAX_SIZE] = {0};
+    size_t mac_length = sizeof( mac );
+
+    if( usage & PSA_KEY_USAGE_SIGN_HASH )
+    {
+        PSA_ASSERT( psa_mac_sign_setup( &operation, key, alg ) );
+        PSA_ASSERT( psa_mac_update( &operation,
+                                    input, sizeof( input ) ) );
+        PSA_ASSERT( psa_mac_sign_finish( &operation,
+                                         mac, sizeof( mac ),
+                                         &mac_length ) );
+    }
+
+    if( usage & PSA_KEY_USAGE_VERIFY_HASH )
+    {
+        psa_status_t verify_status =
+            ( usage & PSA_KEY_USAGE_SIGN_HASH ?
+              PSA_SUCCESS :
+              PSA_ERROR_INVALID_SIGNATURE );
+        PSA_ASSERT( psa_mac_verify_setup( &operation, key, alg ) );
+        PSA_ASSERT( psa_mac_update( &operation,
+                                    input, sizeof( input ) ) );
+        TEST_EQUAL( psa_mac_verify_finish( &operation, mac, mac_length ),
+                    verify_status );
+    }
+
+    return( 1 );
+
+exit:
+    psa_mac_abort( &operation );
+    return( 0 );
+}
+
+static int exercise_cipher_key( mbedtls_svc_key_id_t key,
+                                psa_key_usage_t usage,
+                                psa_algorithm_t alg )
+{
+    psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
+    unsigned char iv[16] = {0};
+    size_t iv_length = sizeof( iv );
+    const unsigned char plaintext[16] = "Hello, world...";
+    unsigned char ciphertext[32] = "(wabblewebblewibblewobblewubble)";
+    size_t ciphertext_length = sizeof( ciphertext );
+    unsigned char decrypted[sizeof( ciphertext )];
+    size_t part_length;
+
+    if( usage & PSA_KEY_USAGE_ENCRYPT )
+    {
+        PSA_ASSERT( psa_cipher_encrypt_setup( &operation, key, alg ) );
+        PSA_ASSERT( psa_cipher_generate_iv( &operation,
+                                            iv, sizeof( iv ),
+                                            &iv_length ) );
+        PSA_ASSERT( psa_cipher_update( &operation,
+                                       plaintext, sizeof( plaintext ),
+                                       ciphertext, sizeof( ciphertext ),
+                                       &ciphertext_length ) );
+        PSA_ASSERT( psa_cipher_finish( &operation,
+                                       ciphertext + ciphertext_length,
+                                       sizeof( ciphertext ) - ciphertext_length,
+                                       &part_length ) );
+        ciphertext_length += part_length;
+    }
+
+    if( usage & PSA_KEY_USAGE_DECRYPT )
+    {
+        psa_status_t status;
+        int maybe_invalid_padding = 0;
+        if( ! ( usage & PSA_KEY_USAGE_ENCRYPT ) )
+        {
+            psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+            PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
+            /* This should be PSA_CIPHER_GET_IV_SIZE but the API doesn't
+             * have this macro yet. */
+            iv_length = PSA_BLOCK_CIPHER_BLOCK_LENGTH(
+                psa_get_key_type( &attributes ) );
+            maybe_invalid_padding = ! PSA_ALG_IS_STREAM_CIPHER( alg );
+            psa_reset_key_attributes( &attributes );
+        }
+        PSA_ASSERT( psa_cipher_decrypt_setup( &operation, key, alg ) );
+        PSA_ASSERT( psa_cipher_set_iv( &operation,
+                                       iv, iv_length ) );
+        PSA_ASSERT( psa_cipher_update( &operation,
+                                       ciphertext, ciphertext_length,
+                                       decrypted, sizeof( decrypted ),
+                                       &part_length ) );
+        status = psa_cipher_finish( &operation,
+                                    decrypted + part_length,
+                                    sizeof( decrypted ) - part_length,
+                                    &part_length );
+        /* For a stream cipher, all inputs are valid. For a block cipher,
+         * if the input is some aribtrary data rather than an actual
+         ciphertext, a padding error is likely.  */
+        if( maybe_invalid_padding )
+            TEST_ASSERT( status == PSA_SUCCESS ||
+                         status == PSA_ERROR_INVALID_PADDING );
+        else
+            PSA_ASSERT( status );
+    }
+
+    return( 1 );
+
+exit:
+    psa_cipher_abort( &operation );
+    return( 0 );
+}
+
+static int exercise_aead_key( mbedtls_svc_key_id_t key,
+                              psa_key_usage_t usage,
+                              psa_algorithm_t alg )
+{
+    unsigned char nonce[16] = {0};
+    size_t nonce_length = sizeof( nonce );
+    unsigned char plaintext[16] = "Hello, world...";
+    unsigned char ciphertext[48] = "(wabblewebblewibblewobblewubble)";
+    size_t ciphertext_length = sizeof( ciphertext );
+    size_t plaintext_length = sizeof( ciphertext );
+
+    /* Default IV length for AES-GCM is 12 bytes */
+    if( PSA_ALG_AEAD_WITH_SHORTENED_TAG( alg, 0 ) ==
+        PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_GCM, 0 ) )
+    {
+        nonce_length = 12;
+    }
+
+    if( usage & PSA_KEY_USAGE_ENCRYPT )
+    {
+        PSA_ASSERT( psa_aead_encrypt( key, alg,
+                                      nonce, nonce_length,
+                                      NULL, 0,
+                                      plaintext, sizeof( plaintext ),
+                                      ciphertext, sizeof( ciphertext ),
+                                      &ciphertext_length ) );
+    }
+
+    if( usage & PSA_KEY_USAGE_DECRYPT )
+    {
+        psa_status_t verify_status =
+            ( usage & PSA_KEY_USAGE_ENCRYPT ?
+              PSA_SUCCESS :
+              PSA_ERROR_INVALID_SIGNATURE );
+        TEST_EQUAL( psa_aead_decrypt( key, alg,
+                                      nonce, nonce_length,
+                                      NULL, 0,
+                                      ciphertext, ciphertext_length,
+                                      plaintext, sizeof( plaintext ),
+                                      &plaintext_length ),
+                    verify_status );
+    }
+
+    return( 1 );
+
+exit:
+    return( 0 );
+}
+
+static int exercise_signature_key( mbedtls_svc_key_id_t key,
+                                   psa_key_usage_t usage,
+                                   psa_algorithm_t 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_HASH_AND_SIGN( 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_ASSERT( ! "No hash algorithm for hash-and-sign testing" );
+#endif
+    }
+
+    if( usage & PSA_KEY_USAGE_SIGN_HASH )
+    {
+        /* Some algorithms require the payload to have the size of
+         * the hash encoded in the algorithm. Use this input size
+         * even for algorithms that allow other input sizes. */
+        if( hash_alg != 0 )
+            payload_length = PSA_HASH_LENGTH( hash_alg );
+        PSA_ASSERT( psa_sign_hash( key, alg,
+                                   payload, payload_length,
+                                   signature, sizeof( signature ),
+                                   &signature_length ) );
+    }
+
+    if( usage & PSA_KEY_USAGE_VERIFY_HASH )
+    {
+        psa_status_t verify_status =
+            ( usage & PSA_KEY_USAGE_SIGN_HASH ?
+              PSA_SUCCESS :
+              PSA_ERROR_INVALID_SIGNATURE );
+        TEST_EQUAL( psa_verify_hash( key, alg,
+                                     payload, payload_length,
+                                     signature, signature_length ),
+                    verify_status );
+    }
+
+    return( 1 );
+
+exit:
+    return( 0 );
+}
+
+static int exercise_asymmetric_encryption_key( mbedtls_svc_key_id_t key,
+                                               psa_key_usage_t usage,
+                                               psa_algorithm_t alg )
+{
+    unsigned char plaintext[256] = "Hello, world...";
+    unsigned char ciphertext[256] = "(wabblewebblewibblewobblewubble)";
+    size_t ciphertext_length = sizeof( ciphertext );
+    size_t plaintext_length = 16;
+
+    if( usage & PSA_KEY_USAGE_ENCRYPT )
+    {
+        PSA_ASSERT( psa_asymmetric_encrypt( key, alg,
+                                            plaintext, plaintext_length,
+                                            NULL, 0,
+                                            ciphertext, sizeof( ciphertext ),
+                                            &ciphertext_length ) );
+    }
+
+    if( usage & PSA_KEY_USAGE_DECRYPT )
+    {
+        psa_status_t status =
+            psa_asymmetric_decrypt( key, alg,
+                                    ciphertext, ciphertext_length,
+                                    NULL, 0,
+                                    plaintext, sizeof( plaintext ),
+                                    &plaintext_length );
+        TEST_ASSERT( status == PSA_SUCCESS ||
+                     ( ( usage & PSA_KEY_USAGE_ENCRYPT ) == 0 &&
+                       ( status == PSA_ERROR_INVALID_ARGUMENT ||
+                         status == PSA_ERROR_INVALID_PADDING ) ) );
+    }
+
+    return( 1 );
+
+exit:
+    return( 0 );
+}
+
+int mbedtls_test_psa_setup_key_derivation_wrap(
+    psa_key_derivation_operation_t* operation,
+    mbedtls_svc_key_id_t key,
+    psa_algorithm_t alg,
+    const unsigned char* input1, size_t input1_length,
+    const unsigned char* input2, size_t input2_length,
+    size_t capacity )
+{
+    PSA_ASSERT( psa_key_derivation_setup( operation, alg ) );
+    if( PSA_ALG_IS_HKDF( alg ) )
+    {
+        PSA_ASSERT( psa_key_derivation_input_bytes( operation,
+                                                    PSA_KEY_DERIVATION_INPUT_SALT,
+                                                    input1, input1_length ) );
+        PSA_ASSERT( psa_key_derivation_input_key( operation,
+                                                  PSA_KEY_DERIVATION_INPUT_SECRET,
+                                                  key ) );
+        PSA_ASSERT( psa_key_derivation_input_bytes( operation,
+                                                    PSA_KEY_DERIVATION_INPUT_INFO,
+                                                    input2,
+                                                    input2_length ) );
+    }
+    else if( PSA_ALG_IS_TLS12_PRF( alg ) ||
+             PSA_ALG_IS_TLS12_PSK_TO_MS( alg ) )
+    {
+        PSA_ASSERT( psa_key_derivation_input_bytes( operation,
+                                                    PSA_KEY_DERIVATION_INPUT_SEED,
+                                                    input1, input1_length ) );
+        PSA_ASSERT( psa_key_derivation_input_key( operation,
+                                                  PSA_KEY_DERIVATION_INPUT_SECRET,
+                                                  key ) );
+        PSA_ASSERT( psa_key_derivation_input_bytes( operation,
+                                                    PSA_KEY_DERIVATION_INPUT_LABEL,
+                                                    input2, input2_length ) );
+    }
+    else
+    {
+        TEST_ASSERT( ! "Key derivation algorithm not supported" );
+    }
+
+    if( capacity != SIZE_MAX )
+        PSA_ASSERT( psa_key_derivation_set_capacity( operation, capacity ) );
+
+    return( 1 );
+
+exit:
+    return( 0 );
+}
+
+
+static int exercise_key_derivation_key( mbedtls_svc_key_id_t key,
+                                        psa_key_usage_t usage,
+                                        psa_algorithm_t alg )
+{
+    psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT;
+    unsigned char input1[] = "Input 1";
+    size_t input1_length = sizeof( input1 );
+    unsigned char input2[] = "Input 2";
+    size_t input2_length = sizeof( input2 );
+    unsigned char output[1];
+    size_t capacity = sizeof( output );
+
+    if( usage & PSA_KEY_USAGE_DERIVE )
+    {
+        if( !mbedtls_test_psa_setup_key_derivation_wrap( &operation, key, alg,
+                                                         input1, input1_length,
+                                                         input2, input2_length,
+                                                         capacity ) )
+            goto exit;
+
+        PSA_ASSERT( psa_key_derivation_output_bytes( &operation,
+                                                     output,
+                                                     capacity ) );
+        PSA_ASSERT( psa_key_derivation_abort( &operation ) );
+    }
+
+    return( 1 );
+
+exit:
+    return( 0 );
+}
+
+/* We need two keys to exercise key agreement. Exercise the
+ * private key against its own public key. */
+psa_status_t mbedtls_test_psa_key_agreement_with_self(
+    psa_key_derivation_operation_t *operation,
+    mbedtls_svc_key_id_t key )
+{
+    psa_key_type_t private_key_type;
+    psa_key_type_t public_key_type;
+    size_t key_bits;
+    uint8_t *public_key = NULL;
+    size_t public_key_length;
+    /* Return GENERIC_ERROR if something other than the final call to
+     * psa_key_derivation_key_agreement fails. This isn't fully satisfactory,
+     * but it's good enough: callers will report it as a failed test anyway. */
+    psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+    PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
+    private_key_type = psa_get_key_type( &attributes );
+    key_bits = psa_get_key_bits( &attributes );
+    public_key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR( private_key_type );
+    public_key_length = PSA_EXPORT_KEY_OUTPUT_SIZE( public_key_type, key_bits );
+    ASSERT_ALLOC( public_key, public_key_length );
+    PSA_ASSERT( psa_export_public_key( key, public_key, public_key_length,
+                                       &public_key_length ) );
+
+    status = psa_key_derivation_key_agreement(
+        operation, PSA_KEY_DERIVATION_INPUT_SECRET, key,
+        public_key, public_key_length );
+exit:
+    /*
+     * Key attributes may have been returned by psa_get_key_attributes()
+     * thus reset them as required.
+     */
+    psa_reset_key_attributes( &attributes );
+
+    mbedtls_free( public_key );
+    return( status );
+}
+
+/* We need two keys to exercise key agreement. Exercise the
+ * private key against its own public key. */
+psa_status_t mbedtls_test_psa_raw_key_agreement_with_self(
+    psa_algorithm_t alg,
+    mbedtls_svc_key_id_t key )
+{
+    psa_key_type_t private_key_type;
+    psa_key_type_t public_key_type;
+    size_t key_bits;
+    uint8_t *public_key = NULL;
+    size_t public_key_length;
+    uint8_t output[1024];
+    size_t output_length;
+    /* Return GENERIC_ERROR if something other than the final call to
+     * psa_key_derivation_key_agreement fails. This isn't fully satisfactory,
+     * but it's good enough: callers will report it as a failed test anyway. */
+    psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+    PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
+    private_key_type = psa_get_key_type( &attributes );
+    key_bits = psa_get_key_bits( &attributes );
+    public_key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR( private_key_type );
+    public_key_length = PSA_EXPORT_KEY_OUTPUT_SIZE( public_key_type, key_bits );
+    ASSERT_ALLOC( public_key, public_key_length );
+    PSA_ASSERT( psa_export_public_key( key,
+                                       public_key, public_key_length,
+                                       &public_key_length ) );
+
+    status = psa_raw_key_agreement( alg, key,
+                                    public_key, public_key_length,
+                                    output, sizeof( output ), &output_length );
+exit:
+    /*
+     * Key attributes may have been returned by psa_get_key_attributes()
+     * thus reset them as required.
+     */
+    psa_reset_key_attributes( &attributes );
+
+    mbedtls_free( public_key );
+    return( status );
+}
+
+static int exercise_raw_key_agreement_key( mbedtls_svc_key_id_t key,
+                                           psa_key_usage_t usage,
+                                           psa_algorithm_t alg )
+{
+    int ok = 0;
+
+    if( usage & PSA_KEY_USAGE_DERIVE )
+    {
+        /* We need two keys to exercise key agreement. Exercise the
+         * private key against its own public key. */
+        PSA_ASSERT( mbedtls_test_psa_raw_key_agreement_with_self( alg, key ) );
+    }
+    ok = 1;
+
+exit:
+    return( ok );
+}
+
+static int exercise_key_agreement_key( mbedtls_svc_key_id_t key,
+                                       psa_key_usage_t usage,
+                                       psa_algorithm_t alg )
+{
+    psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT;
+    unsigned char output[1];
+    int ok = 0;
+
+    if( usage & PSA_KEY_USAGE_DERIVE )
+    {
+        /* We need two keys to exercise key agreement. Exercise the
+         * private key against its own public key. */
+        PSA_ASSERT( psa_key_derivation_setup( &operation, alg ) );
+        PSA_ASSERT( mbedtls_test_psa_key_agreement_with_self( &operation, key ) );
+        PSA_ASSERT( psa_key_derivation_output_bytes( &operation,
+                                                     output,
+                                                     sizeof( output ) ) );
+        PSA_ASSERT( psa_key_derivation_abort( &operation ) );
+    }
+    ok = 1;
+
+exit:
+    return( ok );
+}
+
+int mbedtls_test_psa_exported_key_sanity_check(
+    psa_key_type_t type, size_t bits,
+    const uint8_t *exported, size_t exported_length )
+{
+    TEST_ASSERT( exported_length <= PSA_EXPORT_KEY_OUTPUT_SIZE( type, bits ) );
+
+    if( PSA_KEY_TYPE_IS_UNSTRUCTURED( type ) )
+        TEST_EQUAL( exported_length, PSA_BITS_TO_BYTES( bits ) );
+    else
+
+#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_PK_PARSE_C)
+    if( type == PSA_KEY_TYPE_RSA_KEY_PAIR )
+    {
+        uint8_t *p = (uint8_t*) exported;
+        const uint8_t *end = exported + exported_length;
+        size_t len;
+        /*   RSAPrivateKey ::= SEQUENCE {
+         *       version             INTEGER,  -- must be 0
+         *       modulus             INTEGER,  -- n
+         *       publicExponent      INTEGER,  -- e
+         *       privateExponent     INTEGER,  -- d
+         *       prime1              INTEGER,  -- p
+         *       prime2              INTEGER,  -- q
+         *       exponent1           INTEGER,  -- d mod (p-1)
+         *       exponent2           INTEGER,  -- d mod (q-1)
+         *       coefficient         INTEGER,  -- (inverse of q) mod p
+         *   }
+         */
+        TEST_EQUAL( mbedtls_asn1_get_tag( &p, end, &len,
+                                          MBEDTLS_ASN1_SEQUENCE |
+                                          MBEDTLS_ASN1_CONSTRUCTED ), 0 );
+        TEST_EQUAL( p + len, end );
+        if( ! mbedtls_test_asn1_skip_integer( &p, end, 0, 0, 0 ) )
+            goto exit;
+        if( ! mbedtls_test_asn1_skip_integer( &p, end, bits, bits, 1 ) )
+            goto exit;
+        if( ! mbedtls_test_asn1_skip_integer( &p, end, 2, bits, 1 ) )
+            goto exit;
+        /* Require d to be at least half the size of n. */
+        if( ! mbedtls_test_asn1_skip_integer( &p, end, bits / 2, bits, 1 ) )
+            goto exit;
+        /* Require p and q to be at most half the size of n, rounded up. */
+        if( ! mbedtls_test_asn1_skip_integer( &p, end, bits / 2, bits / 2 + 1, 1 ) )
+            goto exit;
+        if( ! mbedtls_test_asn1_skip_integer( &p, end, bits / 2, bits / 2 + 1, 1 ) )
+            goto exit;
+        if( ! mbedtls_test_asn1_skip_integer( &p, end, 1, bits / 2 + 1, 0 ) )
+            goto exit;
+        if( ! mbedtls_test_asn1_skip_integer( &p, end, 1, bits / 2 + 1, 0 ) )
+            goto exit;
+        if( ! mbedtls_test_asn1_skip_integer( &p, end, 1, bits / 2 + 1, 0 ) )
+            goto exit;
+        TEST_EQUAL( p, end );
+    }
+    else
+#endif /* MBEDTLS_RSA_C */
+
+#if defined(MBEDTLS_ECP_C)
+    if( PSA_KEY_TYPE_IS_ECC_KEY_PAIR( type ) )
+    {
+        /* Just the secret value */
+        TEST_EQUAL( exported_length, PSA_BITS_TO_BYTES( bits ) );
+    }
+    else
+#endif /* MBEDTLS_ECP_C */
+
+#if defined(MBEDTLS_RSA_C)
+    if( type == PSA_KEY_TYPE_RSA_PUBLIC_KEY )
+    {
+        uint8_t *p = (uint8_t*) exported;
+        const uint8_t *end = exported + exported_length;
+        size_t len;
+        /*   RSAPublicKey ::= SEQUENCE {
+         *      modulus            INTEGER,    -- n
+         *      publicExponent     INTEGER  }  -- e
+         */
+        TEST_EQUAL( mbedtls_asn1_get_tag( &p, end, &len,
+                                          MBEDTLS_ASN1_SEQUENCE |
+                                          MBEDTLS_ASN1_CONSTRUCTED ),
+                    0 );
+        TEST_EQUAL( p + len, end );
+        if( ! mbedtls_test_asn1_skip_integer( &p, end, bits, bits, 1 ) )
+            goto exit;
+        if( ! mbedtls_test_asn1_skip_integer( &p, end, 2, bits, 1 ) )
+            goto exit;
+        TEST_EQUAL( p, end );
+    }
+    else
+#endif /* MBEDTLS_RSA_C */
+
+#if defined(MBEDTLS_ECP_C)
+    if( PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY( type ) )
+    {
+        if( PSA_KEY_TYPE_ECC_GET_FAMILY( type ) == PSA_ECC_FAMILY_MONTGOMERY )
+        {
+            /* The representation of an ECC Montgomery public key is
+             * the raw compressed point */
+             TEST_EQUAL( PSA_BITS_TO_BYTES( bits ), exported_length );
+        }
+        else
+        {
+            /* The representation of an ECC Weierstrass public key is:
+             *      - The byte 0x04;
+             *      - `x_P` as a `ceiling(m/8)`-byte string, big-endian;
+             *      - `y_P` as a `ceiling(m/8)`-byte string, big-endian;
+             *      - where m is the bit size associated with the curve.
+             */
+            TEST_EQUAL( 1 + 2 * PSA_BITS_TO_BYTES( bits ), exported_length );
+            TEST_EQUAL( exported[0], 4 );
+        }
+    }
+    else
+#endif /* MBEDTLS_ECP_C */
+
+    {
+        TEST_ASSERT( ! "Sanity check not implemented for this key type" );
+    }
+
+#if defined(MBEDTLS_DES_C)
+    if( type == PSA_KEY_TYPE_DES )
+    {
+        /* Check the parity bits. */
+        unsigned i;
+        for( i = 0; i < bits / 8; i++ )
+        {
+            unsigned bit_count = 0;
+            unsigned m;
+            for( m = 1; m <= 0x100; m <<= 1 )
+            {
+                if( exported[i] & m )
+                    ++bit_count;
+            }
+            TEST_ASSERT( bit_count % 2 != 0 );
+        }
+    }
+#endif
+
+    return( 1 );
+
+exit:
+    return( 0 );
+}
+
+static int exercise_export_key( mbedtls_svc_key_id_t key,
+                                psa_key_usage_t usage )
+{
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    uint8_t *exported = NULL;
+    size_t exported_size = 0;
+    size_t exported_length = 0;
+    int ok = 0;
+
+    PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
+
+    exported_size = PSA_EXPORT_KEY_OUTPUT_SIZE(
+                        psa_get_key_type( &attributes ),
+                        psa_get_key_bits( &attributes ) );
+    ASSERT_ALLOC( exported, exported_size );
+
+    if( ( usage & PSA_KEY_USAGE_EXPORT ) == 0 &&
+        ! PSA_KEY_TYPE_IS_PUBLIC_KEY( psa_get_key_type( &attributes ) ) )
+    {
+        TEST_EQUAL( psa_export_key( key, exported,
+                                    exported_size, &exported_length ),
+                    PSA_ERROR_NOT_PERMITTED );
+        ok = 1;
+        goto exit;
+    }
+
+    PSA_ASSERT( psa_export_key( key,
+                                exported, exported_size,
+                                &exported_length ) );
+    ok = mbedtls_test_psa_exported_key_sanity_check(
+        psa_get_key_type( &attributes ), psa_get_key_bits( &attributes ),
+        exported, exported_length );
+
+exit:
+    /*
+     * Key attributes may have been returned by psa_get_key_attributes()
+     * thus reset them as required.
+     */
+    psa_reset_key_attributes( &attributes );
+
+    mbedtls_free( exported );
+    return( ok );
+}
+
+static int exercise_export_public_key( mbedtls_svc_key_id_t key )
+{
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_type_t public_type;
+    uint8_t *exported = NULL;
+    size_t exported_size = 0;
+    size_t exported_length = 0;
+    int ok = 0;
+
+    PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
+    if( ! PSA_KEY_TYPE_IS_ASYMMETRIC( psa_get_key_type( &attributes ) ) )
+    {
+        exported_size = PSA_EXPORT_KEY_OUTPUT_SIZE(
+                            psa_get_key_type( &attributes ),
+                            psa_get_key_bits( &attributes ) );
+        ASSERT_ALLOC( exported, exported_size );
+
+        TEST_EQUAL( psa_export_public_key( key, exported,
+                                           exported_size, &exported_length ),
+                    PSA_ERROR_INVALID_ARGUMENT );
+        ok = 1;
+        goto exit;
+    }
+
+    public_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(
+        psa_get_key_type( &attributes ) );
+    exported_size = PSA_EXPORT_KEY_OUTPUT_SIZE( public_type,
+                                                psa_get_key_bits( &attributes ) );
+    ASSERT_ALLOC( exported, exported_size );
+
+    PSA_ASSERT( psa_export_public_key( key,
+                                       exported, exported_size,
+                                       &exported_length ) );
+    ok = mbedtls_test_psa_exported_key_sanity_check(
+        public_type, psa_get_key_bits( &attributes ),
+        exported, exported_length );
+
+exit:
+    /*
+     * Key attributes may have been returned by psa_get_key_attributes()
+     * thus reset them as required.
+     */
+    psa_reset_key_attributes( &attributes );
+
+    mbedtls_free( exported );
+    return( ok );
+}
+
+int mbedtls_test_psa_exercise_key( mbedtls_svc_key_id_t key,
+                                   psa_key_usage_t usage,
+                                   psa_algorithm_t alg )
+{
+    int ok = 0;
+
+    if( ! check_key_attributes_sanity( key ) )
+        return( 0 );
+
+    if( alg == 0 )
+        ok = 1; /* If no algorihm, do nothing (used for raw data "keys"). */
+    else if( PSA_ALG_IS_MAC( alg ) )
+        ok = exercise_mac_key( key, usage, alg );
+    else if( PSA_ALG_IS_CIPHER( alg ) )
+        ok = exercise_cipher_key( key, usage, alg );
+    else if( PSA_ALG_IS_AEAD( alg ) )
+        ok = exercise_aead_key( key, usage, alg );
+    else if( PSA_ALG_IS_SIGN( alg ) )
+        ok = exercise_signature_key( key, usage, alg );
+    else if( PSA_ALG_IS_ASYMMETRIC_ENCRYPTION( alg ) )
+        ok = exercise_asymmetric_encryption_key( key, usage, alg );
+    else if( PSA_ALG_IS_KEY_DERIVATION( alg ) )
+        ok = exercise_key_derivation_key( key, usage, alg );
+    else if( PSA_ALG_IS_RAW_KEY_AGREEMENT( alg ) )
+        ok = exercise_raw_key_agreement_key( key, usage, alg );
+    else if( PSA_ALG_IS_KEY_AGREEMENT( alg ) )
+        ok = exercise_key_agreement_key( key, usage, alg );
+    else
+        TEST_ASSERT( ! "No code to exercise this category of algorithm" );
+
+    ok = ok && exercise_export_key( key, usage );
+    ok = ok && exercise_export_public_key( key );
+
+exit:
+    return( ok );
+}
+
+psa_key_usage_t mbedtls_test_psa_usage_to_exercise( psa_key_type_t type,
+                                                    psa_algorithm_t alg )
+{
+    if( PSA_ALG_IS_MAC( alg ) || PSA_ALG_IS_SIGN( alg ) )
+    {
+        return( PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) ?
+                PSA_KEY_USAGE_VERIFY_HASH :
+                PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH );
+    }
+    else if( PSA_ALG_IS_CIPHER( alg ) || PSA_ALG_IS_AEAD( alg ) ||
+             PSA_ALG_IS_ASYMMETRIC_ENCRYPTION( alg ) )
+    {
+        return( PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) ?
+                PSA_KEY_USAGE_ENCRYPT :
+                PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT );
+    }
+    else if( PSA_ALG_IS_KEY_DERIVATION( alg ) ||
+             PSA_ALG_IS_KEY_AGREEMENT( alg ) )
+    {
+        return( PSA_KEY_USAGE_DERIVE );
+    }
+    else
+    {
+        return( 0 );
+    }
+
+}
+
+#endif /* MBEDTLS_PSA_CRYPTO_C */
diff --git a/tests/src/threading_helpers.c b/tests/src/threading_helpers.c
new file mode 100644
index 0000000..ca91b79
--- /dev/null
+++ b/tests/src/threading_helpers.c
@@ -0,0 +1,223 @@
+/** Mutex usage verification framework. */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#include <test/helpers.h>
+#include <test/macros.h>
+
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+
+#include "mbedtls/threading.h"
+
+/** Mutex usage verification framework.
+ *
+ * The mutex usage verification code below aims to detect bad usage of
+ * Mbed TLS's mutex abstraction layer at runtime. Note that this is solely
+ * about the use of the mutex itself, not about checking whether the mutex
+ * correctly protects whatever it is supposed to protect.
+ *
+ * The normal usage of a mutex is:
+ * ```
+ * digraph mutex_states {
+ *   "UNINITIALIZED"; // the initial state
+ *   "IDLE";
+ *   "FREED";
+ *   "LOCKED";
+ *   "UNINITIALIZED" -> "IDLE" [label="init"];
+ *   "FREED" -> "IDLE" [label="init"];
+ *   "IDLE" -> "LOCKED" [label="lock"];
+ *   "LOCKED" -> "IDLE" [label="unlock"];
+ *   "IDLE" -> "FREED" [label="free"];
+ * }
+ * ```
+ *
+ * All bad transitions that can be unambiguously detected are reported.
+ * An attempt to use an uninitialized mutex cannot be detected in general
+ * since the memory content may happen to denote a valid state. For the same
+ * reason, a double init cannot be detected.
+ * All-bits-zero is the state of a freed mutex, which is distinct from an
+ * initialized mutex, so attempting to use zero-initialized memory as a mutex
+ * without calling the init function is detected.
+ *
+ * The framework attempts to detect missing calls to init and free by counting
+ * calls to init and free. If there are more calls to init than free, this
+ * means that a mutex is not being freed somewhere, which is a memory leak
+ * on platforms where a mutex consumes resources other than the
+ * mbedtls_threading_mutex_t object itself. If there are more calls to free
+ * than init, this indicates a missing init, which is likely to be detected
+ * by an attempt to lock the mutex as well. A limitation of this framework is
+ * that it cannot detect scenarios where there is exactly the same number of
+ * calls to init and free but the calls don't match. A bug like this is
+ * unlikely to happen uniformly throughout the whole test suite though.
+ *
+ * If an error is detected, this framework will report what happened and the
+ * test case will be marked as failed. Unfortunately, the error report cannot
+ * indicate the exact location of the problematic call. To locate the error,
+ * use a debugger and set a breakpoint on mbedtls_test_mutex_usage_error().
+ */
+enum value_of_mutex_is_valid_field
+{
+    /* Potential values for the is_valid field of mbedtls_threading_mutex_t.
+     * Note that MUTEX_FREED must be 0 and MUTEX_IDLE must be 1 for
+     * compatibility with threading_mutex_init_pthread() and
+     * threading_mutex_free_pthread(). MUTEX_LOCKED could be any nonzero
+     * value. */
+    MUTEX_FREED = 0, //!< Set by threading_mutex_free_pthread
+    MUTEX_IDLE = 1, //!< Set by threading_mutex_init_pthread and by our unlock
+    MUTEX_LOCKED = 2, //!< Set by our lock
+};
+
+typedef struct
+{
+    void (*init)( mbedtls_threading_mutex_t * );
+    void (*free)( mbedtls_threading_mutex_t * );
+    int (*lock)( mbedtls_threading_mutex_t * );
+    int (*unlock)( mbedtls_threading_mutex_t * );
+} mutex_functions_t;
+static mutex_functions_t mutex_functions;
+
+/** The total number of calls to mbedtls_mutex_init(), minus the total number
+ * of calls to mbedtls_mutex_free().
+ *
+ * Reset to 0 after each test case.
+ */
+static int live_mutexes;
+
+static void mbedtls_test_mutex_usage_error( mbedtls_threading_mutex_t *mutex,
+                                            const char *msg )
+{
+    (void) mutex;
+    if( mbedtls_test_info.mutex_usage_error == NULL )
+        mbedtls_test_info.mutex_usage_error = msg;
+    mbedtls_fprintf( stdout, "[mutex: %s] ", msg );
+    /* Don't mark the test as failed yet. This way, if the test fails later
+     * for a functional reason, the test framework will report the message
+     * and location for this functional reason. If the test passes,
+     * mbedtls_test_mutex_usage_check() will mark it as failed. */
+}
+
+static void mbedtls_test_wrap_mutex_init( mbedtls_threading_mutex_t *mutex )
+{
+    mutex_functions.init( mutex );
+    if( mutex->is_valid )
+        ++live_mutexes;
+}
+
+static void mbedtls_test_wrap_mutex_free( mbedtls_threading_mutex_t *mutex )
+{
+    switch( mutex->is_valid )
+    {
+        case MUTEX_FREED:
+            mbedtls_test_mutex_usage_error( mutex, "free without init or double free" );
+            break;
+        case MUTEX_IDLE:
+            /* Do nothing. The underlying free function will reset is_valid
+             * to 0. */
+            break;
+        case MUTEX_LOCKED:
+            mbedtls_test_mutex_usage_error( mutex, "free without unlock" );
+            break;
+        default:
+            mbedtls_test_mutex_usage_error( mutex, "corrupted state" );
+            break;
+    }
+    if( mutex->is_valid )
+        --live_mutexes;
+    mutex_functions.free( mutex );
+}
+
+static int mbedtls_test_wrap_mutex_lock( mbedtls_threading_mutex_t *mutex )
+{
+    int ret = mutex_functions.lock( mutex );
+    switch( mutex->is_valid )
+    {
+        case MUTEX_FREED:
+            mbedtls_test_mutex_usage_error( mutex, "lock without init" );
+            break;
+        case MUTEX_IDLE:
+            if( ret == 0 )
+                mutex->is_valid = 2;
+            break;
+        case MUTEX_LOCKED:
+            mbedtls_test_mutex_usage_error( mutex, "double lock" );
+            break;
+        default:
+            mbedtls_test_mutex_usage_error( mutex, "corrupted state" );
+            break;
+    }
+    return( ret );
+}
+
+static int mbedtls_test_wrap_mutex_unlock( mbedtls_threading_mutex_t *mutex )
+{
+    int ret = mutex_functions.unlock( mutex );
+    switch( mutex->is_valid )
+    {
+        case MUTEX_FREED:
+            mbedtls_test_mutex_usage_error( mutex, "unlock without init" );
+            break;
+        case MUTEX_IDLE:
+            mbedtls_test_mutex_usage_error( mutex, "unlock without lock" );
+            break;
+        case MUTEX_LOCKED:
+            if( ret == 0 )
+                mutex->is_valid = MUTEX_IDLE;
+            break;
+        default:
+            mbedtls_test_mutex_usage_error( mutex, "corrupted state" );
+            break;
+    }
+    return( ret );
+}
+
+void mbedtls_test_mutex_usage_init( void )
+{
+    mutex_functions.init = mbedtls_mutex_init;
+    mutex_functions.free = mbedtls_mutex_free;
+    mutex_functions.lock = mbedtls_mutex_lock;
+    mutex_functions.unlock = mbedtls_mutex_unlock;
+    mbedtls_mutex_init = &mbedtls_test_wrap_mutex_init;
+    mbedtls_mutex_free = &mbedtls_test_wrap_mutex_free;
+    mbedtls_mutex_lock = &mbedtls_test_wrap_mutex_lock;
+    mbedtls_mutex_unlock = &mbedtls_test_wrap_mutex_unlock;
+}
+
+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;
+        if( mbedtls_test_info.mutex_usage_error == NULL )
+            mbedtls_test_info.mutex_usage_error = "missing free";
+    }
+    if( mbedtls_test_info.mutex_usage_error != NULL &&
+        mbedtls_test_info.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_info.mutex_usage_error = NULL;
+}
+
+#endif /* MBEDTLS_TEST_MUTEX_USAGE */
diff --git a/tests/suites/helpers.function b/tests/suites/helpers.function
index ebe2f06..91ad925 100644
--- a/tests/suites/helpers.function
+++ b/tests/suites/helpers.function
@@ -5,9 +5,7 @@
 #include <test/macros.h>
 #include <test/helpers.h>
 #include <test/random.h>
-#if defined(MBEDTLS_PSA_CRYPTO_C)
 #include <test/psa_crypto_helpers.h>
-#endif
 
 #include <stdlib.h>
 
diff --git a/tests/suites/host_test.function b/tests/suites/host_test.function
index 3138c33..d83d751 100644
--- a/tests/suites/host_test.function
+++ b/tests/suites/host_test.function
@@ -360,8 +360,6 @@
 /**
  * \brief       Tests snprintf implementation.
  *
- * \param none
- *
  * \return      0 for success else 1
  */
 static int run_test_snprintf( void )
@@ -428,8 +426,8 @@
  * \param unmet_dependencies         The array of unmet dependencies.
  * \param missing_unmet_dependencies Non-zero if there was a problem tracking
  *                                   all unmet dependencies, 0 otherwise.
- * \param ret                   The test dispatch status (DISPATCH_xxx).
- * \param mbedtls_test_info     A pointer to the test info structure.
+ * \param ret                        The test dispatch status (DISPATCH_xxx).
+ * \param info                       A pointer to the test info structure.
  */
 static void write_outcome_result( FILE *outcome_file,
                                   size_t unmet_dep_count,
@@ -536,6 +534,10 @@
     mbedtls_memory_buffer_alloc_init( alloc_buf, sizeof( alloc_buf ) );
 #endif
 
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+    mbedtls_test_mutex_usage_init( );
+#endif
+
     /*
      * The C standard doesn't guarantee that all-bits-0 is the representation
      * of a NULL pointer. We do however use that in our code for initializing
diff --git a/tests/suites/main_test.function b/tests/suites/main_test.function
index 57395ae..36a7d23 100644
--- a/tests/suites/main_test.function
+++ b/tests/suites/main_test.function
@@ -105,7 +105,7 @@
  *              Identifiers and check code is generated by script:
  *              $generator_script
  *
- * \param exp_id    Dependency identifier.
+ * \param dep_id    Dependency identifier.
  *
  * \return       DEPENDENCY_SUPPORTED if set else DEPENDENCY_NOT_SUPPORTED
  */
@@ -129,13 +129,17 @@
 /**
  * \brief       Function pointer type for test function wrappers.
  *
+ * A test function wrapper decodes the parameters and passes them to the
+ * underlying test function. Both the wrapper and the underlying function
+ * return void. Test wrappers assume that they are passed a suitable
+ * parameter array and do not perform any error detection.
  *
- * \param void **   Pointer to void pointers. Represents an array of test
- *                  function parameters.
- *
- * \return       void
+ * \param param_array   The array of parameters. Each element is a `void *`
+ *                      which the wrapper casts to the correct type and
+ *                      dereferences. Each wrapper function hard-codes the
+ *                      number and types of the parameters.
  */
-typedef void (*TestWrapper_t)( void ** );
+typedef void (*TestWrapper_t)( void **param_array );
 
 
 /**
@@ -158,8 +162,8 @@
  *               parameter failure callback, to be used. Calls to setjmp()
  *               can invalidate the state of any local auto variables.
  *
- * \param fp     Function pointer to the test function
- * \param params Parameters to pass
+ * \param fp     Function pointer to the test function.
+ * \param params Parameters to pass to the #TestWrapper_t wrapper function.
  *
  */
 void execute_function_ptr(TestWrapper_t fp, void **params)
@@ -188,12 +192,18 @@
 #else
     fp( params );
 #endif
+
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+    mbedtls_test_mutex_usage_check( );
+#endif /* MBEDTLS_TEST_MUTEX_USAGE */
 }
 
 /**
  * \brief        Dispatches test functions based on function index.
  *
- * \param exp_id    Test function index.
+ * \param func_idx    Test function index.
+ * \param params      The array of parameters to pass to the test function.
+ *                    It will be decoded by the #TestWrapper_t wrapper function.
  *
  * \return       DISPATCH_TEST_SUCCESS if found
  *               DISPATCH_TEST_FN_NOT_FOUND if not found
@@ -222,9 +232,10 @@
 
 
 /**
- * \brief       Checks if test function is supported
+ * \brief       Checks if test function is supported in this build-time
+ *              configuration.
  *
- * \param exp_id    Test function index.
+ * \param func_idx    Test function index.
  *
  * \return       DISPATCH_TEST_SUCCESS if found
  *               DISPATCH_TEST_FN_NOT_FOUND if not found
diff --git a/tests/suites/test_suite_ccm.function b/tests/suites/test_suite_ccm.function
index faa7e13..5a3726e 100644
--- a/tests/suites/test_suite_ccm.function
+++ b/tests/suites/test_suite_ccm.function
@@ -201,12 +201,11 @@
     unsigned char iv[13];
     unsigned char result[50];
     mbedtls_ccm_context ctx;
-    size_t i, iv_len, tag_len;
+    size_t iv_len, tag_len;
     int ret;
 
     mbedtls_ccm_init( &ctx );
 
-    memset( iv, 0x00, sizeof( iv ) );
     memset( result, 0x00, sizeof( result ) );
 
     if( sec_level % 4 == 0)
@@ -214,12 +213,10 @@
     else
         tag_len = 1 << ( sec_level % 4 + 1);
 
-    for( i = 0; i < source_address->len; i++ )
-        iv[i] = source_address->x[i];
-
-    for( i = 0; i < frame_counter->len; i++ )
-        iv[source_address->len + i] = frame_counter->x[i];
-
+    TEST_ASSERT( source_address->len == 8 );
+    TEST_ASSERT( frame_counter->len == 4 );
+    memcpy( iv, source_address->x, source_address->len );
+    memcpy( iv + source_address->len, frame_counter->x, frame_counter->len );
     iv[source_address->len + frame_counter->len] = sec_level;
     iv_len = sizeof( iv );
 
@@ -254,7 +251,7 @@
     unsigned char iv[13];
     unsigned char result[50];
     mbedtls_ccm_context ctx;
-    size_t i, iv_len, tag_len;
+    size_t iv_len, tag_len;
     int ret;
 
     mbedtls_ccm_init( &ctx );
@@ -267,12 +264,10 @@
     else
         tag_len = 1 << ( sec_level % 4 + 1);
 
-    for( i = 0; i < source_address->len; i++ )
-        iv[i] = source_address->x[i];
-
-    for( i = 0; i < frame_counter->len; i++ )
-        iv[source_address->len + i] = frame_counter->x[i];
-
+    TEST_ASSERT( source_address->len == 8 );
+    TEST_ASSERT( frame_counter->len == 4 );
+    memcpy( iv, source_address->x, source_address->len );
+    memcpy( iv + source_address->len, frame_counter->x, frame_counter->len );
     iv[source_address->len + frame_counter->len] = sec_level;
     iv_len = sizeof( iv );
 
diff --git a/tests/suites/test_suite_entropy.data b/tests/suites/test_suite_entropy.data
index b2d20b4..2ce01fa 100644
--- a/tests/suites/test_suite_entropy.data
+++ b/tests/suites/test_suite_entropy.data
@@ -1,3 +1,9 @@
+Entropy init-free-free
+entropy_init_free:0
+
+Entropy init-free-init-free
+entropy_init_free:1
+
 Create NV seed_file
 nv_seed_file_create:
 
diff --git a/tests/suites/test_suite_entropy.function b/tests/suites/test_suite_entropy.function
index d9ea441..ad9b5a4 100644
--- a/tests/suites/test_suite_entropy.function
+++ b/tests/suites/test_suite_entropy.function
@@ -134,6 +134,28 @@
  * END_DEPENDENCIES
  */
 
+/* BEGIN_CASE */
+void entropy_init_free( int reinit )
+{
+    mbedtls_entropy_context ctx;
+
+    /* Double free is not explicitly documented to work, but it is convenient
+     * to call mbedtls_entropy_free() unconditionally on an error path without
+     * checking whether it has already been called in the success path. */
+
+    mbedtls_entropy_init( &ctx );
+    mbedtls_entropy_free( &ctx );
+
+    if( reinit )
+        mbedtls_entropy_init( &ctx );
+    mbedtls_entropy_free( &ctx );
+
+    /* This test case always succeeds, functionally speaking. A plausible
+     * bug might trigger an invalid pointer dereference or a memory leak. */
+    goto exit;
+}
+/* END_CASE */
+
 /* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
 void entropy_seed_file( char * path, int ret )
 {
@@ -217,6 +239,9 @@
 
     for( j = len; j < sizeof( buf ); j++ )
         TEST_ASSERT( acc[j] == 0 );
+
+exit:
+    mbedtls_entropy_free( &ctx );
 }
 /* END_CASE */
 
diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function
index 577fb47..bc469b6 100644
--- a/tests/suites/test_suite_pk.function
+++ b/tests/suites/test_suite_pk.function
@@ -15,18 +15,6 @@
  * unconditionally (https://github.com/ARMmbed/mbedtls/issues/2023). */
 #include "psa/crypto.h"
 
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-#include "mbedtls/psa_util.h"
-#define PSA_INIT( ) PSA_ASSERT( psa_crypto_init( ) )
-#else
-/* Define empty macros so that we can use them in the preamble and teardown
- * of every test function that uses PSA conditionally based on
- * MBEDTLS_USE_PSA_CRYPTO. */
-#define PSA_INIT( ) ( (void) 0 )
-#undef PSA_DONE
-#define PSA_DONE( ) ( (void) 0 )
-#endif
-
 #define RSA_KEY_SIZE 512
 #define RSA_KEY_LEN   64
 
@@ -208,7 +196,7 @@
 
     mbedtls_pk_free( &pk ); /* redundant except upon error */
     mbedtls_pk_free( &pk2 );
-    PSA_DONE( );
+    USE_PSA_DONE( );
 }
 /* END_CASE */
 
@@ -770,7 +758,7 @@
     mbedtls_ecp_keypair *eckey;
 
     mbedtls_pk_init( &pk );
-    PSA_INIT( );
+    USE_PSA_INIT( );
 
     TEST_ASSERT( mbedtls_pk_setup( &pk, mbedtls_pk_info_from_type( type ) ) == 0 );
 
@@ -787,7 +775,7 @@
 
 exit:
     mbedtls_pk_free( &pk );
-    PSA_DONE( );
+    USE_PSA_DONE( );
 }
 /* END_CASE */
 
@@ -911,7 +899,7 @@
 #endif
 
     mbedtls_pk_init( &pk );
-    PSA_INIT( );
+    USE_PSA_INIT( );
 
     memset( hash, 0x2a, sizeof hash );
     memset( sig, 0, sizeof sig );
@@ -973,7 +961,7 @@
     mbedtls_pk_restart_free( rs_ctx );
 #endif
     mbedtls_pk_free( &pk );
-    PSA_DONE( );
+    USE_PSA_DONE( );
 }
 /* END_CASE */
 
@@ -1302,6 +1290,6 @@
     psa_reset_key_attributes( &attributes );
 
     mbedtls_pk_free( &pk );
-    PSA_DONE( );
+    USE_PSA_DONE( );
 }
 /* END_CASE */
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index 93f41b5..7ae6725 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -12,110 +12,13 @@
 #include "psa/crypto.h"
 #include "psa_crypto_slot_management.h"
 
+#include "test/asn1_helpers.h"
 #include "test/psa_crypto_helpers.h"
+#include "test/psa_exercise_key.h"
 
 /** An invalid export length that will never be set by psa_export_key(). */
 static const size_t INVALID_EXPORT_LENGTH = ~0U;
 
-/* A hash algorithm that is known to be supported.
- *
- * This is used in some smoke tests.
- */
-#if defined(PSA_WANT_ALG_MD2)
-#define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_MD2
-#elif defined(PSA_WANT_ALG_MD4)
-#define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_MD4
-#elif defined(PSA_WANT_ALG_MD5)
-#define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_MD5
-/* MBEDTLS_RIPEMD160_C 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)
-#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
-#elif defined(PSA_WANT_ALG_SHA_512)
-#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
-#else
-#undef KNOWN_SUPPORTED_HASH_ALG
-#endif
-
-/* A block cipher that is known to be supported.
- *
- * For simplicity's sake, stick to block ciphers with 16-byte blocks.
- */
-#if defined(MBEDTLS_AES_C)
-#define KNOWN_SUPPORTED_BLOCK_CIPHER PSA_KEY_TYPE_AES
-#elif defined(MBEDTLS_ARIA_C)
-#define KNOWN_SUPPORTED_BLOCK_CIPHER PSA_KEY_TYPE_ARIA
-#elif defined(MBEDTLS_CAMELLIA_C)
-#define KNOWN_SUPPORTED_BLOCK_CIPHER PSA_KEY_TYPE_CAMELLIA
-#undef KNOWN_SUPPORTED_BLOCK_CIPHER
-#endif
-
-/* A MAC mode that is known to be supported.
- *
- * It must either be HMAC with #KNOWN_SUPPORTED_HASH_ALG or
- * a block cipher-based MAC with #KNOWN_SUPPORTED_BLOCK_CIPHER.
- *
- * This is used in some smoke tests.
- */
-#if defined(KNOWN_SUPPORTED_HASH_ALG) && defined(PSA_WANT_ALG_HMAC)
-#define KNOWN_SUPPORTED_MAC_ALG ( PSA_ALG_HMAC( KNOWN_SUPPORTED_HASH_ALG ) )
-#define KNOWN_SUPPORTED_MAC_KEY_TYPE PSA_KEY_TYPE_HMAC
-#elif defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(MBEDTLS_CMAC_C)
-#define KNOWN_SUPPORTED_MAC_ALG PSA_ALG_CMAC
-#define KNOWN_SUPPORTED_MAC_KEY_TYPE KNOWN_SUPPORTED_BLOCK_CIPHER
-#else
-#undef KNOWN_SUPPORTED_MAC_ALG
-#undef KNOWN_SUPPORTED_MAC_KEY_TYPE
-#endif
-
-/* A cipher algorithm and key type that are known to be supported.
- *
- * This is used in some smoke tests.
- */
-#if defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(MBEDTLS_CIPHER_MODE_CTR)
-#define KNOWN_SUPPORTED_BLOCK_CIPHER_ALG PSA_ALG_CTR
-#elif defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(MBEDTLS_CIPHER_MODE_CBC)
-#define KNOWN_SUPPORTED_BLOCK_CIPHER_ALG PSA_ALG_CBC_NO_PADDING
-#elif defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(MBEDTLS_CIPHER_MODE_CFB)
-#define KNOWN_SUPPORTED_BLOCK_CIPHER_ALG PSA_ALG_CFB
-#elif defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(MBEDTLS_CIPHER_MODE_OFB)
-#define KNOWN_SUPPORTED_BLOCK_CIPHER_ALG PSA_ALG_OFB
-#else
-#undef KNOWN_SUPPORTED_BLOCK_CIPHER_ALG
-#endif
-#if defined(KNOWN_SUPPORTED_BLOCK_CIPHER_ALG)
-#define KNOWN_SUPPORTED_CIPHER_ALG KNOWN_SUPPORTED_BLOCK_CIPHER_ALG
-#define KNOWN_SUPPORTED_CIPHER_KEY_TYPE KNOWN_SUPPORTED_BLOCK_CIPHER
-#elif defined(MBEDTLS_RC4_C)
-#define KNOWN_SUPPORTED_CIPHER_ALG PSA_ALG_RC4
-#define KNOWN_SUPPORTED_CIPHER_KEY_TYPE PSA_KEY_TYPE_RC4
-#else
-#undef KNOWN_SUPPORTED_CIPHER_ALG
-#undef KNOWN_SUPPORTED_CIPHER_KEY_TYPE
-#endif
-
-#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
-int lifetime_is_dynamic_secure_element( psa_key_lifetime_t lifetime )
-{
-    return( PSA_KEY_LIFETIME_GET_LOCATION( lifetime ) !=
-            PSA_KEY_LOCATION_LOCAL_STORAGE );
-}
-#else
-int lifetime_is_secure_element( psa_key_lifetime_t lifetime )
-{
-    (void) lifetime;
-    return( 0 );
-}
-#endif
-
 /** Test if a buffer contains a constant byte value.
  *
  * `mem_is_char(buffer, c, size)` is true after `memset(buffer, c, size)`.
@@ -222,80 +125,6 @@
     return( len );
 }
 
-int check_key_attributes_sanity( mbedtls_svc_key_id_t key )
-{
-    int ok = 0;
-    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-    psa_key_lifetime_t lifetime;
-    mbedtls_svc_key_id_t id;
-    psa_key_type_t type;
-    psa_key_type_t bits;
-
-    PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
-    lifetime = psa_get_key_lifetime( &attributes );
-    id = psa_get_key_id( &attributes );
-    type = psa_get_key_type( &attributes );
-    bits = psa_get_key_bits( &attributes );
-
-    /* Persistence */
-    if( PSA_KEY_LIFETIME_IS_VOLATILE( lifetime ) )
-    {
-        TEST_ASSERT(
-            ( PSA_KEY_ID_VOLATILE_MIN <=
-              MBEDTLS_SVC_KEY_ID_GET_KEY_ID( id ) ) &&
-            ( MBEDTLS_SVC_KEY_ID_GET_KEY_ID( id ) <=
-              PSA_KEY_ID_VOLATILE_MAX ) );
-    }
-    else
-    {
-        TEST_ASSERT(
-            ( PSA_KEY_ID_USER_MIN <= MBEDTLS_SVC_KEY_ID_GET_KEY_ID( id ) ) &&
-            ( MBEDTLS_SVC_KEY_ID_GET_KEY_ID( id ) <= PSA_KEY_ID_USER_MAX ) );
-    }
-#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
-    /* randomly-generated 64-bit constant, should never appear in test data */
-    psa_key_slot_number_t slot_number = 0xec94d4a5058a1a21;
-    psa_status_t status = psa_get_key_slot_number( &attributes, &slot_number );
-    if( lifetime_is_dynamic_secure_element( lifetime ) )
-    {
-        /* Mbed Crypto currently always exposes the slot number to
-         * applications. This is not mandated by the PSA specification
-         * and may change in future versions. */
-        TEST_EQUAL( status, 0 );
-        TEST_ASSERT( slot_number != 0xec94d4a5058a1a21 );
-    }
-    else
-    {
-        TEST_EQUAL( status, PSA_ERROR_INVALID_ARGUMENT );
-    }
-#endif
-
-    /* Type and size */
-    TEST_ASSERT( type != 0 );
-    TEST_ASSERT( bits != 0 );
-    TEST_ASSERT( bits <= PSA_MAX_KEY_BITS );
-    if( PSA_KEY_TYPE_IS_UNSTRUCTURED( type ) )
-        TEST_ASSERT( bits % 8 == 0 );
-
-    /* MAX macros concerning specific key types */
-    if( PSA_KEY_TYPE_IS_ECC( type ) )
-        TEST_ASSERT( bits <= PSA_VENDOR_ECC_MAX_CURVE_BITS );
-    else if( PSA_KEY_TYPE_IS_RSA( type ) )
-        TEST_ASSERT( bits <= PSA_VENDOR_RSA_MAX_KEY_BITS );
-    TEST_ASSERT( PSA_BLOCK_CIPHER_BLOCK_LENGTH( type ) <= PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE );
-
-    ok = 1;
-
-exit:
-    /*
-     * Key attributes may have been returned by psa_get_key_attributes()
-     * thus reset them as required.
-     */
-    psa_reset_key_attributes( &attributes );
-
-    return( ok );
-}
-
 int exercise_mac_setup( psa_key_type_t key_type,
                         const unsigned char *key_bytes,
                         size_t key_length,
@@ -363,853 +192,6 @@
     return( 0 );
 }
 
-static int exercise_mac_key( mbedtls_svc_key_id_t key,
-                             psa_key_usage_t usage,
-                             psa_algorithm_t alg )
-{
-    psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT;
-    const unsigned char input[] = "foo";
-    unsigned char mac[PSA_MAC_MAX_SIZE] = {0};
-    size_t mac_length = sizeof( mac );
-
-    if( usage & PSA_KEY_USAGE_SIGN_HASH )
-    {
-        PSA_ASSERT( psa_mac_sign_setup( &operation, key, alg ) );
-        PSA_ASSERT( psa_mac_update( &operation,
-                                    input, sizeof( input ) ) );
-        PSA_ASSERT( psa_mac_sign_finish( &operation,
-                                         mac, sizeof( mac ),
-                                         &mac_length ) );
-    }
-
-    if( usage & PSA_KEY_USAGE_VERIFY_HASH )
-    {
-        psa_status_t verify_status =
-            ( usage & PSA_KEY_USAGE_SIGN_HASH ?
-              PSA_SUCCESS :
-              PSA_ERROR_INVALID_SIGNATURE );
-        PSA_ASSERT( psa_mac_verify_setup( &operation, key, alg ) );
-        PSA_ASSERT( psa_mac_update( &operation,
-                                    input, sizeof( input ) ) );
-        TEST_EQUAL( psa_mac_verify_finish( &operation, mac, mac_length ),
-                    verify_status );
-    }
-
-    return( 1 );
-
-exit:
-    psa_mac_abort( &operation );
-    return( 0 );
-}
-
-static int exercise_cipher_key( mbedtls_svc_key_id_t key,
-                                psa_key_usage_t usage,
-                                psa_algorithm_t alg )
-{
-    psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
-    unsigned char iv[16] = {0};
-    size_t iv_length = sizeof( iv );
-    const unsigned char plaintext[16] = "Hello, world...";
-    unsigned char ciphertext[32] = "(wabblewebblewibblewobblewubble)";
-    size_t ciphertext_length = sizeof( ciphertext );
-    unsigned char decrypted[sizeof( ciphertext )];
-    size_t part_length;
-
-    if( usage & PSA_KEY_USAGE_ENCRYPT )
-    {
-        PSA_ASSERT( psa_cipher_encrypt_setup( &operation, key, alg ) );
-        PSA_ASSERT( psa_cipher_generate_iv( &operation,
-                                            iv, sizeof( iv ),
-                                            &iv_length ) );
-        PSA_ASSERT( psa_cipher_update( &operation,
-                                       plaintext, sizeof( plaintext ),
-                                       ciphertext, sizeof( ciphertext ),
-                                       &ciphertext_length ) );
-        PSA_ASSERT( psa_cipher_finish( &operation,
-                                       ciphertext + ciphertext_length,
-                                       sizeof( ciphertext ) - ciphertext_length,
-                                       &part_length ) );
-        ciphertext_length += part_length;
-    }
-
-    if( usage & PSA_KEY_USAGE_DECRYPT )
-    {
-        psa_status_t status;
-        int maybe_invalid_padding = 0;
-        if( ! ( usage & PSA_KEY_USAGE_ENCRYPT ) )
-        {
-            psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-            PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
-            /* This should be PSA_CIPHER_GET_IV_SIZE but the API doesn't
-             * have this macro yet. */
-            iv_length = PSA_BLOCK_CIPHER_BLOCK_LENGTH(
-                psa_get_key_type( &attributes ) );
-            maybe_invalid_padding = ! PSA_ALG_IS_STREAM_CIPHER( alg );
-            psa_reset_key_attributes( &attributes );
-        }
-        PSA_ASSERT( psa_cipher_decrypt_setup( &operation, key, alg ) );
-        PSA_ASSERT( psa_cipher_set_iv( &operation,
-                                       iv, iv_length ) );
-        PSA_ASSERT( psa_cipher_update( &operation,
-                                       ciphertext, ciphertext_length,
-                                       decrypted, sizeof( decrypted ),
-                                       &part_length ) );
-        status = psa_cipher_finish( &operation,
-                                    decrypted + part_length,
-                                    sizeof( decrypted ) - part_length,
-                                    &part_length );
-        /* For a stream cipher, all inputs are valid. For a block cipher,
-         * if the input is some aribtrary data rather than an actual
-         ciphertext, a padding error is likely.  */
-        if( maybe_invalid_padding )
-            TEST_ASSERT( status == PSA_SUCCESS ||
-                         status == PSA_ERROR_INVALID_PADDING );
-        else
-            PSA_ASSERT( status );
-    }
-
-    return( 1 );
-
-exit:
-    psa_cipher_abort( &operation );
-    return( 0 );
-}
-
-static int exercise_aead_key( mbedtls_svc_key_id_t key,
-                              psa_key_usage_t usage,
-                              psa_algorithm_t alg )
-{
-    unsigned char nonce[16] = {0};
-    size_t nonce_length = sizeof( nonce );
-    unsigned char plaintext[16] = "Hello, world...";
-    unsigned char ciphertext[48] = "(wabblewebblewibblewobblewubble)";
-    size_t ciphertext_length = sizeof( ciphertext );
-    size_t plaintext_length = sizeof( ciphertext );
-
-    /* Default IV length for AES-GCM is 12 bytes */
-    if( PSA_ALG_AEAD_WITH_SHORTENED_TAG( alg, 0 ) ==
-        PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_GCM, 0 ) )
-    {
-        nonce_length = 12;
-    }
-
-    if( usage & PSA_KEY_USAGE_ENCRYPT )
-    {
-        PSA_ASSERT( psa_aead_encrypt( key, alg,
-                                      nonce, nonce_length,
-                                      NULL, 0,
-                                      plaintext, sizeof( plaintext ),
-                                      ciphertext, sizeof( ciphertext ),
-                                      &ciphertext_length ) );
-    }
-
-    if( usage & PSA_KEY_USAGE_DECRYPT )
-    {
-        psa_status_t verify_status =
-            ( usage & PSA_KEY_USAGE_ENCRYPT ?
-              PSA_SUCCESS :
-              PSA_ERROR_INVALID_SIGNATURE );
-        TEST_EQUAL( psa_aead_decrypt( key, alg,
-                                      nonce, nonce_length,
-                                      NULL, 0,
-                                      ciphertext, ciphertext_length,
-                                      plaintext, sizeof( plaintext ),
-                                      &plaintext_length ),
-                    verify_status );
-    }
-
-    return( 1 );
-
-exit:
-    return( 0 );
-}
-
-static int exercise_signature_key( mbedtls_svc_key_id_t key,
-                                   psa_key_usage_t usage,
-                                   psa_algorithm_t 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_HASH_AND_SIGN( 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
-        mbedtls_test_fail( "No hash algorithm for hash-and-sign testing",
-                            __LINE__, __FILE__ );
-        return( 1 );
-#endif
-    }
-
-    if( usage & PSA_KEY_USAGE_SIGN_HASH )
-    {
-        /* Some algorithms require the payload to have the size of
-         * the hash encoded in the algorithm. Use this input size
-         * even for algorithms that allow other input sizes. */
-        if( hash_alg != 0 )
-            payload_length = PSA_HASH_LENGTH( hash_alg );
-        PSA_ASSERT( psa_sign_hash( key, alg,
-                                   payload, payload_length,
-                                   signature, sizeof( signature ),
-                                   &signature_length ) );
-    }
-
-    if( usage & PSA_KEY_USAGE_VERIFY_HASH )
-    {
-        psa_status_t verify_status =
-            ( usage & PSA_KEY_USAGE_SIGN_HASH ?
-              PSA_SUCCESS :
-              PSA_ERROR_INVALID_SIGNATURE );
-        TEST_EQUAL( psa_verify_hash( key, alg,
-                                     payload, payload_length,
-                                     signature, signature_length ),
-                    verify_status );
-    }
-
-    return( 1 );
-
-exit:
-    return( 0 );
-}
-
-static int exercise_asymmetric_encryption_key( mbedtls_svc_key_id_t key,
-                                               psa_key_usage_t usage,
-                                               psa_algorithm_t alg )
-{
-    unsigned char plaintext[256] = "Hello, world...";
-    unsigned char ciphertext[256] = "(wabblewebblewibblewobblewubble)";
-    size_t ciphertext_length = sizeof( ciphertext );
-    size_t plaintext_length = 16;
-
-    if( usage & PSA_KEY_USAGE_ENCRYPT )
-    {
-        PSA_ASSERT( psa_asymmetric_encrypt( key, alg,
-                                            plaintext, plaintext_length,
-                                            NULL, 0,
-                                            ciphertext, sizeof( ciphertext ),
-                                            &ciphertext_length ) );
-    }
-
-    if( usage & PSA_KEY_USAGE_DECRYPT )
-    {
-        psa_status_t status =
-            psa_asymmetric_decrypt( key, alg,
-                                    ciphertext, ciphertext_length,
-                                    NULL, 0,
-                                    plaintext, sizeof( plaintext ),
-                                    &plaintext_length );
-        TEST_ASSERT( status == PSA_SUCCESS ||
-                     ( ( usage & PSA_KEY_USAGE_ENCRYPT ) == 0 &&
-                       ( status == PSA_ERROR_INVALID_ARGUMENT ||
-                         status == PSA_ERROR_INVALID_PADDING ) ) );
-    }
-
-    return( 1 );
-
-exit:
-    return( 0 );
-}
-
-static int setup_key_derivation_wrap( psa_key_derivation_operation_t* operation,
-                                      mbedtls_svc_key_id_t key,
-                                      psa_algorithm_t alg,
-                                      unsigned char* input1, size_t input1_length,
-                                      unsigned char* input2, size_t input2_length,
-                                      size_t capacity )
-{
-    PSA_ASSERT( psa_key_derivation_setup( operation, alg ) );
-    if( PSA_ALG_IS_HKDF( alg ) )
-    {
-        PSA_ASSERT( psa_key_derivation_input_bytes( operation,
-                                                    PSA_KEY_DERIVATION_INPUT_SALT,
-                                                    input1, input1_length ) );
-        PSA_ASSERT( psa_key_derivation_input_key( operation,
-                                                  PSA_KEY_DERIVATION_INPUT_SECRET,
-                                                  key ) );
-        PSA_ASSERT( psa_key_derivation_input_bytes( operation,
-                                                    PSA_KEY_DERIVATION_INPUT_INFO,
-                                                    input2,
-                                                    input2_length ) );
-    }
-    else if( PSA_ALG_IS_TLS12_PRF( alg ) ||
-             PSA_ALG_IS_TLS12_PSK_TO_MS( alg ) )
-    {
-        PSA_ASSERT( psa_key_derivation_input_bytes( operation,
-                                                    PSA_KEY_DERIVATION_INPUT_SEED,
-                                                    input1, input1_length ) );
-        PSA_ASSERT( psa_key_derivation_input_key( operation,
-                                                  PSA_KEY_DERIVATION_INPUT_SECRET,
-                                                  key ) );
-        PSA_ASSERT( psa_key_derivation_input_bytes( operation,
-                                                    PSA_KEY_DERIVATION_INPUT_LABEL,
-                                                    input2, input2_length ) );
-    }
-    else
-    {
-        TEST_ASSERT( ! "Key derivation algorithm not supported" );
-    }
-
-    if( capacity != SIZE_MAX )
-        PSA_ASSERT( psa_key_derivation_set_capacity( operation, capacity ) );
-
-    return( 1 );
-
-exit:
-    return( 0 );
-}
-
-
-static int exercise_key_derivation_key( mbedtls_svc_key_id_t key,
-                                        psa_key_usage_t usage,
-                                        psa_algorithm_t alg )
-{
-    psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT;
-    unsigned char input1[] = "Input 1";
-    size_t input1_length = sizeof( input1 );
-    unsigned char input2[] = "Input 2";
-    size_t input2_length = sizeof( input2 );
-    unsigned char output[1];
-    size_t capacity = sizeof( output );
-
-    if( usage & PSA_KEY_USAGE_DERIVE )
-    {
-        if( !setup_key_derivation_wrap( &operation, key, alg,
-                                        input1, input1_length,
-                                        input2, input2_length, capacity ) )
-            goto exit;
-
-        PSA_ASSERT( psa_key_derivation_output_bytes( &operation,
-                                                     output,
-                                                     capacity ) );
-        PSA_ASSERT( psa_key_derivation_abort( &operation ) );
-    }
-
-    return( 1 );
-
-exit:
-    return( 0 );
-}
-
-/* We need two keys to exercise key agreement. Exercise the
- * private key against its own public key. */
-static psa_status_t key_agreement_with_self(
-    psa_key_derivation_operation_t *operation,
-    mbedtls_svc_key_id_t key )
-{
-    psa_key_type_t private_key_type;
-    psa_key_type_t public_key_type;
-    size_t key_bits;
-    uint8_t *public_key = NULL;
-    size_t public_key_length;
-    /* Return GENERIC_ERROR if something other than the final call to
-     * psa_key_derivation_key_agreement fails. This isn't fully satisfactory,
-     * but it's good enough: callers will report it as a failed test anyway. */
-    psa_status_t status = PSA_ERROR_GENERIC_ERROR;
-    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-
-    PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
-    private_key_type = psa_get_key_type( &attributes );
-    key_bits = psa_get_key_bits( &attributes );
-    public_key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR( private_key_type );
-    public_key_length = PSA_EXPORT_KEY_OUTPUT_SIZE( public_key_type, key_bits );
-    ASSERT_ALLOC( public_key, public_key_length );
-    PSA_ASSERT( psa_export_public_key( key, public_key, public_key_length,
-                                       &public_key_length ) );
-
-    status = psa_key_derivation_key_agreement(
-        operation, PSA_KEY_DERIVATION_INPUT_SECRET, key,
-        public_key, public_key_length );
-exit:
-    /*
-     * Key attributes may have been returned by psa_get_key_attributes()
-     * thus reset them as required.
-     */
-    psa_reset_key_attributes( &attributes );
-
-    mbedtls_free( public_key );
-    return( status );
-}
-
-/* We need two keys to exercise key agreement. Exercise the
- * private key against its own public key. */
-static psa_status_t raw_key_agreement_with_self( psa_algorithm_t alg,
-                                                 mbedtls_svc_key_id_t key )
-{
-    psa_key_type_t private_key_type;
-    psa_key_type_t public_key_type;
-    size_t key_bits;
-    uint8_t *public_key = NULL;
-    size_t public_key_length;
-    uint8_t output[1024];
-    size_t output_length;
-    /* Return GENERIC_ERROR if something other than the final call to
-     * psa_key_derivation_key_agreement fails. This isn't fully satisfactory,
-     * but it's good enough: callers will report it as a failed test anyway. */
-    psa_status_t status = PSA_ERROR_GENERIC_ERROR;
-    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-
-    PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
-    private_key_type = psa_get_key_type( &attributes );
-    key_bits = psa_get_key_bits( &attributes );
-    public_key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR( private_key_type );
-    public_key_length = PSA_EXPORT_KEY_OUTPUT_SIZE( public_key_type, key_bits );
-    ASSERT_ALLOC( public_key, public_key_length );
-    PSA_ASSERT( psa_export_public_key( key,
-                                       public_key, public_key_length,
-                                       &public_key_length ) );
-
-    status = psa_raw_key_agreement( alg, key,
-                                    public_key, public_key_length,
-                                    output, sizeof( output ), &output_length );
-exit:
-    /*
-     * Key attributes may have been returned by psa_get_key_attributes()
-     * thus reset them as required.
-     */
-    psa_reset_key_attributes( &attributes );
-
-    mbedtls_free( public_key );
-    return( status );
-}
-
-static int exercise_raw_key_agreement_key( mbedtls_svc_key_id_t key,
-                                           psa_key_usage_t usage,
-                                           psa_algorithm_t alg )
-{
-    int ok = 0;
-
-    if( usage & PSA_KEY_USAGE_DERIVE )
-    {
-        /* We need two keys to exercise key agreement. Exercise the
-         * private key against its own public key. */
-        PSA_ASSERT( raw_key_agreement_with_self( alg, key ) );
-    }
-    ok = 1;
-
-exit:
-    return( ok );
-}
-
-static int exercise_key_agreement_key( mbedtls_svc_key_id_t key,
-                                       psa_key_usage_t usage,
-                                       psa_algorithm_t alg )
-{
-    psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT;
-    unsigned char output[1];
-    int ok = 0;
-
-    if( usage & PSA_KEY_USAGE_DERIVE )
-    {
-        /* We need two keys to exercise key agreement. Exercise the
-         * private key against its own public key. */
-        PSA_ASSERT( psa_key_derivation_setup( &operation, alg ) );
-        PSA_ASSERT( key_agreement_with_self( &operation, key ) );
-        PSA_ASSERT( psa_key_derivation_output_bytes( &operation,
-                                                     output,
-                                                     sizeof( output ) ) );
-        PSA_ASSERT( psa_key_derivation_abort( &operation ) );
-    }
-    ok = 1;
-
-exit:
-    return( ok );
-}
-
-int asn1_skip_integer( unsigned char **p, const unsigned char *end,
-                       size_t min_bits, size_t max_bits,
-                       int must_be_odd )
-{
-    size_t len;
-    size_t actual_bits;
-    unsigned char msb;
-    TEST_EQUAL( mbedtls_asn1_get_tag( p, end, &len,
-                                      MBEDTLS_ASN1_INTEGER ),
-                0 );
-
-    /* Check if the retrieved length doesn't extend the actual buffer's size.
-     * It is assumed here, that end >= p, which validates casting to size_t. */
-    TEST_ASSERT( len <= (size_t)( end - *p) );
-
-    /* Tolerate a slight departure from DER encoding:
-     * - 0 may be represented by an empty string or a 1-byte string.
-     * - The sign bit may be used as a value bit. */
-    if( ( len == 1 && ( *p )[0] == 0 ) ||
-        ( len > 1 && ( *p )[0] == 0 && ( ( *p )[1] & 0x80 ) != 0 ) )
-    {
-        ++( *p );
-        --len;
-    }
-    if( min_bits == 0 && len == 0 )
-        return( 1 );
-    msb = ( *p )[0];
-    TEST_ASSERT( msb != 0 );
-    actual_bits = 8 * ( len - 1 );
-    while( msb != 0 )
-    {
-        msb >>= 1;
-        ++actual_bits;
-    }
-    TEST_ASSERT( actual_bits >= min_bits );
-    TEST_ASSERT( actual_bits <= max_bits );
-    if( must_be_odd )
-        TEST_ASSERT( ( ( *p )[len-1] & 1 ) != 0 );
-    *p += len;
-    return( 1 );
-exit:
-    return( 0 );
-}
-
-static int exported_key_sanity_check( psa_key_type_t type, size_t bits,
-                                      uint8_t *exported, size_t exported_length )
-{
-    if( PSA_KEY_TYPE_IS_UNSTRUCTURED( type ) )
-        TEST_EQUAL( exported_length, ( bits + 7 ) / 8 );
-    else
-        TEST_ASSERT( exported_length <= PSA_EXPORT_KEY_OUTPUT_SIZE( type, bits ) );
-
-#if defined(MBEDTLS_DES_C)
-    if( type == PSA_KEY_TYPE_DES )
-    {
-        /* Check the parity bits. */
-        unsigned i;
-        for( i = 0; i < bits / 8; i++ )
-        {
-            unsigned bit_count = 0;
-            unsigned m;
-            for( m = 1; m <= 0x100; m <<= 1 )
-            {
-                if( exported[i] & m )
-                    ++bit_count;
-            }
-            TEST_ASSERT( bit_count % 2 != 0 );
-        }
-    }
-    else
-#endif
-
-#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_PK_PARSE_C)
-    if( type == PSA_KEY_TYPE_RSA_KEY_PAIR )
-    {
-        uint8_t *p = exported;
-        uint8_t *end = exported + exported_length;
-        size_t len;
-        /*   RSAPrivateKey ::= SEQUENCE {
-         *       version             INTEGER,  -- must be 0
-         *       modulus             INTEGER,  -- n
-         *       publicExponent      INTEGER,  -- e
-         *       privateExponent     INTEGER,  -- d
-         *       prime1              INTEGER,  -- p
-         *       prime2              INTEGER,  -- q
-         *       exponent1           INTEGER,  -- d mod (p-1)
-         *       exponent2           INTEGER,  -- d mod (q-1)
-         *       coefficient         INTEGER,  -- (inverse of q) mod p
-         *   }
-         */
-        TEST_EQUAL( mbedtls_asn1_get_tag( &p, end, &len,
-                                          MBEDTLS_ASN1_SEQUENCE |
-                                          MBEDTLS_ASN1_CONSTRUCTED ), 0 );
-        TEST_EQUAL( p + len, end );
-        if( ! asn1_skip_integer( &p, end, 0, 0, 0 ) )
-            goto exit;
-        if( ! asn1_skip_integer( &p, end, bits, bits, 1 ) )
-            goto exit;
-        if( ! asn1_skip_integer( &p, end, 2, bits, 1 ) )
-            goto exit;
-        /* Require d to be at least half the size of n. */
-        if( ! asn1_skip_integer( &p, end, bits / 2, bits, 1 ) )
-            goto exit;
-        /* Require p and q to be at most half the size of n, rounded up. */
-        if( ! asn1_skip_integer( &p, end, bits / 2, bits / 2 + 1, 1 ) )
-            goto exit;
-        if( ! asn1_skip_integer( &p, end, bits / 2, bits / 2 + 1, 1 ) )
-            goto exit;
-        if( ! asn1_skip_integer( &p, end, 1, bits / 2 + 1, 0 ) )
-            goto exit;
-        if( ! asn1_skip_integer( &p, end, 1, bits / 2 + 1, 0 ) )
-            goto exit;
-        if( ! asn1_skip_integer( &p, end, 1, bits / 2 + 1, 0 ) )
-            goto exit;
-        TEST_EQUAL( p, end );
-    }
-    else
-#endif /* MBEDTLS_RSA_C */
-
-#if defined(MBEDTLS_ECP_C)
-    if( PSA_KEY_TYPE_IS_ECC_KEY_PAIR( type ) )
-    {
-        /* Just the secret value */
-        TEST_EQUAL( exported_length, PSA_BITS_TO_BYTES( bits ) );
-    }
-    else
-#endif /* MBEDTLS_ECP_C */
-
-    if( PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) )
-    {
-        uint8_t *p = exported;
-        uint8_t *end = exported + exported_length;
-#if defined(MBEDTLS_RSA_C)
-        if( type == PSA_KEY_TYPE_RSA_PUBLIC_KEY )
-        {
-            size_t len;
-            /*   RSAPublicKey ::= SEQUENCE {
-             *      modulus            INTEGER,    -- n
-             *      publicExponent     INTEGER  }  -- e
-             */
-            TEST_EQUAL( mbedtls_asn1_get_tag( &p, end, &len,
-                                              MBEDTLS_ASN1_SEQUENCE |
-                                              MBEDTLS_ASN1_CONSTRUCTED ),
-                        0 );
-            TEST_EQUAL( p + len, end );
-            if( ! asn1_skip_integer( &p, end, bits, bits, 1 ) )
-                goto exit;
-            if( ! asn1_skip_integer( &p, end, 2, bits, 1 ) )
-                goto exit;
-            TEST_EQUAL( p, end );
-        }
-        else
-#endif /* MBEDTLS_RSA_C */
-#if defined(MBEDTLS_ECP_C)
-        if( PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY( type ) )
-        {
-            if( PSA_KEY_TYPE_ECC_GET_FAMILY( type ) == PSA_ECC_FAMILY_MONTGOMERY )
-            {
-                /* The representation of an ECC Montgomery public key is
-                 * the raw compressed point */
-                 TEST_EQUAL( p + PSA_BITS_TO_BYTES( bits ), end );
-            }
-            else
-            {
-                /* The representation of an ECC Weierstrass public key is:
-                 *      - The byte 0x04;
-                 *      - `x_P` as a `ceiling(m/8)`-byte string, big-endian;
-                 *      - `y_P` as a `ceiling(m/8)`-byte string, big-endian;
-                 *      - where m is the bit size associated with the curve.
-                 */
-                TEST_EQUAL( p + 1 + 2 * PSA_BITS_TO_BYTES( bits ), end );
-                TEST_EQUAL( p[0], 4 );
-            }
-        }
-        else
-#endif /* MBEDTLS_ECP_C */
-        {
-            char message[47];
-            mbedtls_snprintf( message, sizeof( message ),
-                              "No sanity check for public key type=0x%08lx",
-                              (unsigned long) type );
-            mbedtls_test_fail( message, __LINE__, __FILE__ );
-            (void) p;
-            (void) end;
-            return( 0 );
-        }
-    }
-    else
-
-    {
-        /* No sanity checks for other types */
-    }
-
-    return( 1 );
-
-exit:
-    return( 0 );
-}
-
-static int exercise_export_key( mbedtls_svc_key_id_t key,
-                                psa_key_usage_t usage )
-{
-    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-    uint8_t *exported = NULL;
-    size_t exported_size = 0;
-    size_t exported_length = 0;
-    int ok = 0;
-
-    PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
-
-    exported_size = PSA_EXPORT_KEY_OUTPUT_SIZE(
-                        psa_get_key_type( &attributes ),
-                        psa_get_key_bits( &attributes ) );
-    ASSERT_ALLOC( exported, exported_size );
-
-    if( ( usage & PSA_KEY_USAGE_EXPORT ) == 0 &&
-        ! PSA_KEY_TYPE_IS_PUBLIC_KEY( psa_get_key_type( &attributes ) ) )
-    {
-        TEST_EQUAL( psa_export_key( key, exported,
-                                    exported_size, &exported_length ),
-                    PSA_ERROR_NOT_PERMITTED );
-        ok = 1;
-        goto exit;
-    }
-
-    PSA_ASSERT( psa_export_key( key,
-                                exported, exported_size,
-                                &exported_length ) );
-    ok = exported_key_sanity_check( psa_get_key_type( &attributes ),
-                                    psa_get_key_bits( &attributes ),
-                                    exported, exported_length );
-
-exit:
-    /*
-     * Key attributes may have been returned by psa_get_key_attributes()
-     * thus reset them as required.
-     */
-    psa_reset_key_attributes( &attributes );
-
-    mbedtls_free( exported );
-    return( ok );
-}
-
-static int exercise_export_public_key( mbedtls_svc_key_id_t key )
-{
-    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-    psa_key_type_t public_type;
-    uint8_t *exported = NULL;
-    size_t exported_size = 0;
-    size_t exported_length = 0;
-    int ok = 0;
-
-    PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
-    if( ! PSA_KEY_TYPE_IS_ASYMMETRIC( psa_get_key_type( &attributes ) ) )
-    {
-        exported_size = PSA_EXPORT_KEY_OUTPUT_SIZE(
-                            psa_get_key_type( &attributes ),
-                            psa_get_key_bits( &attributes ) );
-        ASSERT_ALLOC( exported, exported_size );
-
-        TEST_EQUAL( psa_export_public_key( key, exported,
-                                           exported_size, &exported_length ),
-                    PSA_ERROR_INVALID_ARGUMENT );
-        ok = 1;
-        goto exit;
-    }
-
-    public_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(
-        psa_get_key_type( &attributes ) );
-    exported_size = PSA_EXPORT_KEY_OUTPUT_SIZE( public_type,
-                                                psa_get_key_bits( &attributes ) );
-    ASSERT_ALLOC( exported, exported_size );
-
-    PSA_ASSERT( psa_export_public_key( key,
-                                       exported, exported_size,
-                                       &exported_length ) );
-    ok = exported_key_sanity_check( public_type,
-                                    psa_get_key_bits( &attributes ),
-                                    exported, exported_length );
-
-exit:
-    /*
-     * Key attributes may have been returned by psa_get_key_attributes()
-     * thus reset them as required.
-     */
-    psa_reset_key_attributes( &attributes );
-
-    mbedtls_free( exported );
-    return( ok );
-}
-
-/** Do smoke tests on a key.
- *
- * Perform one of each operation indicated by \p alg (decrypt/encrypt,
- * sign/verify, or derivation) that is permitted according to \p usage.
- * \p usage and \p alg should correspond to the expected policy on the
- * key.
- *
- * Export the key if permitted by \p usage, and check that the output
- * looks sensible. If \p usage forbids export, check that
- * \p psa_export_key correctly rejects the attempt. If the key is
- * asymmetric, also check \p psa_export_public_key.
- *
- * If the key fails the tests, this function calls the test framework's
- * `mbedtls_test_fail` function and returns false. Otherwise this function
- * returns true. Therefore it should be used as follows:
- * ```
- * if( ! exercise_key( ... ) ) goto exit;
- * ```
- *
- * \param key       The key to exercise. It should be capable of performing
- *                  \p alg.
- * \param usage     The usage flags to assume.
- * \param alg       The algorithm to exercise.
- *
- * \retval 0 The key failed the smoke tests.
- * \retval 1 The key passed the smoke tests.
- */
-static int exercise_key( mbedtls_svc_key_id_t key,
-                         psa_key_usage_t usage,
-                         psa_algorithm_t alg )
-{
-    int ok;
-
-    if( ! check_key_attributes_sanity( key ) )
-        return( 0 );
-
-    if( alg == 0 )
-        ok = 1; /* If no algorihm, do nothing (used for raw data "keys"). */
-    else if( PSA_ALG_IS_MAC( alg ) )
-        ok = exercise_mac_key( key, usage, alg );
-    else if( PSA_ALG_IS_CIPHER( alg ) )
-        ok = exercise_cipher_key( key, usage, alg );
-    else if( PSA_ALG_IS_AEAD( alg ) )
-        ok = exercise_aead_key( key, usage, alg );
-    else if( PSA_ALG_IS_SIGN( alg ) )
-        ok = exercise_signature_key( key, usage, alg );
-    else if( PSA_ALG_IS_ASYMMETRIC_ENCRYPTION( alg ) )
-        ok = exercise_asymmetric_encryption_key( key, usage, alg );
-    else if( PSA_ALG_IS_KEY_DERIVATION( alg ) )
-        ok = exercise_key_derivation_key( key, usage, alg );
-    else if( PSA_ALG_IS_RAW_KEY_AGREEMENT( alg ) )
-        ok = exercise_raw_key_agreement_key( key, usage, alg );
-    else if( PSA_ALG_IS_KEY_AGREEMENT( alg ) )
-        ok = exercise_key_agreement_key( key, usage, alg );
-    else
-    {
-        char message[40];
-        mbedtls_snprintf( message, sizeof( message ),
-                          "No code to exercise alg=0x%08lx",
-                          (unsigned long) alg );
-        mbedtls_test_fail( message, __LINE__, __FILE__ );
-        ok = 0;
-    }
-
-    ok = ok && exercise_export_key( key, usage );
-    ok = ok && exercise_export_public_key( key );
-
-    return( ok );
-}
-
-static psa_key_usage_t usage_to_exercise( psa_key_type_t type,
-                                          psa_algorithm_t alg )
-{
-    if( PSA_ALG_IS_MAC( alg ) || PSA_ALG_IS_SIGN( alg ) )
-    {
-        return( PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) ?
-                PSA_KEY_USAGE_VERIFY_HASH :
-                PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH );
-    }
-    else if( PSA_ALG_IS_CIPHER( alg ) || PSA_ALG_IS_AEAD( alg ) ||
-             PSA_ALG_IS_ASYMMETRIC_ENCRYPTION( alg ) )
-    {
-        return( PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) ?
-                PSA_KEY_USAGE_ENCRYPT :
-                PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT );
-    }
-    else if( PSA_ALG_IS_KEY_DERIVATION( alg ) ||
-             PSA_ALG_IS_KEY_AGREEMENT( alg ) )
-    {
-        return( PSA_KEY_USAGE_DERIVE );
-    }
-    else
-    {
-        return( 0 );
-    }
-
-}
-
 static int test_operations_on_invalid_key( mbedtls_svc_key_id_t key )
 {
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
@@ -1609,7 +591,11 @@
         goto destroy;
     }
 
-    if( ! exercise_export_key( key, usage_arg ) )
+    /* Run sanity checks on the exported key. For non-canonical inputs,
+     * this validates the canonical representations. For canonical inputs,
+     * this doesn't directly validate the implementation, but it still helps
+     * by cross-validating the test data with the sanity check code. */
+    if( ! mbedtls_test_psa_exercise_key( key, usage_arg, 0 ) )
         goto exit;
 
     if( canonical_input )
@@ -1715,7 +701,7 @@
     psa_key_type_t type = type_arg;
     size_t bits = bits_arg;
     psa_algorithm_t alg = alg_arg;
-    psa_key_usage_t usage = usage_to_exercise( type, alg );
+    psa_key_usage_t usage = mbedtls_test_psa_usage_to_exercise( type, alg );
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
     psa_key_attributes_t got_attributes = PSA_KEY_ATTRIBUTES_INIT;
 
@@ -1734,7 +720,7 @@
     TEST_EQUAL( psa_get_key_bits( &got_attributes ), bits );
 
     /* Do something with the key according to its type and permitted usage. */
-    if( ! exercise_key( key, usage, alg ) )
+    if( ! mbedtls_test_psa_exercise_key( key, usage, alg ) )
         goto exit;
 
     PSA_ASSERT( psa_destroy_key( key ) );
@@ -2187,7 +1173,7 @@
                                 &key ) );
 
     PSA_ASSERT( psa_key_derivation_setup( &operation, exercise_alg ) );
-    status = key_agreement_with_self( &operation, key );
+    status = mbedtls_test_psa_key_agreement_with_self( &operation, key );
 
     TEST_EQUAL( status, expected_status );
 
@@ -2224,9 +1210,9 @@
     TEST_EQUAL( psa_get_key_algorithm( &got_attributes ), alg );
     TEST_EQUAL( psa_get_key_enrollment_algorithm( &got_attributes ), alg2 );
 
-    if( ! exercise_key( key, usage, alg ) )
+    if( ! mbedtls_test_psa_exercise_key( key, usage, alg ) )
         goto exit;
-    if( ! exercise_key( key, usage, alg2 ) )
+    if( ! mbedtls_test_psa_exercise_key( key, usage, alg2 ) )
         goto exit;
 
 exit:
@@ -2265,7 +1251,7 @@
     PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len,
                                 &key ) );
 
-    status = raw_key_agreement_with_self( exercise_alg, key );
+    status = mbedtls_test_psa_raw_key_agreement_with_self( exercise_alg, key );
 
     TEST_EQUAL( status, expected_status );
 
@@ -2348,9 +1334,9 @@
         ASSERT_COMPARE( material->x, material->len,
                         export_buffer, length );
     }
-    if( ! exercise_key( target_key, expected_usage, expected_alg ) )
+    if( ! mbedtls_test_psa_exercise_key( target_key, expected_usage, expected_alg ) )
         goto exit;
-    if( ! exercise_key( target_key, expected_usage, expected_alg2 ) )
+    if( ! mbedtls_test_psa_exercise_key( target_key, expected_usage, expected_alg2 ) )
         goto exit;
 
     PSA_ASSERT( psa_destroy_key( target_key ) );
@@ -4740,7 +3726,8 @@
             {
                 // When taking a private key as secret input, use key agreement
                 // to add the shared secret to the derivation
-                TEST_EQUAL( key_agreement_with_self( &operation, keys[i] ),
+                TEST_EQUAL( mbedtls_test_psa_key_agreement_with_self(
+                                &operation, keys[i] ),
                             expected_statuses[i] );
             }
             else
@@ -4815,10 +3802,10 @@
                                 &key ) );
 
     /* valid key derivation */
-    if( !setup_key_derivation_wrap( &operation, key, alg,
-                                    input1, input1_length,
-                                    input2, input2_length,
-                                    capacity ) )
+    if( !mbedtls_test_psa_setup_key_derivation_wrap( &operation, key, alg,
+                                                     input1, input1_length,
+                                                     input2, input2_length,
+                                                     capacity ) )
         goto exit;
 
     /* state of operation shouldn't allow additional generation */
@@ -5007,10 +3994,10 @@
     PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len,
                                 &key ) );
 
-    if( !setup_key_derivation_wrap( &operation, key, alg,
-                                    input1->x, input1->len,
-                                    input2->x, input2->len,
-                                    requested_capacity ) )
+    if( !mbedtls_test_psa_setup_key_derivation_wrap( &operation, key, alg,
+                                                     input1->x, input1->len,
+                                                     input2->x, input2->len,
+                                                     requested_capacity ) )
         goto exit;
 
     PSA_ASSERT( psa_key_derivation_get_capacity( &operation,
@@ -5076,9 +4063,10 @@
                                 &base_key ) );
 
     /* Derive a key. */
-    if ( setup_key_derivation_wrap( &operation, base_key, alg,
-                                    input1->x, input1->len,
-                                    input2->x, input2->len, capacity ) )
+    if ( mbedtls_test_psa_setup_key_derivation_wrap( &operation, base_key, alg,
+                                                     input1->x, input1->len,
+                                                     input2->x, input2->len,
+                                                     capacity ) )
         goto exit;
 
     psa_set_key_usage_flags( &attributes, derived_usage );
@@ -5094,7 +4082,7 @@
     TEST_EQUAL( psa_get_key_bits( &got_attributes ), derived_bits );
 
     /* Exercise the derived key. */
-    if( ! exercise_key( derived_key, derived_usage, derived_alg ) )
+    if( ! mbedtls_test_psa_exercise_key( derived_key, derived_usage, derived_alg ) )
         goto exit;
 
 exit:
@@ -5143,9 +4131,10 @@
                                 &base_key ) );
 
     /* Derive some material and output it. */
-    if( !setup_key_derivation_wrap( &operation, base_key, alg,
-                                    input1->x, input1->len,
-                                    input2->x, input2->len, capacity ) )
+    if( !mbedtls_test_psa_setup_key_derivation_wrap( &operation, base_key, alg,
+                                                     input1->x, input1->len,
+                                                     input2->x, input2->len,
+                                                     capacity ) )
         goto exit;
 
     PSA_ASSERT( psa_key_derivation_output_bytes( &operation,
@@ -5154,9 +4143,10 @@
     PSA_ASSERT( psa_key_derivation_abort( &operation ) );
 
     /* Derive the same output again, but this time store it in key objects. */
-    if( !setup_key_derivation_wrap( &operation, base_key, alg,
-                                    input1->x, input1->len,
-                                    input2->x, input2->len, capacity ) )
+    if( !mbedtls_test_psa_setup_key_derivation_wrap( &operation, base_key, alg,
+                                                     input1->x, input1->len,
+                                                     input2->x, input2->len,
+                                                     capacity ) )
         goto exit;
 
     psa_set_key_usage_flags( &derived_attributes, PSA_KEY_USAGE_EXPORT );
@@ -5217,9 +4207,10 @@
     PSA_ASSERT( psa_import_key( &base_attributes, key_data->x, key_data->len,
                                 &base_key ) );
 
-    if( !setup_key_derivation_wrap( &operation, base_key, alg,
-                                    input1->x, input1->len,
-                                    input2->x, input2->len, SIZE_MAX ) )
+    if( !mbedtls_test_psa_setup_key_derivation_wrap( &operation, base_key, alg,
+                                                     input1->x, input1->len,
+                                                     input2->x, input2->len,
+                                                     SIZE_MAX ) )
         goto exit;
 
     psa_set_key_usage_flags( &derived_attributes, PSA_KEY_USAGE_EXPORT );
@@ -5535,7 +4526,7 @@
     TEST_EQUAL( psa_get_key_bits( &got_attributes ), bits );
 
     /* Do something with the key according to its type and permitted usage. */
-    if( ! exercise_key( key, usage, alg ) )
+    if( ! mbedtls_test_psa_exercise_key( key, usage, alg ) )
         goto exit;
 
 exit:
@@ -5607,7 +4598,7 @@
         ASSERT_COMPARE( e_read_buffer, e_read_length, e_arg->x, e_arg->len );
 
     /* Do something with the key according to its type and permitted usage. */
-    if( ! exercise_key( key, usage, alg ) )
+    if( ! mbedtls_test_psa_exercise_key( key, usage, alg ) )
         goto exit;
 
     /* Export the key and check the public exponent. */
@@ -5625,7 +4616,7 @@
         TEST_EQUAL( 0, mbedtls_asn1_get_tag( &p, end, &len,
                                              MBEDTLS_ASN1_SEQUENCE |
                                              MBEDTLS_ASN1_CONSTRUCTED ) );
-        TEST_ASSERT( asn1_skip_integer( &p, end, bits, bits, 1 ) );
+        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 )
@@ -5783,7 +4774,7 @@
     }
 
     /* Do something with the key according to its type and permitted usage. */
-    if( ! exercise_key( key, usage_flags, alg ) )
+    if( ! mbedtls_test_psa_exercise_key( key, usage_flags, alg ) )
         goto exit;
 
 exit:
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 fa516c5..79d658f 100644
--- a/tests/suites/test_suite_psa_crypto_se_driver_hal.function
+++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.function
@@ -767,41 +767,12 @@
     return( ok );
 }
 
-static mbedtls_svc_key_id_t key_ids_used_in_test[10];
-static size_t num_key_ids_used;
-
-/* Record a key id as potentially used in a test case. */
-static int test_uses_key_id( mbedtls_svc_key_id_t key_id )
-{
-    size_t i;
-
-    for( i = 0; i < num_key_ids_used ; i++ )
-    {
-        if( mbedtls_svc_key_id_equal( key_id, key_ids_used_in_test[i] ) )
-            return( 1 );
-    }
-
-    if( num_key_ids_used >= ARRAY_LENGTH( key_ids_used_in_test ) )
-        return( 0 );
-
-    key_ids_used_in_test[num_key_ids_used] = key_id;
-    ++num_key_ids_used;
-
-    return( 1 );
-}
-
-#define TEST_USES_KEY_ID( key_id )                       \
-    TEST_ASSERT( test_uses_key_id( key_id ) )
-
 static void psa_purge_storage( void )
 {
-    size_t i;
+    /* The generic code in mbedtls_test_psa_purge_key_storage()
+     * (which is called by PSA_DONE()) doesn't take care of things that are
+     * specific to dynamic secure elements. */
     psa_key_location_t location;
-
-    for( i = 0; i < num_key_ids_used; i++ )
-        psa_destroy_persistent_key( key_ids_used_in_test[i] );
-    num_key_ids_used = 0;
-
     /* Purge the transaction file. */
     psa_crypto_stop_transaction( );
     /* Purge driver persistent data. */
@@ -1496,6 +1467,7 @@
             ( validate > 0 ? PSA_SUCCESS : PSA_ERROR_NOT_PERMITTED );
     }
 
+    mbedtls_test_set_step( 1 );
     PSA_ASSERT( psa_register_se_driver( MIN_DRIVER_LOCATION, &driver ) );
     PSA_ASSERT( psa_crypto_init( ) );
 
@@ -1525,7 +1497,8 @@
     PSA_ASSERT( psa_purge_key( id ) );
 
     /* Restart and try again. */
-    PSA_DONE( );
+    mbedtls_test_set_step( 2 );
+    PSA_SESSION_DONE( );
     PSA_ASSERT( psa_register_se_driver( location, &driver ) );
     PSA_ASSERT( psa_crypto_init( ) );
     if( ! check_key_attributes( id, &attributes ) )
diff --git a/tests/suites/test_suite_psa_crypto_slot_management.function b/tests/suites/test_suite_psa_crypto_slot_management.function
index dbf05d2..bafb7d8 100644
--- a/tests/suites/test_suite_psa_crypto_slot_management.function
+++ b/tests/suites/test_suite_psa_crypto_slot_management.function
@@ -43,51 +43,6 @@
     INVALID_HANDLE_HUGE,
 } invalid_handle_construction_t;
 
-/* All test functions that create persistent keys must call
- * `TEST_USES_KEY_ID( key_id )` before creating a persistent key with this
- * identifier, and must call psa_purge_key_storage() in their cleanup
- * code. */
-
-#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
-static mbedtls_svc_key_id_t key_ids_used_in_test[9];
-static size_t num_key_ids_used;
-
-/* Record a key id as potentially used in a test case. */
-static int test_uses_key_id( mbedtls_svc_key_id_t key_id )
-{
-    size_t i;
-    if( MBEDTLS_SVC_KEY_ID_GET_KEY_ID( key_id ) >
-        PSA_MAX_PERSISTENT_KEY_IDENTIFIER )
-    {
-        /* Don't touch key id values that designate non-key files. */
-        return( 1 );
-    }
-    for( i = 0; i < num_key_ids_used ; i++ )
-    {
-        if( mbedtls_svc_key_id_equal( key_id, key_ids_used_in_test[i] ) )
-            return( 1 );
-    }
-    if( num_key_ids_used == ARRAY_LENGTH( key_ids_used_in_test ) )
-        return( 0 );
-    key_ids_used_in_test[num_key_ids_used] = key_id;
-    ++num_key_ids_used;
-    return( 1 );
-}
-#define TEST_USES_KEY_ID( key_id )                       \
-    TEST_ASSERT( test_uses_key_id( key_id ) )
-
-/* Destroy all key ids that may have been created by the current test case. */
-static void psa_purge_key_storage( void )
-{
-    size_t i;
-    for( i = 0; i < num_key_ids_used; i++ )
-        psa_destroy_persistent_key( key_ids_used_in_test[i] );
-    num_key_ids_used = 0;
-}
-#else
-#define TEST_USES_KEY_ID( key_id ) ( (void) ( key_id ) )
-#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
-
 /** Apply \p invalidate_method to invalidate the specified key:
  * close it, destroy it, or do nothing;
  */
@@ -131,7 +86,7 @@
         case INVALIDATE_BY_DESTROYING_WITH_SHUTDOWN:
         case INVALIDATE_BY_PURGING_WITH_SHUTDOWN:
             /* All keys must have been closed. */
-            PSA_DONE( );
+            PSA_SESSION_DONE( );
             break;
         case INVALIDATE_BY_SHUTDOWN:
             /* Some keys may remain behind, and we're testing that this
@@ -168,6 +123,7 @@
     mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
 
+    mbedtls_test_set_step( 1 );
     PSA_ASSERT( psa_crypto_init( ) );
 
     /* Import a key. */
@@ -214,6 +170,7 @@
     psa_reset_key_attributes( &attributes );
 
     /* Do something that invalidates the key. */
+    mbedtls_test_set_step( 2 );
     if( ! invalidate_key( invalidate_method, key ) )
         goto exit;
     if( ! invalidate_psa( invalidate_method ) )
@@ -263,6 +220,7 @@
 
     TEST_USES_KEY_ID( id );
 
+    mbedtls_test_set_step( 1 );
     PSA_ASSERT( psa_crypto_init( ) );
 
     psa_set_key_id( &attributes, id );
@@ -312,6 +270,7 @@
      * Do something that wipes key data in volatile memory or destroy the
      * key.
      */
+    mbedtls_test_set_step( 2 );
     if( ! invalidate_key( invalidate_method, id ) )
         goto exit;
     if( ! invalidate_psa( invalidate_method ) )
@@ -383,7 +342,6 @@
     psa_reset_key_attributes( &read_attributes );
 
     PSA_DONE( );
-    psa_purge_key_storage( );
     mbedtls_free( reexported );
 }
 /* END_CASE */
@@ -457,7 +415,6 @@
     psa_reset_key_attributes( &attributes );
 
     PSA_DONE( );
-    psa_purge_key_storage( );
 }
 /* END_CASE */
 
@@ -516,9 +473,6 @@
 
 exit:
     PSA_DONE( );
-#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
-    psa_purge_key_storage( );
-#endif
 }
 /* END_CASE */
 
@@ -654,9 +608,6 @@
 
     PSA_DONE( );
     mbedtls_free( export_buffer );
-#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
-    psa_purge_key_storage( );
-#endif
 }
 /* END_CASE */
 
@@ -772,9 +723,6 @@
 
     PSA_DONE( );
     mbedtls_free( export_buffer );
-#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
-    psa_purge_key_storage( );
-#endif
 }
 /* END_CASE */
 
diff --git a/tests/suites/test_suite_random.data b/tests/suites/test_suite_random.data
new file mode 100644
index 0000000..c23d922
--- /dev/null
+++ b/tests/suites/test_suite_random.data
@@ -0,0 +1,55 @@
+Generate random twice with CTR_DRBG
+random_twice_with_ctr_drbg:
+
+Generate random twice with HMAC_DRBG(SHA-1)
+depends_on:MBEDTLS_SHA1_C
+random_twice_with_hmac_drbg:MBEDTLS_MD_SHA1
+
+Generate random twice with HMAC_DRBG(SHA-256)
+depends_on:MBEDTLS_SHA256_C
+random_twice_with_hmac_drbg:MBEDTLS_MD_SHA256
+
+Generate random twice with HMAC_DRBG(SHA-512)
+depends_on:MBEDTLS_SHA512_C
+random_twice_with_hmac_drbg:MBEDTLS_MD_SHA512
+
+Generate random twice with PSA classic wrapper
+random_twice_with_psa_from_classic:
+
+Generate random twice with PSA API
+random_twice_with_psa_from_psa:
+
+# This bad-usage test case currently crashes in the default configuration
+# because CTR_DRBG crashes when given an unseeded context. This is arguably
+# a good thing because it prevents misuse of mbedtls_psa_get_random().
+#PSA classic wrapper: PSA not active
+#mbedtls_psa_get_random_no_init:
+
+PSA classic wrapper: 0 bytes
+mbedtls_psa_get_random_length:0
+
+PSA classic wrapper: 1 byte
+mbedtls_psa_get_random_length:1
+
+PSA classic wrapper: 256 bytes
+mbedtls_psa_get_random_length:256
+
+# An external RNG is supposed to handle arbitrary request lengths. Test it
+# with something larger than any RNG call made by Mbed TLS itself expects.
+# CTR_DRBG and HMAC_DRBG have their own maximum request lengths which may
+# be lower than the value chosen here and are tested separately.
+PSA classic wrapper: external RNG large
+depends_on:MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+mbedtls_psa_get_random_length:1024
+
+PSA classic wrapper: CTR_DRBG max
+depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG:MBEDTLS_CTR_DRBG_C
+mbedtls_psa_get_random_length:MBEDTLS_CTR_DRBG_MAX_REQUEST
+
+PSA classic wrapper: HMAC_DRBG max
+depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG:!MBEDTLS_CTR_DRBG_C:MBEDTLS_HMAC_DRBG_C
+mbedtls_psa_get_random_length:MBEDTLS_HMAC_DRBG_MAX_REQUEST
+
+PSA classic wrapper: ECDSA signature (SECP256R1)
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+mbedtls_psa_get_random_ecdsa_sign:MBEDTLS_ECP_DP_SECP256R1
diff --git a/tests/suites/test_suite_random.function b/tests/suites/test_suite_random.function
new file mode 100644
index 0000000..37fa36e
--- /dev/null
+++ b/tests/suites/test_suite_random.function
@@ -0,0 +1,202 @@
+/* BEGIN_HEADER */
+
+/* Test random generation as a whole. */
+
+#include "mbedtls/bignum.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/ecdsa.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/hmac_drbg.h"
+#include "mbedtls/psa_util.h"
+#include "psa/crypto.h"
+
+/* How many bytes to generate in each test case for repeated generation.
+ * This must be high enough that the probability of generating the same
+ * output twice is infinitesimal, but low enough that random generators
+ * are willing to deliver that much. */
+#define OUTPUT_SIZE 32
+
+/* END_HEADER */
+
+/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_C:!MBEDTLS_TEST_NULL_ENTROPY:MBEDTLS_CTR_DRBG_C */
+void random_twice_with_ctr_drbg( )
+{
+    mbedtls_entropy_context entropy;
+    mbedtls_ctr_drbg_context drbg;
+    unsigned char output1[OUTPUT_SIZE];
+    unsigned char output2[OUTPUT_SIZE];
+
+    /* First round */
+    mbedtls_entropy_init( &entropy );
+    mbedtls_ctr_drbg_init( &drbg );
+    TEST_EQUAL( 0, mbedtls_ctr_drbg_seed( &drbg,
+                                          mbedtls_entropy_func, &entropy,
+                                          NULL, 0 ) );
+    TEST_EQUAL( 0, mbedtls_ctr_drbg_random( &drbg,
+                                            output1, sizeof( output1 ) ) );
+    mbedtls_ctr_drbg_free( &drbg );
+    mbedtls_entropy_free( &entropy );
+
+    /* Second round */
+    mbedtls_entropy_init( &entropy );
+    mbedtls_ctr_drbg_init( &drbg );
+    TEST_EQUAL( 0, mbedtls_ctr_drbg_seed( &drbg,
+                                          mbedtls_entropy_func, &entropy,
+                                          NULL, 0 ) );
+    TEST_EQUAL( 0, mbedtls_ctr_drbg_random( &drbg,
+                                            output2, sizeof( output2 ) ) );
+    mbedtls_ctr_drbg_free( &drbg );
+    mbedtls_entropy_free( &entropy );
+
+    /* The two rounds must generate different random data. */
+    TEST_ASSERT( memcmp( output1, output2, OUTPUT_SIZE ) != 0 );
+
+exit:
+    mbedtls_ctr_drbg_free( &drbg );
+    mbedtls_entropy_free( &entropy );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_C:!MBEDTLS_TEST_NULL_ENTROPY:MBEDTLS_HMAC_DRBG_C */
+void random_twice_with_hmac_drbg( int md_type )
+{
+    mbedtls_entropy_context entropy;
+    mbedtls_hmac_drbg_context drbg;
+    unsigned char output1[OUTPUT_SIZE];
+    unsigned char output2[OUTPUT_SIZE];
+    const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_type );
+
+    /* First round */
+    mbedtls_entropy_init( &entropy );
+    mbedtls_hmac_drbg_init( &drbg );
+    TEST_EQUAL( 0, mbedtls_hmac_drbg_seed( &drbg, md_info,
+                                           mbedtls_entropy_func, &entropy,
+                                           NULL, 0 ) );
+    TEST_EQUAL( 0, mbedtls_hmac_drbg_random( &drbg,
+                                             output1, sizeof( output1 ) ) );
+    mbedtls_hmac_drbg_free( &drbg );
+    mbedtls_entropy_free( &entropy );
+
+    /* Second round */
+    mbedtls_entropy_init( &entropy );
+    mbedtls_hmac_drbg_init( &drbg );
+    TEST_EQUAL( 0, mbedtls_hmac_drbg_seed( &drbg, md_info,
+                                           mbedtls_entropy_func, &entropy,
+                                           NULL, 0 ) );
+    TEST_EQUAL( 0, mbedtls_hmac_drbg_random( &drbg,
+                                             output2, sizeof( output2 ) ) );
+    mbedtls_hmac_drbg_free( &drbg );
+    mbedtls_entropy_free( &entropy );
+
+    /* The two rounds must generate different random data. */
+    TEST_ASSERT( memcmp( output1, output2, OUTPUT_SIZE ) != 0 );
+
+exit:
+    mbedtls_hmac_drbg_free( &drbg );
+    mbedtls_entropy_free( &entropy );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C:!MBEDTLS_TEST_NULL_ENTROPY:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+void random_twice_with_psa_from_classic( )
+{
+    unsigned char output1[OUTPUT_SIZE];
+    unsigned char output2[OUTPUT_SIZE];
+
+    /* First round */
+    PSA_ASSERT( psa_crypto_init( ) );
+    TEST_EQUAL( 0, mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE,
+                                           output1, sizeof( output1 ) ) );
+    PSA_DONE( );
+
+    /* Second round */
+    PSA_ASSERT( psa_crypto_init( ) );
+    TEST_EQUAL( 0, mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE,
+                                           output2, sizeof( output2 ) ) );
+    PSA_DONE( );
+
+    /* The two rounds must generate different random data. */
+    TEST_ASSERT( memcmp( output1, output2, OUTPUT_SIZE ) != 0 );
+
+exit:
+    PSA_DONE( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C:!MBEDTLS_TEST_NULL_ENTROPY:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+void random_twice_with_psa_from_psa( )
+{
+    unsigned char output1[OUTPUT_SIZE];
+    unsigned char output2[OUTPUT_SIZE];
+
+    /* First round */
+    PSA_ASSERT( psa_crypto_init( ) );
+    PSA_ASSERT( psa_generate_random( output1, sizeof( output1 ) ) );
+    PSA_DONE( );
+
+    /* Second round */
+    PSA_ASSERT( psa_crypto_init( ) );
+    PSA_ASSERT( psa_generate_random( output2, sizeof( output2 ) ) );
+    PSA_DONE( );
+
+    /* The two rounds must generate different random data. */
+    TEST_ASSERT( memcmp( output1, output2, OUTPUT_SIZE ) != 0 );
+
+exit:
+    PSA_DONE( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C */
+void mbedtls_psa_get_random_no_init( )
+{
+    unsigned char output[1];
+
+    TEST_ASSERT( mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE,
+                                         output, sizeof( output ) ) != 0 );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C */
+void mbedtls_psa_get_random_length( int n )
+{
+    unsigned char *output = NULL;
+
+    PSA_ASSERT( psa_crypto_init( ) );
+    ASSERT_ALLOC( output, n );
+
+    TEST_EQUAL( 0, mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE,
+                                           output, n ) );
+exit:
+    mbedtls_free( output );
+    PSA_DONE( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C:MBEDTLS_ECDSA_C */
+void mbedtls_psa_get_random_ecdsa_sign( int curve )
+{
+    mbedtls_ecp_group grp;
+    mbedtls_mpi d, r, s;
+    unsigned char buf[] = "This is not a hash.";
+
+    mbedtls_ecp_group_init( &grp );
+    mbedtls_mpi_init( &d );
+    mbedtls_mpi_init( &r );
+    mbedtls_mpi_init( &s );
+
+    TEST_EQUAL( 0, mbedtls_mpi_lset( &d, 123456789 ) );
+    TEST_EQUAL( 0, mbedtls_ecp_group_load( &grp, curve ) );
+    PSA_ASSERT( psa_crypto_init( ) );
+    TEST_EQUAL( 0, mbedtls_ecdsa_sign( &grp, &r, &s, &d,
+                                       buf, sizeof( buf ),
+                                       mbedtls_psa_get_random,
+                                       MBEDTLS_PSA_RANDOM_STATE ) );
+exit:
+    mbedtls_mpi_free( &d );
+    mbedtls_mpi_free( &r );
+    mbedtls_mpi_free( &s );
+    mbedtls_ecp_group_free( &grp );
+    PSA_DONE( );
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_rsa.data b/tests/suites/test_suite_rsa.data
index 30919f3..6f9406c 100644
--- a/tests/suites/test_suite_rsa.data
+++ b/tests/suites/test_suite_rsa.data
@@ -1,6 +1,12 @@
 RSA parameter validation
 rsa_invalid_param:
 
+RSA init-free-free
+rsa_init_free:0
+
+RSA init-free-init-free
+rsa_init_free:1
+
 RSA PKCS1 Verify v1.5 CAVS #1
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_PKCS1_V15
 # Good padding but wrong hash
diff --git a/tests/suites/test_suite_rsa.function b/tests/suites/test_suite_rsa.function
index 6c73e39..cdbaa13 100644
--- a/tests/suites/test_suite_rsa.function
+++ b/tests/suites/test_suite_rsa.function
@@ -467,6 +467,29 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void rsa_init_free( int reinit )
+{
+    mbedtls_rsa_context ctx;
+
+    /* Double free is not explicitly documented to work, but we rely on it
+     * even inside the library so that you can call mbedtls_rsa_free()
+     * unconditionally on an error path without checking whether it has
+     * already been called in the success path. */
+
+    mbedtls_rsa_init( &ctx, 0, 0 );
+    mbedtls_rsa_free( &ctx );
+
+    if( reinit )
+        mbedtls_rsa_init( &ctx, 0, 0 );
+    mbedtls_rsa_free( &ctx );
+
+    /* This test case always succeeds, functionally speaking. A plausible
+     * bug might trigger an invalid pointer dereference or a memory leak. */
+    goto exit;
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void mbedtls_rsa_pkcs1_sign( data_t * message_str, int padding_mode,
                              int digest, int mod, int radix_P, char * input_P,
                              int radix_Q, char * input_Q, int radix_N,
diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function
index 5c97d90..b1ebf5b 100644
--- a/tests/suites/test_suite_ssl.function
+++ b/tests/suites/test_suite_ssl.function
@@ -3836,9 +3836,7 @@
     if( output == NULL )
         goto exit;
 
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-    TEST_ASSERT( psa_crypto_init() == 0 );
-#endif
+    USE_PSA_INIT( );
 
     TEST_ASSERT( mbedtls_ssl_tls_prf( type, secret->x, secret->len,
                                       label, random->x, random->len,
@@ -3852,6 +3850,7 @@
 exit:
 
     mbedtls_free( output );
+    USE_PSA_DONE( );
 }
 /* END_CASE */
 
diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function
index 2bba4e2..66f0376 100644
--- a/tests/suites/test_suite_x509parse.function
+++ b/tests/suites/test_suite_x509parse.function
@@ -610,14 +610,12 @@
     char *      cn_name = NULL;
     const mbedtls_x509_crt_profile *profile;
 
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-    TEST_ASSERT( psa_crypto_init() == 0 );
-#endif
-
     mbedtls_x509_crt_init( &crt );
     mbedtls_x509_crt_init( &ca );
     mbedtls_x509_crl_init( &crl );
 
+    USE_PSA_INIT( );
+
     if( strcmp( cn_name_str, "NULL" ) != 0 )
         cn_name = cn_name_str;
 
@@ -669,6 +667,7 @@
     mbedtls_x509_crt_free( &crt );
     mbedtls_x509_crt_free( &ca );
     mbedtls_x509_crl_free( &crl );
+    USE_PSA_DONE( );
 }
 /* END_CASE */
 
@@ -712,14 +711,12 @@
     uint32_t flags = 0;
     verify_print_context vrfy_ctx;
 
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-    TEST_ASSERT( psa_crypto_init() == 0 );
-#endif
-
     mbedtls_x509_crt_init( &crt );
     mbedtls_x509_crt_init( &ca );
     verify_print_init( &vrfy_ctx );
 
+    USE_PSA_INIT( );
+
     TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 );
     TEST_ASSERT( mbedtls_x509_crt_parse_file( &ca, ca_file ) == 0 );
 
@@ -737,6 +734,7 @@
 exit:
     mbedtls_x509_crt_free( &crt );
     mbedtls_x509_crt_free( &ca );
+    USE_PSA_DONE( );
 }
 /* END_CASE */
 
@@ -1024,10 +1022,6 @@
     uint32_t flags;
     mbedtls_x509_crt trusted, chain;
 
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-    TEST_ASSERT( psa_crypto_init() == 0 );
-#endif
-
     /*
      * We expect chain_dir to contain certificates 00.crt, 01.crt, etc.
      * with NN.crt signed by NN-1.crt
@@ -1036,6 +1030,8 @@
     mbedtls_x509_crt_init( &trusted );
     mbedtls_x509_crt_init( &chain );
 
+    USE_PSA_INIT( );
+
     /* Load trusted root */
     TEST_ASSERT( mbedtls_x509_crt_parse_file( &trusted, ca_file ) == 0 );
 
@@ -1055,6 +1051,7 @@
 exit:
     mbedtls_x509_crt_free( &chain );
     mbedtls_x509_crt_free( &trusted );
+    USE_PSA_DONE( );
 }
 /* END_CASE */
 
@@ -1069,13 +1066,11 @@
     mbedtls_x509_crt trusted, chain;
     const mbedtls_x509_crt_profile *profile = NULL;
 
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-    TEST_ASSERT( psa_crypto_init() == 0 );
-#endif
-
     mbedtls_x509_crt_init( &chain );
     mbedtls_x509_crt_init( &trusted );
 
+    USE_PSA_INIT( );
+
     while( ( act = mystrsep( &chain_paths, " " ) ) != NULL )
         TEST_ASSERT( mbedtls_x509_crt_parse_file( &chain, act ) == 0 );
     TEST_ASSERT( mbedtls_x509_crt_parse_file( &trusted, trusted_ca ) == 0 );
@@ -1100,6 +1095,7 @@
 exit:
     mbedtls_x509_crt_free( &trusted );
     mbedtls_x509_crt_free( &chain );
+    USE_PSA_DONE( );
 }
 /* END_CASE */
 
diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function
index 9960989..59ea17b 100644
--- a/tests/suites/test_suite_x509write.function
+++ b/tests/suites/test_suite_x509write.function
@@ -6,12 +6,6 @@
 #include "mbedtls/oid.h"
 #include "mbedtls/rsa.h"
 
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-#include "psa/crypto.h"
-#include "mbedtls/psa_util.h"
-#define PSA_INIT( ) PSA_ASSERT( psa_crypto_init( ) )
-#endif /* MBEDTLS_USE_PSA_CRYPTO */
-
 #if defined(MBEDTLS_RSA_C)
 int mbedtls_rsa_decrypt_func( void *ctx, int mode, size_t *olen,
                        const unsigned char *input, unsigned char *output,
diff --git a/visualc/VS2010/mbedTLS.vcxproj b/visualc/VS2010/mbedTLS.vcxproj
index e6d6532..c2051e6 100644
--- a/visualc/VS2010/mbedTLS.vcxproj
+++ b/visualc/VS2010/mbedTLS.vcxproj
@@ -232,11 +232,13 @@
     <ClInclude Include="..\..\include\psa\crypto_struct.h" />

     <ClInclude Include="..\..\include\psa\crypto_types.h" />

     <ClInclude Include="..\..\include\psa\crypto_values.h" />

+    <ClInclude Include="..\..\tests\include\test\asn1_helpers.h" />

     <ClInclude Include="..\..\tests\include\test\constant_flow.h" />

     <ClInclude Include="..\..\tests\include\test\fake_external_rng_for_test.h" />

     <ClInclude Include="..\..\tests\include\test\helpers.h" />

     <ClInclude Include="..\..\tests\include\test\macros.h" />

     <ClInclude Include="..\..\tests\include\test\psa_crypto_helpers.h" />

+    <ClInclude Include="..\..\tests\include\test\psa_exercise_key.h" />

     <ClInclude Include="..\..\tests\include\test\psa_helpers.h" />

     <ClInclude Include="..\..\tests\include\test\random.h" />

     <ClInclude Include="..\..\tests\include\test\drivers\cipher.h" />

@@ -354,10 +356,13 @@
     <ClCompile Include="..\..\library\x509write_crt.c" />

     <ClCompile Include="..\..\library\x509write_csr.c" />

     <ClCompile Include="..\..\library\xtea.c" />

+    <ClCompile Include="..\..\tests\src\asn1_helpers.c" />

     <ClCompile Include="..\..\tests\src\fake_external_rng_for_test.c" />

     <ClCompile Include="..\..\tests\src\helpers.c" />

     <ClCompile Include="..\..\tests\src\psa_crypto_helpers.c" />

+    <ClCompile Include="..\..\tests\src\psa_exercise_key.c" />

     <ClCompile Include="..\..\tests\src\random.c" />

+    <ClCompile Include="..\..\tests\src\threading_helpers.c" />

     <ClCompile Include="..\..\3rdparty\everest\library\everest.c" />

     <ClCompile Include="..\..\3rdparty\everest\library\Hacl_Curve25519_joined.c" />

     <ClCompile Include="..\..\3rdparty\everest\library\x25519.c" />