Added framework as a flattened directory

Signed-off-by: Minos Galanakis <minos.galanakis@arm.com>
diff --git a/framework/tests/src/asn1_helpers.c b/framework/tests/src/asn1_helpers.c
new file mode 100644
index 0000000..c63bd0c
--- /dev/null
+++ b/framework/tests/src/asn1_helpers.c
@@ -0,0 +1,64 @@
+/** \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 OR GPL-2.0-or-later
+ */
+
+#include <test/helpers.h>
+#include <test/macros.h>
+
+#if defined(MBEDTLS_ASN1_PARSE_C)
+
+#include <mbedtls/asn1.h>
+
+#include <test/asn1_helpers.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/framework/tests/src/bignum_codepath_check.c b/framework/tests/src/bignum_codepath_check.c
new file mode 100644
index 0000000..9c6bbc7
--- /dev/null
+++ b/framework/tests/src/bignum_codepath_check.c
@@ -0,0 +1,38 @@
+/** Support for path tracking in optionally safe bignum functions
+ */
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "test/bignum_codepath_check.h"
+#include "bignum_core_invasive.h"
+
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+int mbedtls_codepath_check = MBEDTLS_MPI_IS_TEST;
+
+static void mbedtls_codepath_take_safe(void)
+{
+    if (mbedtls_codepath_check == MBEDTLS_MPI_IS_TEST) {
+        mbedtls_codepath_check = MBEDTLS_MPI_IS_SECRET;
+    }
+}
+
+static void mbedtls_codepath_take_unsafe(void)
+{
+    mbedtls_codepath_check = MBEDTLS_MPI_IS_PUBLIC;
+}
+
+void mbedtls_codepath_test_hooks_setup(void)
+{
+    mbedtls_safe_codepath_hook = mbedtls_codepath_take_safe;
+    mbedtls_unsafe_codepath_hook = mbedtls_codepath_take_unsafe;
+}
+
+void mbedtls_codepath_test_hooks_teardown(void)
+{
+    mbedtls_safe_codepath_hook = NULL;
+    mbedtls_unsafe_codepath_hook = NULL;
+}
+
+#endif /* MBEDTLS_TEST_HOOKS && !MBEDTLS_THREADING_C */
diff --git a/framework/tests/src/bignum_helpers.c b/framework/tests/src/bignum_helpers.c
new file mode 100644
index 0000000..913f5e3
--- /dev/null
+++ b/framework/tests/src/bignum_helpers.c
@@ -0,0 +1,145 @@
+/**
+ * \file bignum_helpers.c
+ *
+ * \brief   This file contains the prototypes of helper functions for
+ *          bignum-related testing.
+ */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#define MBEDTLS_ALLOW_PRIVATE_ACCESS
+#include <test/bignum_helpers.h>
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <mbedtls/bignum.h>
+#include <bignum_core.h>
+#include <bignum_mod.h>
+#include <bignum_mod_raw.h>
+
+#include <test/helpers.h>
+#include <test/macros.h>
+
+int mbedtls_test_read_mpi_core(mbedtls_mpi_uint **pX, size_t *plimbs,
+                               const char *input)
+{
+    /* Sanity check */
+    if (*pX != NULL) {
+        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
+    }
+
+    size_t hex_len = strlen(input);
+    size_t byte_len = (hex_len + 1) / 2;
+    *plimbs = CHARS_TO_LIMBS(byte_len);
+
+    /* A core bignum is not allowed to be empty. Forbid it as test data,
+     * this way static analyzers have a chance of knowing we don't expect
+     * the bignum functions to support empty inputs. */
+    if (*plimbs == 0) {
+        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
+    }
+
+    *pX = mbedtls_calloc(*plimbs, sizeof(**pX));
+    if (*pX == NULL) {
+        return MBEDTLS_ERR_MPI_ALLOC_FAILED;
+    }
+
+    unsigned char *byte_start = (unsigned char *) *pX;
+    if (byte_len % sizeof(mbedtls_mpi_uint) != 0) {
+        byte_start += sizeof(mbedtls_mpi_uint) - byte_len % sizeof(mbedtls_mpi_uint);
+    }
+    if ((hex_len & 1) != 0) {
+        /* mbedtls_test_unhexify wants an even number of hex digits */
+        TEST_ASSERT(mbedtls_test_ascii2uc(*input, byte_start) == 0);
+        ++byte_start;
+        ++input;
+        --byte_len;
+    }
+    TEST_ASSERT(mbedtls_test_unhexify(byte_start,
+                                      byte_len,
+                                      input,
+                                      &byte_len) == 0);
+
+    mbedtls_mpi_core_bigendian_to_host(*pX, *plimbs);
+    return 0;
+
+exit:
+    mbedtls_free(*pX);
+    return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
+}
+
+#if defined(MBEDTLS_ECP_WITH_MPI_UINT)
+int mbedtls_test_read_mpi_modulus(mbedtls_mpi_mod_modulus *N,
+                                  const char *s,
+                                  mbedtls_mpi_mod_rep_selector int_rep)
+{
+    mbedtls_mpi_uint *p = NULL;
+    size_t limbs = 0;
+    if (N->limbs != 0) {
+        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
+    }
+    int ret = mbedtls_test_read_mpi_core(&p, &limbs, s);
+    if (ret != 0) {
+        return ret;
+    }
+
+    switch (int_rep) {
+        case MBEDTLS_MPI_MOD_REP_MONTGOMERY:
+            ret = mbedtls_mpi_mod_modulus_setup(N, p, limbs);
+            break;
+        case MBEDTLS_MPI_MOD_REP_OPT_RED:
+            ret = mbedtls_mpi_mod_optred_modulus_setup(N, p, limbs, NULL);
+            break;
+        default:
+            ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
+            break;
+    }
+    if (ret != 0) {
+        mbedtls_free(p);
+    }
+    return ret;
+}
+
+void mbedtls_test_mpi_mod_modulus_free_with_limbs(mbedtls_mpi_mod_modulus *N)
+{
+    mbedtls_free((mbedtls_mpi_uint *) N->p);
+    mbedtls_mpi_mod_modulus_free(N);
+}
+#endif /* MBEDTLS_ECP_WITH_MPI_UINT */
+
+int mbedtls_test_read_mpi(mbedtls_mpi *X, const char *s)
+{
+    int negative = 0;
+    /* Always set the sign bit to -1 if the input has a minus sign, even for 0.
+     * This creates an invalid representation, which mbedtls_mpi_read_string()
+     * avoids but we want to be able to create that in test data. */
+    if (s[0] == '-') {
+        ++s;
+        negative = 1;
+    }
+    /* mbedtls_mpi_read_string() currently retains leading zeros.
+     * It always allocates at least one limb for the value 0. */
+    if (s[0] == 0) {
+        mbedtls_mpi_free(X);
+        return 0;
+    }
+    int ret = mbedtls_mpi_read_string(X, 16, s);
+    if (ret != 0) {
+        return ret;
+    }
+    if (negative) {
+        if (mbedtls_mpi_cmp_int(X, 0) == 0) {
+            mbedtls_test_increment_case_uses_negative_0();
+        }
+        X->s = -1;
+    }
+    return 0;
+}
+
+#endif /* MBEDTLS_BIGNUM_C */
diff --git a/framework/tests/src/drivers/hash.c b/framework/tests/src/drivers/hash.c
new file mode 100644
index 0000000..54aec93
--- /dev/null
+++ b/framework/tests/src/drivers/hash.c
@@ -0,0 +1,203 @@
+/*
+ * Test driver for hash entry points.
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <test/helpers.h>
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include "psa_crypto_hash.h"
+
+#include "test/drivers/hash.h"
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
+#if MBEDTLS_VERSION_MAJOR < 4
+#include "libtestdriver1/library/psa_crypto_hash.h"
+#else
+#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_hash.h"
+#endif
+#endif
+
+mbedtls_test_driver_hash_hooks_t
+    mbedtls_test_driver_hash_hooks = MBEDTLS_TEST_DRIVER_HASH_INIT;
+
+psa_status_t mbedtls_test_transparent_hash_compute(
+    psa_algorithm_t alg,
+    const uint8_t *input, size_t input_length,
+    uint8_t *hash, size_t hash_size, size_t *hash_length)
+{
+    mbedtls_test_driver_hash_hooks.hits++;
+
+    if (mbedtls_test_driver_hash_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_hash_hooks.driver_status =
+            mbedtls_test_driver_hash_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_HASH)
+        mbedtls_test_driver_hash_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_hash_compute(
+                alg, input, input_length,
+                hash, hash_size, hash_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_HASH)
+        mbedtls_test_driver_hash_hooks.driver_status =
+            mbedtls_psa_hash_compute(
+                alg, input, input_length,
+                hash, hash_size, hash_length);
+#else
+        (void) alg;
+        (void) input;
+        (void) input_length;
+        (void) hash;
+        (void) hash_size;
+        (void) hash_length;
+        mbedtls_test_driver_hash_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_hash_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_hash_setup(
+    mbedtls_transparent_test_driver_hash_operation_t *operation,
+    psa_algorithm_t alg)
+{
+    mbedtls_test_driver_hash_hooks.hits++;
+
+    if (mbedtls_test_driver_hash_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_hash_hooks.driver_status =
+            mbedtls_test_driver_hash_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_HASH)
+        mbedtls_test_driver_hash_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_hash_setup(operation, alg);
+#elif defined(MBEDTLS_PSA_BUILTIN_HASH)
+        mbedtls_test_driver_hash_hooks.driver_status =
+            mbedtls_psa_hash_setup(operation, alg);
+#else
+        (void) operation;
+        (void) alg;
+        mbedtls_test_driver_hash_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_hash_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_hash_clone(
+    const mbedtls_transparent_test_driver_hash_operation_t *source_operation,
+    mbedtls_transparent_test_driver_hash_operation_t *target_operation)
+{
+    mbedtls_test_driver_hash_hooks.hits++;
+
+    if (mbedtls_test_driver_hash_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_hash_hooks.driver_status =
+            mbedtls_test_driver_hash_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_HASH)
+        mbedtls_test_driver_hash_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_hash_clone(source_operation,
+                                                  target_operation);
+#elif defined(MBEDTLS_PSA_BUILTIN_HASH)
+        mbedtls_test_driver_hash_hooks.driver_status =
+            mbedtls_psa_hash_clone(source_operation, target_operation);
+#else
+        (void) source_operation;
+        (void) target_operation;
+        mbedtls_test_driver_hash_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_hash_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_hash_update(
+    mbedtls_transparent_test_driver_hash_operation_t *operation,
+    const uint8_t *input,
+    size_t input_length)
+{
+    mbedtls_test_driver_hash_hooks.hits++;
+
+    if (mbedtls_test_driver_hash_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_hash_hooks.driver_status =
+            mbedtls_test_driver_hash_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_HASH)
+        mbedtls_test_driver_hash_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_hash_update(
+                operation, input, input_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_HASH)
+        mbedtls_test_driver_hash_hooks.driver_status =
+            mbedtls_psa_hash_update(operation, input, input_length);
+#else
+        (void) operation;
+        (void) input;
+        (void) input_length;
+        mbedtls_test_driver_hash_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_hash_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_hash_finish(
+    mbedtls_transparent_test_driver_hash_operation_t *operation,
+    uint8_t *hash,
+    size_t hash_size,
+    size_t *hash_length)
+{
+    mbedtls_test_driver_hash_hooks.hits++;
+
+    if (mbedtls_test_driver_hash_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_hash_hooks.driver_status =
+            mbedtls_test_driver_hash_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_HASH)
+        mbedtls_test_driver_hash_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_hash_finish(
+                operation, hash, hash_size, hash_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_HASH)
+        mbedtls_test_driver_hash_hooks.driver_status =
+            mbedtls_psa_hash_finish(operation, hash, hash_size, hash_length);
+#else
+        (void) operation;
+        (void) hash;
+        (void) hash_size;
+        (void) hash_length;
+        mbedtls_test_driver_hash_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_hash_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_hash_abort(
+    mbedtls_transparent_test_driver_hash_operation_t *operation)
+{
+    mbedtls_test_driver_hash_hooks.hits++;
+
+    if (mbedtls_test_driver_hash_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_hash_hooks.driver_status =
+            mbedtls_test_driver_hash_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_HASH)
+        mbedtls_test_driver_hash_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_hash_abort(operation);
+#elif defined(MBEDTLS_PSA_BUILTIN_HASH)
+        mbedtls_test_driver_hash_hooks.driver_status =
+            mbedtls_psa_hash_abort(operation);
+#else
+        (void) operation;
+        mbedtls_test_driver_hash_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_hash_hooks.driver_status;
+}
+#endif /* PSA_CRYPTO_DRIVER_TEST */
diff --git a/framework/tests/src/drivers/platform_builtin_keys.c b/framework/tests/src/drivers/platform_builtin_keys.c
new file mode 100644
index 0000000..4561b6f
--- /dev/null
+++ b/framework/tests/src/drivers/platform_builtin_keys.c
@@ -0,0 +1,82 @@
+/** \file platform_builtin_keys.c
+ *
+ * \brief Test driver implementation of the builtin key support
+ */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <test/helpers.h>
+
+#if defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)
+
+#include <psa/crypto.h>
+#include <psa/crypto_extra.h>
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include <test/drivers/test_driver.h>
+#endif
+
+typedef struct {
+    psa_key_id_t builtin_key_id;
+    psa_key_lifetime_t lifetime;
+    psa_drv_slot_number_t slot_number;
+} mbedtls_psa_builtin_key_description_t;
+
+static const mbedtls_psa_builtin_key_description_t builtin_keys[] = {
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+    /* For testing, assign the AES builtin key slot to the boundary values.
+     * ECDSA can be exercised on key ID MBEDTLS_PSA_KEY_ID_BUILTIN_MIN + 1. */
+    { MBEDTLS_PSA_KEY_ID_BUILTIN_MIN - 1,
+      PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
+          PSA_KEY_PERSISTENCE_READ_ONLY, PSA_CRYPTO_TEST_DRIVER_LOCATION),
+      PSA_CRYPTO_TEST_DRIVER_BUILTIN_AES_KEY_SLOT },
+    { MBEDTLS_PSA_KEY_ID_BUILTIN_MIN,
+      PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
+          PSA_KEY_PERSISTENCE_READ_ONLY, PSA_CRYPTO_TEST_DRIVER_LOCATION),
+      PSA_CRYPTO_TEST_DRIVER_BUILTIN_AES_KEY_SLOT },
+    { MBEDTLS_PSA_KEY_ID_BUILTIN_MIN + 1,
+      PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
+          PSA_KEY_PERSISTENCE_READ_ONLY, PSA_CRYPTO_TEST_DRIVER_LOCATION),
+      PSA_CRYPTO_TEST_DRIVER_BUILTIN_ECDSA_KEY_SLOT },
+    { MBEDTLS_PSA_KEY_ID_BUILTIN_MAX - 1,
+      PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
+          PSA_KEY_PERSISTENCE_READ_ONLY, PSA_CRYPTO_TEST_DRIVER_LOCATION),
+      PSA_CRYPTO_TEST_DRIVER_BUILTIN_AES_KEY_SLOT },
+    { MBEDTLS_PSA_KEY_ID_BUILTIN_MAX,
+      PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
+          PSA_KEY_PERSISTENCE_READ_ONLY, PSA_CRYPTO_TEST_DRIVER_LOCATION),
+      PSA_CRYPTO_TEST_DRIVER_BUILTIN_AES_KEY_SLOT },
+    { MBEDTLS_PSA_KEY_ID_BUILTIN_MAX + 1,
+      PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
+          PSA_KEY_PERSISTENCE_READ_ONLY, PSA_CRYPTO_TEST_DRIVER_LOCATION),
+      PSA_CRYPTO_TEST_DRIVER_BUILTIN_AES_KEY_SLOT },
+#else
+    { 0, 0, 0 }
+#endif
+};
+
+psa_status_t mbedtls_psa_platform_get_builtin_key(
+    mbedtls_svc_key_id_t key_id,
+    psa_key_lifetime_t *lifetime,
+    psa_drv_slot_number_t *slot_number)
+{
+    psa_key_id_t app_key_id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(key_id);
+    const mbedtls_psa_builtin_key_description_t *builtin_key;
+
+    for (size_t i = 0;
+         i < (sizeof(builtin_keys) / sizeof(builtin_keys[0])); i++) {
+        builtin_key = &builtin_keys[i];
+        if (builtin_key->builtin_key_id == app_key_id) {
+            *lifetime = builtin_key->lifetime;
+            *slot_number = builtin_key->slot_number;
+            return PSA_SUCCESS;
+        }
+    }
+
+    return PSA_ERROR_DOES_NOT_EXIST;
+}
+
+#endif /* MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
diff --git a/framework/tests/src/drivers/test_driver_aead.c b/framework/tests/src/drivers/test_driver_aead.c
new file mode 100644
index 0000000..6992a06
--- /dev/null
+++ b/framework/tests/src/drivers/test_driver_aead.c
@@ -0,0 +1,466 @@
+/*
+ * Test driver for AEAD entry points.
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <test/helpers.h>
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include "psa_crypto_aead.h"
+#include "psa_crypto_core.h"
+
+#include "test/drivers/aead.h"
+
+#include "mbedtls/constant_time.h"
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
+#if MBEDTLS_VERSION_MAJOR < 4
+#include "libtestdriver1/library/psa_crypto_aead.h"
+#else
+#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_aead.h"
+#endif
+#endif
+
+mbedtls_test_driver_aead_hooks_t
+    mbedtls_test_driver_aead_hooks = MBEDTLS_TEST_DRIVER_AEAD_INIT;
+
+psa_status_t mbedtls_test_transparent_aead_encrypt(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer, size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *nonce, size_t nonce_length,
+    const uint8_t *additional_data, size_t additional_data_length,
+    const uint8_t *plaintext, size_t plaintext_length,
+    uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_length)
+{
+    mbedtls_test_driver_aead_hooks.hits_encrypt++;
+
+    if (mbedtls_test_driver_aead_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_test_driver_aead_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_aead_encrypt(
+                (const libtestdriver1_psa_key_attributes_t *) attributes,
+                key_buffer, key_buffer_size,
+                alg,
+                nonce, nonce_length,
+                additional_data, additional_data_length,
+                plaintext, plaintext_length,
+                ciphertext, ciphertext_size, ciphertext_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_psa_aead_encrypt(
+                attributes, key_buffer, key_buffer_size,
+                alg,
+                nonce, nonce_length,
+                additional_data, additional_data_length,
+                plaintext, plaintext_length,
+                ciphertext, ciphertext_size, ciphertext_length);
+#else
+        (void) attributes;
+        (void) key_buffer;
+        (void) key_buffer_size;
+        (void) alg;
+        (void) nonce;
+        (void) nonce_length;
+        (void) additional_data;
+        (void) additional_data_length;
+        (void) plaintext;
+        (void) plaintext_length;
+        (void) ciphertext;
+        (void) ciphertext_size;
+        (void) ciphertext_length;
+        mbedtls_test_driver_aead_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_aead_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_aead_decrypt(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer, size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *nonce, size_t nonce_length,
+    const uint8_t *additional_data, size_t additional_data_length,
+    const uint8_t *ciphertext, size_t ciphertext_length,
+    uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_length)
+{
+    mbedtls_test_driver_aead_hooks.hits_decrypt++;
+
+    if (mbedtls_test_driver_aead_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_test_driver_aead_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_aead_decrypt(
+                (const libtestdriver1_psa_key_attributes_t *) attributes,
+                key_buffer, key_buffer_size,
+                alg,
+                nonce, nonce_length,
+                additional_data, additional_data_length,
+                ciphertext, ciphertext_length,
+                plaintext, plaintext_size, plaintext_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_psa_aead_decrypt(
+                attributes, key_buffer, key_buffer_size,
+                alg,
+                nonce, nonce_length,
+                additional_data, additional_data_length,
+                ciphertext, ciphertext_length,
+                plaintext, plaintext_size, plaintext_length);
+#else
+        (void) attributes;
+        (void) key_buffer;
+        (void) key_buffer_size;
+        (void) alg;
+        (void) nonce;
+        (void) nonce_length;
+        (void) additional_data;
+        (void) additional_data_length;
+        (void) ciphertext;
+        (void) ciphertext_length;
+        (void) plaintext;
+        (void) plaintext_size;
+        (void) plaintext_length;
+        mbedtls_test_driver_aead_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_aead_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_aead_encrypt_setup(
+    mbedtls_transparent_test_driver_aead_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer, size_t key_buffer_size,
+    psa_algorithm_t alg)
+{
+    mbedtls_test_driver_aead_hooks.hits_encrypt_setup++;
+
+    if (mbedtls_test_driver_aead_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_test_driver_aead_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_aead_encrypt_setup(operation,
+                                                          (const libtestdriver1_psa_key_attributes_t
+                                                           *) attributes,
+                                                          key_buffer,
+                                                          key_buffer_size, alg);
+#elif defined(MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_psa_aead_encrypt_setup(operation, attributes, key_buffer,
+                                           key_buffer_size, alg);
+#else
+        (void) operation;
+        (void) attributes;
+        (void) key_buffer;
+        (void) key_buffer_size;
+        (void) alg;
+        mbedtls_test_driver_aead_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_aead_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_aead_decrypt_setup(
+    mbedtls_transparent_test_driver_aead_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer, size_t key_buffer_size,
+    psa_algorithm_t alg)
+{
+    mbedtls_test_driver_aead_hooks.hits_decrypt_setup++;
+
+    if (mbedtls_test_driver_aead_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_test_driver_aead_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_aead_decrypt_setup(operation,
+                                                          (const libtestdriver1_psa_key_attributes_t
+                                                           *) attributes,
+                                                          key_buffer, key_buffer_size, alg);
+#elif defined(MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_psa_aead_decrypt_setup(operation, attributes, key_buffer,
+                                           key_buffer_size, alg);
+#else
+        (void) operation;
+        (void) attributes;
+        (void) key_buffer;
+        (void) key_buffer_size;
+        (void) alg;
+        mbedtls_test_driver_aead_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_aead_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_aead_set_nonce(
+    mbedtls_transparent_test_driver_aead_operation_t *operation,
+    const uint8_t *nonce,
+    size_t nonce_length)
+{
+    mbedtls_test_driver_aead_hooks.hits_set_nonce++;
+
+    if (mbedtls_test_driver_aead_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_test_driver_aead_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_aead_set_nonce(operation, nonce, nonce_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_psa_aead_set_nonce(operation, nonce, nonce_length);
+#else
+        (void) operation;
+        (void) nonce;
+        (void) nonce_length;
+        mbedtls_test_driver_aead_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_aead_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_aead_set_lengths(
+    mbedtls_transparent_test_driver_aead_operation_t *operation,
+    size_t ad_length,
+    size_t plaintext_length)
+{
+    mbedtls_test_driver_aead_hooks.hits_set_lengths++;
+
+    if (mbedtls_test_driver_aead_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_test_driver_aead_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_aead_set_lengths(operation, ad_length,
+                                                        plaintext_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_psa_aead_set_lengths(operation, ad_length,
+                                         plaintext_length);
+#else
+        (void) operation;
+        (void) ad_length;
+        (void) plaintext_length;
+        mbedtls_test_driver_aead_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_aead_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_aead_update_ad(
+    mbedtls_transparent_test_driver_aead_operation_t *operation,
+    const uint8_t *input,
+    size_t input_length)
+{
+    mbedtls_test_driver_aead_hooks.hits_update_ad++;
+
+    if (mbedtls_test_driver_aead_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_test_driver_aead_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_aead_update_ad(operation, input, input_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_psa_aead_update_ad(operation, input, input_length);
+#else
+        (void) operation;
+        (void) input;
+        (void) input_length;
+        mbedtls_test_driver_aead_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_aead_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_aead_update(
+    mbedtls_transparent_test_driver_aead_operation_t *operation,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length)
+{
+    mbedtls_test_driver_aead_hooks.hits_update++;
+
+    if (mbedtls_test_driver_aead_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_test_driver_aead_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_aead_update(operation, input,
+                                                   input_length, output,
+                                                   output_size, output_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_psa_aead_update(operation, input, input_length, output,
+                                    output_size, output_length);
+#else
+        (void) operation;
+        (void) input;
+        (void) input_length;
+        (void) output;
+        (void) output_size;
+        (void) output_length;
+        mbedtls_test_driver_aead_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_aead_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_aead_finish(
+    mbedtls_transparent_test_driver_aead_operation_t *operation,
+    uint8_t *ciphertext,
+    size_t ciphertext_size,
+    size_t *ciphertext_length,
+    uint8_t *tag,
+    size_t tag_size,
+    size_t *tag_length)
+{
+    mbedtls_test_driver_aead_hooks.hits_finish++;
+
+    if (mbedtls_test_driver_aead_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_test_driver_aead_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_aead_finish(operation, ciphertext,
+                                                   ciphertext_size, ciphertext_length,
+                                                   tag, tag_size, tag_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_psa_aead_finish(operation, ciphertext, ciphertext_size,
+                                    ciphertext_length, tag, tag_size,
+                                    tag_length);
+#else
+        (void) operation;
+        (void) ciphertext;
+        (void) ciphertext_size;
+        (void) ciphertext_length;
+        (void) tag;
+        (void) tag_size;
+        (void) tag_length;
+        mbedtls_test_driver_aead_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_aead_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_aead_verify(
+    mbedtls_transparent_test_driver_aead_operation_t *operation,
+    uint8_t *plaintext,
+    size_t plaintext_size,
+    size_t *plaintext_length,
+    const uint8_t *tag,
+    size_t tag_length)
+{
+    mbedtls_test_driver_aead_hooks.hits_verify++;
+
+    if (mbedtls_test_driver_aead_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_test_driver_aead_hooks.forced_status;
+    } else {
+        uint8_t check_tag[PSA_AEAD_TAG_MAX_SIZE];
+        size_t check_tag_length = 0;
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_aead_finish(operation,
+                                                   plaintext,
+                                                   plaintext_size,
+                                                   plaintext_length,
+                                                   check_tag,
+                                                   sizeof(check_tag),
+                                                   &check_tag_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_psa_aead_finish(operation,
+                                    plaintext,
+                                    plaintext_size,
+                                    plaintext_length,
+                                    check_tag,
+                                    sizeof(check_tag),
+                                    &check_tag_length);
+#else
+        (void) operation;
+        (void) plaintext;
+        (void) plaintext_size;
+        (void) plaintext_length;
+        mbedtls_test_driver_aead_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+
+        if (mbedtls_test_driver_aead_hooks.driver_status == PSA_SUCCESS) {
+            if (tag_length != check_tag_length ||
+                mbedtls_ct_memcmp(tag, check_tag, tag_length)
+                != 0) {
+                mbedtls_test_driver_aead_hooks.driver_status =
+                    PSA_ERROR_INVALID_SIGNATURE;
+            }
+        }
+
+        mbedtls_platform_zeroize(check_tag, sizeof(check_tag));
+    }
+
+    return mbedtls_test_driver_aead_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_aead_abort(
+    mbedtls_transparent_test_driver_aead_operation_t *operation)
+{
+    mbedtls_test_driver_aead_hooks.hits_abort++;
+
+    if (mbedtls_test_driver_aead_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_test_driver_aead_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_aead_abort(operation);
+#elif defined(MBEDTLS_PSA_BUILTIN_AEAD)
+        mbedtls_test_driver_aead_hooks.driver_status =
+            mbedtls_psa_aead_abort(operation);
+#else
+        (void) operation;
+        mbedtls_test_driver_aead_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_aead_hooks.driver_status;
+}
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
diff --git a/framework/tests/src/drivers/test_driver_asymmetric_encryption.c b/framework/tests/src/drivers/test_driver_asymmetric_encryption.c
new file mode 100644
index 0000000..6fdbe43
--- /dev/null
+++ b/framework/tests/src/drivers/test_driver_asymmetric_encryption.c
@@ -0,0 +1,185 @@
+/*
+ * Test driver for asymmetric encryption.
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <test/helpers.h>
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include "psa/crypto.h"
+#include "mbedtls/rsa.h"
+#include "psa_crypto_rsa.h"
+#include "string.h"
+#include "test/drivers/asymmetric_encryption.h"
+#include "test/drivers/key_management.h"
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
+#if MBEDTLS_VERSION_MAJOR < 4
+#include "libtestdriver1/library/psa_crypto_rsa.h"
+#else
+#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_rsa.h"
+#endif
+#endif
+
+#define PSA_RSA_KEY_PAIR_MAX_SIZE \
+    PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(PSA_VENDOR_RSA_MAX_KEY_BITS)
+
+mbedtls_test_driver_asymmetric_encryption_hooks_t mbedtls_test_driver_asymmetric_encryption_hooks =
+    MBEDTLS_TEST_DRIVER_ASYMMETRIC_ENCRYPTION_INIT;
+
+psa_status_t mbedtls_test_transparent_asymmetric_encrypt(
+    const psa_key_attributes_t *attributes, const uint8_t *key_buffer,
+    size_t key_buffer_size, psa_algorithm_t alg, const uint8_t *input,
+    size_t input_length, const uint8_t *salt, size_t salt_length,
+    uint8_t *output, size_t output_size, size_t *output_length)
+{
+    mbedtls_test_driver_asymmetric_encryption_hooks.hits++;
+
+    if (mbedtls_test_driver_asymmetric_encryption_hooks.forced_output != NULL) {
+        if (output_size < mbedtls_test_driver_asymmetric_encryption_hooks.forced_output_length) {
+            return PSA_ERROR_BUFFER_TOO_SMALL;
+        }
+
+        memcpy(output,
+               mbedtls_test_driver_asymmetric_encryption_hooks.forced_output,
+               mbedtls_test_driver_asymmetric_encryption_hooks.forced_output_length);
+        *output_length = mbedtls_test_driver_asymmetric_encryption_hooks.forced_output_length;
+
+        return mbedtls_test_driver_asymmetric_encryption_hooks.forced_status;
+    }
+
+    if (mbedtls_test_driver_asymmetric_encryption_hooks.forced_status != PSA_SUCCESS) {
+        return mbedtls_test_driver_asymmetric_encryption_hooks.forced_status;
+    }
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
+    return libtestdriver1_mbedtls_psa_asymmetric_encrypt(
+        (const libtestdriver1_psa_key_attributes_t *) attributes,
+        key_buffer, key_buffer_size,
+        alg, input, input_length, salt, salt_length,
+        output, output_size, output_length);
+#else
+    return mbedtls_psa_asymmetric_encrypt(
+        attributes, key_buffer, key_buffer_size,
+        alg, input, input_length, salt, salt_length,
+        output, output_size, output_length);
+#endif
+
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_transparent_asymmetric_decrypt(
+    const psa_key_attributes_t *attributes, const uint8_t *key_buffer,
+    size_t key_buffer_size, psa_algorithm_t alg, const uint8_t *input,
+    size_t input_length, const uint8_t *salt, size_t salt_length,
+    uint8_t *output, size_t output_size, size_t *output_length)
+{
+    mbedtls_test_driver_asymmetric_encryption_hooks.hits++;
+
+    if (mbedtls_test_driver_asymmetric_encryption_hooks.forced_output != NULL) {
+        if (output_size < mbedtls_test_driver_asymmetric_encryption_hooks.forced_output_length) {
+            return PSA_ERROR_BUFFER_TOO_SMALL;
+        }
+
+        memcpy(output,
+               mbedtls_test_driver_asymmetric_encryption_hooks.forced_output,
+               mbedtls_test_driver_asymmetric_encryption_hooks.forced_output_length);
+        *output_length = mbedtls_test_driver_asymmetric_encryption_hooks.forced_output_length;
+
+        return mbedtls_test_driver_asymmetric_encryption_hooks.forced_status;
+    }
+
+    if (mbedtls_test_driver_asymmetric_encryption_hooks.forced_status != PSA_SUCCESS) {
+        return mbedtls_test_driver_asymmetric_encryption_hooks.forced_status;
+    }
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
+    return libtestdriver1_mbedtls_psa_asymmetric_decrypt(
+        (const libtestdriver1_psa_key_attributes_t *) attributes,
+        key_buffer, key_buffer_size,
+        alg, input, input_length, salt, salt_length,
+        output, output_size, output_length);
+#else
+    return mbedtls_psa_asymmetric_decrypt(
+        attributes, key_buffer, key_buffer_size,
+        alg, input, input_length, salt, salt_length,
+        output, output_size, output_length);
+#endif
+
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+/*
+ * opaque versions
+ */
+psa_status_t mbedtls_test_opaque_asymmetric_encrypt(
+    const psa_key_attributes_t *attributes, const uint8_t *key,
+    size_t key_length, psa_algorithm_t alg, const uint8_t *input,
+    size_t input_length, const uint8_t *salt, size_t salt_length,
+    uint8_t *output, size_t output_size, size_t *output_length)
+{
+    unsigned char unwrapped_key[PSA_RSA_KEY_PAIR_MAX_SIZE];
+    size_t unwrapped_key_length;
+    psa_status_t status;
+
+    status = mbedtls_test_opaque_unwrap_key(key, key_length,
+                                            unwrapped_key, sizeof(unwrapped_key),
+                                            &unwrapped_key_length);
+    if (status != PSA_SUCCESS) {
+        return status;
+    }
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+    (defined(MBEDTLS_PSA_ACCEL_ALG_RSA_OAEP) || defined(MBEDTLS_PSA_ACCEL_ALG_RSA_PKCS1V15_CRYPT))
+    return libtestdriver1_mbedtls_psa_asymmetric_encrypt(
+        (const libtestdriver1_psa_key_attributes_t *) attributes,
+        unwrapped_key, unwrapped_key_length,
+        alg, input, input_length, salt, salt_length,
+        output, output_size, output_length);
+#else
+    return mbedtls_psa_asymmetric_encrypt(
+        attributes, unwrapped_key, unwrapped_key_length,
+        alg, input, input_length, salt, salt_length,
+        output, output_size, output_length);
+#endif
+
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_opaque_asymmetric_decrypt(
+    const psa_key_attributes_t *attributes, const uint8_t *key,
+    size_t key_length, psa_algorithm_t alg, const uint8_t *input,
+    size_t input_length, const uint8_t *salt, size_t salt_length,
+    uint8_t *output, size_t output_size, size_t *output_length)
+{
+    unsigned char unwrapped_key[PSA_RSA_KEY_PAIR_MAX_SIZE];
+    size_t unwrapped_key_length;
+    psa_status_t status;
+
+    status = mbedtls_test_opaque_unwrap_key(key, key_length,
+                                            unwrapped_key, sizeof(unwrapped_key),
+                                            &unwrapped_key_length);
+    if (status != PSA_SUCCESS) {
+        return status;
+    }
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+    (defined(MBEDTLS_PSA_ACCEL_ALG_RSA_OAEP) || defined(MBEDTLS_PSA_ACCEL_ALG_RSA_PKCS1V15_CRYPT))
+    return libtestdriver1_mbedtls_psa_asymmetric_decrypt(
+        (const libtestdriver1_psa_key_attributes_t *) attributes,
+        unwrapped_key, unwrapped_key_length,
+        alg, input, input_length, salt, salt_length,
+        output, output_size, output_length);
+#else
+    return mbedtls_psa_asymmetric_decrypt(
+        attributes, unwrapped_key, unwrapped_key_length,
+        alg, input, input_length, salt, salt_length,
+        output, output_size, output_length);
+#endif
+
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
diff --git a/framework/tests/src/drivers/test_driver_cipher.c b/framework/tests/src/drivers/test_driver_cipher.c
new file mode 100644
index 0000000..90256fc
--- /dev/null
+++ b/framework/tests/src/drivers/test_driver_cipher.c
@@ -0,0 +1,436 @@
+/*
+ * Test driver for cipher functions.
+ * Currently only supports multi-part operations using AES-CTR.
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <test/helpers.h>
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include "psa/crypto.h"
+#include "psa_crypto_cipher.h"
+#include "psa_crypto_core.h"
+#include "mbedtls/cipher.h"
+
+#include "test/drivers/cipher.h"
+
+#include "test/random.h"
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
+#if MBEDTLS_VERSION_MAJOR < 4
+#include "libtestdriver1/library/psa_crypto_cipher.h"
+#else
+#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_cipher.h"
+#endif
+#endif
+
+#include <string.h>
+
+mbedtls_test_driver_cipher_hooks_t mbedtls_test_driver_cipher_hooks =
+    MBEDTLS_TEST_DRIVER_CIPHER_INIT;
+
+psa_status_t mbedtls_test_transparent_cipher_encrypt(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *iv,
+    size_t iv_length,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length)
+{
+    mbedtls_test_driver_cipher_hooks.hits++;
+    mbedtls_test_driver_cipher_hooks.hits_encrypt++;
+
+    if (mbedtls_test_driver_cipher_hooks.forced_output != NULL) {
+        if (output_size < mbedtls_test_driver_cipher_hooks.forced_output_length) {
+            return PSA_ERROR_BUFFER_TOO_SMALL;
+        }
+
+        memcpy(output,
+               mbedtls_test_driver_cipher_hooks.forced_output,
+               mbedtls_test_driver_cipher_hooks.forced_output_length);
+        *output_length = mbedtls_test_driver_cipher_hooks.forced_output_length;
+
+        return mbedtls_test_driver_cipher_hooks.forced_status;
+    }
+
+    if (mbedtls_test_driver_cipher_hooks.forced_status != PSA_SUCCESS) {
+        return mbedtls_test_driver_cipher_hooks.forced_status;
+    }
+    if (mbedtls_test_driver_cipher_hooks.forced_status_encrypt != PSA_SUCCESS) {
+        return mbedtls_test_driver_cipher_hooks.forced_status_encrypt;
+    }
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+    defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_CIPHER)
+    return libtestdriver1_mbedtls_psa_cipher_encrypt(
+        (const libtestdriver1_psa_key_attributes_t *) attributes,
+        key_buffer, key_buffer_size,
+        alg, iv, iv_length, input, input_length,
+        output, output_size, output_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_CIPHER)
+    return mbedtls_psa_cipher_encrypt(
+        attributes, key_buffer, key_buffer_size,
+        alg, iv, iv_length, input, input_length,
+        output, output_size, output_length);
+#endif
+
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_transparent_cipher_decrypt(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length)
+{
+    mbedtls_test_driver_cipher_hooks.hits++;
+
+    if (mbedtls_test_driver_cipher_hooks.forced_output != NULL) {
+        if (output_size < mbedtls_test_driver_cipher_hooks.forced_output_length) {
+            return PSA_ERROR_BUFFER_TOO_SMALL;
+        }
+
+        memcpy(output,
+               mbedtls_test_driver_cipher_hooks.forced_output,
+               mbedtls_test_driver_cipher_hooks.forced_output_length);
+        *output_length = mbedtls_test_driver_cipher_hooks.forced_output_length;
+
+        return mbedtls_test_driver_cipher_hooks.forced_status;
+    }
+
+    if (mbedtls_test_driver_cipher_hooks.forced_status != PSA_SUCCESS) {
+        return mbedtls_test_driver_cipher_hooks.forced_status;
+    }
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+    defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_CIPHER)
+    return libtestdriver1_mbedtls_psa_cipher_decrypt(
+        (const libtestdriver1_psa_key_attributes_t *) attributes,
+        key_buffer, key_buffer_size,
+        alg, input, input_length,
+        output, output_size, output_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_CIPHER)
+    return mbedtls_psa_cipher_decrypt(
+        attributes, key_buffer, key_buffer_size,
+        alg, input, input_length,
+        output, output_size, output_length);
+#endif
+
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_transparent_cipher_encrypt_setup(
+    mbedtls_transparent_test_driver_cipher_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg)
+{
+    mbedtls_test_driver_cipher_hooks.hits++;
+
+    /* Wiping the entire struct here, instead of member-by-member. This is
+     * useful for the test suite, since it gives a chance of catching memory
+     * corruption errors should the core not have allocated (enough) memory for
+     * our context struct. */
+    memset(operation, 0, sizeof(*operation));
+
+    if (mbedtls_test_driver_cipher_hooks.forced_status != PSA_SUCCESS) {
+        return mbedtls_test_driver_cipher_hooks.forced_status;
+    }
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+    defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_CIPHER)
+    return libtestdriver1_mbedtls_psa_cipher_encrypt_setup(
+        operation,
+        (const libtestdriver1_psa_key_attributes_t *) attributes,
+        key, key_length, alg);
+#elif defined(MBEDTLS_PSA_BUILTIN_CIPHER)
+    return mbedtls_psa_cipher_encrypt_setup(
+        operation, attributes, key, key_length, alg);
+#endif
+
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_transparent_cipher_decrypt_setup(
+    mbedtls_transparent_test_driver_cipher_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg)
+{
+    mbedtls_test_driver_cipher_hooks.hits++;
+
+    if (mbedtls_test_driver_cipher_hooks.forced_status != PSA_SUCCESS) {
+        return mbedtls_test_driver_cipher_hooks.forced_status;
+    }
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+    defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_CIPHER)
+    return libtestdriver1_mbedtls_psa_cipher_decrypt_setup(
+        operation,
+        (const libtestdriver1_psa_key_attributes_t *) attributes,
+        key, key_length, alg);
+#elif defined(MBEDTLS_PSA_BUILTIN_CIPHER)
+    return mbedtls_psa_cipher_decrypt_setup(
+        operation, attributes, key, key_length, alg);
+#endif
+
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_transparent_cipher_abort(
+    mbedtls_transparent_test_driver_cipher_operation_t *operation)
+{
+    mbedtls_test_driver_cipher_hooks.hits++;
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+    defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_CIPHER)
+    libtestdriver1_mbedtls_psa_cipher_abort(operation);
+#elif defined(MBEDTLS_PSA_BUILTIN_CIPHER)
+    mbedtls_psa_cipher_abort(operation);
+#endif
+
+    /* Wiping the entire struct here, instead of member-by-member. This is
+     * useful for the test suite, since it gives a chance of catching memory
+     * corruption errors should the core not have allocated (enough) memory for
+     * our context struct. */
+    memset(operation, 0, sizeof(*operation));
+
+    return mbedtls_test_driver_cipher_hooks.forced_status;
+}
+
+psa_status_t mbedtls_test_transparent_cipher_set_iv(
+    mbedtls_transparent_test_driver_cipher_operation_t *operation,
+    const uint8_t *iv,
+    size_t iv_length)
+{
+    mbedtls_test_driver_cipher_hooks.hits++;
+    mbedtls_test_driver_cipher_hooks.hits_set_iv++;
+
+    if (mbedtls_test_driver_cipher_hooks.forced_status != PSA_SUCCESS) {
+        return mbedtls_test_driver_cipher_hooks.forced_status;
+    }
+    if (mbedtls_test_driver_cipher_hooks.forced_status_set_iv != PSA_SUCCESS) {
+        return mbedtls_test_driver_cipher_hooks.forced_status_set_iv;
+    }
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+    defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_CIPHER)
+    return libtestdriver1_mbedtls_psa_cipher_set_iv(
+        operation, iv, iv_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_CIPHER)
+    return mbedtls_psa_cipher_set_iv(operation, iv, iv_length);
+#endif
+
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_transparent_cipher_update(
+    mbedtls_transparent_test_driver_cipher_operation_t *operation,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length)
+{
+    mbedtls_test_driver_cipher_hooks.hits++;
+
+    if (mbedtls_test_driver_cipher_hooks.forced_output != NULL) {
+        if (output_size < mbedtls_test_driver_cipher_hooks.forced_output_length) {
+            return PSA_ERROR_BUFFER_TOO_SMALL;
+        }
+
+        memcpy(output,
+               mbedtls_test_driver_cipher_hooks.forced_output,
+               mbedtls_test_driver_cipher_hooks.forced_output_length);
+        *output_length = mbedtls_test_driver_cipher_hooks.forced_output_length;
+
+        return mbedtls_test_driver_cipher_hooks.forced_status;
+    }
+
+    if (mbedtls_test_driver_cipher_hooks.forced_status != PSA_SUCCESS) {
+        return mbedtls_test_driver_cipher_hooks.forced_status;
+    }
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+    defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_CIPHER)
+    return libtestdriver1_mbedtls_psa_cipher_update(
+        operation, input, input_length,
+        output, output_size, output_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_CIPHER)
+    return mbedtls_psa_cipher_update(
+        operation, input, input_length,
+        output, output_size, output_length);
+#endif
+
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_transparent_cipher_finish(
+    mbedtls_transparent_test_driver_cipher_operation_t *operation,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length)
+{
+    mbedtls_test_driver_cipher_hooks.hits++;
+
+    if (mbedtls_test_driver_cipher_hooks.forced_output != NULL) {
+        if (output_size < mbedtls_test_driver_cipher_hooks.forced_output_length) {
+            return PSA_ERROR_BUFFER_TOO_SMALL;
+        }
+
+        memcpy(output,
+               mbedtls_test_driver_cipher_hooks.forced_output,
+               mbedtls_test_driver_cipher_hooks.forced_output_length);
+        *output_length = mbedtls_test_driver_cipher_hooks.forced_output_length;
+
+        return mbedtls_test_driver_cipher_hooks.forced_status;
+    }
+
+    if (mbedtls_test_driver_cipher_hooks.forced_status != PSA_SUCCESS) {
+        return mbedtls_test_driver_cipher_hooks.forced_status;
+    }
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+    defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_CIPHER)
+    return libtestdriver1_mbedtls_psa_cipher_finish(
+        operation, output, output_size, output_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_CIPHER)
+    return mbedtls_psa_cipher_finish(
+        operation, output, output_size, output_length);
+#endif
+
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+/*
+ * opaque versions, to do
+ */
+psa_status_t mbedtls_test_opaque_cipher_encrypt(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *iv, size_t iv_length,
+    const uint8_t *input, size_t input_length,
+    uint8_t *output, size_t output_size, size_t *output_length)
+{
+    (void) attributes;
+    (void) key;
+    (void) key_length;
+    (void) alg;
+    (void) iv;
+    (void) iv_length;
+    (void) input;
+    (void) input_length;
+    (void) output;
+    (void) output_size;
+    (void) output_length;
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_opaque_cipher_decrypt(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *input, size_t input_length,
+    uint8_t *output, size_t output_size, size_t *output_length)
+{
+    (void) attributes;
+    (void) key;
+    (void) key_length;
+    (void) alg;
+    (void) input;
+    (void) input_length;
+    (void) output;
+    (void) output_size;
+    (void) output_length;
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_opaque_cipher_encrypt_setup(
+    mbedtls_opaque_test_driver_cipher_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg)
+{
+    (void) operation;
+    (void) attributes;
+    (void) key;
+    (void) key_length;
+    (void) alg;
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_opaque_cipher_decrypt_setup(
+    mbedtls_opaque_test_driver_cipher_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg)
+{
+    (void) operation;
+    (void) attributes;
+    (void) key;
+    (void) key_length;
+    (void) alg;
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_opaque_cipher_abort(
+    mbedtls_opaque_test_driver_cipher_operation_t *operation)
+{
+    (void) operation;
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_opaque_cipher_set_iv(
+    mbedtls_opaque_test_driver_cipher_operation_t *operation,
+    const uint8_t *iv,
+    size_t iv_length)
+{
+    (void) operation;
+    (void) iv;
+    (void) iv_length;
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_opaque_cipher_update(
+    mbedtls_opaque_test_driver_cipher_operation_t *operation,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length)
+{
+    (void) operation;
+    (void) input;
+    (void) input_length;
+    (void) output;
+    (void) output_size;
+    (void) output_length;
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_opaque_cipher_finish(
+    mbedtls_opaque_test_driver_cipher_operation_t *operation,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length)
+{
+    (void) operation;
+    (void) output;
+    (void) output_size;
+    (void) output_length;
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+#endif /* PSA_CRYPTO_DRIVER_TEST */
diff --git a/framework/tests/src/drivers/test_driver_key_agreement.c b/framework/tests/src/drivers/test_driver_key_agreement.c
new file mode 100644
index 0000000..8a7a9ea
--- /dev/null
+++ b/framework/tests/src/drivers/test_driver_key_agreement.c
@@ -0,0 +1,153 @@
+/*
+ * Test driver for key agreement functions.
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <test/helpers.h>
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+
+#include "psa/crypto.h"
+#include "psa_crypto_core.h"
+#include "psa_crypto_ecp.h"
+#include "psa_crypto_ffdh.h"
+
+#include "test/drivers/key_agreement.h"
+#include "test/drivers/test_driver.h"
+
+#include <string.h>
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
+#if MBEDTLS_VERSION_MAJOR < 4
+#include "libtestdriver1/include/psa/crypto.h"
+#include "libtestdriver1/library/psa_crypto_ecp.h"
+#include "libtestdriver1/library/psa_crypto_ffdh.h"
+#else
+#include "libtestdriver1/tf-psa-crypto/include/psa/crypto.h"
+#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.h"
+#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_ffdh.h"
+#endif
+#endif
+
+mbedtls_test_driver_key_agreement_hooks_t
+    mbedtls_test_driver_key_agreement_hooks = MBEDTLS_TEST_DRIVER_KEY_AGREEMENT_INIT;
+
+psa_status_t mbedtls_test_transparent_key_agreement(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *peer_key,
+    size_t peer_key_length,
+    uint8_t *shared_secret,
+    size_t shared_secret_size,
+    size_t *shared_secret_length)
+{
+    mbedtls_test_driver_key_agreement_hooks.hits++;
+
+    if (mbedtls_test_driver_key_agreement_hooks.forced_status != PSA_SUCCESS) {
+        return mbedtls_test_driver_key_agreement_hooks.forced_status;
+    }
+
+    if (mbedtls_test_driver_key_agreement_hooks.forced_output != NULL) {
+        if (mbedtls_test_driver_key_agreement_hooks.forced_output_length > shared_secret_size) {
+            return PSA_ERROR_BUFFER_TOO_SMALL;
+        }
+
+        memcpy(shared_secret, mbedtls_test_driver_key_agreement_hooks.forced_output,
+               mbedtls_test_driver_key_agreement_hooks.forced_output_length);
+        *shared_secret_length = mbedtls_test_driver_key_agreement_hooks.forced_output_length;
+
+        return PSA_SUCCESS;
+    }
+
+    if (PSA_ALG_IS_ECDH(alg)) {
+#if (defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_ALG_ECDH))
+        return libtestdriver1_mbedtls_psa_key_agreement_ecdh(
+            (const libtestdriver1_psa_key_attributes_t *) attributes,
+            key_buffer, key_buffer_size,
+            alg, peer_key, peer_key_length,
+            shared_secret, shared_secret_size,
+            shared_secret_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH)
+        return mbedtls_psa_key_agreement_ecdh(
+            attributes,
+            key_buffer, key_buffer_size,
+            alg, peer_key, peer_key_length,
+            shared_secret, shared_secret_size,
+            shared_secret_length);
+#else
+        (void) attributes;
+        (void) key_buffer;
+        (void) key_buffer_size;
+        (void) peer_key;
+        (void) peer_key_length;
+        (void) shared_secret;
+        (void) shared_secret_size;
+        (void) shared_secret_length;
+        return PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+    if (PSA_ALG_IS_FFDH(alg)) {
+#if (defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_ALG_FFDH))
+        return libtestdriver1_mbedtls_psa_ffdh_key_agreement(
+            (const libtestdriver1_psa_key_attributes_t *) attributes,
+            peer_key, peer_key_length,
+            key_buffer, key_buffer_size,
+            shared_secret, shared_secret_size,
+            shared_secret_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_ALG_FFDH)
+        return mbedtls_psa_ffdh_key_agreement(
+            attributes,
+            peer_key,
+            peer_key_length,
+            key_buffer,
+            key_buffer_size,
+            shared_secret,
+            shared_secret_size,
+            shared_secret_length);
+#else
+        (void) attributes;
+        (void) key_buffer;
+        (void) key_buffer_size;
+        (void) peer_key;
+        (void) peer_key_length;
+        (void) shared_secret;
+        (void) shared_secret_size;
+        (void) shared_secret_length;
+        return PSA_ERROR_NOT_SUPPORTED;
+#endif
+    } else {
+        return PSA_ERROR_INVALID_ARGUMENT;
+    }
+
+}
+
+psa_status_t mbedtls_test_opaque_key_agreement(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *peer_key,
+    size_t peer_key_length,
+    uint8_t *shared_secret,
+    size_t shared_secret_size,
+    size_t *shared_secret_length)
+{
+    (void) attributes;
+    (void) key_buffer;
+    (void) key_buffer_size;
+    (void) alg;
+    (void) peer_key;
+    (void) peer_key_length;
+    (void) shared_secret;
+    (void) shared_secret_size;
+    (void) shared_secret_length;
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
diff --git a/framework/tests/src/drivers/test_driver_key_management.c b/framework/tests/src/drivers/test_driver_key_management.c
new file mode 100644
index 0000000..d2ca157
--- /dev/null
+++ b/framework/tests/src/drivers/test_driver_key_management.c
@@ -0,0 +1,794 @@
+/*
+ * Test driver for generating and verifying keys.
+ * Currently only supports generating and verifying ECC keys.
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <test/helpers.h>
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include "psa/crypto.h"
+#include "psa_crypto_core.h"
+#include "psa_crypto_ecp.h"
+#include "psa_crypto_rsa.h"
+#include "psa_crypto_ffdh.h"
+#include "mbedtls/ecp.h"
+#include "mbedtls/error.h"
+
+#include "test/drivers/key_management.h"
+#include "test/drivers/test_driver.h"
+
+#include "test/random.h"
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
+#if MBEDTLS_VERSION_MAJOR < 4
+#include "libtestdriver1/library/psa_crypto_ecp.h"
+#include "libtestdriver1/library/psa_crypto_rsa.h"
+#include "libtestdriver1/library/psa_crypto_ffdh.h"
+#else
+#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.h"
+#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_rsa.h"
+#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_ffdh.h"
+#endif
+#endif
+
+#include <string.h>
+
+mbedtls_test_driver_key_management_hooks_t
+    mbedtls_test_driver_key_management_hooks = MBEDTLS_TEST_DRIVER_KEY_MANAGEMENT_INIT;
+
+const uint8_t mbedtls_test_driver_aes_key[16] =
+{ 0x36, 0x77, 0x39, 0x7A, 0x24, 0x43, 0x26, 0x46,
+  0x29, 0x4A, 0x40, 0x4E, 0x63, 0x52, 0x66, 0x55 };
+const uint8_t mbedtls_test_driver_ecdsa_key[32] =
+{ 0xdc, 0x7d, 0x9d, 0x26, 0xd6, 0x7a, 0x4f, 0x63,
+  0x2c, 0x34, 0xc2, 0xdc, 0x0b, 0x69, 0x86, 0x18,
+  0x38, 0x82, 0xc2, 0x06, 0xdf, 0x04, 0xcd, 0xb7,
+  0xd6, 0x9a, 0xab, 0xe2, 0x8b, 0xe4, 0xf8, 0x1a };
+const uint8_t mbedtls_test_driver_ecdsa_pubkey[65] =
+{ 0x04,
+  0x85, 0xf6, 0x4d, 0x89, 0xf0, 0x0b, 0xe6, 0x6c,
+  0x88, 0xdd, 0x93, 0x7e, 0xfd, 0x6d, 0x7c, 0x44,
+  0x56, 0x48, 0xdc, 0xb7, 0x01, 0x15, 0x0b, 0x8a,
+  0x95, 0x09, 0x29, 0x58, 0x50, 0xf4, 0x1c, 0x19,
+  0x31, 0xe5, 0x71, 0xfb, 0x8f, 0x8c, 0x78, 0x31,
+  0x7a, 0x20, 0xb3, 0x80, 0xe8, 0x66, 0x58, 0x4b,
+  0xbc, 0x25, 0x16, 0xc3, 0xd2, 0x70, 0x2d, 0x79,
+  0x2f, 0x13, 0x1a, 0x92, 0x20, 0x95, 0xfd, 0x6c };
+
+psa_status_t mbedtls_test_transparent_init(void)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
+    status = libtestdriver1_psa_crypto_init();
+    if (status != PSA_SUCCESS) {
+        return status;
+    }
+#endif
+
+    (void) status;
+    return PSA_SUCCESS;
+}
+
+void mbedtls_test_transparent_free(void)
+{
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
+    libtestdriver1_mbedtls_psa_crypto_free();
+#endif
+
+    return;
+}
+
+psa_status_t mbedtls_test_opaque_init(void)
+{
+    return PSA_SUCCESS;
+}
+
+void mbedtls_test_opaque_free(void)
+{
+    return;
+}
+
+/*
+ * This macro returns the base size for the key context when SE does not
+ * support storage. It is the size of the metadata that gets added to the
+ * wrapped key. In its test functionality the metadata is just some padded
+ * prefixing to the key.
+ */
+#define TEST_DRIVER_KEY_CONTEXT_BASE_SIZE  \
+    PSA_CRYPTO_TEST_DRIVER_OPAQUE_PAD_PREFIX_SIZE
+
+
+size_t mbedtls_test_opaque_size_function(
+    const psa_key_type_t key_type,
+    const size_t key_bits)
+{
+    size_t key_buffer_size = 0;
+
+    key_buffer_size = PSA_EXPORT_KEY_OUTPUT_SIZE(key_type, key_bits);
+    if (key_buffer_size == 0) {
+        return 0;
+    }
+    /* Include spacing for base size overhead over the key size
+     * */
+    key_buffer_size += TEST_DRIVER_KEY_CONTEXT_BASE_SIZE;
+    return key_buffer_size;
+}
+
+static size_t mbedtls_test_opaque_get_base_size()
+{
+    return TEST_DRIVER_KEY_CONTEXT_BASE_SIZE;
+}
+
+/*
+ * The wrap function mbedtls_test_opaque_wrap_key pads and wraps the
+ * clear key. It expects the clear and wrap buffers to be passed in.
+ * key_length is the size of the clear key to be wrapped.
+ * wrapped_key_buffer_size is the size of the output buffer wrap_key.
+ * The argument wrapped_key_buffer_length is filled with the wrapped
+ * key_size on success.
+ * */
+static psa_status_t mbedtls_test_opaque_wrap_key(
+    const uint8_t *key,
+    size_t key_length,
+    uint8_t *wrapped_key_buffer,
+    size_t wrapped_key_buffer_size,
+    size_t *wrapped_key_buffer_length)
+{
+    size_t opaque_key_base_size = mbedtls_test_opaque_get_base_size();
+    uint64_t prefix = PSA_CRYPTO_TEST_DRIVER_OPAQUE_PAD_PREFIX;
+
+    if (key_length + opaque_key_base_size > wrapped_key_buffer_size) {
+        return PSA_ERROR_BUFFER_TOO_SMALL;
+    }
+
+    /* Write in the opaque pad prefix */
+    memcpy(wrapped_key_buffer, &prefix, opaque_key_base_size);
+    wrapped_key_buffer += opaque_key_base_size;
+    *wrapped_key_buffer_length = key_length + opaque_key_base_size;
+
+    while (key_length--) {
+        wrapped_key_buffer[key_length] = key[key_length] ^ 0xFF;
+    }
+    return PSA_SUCCESS;
+}
+
+/*
+ * The unwrap function mbedtls_test_opaque_unwrap_key removes a pad prefix
+ * and unwraps the wrapped key. It expects the clear and wrap buffers to be
+ * passed in.
+ * wrapped_key_length is the size of the wrapped key,
+ * key_buffer_size is the size of the output buffer clear_key.
+ * The argument key_buffer_length is filled with the unwrapped(clear)
+ * key_size on success.
+ * */
+psa_status_t mbedtls_test_opaque_unwrap_key(
+    const uint8_t *wrapped_key,
+    size_t wrapped_key_length,
+    uint8_t *key_buffer,
+    size_t key_buffer_size,
+    size_t *key_buffer_length)
+{
+    /* Remove the pad prefix from the wrapped key */
+    size_t opaque_key_base_size = mbedtls_test_opaque_get_base_size();
+    size_t clear_key_size;
+
+    /* Check for underflow */
+    if (wrapped_key_length < opaque_key_base_size) {
+        return PSA_ERROR_DATA_CORRUPT;
+    }
+    clear_key_size = wrapped_key_length - opaque_key_base_size;
+
+    wrapped_key += opaque_key_base_size;
+    if (clear_key_size > key_buffer_size) {
+        return PSA_ERROR_BUFFER_TOO_SMALL;
+    }
+
+    *key_buffer_length = clear_key_size;
+    while (clear_key_size--) {
+        key_buffer[clear_key_size] = wrapped_key[clear_key_size] ^ 0xFF;
+    }
+    return PSA_SUCCESS;
+}
+
+psa_status_t mbedtls_test_transparent_generate_key(
+    const psa_key_attributes_t *attributes,
+    uint8_t *key, size_t key_size, size_t *key_length)
+{
+    ++mbedtls_test_driver_key_management_hooks.hits;
+    ++mbedtls_test_driver_key_management_hooks.hits_generate_key;
+
+    if (mbedtls_test_driver_key_management_hooks.forced_status != PSA_SUCCESS) {
+        return mbedtls_test_driver_key_management_hooks.forced_status;
+    }
+
+    if (mbedtls_test_driver_key_management_hooks.forced_output != NULL) {
+        if (mbedtls_test_driver_key_management_hooks.forced_output_length >
+            key_size) {
+            return PSA_ERROR_BUFFER_TOO_SMALL;
+        }
+        memcpy(key, mbedtls_test_driver_key_management_hooks.forced_output,
+               mbedtls_test_driver_key_management_hooks.forced_output_length);
+        *key_length = mbedtls_test_driver_key_management_hooks.forced_output_length;
+        return PSA_SUCCESS;
+    }
+
+    if (PSA_KEY_TYPE_IS_ECC(psa_get_key_type(attributes))
+        && PSA_KEY_TYPE_IS_KEY_PAIR(psa_get_key_type(attributes))) {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE)
+        return libtestdriver1_mbedtls_psa_ecp_generate_key(
+            (const libtestdriver1_psa_key_attributes_t *) attributes,
+            key, key_size, key_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE)
+        return mbedtls_psa_ecp_generate_key(
+            attributes, key, key_size, key_length);
+#endif
+    } else if (psa_get_key_type(attributes) == PSA_KEY_TYPE_RSA_KEY_PAIR) {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE)
+        return libtestdriver1_mbedtls_psa_rsa_generate_key(
+            (const libtestdriver1_psa_key_attributes_t *) attributes,
+            NULL, 0, /* We don't support custom e in the test driver yet */
+            key, key_size, key_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE)
+        return mbedtls_psa_rsa_generate_key(
+            attributes,
+            NULL, 0, /* We don't support custom e in the test driver yet */
+            key, key_size, key_length);
+#endif
+    } else if (PSA_KEY_TYPE_IS_DH(psa_get_key_type(attributes))
+               && PSA_KEY_TYPE_IS_KEY_PAIR(psa_get_key_type(attributes))) {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_GENERATE)
+        return libtestdriver1_mbedtls_psa_ffdh_generate_key(
+            (const libtestdriver1_psa_key_attributes_t *) attributes,
+            key, key_size, key_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR)
+        return mbedtls_psa_ffdh_generate_key(
+            attributes, key, key_size, key_length);
+#endif
+    }
+
+    (void) attributes;
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_opaque_generate_key(
+    const psa_key_attributes_t *attributes,
+    uint8_t *key, size_t key_size, size_t *key_length)
+{
+    (void) attributes;
+    (void) key;
+    (void) key_size;
+    (void) key_length;
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_transparent_import_key(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *data,
+    size_t data_length,
+    uint8_t *key_buffer,
+    size_t key_buffer_size,
+    size_t *key_buffer_length,
+    size_t *bits)
+{
+    psa_key_type_t type = psa_get_key_type(attributes);
+
+    ++mbedtls_test_driver_key_management_hooks.hits;
+    mbedtls_test_driver_key_management_hooks.location = PSA_KEY_LOCATION_LOCAL_STORAGE;
+
+    if (mbedtls_test_driver_key_management_hooks.forced_status != PSA_SUCCESS) {
+        return mbedtls_test_driver_key_management_hooks.forced_status;
+    }
+
+    if (PSA_KEY_TYPE_IS_ECC(type)) {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        (defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY))
+        return libtestdriver1_mbedtls_psa_ecp_import_key(
+            (const libtestdriver1_psa_key_attributes_t *) attributes,
+            data, data_length,
+            key_buffer, key_buffer_size,
+            key_buffer_length, bits);
+#elif defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \
+        defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY)
+        return mbedtls_psa_ecp_import_key(
+            attributes,
+            data, data_length,
+            key_buffer, key_buffer_size,
+            key_buffer_length, bits);
+#endif
+    } else if (PSA_KEY_TYPE_IS_RSA(type)) {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        (defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_IMPORT) || \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY))
+        return libtestdriver1_mbedtls_psa_rsa_import_key(
+            (const libtestdriver1_psa_key_attributes_t *) attributes,
+            data, data_length,
+            key_buffer, key_buffer_size,
+            key_buffer_length, bits);
+#elif defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_IMPORT) || \
+        defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY)
+        return mbedtls_psa_rsa_import_key(
+            attributes,
+            data, data_length,
+            key_buffer, key_buffer_size,
+            key_buffer_length, bits);
+#endif
+    } else if (PSA_KEY_TYPE_IS_DH(type)) {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        (defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR) || \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_PUBLIC_KEY))
+        return libtestdriver1_mbedtls_psa_ffdh_import_key(
+            (const libtestdriver1_psa_key_attributes_t *) attributes,
+            data, data_length,
+            key_buffer, key_buffer_size,
+            key_buffer_length, bits);
+#elif defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR) || \
+        defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY)
+        return mbedtls_psa_ffdh_import_key(
+            attributes,
+            data, data_length,
+            key_buffer, key_buffer_size,
+            key_buffer_length, bits);
+#endif
+    }
+    (void) data;
+    (void) data_length;
+    (void) key_buffer;
+    (void) key_buffer_size;
+    (void) key_buffer_length;
+    (void) bits;
+    (void) type;
+
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+
+psa_status_t mbedtls_test_opaque_import_key(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *data,
+    size_t data_length,
+    uint8_t *key_buffer,
+    size_t key_buffer_size,
+    size_t *key_buffer_length,
+    size_t *bits)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    psa_key_type_t type = psa_get_key_type(attributes);
+    /* This buffer will be used as an intermediate placeholder for
+     * the clear key till we wrap it */
+    uint8_t *key_buffer_temp;
+
+    ++mbedtls_test_driver_key_management_hooks.hits;
+    mbedtls_test_driver_key_management_hooks.location = PSA_CRYPTO_TEST_DRIVER_LOCATION;
+
+    if (mbedtls_test_driver_key_management_hooks.forced_status != PSA_SUCCESS) {
+        return mbedtls_test_driver_key_management_hooks.forced_status;
+    }
+
+    key_buffer_temp = mbedtls_calloc(1, key_buffer_size);
+    if (key_buffer_temp == NULL) {
+        return PSA_ERROR_INSUFFICIENT_MEMORY;
+    }
+
+    if (PSA_KEY_TYPE_IS_UNSTRUCTURED(type)) {
+        *bits = PSA_BYTES_TO_BITS(data_length);
+
+        status = psa_validate_unstructured_key_bit_size(type,
+                                                        *bits);
+        if (status != PSA_SUCCESS) {
+            goto exit;
+        }
+
+        if (data_length > key_buffer_size) {
+            return PSA_ERROR_BUFFER_TOO_SMALL;
+        }
+
+        /* Copy the key material accounting for opaque key padding. */
+        memcpy(key_buffer_temp, data, data_length);
+        *key_buffer_length = data_length;
+    } else if (PSA_KEY_TYPE_IS_ECC(type)) {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        (defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR) || \
+        defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_PUBLIC_KEY))
+        status = libtestdriver1_mbedtls_psa_ecp_import_key(
+            (const libtestdriver1_psa_key_attributes_t *) attributes,
+            data, data_length,
+            key_buffer_temp, key_buffer_size,
+            key_buffer_length, bits);
+#elif defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \
+        defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY)
+        status = mbedtls_psa_ecp_import_key(
+            attributes,
+            data, data_length,
+            key_buffer_temp, key_buffer_size,
+            key_buffer_length, bits);
+#else
+        status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+        if (status != PSA_SUCCESS) {
+            goto exit;
+        }
+    } else if (PSA_KEY_TYPE_IS_RSA(type)) {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        (defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_KEY_PAIR) || \
+        defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_PUBLIC_KEY))
+        status = libtestdriver1_mbedtls_psa_rsa_import_key(
+            (const libtestdriver1_psa_key_attributes_t *) attributes,
+            data, data_length,
+            key_buffer_temp, key_buffer_size,
+            key_buffer_length, bits);
+#elif defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_IMPORT) || \
+        defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY)
+        status = mbedtls_psa_rsa_import_key(
+            attributes,
+            data, data_length,
+            key_buffer_temp, key_buffer_size,
+            key_buffer_length, bits);
+#else
+        status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+        if (status != PSA_SUCCESS) {
+            goto exit;
+        }
+    } else {
+        status = PSA_ERROR_INVALID_ARGUMENT;
+        goto exit;
+    }
+
+    status = mbedtls_test_opaque_wrap_key(key_buffer_temp, *key_buffer_length,
+                                          key_buffer, key_buffer_size, key_buffer_length);
+exit:
+    mbedtls_free(key_buffer_temp);
+    return status;
+}
+
+psa_status_t mbedtls_test_opaque_export_key(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    uint8_t *data, size_t data_size, size_t *data_length)
+{
+    if (key_length == sizeof(psa_drv_slot_number_t)) {
+        /* Assume this is a builtin key based on the key material length. */
+        psa_drv_slot_number_t slot_number = *((psa_drv_slot_number_t *) key);
+
+        switch (slot_number) {
+            case PSA_CRYPTO_TEST_DRIVER_BUILTIN_ECDSA_KEY_SLOT:
+                /* This is the ECDSA slot. Verify the key's attributes before
+                 * returning the private key. */
+                if (psa_get_key_type(attributes) !=
+                    PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)) {
+                    return PSA_ERROR_CORRUPTION_DETECTED;
+                }
+                if (psa_get_key_bits(attributes) != 256) {
+                    return PSA_ERROR_CORRUPTION_DETECTED;
+                }
+                if (psa_get_key_algorithm(attributes) !=
+                    PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)) {
+                    return PSA_ERROR_CORRUPTION_DETECTED;
+                }
+                if ((psa_get_key_usage_flags(attributes) &
+                     PSA_KEY_USAGE_EXPORT) == 0) {
+                    return PSA_ERROR_CORRUPTION_DETECTED;
+                }
+
+                if (data_size < sizeof(mbedtls_test_driver_ecdsa_key)) {
+                    return PSA_ERROR_BUFFER_TOO_SMALL;
+                }
+
+                memcpy(data, mbedtls_test_driver_ecdsa_key,
+                       sizeof(mbedtls_test_driver_ecdsa_key));
+                *data_length = sizeof(mbedtls_test_driver_ecdsa_key);
+                return PSA_SUCCESS;
+
+            case PSA_CRYPTO_TEST_DRIVER_BUILTIN_AES_KEY_SLOT:
+                /* This is the AES slot. Verify the key's attributes before
+                 * returning the key. */
+                if (psa_get_key_type(attributes) != PSA_KEY_TYPE_AES) {
+                    return PSA_ERROR_CORRUPTION_DETECTED;
+                }
+                if (psa_get_key_bits(attributes) != 128) {
+                    return PSA_ERROR_CORRUPTION_DETECTED;
+                }
+                if (psa_get_key_algorithm(attributes) != PSA_ALG_CTR) {
+                    return PSA_ERROR_CORRUPTION_DETECTED;
+                }
+                if ((psa_get_key_usage_flags(attributes) &
+                     PSA_KEY_USAGE_EXPORT) == 0) {
+                    return PSA_ERROR_CORRUPTION_DETECTED;
+                }
+
+                if (data_size < sizeof(mbedtls_test_driver_aes_key)) {
+                    return PSA_ERROR_BUFFER_TOO_SMALL;
+                }
+
+                memcpy(data, mbedtls_test_driver_aes_key,
+                       sizeof(mbedtls_test_driver_aes_key));
+                *data_length = sizeof(mbedtls_test_driver_aes_key);
+                return PSA_SUCCESS;
+
+            default:
+                return PSA_ERROR_DOES_NOT_EXIST;
+        }
+    } else {
+        /* This buffer will be used as an intermediate placeholder for
+         * the opaque key till we unwrap the key into key_buffer */
+        psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+        psa_key_type_t type = psa_get_key_type(attributes);
+
+        if (PSA_KEY_TYPE_IS_UNSTRUCTURED(type) ||
+            PSA_KEY_TYPE_IS_RSA(type)   ||
+            PSA_KEY_TYPE_IS_ECC(type)) {
+            status = mbedtls_test_opaque_unwrap_key(key, key_length,
+                                                    data, data_size, data_length);
+            return status;
+        }
+    }
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_transparent_export_public_key(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer, size_t key_buffer_size,
+    uint8_t *data, size_t data_size, size_t *data_length)
+{
+    ++mbedtls_test_driver_key_management_hooks.hits;
+    ++mbedtls_test_driver_key_management_hooks.hits_export_public_key;
+
+    if (mbedtls_test_driver_key_management_hooks.forced_status != PSA_SUCCESS) {
+        return mbedtls_test_driver_key_management_hooks.forced_status;
+    }
+
+    if (mbedtls_test_driver_key_management_hooks.forced_output != NULL) {
+        if (mbedtls_test_driver_key_management_hooks.forced_output_length >
+            data_size) {
+            return PSA_ERROR_BUFFER_TOO_SMALL;
+        }
+        memcpy(data, mbedtls_test_driver_key_management_hooks.forced_output,
+               mbedtls_test_driver_key_management_hooks.forced_output_length);
+        *data_length = mbedtls_test_driver_key_management_hooks.forced_output_length;
+        return PSA_SUCCESS;
+    }
+
+    psa_key_type_t key_type = psa_get_key_type(attributes);
+
+    if (PSA_KEY_TYPE_IS_ECC(key_type)) {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        (defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY))
+        return libtestdriver1_mbedtls_psa_ecp_export_public_key(
+            (const libtestdriver1_psa_key_attributes_t *) attributes,
+            key_buffer, key_buffer_size,
+            data, data_size, data_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \
+        defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY)
+        return mbedtls_psa_ecp_export_public_key(
+            attributes,
+            key_buffer, key_buffer_size,
+            data, data_size, data_length);
+#endif
+    } else if (PSA_KEY_TYPE_IS_RSA(key_type)) {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        (defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT) || \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY))
+        return libtestdriver1_mbedtls_psa_rsa_export_public_key(
+            (const libtestdriver1_psa_key_attributes_t *) attributes,
+            key_buffer, key_buffer_size,
+            data, data_size, data_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT) || \
+        defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY)
+        return mbedtls_psa_rsa_export_public_key(
+            attributes,
+            key_buffer, key_buffer_size,
+            data, data_size, data_length);
+#endif
+    } else if (PSA_KEY_TYPE_IS_DH(key_type)) {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        (defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR) || \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_PUBLIC_KEY))
+        return libtestdriver1_mbedtls_psa_ffdh_export_public_key(
+            (const libtestdriver1_psa_key_attributes_t *) attributes,
+            key_buffer, key_buffer_size,
+            data, data_size, data_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR) || \
+        defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_PUBLIC_KEY)
+        return mbedtls_psa_ffdh_export_public_key(
+            attributes,
+            key_buffer, key_buffer_size,
+            data, data_size, data_length);
+#endif
+    }
+
+    (void) key_buffer;
+    (void) key_buffer_size;
+    (void) key_type;
+
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_opaque_export_public_key(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    uint8_t *data, size_t data_size, size_t *data_length)
+{
+    if (key_length != sizeof(psa_drv_slot_number_t)) {
+        psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+        psa_key_type_t key_type = psa_get_key_type(attributes);
+        uint8_t *key_buffer_temp;
+
+        key_buffer_temp = mbedtls_calloc(1, key_length);
+        if (key_buffer_temp == NULL) {
+            return PSA_ERROR_INSUFFICIENT_MEMORY;
+        }
+
+        if (PSA_KEY_TYPE_IS_ECC(key_type)) {
+            status = mbedtls_test_opaque_unwrap_key(key, key_length,
+                                                    key_buffer_temp, key_length, data_length);
+            if (status == PSA_SUCCESS) {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+                (defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR) || \
+                defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_PUBLIC_KEY))
+                status = libtestdriver1_mbedtls_psa_ecp_export_public_key(
+                    (const libtestdriver1_psa_key_attributes_t *) attributes,
+                    key_buffer_temp, *data_length,
+                    data, data_size, data_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \
+                defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY)
+                status = mbedtls_psa_ecp_export_public_key(
+                    attributes,
+                    key_buffer_temp, *data_length,
+                    data, data_size, data_length);
+#else
+                status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+            }
+        } else if (PSA_KEY_TYPE_IS_RSA(key_type)) {
+            status = mbedtls_test_opaque_unwrap_key(key, key_length,
+                                                    key_buffer_temp, key_length, data_length);
+            if (status == PSA_SUCCESS) {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+                (defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_KEY_PAIR) || \
+                defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_PUBLIC_KEY))
+                status = libtestdriver1_mbedtls_psa_rsa_export_public_key(
+                    (const libtestdriver1_psa_key_attributes_t *) attributes,
+                    key_buffer_temp, *data_length,
+                    data, data_size, data_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT) || \
+                defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY)
+                status = mbedtls_psa_rsa_export_public_key(
+                    attributes,
+                    key_buffer_temp, *data_length,
+                    data, data_size, data_length);
+#else
+                status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+            }
+        } else {
+            status = PSA_ERROR_NOT_SUPPORTED;
+            (void) key;
+            (void) key_type;
+        }
+        mbedtls_free(key_buffer_temp);
+        return status;
+    }
+
+    /* Assume this is a builtin key based on the key material length. */
+    psa_drv_slot_number_t slot_number = *((psa_drv_slot_number_t *) key);
+    switch (slot_number) {
+        case PSA_CRYPTO_TEST_DRIVER_BUILTIN_ECDSA_KEY_SLOT:
+            /* This is the ECDSA slot. Verify the key's attributes before
+             * returning the public key. */
+            if (psa_get_key_type(attributes) !=
+                PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)) {
+                return PSA_ERROR_CORRUPTION_DETECTED;
+            }
+            if (psa_get_key_bits(attributes) != 256) {
+                return PSA_ERROR_CORRUPTION_DETECTED;
+            }
+            if (psa_get_key_algorithm(attributes) !=
+                PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)) {
+                return PSA_ERROR_CORRUPTION_DETECTED;
+            }
+
+            if (data_size < sizeof(mbedtls_test_driver_ecdsa_pubkey)) {
+                return PSA_ERROR_BUFFER_TOO_SMALL;
+            }
+
+            memcpy(data, mbedtls_test_driver_ecdsa_pubkey,
+                   sizeof(mbedtls_test_driver_ecdsa_pubkey));
+            *data_length = sizeof(mbedtls_test_driver_ecdsa_pubkey);
+            return PSA_SUCCESS;
+
+        default:
+            return PSA_ERROR_DOES_NOT_EXIST;
+    }
+}
+
+/* The opaque test driver exposes two built-in keys when builtin key support is
+ * compiled in.
+ * The key in slot #PSA_CRYPTO_TEST_DRIVER_BUILTIN_AES_KEY_SLOT is an AES-128
+ * key which allows CTR mode.
+ * The key in slot #PSA_CRYPTO_TEST_DRIVER_BUILTIN_ECDSA_KEY_SLOT is a secp256r1
+ * private key which allows ECDSA sign & verify.
+ * The key buffer format for these is the raw format of psa_drv_slot_number_t
+ * (i.e. for an actual driver this would mean 'builtin_key_size' =
+ * sizeof(psa_drv_slot_number_t)).
+ */
+psa_status_t mbedtls_test_opaque_get_builtin_key(
+    psa_drv_slot_number_t slot_number,
+    psa_key_attributes_t *attributes,
+    uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length)
+{
+    switch (slot_number) {
+        case PSA_CRYPTO_TEST_DRIVER_BUILTIN_AES_KEY_SLOT:
+            psa_set_key_type(attributes, PSA_KEY_TYPE_AES);
+            psa_set_key_bits(attributes, 128);
+            psa_set_key_usage_flags(
+                attributes,
+                PSA_KEY_USAGE_ENCRYPT |
+                PSA_KEY_USAGE_DECRYPT |
+                PSA_KEY_USAGE_EXPORT);
+            psa_set_key_algorithm(attributes, PSA_ALG_CTR);
+
+            if (key_buffer_size < sizeof(psa_drv_slot_number_t)) {
+                return PSA_ERROR_BUFFER_TOO_SMALL;
+            }
+
+            *((psa_drv_slot_number_t *) key_buffer) =
+                PSA_CRYPTO_TEST_DRIVER_BUILTIN_AES_KEY_SLOT;
+            *key_buffer_length = sizeof(psa_drv_slot_number_t);
+            return PSA_SUCCESS;
+        case PSA_CRYPTO_TEST_DRIVER_BUILTIN_ECDSA_KEY_SLOT:
+            psa_set_key_type(
+                attributes,
+                PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
+            psa_set_key_bits(attributes, 256);
+            psa_set_key_usage_flags(
+                attributes,
+                PSA_KEY_USAGE_SIGN_HASH |
+                PSA_KEY_USAGE_VERIFY_HASH |
+                PSA_KEY_USAGE_EXPORT);
+            psa_set_key_algorithm(
+                attributes, PSA_ALG_ECDSA(PSA_ALG_ANY_HASH));
+
+            if (key_buffer_size < sizeof(psa_drv_slot_number_t)) {
+                return PSA_ERROR_BUFFER_TOO_SMALL;
+            }
+
+            *((psa_drv_slot_number_t *) key_buffer) =
+                PSA_CRYPTO_TEST_DRIVER_BUILTIN_ECDSA_KEY_SLOT;
+            *key_buffer_length = sizeof(psa_drv_slot_number_t);
+            return PSA_SUCCESS;
+        default:
+            return PSA_ERROR_DOES_NOT_EXIST;
+    }
+}
+
+psa_status_t mbedtls_test_opaque_copy_key(
+    psa_key_attributes_t *attributes,
+    const uint8_t *source_key, size_t source_key_length,
+    uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length)
+{
+    /* This is a case where the opaque test driver emulates an SE without storage.
+     * With that all key context is stored in the wrapped buffer.
+     * So no additional house keeping is necessary to reference count the
+     * copied keys. This could change when the opaque test driver is extended
+     * to support SE with storage, or to emulate an SE without storage but
+     * still holding some slot references */
+    if (source_key_length > key_buffer_size) {
+        return PSA_ERROR_BUFFER_TOO_SMALL;
+    }
+
+    memcpy(key_buffer, source_key, source_key_length);
+    *key_buffer_length = source_key_length;
+    (void) attributes;
+    return PSA_SUCCESS;
+}
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
diff --git a/framework/tests/src/drivers/test_driver_mac.c b/framework/tests/src/drivers/test_driver_mac.c
new file mode 100644
index 0000000..f1cf504
--- /dev/null
+++ b/framework/tests/src/drivers/test_driver_mac.c
@@ -0,0 +1,426 @@
+/*
+ * Test driver for MAC entry points.
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <test/helpers.h>
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include "psa_crypto_mac.h"
+
+#include "test/drivers/mac.h"
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
+#if MBEDTLS_VERSION_MAJOR < 4
+#include "libtestdriver1/library/psa_crypto_mac.h"
+#else
+#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_mac.h"
+#endif
+#endif
+
+mbedtls_test_driver_mac_hooks_t mbedtls_test_driver_mac_hooks =
+    MBEDTLS_TEST_DRIVER_MAC_INIT;
+
+psa_status_t mbedtls_test_transparent_mac_compute(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *mac,
+    size_t mac_size,
+    size_t *mac_length)
+{
+    mbedtls_test_driver_mac_hooks.hits++;
+
+    if (mbedtls_test_driver_mac_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_test_driver_mac_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_MAC)
+        mbedtls_test_driver_mac_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_mac_compute(
+                (const libtestdriver1_psa_key_attributes_t *) attributes,
+                key_buffer, key_buffer_size, alg,
+                input, input_length,
+                mac, mac_size, mac_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_MAC)
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_psa_mac_compute(
+                attributes, key_buffer, key_buffer_size, alg,
+                input, input_length,
+                mac, mac_size, mac_length);
+#else
+        (void) attributes;
+        (void) key_buffer;
+        (void) key_buffer_size;
+        (void) alg;
+        (void) input;
+        (void) input_length;
+        (void) mac;
+        (void) mac_size;
+        (void) mac_length;
+        mbedtls_test_driver_mac_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_mac_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_mac_sign_setup(
+    mbedtls_transparent_test_driver_mac_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg)
+{
+    mbedtls_test_driver_mac_hooks.hits++;
+
+    if (mbedtls_test_driver_mac_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_test_driver_mac_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_MAC)
+        mbedtls_test_driver_mac_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_mac_sign_setup(
+                operation,
+                (const libtestdriver1_psa_key_attributes_t *) attributes,
+                key_buffer, key_buffer_size, alg);
+#elif defined(MBEDTLS_PSA_BUILTIN_MAC)
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_psa_mac_sign_setup(
+                operation, attributes, key_buffer, key_buffer_size, alg);
+#else
+        (void) operation;
+        (void) attributes;
+        (void) key_buffer;
+        (void) key_buffer_size;
+        (void) alg;
+        mbedtls_test_driver_mac_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_mac_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_mac_verify_setup(
+    mbedtls_transparent_test_driver_mac_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg)
+{
+    mbedtls_test_driver_mac_hooks.hits++;
+
+    if (mbedtls_test_driver_mac_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_test_driver_mac_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_MAC)
+        mbedtls_test_driver_mac_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_mac_verify_setup(
+                operation,
+                (const libtestdriver1_psa_key_attributes_t *) attributes,
+                key_buffer, key_buffer_size, alg);
+#elif defined(MBEDTLS_PSA_BUILTIN_MAC)
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_psa_mac_verify_setup(
+                operation, attributes, key_buffer, key_buffer_size, alg);
+#else
+        (void) operation;
+        (void) attributes;
+        (void) key_buffer;
+        (void) key_buffer_size;
+        (void) alg;
+        mbedtls_test_driver_mac_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_mac_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_mac_update(
+    mbedtls_transparent_test_driver_mac_operation_t *operation,
+    const uint8_t *input,
+    size_t input_length)
+{
+    mbedtls_test_driver_mac_hooks.hits++;
+
+    if (mbedtls_test_driver_mac_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_test_driver_mac_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_MAC)
+        mbedtls_test_driver_mac_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_mac_update(
+                operation, input, input_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_MAC)
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_psa_mac_update(
+                operation, input, input_length);
+#else
+        (void) operation;
+        (void) input;
+        (void) input_length;
+        mbedtls_test_driver_mac_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_mac_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_mac_sign_finish(
+    mbedtls_transparent_test_driver_mac_operation_t *operation,
+    uint8_t *mac,
+    size_t mac_size,
+    size_t *mac_length)
+{
+    mbedtls_test_driver_mac_hooks.hits++;
+
+    if (mbedtls_test_driver_mac_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_test_driver_mac_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_MAC)
+        mbedtls_test_driver_mac_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_mac_sign_finish(
+                operation, mac, mac_size, mac_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_MAC)
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_psa_mac_sign_finish(
+                operation, mac, mac_size, mac_length);
+#else
+        (void) operation;
+        (void) mac;
+        (void) mac_size;
+        (void) mac_length;
+        mbedtls_test_driver_mac_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_mac_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_mac_verify_finish(
+    mbedtls_transparent_test_driver_mac_operation_t *operation,
+    const uint8_t *mac,
+    size_t mac_length)
+{
+    mbedtls_test_driver_mac_hooks.hits++;
+
+    if (mbedtls_test_driver_mac_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_test_driver_mac_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_MAC)
+        mbedtls_test_driver_mac_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_mac_verify_finish(
+                operation, mac, mac_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_MAC)
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_psa_mac_verify_finish(
+                operation, mac, mac_length);
+#else
+        (void) operation;
+        (void) mac;
+        (void) mac_length;
+        mbedtls_test_driver_mac_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_mac_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_mac_abort(
+    mbedtls_transparent_test_driver_mac_operation_t *operation)
+{
+    mbedtls_test_driver_mac_hooks.hits++;
+
+    if (mbedtls_test_driver_mac_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_test_driver_mac_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_MAC)
+        mbedtls_test_driver_mac_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_mac_abort(operation);
+#elif defined(MBEDTLS_PSA_BUILTIN_MAC)
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_psa_mac_abort(operation);
+#else
+        (void) operation;
+        mbedtls_test_driver_mac_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_mac_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_opaque_mac_compute(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *mac,
+    size_t mac_size,
+    size_t *mac_length)
+{
+    mbedtls_test_driver_mac_hooks.hits++;
+
+    if (mbedtls_test_driver_mac_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_test_driver_mac_hooks.forced_status;
+    } else {
+        (void) attributes;
+        (void) key_buffer;
+        (void) key_buffer_size;
+        (void) alg;
+        (void) input;
+        (void) input_length;
+        (void) mac;
+        (void) mac_size;
+        (void) mac_length;
+        mbedtls_test_driver_mac_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+    }
+
+    return mbedtls_test_driver_mac_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_opaque_mac_sign_setup(
+    mbedtls_opaque_test_driver_mac_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg)
+{
+    mbedtls_test_driver_mac_hooks.hits++;
+
+    if (mbedtls_test_driver_mac_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_test_driver_mac_hooks.forced_status;
+    } else {
+        (void) operation;
+        (void) attributes;
+        (void) key_buffer;
+        (void) key_buffer_size;
+        (void) alg;
+        mbedtls_test_driver_mac_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+    }
+
+    return mbedtls_test_driver_mac_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_opaque_mac_verify_setup(
+    mbedtls_opaque_test_driver_mac_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg)
+{
+    mbedtls_test_driver_mac_hooks.hits++;
+
+    if (mbedtls_test_driver_mac_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_test_driver_mac_hooks.forced_status;
+    } else {
+        (void) operation;
+        (void) attributes;
+        (void) key_buffer;
+        (void) key_buffer_size;
+        (void) alg;
+        mbedtls_test_driver_mac_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+    }
+
+    return mbedtls_test_driver_mac_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_opaque_mac_update(
+    mbedtls_opaque_test_driver_mac_operation_t *operation,
+    const uint8_t *input,
+    size_t input_length)
+{
+    mbedtls_test_driver_mac_hooks.hits++;
+
+    if (mbedtls_test_driver_mac_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_test_driver_mac_hooks.forced_status;
+    } else {
+        (void) operation;
+        (void) input;
+        (void) input_length;
+        mbedtls_test_driver_mac_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+    }
+
+    return mbedtls_test_driver_mac_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_opaque_mac_sign_finish(
+    mbedtls_opaque_test_driver_mac_operation_t *operation,
+    uint8_t *mac,
+    size_t mac_size,
+    size_t *mac_length)
+{
+    mbedtls_test_driver_mac_hooks.hits++;
+
+    if (mbedtls_test_driver_mac_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_test_driver_mac_hooks.forced_status;
+    } else {
+        (void) operation;
+        (void) mac;
+        (void) mac_size;
+        (void) mac_length;
+        mbedtls_test_driver_mac_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+    }
+
+    return mbedtls_test_driver_mac_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_opaque_mac_verify_finish(
+    mbedtls_opaque_test_driver_mac_operation_t *operation,
+    const uint8_t *mac,
+    size_t mac_length)
+{
+    mbedtls_test_driver_mac_hooks.hits++;
+
+    if (mbedtls_test_driver_mac_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_test_driver_mac_hooks.forced_status;
+    } else {
+        (void) operation;
+        (void) mac;
+        (void) mac_length;
+        mbedtls_test_driver_mac_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+    }
+
+    return mbedtls_test_driver_mac_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_opaque_mac_abort(
+    mbedtls_opaque_test_driver_mac_operation_t *operation)
+{
+    mbedtls_test_driver_mac_hooks.hits++;
+
+    if (mbedtls_test_driver_mac_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_mac_hooks.driver_status =
+            mbedtls_test_driver_mac_hooks.forced_status;
+    } else {
+        (void) operation;
+        mbedtls_test_driver_mac_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+    }
+
+    return mbedtls_test_driver_mac_hooks.driver_status;
+}
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
diff --git a/framework/tests/src/drivers/test_driver_pake.c b/framework/tests/src/drivers/test_driver_pake.c
new file mode 100644
index 0000000..c3ce326
--- /dev/null
+++ b/framework/tests/src/drivers/test_driver_pake.c
@@ -0,0 +1,206 @@
+/*
+ * Test driver for PAKE entry points.
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <test/helpers.h>
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include "psa_crypto_pake.h"
+
+#include "test/drivers/pake.h"
+#include "string.h"
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
+#if MBEDTLS_VERSION_MAJOR < 4
+#include "libtestdriver1/library/psa_crypto_pake.h"
+#else
+#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_pake.h"
+#endif
+#endif
+
+mbedtls_test_driver_pake_hooks_t mbedtls_test_driver_pake_hooks =
+    MBEDTLS_TEST_DRIVER_PAKE_INIT;
+
+
+psa_status_t mbedtls_test_transparent_pake_setup(
+    mbedtls_transparent_test_driver_pake_operation_t *operation,
+    const psa_crypto_driver_pake_inputs_t *inputs)
+{
+    mbedtls_test_driver_pake_hooks.hits.total++;
+    mbedtls_test_driver_pake_hooks.hits.setup++;
+
+    if (mbedtls_test_driver_pake_hooks.forced_setup_status != PSA_SUCCESS) {
+        mbedtls_test_driver_pake_hooks.driver_status =
+            mbedtls_test_driver_pake_hooks.forced_setup_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_PAKE)
+        mbedtls_test_driver_pake_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_pake_setup(
+                operation, (const libtestdriver1_psa_crypto_driver_pake_inputs_t *) inputs);
+#elif defined(MBEDTLS_PSA_BUILTIN_PAKE)
+        mbedtls_test_driver_pake_hooks.driver_status =
+            mbedtls_psa_pake_setup(
+                operation, inputs);
+#else
+        (void) operation;
+        (void) inputs;
+        mbedtls_test_driver_pake_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_pake_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_pake_output(
+    mbedtls_transparent_test_driver_pake_operation_t *operation,
+    psa_crypto_driver_pake_step_t step,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length)
+{
+    mbedtls_test_driver_pake_hooks.hits.total++;
+    mbedtls_test_driver_pake_hooks.hits.output++;
+
+    if (mbedtls_test_driver_pake_hooks.forced_output != NULL) {
+        if (output_size < mbedtls_test_driver_pake_hooks.forced_output_length) {
+            return PSA_ERROR_BUFFER_TOO_SMALL;
+        }
+
+        memcpy(output,
+               mbedtls_test_driver_pake_hooks.forced_output,
+               mbedtls_test_driver_pake_hooks.forced_output_length);
+        *output_length = mbedtls_test_driver_pake_hooks.forced_output_length;
+
+        return mbedtls_test_driver_pake_hooks.forced_status;
+    }
+
+    if (mbedtls_test_driver_pake_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_pake_hooks.driver_status =
+            mbedtls_test_driver_pake_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_PAKE)
+        mbedtls_test_driver_pake_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_pake_output(
+                operation, (libtestdriver1_psa_crypto_driver_pake_step_t) step,
+                output, output_size, output_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_PAKE)
+        mbedtls_test_driver_pake_hooks.driver_status =
+            mbedtls_psa_pake_output(
+                operation, step, output, output_size, output_length);
+#else
+        (void) operation;
+        (void) step;
+        (void) output;
+        (void) output_size;
+        (void) output_length;
+        mbedtls_test_driver_pake_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_pake_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_pake_input(
+    mbedtls_transparent_test_driver_pake_operation_t *operation,
+    psa_crypto_driver_pake_step_t step,
+    const uint8_t *input,
+    size_t input_length)
+{
+    mbedtls_test_driver_pake_hooks.hits.total++;
+    mbedtls_test_driver_pake_hooks.hits.input++;
+
+    if (mbedtls_test_driver_pake_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_pake_hooks.driver_status =
+            mbedtls_test_driver_pake_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_PAKE)
+        mbedtls_test_driver_pake_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_pake_input(
+                operation, (libtestdriver1_psa_crypto_driver_pake_step_t) step,
+                input, input_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_PAKE)
+        mbedtls_test_driver_pake_hooks.driver_status =
+            mbedtls_psa_pake_input(
+                operation, step, input, input_length);
+#else
+        (void) operation;
+        (void) step;
+        (void) input;
+        (void) input_length;
+        mbedtls_test_driver_pake_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_pake_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_pake_get_implicit_key(
+    mbedtls_transparent_test_driver_pake_operation_t *operation,
+    uint8_t *output, size_t output_size, size_t *output_length)
+{
+    mbedtls_test_driver_pake_hooks.hits.total++;
+    mbedtls_test_driver_pake_hooks.hits.implicit_key++;
+
+    if (mbedtls_test_driver_pake_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_pake_hooks.driver_status =
+            mbedtls_test_driver_pake_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_PAKE)
+        mbedtls_test_driver_pake_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_pake_get_implicit_key(
+                operation,  output, output_size, output_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_PAKE)
+        mbedtls_test_driver_pake_hooks.driver_status =
+            mbedtls_psa_pake_get_implicit_key(
+                operation, output, output_size, output_length);
+#else
+        (void) operation;
+        (void) output;
+        (void) output_size;
+        (void) output_length;
+        mbedtls_test_driver_pake_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_pake_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_pake_abort(
+    mbedtls_transparent_test_driver_pake_operation_t *operation)
+{
+    mbedtls_test_driver_pake_hooks.hits.total++;
+    mbedtls_test_driver_pake_hooks.hits.abort++;
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+    defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_PAKE)
+    mbedtls_test_driver_pake_hooks.driver_status =
+        libtestdriver1_mbedtls_psa_pake_abort(
+            operation);
+#elif defined(MBEDTLS_PSA_BUILTIN_PAKE)
+    mbedtls_test_driver_pake_hooks.driver_status =
+        mbedtls_psa_pake_abort(
+            operation);
+#else
+    (void) operation;
+    mbedtls_test_driver_pake_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+
+
+    if (mbedtls_test_driver_pake_hooks.forced_status != PSA_SUCCESS &&
+        mbedtls_test_driver_pake_hooks.driver_status == PSA_SUCCESS) {
+        mbedtls_test_driver_pake_hooks.driver_status =
+            mbedtls_test_driver_pake_hooks.forced_status;
+    }
+
+
+    return mbedtls_test_driver_pake_hooks.driver_status;
+}
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
diff --git a/framework/tests/src/drivers/test_driver_signature.c b/framework/tests/src/drivers/test_driver_signature.c
new file mode 100644
index 0000000..a6eef57
--- /dev/null
+++ b/framework/tests/src/drivers/test_driver_signature.c
@@ -0,0 +1,410 @@
+/*
+ * Test driver for signature functions.
+ * Currently supports signing and verifying precalculated hashes, using
+ * only deterministic ECDSA on curves secp256r1, secp384r1 and secp521r1.
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <test/helpers.h>
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include "psa/crypto.h"
+#include "psa_crypto_core.h"
+#include "psa_crypto_ecp.h"
+#include "psa_crypto_hash.h"
+#include "psa_crypto_rsa.h"
+#include "mbedtls/ecp.h"
+
+#include "test/drivers/hash.h"
+#include "test/drivers/signature.h"
+#include "test/drivers/hash.h"
+
+#include "mbedtls/ecdsa.h"
+
+#include "test/random.h"
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
+#if MBEDTLS_VERSION_MAJOR < 4
+#include "libtestdriver1/library/psa_crypto_ecp.h"
+#include "libtestdriver1/library/psa_crypto_hash.h"
+#include "libtestdriver1/library/psa_crypto_rsa.h"
+#else
+#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.h"
+#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_hash.h"
+#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_rsa.h"
+#endif
+#endif
+
+#include <string.h>
+
+mbedtls_test_driver_signature_hooks_t
+    mbedtls_test_driver_signature_sign_hooks = MBEDTLS_TEST_DRIVER_SIGNATURE_INIT;
+mbedtls_test_driver_signature_hooks_t
+    mbedtls_test_driver_signature_verify_hooks = MBEDTLS_TEST_DRIVER_SIGNATURE_INIT;
+
+psa_status_t sign_hash(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *hash,
+    size_t hash_length,
+    uint8_t *signature,
+    size_t signature_size,
+    size_t *signature_length)
+{
+    if (attributes->type == PSA_KEY_TYPE_RSA_KEY_PAIR) {
+        if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) ||
+            PSA_ALG_IS_RSA_PSS(alg)) {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+            (defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) || \
+            defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS))
+            return libtestdriver1_mbedtls_psa_rsa_sign_hash(
+                (const libtestdriver1_psa_key_attributes_t *) attributes,
+                key_buffer, key_buffer_size,
+                alg, hash, hash_length,
+                signature, signature_size, signature_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) || \
+            defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS)
+            return mbedtls_psa_rsa_sign_hash(
+                attributes,
+                key_buffer, key_buffer_size,
+                alg, hash, hash_length,
+                signature, signature_size, signature_length);
+#endif
+        } else {
+            return PSA_ERROR_INVALID_ARGUMENT;
+        }
+    } else if (PSA_KEY_TYPE_IS_ECC(attributes->type)) {
+        if (PSA_ALG_IS_ECDSA(alg)) {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+            (defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
+            defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA))
+            return libtestdriver1_mbedtls_psa_ecdsa_sign_hash(
+                (const libtestdriver1_psa_key_attributes_t *) attributes,
+                key_buffer, key_buffer_size,
+                alg, hash, hash_length,
+                signature, signature_size, signature_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
+            defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)
+            return mbedtls_psa_ecdsa_sign_hash(
+                attributes,
+                key_buffer, key_buffer_size,
+                alg, hash, hash_length,
+                signature, signature_size, signature_length);
+#endif
+        } else {
+            return PSA_ERROR_INVALID_ARGUMENT;
+        }
+    }
+
+    (void) attributes;
+    (void) key_buffer;
+    (void) key_buffer_size;
+    (void) alg;
+    (void) hash;
+    (void) hash_length;
+    (void) signature;
+    (void) signature_size;
+    (void) signature_length;
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t verify_hash(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *hash,
+    size_t hash_length,
+    const uint8_t *signature,
+    size_t signature_length)
+{
+    if (PSA_KEY_TYPE_IS_RSA(attributes->type)) {
+        if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) ||
+            PSA_ALG_IS_RSA_PSS(alg)) {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+            (defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) || \
+            defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS))
+            return libtestdriver1_mbedtls_psa_rsa_verify_hash(
+                (const libtestdriver1_psa_key_attributes_t *) attributes,
+                key_buffer, key_buffer_size,
+                alg, hash, hash_length,
+                signature, signature_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) || \
+            defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS)
+            return mbedtls_psa_rsa_verify_hash(
+                attributes,
+                key_buffer, key_buffer_size,
+                alg, hash, hash_length,
+                signature, signature_length);
+#endif
+        } else {
+            return PSA_ERROR_INVALID_ARGUMENT;
+        }
+    } else if (PSA_KEY_TYPE_IS_ECC(attributes->type)) {
+        if (PSA_ALG_IS_ECDSA(alg)) {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+            (defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
+            defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA))
+            return libtestdriver1_mbedtls_psa_ecdsa_verify_hash(
+                (const libtestdriver1_psa_key_attributes_t *) attributes,
+                key_buffer, key_buffer_size,
+                alg, hash, hash_length,
+                signature, signature_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
+            defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)
+            return mbedtls_psa_ecdsa_verify_hash(
+                attributes,
+                key_buffer, key_buffer_size,
+                alg, hash, hash_length,
+                signature, signature_length);
+#endif
+        } else {
+            return PSA_ERROR_INVALID_ARGUMENT;
+        }
+    }
+
+    (void) attributes;
+    (void) key_buffer;
+    (void) key_buffer_size;
+    (void) alg;
+    (void) hash;
+    (void) hash_length;
+    (void) signature;
+    (void) signature_length;
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_transparent_signature_sign_message(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *signature,
+    size_t signature_size,
+    size_t *signature_length)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    size_t hash_length;
+    uint8_t hash[PSA_HASH_MAX_SIZE];
+
+    ++mbedtls_test_driver_signature_sign_hooks.hits;
+
+    if (mbedtls_test_driver_signature_sign_hooks.forced_status != PSA_SUCCESS) {
+        return mbedtls_test_driver_signature_sign_hooks.forced_status;
+    }
+
+    if (mbedtls_test_driver_signature_sign_hooks.forced_output != NULL) {
+        if (mbedtls_test_driver_signature_sign_hooks.forced_output_length > signature_size) {
+            return PSA_ERROR_BUFFER_TOO_SMALL;
+        }
+
+        memcpy(signature, mbedtls_test_driver_signature_sign_hooks.forced_output,
+               mbedtls_test_driver_signature_sign_hooks.forced_output_length);
+        *signature_length = mbedtls_test_driver_signature_sign_hooks.forced_output_length;
+
+        return PSA_SUCCESS;
+    }
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+    defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_HASH)
+    status = libtestdriver1_mbedtls_psa_hash_compute(
+        PSA_ALG_SIGN_GET_HASH(alg), input, input_length,
+        hash, sizeof(hash), &hash_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_HASH)
+    status = mbedtls_psa_hash_compute(
+        PSA_ALG_SIGN_GET_HASH(alg), input, input_length,
+        hash, sizeof(hash), &hash_length);
+#else
+    (void) input;
+    (void) input_length;
+    status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    if (status != PSA_SUCCESS) {
+        return status;
+    }
+
+    return sign_hash(attributes, key_buffer, key_buffer_size,
+                     alg, hash, hash_length,
+                     signature, signature_size, signature_length);
+}
+
+psa_status_t mbedtls_test_opaque_signature_sign_message(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key,
+    size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *signature,
+    size_t signature_size,
+    size_t *signature_length)
+{
+    (void) attributes;
+    (void) key;
+    (void) key_length;
+    (void) alg;
+    (void) input;
+    (void) input_length;
+    (void) signature;
+    (void) signature_size;
+    (void) signature_length;
+
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_transparent_signature_verify_message(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *input,
+    size_t input_length,
+    const uint8_t *signature,
+    size_t signature_length)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    size_t hash_length;
+    uint8_t hash[PSA_HASH_MAX_SIZE];
+
+    ++mbedtls_test_driver_signature_verify_hooks.hits;
+
+    if (mbedtls_test_driver_signature_verify_hooks.forced_status != PSA_SUCCESS) {
+        return mbedtls_test_driver_signature_verify_hooks.forced_status;
+    }
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+    defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_HASH)
+    status = libtestdriver1_mbedtls_psa_hash_compute(
+        PSA_ALG_SIGN_GET_HASH(alg), input, input_length,
+        hash, sizeof(hash), &hash_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_HASH)
+    status = mbedtls_psa_hash_compute(
+        PSA_ALG_SIGN_GET_HASH(alg), input, input_length,
+        hash, sizeof(hash), &hash_length);
+#else
+    (void) input;
+    (void) input_length;
+    status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    if (status != PSA_SUCCESS) {
+        return status;
+    }
+
+    return verify_hash(attributes, key_buffer, key_buffer_size,
+                       alg, hash, hash_length,
+                       signature, signature_length);
+}
+
+psa_status_t mbedtls_test_opaque_signature_verify_message(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key,
+    size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *input,
+    size_t input_length,
+    const uint8_t *signature,
+    size_t signature_length)
+{
+    (void) attributes;
+    (void) key;
+    (void) key_length;
+    (void) alg;
+    (void) input;
+    (void) input_length;
+    (void) signature;
+    (void) signature_length;
+
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_transparent_signature_sign_hash(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer, size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *hash, size_t hash_length,
+    uint8_t *signature, size_t signature_size, size_t *signature_length)
+{
+    ++mbedtls_test_driver_signature_sign_hooks.hits;
+
+    if (mbedtls_test_driver_signature_sign_hooks.forced_status != PSA_SUCCESS) {
+        return mbedtls_test_driver_signature_sign_hooks.forced_status;
+    }
+
+    if (mbedtls_test_driver_signature_sign_hooks.forced_output != NULL) {
+        if (mbedtls_test_driver_signature_sign_hooks.forced_output_length > signature_size) {
+            return PSA_ERROR_BUFFER_TOO_SMALL;
+        }
+        memcpy(signature, mbedtls_test_driver_signature_sign_hooks.forced_output,
+               mbedtls_test_driver_signature_sign_hooks.forced_output_length);
+        *signature_length = mbedtls_test_driver_signature_sign_hooks.forced_output_length;
+        return PSA_SUCCESS;
+    }
+
+    return sign_hash(attributes, key_buffer, key_buffer_size,
+                     alg, hash, hash_length,
+                     signature, signature_size, signature_length);
+}
+
+psa_status_t mbedtls_test_opaque_signature_sign_hash(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *hash, size_t hash_length,
+    uint8_t *signature, size_t signature_size, size_t *signature_length)
+{
+    (void) attributes;
+    (void) key;
+    (void) key_length;
+    (void) alg;
+    (void) hash;
+    (void) hash_length;
+    (void) signature;
+    (void) signature_size;
+    (void) signature_length;
+
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t mbedtls_test_transparent_signature_verify_hash(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer, size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *hash, size_t hash_length,
+    const uint8_t *signature, size_t signature_length)
+{
+    ++mbedtls_test_driver_signature_verify_hooks.hits;
+
+    if (mbedtls_test_driver_signature_verify_hooks.forced_status != PSA_SUCCESS) {
+        return mbedtls_test_driver_signature_verify_hooks.forced_status;
+    }
+
+    return verify_hash(attributes, key_buffer, key_buffer_size,
+                       alg, hash, hash_length,
+                       signature, signature_length);
+}
+
+psa_status_t mbedtls_test_opaque_signature_verify_hash(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *hash, size_t hash_length,
+    const uint8_t *signature, size_t signature_length)
+{
+    (void) attributes;
+    (void) key;
+    (void) key_length;
+    (void) alg;
+    (void) hash;
+    (void) hash_length;
+    (void) signature;
+    (void) signature_length;
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
diff --git a/framework/tests/src/fake_external_rng_for_test.c b/framework/tests/src/fake_external_rng_for_test.c
new file mode 100644
index 0000000..c0bfde5
--- /dev/null
+++ b/framework/tests/src/fake_external_rng_for_test.c
@@ -0,0 +1,45 @@
+/** \file fake_external_rng_for_test.c
+ *
+ * \brief Helper functions to test PSA crypto functionality.
+ */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <test/fake_external_rng_for_test.h>
+
+#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+#include <test/random.h>
+#include <psa/crypto.h>
+
+static int test_insecure_external_rng_enabled = 0;
+
+void mbedtls_test_enable_insecure_external_rng(void)
+{
+    test_insecure_external_rng_enabled = 1;
+}
+
+void mbedtls_test_disable_insecure_external_rng(void)
+{
+    test_insecure_external_rng_enabled = 0;
+}
+
+psa_status_t mbedtls_psa_external_get_random(
+    mbedtls_psa_external_random_context_t *context,
+    uint8_t *output, size_t output_size, size_t *output_length)
+{
+    (void) context;
+
+    if (!test_insecure_external_rng_enabled) {
+        return PSA_ERROR_INSUFFICIENT_ENTROPY;
+    }
+
+    /* This implementation is for test purposes only!
+     * Use the libc non-cryptographic random generator. */
+    mbedtls_test_rnd_std_rand(NULL, output, output_size);
+    *output_length = output_size;
+    return PSA_SUCCESS;
+}
+#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
diff --git a/framework/tests/src/helpers.c b/framework/tests/src/helpers.c
new file mode 100644
index 0000000..1a15733
--- /dev/null
+++ b/framework/tests/src/helpers.c
@@ -0,0 +1,723 @@
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <test/constant_flow.h>
+#include <test/helpers.h>
+#include <test/macros.h>
+#include <string.h>
+
+#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
+#include <psa/crypto.h>
+#include <test/psa_crypto_helpers.h>
+#endif
+
+#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_PSA_CRYPTO_C)
+#include <test/psa_memory_poisoning_wrappers.h>
+#endif
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+#include <test/bignum_codepath_check.h>
+#endif
+#if defined(MBEDTLS_THREADING_C)
+#include "mbedtls/threading.h"
+#endif
+
+/*----------------------------------------------------------------------------*/
+/* Static global variables */
+
+#if defined(MBEDTLS_PLATFORM_C)
+static mbedtls_platform_context platform_ctx;
+#endif
+
+static mbedtls_test_info_t mbedtls_test_info;
+
+#ifdef MBEDTLS_THREADING_C
+mbedtls_threading_mutex_t mbedtls_test_info_mutex;
+#endif /* MBEDTLS_THREADING_C */
+
+/*----------------------------------------------------------------------------*/
+/* Mbedtls Test Info accessors
+ *
+ * NOTE - there are two types of accessors here: public accessors and internal
+ * accessors. The public accessors have prototypes in helpers.h and lock
+ * mbedtls_test_info_mutex (if mutexes are enabled). The _internal accessors,
+ * which are expected to be used from this module *only*, do not lock the mutex.
+ * These are designed to be called from within public functions which already
+ * hold the mutex. The main reason for this difference is the need to set
+ * multiple test data values atomically (without releasing the mutex) to prevent
+ * race conditions. */
+
+mbedtls_test_result_t mbedtls_test_get_result(void)
+{
+    mbedtls_test_result_t result;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    result =  mbedtls_test_info.result;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    return result;
+}
+
+static void mbedtls_test_set_result_internal(mbedtls_test_result_t result, const char *test,
+                                             int line_no, const char *filename)
+{
+    /* Internal function only - mbedtls_test_info_mutex should be held prior
+     * to calling this function. */
+
+    mbedtls_test_info.result = result;
+    mbedtls_test_info.test = test;
+    mbedtls_test_info.line_no = line_no;
+    mbedtls_test_info.filename = filename;
+}
+
+const char *mbedtls_test_get_test(void)
+{
+    const char *test;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    test = mbedtls_test_info.test;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    return test;
+}
+const char *mbedtls_get_test_filename(void)
+{
+    const char *filename;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    /* It should be ok just to pass back the pointer here, as it is going to
+     * be a pointer into non changing data. */
+    filename = mbedtls_test_info.filename;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    return filename;
+}
+
+int mbedtls_test_get_line_no(void)
+{
+    int line_no;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    line_no = mbedtls_test_info.line_no;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    return line_no;
+}
+
+void mbedtls_test_increment_step(void)
+{
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    ++mbedtls_test_info.step;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
+
+unsigned long mbedtls_test_get_step(void)
+{
+    unsigned long step;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    step = mbedtls_test_info.step;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    return step;
+}
+
+static void mbedtls_test_reset_step_internal(void)
+{
+    /* Internal function only - mbedtls_test_info_mutex should be held prior
+     * to calling this function. */
+
+    mbedtls_test_info.step = (unsigned long) (-1);
+}
+
+void mbedtls_test_set_step(unsigned long step)
+{
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    mbedtls_test_info.step = step;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
+
+void mbedtls_test_get_line1(char *line)
+{
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    memcpy(line, mbedtls_test_info.line1, MBEDTLS_TEST_LINE_LENGTH);
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
+
+static void mbedtls_test_set_line1_internal(const char *line)
+{
+    /* Internal function only - mbedtls_test_info_mutex should be held prior
+     * to calling this function. */
+
+    if (line == NULL) {
+        memset(mbedtls_test_info.line1, 0, MBEDTLS_TEST_LINE_LENGTH);
+    } else {
+        memcpy(mbedtls_test_info.line1, line, MBEDTLS_TEST_LINE_LENGTH);
+    }
+}
+
+void mbedtls_test_get_line2(char *line)
+{
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    memcpy(line, mbedtls_test_info.line2, MBEDTLS_TEST_LINE_LENGTH);
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
+
+static void mbedtls_test_set_line2_internal(const char *line)
+{
+    /* Internal function only - mbedtls_test_info_mutex should be held prior
+     * to calling this function. */
+
+    if (line == NULL) {
+        memset(mbedtls_test_info.line2, 0, MBEDTLS_TEST_LINE_LENGTH);
+    } else {
+        memcpy(mbedtls_test_info.line2, line, MBEDTLS_TEST_LINE_LENGTH);
+    }
+}
+
+
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+const char *mbedtls_test_get_mutex_usage_error(void)
+{
+    const char *usage_error;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    usage_error = mbedtls_test_info.mutex_usage_error;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    return usage_error;
+}
+
+void mbedtls_test_set_mutex_usage_error(const char *msg)
+{
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    if (mbedtls_test_info.mutex_usage_error == NULL || msg == NULL) {
+        mbedtls_test_info.mutex_usage_error = msg;
+    }
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
+#endif // #if defined(MBEDTLS_TEST_MUTEX_USAGE)
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+unsigned mbedtls_test_get_case_uses_negative_0(void)
+{
+    unsigned test_case_uses_negative_0 = 0;
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+    test_case_uses_negative_0 = mbedtls_test_info.case_uses_negative_0;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    return test_case_uses_negative_0;
+}
+
+static void mbedtls_test_set_case_uses_negative_0_internal(unsigned uses)
+{
+    /* Internal function only - mbedtls_test_info_mutex should be held prior
+     * to calling this function. */
+
+    mbedtls_test_info.case_uses_negative_0 = uses;
+}
+
+void mbedtls_test_increment_case_uses_negative_0(void)
+{
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    ++mbedtls_test_info.case_uses_negative_0;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
+
+#endif /* MBEDTLS_BIGNUM_C */
+
+#ifdef MBEDTLS_TEST_MUTEX_USAGE
+mbedtls_threading_mutex_t *mbedtls_test_get_info_mutex(void)
+{
+    return &mbedtls_test_info_mutex;
+}
+
+#endif /* MBEDTLS_TEST_MUTEX_USAGE */
+
+/*----------------------------------------------------------------------------*/
+/* Helper Functions */
+
+int mbedtls_test_platform_setup(void)
+{
+    int ret = 0;
+
+#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_PSA_CRYPTO_C) \
+    && !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) \
+    && defined(MBEDTLS_TEST_MEMORY_CAN_POISON)
+    mbedtls_poison_test_hooks_setup();
+#endif
+
+#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
+    /* Make sure that injected entropy is present. Otherwise
+     * psa_crypto_init() will fail. This is not necessary for test suites
+     * that don't use PSA, but it's harmless (except for leaving a file
+     * behind). */
+    ret = mbedtls_test_inject_entropy_restore();
+    if (ret != 0) {
+        return ret;
+    }
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+    ret = mbedtls_platform_setup(&platform_ctx);
+#endif /* MBEDTLS_PLATFORM_C */
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_init(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    mbedtls_codepath_test_hooks_setup();
+#endif /* MBEDTLS_TEST_HOOKS && !MBEDTLS_THREADING_C */
+
+    return ret;
+}
+
+void mbedtls_test_platform_teardown(void)
+{
+#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_PSA_CRYPTO_C) \
+    && !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) \
+    &&  defined(MBEDTLS_TEST_MEMORY_CAN_POISON)
+    mbedtls_poison_test_hooks_teardown();
+#endif
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_free(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+#if defined(MBEDTLS_PLATFORM_C)
+    mbedtls_platform_teardown(&platform_ctx);
+#endif /* MBEDTLS_PLATFORM_C */
+
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    mbedtls_codepath_test_hooks_teardown();
+#endif /* MBEDTLS_TEST_HOOKS && !MBEDTLS_THREADING_C */
+}
+
+int mbedtls_test_ascii2uc(const char c, unsigned char *uc)
+{
+    if ((c >= '0') && (c <= '9')) {
+        *uc = c - '0';
+    } else if ((c >= 'a') && (c <= 'f')) {
+        *uc = c - 'a' + 10;
+    } else if ((c >= 'A') && (c <= 'F')) {
+        *uc = c - 'A' + 10;
+    } else {
+        return -1;
+    }
+
+    return 0;
+}
+
+static void mbedtls_test_fail_internal(const char *test, int line_no, const char *filename)
+{
+    /* Internal function only - mbedtls_test_info_mutex should be held prior
+     * to calling this function. */
+
+    /* Don't use accessor, we already hold mutex. */
+    if (mbedtls_test_info.result != MBEDTLS_TEST_RESULT_FAILED) {
+        /* If we have already recorded the test as having failed then don't
+         * overwrite any previous information about the failure. */
+        mbedtls_test_set_result_internal(MBEDTLS_TEST_RESULT_FAILED, test, line_no, filename);
+    }
+}
+
+void mbedtls_test_fail(const char *test, int line_no, const char *filename)
+{
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    mbedtls_test_fail_internal(test, line_no, filename);
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
+
+void mbedtls_test_skip(const char *test, int line_no, const char *filename)
+{
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    mbedtls_test_set_result_internal(MBEDTLS_TEST_RESULT_SKIPPED, test, line_no, filename);
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
+
+void mbedtls_test_info_reset(void)
+{
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    mbedtls_test_set_result_internal(MBEDTLS_TEST_RESULT_SUCCESS, 0, 0, 0);
+    mbedtls_test_reset_step_internal();
+    mbedtls_test_set_line1_internal(NULL);
+    mbedtls_test_set_line2_internal(NULL);
+
+#if defined(MBEDTLS_BIGNUM_C)
+    mbedtls_test_set_case_uses_negative_0_internal(0);
+#endif
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
+
+int mbedtls_test_equal(const char *test, int line_no, const char *filename,
+                       unsigned long long value1, unsigned long long value2)
+{
+    TEST_CF_PUBLIC(&value1, sizeof(value1));
+    TEST_CF_PUBLIC(&value2, sizeof(value2));
+
+    if (value1 == value2) {
+        return 1;
+    }
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    /* Don't use accessor, as we already hold mutex. */
+    if (mbedtls_test_info.result != MBEDTLS_TEST_RESULT_FAILED) {
+        /* If we've already recorded the test as having failed then don't
+         * overwrite any previous information about the failure. */
+
+        char buf[MBEDTLS_TEST_LINE_LENGTH];
+        mbedtls_test_fail_internal(test, line_no, filename);
+        (void) mbedtls_snprintf(buf, sizeof(buf),
+                                "lhs = 0x%016llx = %lld",
+                                value1, (long long) value1);
+        mbedtls_test_set_line1_internal(buf);
+        (void) mbedtls_snprintf(buf, sizeof(buf),
+                                "rhs = 0x%016llx = %lld",
+                                value2, (long long) value2);
+        mbedtls_test_set_line2_internal(buf);
+    }
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    return 0;
+}
+
+int mbedtls_test_le_u(const char *test, int line_no, const char *filename,
+                      unsigned long long value1, unsigned long long value2)
+{
+    TEST_CF_PUBLIC(&value1, sizeof(value1));
+    TEST_CF_PUBLIC(&value2, sizeof(value2));
+
+    if (value1 <= value2) {
+        return 1;
+    }
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    /* Don't use accessor, we already hold mutex. */
+    if (mbedtls_test_info.result != MBEDTLS_TEST_RESULT_FAILED) {
+        /* If we've already recorded the test as having failed then don't
+         * overwrite any previous information about the failure. */
+
+        char buf[MBEDTLS_TEST_LINE_LENGTH];
+        mbedtls_test_fail_internal(test, line_no, filename);
+        (void) mbedtls_snprintf(buf, sizeof(buf),
+                                "lhs = 0x%016llx = %llu",
+                                value1, value1);
+        mbedtls_test_set_line1_internal(buf);
+        (void) mbedtls_snprintf(buf, sizeof(buf),
+                                "rhs = 0x%016llx = %llu",
+                                value2, value2);
+        mbedtls_test_set_line2_internal(buf);
+    }
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    return 0;
+}
+
+int mbedtls_test_le_s(const char *test, int line_no, const char *filename,
+                      long long value1, long long value2)
+{
+    TEST_CF_PUBLIC(&value1, sizeof(value1));
+    TEST_CF_PUBLIC(&value2, sizeof(value2));
+
+    if (value1 <= value2) {
+        return 1;
+    }
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    /* Don't use accessor, we already hold mutex. */
+    if (mbedtls_test_info.result != MBEDTLS_TEST_RESULT_FAILED) {
+        /* If we've already recorded the test as having failed then don't
+         * overwrite any previous information about the failure. */
+
+        char buf[MBEDTLS_TEST_LINE_LENGTH];
+        mbedtls_test_fail_internal(test, line_no, filename);
+        (void) mbedtls_snprintf(buf, sizeof(buf),
+                                "lhs = 0x%016llx = %lld",
+                                (unsigned long long) value1, value1);
+        mbedtls_test_set_line1_internal(buf);
+        (void) mbedtls_snprintf(buf, sizeof(buf),
+                                "rhs = 0x%016llx = %lld",
+                                (unsigned long long) value2, value2);
+        mbedtls_test_set_line2_internal(buf);
+    }
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    return 0;
+}
+
+int mbedtls_test_unhexify(unsigned char *obuf,
+                          size_t obufmax,
+                          const char *ibuf,
+                          size_t *len)
+{
+    unsigned char uc, uc2;
+
+    *len = strlen(ibuf);
+
+    /* Must be even number of bytes. */
+    if ((*len) & 1) {
+        return -1;
+    }
+    *len /= 2;
+
+    if ((*len) > obufmax) {
+        return -1;
+    }
+
+    while (*ibuf != 0) {
+        if (mbedtls_test_ascii2uc(*(ibuf++), &uc) != 0) {
+            return -1;
+        }
+
+        if (mbedtls_test_ascii2uc(*(ibuf++), &uc2) != 0) {
+            return -1;
+        }
+
+        *(obuf++) = (uc << 4) | uc2;
+    }
+
+    return 0;
+}
+
+void mbedtls_test_hexify(unsigned char *obuf,
+                         const unsigned char *ibuf,
+                         int len)
+{
+    unsigned char l, h;
+
+    while (len != 0) {
+        h = *ibuf / 16;
+        l = *ibuf % 16;
+
+        if (h < 10) {
+            *obuf++ = '0' + h;
+        } else {
+            *obuf++ = 'a' + h - 10;
+        }
+
+        if (l < 10) {
+            *obuf++ = '0' + l;
+        } else {
+            *obuf++ = 'a' + l - 10;
+        }
+
+        ++ibuf;
+        len--;
+    }
+}
+
+unsigned char *mbedtls_test_zero_alloc(size_t len)
+{
+    void *p;
+    size_t actual_len = (len != 0) ? len : 1;
+
+    p = mbedtls_calloc(1, actual_len);
+    TEST_HELPER_ASSERT(p != NULL);
+
+    memset(p, 0x00, actual_len);
+
+    return p;
+}
+
+unsigned char *mbedtls_test_unhexify_alloc(const char *ibuf, size_t *olen)
+{
+    unsigned char *obuf;
+    size_t len;
+
+    *olen = strlen(ibuf) / 2;
+
+    if (*olen == 0) {
+        return mbedtls_test_zero_alloc(*olen);
+    }
+
+    obuf = mbedtls_calloc(1, *olen);
+    TEST_HELPER_ASSERT(obuf != NULL);
+    TEST_HELPER_ASSERT(mbedtls_test_unhexify(obuf, *olen, ibuf, &len) == 0);
+
+    return obuf;
+}
+
+int mbedtls_test_hexcmp(uint8_t *a, uint8_t *b,
+                        uint32_t a_len, uint32_t b_len)
+{
+    int ret = 0;
+    uint32_t i = 0;
+
+    if (a_len != b_len) {
+        return -1;
+    }
+
+    for (i = 0; i < a_len; i++) {
+        if (a[i] != b[i]) {
+            ret = -1;
+            break;
+        }
+    }
+    return ret;
+}
+
+#if defined(MBEDTLS_TEST_HOOKS)
+void mbedtls_test_err_add_check(int high, int low,
+                                const char *file, int line)
+{
+    /* Error codes are always negative (a value of zero is a success) however
+     * their positive opposites can be easier to understand. The following
+     * examples given in comments have been made positive for ease of
+     * understanding. The structure of an error code is such:
+     *
+     *                                                shhhhhhhhlllllll
+     *
+     * s = sign bit.
+     * h = high level error code (includes high level module ID (bits 12..14)
+     *     and module-dependent error code (bits 7..11)).
+     * l = low level error code.
+     */
+    if (high > -0x1000 && high != 0) {
+        /* high < 0001000000000000
+         * No high level module ID bits are set.
+         */
+        mbedtls_test_fail("'high' is not a high-level error code",
+                          line, file);
+    } else if (high < -0x7F80) {
+        /* high > 0111111110000000
+         * Error code is greater than the largest allowed high level module ID.
+         */
+        mbedtls_test_fail("'high' error code is greater than 15 bits",
+                          line, file);
+    } else if ((high & 0x7F) != 0) {
+        /* high & 0000000001111111
+         * Error code contains low level error code bits.
+         */
+        mbedtls_test_fail("'high' contains a low-level error code",
+                          line, file);
+    } else if (low < -0x007F) {
+        /* low >  0000000001111111
+         * Error code contains high or module level error code bits.
+         */
+        mbedtls_test_fail("'low' error code is greater than 7 bits",
+                          line, file);
+    } else if (low > 0) {
+        mbedtls_test_fail("'low' error code is greater than zero",
+                          line, file);
+    }
+}
+
+void (*mbedtls_test_hook_error_add)(int, int, const char *, int);
+
+#endif /* MBEDTLS_TEST_HOOKS */
diff --git a/framework/tests/src/psa_crypto_helpers.c b/framework/tests/src/psa_crypto_helpers.c
new file mode 100644
index 0000000..197fd41
--- /dev/null
+++ b/framework/tests/src/psa_crypto_helpers.c
@@ -0,0 +1,205 @@
+/** \file psa_crypto_helpers.c
+ *
+ * \brief Helper functions to test PSA crypto functionality.
+ */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <test/helpers.h>
+#include <test/macros.h>
+#include <psa_crypto_slot_management.h>
+#include <test/psa_crypto_helpers.h>
+
+#if defined(MBEDTLS_CTR_DRBG_C)
+#include <mbedtls/ctr_drbg.h>
+#endif
+
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+
+#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;
+
+    mbedtls_psa_get_stats(&stats);
+
+    /* Some volatile slots may be used for internal purposes. Generally
+     * we'll have exactly MBEDTLS_TEST_PSA_INTERNAL_KEYS at this point,
+     * but in some cases we might have less, e.g. if a code path calls
+     * PSA_DONE more than once, or if there has only been a partial or
+     * failed initialization. */
+    if (stats.volatile_slots > MBEDTLS_TEST_PSA_INTERNAL_KEYS) {
+        return "A volatile slot has not been closed properly.";
+    }
+    if (stats.persistent_slots != 0) {
+        return "A persistent slot has not been closed properly.";
+    }
+    if (stats.external_slots != 0) {
+        return "An external slot has not been closed properly.";
+    }
+    if (stats.half_filled_slots != 0) {
+        return "A half-filled slot has not been cleared properly.";
+    }
+    if (stats.locked_slots != 0) {
+        return "Some slots are still marked as locked.";
+    }
+
+    return NULL;
+}
+
+#if defined(RECORD_PSA_STATUS_COVERAGE_LOG)
+/** Name of the file where return statuses are logged by #RECORD_STATUS. */
+#define STATUS_LOG_FILE_NAME "statuses.log"
+
+psa_status_t mbedtls_test_record_status(psa_status_t status,
+                                        const char *func,
+                                        const char *file, int line,
+                                        const char *expr)
+{
+    /* We open the log file on first use.
+     * We never close the log file, so the record_status feature is not
+     * compatible with resource leak detectors such as Asan.
+     */
+    static FILE *log;
+    if (log == NULL) {
+        log = fopen(STATUS_LOG_FILE_NAME, "a");
+    }
+    fprintf(log, "%d:%s:%s:%d:%s\n", (int) status, func, file, line, expr);
+    return status;
+}
+#endif /* defined(RECORD_PSA_STATUS_COVERAGE_LOG) */
+
+psa_key_usage_t mbedtls_test_update_key_usage_flags(psa_key_usage_t usage_flags)
+{
+    psa_key_usage_t updated_usage = usage_flags;
+
+    if (usage_flags & PSA_KEY_USAGE_SIGN_HASH) {
+        updated_usage |= PSA_KEY_USAGE_SIGN_MESSAGE;
+    }
+
+    if (usage_flags & PSA_KEY_USAGE_VERIFY_HASH) {
+        updated_usage |= PSA_KEY_USAGE_VERIFY_MESSAGE;
+    }
+
+    return updated_usage;
+}
+
+int mbedtls_test_fail_if_psa_leaking(int line_no, const char *filename)
+{
+    const char *msg = mbedtls_test_helper_is_psa_leaking();
+    if (msg == NULL) {
+        return 0;
+    } else {
+        mbedtls_test_fail(msg, line_no, filename);
+        return 1;
+    }
+}
+
+uint64_t mbedtls_test_parse_binary_string(data_t *bin_string)
+{
+    uint64_t result = 0;
+    TEST_LE_U(bin_string->len, 8);
+    for (size_t i = 0; i < bin_string->len; i++) {
+        result = result << 8 | bin_string->x[i];
+    }
+exit:
+    return result; /* returns 0 if len > 8 */
+}
+
+#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
+
+#include <mbedtls/entropy.h>
+#include <psa_crypto_its.h>
+
+int mbedtls_test_inject_entropy_seed_read(unsigned char *buf, size_t len)
+{
+    size_t actual_len = 0;
+    psa_status_t status = psa_its_get(PSA_CRYPTO_ITS_RANDOM_SEED_UID,
+                                      0, len, buf, &actual_len);
+    if (status != 0) {
+        return MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
+    }
+    if (actual_len != len) {
+        return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
+    }
+    return 0;
+}
+
+int mbedtls_test_inject_entropy_seed_write(unsigned char *buf, size_t len)
+{
+    psa_status_t status = psa_its_set(PSA_CRYPTO_ITS_RANDOM_SEED_UID,
+                                      len, buf, 0);
+    if (status != 0) {
+        return MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
+    }
+    return 0;
+}
+
+int mbedtls_test_inject_entropy_restore(void)
+{
+    unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
+    for (size_t i = 0; i < sizeof(buf); i++) {
+        buf[i] = (unsigned char) i;
+    }
+    psa_status_t status = mbedtls_psa_inject_entropy(buf, sizeof(buf));
+    /* It's ok if the file was just created, or if it already exists. */
+    if (status != PSA_SUCCESS && status != PSA_ERROR_NOT_PERMITTED) {
+        return status;
+    }
+    return PSA_SUCCESS;
+}
+
+#endif /* MBEDTLS_PSA_INJECT_ENTROPY */
+
+#endif /* MBEDTLS_PSA_CRYPTO_C */
diff --git a/framework/tests/src/psa_crypto_stubs.c b/framework/tests/src/psa_crypto_stubs.c
new file mode 100644
index 0000000..8d7ba33
--- /dev/null
+++ b/framework/tests/src/psa_crypto_stubs.c
@@ -0,0 +1,133 @@
+/** \file psa_crypto_stubs.c
+ *
+ * \brief Stub functions when MBEDTLS_PSA_CRYPTO_CLIENT is enabled but
+ *        MBEDTLS_PSA_CRYPTO_C is disabled.
+ */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <psa/crypto.h>
+
+#if defined(MBEDTLS_PSA_CRYPTO_CLIENT) && !defined(MBEDTLS_PSA_CRYPTO_C)
+
+psa_status_t psa_generate_random(uint8_t *output,
+                                 size_t output_size)
+{
+    (void) output;
+    (void) output_size;
+
+    return PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
+psa_status_t psa_export_key(mbedtls_svc_key_id_t key,
+                            uint8_t *data,
+                            size_t data_size,
+                            size_t *data_length)
+{
+    (void) key;
+    (void) data;
+    (void) data_size;
+    (void) data_length;
+    return PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
+psa_status_t psa_export_public_key(mbedtls_svc_key_id_t key,
+                                   uint8_t *data,
+                                   size_t data_size,
+                                   size_t *data_length)
+{
+    (void) key;
+    (void) data;
+    (void) data_size;
+    (void) data_length;
+    return PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
+psa_status_t psa_get_key_attributes(mbedtls_svc_key_id_t key,
+                                    psa_key_attributes_t *attributes)
+{
+    (void) key;
+    (void) attributes;
+    return PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
+psa_status_t psa_hash_abort(psa_hash_operation_t *operation)
+{
+    (void) operation;
+    return PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
+psa_status_t psa_import_key(const psa_key_attributes_t *attributes,
+                            const uint8_t *data,
+                            size_t data_length,
+                            mbedtls_svc_key_id_t *key)
+{
+    (void) attributes;
+    (void) data;
+    (void) data_length;
+    (void) key;
+    return PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
+int psa_can_do_hash(psa_algorithm_t hash_alg)
+{
+    (void) hash_alg;
+    return 0;
+}
+
+psa_status_t psa_hash_clone(const psa_hash_operation_t *source_operation,
+                            psa_hash_operation_t *target_operation)
+{
+    (void) source_operation;
+    (void) target_operation;
+    return PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
+psa_status_t psa_hash_setup(psa_hash_operation_t *operation,
+                            psa_algorithm_t alg)
+{
+    (void) operation;
+    (void) alg;
+    return PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
+psa_status_t psa_hash_update(psa_hash_operation_t *operation,
+                             const uint8_t *input_external,
+                             size_t input_length)
+{
+    (void) operation;
+    (void) input_external;
+    (void) input_length;
+    return PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
+psa_status_t psa_hash_finish(psa_hash_operation_t *operation,
+                             uint8_t *hash_external,
+                             size_t hash_size,
+                             size_t *hash_length)
+{
+    (void) operation;
+    (void) hash_external;
+    (void) hash_size;
+    (void) hash_length;
+    return PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
+psa_status_t psa_hash_compute(psa_algorithm_t alg,
+                              const uint8_t *input_external, size_t input_length,
+                              uint8_t *hash_external, size_t hash_size,
+                              size_t *hash_length)
+{
+    (void) alg;
+    (void) input_external;
+    (void) input_length;
+    (void) hash_external;
+    (void) hash_size;
+    (void) hash_length;
+    return PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
+#endif /* MBEDTLS_PSA_CRYPTO_CLIENT && !MBEDTLS_PSA_CRYPTO_C */
diff --git a/framework/tests/src/psa_exercise_key.c b/framework/tests/src/psa_exercise_key.c
new file mode 100644
index 0000000..b92c1f7
--- /dev/null
+++ b/framework/tests/src/psa_exercise_key.c
@@ -0,0 +1,1434 @@
+/** 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 OR GPL-2.0-or-later
+ */
+
+#include <test/helpers.h>
+#include <test/macros.h>
+#include <test/psa_exercise_key.h>
+
+#if (MBEDTLS_VERSION_MAJOR < 4 && defined(MBEDTLS_PSA_CRYPTO_C)) || \
+    (MBEDTLS_VERSION_MAJOR >= 4 && defined(MBEDTLS_PSA_CRYPTO_CLIENT))
+
+#include <mbedtls/asn1.h>
+#include <psa/crypto.h>
+
+#include <test/asn1_helpers.h>
+#include <psa_crypto_slot_management.h>
+#include <test/psa_crypto_helpers.h>
+
+#if defined(MBEDTLS_PK_C)
+#include <pk_internal.h>
+#endif
+#if defined(MBEDTLS_ECP_C)
+#include <mbedtls/ecp.h>
+#endif
+#if defined(MBEDTLS_RSA_C)
+#include <rsa_internal.h>
+#endif
+
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+static int lifetime_is_dynamic_secure_element(psa_key_lifetime_t lifetime)
+{
+    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 key_destroyable)
+{
+    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_status_t status = psa_get_key_attributes(key, &attributes);
+    if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+        /* The key has been destroyed. */
+        psa_reset_key_attributes(&attributes);
+        return 1;
+    }
+    PSA_ASSERT(status);
+    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)
+    /* MBEDTLS_PSA_CRYPTO_SE_C does not support thread safety. */
+    if (key_destroyable == 0) {
+        /* randomly-generated 64-bit constant, should never appear in test data */
+        psa_key_slot_number_t slot_number = 0xec94d4a5058a1a21;
+        status = psa_get_key_slot_number(&attributes, &slot_number);
+        if (lifetime_is_dynamic_secure_element(lifetime)) {
+            /* Mbed TLS 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,
+                            int key_destroyable)
+{
+    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);
+    psa_status_t status = PSA_SUCCESS;
+    /* Convert wildcard algorithm to exercisable algorithm */
+    if (alg & PSA_ALG_MAC_AT_LEAST_THIS_LENGTH_FLAG) {
+        alg = PSA_ALG_TRUNCATED_MAC(alg, PSA_MAC_TRUNCATED_LENGTH(alg));
+    }
+
+    if (usage & PSA_KEY_USAGE_SIGN_HASH) {
+        status = psa_mac_sign_setup(&operation, key, alg);
+        if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+            /* The key has been destroyed. */
+            PSA_ASSERT(psa_mac_abort(&operation));
+            return 1;
+        }
+        PSA_ASSERT(status);
+        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);
+        status = psa_mac_verify_setup(&operation, key, alg);
+        if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+            /* The key has been destroyed. */
+            PSA_ASSERT(psa_mac_abort(&operation));
+            return 1;
+        }
+        PSA_ASSERT(status);
+        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,
+                               int key_destroyable)
+{
+    psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
+    unsigned char iv[PSA_CIPHER_IV_MAX_SIZE] = { 0 };
+    size_t iv_length;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_type_t key_type;
+    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;
+    psa_status_t status = PSA_SUCCESS;
+
+    PSA_ASSERT(psa_get_key_attributes(key, &attributes));
+    key_type = psa_get_key_type(&attributes);
+    iv_length = PSA_CIPHER_IV_LENGTH(key_type, alg);
+
+    if (usage & PSA_KEY_USAGE_ENCRYPT) {
+        status = psa_cipher_encrypt_setup(&operation, key, alg);
+        if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+            /* The key has been destroyed. */
+            PSA_ASSERT(psa_cipher_abort(&operation));
+            return 1;
+        }
+        PSA_ASSERT(status);
+        if (iv_length != 0) {
+            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) {
+        int maybe_invalid_padding = 0;
+        if (!(usage & PSA_KEY_USAGE_ENCRYPT)) {
+            maybe_invalid_padding = !PSA_ALG_IS_STREAM_CIPHER(alg);
+        }
+        status = psa_cipher_decrypt_setup(&operation, key, alg);
+        if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+            /* The key has been destroyed. */
+            PSA_ASSERT(psa_cipher_abort(&operation));
+            return 1;
+        }
+        PSA_ASSERT(status);
+        if (iv_length != 0) {
+            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 arbitrary 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);
+    psa_reset_key_attributes(&attributes);
+    return 0;
+}
+
+static int exercise_aead_key(mbedtls_svc_key_id_t key,
+                             psa_key_usage_t usage,
+                             psa_algorithm_t alg,
+                             int key_destroyable)
+{
+    unsigned char nonce[PSA_AEAD_NONCE_MAX_SIZE] = { 0 };
+    size_t nonce_length;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_type_t key_type;
+    unsigned char plaintext[16] = "Hello, world...";
+    unsigned char ciphertext[48] = "(wabblewebblewibblewobblewubble)";
+    size_t ciphertext_length = sizeof(ciphertext);
+    size_t plaintext_length = sizeof(ciphertext);
+    psa_status_t status = PSA_SUCCESS;
+
+    /* Convert wildcard algorithm to exercisable algorithm */
+    if (alg & PSA_ALG_AEAD_AT_LEAST_THIS_LENGTH_FLAG) {
+        alg = PSA_ALG_AEAD_WITH_SHORTENED_TAG(alg, PSA_ALG_AEAD_GET_TAG_LENGTH(alg));
+    }
+
+    PSA_ASSERT(psa_get_key_attributes(key, &attributes));
+    key_type = psa_get_key_type(&attributes);
+    nonce_length = PSA_AEAD_NONCE_LENGTH(key_type, alg);
+
+    if (usage & PSA_KEY_USAGE_ENCRYPT) {
+        status = psa_aead_encrypt(key, alg,
+                                  nonce, nonce_length,
+                                  NULL, 0,
+                                  plaintext, sizeof(plaintext),
+                                  ciphertext, sizeof(ciphertext),
+                                  &ciphertext_length);
+        if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+            /* The key has been destroyed. */
+            return 1;
+        }
+        PSA_ASSERT(status);
+    }
+
+    if (usage & PSA_KEY_USAGE_DECRYPT) {
+        psa_status_t verify_status =
+            (usage & PSA_KEY_USAGE_ENCRYPT ?
+             PSA_SUCCESS :
+             PSA_ERROR_INVALID_SIGNATURE);
+        status = psa_aead_decrypt(key, alg,
+                                  nonce, nonce_length,
+                                  NULL, 0,
+                                  ciphertext, ciphertext_length,
+                                  plaintext, sizeof(plaintext),
+                                  &plaintext_length);
+        if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+            /* The key has been destroyed. */
+            return 1;
+        }
+        TEST_ASSERT(status == verify_status);
+    }
+
+    return 1;
+
+exit:
+    psa_reset_key_attributes(&attributes);
+    return 0;
+}
+
+static int can_sign_or_verify_message(psa_key_usage_t usage,
+                                      psa_algorithm_t alg)
+{
+    /* Sign-the-unspecified-hash algorithms can only be used with
+     * {sign,verify}_hash, not with {sign,verify}_message. */
+    if (alg == PSA_ALG_ECDSA_ANY || alg == PSA_ALG_RSA_PKCS1V15_SIGN_RAW) {
+        return 0;
+    }
+    return usage & (PSA_KEY_USAGE_SIGN_MESSAGE |
+                    PSA_KEY_USAGE_VERIFY_MESSAGE);
+}
+
+static int exercise_signature_key(mbedtls_svc_key_id_t key,
+                                  psa_key_usage_t usage,
+                                  psa_algorithm_t alg,
+                                  int key_destroyable)
+{
+    /* If the policy allows signing with any hash, just pick one. */
+    psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH(alg);
+    if (PSA_ALG_IS_SIGN_HASH(alg) && hash_alg == PSA_ALG_ANY_HASH &&
+        usage & (PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH |
+                 PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE)) {
+#if defined(KNOWN_SUPPORTED_HASH_ALG)
+        hash_alg = KNOWN_SUPPORTED_HASH_ALG;
+        alg ^= PSA_ALG_ANY_HASH ^ hash_alg;
+#else
+        TEST_FAIL("No hash algorithm for hash-and-sign testing");
+#endif
+    }
+    psa_status_t status = PSA_SUCCESS;
+
+    if (usage & (PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH) &&
+        PSA_ALG_IS_SIGN_HASH(alg)) {
+        unsigned char payload[PSA_HASH_MAX_SIZE] = { 1 };
+        size_t payload_length = 16;
+        unsigned char signature[PSA_SIGNATURE_MAX_SIZE] = { 0 };
+        size_t signature_length = sizeof(signature);
+
+        /* 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);
+        }
+
+        if (usage & PSA_KEY_USAGE_SIGN_HASH) {
+            status = psa_sign_hash(key, alg,
+                                   payload, payload_length,
+                                   signature, sizeof(signature),
+                                   &signature_length);
+            if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+                /* The key has been destroyed. */
+                return 1;
+            }
+            PSA_ASSERT(status);
+        }
+
+        if (usage & PSA_KEY_USAGE_VERIFY_HASH) {
+            psa_status_t verify_status =
+                (usage & PSA_KEY_USAGE_SIGN_HASH ?
+                 PSA_SUCCESS :
+                 PSA_ERROR_INVALID_SIGNATURE);
+            status = psa_verify_hash(key, alg,
+                                     payload, payload_length,
+                                     signature, signature_length);
+            if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+                /* The key has been destroyed. */
+                return 1;
+            }
+            TEST_ASSERT(status == verify_status);
+        }
+    }
+
+    if (can_sign_or_verify_message(usage, alg)) {
+        unsigned char message[256] = "Hello, world...";
+        unsigned char signature[PSA_SIGNATURE_MAX_SIZE] = { 0 };
+        size_t message_length = 16;
+        size_t signature_length = sizeof(signature);
+
+        if (usage & PSA_KEY_USAGE_SIGN_MESSAGE) {
+            status = psa_sign_message(key, alg,
+                                      message, message_length,
+                                      signature, sizeof(signature),
+                                      &signature_length);
+            if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+                /* The key has been destroyed. */
+                return 1;
+            }
+            PSA_ASSERT(status);
+        }
+
+        if (usage & PSA_KEY_USAGE_VERIFY_MESSAGE) {
+            psa_status_t verify_status =
+                (usage & PSA_KEY_USAGE_SIGN_MESSAGE ?
+                 PSA_SUCCESS :
+                 PSA_ERROR_INVALID_SIGNATURE);
+            status = psa_verify_message(key, alg,
+                                        message, message_length,
+                                        signature, signature_length);
+            if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+                /* The key has been destroyed. */
+                return 1;
+            }
+            TEST_ASSERT(status == 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,
+                                              int key_destroyable)
+{
+    unsigned char plaintext[PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE] =
+        "Hello, world...";
+    unsigned char ciphertext[PSA_ASYMMETRIC_ENCRYPT_OUTPUT_MAX_SIZE] =
+        "(wabblewebblewibblewobblewubble)";
+    size_t ciphertext_length = sizeof(ciphertext);
+    size_t plaintext_length = 16;
+    psa_status_t status = PSA_SUCCESS;
+    if (usage & PSA_KEY_USAGE_ENCRYPT) {
+        status = psa_asymmetric_encrypt(key, alg,
+                                        plaintext, plaintext_length,
+                                        NULL, 0,
+                                        ciphertext, sizeof(ciphertext),
+                                        &ciphertext_length);
+        if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+            /* The key has been destroyed. */
+            return 1;
+        }
+        PSA_ASSERT(status);
+    }
+
+    if (usage & PSA_KEY_USAGE_DECRYPT) {
+        status = psa_asymmetric_decrypt(key, alg,
+                                        ciphertext, ciphertext_length,
+                                        NULL, 0,
+                                        plaintext, sizeof(plaintext),
+                                        &plaintext_length);
+        if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+            /* The key has been destroyed. */
+            return 1;
+        }
+        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, int key_destroyable)
+{
+    PSA_ASSERT(psa_key_derivation_setup(operation, alg));
+    psa_status_t status = PSA_SUCCESS;
+    if (PSA_ALG_IS_HKDF(alg)) {
+        PSA_ASSERT(psa_key_derivation_input_bytes(operation,
+                                                  PSA_KEY_DERIVATION_INPUT_SALT,
+                                                  input1, input1_length));
+        status = psa_key_derivation_input_key(operation,
+                                              PSA_KEY_DERIVATION_INPUT_SECRET,
+                                              key);
+        if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+            /* The key has been destroyed. */
+            return 1;
+        }
+        PSA_ASSERT(status);
+        PSA_ASSERT(psa_key_derivation_input_bytes(operation,
+                                                  PSA_KEY_DERIVATION_INPUT_INFO,
+                                                  input2,
+                                                  input2_length));
+    } else if (PSA_ALG_IS_HKDF_EXTRACT(alg)) {
+        PSA_ASSERT(psa_key_derivation_input_bytes(operation,
+                                                  PSA_KEY_DERIVATION_INPUT_SALT,
+                                                  input1, input1_length));
+        status = psa_key_derivation_input_key(operation,
+                                              PSA_KEY_DERIVATION_INPUT_SECRET,
+                                              key);
+        if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+            /* The key has been destroyed. */
+            return 1;
+        }
+        PSA_ASSERT(status);
+    } else if (PSA_ALG_IS_HKDF_EXPAND(alg)) {
+        status = psa_key_derivation_input_key(operation,
+                                              PSA_KEY_DERIVATION_INPUT_SECRET,
+                                              key);
+        if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+            /* The key has been destroyed. */
+            return 1;
+        }
+        PSA_ASSERT(status);
+        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));
+        status = psa_key_derivation_input_key(operation,
+                                              PSA_KEY_DERIVATION_INPUT_SECRET,
+                                              key);
+        if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+            /* The key has been destroyed. */
+            return 1;
+        }
+        PSA_ASSERT(status);
+        PSA_ASSERT(psa_key_derivation_input_bytes(operation,
+                                                  PSA_KEY_DERIVATION_INPUT_LABEL,
+                                                  input2, input2_length));
+    } else if (PSA_ALG_IS_PBKDF2(alg)) {
+        PSA_ASSERT(psa_key_derivation_input_integer(operation,
+                                                    PSA_KEY_DERIVATION_INPUT_COST,
+                                                    1U));
+        PSA_ASSERT(psa_key_derivation_input_bytes(operation,
+                                                  PSA_KEY_DERIVATION_INPUT_SALT,
+                                                  input2,
+                                                  input2_length));
+        status = psa_key_derivation_input_key(operation,
+                                              PSA_KEY_DERIVATION_INPUT_PASSWORD,
+                                              key);
+        if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+            /* The key has been destroyed. */
+            return 1;
+        }
+        PSA_ASSERT(status);
+    } else if (alg == PSA_ALG_TLS12_ECJPAKE_TO_PMS) {
+        PSA_ASSERT(psa_key_derivation_input_bytes(operation,
+                                                  PSA_KEY_DERIVATION_INPUT_SECRET,
+                                                  input1, input1_length));
+    } else {
+        TEST_FAIL("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,
+                                       int key_destroyable)
+{
+    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, key_destroyable)) {
+            goto exit;
+        }
+
+        psa_status_t status = psa_key_derivation_output_bytes(&operation,
+                                                              output,
+                                                              capacity);
+        if (key_destroyable && status == PSA_ERROR_BAD_STATE) {
+            /* The key has been destroyed. */
+            PSA_ASSERT(psa_key_derivation_abort(&operation));
+        } else {
+            PSA_ASSERT(status);
+            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, int key_destroyable)
+{
+    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;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+    psa_status_t status = psa_get_key_attributes(key, &attributes);
+    if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+        /* The key has been destroyed. */
+        psa_reset_key_attributes(&attributes);
+        return PSA_SUCCESS;
+    }
+    PSA_ASSERT(status);
+
+    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_PUBLIC_KEY_OUTPUT_SIZE(public_key_type, key_bits);
+    TEST_CALLOC(public_key, public_key_length);
+    status = psa_export_public_key(key, public_key, public_key_length,
+                                   &public_key_length);
+    if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+        /* The key has been destroyed. */
+        status = PSA_SUCCESS;
+        goto exit;
+    }
+    PSA_ASSERT(status);
+
+    status = psa_key_derivation_key_agreement(
+        operation, PSA_KEY_DERIVATION_INPUT_SECRET, key,
+        public_key, public_key_length);
+    if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+        /* The key has been destroyed. */
+        status = PSA_SUCCESS;
+        goto exit;
+    }
+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,
+    int key_destroyable)
+{
+    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;
+
+#if MBEDTLS_VERSION_MAJOR >= 4
+    uint8_t *exported = NULL;
+    size_t exported_size = 0;
+    size_t exported_length = 0;
+
+    psa_key_attributes_t export_attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+    mbedtls_svc_key_id_t shared_secret_id = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_key_attributes_t shared_secret_attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+    psa_key_agreement_iop_t iop_operation = psa_key_agreement_iop_init();
+#endif /* MBEDTLS_VERSION_MAJOR >= 4 */
+
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+    psa_status_t status = psa_get_key_attributes(key, &attributes);
+    if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+        /* The key has been destroyed. */
+        psa_reset_key_attributes(&attributes);
+        return PSA_SUCCESS;
+    }
+    PSA_ASSERT(status);
+
+    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_PUBLIC_KEY_OUTPUT_SIZE(public_key_type, key_bits);
+    TEST_CALLOC(public_key, public_key_length);
+    status = psa_export_public_key(key,
+                                   public_key, public_key_length,
+                                   &public_key_length);
+    if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+        /* The key has been destroyed. */
+        status = PSA_SUCCESS;
+        goto exit;
+    }
+    PSA_ASSERT(status);
+
+    status = psa_raw_key_agreement(alg, key,
+                                   public_key, public_key_length,
+                                   output, sizeof(output), &output_length);
+    if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+        /* The key has been destroyed. */
+        status = PSA_SUCCESS;
+        goto exit;
+    }
+    if (status == PSA_SUCCESS) {
+        TEST_ASSERT(output_length <=
+                    PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(private_key_type,
+                                                      key_bits));
+        TEST_ASSERT(output_length <=
+                    PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE);
+    }
+
+#if MBEDTLS_VERSION_MAJOR >= 4
+    psa_set_key_type(&shared_secret_attributes, PSA_KEY_TYPE_DERIVE);
+    psa_set_key_usage_flags(&shared_secret_attributes, PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT);
+
+    status = psa_key_agreement(key, public_key, public_key_length, alg,
+                               &shared_secret_attributes, &shared_secret_id);
+
+    if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+        /* The key has been destroyed. */
+        status = PSA_SUCCESS;
+        goto exit;
+    } else if (status == PSA_SUCCESS) {
+
+        status = psa_get_key_attributes(shared_secret_id, &export_attributes);
+        if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+            /* The key has been destroyed. */
+            status = PSA_SUCCESS;
+            goto exit;
+        }
+
+        exported_size = PSA_EXPORT_KEY_OUTPUT_SIZE(psa_get_key_type(&export_attributes),
+                                                   psa_get_key_bits(&export_attributes));
+        TEST_CALLOC(exported, exported_size);
+
+        status = psa_export_key(shared_secret_id, exported, exported_size, &exported_length);
+
+        if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+            /* The key has been destroyed. */
+            status = PSA_SUCCESS;
+        }
+
+        PSA_ASSERT(status);
+    }
+
+ #if defined(MBEDTLS_ECP_RESTARTABLE) && defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH)
+
+    psa_destroy_key(shared_secret_id);
+
+    if (PSA_KEY_TYPE_IS_ECC(private_key_type)) {
+
+        psa_interruptible_set_max_ops(1);
+
+        status = psa_key_agreement_iop_setup(&iop_operation, key, public_key,
+                                             public_key_length, alg,
+                                             &shared_secret_attributes);
+
+        if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+            /* The key has been destroyed. */
+            status = PSA_SUCCESS;
+            goto exit;
+        } else if (status == PSA_SUCCESS) {
+
+            do {
+                status = psa_key_agreement_iop_complete(&iop_operation, &shared_secret_id);
+            } while (status == PSA_OPERATION_INCOMPLETE);
+
+            if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+                /* The key has been destroyed. */
+                status = PSA_SUCCESS;
+            }
+
+            PSA_ASSERT(status);
+        }
+    } else {
+        TEST_EQUAL(psa_key_agreement_iop_setup(&iop_operation, key, public_key,
+                                               public_key_length, alg,
+                                               &shared_secret_attributes),
+                   PSA_ERROR_INVALID_ARGUMENT);
+    }
+
+#endif // defined(MBEDTLS_ECP_RESTARTABLE) && defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH)
+#endif /* MBEDTLS_VERSION_MAJOR >= 4 */
+
+exit:
+    /*
+     * Key attributes may have been returned by psa_get_key_attributes()
+     * thus reset them as required.
+     */
+    psa_reset_key_attributes(&attributes);
+
+#if MBEDTLS_VERSION_MAJOR >= 4
+    psa_reset_key_attributes(&export_attributes);
+
+    /* Make sure to reset and free derived key attributes and slot. */
+    psa_reset_key_attributes(&shared_secret_attributes);
+    psa_destroy_key(shared_secret_id);
+
+    mbedtls_free(exported);
+    psa_key_agreement_iop_abort(&iop_operation);
+#endif /* MBEDTLS_VERSION_MAJOR >= 4 */
+
+    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 key_destroyable)
+{
+    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,
+                                                                key_destroyable));
+    }
+    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,
+                                      int key_destroyable)
+{
+    psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT;
+    unsigned char input[1] = { 0 };
+    unsigned char output[1];
+    int ok = 0;
+    psa_algorithm_t kdf_alg = PSA_ALG_KEY_AGREEMENT_GET_KDF(alg);
+    psa_status_t expected_key_agreement_status = PSA_SUCCESS;
+
+    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));
+        if (PSA_ALG_IS_TLS12_PRF(kdf_alg) ||
+            PSA_ALG_IS_TLS12_PSK_TO_MS(kdf_alg)) {
+            PSA_ASSERT(psa_key_derivation_input_bytes(
+                           &operation, PSA_KEY_DERIVATION_INPUT_SEED,
+                           input, sizeof(input)));
+        }
+
+        if (PSA_ALG_IS_HKDF_EXTRACT(kdf_alg)) {
+            PSA_ASSERT(psa_key_derivation_input_bytes(
+                           &operation, PSA_KEY_DERIVATION_INPUT_SALT,
+                           input, sizeof(input)));
+        }
+
+        /* For HKDF_EXPAND input secret may fail as secret size may not match
+           to expected PRK size. In practice it means that key bits must match
+           hash length. Otherwise test should fail with INVALID_ARGUMENT. */
+        if (PSA_ALG_IS_HKDF_EXPAND(kdf_alg)) {
+            psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+            psa_status_t status = psa_get_key_attributes(key, &attributes);
+            if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+                /* The key has been destroyed. */
+                ok = 1;
+            }
+            PSA_ASSERT(status);
+            size_t key_bits = psa_get_key_bits(&attributes);
+            psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH(kdf_alg);
+
+            if (PSA_BITS_TO_BYTES(key_bits) != PSA_HASH_LENGTH(hash_alg)) {
+                expected_key_agreement_status = PSA_ERROR_INVALID_ARGUMENT;
+            }
+        }
+
+        TEST_EQUAL(mbedtls_test_psa_key_agreement_with_self(&operation, key,
+                                                            key_destroyable),
+                   expected_key_agreement_status);
+
+        if (expected_key_agreement_status != PSA_SUCCESS) {
+            return 1;
+        }
+
+        if (PSA_ALG_IS_TLS12_PRF(kdf_alg) ||
+            PSA_ALG_IS_TLS12_PSK_TO_MS(kdf_alg)) {
+            PSA_ASSERT(psa_key_derivation_input_bytes(
+                           &operation, PSA_KEY_DERIVATION_INPUT_LABEL,
+                           input, sizeof(input)));
+        } else if (PSA_ALG_IS_HKDF(kdf_alg) || PSA_ALG_IS_HKDF_EXPAND(kdf_alg)) {
+            PSA_ASSERT(psa_key_derivation_input_bytes(
+                           &operation, PSA_KEY_DERIVATION_INPUT_INFO,
+                           input, sizeof(input)));
+        }
+        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_ASN1_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(len, end - p);
+        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, 0);
+
+        TEST_ASSERT(exported_length <= PSA_EXPORT_KEY_PAIR_MAX_SIZE);
+    } else
+#endif /* MBEDTLS_ASN1_PARSE_C */
+
+    if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(type)) {
+        /* Just the secret value */
+        TEST_EQUAL(exported_length, PSA_BITS_TO_BYTES(bits));
+
+        TEST_ASSERT(exported_length <= PSA_EXPORT_KEY_PAIR_MAX_SIZE);
+    } else
+
+#if defined(MBEDTLS_ASN1_PARSE_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(len, end - p);
+        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, 0);
+
+
+        TEST_ASSERT(exported_length <=
+                    PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(type, bits));
+        TEST_ASSERT(exported_length <=
+                    PSA_EXPORT_PUBLIC_KEY_MAX_SIZE);
+    } else
+#endif /* MBEDTLS_ASN1_PARSE_C */
+
+    if (PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(type)) {
+
+        TEST_ASSERT(exported_length <=
+                    PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(type, bits));
+        TEST_ASSERT(exported_length <=
+                    PSA_EXPORT_PUBLIC_KEY_MAX_SIZE);
+
+        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 if (PSA_KEY_TYPE_ECC_GET_FAMILY(type) == PSA_ECC_FAMILY_TWISTED_EDWARDS) {
+            /* The representation of an ECC Edwards public key is
+             * the raw compressed point */
+            TEST_EQUAL(PSA_BITS_TO_BYTES(bits + 1), 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
+    if (PSA_KEY_TYPE_IS_DH_PUBLIC_KEY(type) || PSA_KEY_TYPE_IS_DH_KEY_PAIR(type)) {
+        TEST_ASSERT(exported_length ==
+                    PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(type, bits));
+        TEST_ASSERT(exported_length <=
+                    PSA_EXPORT_PUBLIC_KEY_MAX_SIZE);
+    } else {
+        (void) exported;
+        TEST_FAIL("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,
+                               int key_destroyable)
+{
+    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_status_t status = psa_get_key_attributes(key, &attributes);
+    if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+        /* The key has been destroyed. */
+        psa_reset_key_attributes(&attributes);
+        return 1;
+    }
+    PSA_ASSERT(status);
+
+    exported_size = PSA_EXPORT_KEY_OUTPUT_SIZE(
+        psa_get_key_type(&attributes),
+        psa_get_key_bits(&attributes));
+    TEST_CALLOC(exported, exported_size);
+
+    status = psa_export_key(key, exported, exported_size, &exported_length);
+    if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+        /* The key has been destroyed. */
+        ok = 1;
+        goto exit;
+    } else if ((usage & PSA_KEY_USAGE_EXPORT) == 0 &&
+               !PSA_KEY_TYPE_IS_PUBLIC_KEY(psa_get_key_type(&attributes))) {
+        TEST_EQUAL(status, PSA_ERROR_NOT_PERMITTED);
+        ok = 1;
+        goto exit;
+    }
+    PSA_ASSERT(status);
+    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,
+                                      int key_destroyable)
+{
+    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_status_t status = psa_get_key_attributes(key, &attributes);
+    if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+        /* The key has been destroyed. */
+        psa_reset_key_attributes(&attributes);
+        return 1;
+    }
+    PSA_ASSERT(status);
+    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));
+        TEST_CALLOC(exported, exported_size);
+
+        status = psa_export_public_key(key, exported,
+                                       exported_size, &exported_length);
+        if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+            /* The key has been destroyed. */
+            ok = 1;
+            goto exit;
+        }
+        TEST_EQUAL(status, 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_PUBLIC_KEY_OUTPUT_SIZE(public_type,
+                                                      psa_get_key_bits(&attributes));
+    TEST_CALLOC(exported, exported_size);
+
+    status = psa_export_public_key(key, exported,
+                                   exported_size, &exported_length);
+    if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
+        /* The key has been destroyed. */
+        ok = 1;
+        goto exit;
+    }
+    PSA_ASSERT(status);
+    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 key_destroyable)
+{
+    int ok = 0;
+
+    if (!check_key_attributes_sanity(key, key_destroyable)) {
+        return 0;
+    }
+
+    if (alg == 0) {
+        ok = 1; /* If no algorithm, do nothing (used for raw data "keys"). */
+    } else if (PSA_ALG_IS_MAC(alg)) {
+        ok = exercise_mac_key(key, usage, alg, key_destroyable);
+    } else if (PSA_ALG_IS_CIPHER(alg)) {
+        ok = exercise_cipher_key(key, usage, alg, key_destroyable);
+    } else if (PSA_ALG_IS_AEAD(alg)) {
+        ok = exercise_aead_key(key, usage, alg, key_destroyable);
+    } else if (PSA_ALG_IS_SIGN(alg)) {
+        ok = exercise_signature_key(key, usage, alg, key_destroyable);
+    } else if (PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg)) {
+        ok = exercise_asymmetric_encryption_key(key, usage, alg,
+                                                key_destroyable);
+    } else if (PSA_ALG_IS_KEY_DERIVATION(alg)) {
+        ok = exercise_key_derivation_key(key, usage, alg, key_destroyable);
+    } else if (PSA_ALG_IS_RAW_KEY_AGREEMENT(alg)) {
+        ok = exercise_raw_key_agreement_key(key, usage, alg, key_destroyable);
+    } else if (PSA_ALG_IS_KEY_AGREEMENT(alg)) {
+        ok = exercise_key_agreement_key(key, usage, alg, key_destroyable);
+    } else {
+        TEST_FAIL("No code to exercise this category of algorithm");
+    }
+
+    ok = ok && exercise_export_key(key,
+                                   usage,
+                                   key_destroyable);
+    ok = ok && exercise_export_public_key(key,
+                                          key_destroyable);
+
+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)) {
+        if (PSA_ALG_IS_SIGN_HASH(alg)) {
+            if (PSA_ALG_SIGN_GET_HASH(alg)) {
+                return PSA_KEY_TYPE_IS_PUBLIC_KEY(type) ?
+                       PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE :
+                       PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH |
+                       PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE;
+            }
+        } else if (PSA_ALG_IS_SIGN_MESSAGE(alg)) {
+            return PSA_KEY_TYPE_IS_PUBLIC_KEY(type) ?
+                   PSA_KEY_USAGE_VERIFY_MESSAGE :
+                   PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE;
+        }
+
+        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;
+    }
+
+}
+
+int mbedtls_test_can_exercise_psa_algorithm(psa_algorithm_t alg)
+{
+    /* Reject algorithms that we know are not supported. Default to
+     * attempting exercise, so that if an algorithm is missing from this
+     * function, the result will be a test failure and not silently
+     * omitting exercise. */
+#if !defined(PSA_WANT_ALG_RSA_PKCS1V15_CRYPT)
+    if (alg == PSA_ALG_RSA_PKCS1V15_CRYPT) {
+        return 0;
+    }
+#endif
+#if !defined(PSA_WANT_ALG_RSA_PKCS1V15_SIGN)
+    if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg)) {
+        return 0;
+    }
+#endif
+#if !defined(PSA_WANT_ALG_RSA_PSS)
+    if (PSA_ALG_IS_RSA_PSS_STANDARD_SALT(alg)) {
+        return 0;
+    }
+#endif
+#if !defined(PSA_WANT_ALG_RSA_PSS_ANY_SALT)
+    if (PSA_ALG_IS_RSA_PSS_ANY_SALT(alg)) {
+        return 0;
+    }
+#endif
+#if !defined(PSA_WANT_ALG_ECDSA)
+    if (PSA_ALG_IS_ECDSA(alg)) {
+        return 0;
+    }
+#endif
+#if !defined(PSA_WANT_ALG_DETERMINISTIC_ECDSA)
+    if (PSA_ALG_IS_DETERMINISTIC_ECDSA(alg)) {
+        return 0;
+    }
+#endif
+#if !defined(PSA_WANT_ALG_ECDH)
+    if (PSA_ALG_IS_ECDH(alg)) {
+        return 0;
+    }
+#endif
+    (void) alg;
+    return 1;
+}
+
+#if defined(MBEDTLS_PK_C)
+int mbedtls_test_key_consistency_psa_pk(mbedtls_svc_key_id_t psa_key,
+                                        const mbedtls_pk_context *pk)
+{
+    psa_key_attributes_t psa_attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_attributes_t pk_attributes = PSA_KEY_ATTRIBUTES_INIT;
+    int ok = 0;
+
+    PSA_ASSERT(psa_get_key_attributes(psa_key, &psa_attributes));
+    psa_key_type_t psa_type = psa_get_key_type(&psa_attributes);
+    mbedtls_pk_type_t pk_type = mbedtls_pk_get_type(pk);
+
+    TEST_ASSERT(PSA_KEY_TYPE_IS_PUBLIC_KEY(psa_type) ||
+                PSA_KEY_TYPE_IS_KEY_PAIR(psa_type));
+    TEST_EQUAL(psa_get_key_bits(&psa_attributes), mbedtls_pk_get_bitlen(pk));
+
+    uint8_t pk_public_buffer[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
+    const uint8_t *pk_public = NULL;
+    size_t pk_public_length = 0;
+
+    switch (pk_type) {
+#if defined(MBEDTLS_RSA_C)
+        case MBEDTLS_PK_RSA:
+            TEST_ASSERT(PSA_KEY_TYPE_IS_RSA(psa_type));
+            const mbedtls_rsa_context *rsa = mbedtls_pk_rsa(*pk);
+            uint8_t *const end = pk_public_buffer + sizeof(pk_public_buffer);
+            uint8_t *cursor = end;
+            TEST_LE_U(1, mbedtls_rsa_write_pubkey(rsa,
+                                                  pk_public_buffer, &cursor));
+            pk_public = cursor;
+            pk_public_length = end - pk_public;
+            break;
+#endif
+
+#if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
+        case MBEDTLS_PK_ECKEY:
+        case MBEDTLS_PK_ECKEY_DH:
+        case MBEDTLS_PK_ECDSA:
+            TEST_ASSERT(PSA_KEY_TYPE_IS_ECC(psa_type));
+            TEST_EQUAL(PSA_KEY_TYPE_ECC_GET_FAMILY(psa_type), pk->ec_family);
+            pk_public = pk->pub_raw;
+            pk_public_length = pk->pub_raw_len;
+            break;
+#endif /* MBEDTLS_PK_USE_PSA_EC_DATA */
+
+#if defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) && !defined(MBEDTLS_PK_USE_PSA_EC_DATA)
+        case MBEDTLS_PK_ECKEY:
+        case MBEDTLS_PK_ECKEY_DH:
+        case MBEDTLS_PK_ECDSA:
+            TEST_ASSERT(PSA_KEY_TYPE_IS_ECC(psa_get_key_type(&psa_attributes)));
+            const mbedtls_ecp_keypair *ec = mbedtls_pk_ec_ro(*pk);
+            TEST_EQUAL(mbedtls_ecp_write_public_key(
+                           ec, MBEDTLS_ECP_PF_UNCOMPRESSED, &pk_public_length,
+                           pk_public_buffer, sizeof(pk_public_buffer)), 0);
+            pk_public = pk_public_buffer;
+            break;
+#endif /* PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY && !MBEDTLS_PK_USE_PSA_EC_DATA */
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+        case MBEDTLS_PK_OPAQUE:
+            PSA_ASSERT(psa_get_key_attributes(pk->priv_id, &pk_attributes));
+            psa_key_type_t pk_psa_type = psa_get_key_type(&pk_attributes);
+            TEST_EQUAL(PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(psa_type),
+                       PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(pk_psa_type));
+            PSA_ASSERT(psa_export_public_key(psa_key,
+                                             pk_public_buffer,
+                                             sizeof(pk_public_buffer),
+                                             &pk_public_length));
+            pk_public = pk_public_buffer;
+            break;
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+        default:
+            TEST_FAIL("pk type not supported");
+    }
+
+    uint8_t psa_public[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
+    size_t psa_public_length = 0;
+    PSA_ASSERT(psa_export_public_key(psa_key,
+                                     psa_public, sizeof(psa_public),
+                                     &psa_public_length));
+    TEST_MEMORY_COMPARE(pk_public, pk_public_length,
+                        psa_public, psa_public_length);
+
+    ok = 1;
+
+exit:
+    psa_reset_key_attributes(&psa_attributes);
+    psa_reset_key_attributes(&pk_attributes);
+    return ok;
+}
+#endif /* MBEDTLS_PK_C */
+
+#endif /* MBEDTLS_PSA_CRYPTO_C || MBEDTLS_PSA_CRYPTO_CLIENT */
diff --git a/framework/tests/src/psa_memory_poisoning_wrappers.c b/framework/tests/src/psa_memory_poisoning_wrappers.c
new file mode 100644
index 0000000..7b48c7c
--- /dev/null
+++ b/framework/tests/src/psa_memory_poisoning_wrappers.c
@@ -0,0 +1,32 @@
+/** Helper functions for memory poisoning in tests.
+ */
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+#include <test/memory.h>
+#include <test/psa_memory_poisoning_wrappers.h>
+
+#include "psa_crypto_invasive.h"
+
+#if defined(MBEDTLS_TEST_HOOKS)  && defined(MBEDTLS_PSA_CRYPTO_C) \
+    && defined(MBEDTLS_TEST_MEMORY_CAN_POISON)
+
+void mbedtls_poison_test_hooks_setup(void)
+{
+    psa_input_pre_copy_hook = mbedtls_test_memory_unpoison;
+    psa_input_post_copy_hook = mbedtls_test_memory_poison;
+    psa_output_pre_copy_hook = mbedtls_test_memory_unpoison;
+    psa_output_post_copy_hook = mbedtls_test_memory_poison;
+}
+
+void mbedtls_poison_test_hooks_teardown(void)
+{
+    psa_input_pre_copy_hook = NULL;
+    psa_input_post_copy_hook = NULL;
+    psa_output_pre_copy_hook = NULL;
+    psa_output_post_copy_hook = NULL;
+}
+
+#endif /* MBEDTLS_TEST_HOOKS && MBEDTLS_PSA_CRYPTO_C &&
+          MBEDTLS_TEST_MEMORY_CAN_POISON */
diff --git a/framework/tests/src/random.c b/framework/tests/src/random.c
new file mode 100644
index 0000000..d041f36
--- /dev/null
+++ b/framework/tests/src/random.c
@@ -0,0 +1,136 @@
+/**
+ * \file random.c
+ *
+ * \brief   This file contains the helper functions to generate random numbers
+ *          for the purpose of testing.
+ */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+/*
+ * for arc4random_buf() from <stdlib.h>
+ */
+#if defined(__NetBSD__)
+#define _NETBSD_SOURCE 1
+#elif defined(__OpenBSD__)
+#define _BSD_SOURCE 1
+#endif
+
+#include <test/macros.h>
+#include <test/random.h>
+#include <string.h>
+
+#include <mbedtls/entropy.h>
+#include <alignment.h>
+
+int mbedtls_test_rnd_std_rand(void *rng_state,
+                              unsigned char *output,
+                              size_t len)
+{
+#if !defined(__OpenBSD__) && !defined(__NetBSD__)
+    size_t i;
+
+    if (rng_state != NULL) {
+        rng_state  = NULL;
+    }
+
+    for (i = 0; i < len; ++i) {
+        output[i] = rand();
+    }
+#else
+    if (rng_state != NULL) {
+        rng_state = NULL;
+    }
+
+    arc4random_buf(output, len);
+#endif /* !OpenBSD && !NetBSD */
+
+    return 0;
+}
+
+int mbedtls_test_rnd_zero_rand(void *rng_state,
+                               unsigned char *output,
+                               size_t len)
+{
+    if (rng_state != NULL) {
+        rng_state  = NULL;
+    }
+
+    memset(output, 0, len);
+
+    return 0;
+}
+
+int mbedtls_test_rnd_buffer_rand(void *rng_state,
+                                 unsigned char *output,
+                                 size_t len)
+{
+    mbedtls_test_rnd_buf_info *info = (mbedtls_test_rnd_buf_info *) rng_state;
+    size_t use_len;
+
+    if (rng_state == NULL) {
+        return mbedtls_test_rnd_std_rand(NULL, output, len);
+    }
+
+    use_len = len;
+    if (len > info->length) {
+        use_len = info->length;
+    }
+
+    if (use_len) {
+        memcpy(output, info->buf, use_len);
+        info->buf += use_len;
+        info->length -= use_len;
+    }
+
+    if (len - use_len > 0) {
+        if (info->fallback_f_rng != NULL) {
+            return info->fallback_f_rng(info->fallback_p_rng,
+                                        output + use_len,
+                                        len - use_len);
+        } else {
+            return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
+        }
+    }
+
+    return 0;
+}
+
+int mbedtls_test_rnd_pseudo_rand(void *rng_state,
+                                 unsigned char *output,
+                                 size_t len)
+{
+    mbedtls_test_rnd_pseudo_info *info =
+        (mbedtls_test_rnd_pseudo_info *) rng_state;
+    uint32_t i, *k, sum, delta = 0x9E3779B9;
+    unsigned char result[4], *out = output;
+
+    if (rng_state == NULL) {
+        return mbedtls_test_rnd_std_rand(NULL, output, len);
+    }
+
+    k = info->key;
+
+    while (len > 0) {
+        size_t use_len = (len > 4) ? 4 : len;
+        sum = 0;
+
+        for (i = 0; i < 32; i++) {
+            info->v0 += (((info->v1 << 4) ^ (info->v1 >> 5))
+                         + info->v1) ^ (sum + k[sum & 3]);
+            sum += delta;
+            info->v1 += (((info->v0 << 4) ^ (info->v0 >> 5))
+                         + info->v0) ^ (sum + k[(sum>>11) & 3]);
+        }
+
+        MBEDTLS_PUT_UINT32_BE(info->v0, result, 0);
+        memcpy(out, result, use_len);
+        len -= use_len;
+        out += 4;
+    }
+
+    return 0;
+}
diff --git a/framework/tests/src/test_memory.c b/framework/tests/src/test_memory.c
new file mode 100644
index 0000000..ac9dde6
--- /dev/null
+++ b/framework/tests/src/test_memory.c
@@ -0,0 +1,60 @@
+/**
+ * \file memory.c
+ *
+ * \brief   Helper functions related to testing memory management.
+ */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <test/helpers.h>
+#include <test/macros.h>
+#include <test/memory.h>
+
+#if defined(MBEDTLS_TEST_MEMORY_CAN_POISON)
+#include <sanitizer/asan_interface.h>
+#include <stdint.h>
+#endif
+
+#if defined(MBEDTLS_TEST_MEMORY_CAN_POISON)
+
+_Thread_local unsigned int mbedtls_test_memory_poisoning_count = 0;
+
+static void align_for_asan(const unsigned char **p_ptr, size_t *p_size)
+{
+    uintptr_t start = (uintptr_t) *p_ptr;
+    uintptr_t end = start + (uintptr_t) *p_size;
+    /* ASan can only poison regions with 8-byte alignment, and only poisons a
+     * region if it's fully within the requested range. We want to poison the
+     * whole requested region and don't mind a few extra bytes. Therefore,
+     * align start down to an 8-byte boundary, and end up to an 8-byte
+     * boundary. */
+    start = start & ~(uintptr_t) 7;
+    end = (end + 7) & ~(uintptr_t) 7;
+    *p_ptr = (const unsigned char *) start;
+    *p_size = end - start;
+}
+
+void mbedtls_test_memory_poison(const unsigned char *ptr, size_t size)
+{
+    if (mbedtls_test_memory_poisoning_count == 0) {
+        return;
+    }
+    if (size == 0) {
+        return;
+    }
+    align_for_asan(&ptr, &size);
+    __asan_poison_memory_region(ptr, size);
+}
+
+void mbedtls_test_memory_unpoison(const unsigned char *ptr, size_t size)
+{
+    if (size == 0) {
+        return;
+    }
+    align_for_asan(&ptr, &size);
+    __asan_unpoison_memory_region(ptr, size);
+}
+#endif /* Memory poisoning */
diff --git a/framework/tests/src/threading_helpers.c b/framework/tests/src/threading_helpers.c
new file mode 100644
index 0000000..c1686c2
--- /dev/null
+++ b/framework/tests/src/threading_helpers.c
@@ -0,0 +1,354 @@
+/** Mutex usage verification framework. */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <test/helpers.h>
+#include <test/threading_helpers.h>
+#include <test/macros.h>
+
+#include "mbedtls/threading.h"
+
+#if defined(MBEDTLS_THREADING_C)
+
+#if defined(MBEDTLS_THREADING_PTHREAD)
+
+static int threading_thread_create_pthread(mbedtls_test_thread_t *thread, void *(*thread_func)(
+                                               void *), void *thread_data)
+{
+    if (thread == NULL || thread_func == NULL) {
+        return MBEDTLS_ERR_THREADING_BAD_INPUT_DATA;
+    }
+
+    if (pthread_create(&thread->thread, NULL, thread_func, thread_data)) {
+        return MBEDTLS_ERR_THREADING_THREAD_ERROR;
+    }
+
+    return 0;
+}
+
+static int threading_thread_join_pthread(mbedtls_test_thread_t *thread)
+{
+    if (thread == NULL) {
+        return MBEDTLS_ERR_THREADING_BAD_INPUT_DATA;
+    }
+
+    if (pthread_join(thread->thread, NULL) != 0) {
+        return MBEDTLS_ERR_THREADING_THREAD_ERROR;
+    }
+
+    return 0;
+}
+
+int (*mbedtls_test_thread_create)(mbedtls_test_thread_t *thread, void *(*thread_func)(void *),
+                                  void *thread_data) = threading_thread_create_pthread;
+int (*mbedtls_test_thread_join)(mbedtls_test_thread_t *thread) = threading_thread_join_pthread;
+
+#endif /* MBEDTLS_THREADING_PTHREAD */
+
+#if defined(MBEDTLS_THREADING_ALT)
+
+static int threading_thread_create_fail(mbedtls_test_thread_t *thread,
+                                        void *(*thread_func)(void *),
+                                        void *thread_data)
+{
+    (void) thread;
+    (void) thread_func;
+    (void) thread_data;
+
+    return MBEDTLS_ERR_THREADING_BAD_INPUT_DATA;
+}
+
+static int threading_thread_join_fail(mbedtls_test_thread_t *thread)
+{
+    (void) thread;
+
+    return MBEDTLS_ERR_THREADING_BAD_INPUT_DATA;
+}
+
+int (*mbedtls_test_thread_create)(mbedtls_test_thread_t *thread, void *(*thread_func)(void *),
+                                  void *thread_data) = threading_thread_create_fail;
+int (*mbedtls_test_thread_join)(mbedtls_test_thread_t *thread) = threading_thread_join_fail;
+
+#endif /* MBEDTLS_THREADING_ALT */
+
+#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_state_field {
+    /* Potential values for the state 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 mbedtls_test_wrap_mutex_free
+    MUTEX_IDLE = 1, //! < Set by mbedtls_test_wrap_mutex_init and by mbedtls_test_wrap_mutex_unlock
+    MUTEX_LOCKED = 2, //! < Set by mbedtls_test_wrap_mutex_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 mutex used to guard live_mutexes below and access to the status variable
+ *  in every mbedtls_threading_mutex_t.
+ *  Note that we are not reporting any errors when locking and unlocking this
+ *  mutex. This is for a couple of reasons:
+ *
+ *  1. We have no real way of reporting any errors with this mutex - we cannot
+ *  report it back to the caller, as the failure was not that of the mutex
+ *  passed in. We could fail the test, but again this would indicate a problem
+ *  with the test code that did not exist.
+ *
+ *  2. Any failure to lock is unlikely to be intermittent, and will thus not
+ *  give false test results - the overall result would be to turn off the
+ *  testing. This is not a situation that is likely to happen with normal
+ *  testing and we still have TSan to fall back on should this happen.
+ */
+mbedtls_threading_mutex_t mbedtls_test_mutex_mutex;
+
+/**
+ *  The total number of calls to mbedtls_mutex_init(), minus the total number
+ *  of calls to mbedtls_mutex_free().
+ *
+ *  Do not read or write without holding mbedtls_test_mutex_mutex (above). 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;
+
+    mbedtls_test_set_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 int mbedtls_test_mutex_can_test(mbedtls_threading_mutex_t *mutex)
+{
+    /* If we attempt to run tests on this mutex then we are going to run into a
+     * couple of problems:
+     * 1. If any test on this mutex fails, we are going to deadlock when
+     * reporting that failure, as we already hold the mutex at that point.
+     * 2. Given the 'global' position of the initialization and free of this
+     * mutex, it will be shown as leaked on the first test run. */
+    if (mutex == mbedtls_test_get_info_mutex()) {
+        return 0;
+    }
+
+    return 1;
+}
+
+static void mbedtls_test_wrap_mutex_init(mbedtls_threading_mutex_t *mutex)
+{
+    mutex_functions.init(mutex);
+
+    if (mbedtls_test_mutex_can_test(mutex)) {
+        if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
+            mutex->state = MUTEX_IDLE;
+            ++live_mutexes;
+
+            mutex_functions.unlock(&mbedtls_test_mutex_mutex);
+        }
+    }
+}
+
+static void mbedtls_test_wrap_mutex_free(mbedtls_threading_mutex_t *mutex)
+{
+    if (mbedtls_test_mutex_can_test(mutex)) {
+        if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
+
+            switch (mutex->state) {
+                case MUTEX_FREED:
+                    mbedtls_test_mutex_usage_error(mutex, "free without init or double free");
+                    break;
+                case MUTEX_IDLE:
+                    mutex->state = MUTEX_FREED;
+                    --live_mutexes;
+                    break;
+                case MUTEX_LOCKED:
+                    mbedtls_test_mutex_usage_error(mutex, "free without unlock");
+                    break;
+                default:
+                    mbedtls_test_mutex_usage_error(mutex, "corrupted state");
+                    break;
+            }
+
+            mutex_functions.unlock(&mbedtls_test_mutex_mutex);
+        }
+    }
+
+    mutex_functions.free(mutex);
+}
+
+static int mbedtls_test_wrap_mutex_lock(mbedtls_threading_mutex_t *mutex)
+{
+    /* Lock the passed in mutex first, so that the only way to change the state
+     * is to hold the passed in and internal mutex - otherwise we create a race
+     * condition. */
+    int ret = mutex_functions.lock(mutex);
+
+    if (mbedtls_test_mutex_can_test(mutex)) {
+        if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
+            switch (mutex->state) {
+                case MUTEX_FREED:
+                    mbedtls_test_mutex_usage_error(mutex, "lock without init");
+                    break;
+                case MUTEX_IDLE:
+                    if (ret == 0) {
+                        mutex->state = MUTEX_LOCKED;
+                    }
+                    break;
+                case MUTEX_LOCKED:
+                    mbedtls_test_mutex_usage_error(mutex, "double lock");
+                    break;
+                default:
+                    mbedtls_test_mutex_usage_error(mutex, "corrupted state");
+                    break;
+            }
+
+            mutex_functions.unlock(&mbedtls_test_mutex_mutex);
+        }
+    }
+
+    return ret;
+}
+
+static int mbedtls_test_wrap_mutex_unlock(mbedtls_threading_mutex_t *mutex)
+{
+    /* Lock the internal mutex first and change state, so that the only way to
+     * change the state is to hold the passed in and internal mutex - otherwise
+     * we create a race condition. */
+    if (mbedtls_test_mutex_can_test(mutex)) {
+        if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
+            switch (mutex->state) {
+                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:
+                    mutex->state = MUTEX_IDLE;
+                    break;
+                default:
+                    mbedtls_test_mutex_usage_error(mutex, "corrupted state");
+                    break;
+            }
+            mutex_functions.unlock(&mbedtls_test_mutex_mutex);
+        }
+    }
+
+    return mutex_functions.unlock(mutex);
+}
+
+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;
+
+    mutex_functions.init(&mbedtls_test_mutex_mutex);
+}
+
+void mbedtls_test_mutex_usage_check(void)
+{
+    if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
+        if (live_mutexes != 0) {
+            /* A positive number (more init than free) means that a mutex resource
+             * is leaking (on platforms where a mutex consumes more than the
+             * mbedtls_threading_mutex_t object itself). The (hopefully) rare
+             * case of a negative number means a missing init somewhere. */
+            mbedtls_fprintf(stdout, "[mutex: %d leaked] ", live_mutexes);
+            live_mutexes = 0;
+            mbedtls_test_set_mutex_usage_error("missing free");
+        }
+        if (mbedtls_test_get_mutex_usage_error() != NULL &&
+            mbedtls_test_get_result() != MBEDTLS_TEST_RESULT_FAILED) {
+            /* Functionally, the test passed. But there was a mutex usage error,
+             * so mark the test as failed after all. */
+            mbedtls_test_fail("Mutex usage error", __LINE__, __FILE__);
+        }
+        mbedtls_test_set_mutex_usage_error(NULL);
+
+        mutex_functions.unlock(&mbedtls_test_mutex_mutex);
+    }
+}
+
+void mbedtls_test_mutex_usage_end(void)
+{
+    mbedtls_mutex_init = mutex_functions.init;
+    mbedtls_mutex_free = mutex_functions.free;
+    mbedtls_mutex_lock = mutex_functions.lock;
+    mbedtls_mutex_unlock = mutex_functions.unlock;
+
+    mutex_functions.free(&mbedtls_test_mutex_mutex);
+}
+
+#endif /* MBEDTLS_TEST_MUTEX_USAGE */
+
+#endif /* MBEDTLS_THREADING_C */