Added framework as a flattened directory
Signed-off-by: Minos Galanakis <minos.galanakis@arm.com>
diff --git a/framework/tests/.gitignore b/framework/tests/.gitignore
new file mode 100644
index 0000000..6f90b6e
--- /dev/null
+++ b/framework/tests/.gitignore
@@ -0,0 +1,2 @@
+# Generated file created by TF-PSA-Crypto and mbedtls
+/include/test/test_keys.h
diff --git a/framework/tests/.jenkins/Jenkinsfile b/framework/tests/.jenkins/Jenkinsfile
new file mode 100644
index 0000000..8f71157
--- /dev/null
+++ b/framework/tests/.jenkins/Jenkinsfile
@@ -0,0 +1 @@
+mbedtls.run_framework_pr_job()
diff --git a/framework/tests/include/alt-extra/psa/crypto.h b/framework/tests/include/alt-extra/psa/crypto.h
new file mode 100644
index 0000000..005f3ae
--- /dev/null
+++ b/framework/tests/include/alt-extra/psa/crypto.h
@@ -0,0 +1,7 @@
+/* The goal of the include/alt-extra directory is to test what happens
+ * if certain files come _after_ the normal include directory.
+ * Make sure that if the alt-extra directory comes before the normal
+ * directory (so we wouldn't be achieving our test objective), the build
+ * will fail.
+ */
+#error "The normal include directory must come first in the include path"
diff --git a/framework/tests/include/baremetal-override/time.h b/framework/tests/include/baremetal-override/time.h
new file mode 100644
index 0000000..0a44275
--- /dev/null
+++ b/framework/tests/include/baremetal-override/time.h
@@ -0,0 +1,6 @@
+/*
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#error "time.h included in a configuration without MBEDTLS_HAVE_TIME"
diff --git a/framework/tests/include/spe/crypto_spe.h b/framework/tests/include/spe/crypto_spe.h
new file mode 100644
index 0000000..fdf3a2d
--- /dev/null
+++ b/framework/tests/include/spe/crypto_spe.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ *
+ */
+
+/**
+ * \file crypto_spe.h
+ *
+ * \brief When Mbed TLS is built with the MBEDTLS_PSA_CRYPTO_SPM option
+ * enabled, this header is included by all .c files in Mbed TLS that
+ * use PSA Crypto function names. This avoids duplication of symbols
+ * between TF-M and Mbed TLS.
+ *
+ * \note This file should be included before including any PSA Crypto headers
+ * from Mbed TLS.
+ */
+
+#ifndef CRYPTO_SPE_H
+#define CRYPTO_SPE_H
+
+#define PSA_FUNCTION_NAME(x) mbedcrypto__ ## x
+
+#define psa_crypto_init \
+ PSA_FUNCTION_NAME(psa_crypto_init)
+#define psa_key_derivation_get_capacity \
+ PSA_FUNCTION_NAME(psa_key_derivation_get_capacity)
+#define psa_key_derivation_set_capacity \
+ PSA_FUNCTION_NAME(psa_key_derivation_set_capacity)
+#define psa_key_derivation_input_bytes \
+ PSA_FUNCTION_NAME(psa_key_derivation_input_bytes)
+#define psa_key_derivation_output_bytes \
+ PSA_FUNCTION_NAME(psa_key_derivation_output_bytes)
+#define psa_key_derivation_input_key \
+ PSA_FUNCTION_NAME(psa_key_derivation_input_key)
+#define psa_key_derivation_output_key \
+ PSA_FUNCTION_NAME(psa_key_derivation_output_key)
+#define psa_key_derivation_setup \
+ PSA_FUNCTION_NAME(psa_key_derivation_setup)
+#define psa_key_derivation_abort \
+ PSA_FUNCTION_NAME(psa_key_derivation_abort)
+#define psa_key_derivation_key_agreement \
+ PSA_FUNCTION_NAME(psa_key_derivation_key_agreement)
+#define psa_raw_key_agreement \
+ PSA_FUNCTION_NAME(psa_raw_key_agreement)
+#define psa_generate_random \
+ PSA_FUNCTION_NAME(psa_generate_random)
+#define psa_aead_encrypt \
+ PSA_FUNCTION_NAME(psa_aead_encrypt)
+#define psa_aead_decrypt \
+ PSA_FUNCTION_NAME(psa_aead_decrypt)
+#define psa_open_key \
+ PSA_FUNCTION_NAME(psa_open_key)
+#define psa_close_key \
+ PSA_FUNCTION_NAME(psa_close_key)
+#define psa_import_key \
+ PSA_FUNCTION_NAME(psa_import_key)
+#define psa_destroy_key \
+ PSA_FUNCTION_NAME(psa_destroy_key)
+#define psa_get_key_attributes \
+ PSA_FUNCTION_NAME(psa_get_key_attributes)
+#define psa_reset_key_attributes \
+ PSA_FUNCTION_NAME(psa_reset_key_attributes)
+#define psa_export_key \
+ PSA_FUNCTION_NAME(psa_export_key)
+#define psa_export_public_key \
+ PSA_FUNCTION_NAME(psa_export_public_key)
+#define psa_purge_key \
+ PSA_FUNCTION_NAME(psa_purge_key)
+#define psa_copy_key \
+ PSA_FUNCTION_NAME(psa_copy_key)
+#define psa_cipher_operation_init \
+ PSA_FUNCTION_NAME(psa_cipher_operation_init)
+#define psa_cipher_generate_iv \
+ PSA_FUNCTION_NAME(psa_cipher_generate_iv)
+#define psa_cipher_set_iv \
+ PSA_FUNCTION_NAME(psa_cipher_set_iv)
+#define psa_cipher_encrypt_setup \
+ PSA_FUNCTION_NAME(psa_cipher_encrypt_setup)
+#define psa_cipher_decrypt_setup \
+ PSA_FUNCTION_NAME(psa_cipher_decrypt_setup)
+#define psa_cipher_update \
+ PSA_FUNCTION_NAME(psa_cipher_update)
+#define psa_cipher_finish \
+ PSA_FUNCTION_NAME(psa_cipher_finish)
+#define psa_cipher_abort \
+ PSA_FUNCTION_NAME(psa_cipher_abort)
+#define psa_hash_operation_init \
+ PSA_FUNCTION_NAME(psa_hash_operation_init)
+#define psa_hash_setup \
+ PSA_FUNCTION_NAME(psa_hash_setup)
+#define psa_hash_update \
+ PSA_FUNCTION_NAME(psa_hash_update)
+#define psa_hash_finish \
+ PSA_FUNCTION_NAME(psa_hash_finish)
+#define psa_hash_verify \
+ PSA_FUNCTION_NAME(psa_hash_verify)
+#define psa_hash_abort \
+ PSA_FUNCTION_NAME(psa_hash_abort)
+#define psa_hash_clone \
+ PSA_FUNCTION_NAME(psa_hash_clone)
+#define psa_hash_compute \
+ PSA_FUNCTION_NAME(psa_hash_compute)
+#define psa_hash_compare \
+ PSA_FUNCTION_NAME(psa_hash_compare)
+#define psa_mac_operation_init \
+ PSA_FUNCTION_NAME(psa_mac_operation_init)
+#define psa_mac_sign_setup \
+ PSA_FUNCTION_NAME(psa_mac_sign_setup)
+#define psa_mac_verify_setup \
+ PSA_FUNCTION_NAME(psa_mac_verify_setup)
+#define psa_mac_update \
+ PSA_FUNCTION_NAME(psa_mac_update)
+#define psa_mac_sign_finish \
+ PSA_FUNCTION_NAME(psa_mac_sign_finish)
+#define psa_mac_verify_finish \
+ PSA_FUNCTION_NAME(psa_mac_verify_finish)
+#define psa_mac_abort \
+ PSA_FUNCTION_NAME(psa_mac_abort)
+#define psa_sign_hash \
+ PSA_FUNCTION_NAME(psa_sign_hash)
+#define psa_verify_hash \
+ PSA_FUNCTION_NAME(psa_verify_hash)
+#define psa_asymmetric_encrypt \
+ PSA_FUNCTION_NAME(psa_asymmetric_encrypt)
+#define psa_asymmetric_decrypt \
+ PSA_FUNCTION_NAME(psa_asymmetric_decrypt)
+#define psa_generate_key \
+ PSA_FUNCTION_NAME(psa_generate_key)
+
+#endif /* CRYPTO_SPE_H */
diff --git a/framework/tests/include/test/arguments.h b/framework/tests/include/test/arguments.h
new file mode 100644
index 0000000..6d267b6
--- /dev/null
+++ b/framework/tests/include/test/arguments.h
@@ -0,0 +1,26 @@
+/**
+ * \file arguments.h
+ *
+ * \brief Manipulation of test arguments.
+ *
+ * Much of the code is in host_test.function, to be migrated here later.
+ */
+
+/*
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef TEST_ARGUMENTS_H
+#define TEST_ARGUMENTS_H
+
+#include "mbedtls/build_info.h"
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef union {
+ size_t len;
+ intmax_t sint;
+} mbedtls_test_argument_t;
+
+#endif /* TEST_ARGUMENTS_H */
diff --git a/framework/tests/include/test/asn1_helpers.h b/framework/tests/include/test/asn1_helpers.h
new file mode 100644
index 0000000..2eb9171
--- /dev/null
+++ b/framework/tests/include/test/asn1_helpers.h
@@ -0,0 +1,38 @@
+/** 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
+ */
+
+#ifndef ASN1_HELPERS_H
+#define ASN1_HELPERS_H
+
+#include "test/helpers.h"
+
+/** Skip past an INTEGER in an ASN.1 buffer.
+ *
+ * Mark the current test case as failed in any of the following conditions:
+ * - The buffer does not start with an ASN.1 INTEGER.
+ * - The integer's size or parity does not match the constraints expressed
+ * through \p min_bits, \p max_bits and \p must_be_odd.
+ *
+ * \param p Upon entry, `*p` points to the first byte of the
+ * buffer to parse.
+ * On successful return, `*p` points to the first byte
+ * after the parsed INTEGER.
+ * On failure, `*p` is unspecified.
+ * \param end The end of the ASN.1 buffer.
+ * \param min_bits Fail the test case if the integer does not have at
+ * least this many significant bits.
+ * \param max_bits Fail the test case if the integer has more than
+ * this many significant bits.
+ * \param must_be_odd Fail the test case if the integer is even.
+ *
+ * \return \c 0 if the test failed, otherwise 1.
+ */
+int mbedtls_test_asn1_skip_integer(unsigned char **p, const unsigned char *end,
+ size_t min_bits, size_t max_bits,
+ int must_be_odd);
+
+#endif /* ASN1_HELPERS_H */
diff --git a/framework/tests/include/test/bignum_codepath_check.h b/framework/tests/include/test/bignum_codepath_check.h
new file mode 100644
index 0000000..3d72be1
--- /dev/null
+++ b/framework/tests/include/test/bignum_codepath_check.h
@@ -0,0 +1,94 @@
+/** Support for path tracking in optionally safe bignum functions
+ *
+ * The functions are called when an optionally safe path is taken and logs it with a single
+ * variable. This variable is at any time in one of three states:
+ * - MBEDTLS_MPI_IS_TEST: No optionally safe path has been taken since the last reset
+ * - MBEDTLS_MPI_IS_SECRET: Only safe paths were teken since the last reset
+ * - MBEDTLS_MPI_IS_PUBLIC: At least one unsafe path has been taken since the last reset
+ *
+ * Use a simple global variable to track execution path. Making it work with multithreading
+ * isn't worth the effort as multithreaded tests add little to no value here.
+ */
+/*
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef BIGNUM_CODEPATH_CHECK_H
+#define BIGNUM_CODEPATH_CHECK_H
+
+#include "bignum_core.h"
+
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+
+extern int mbedtls_codepath_check;
+
+/**
+ * \brief Setup the codepath test hooks used by optionally safe bignum functions to signal
+ * the path taken.
+ */
+void mbedtls_codepath_test_hooks_setup(void);
+
+/**
+ * \brief Teardown the codepath test hooks used by optionally safe bignum functions to
+ * signal the path taken.
+ */
+void mbedtls_codepath_test_hooks_teardown(void);
+
+/**
+ * \brief Reset the state of the codepath to the initial state.
+ */
+static inline void mbedtls_codepath_reset(void)
+{
+ mbedtls_codepath_check = MBEDTLS_MPI_IS_TEST;
+}
+
+/** Check the codepath taken and fail if it doesn't match.
+ *
+ * When a function returns with an error, it can do so before reaching any interesting codepath. The
+ * same can happen if a parameter to the function is zero. In these cases we need to allow
+ * the codepath tracking variable to still have its initial "not set" value.
+ *
+ * This macro expands to an instruction, not an expression.
+ * It may jump to the \c exit label.
+ *
+ * \param path The expected codepath.
+ * This expression may be evaluated multiple times.
+ * \param ret The expected return value.
+ * \param E The MPI parameter that can cause shortcuts.
+ */
+#define ASSERT_BIGNUM_CODEPATH(path, ret, E) \
+ do { \
+ if ((ret) != 0 || (E).n == 0) { \
+ TEST_ASSERT(mbedtls_codepath_check == (path) || \
+ mbedtls_codepath_check == MBEDTLS_MPI_IS_TEST); \
+ } else { \
+ TEST_EQUAL(mbedtls_codepath_check, (path)); \
+ } \
+ } while (0)
+
+/** Check the codepath taken and fail if it doesn't match.
+ *
+ * When a function returns with an error, it can do so before reaching any interesting codepath. In
+ * this case we need to allow the codepath tracking variable to still have its
+ * initial "not set" value.
+ *
+ * This macro expands to an instruction, not an expression.
+ * It may jump to the \c exit label.
+ *
+ * \param path The expected codepath.
+ * This expression may be evaluated multiple times.
+ * \param ret The expected return value.
+ */
+#define ASSERT_RSA_CODEPATH(path, ret) \
+ do { \
+ if ((ret) != 0) { \
+ TEST_ASSERT(mbedtls_codepath_check == (path) || \
+ mbedtls_codepath_check == MBEDTLS_MPI_IS_TEST); \
+ } else { \
+ TEST_EQUAL(mbedtls_codepath_check, (path)); \
+ } \
+ } while (0)
+#endif /* MBEDTLS_TEST_HOOKS && !MBEDTLS_THREADING_C */
+
+#endif /* BIGNUM_CODEPATH_CHECK_H */
diff --git a/framework/tests/include/test/bignum_helpers.h b/framework/tests/include/test/bignum_helpers.h
new file mode 100644
index 0000000..a5e49cb
--- /dev/null
+++ b/framework/tests/include/test/bignum_helpers.h
@@ -0,0 +1,98 @@
+/**
+ * \file bignum_helpers.h
+ *
+ * \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
+ */
+
+#ifndef TEST_BIGNUM_HELPERS_H
+#define TEST_BIGNUM_HELPERS_H
+
+#include <mbedtls/build_info.h>
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+#include <mbedtls/bignum.h>
+#include <bignum_mod.h>
+
+/** Allocate and populate a core MPI from a test case argument.
+ *
+ * This function allocates exactly as many limbs as necessary to fit
+ * the length of the input. In other words, it preserves leading zeros.
+ *
+ * The limb array is allocated with mbedtls_calloc() and must later be
+ * freed with mbedtls_free().
+ *
+ * \param[in,out] pX The address where a pointer to the allocated limb
+ * array will be stored.
+ * \c *pX must be null on entry.
+ * On exit, \c *pX is null on error or if the number
+ * of limbs is 0.
+ * \param[out] plimbs The address where the number of limbs will be stored.
+ * \param[in] input The test argument to read.
+ * It is interpreted as a hexadecimal representation
+ * of a non-negative integer.
+ *
+ * \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise.
+ */
+int mbedtls_test_read_mpi_core(mbedtls_mpi_uint **pX, size_t *plimbs,
+ const char *input);
+
+/** Read a modulus from a hexadecimal string.
+ *
+ * This function allocates exactly as many limbs as necessary to fit
+ * the length of the input. In other words, it preserves leading zeros.
+ *
+ * The limb array is allocated with mbedtls_calloc() and must later be
+ * freed with mbedtls_free(). You can do that by calling
+ * mbedtls_test_mpi_mod_modulus_free_with_limbs().
+ *
+ * \param[in,out] N A modulus structure. It must be initialized, but
+ * not set up.
+ * \param[in] s The null-terminated hexadecimal string to read from.
+ * \param int_rep The desired representation of residues.
+ *
+ * \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise.
+ */
+int mbedtls_test_read_mpi_modulus(mbedtls_mpi_mod_modulus *N,
+ const char *s,
+ mbedtls_mpi_mod_rep_selector int_rep);
+
+/** Free a modulus and its limbs.
+ *
+ * \param[in] N A modulus structure such that there is no other
+ * reference to `N->p`.
+ */
+void mbedtls_test_mpi_mod_modulus_free_with_limbs(mbedtls_mpi_mod_modulus *N);
+
+/** Read an MPI from a hexadecimal string.
+ *
+ * Like mbedtls_mpi_read_string(), but with tighter guarantees around
+ * edge cases.
+ *
+ * - This function guarantees that if \p s begins with '-' then the sign
+ * bit of the result will be negative, even if the value is 0.
+ * When this function encounters such a "negative 0", it calls
+ * mbedtls_test_increment_case_uses_negative_0().
+ * - The size of the result is exactly the minimum number of limbs needed to fit
+ * the digits in the input. In particular, this function constructs a bignum
+ * with 0 limbs for an empty string, and a bignum with leading 0 limbs if the
+ * string has sufficiently many leading 0 digits. This is important so that
+ * the "0 (null)" and "0 (1 limb)" and "leading zeros" test cases do what they
+ * claim.
+ *
+ * \param[out] X The MPI object to populate. It must be initialized.
+ * \param[in] s The null-terminated hexadecimal string to read from.
+ *
+ * \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise.
+ */
+int mbedtls_test_read_mpi(mbedtls_mpi *X, const char *s);
+
+#endif /* MBEDTLS_BIGNUM_C */
+
+#endif /* TEST_BIGNUM_HELPERS_H */
diff --git a/framework/tests/include/test/constant_flow.h b/framework/tests/include/test/constant_flow.h
new file mode 100644
index 0000000..c5658eb
--- /dev/null
+++ b/framework/tests/include/test/constant_flow.h
@@ -0,0 +1,71 @@
+/**
+ * \file constant_flow.h
+ *
+ * \brief This file contains tools to ensure tested code has constant flow.
+ */
+
+/*
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef TEST_CONSTANT_FLOW_H
+#define TEST_CONSTANT_FLOW_H
+
+#include "mbedtls/build_info.h"
+
+/*
+ * This file defines the two macros
+ *
+ * #define TEST_CF_SECRET(ptr, size)
+ * #define TEST_CF_PUBLIC(ptr, size)
+ *
+ * that can be used in tests to mark a memory area as secret (no branch or
+ * memory access should depend on it) or public (default, only needs to be
+ * marked explicitly when it was derived from secret data).
+ *
+ * Arguments:
+ * - ptr: a pointer to the memory area to be marked
+ * - size: the size in bytes of the memory area
+ *
+ * Implementation:
+ * The basic idea is that of ctgrind <https://github.com/agl/ctgrind>: we can
+ * re-use tools that were designed for checking use of uninitialized memory.
+ * This file contains two implementations: one based on MemorySanitizer, the
+ * other on valgrind's memcheck. If none of them is enabled, dummy macros that
+ * do nothing are defined for convenience.
+ *
+ * \note #TEST_CF_SECRET must be called directly from within a .function file,
+ * not indirectly via a macro defined under tests/include or a function
+ * under tests/src. This is because we only run Valgrind for constant
+ * flow on test suites that have greppable annotations inside them (see
+ * `skip_suites_without_constant_flow` in `tests/scripts/all.sh`).
+ */
+
+#if defined(MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN)
+#include <sanitizer/msan_interface.h>
+
+/* Use macros to avoid messing up with origin tracking */
+#define TEST_CF_SECRET __msan_allocated_memory
+// void __msan_allocated_memory(const volatile void* data, size_t size);
+#define TEST_CF_PUBLIC __msan_unpoison
+// void __msan_unpoison(const volatile void *a, size_t size);
+
+#elif defined(MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND)
+#include <valgrind/memcheck.h>
+
+#define TEST_CF_SECRET VALGRIND_MAKE_MEM_UNDEFINED
+// VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr, _qzz_len)
+#define TEST_CF_PUBLIC VALGRIND_MAKE_MEM_DEFINED
+// VALGRIND_MAKE_MEM_DEFINED(_qzz_addr, _qzz_len)
+
+#else /* MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN ||
+ MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND */
+
+#define TEST_CF_SECRET(ptr, size)
+#define TEST_CF_PUBLIC(ptr, size)
+
+#endif /* MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN ||
+ MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND */
+
+#endif /* TEST_CONSTANT_FLOW_H */
diff --git a/framework/tests/include/test/drivers/aead.h b/framework/tests/include/test/drivers/aead.h
new file mode 100644
index 0000000..a033e39
--- /dev/null
+++ b/framework/tests/include/test/drivers/aead.h
@@ -0,0 +1,121 @@
+/*
+ * Test driver for AEAD driver entry points.
+ */
+/* Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef PSA_CRYPTO_TEST_DRIVERS_AEAD_H
+#define PSA_CRYPTO_TEST_DRIVERS_AEAD_H
+
+#include "mbedtls/build_info.h"
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include <psa/crypto_driver_common.h>
+
+typedef struct {
+ /* If not PSA_SUCCESS, return this error code instead of processing the
+ * function call. */
+ psa_status_t forced_status;
+ /* Count the amount of times AEAD driver functions are called. */
+ unsigned long hits_encrypt;
+ unsigned long hits_decrypt;
+ unsigned long hits_encrypt_setup;
+ unsigned long hits_decrypt_setup;
+ unsigned long hits_set_nonce;
+ unsigned long hits_set_lengths;
+ unsigned long hits_update_ad;
+ unsigned long hits_update;
+ unsigned long hits_finish;
+ unsigned long hits_verify;
+ unsigned long hits_abort;
+
+ /* Status returned by the last AEAD driver function call. */
+ psa_status_t driver_status;
+} mbedtls_test_driver_aead_hooks_t;
+
+#define MBEDTLS_TEST_DRIVER_AEAD_INIT { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+static inline mbedtls_test_driver_aead_hooks_t
+mbedtls_test_driver_aead_hooks_init(void)
+{
+ const mbedtls_test_driver_aead_hooks_t v = MBEDTLS_TEST_DRIVER_AEAD_INIT;
+ return v;
+}
+
+extern mbedtls_test_driver_aead_hooks_t mbedtls_test_driver_aead_hooks;
+
+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);
+
+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);
+
+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);
+
+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);
+
+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);
+
+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);
+
+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);
+
+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);
+
+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);
+
+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);
+
+psa_status_t mbedtls_test_transparent_aead_abort(
+ mbedtls_transparent_test_driver_aead_operation_t *operation);
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_TEST_DRIVERS_AEAD_H */
diff --git a/framework/tests/include/test/drivers/asymmetric_encryption.h b/framework/tests/include/test/drivers/asymmetric_encryption.h
new file mode 100644
index 0000000..0ac7708
--- /dev/null
+++ b/framework/tests/include/test/drivers/asymmetric_encryption.h
@@ -0,0 +1,67 @@
+/*
+ * Test driver for asymmetric encryption.
+ */
+/* Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef PSA_CRYPTO_TEST_DRIVERS_ASYMMETRIC_ENCRYPTION_H
+#define PSA_CRYPTO_TEST_DRIVERS_ASYMMETRIC_ENCRYPTION_H
+
+#include "mbedtls/build_info.h"
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include <psa/crypto_driver_common.h>
+#include <psa/crypto.h>
+
+typedef struct {
+ /* If non-null, on success, copy this to the output. */
+ void *forced_output;
+ size_t forced_output_length;
+ /* If not PSA_SUCCESS, return this error code instead of processing the
+ * function call. */
+ psa_status_t forced_status;
+ /* Count the amount of times one of the asymmetric_encryption driver
+ functions is called. */
+ unsigned long hits;
+} mbedtls_test_driver_asymmetric_encryption_hooks_t;
+
+#define MBEDTLS_TEST_DRIVER_ASYMMETRIC_ENCRYPTION_INIT { NULL, 0, PSA_SUCCESS, 0 }
+
+static inline mbedtls_test_driver_asymmetric_encryption_hooks_t
+mbedtls_test_driver_asymmetric_encryption_hooks_init(void)
+{
+ const mbedtls_test_driver_asymmetric_encryption_hooks_t v =
+ MBEDTLS_TEST_DRIVER_ASYMMETRIC_ENCRYPTION_INIT;
+ return v;
+}
+
+extern mbedtls_test_driver_asymmetric_encryption_hooks_t
+ mbedtls_test_driver_asymmetric_encryption_hooks;
+
+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);
+
+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);
+
+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);
+
+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);
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_TEST_DRIVERS_ASYMMETRIC_ENCRYPTION_H */
diff --git a/framework/tests/include/test/drivers/cipher.h b/framework/tests/include/test/drivers/cipher.h
new file mode 100644
index 0000000..2fe47e4
--- /dev/null
+++ b/framework/tests/include/test/drivers/cipher.h
@@ -0,0 +1,136 @@
+/*
+ * Test driver for cipher functions
+ */
+/* Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef PSA_CRYPTO_TEST_DRIVERS_CIPHER_H
+#define PSA_CRYPTO_TEST_DRIVERS_CIPHER_H
+
+#include "mbedtls/build_info.h"
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include <psa/crypto_driver_common.h>
+#include <psa/crypto.h>
+
+#include "mbedtls/cipher.h"
+
+typedef struct {
+ /* If non-null, on success, copy this to the output. */
+ void *forced_output;
+ size_t forced_output_length;
+ /* If not PSA_SUCCESS, return this error code instead of processing the
+ * function call. */
+ psa_status_t forced_status;
+ psa_status_t forced_status_encrypt;
+ psa_status_t forced_status_set_iv;
+ /* Count the amount of times one of the cipher driver functions is called. */
+ unsigned long hits;
+ unsigned long hits_encrypt;
+ unsigned long hits_set_iv;
+} mbedtls_test_driver_cipher_hooks_t;
+
+#define MBEDTLS_TEST_DRIVER_CIPHER_INIT { NULL, 0, \
+ PSA_SUCCESS, PSA_SUCCESS, PSA_SUCCESS, \
+ 0, 0, 0 }
+static inline mbedtls_test_driver_cipher_hooks_t
+mbedtls_test_driver_cipher_hooks_init(void)
+{
+ const mbedtls_test_driver_cipher_hooks_t v = MBEDTLS_TEST_DRIVER_CIPHER_INIT;
+ return v;
+}
+
+extern mbedtls_test_driver_cipher_hooks_t mbedtls_test_driver_cipher_hooks;
+
+psa_status_t mbedtls_test_transparent_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);
+
+psa_status_t mbedtls_test_transparent_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);
+
+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);
+
+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);
+
+psa_status_t mbedtls_test_transparent_cipher_abort(
+ mbedtls_transparent_test_driver_cipher_operation_t *operation);
+
+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);
+
+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);
+
+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);
+
+/*
+ * opaque versions
+ */
+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);
+
+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);
+
+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);
+
+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);
+
+psa_status_t mbedtls_test_opaque_cipher_abort(
+ mbedtls_opaque_test_driver_cipher_operation_t *operation);
+
+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);
+
+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);
+
+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);
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_TEST_DRIVERS_CIPHER_H */
diff --git a/framework/tests/include/test/drivers/hash.h b/framework/tests/include/test/drivers/hash.h
new file mode 100644
index 0000000..ad48c45
--- /dev/null
+++ b/framework/tests/include/test/drivers/hash.h
@@ -0,0 +1,64 @@
+/*
+ * Test driver for hash driver entry points.
+ */
+/* Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef PSA_CRYPTO_TEST_DRIVERS_HASH_H
+#define PSA_CRYPTO_TEST_DRIVERS_HASH_H
+
+#include "mbedtls/build_info.h"
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include <psa/crypto_driver_common.h>
+
+typedef struct {
+ /* If not PSA_SUCCESS, return this error code instead of processing the
+ * function call. */
+ psa_status_t forced_status;
+ /* Count the amount of times hash driver entry points are called. */
+ unsigned long hits;
+ /* Status returned by the last hash driver entry point call. */
+ psa_status_t driver_status;
+} mbedtls_test_driver_hash_hooks_t;
+
+#define MBEDTLS_TEST_DRIVER_HASH_INIT { 0, 0, 0 }
+static inline mbedtls_test_driver_hash_hooks_t
+mbedtls_test_driver_hash_hooks_init(void)
+{
+ const mbedtls_test_driver_hash_hooks_t v = MBEDTLS_TEST_DRIVER_HASH_INIT;
+ return v;
+}
+
+extern mbedtls_test_driver_hash_hooks_t mbedtls_test_driver_hash_hooks;
+
+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);
+
+psa_status_t mbedtls_test_transparent_hash_setup(
+ mbedtls_transparent_test_driver_hash_operation_t *operation,
+ psa_algorithm_t alg);
+
+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);
+
+psa_status_t mbedtls_test_transparent_hash_update(
+ mbedtls_transparent_test_driver_hash_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length);
+
+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);
+
+psa_status_t mbedtls_test_transparent_hash_abort(
+ mbedtls_transparent_test_driver_hash_operation_t *operation);
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_TEST_DRIVERS_HASH_H */
diff --git a/framework/tests/include/test/drivers/key_agreement.h b/framework/tests/include/test/drivers/key_agreement.h
new file mode 100644
index 0000000..ca82b3a
--- /dev/null
+++ b/framework/tests/include/test/drivers/key_agreement.h
@@ -0,0 +1,62 @@
+/*
+ * Test driver for key agreement functions.
+ */
+/* Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef PSA_CRYPTO_TEST_DRIVERS_KEY_AGREEMENT_H
+#define PSA_CRYPTO_TEST_DRIVERS_KEY_AGREEMENT_H
+
+#include "mbedtls/build_info.h"
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include <psa/crypto_driver_common.h>
+
+typedef struct {
+ /* If non-null, on success, copy this to the output. */
+ void *forced_output;
+ size_t forced_output_length;
+ /* If not PSA_SUCCESS, return this error code instead of processing the
+ * function call. */
+ psa_status_t forced_status;
+ /* Count the amount of times one of the signature driver functions is called. */
+ unsigned long hits;
+} mbedtls_test_driver_key_agreement_hooks_t;
+
+#define MBEDTLS_TEST_DRIVER_KEY_AGREEMENT_INIT { NULL, 0, PSA_SUCCESS, 0 }
+static inline mbedtls_test_driver_key_agreement_hooks_t
+mbedtls_test_driver_key_agreement_hooks_init(void)
+{
+ const mbedtls_test_driver_key_agreement_hooks_t
+ v = MBEDTLS_TEST_DRIVER_KEY_AGREEMENT_INIT;
+ return v;
+}
+
+extern mbedtls_test_driver_key_agreement_hooks_t
+ mbedtls_test_driver_key_agreement_hooks;
+
+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);
+
+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);
+
+#endif /*PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_TEST_DRIVERS_KEY_AGREEMENT_H */
diff --git a/framework/tests/include/test/drivers/key_management.h b/framework/tests/include/test/drivers/key_management.h
new file mode 100644
index 0000000..1d9bc43
--- /dev/null
+++ b/framework/tests/include/test/drivers/key_management.h
@@ -0,0 +1,131 @@
+/*
+ * Test driver for generating and verifying keys.
+ */
+/* Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef PSA_CRYPTO_TEST_DRIVERS_KEY_MANAGEMENT_H
+#define PSA_CRYPTO_TEST_DRIVERS_KEY_MANAGEMENT_H
+
+#include "mbedtls/build_info.h"
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include <psa/crypto_driver_common.h>
+
+#define PSA_CRYPTO_TEST_DRIVER_BUILTIN_AES_KEY_SLOT 0
+#define PSA_CRYPTO_TEST_DRIVER_BUILTIN_ECDSA_KEY_SLOT 1
+
+typedef struct {
+ /* If non-null, on success, copy this to the output. */
+ void *forced_output;
+ size_t forced_output_length;
+ /* If not PSA_SUCCESS, return this error code instead of processing the
+ * function call. */
+ psa_status_t forced_status;
+ /* Count the amount of times one of the key management driver functions
+ * is called. */
+ unsigned long hits;
+ /* Subset of hits which only counts public key export operations */
+ unsigned long hits_export_public_key;
+ /* Subset of hits which only counts key generation operations */
+ unsigned long hits_generate_key;
+ /* Location of the last key management driver called to import a key. */
+ psa_key_location_t location;
+} mbedtls_test_driver_key_management_hooks_t;
+
+/* The location is initialized to the invalid value 0x800000. Invalid in the
+ * sense that no PSA specification will assign a meaning to this location
+ * (stated first in version 1.0.1 of the specification) and that it is not
+ * used as a location of an opaque test drivers. */
+#define MBEDTLS_TEST_DRIVER_KEY_MANAGEMENT_INIT { NULL, 0, PSA_SUCCESS, 0, 0, 0, 0x800000 }
+static inline mbedtls_test_driver_key_management_hooks_t
+mbedtls_test_driver_key_management_hooks_init(void)
+{
+ const mbedtls_test_driver_key_management_hooks_t
+ v = MBEDTLS_TEST_DRIVER_KEY_MANAGEMENT_INIT;
+ return v;
+}
+
+/*
+ * In order to convert the plain text keys to Opaque, the size of the key is
+ * padded up by PSA_CRYPTO_TEST_DRIVER_OPAQUE_PAD_PREFIX_SIZE in addition to
+ * xor mangling the key. The pad prefix needs to be accounted for while
+ * sizing for the key.
+ */
+#define PSA_CRYPTO_TEST_DRIVER_OPAQUE_PAD_PREFIX 0xBEEFED00U
+#define PSA_CRYPTO_TEST_DRIVER_OPAQUE_PAD_PREFIX_SIZE sizeof( \
+ PSA_CRYPTO_TEST_DRIVER_OPAQUE_PAD_PREFIX)
+
+size_t mbedtls_test_opaque_size_function(
+ const psa_key_type_t key_type,
+ const size_t key_bits);
+
+extern mbedtls_test_driver_key_management_hooks_t
+ mbedtls_test_driver_key_management_hooks;
+
+psa_status_t mbedtls_test_transparent_init(void);
+void mbedtls_test_transparent_free(void);
+psa_status_t mbedtls_test_opaque_init(void);
+void mbedtls_test_opaque_free(void);
+
+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);
+
+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);
+
+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);
+
+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);
+
+psa_status_t mbedtls_test_transparent_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);
+
+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);
+
+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_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 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);
+
+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 *target_key_buffer,
+ size_t target_key_buffer_size,
+ size_t *target_key_buffer_length);
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_TEST_DRIVERS_KEY_MANAGEMENT_H */
diff --git a/framework/tests/include/test/drivers/mac.h b/framework/tests/include/test/drivers/mac.h
new file mode 100644
index 0000000..d92eff9
--- /dev/null
+++ b/framework/tests/include/test/drivers/mac.h
@@ -0,0 +1,125 @@
+/*
+ * Test driver for MAC driver entry points.
+ */
+/* Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef PSA_CRYPTO_TEST_DRIVERS_MAC_H
+#define PSA_CRYPTO_TEST_DRIVERS_MAC_H
+
+#include "mbedtls/build_info.h"
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include <psa/crypto_driver_common.h>
+
+typedef struct {
+ /* If not PSA_SUCCESS, return this error code instead of processing the
+ * function call. */
+ psa_status_t forced_status;
+ /* Count the amount of times MAC driver functions are called. */
+ unsigned long hits;
+ /* Status returned by the last MAC driver function call. */
+ psa_status_t driver_status;
+} mbedtls_test_driver_mac_hooks_t;
+
+#define MBEDTLS_TEST_DRIVER_MAC_INIT { 0, 0, 0 }
+static inline mbedtls_test_driver_mac_hooks_t
+mbedtls_test_driver_mac_hooks_init(void)
+{
+ const mbedtls_test_driver_mac_hooks_t v = MBEDTLS_TEST_DRIVER_MAC_INIT;
+ return v;
+}
+
+extern mbedtls_test_driver_mac_hooks_t mbedtls_test_driver_mac_hooks;
+
+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);
+
+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);
+
+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);
+
+psa_status_t mbedtls_test_transparent_mac_update(
+ mbedtls_transparent_test_driver_mac_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length);
+
+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);
+
+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);
+
+psa_status_t mbedtls_test_transparent_mac_abort(
+ mbedtls_transparent_test_driver_mac_operation_t *operation);
+
+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);
+
+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);
+
+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);
+
+psa_status_t mbedtls_test_opaque_mac_update(
+ mbedtls_opaque_test_driver_mac_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length);
+
+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);
+
+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);
+
+psa_status_t mbedtls_test_opaque_mac_abort(
+ mbedtls_opaque_test_driver_mac_operation_t *operation);
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_TEST_DRIVERS_MAC_H */
diff --git a/framework/tests/include/test/drivers/pake.h b/framework/tests/include/test/drivers/pake.h
new file mode 100644
index 0000000..d292ca0
--- /dev/null
+++ b/framework/tests/include/test/drivers/pake.h
@@ -0,0 +1,75 @@
+/*
+ * Test driver for PAKE driver entry points.
+ */
+/* Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef PSA_CRYPTO_TEST_DRIVERS_PAKE_H
+#define PSA_CRYPTO_TEST_DRIVERS_PAKE_H
+
+#include "mbedtls/build_info.h"
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include <psa/crypto_driver_common.h>
+
+typedef struct {
+ /* If not PSA_SUCCESS, return this error code instead of processing the
+ * function call. */
+ psa_status_t forced_status;
+ /* PAKE driver setup is executed on the first call to
+ pake_output/pake_input (added to distinguish forced statuses). */
+ psa_status_t forced_setup_status;
+ /* Count the amount of times PAKE driver functions are called. */
+ struct {
+ unsigned long total;
+ unsigned long setup;
+ unsigned long input;
+ unsigned long output;
+ unsigned long implicit_key;
+ unsigned long abort;
+ } hits;
+ /* Status returned by the last PAKE driver function call. */
+ psa_status_t driver_status;
+ /* Output returned by pake_output */
+ void *forced_output;
+ size_t forced_output_length;
+} mbedtls_test_driver_pake_hooks_t;
+
+#define MBEDTLS_TEST_DRIVER_PAKE_INIT { PSA_SUCCESS, PSA_SUCCESS, { 0, 0, 0, 0, 0, 0 }, PSA_SUCCESS, \
+ NULL, 0 }
+static inline mbedtls_test_driver_pake_hooks_t
+mbedtls_test_driver_pake_hooks_init(void)
+{
+ const mbedtls_test_driver_pake_hooks_t v = MBEDTLS_TEST_DRIVER_PAKE_INIT;
+ return v;
+}
+
+extern mbedtls_test_driver_pake_hooks_t mbedtls_test_driver_pake_hooks;
+
+psa_status_t mbedtls_test_transparent_pake_setup(
+ mbedtls_transparent_test_driver_pake_operation_t *operation,
+ const psa_crypto_driver_pake_inputs_t *inputs);
+
+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);
+
+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);
+
+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);
+
+psa_status_t mbedtls_test_transparent_pake_abort(
+ mbedtls_transparent_test_driver_pake_operation_t *operation);
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_TEST_DRIVERS_PAKE_H */
diff --git a/framework/tests/include/test/drivers/signature.h b/framework/tests/include/test/drivers/signature.h
new file mode 100644
index 0000000..8c5703e
--- /dev/null
+++ b/framework/tests/include/test/drivers/signature.h
@@ -0,0 +1,112 @@
+/*
+ * Test driver for signature functions.
+ */
+/* Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef PSA_CRYPTO_TEST_DRIVERS_SIGNATURE_H
+#define PSA_CRYPTO_TEST_DRIVERS_SIGNATURE_H
+
+#include "mbedtls/build_info.h"
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include <psa/crypto_driver_common.h>
+
+typedef struct {
+ /* If non-null, on success, copy this to the output. */
+ void *forced_output;
+ size_t forced_output_length;
+ /* If not PSA_SUCCESS, return this error code instead of processing the
+ * function call. */
+ psa_status_t forced_status;
+ /* Count the amount of times one of the signature driver functions is called. */
+ unsigned long hits;
+} mbedtls_test_driver_signature_hooks_t;
+
+#define MBEDTLS_TEST_DRIVER_SIGNATURE_INIT { NULL, 0, PSA_SUCCESS, 0 }
+static inline mbedtls_test_driver_signature_hooks_t
+mbedtls_test_driver_signature_hooks_init(void)
+{
+ const mbedtls_test_driver_signature_hooks_t
+ v = MBEDTLS_TEST_DRIVER_SIGNATURE_INIT;
+ return v;
+}
+
+extern mbedtls_test_driver_signature_hooks_t
+ mbedtls_test_driver_signature_sign_hooks;
+extern mbedtls_test_driver_signature_hooks_t
+ mbedtls_test_driver_signature_verify_hooks;
+
+psa_status_t mbedtls_test_transparent_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);
+
+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);
+
+psa_status_t mbedtls_test_transparent_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);
+
+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);
+
+psa_status_t mbedtls_test_transparent_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);
+
+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);
+
+psa_status_t mbedtls_test_transparent_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);
+
+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);
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_TEST_DRIVERS_SIGNATURE_H */
diff --git a/framework/tests/include/test/drivers/test_driver.h b/framework/tests/include/test/drivers/test_driver.h
new file mode 100644
index 0000000..74605d6
--- /dev/null
+++ b/framework/tests/include/test/drivers/test_driver.h
@@ -0,0 +1,32 @@
+/*
+ * Umbrella include for all of the test driver functionality
+ */
+/* Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef PSA_CRYPTO_TEST_DRIVER_H
+#define PSA_CRYPTO_TEST_DRIVER_H
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#ifndef PSA_CRYPTO_DRIVER_PRESENT
+#define PSA_CRYPTO_DRIVER_PRESENT
+#endif
+#ifndef PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT
+#define PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT
+#endif
+
+#define PSA_CRYPTO_TEST_DRIVER_LOCATION 0x7fffff
+
+#include "test/drivers/aead.h"
+#include "test/drivers/cipher.h"
+#include "test/drivers/hash.h"
+#include "test/drivers/mac.h"
+#include "test/drivers/key_management.h"
+#include "test/drivers/signature.h"
+#include "test/drivers/asymmetric_encryption.h"
+#include "test/drivers/key_agreement.h"
+#include "test/drivers/pake.h"
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_TEST_DRIVER_H */
diff --git a/framework/tests/include/test/fake_external_rng_for_test.h b/framework/tests/include/test/fake_external_rng_for_test.h
new file mode 100644
index 0000000..e3e331d
--- /dev/null
+++ b/framework/tests/include/test/fake_external_rng_for_test.h
@@ -0,0 +1,40 @@
+/*
+ * Insecure but standalone implementation of mbedtls_psa_external_get_random().
+ * Only for use in tests!
+ */
+/*
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef FAKE_EXTERNAL_RNG_FOR_TEST_H
+#define FAKE_EXTERNAL_RNG_FOR_TEST_H
+
+#include "mbedtls/build_info.h"
+
+#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+/** Enable the insecure implementation of mbedtls_psa_external_get_random().
+ *
+ * The insecure implementation of mbedtls_psa_external_get_random() is
+ * disabled by default.
+ *
+ * When MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG is enabled and the test
+ * helpers are linked into a program, you must enable this before running any
+ * code that uses the PSA subsystem to generate random data (including internal
+ * random generation for purposes such as blinding when the random generation
+ * is routed through PSA).
+ *
+ * You can enable and disable it at any time, regardless of the state
+ * of the PSA subsystem. You may disable it temporarily to simulate a
+ * depleted entropy source.
+ */
+void mbedtls_test_enable_insecure_external_rng(void);
+
+/** Disable the insecure implementation of mbedtls_psa_external_get_random().
+ *
+ * See mbedtls_test_enable_insecure_external_rng().
+ */
+void mbedtls_test_disable_insecure_external_rng(void);
+#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+
+#endif /* FAKE_EXTERNAL_RNG_FOR_TEST_H */
diff --git a/framework/tests/include/test/helpers.h b/framework/tests/include/test/helpers.h
new file mode 100644
index 0000000..d08100f
--- /dev/null
+++ b/framework/tests/include/test/helpers.h
@@ -0,0 +1,404 @@
+/**
+ * \file helpers.h
+ *
+ * \brief This file contains the prototypes of helper functions for the
+ * purpose of testing.
+ */
+
+/*
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef TEST_HELPERS_H
+#define TEST_HELPERS_H
+
+/* Most fields of publicly available structs are private and are wrapped with
+ * MBEDTLS_PRIVATE macro. This define allows tests to access the private fields
+ * directly (without using the MBEDTLS_PRIVATE wrapper). */
+#define MBEDTLS_ALLOW_PRIVATE_ACCESS
+
+#include "mbedtls/build_info.h"
+
+#if defined(__SANITIZE_ADDRESS__) /* gcc -fsanitize=address */
+# define MBEDTLS_TEST_HAVE_ASAN
+#endif
+#if defined(__SANITIZE_THREAD__) /* gcc -fsanitize-thread */
+# define MBEDTLS_TEST_HAVE_TSAN
+#endif
+
+#if defined(__has_feature)
+# if __has_feature(address_sanitizer) /* clang -fsanitize=address */
+# define MBEDTLS_TEST_HAVE_ASAN
+# endif
+# if __has_feature(memory_sanitizer) /* clang -fsanitize=memory */
+# define MBEDTLS_TEST_HAVE_MSAN
+# endif
+# if __has_feature(thread_sanitizer) /* clang -fsanitize=thread */
+# define MBEDTLS_TEST_HAVE_TSAN
+# endif
+#endif
+
+#include "test/threading_helpers.h"
+
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+#include "mbedtls/threading.h"
+#endif
+
+#include "mbedtls/platform.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#if defined(MBEDTLS_BIGNUM_C)
+#include "mbedtls/bignum.h"
+#endif
+
+/** The type of test case arguments that contain binary data. */
+typedef struct data_tag {
+ uint8_t *x;
+ uint32_t len;
+} data_t;
+
+typedef enum {
+ MBEDTLS_TEST_RESULT_SUCCESS = 0,
+ MBEDTLS_TEST_RESULT_FAILED,
+ MBEDTLS_TEST_RESULT_SKIPPED
+} mbedtls_test_result_t;
+
+#define MBEDTLS_TEST_LINE_LENGTH 76
+
+typedef struct {
+ mbedtls_test_result_t result;
+ const char *test;
+ const char *filename;
+ int line_no;
+ unsigned long step;
+ char line1[MBEDTLS_TEST_LINE_LENGTH];
+ char line2[MBEDTLS_TEST_LINE_LENGTH];
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+ const char *mutex_usage_error;
+#endif
+#if defined(MBEDTLS_BIGNUM_C)
+ unsigned case_uses_negative_0;
+#endif
+}
+mbedtls_test_info_t;
+
+/**
+ * \brief Get the current test result status
+ *
+ * \return The current test result status
+ */
+mbedtls_test_result_t mbedtls_test_get_result(void);
+
+/**
+ * \brief Get the current test name/description
+ *
+ * \return The current test name/description
+ */
+const char *mbedtls_test_get_test(void);
+
+/**
+ * \brief Get the current test filename
+ *
+ * \return The current test filename
+ */
+const char *mbedtls_get_test_filename(void);
+
+/**
+ * \brief Get the current test file line number (for failure / skip)
+ *
+ * \return The current test file line number (for failure / skip)
+ */
+int mbedtls_test_get_line_no(void);
+
+/**
+ * \brief Increment the current test step.
+ *
+ * \note It is not recommended for multiple threads to call this
+ * function concurrently - whilst it is entirely thread safe,
+ * the order of calls to this function can obviously not be
+ * ensured, so unexpected results may occur.
+ */
+void mbedtls_test_increment_step(void);
+
+/**
+ * \brief Get the current test step
+ *
+ * \return The current test step
+ */
+unsigned long mbedtls_test_get_step(void);
+
+/**
+ * \brief Get the current test line buffer 1
+ *
+ * \param line Buffer of minimum size \c MBEDTLS_TEST_LINE_LENGTH,
+ * which will have line buffer 1 copied to it.
+ */
+void mbedtls_test_get_line1(char *line);
+
+/**
+ * \brief Get the current test line buffer 2
+ *
+ * \param line Buffer of minimum size \c MBEDTLS_TEST_LINE_LENGTH,
+ * which will have line buffer 1 copied to it.
+ */
+void mbedtls_test_get_line2(char *line);
+
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+/**
+ * \brief Get the current mutex usage error message
+ *
+ * \return The current mutex error message (may be NULL if no error)
+ */
+const char *mbedtls_test_get_mutex_usage_error(void);
+
+/**
+ * \brief Set the current mutex usage error message
+ *
+ * \note This will only set the mutex error message if one has not
+ * already been set, or if we are clearing the message (msg is
+ * NULL)
+ *
+ * \param msg Error message to set (can be NULL to clear)
+ */
+void mbedtls_test_set_mutex_usage_error(const char *msg);
+#endif
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+/**
+ * \brief Get whether the current test is a bignum test that uses
+ * negative zero.
+ *
+ * \return non zero if the current test uses bignum negative zero.
+ */
+unsigned mbedtls_test_get_case_uses_negative_0(void);
+
+/**
+ * \brief Indicate that the current test uses bignum negative zero.
+ *
+ * \note This function is called if the current test case had an
+ * input parsed with mbedtls_test_read_mpi() that is a negative
+ * 0 (`"-"`, `"-0"`, `"-00"`, etc., constructing a result with
+ * the sign bit set to -1 and the value being all-limbs-0,
+ * which is not a valid representation in #mbedtls_mpi but is
+ * tested for robustness). *
+ */
+void mbedtls_test_increment_case_uses_negative_0(void);
+#endif
+
+int mbedtls_test_platform_setup(void);
+void mbedtls_test_platform_teardown(void);
+
+/**
+ * \brief Record the current test case as a failure.
+ *
+ * This function can be called directly however it is usually
+ * called via macros such as TEST_ASSERT, TEST_EQUAL,
+ * PSA_ASSERT, etc...
+ *
+ * \note If the test case was already marked as failed, calling
+ * `mbedtls_test_fail( )` again will not overwrite any
+ * previous information about the failure.
+ *
+ * \param test Description of the failure or assertion that failed. This
+ * MUST be a string literal.
+ * \param line_no Line number where the failure originated.
+ * \param filename Filename where the failure originated.
+ */
+void mbedtls_test_fail(const char *test, int line_no, const char *filename);
+
+/**
+ * \brief Record the current test case as skipped.
+ *
+ * This function can be called directly however it is usually
+ * called via the TEST_ASSUME macro.
+ *
+ * \param test Description of the assumption that caused the test case to
+ * be skipped. This MUST be a string literal.
+ * \param line_no Line number where the test case was skipped.
+ * \param filename Filename where the test case was skipped.
+ */
+void mbedtls_test_skip(const char *test, int line_no, const char *filename);
+
+/**
+ * \brief Set the test step number for failure reports.
+ *
+ * Call this function to display "step NNN" in addition to the
+ * line number and file name if a test fails. Typically the
+ * "step number" is the index of a for loop but it can be
+ * whatever you want.
+ *
+ * \note It is not recommended for multiple threads to call this
+ * function concurrently - whilst it is entirely thread safe,
+ * the order of calls to this function can obviously not be
+ * ensured, so unexpected results may occur.
+ *
+ * \param step The step number to report.
+ */
+void mbedtls_test_set_step(unsigned long step);
+
+/**
+ * \brief Reset mbedtls_test_info to a ready/starting state.
+ */
+void mbedtls_test_info_reset(void);
+
+#ifdef MBEDTLS_TEST_MUTEX_USAGE
+/**
+ * \brief Get the test info data mutex.
+ *
+ * \note This is designed only to be used by threading_helpers to
+ * avoid a deadlock, not for general access to this mutex.
+ *
+ * \return The test info data mutex.
+ */
+mbedtls_threading_mutex_t *mbedtls_test_get_info_mutex(void);
+
+#endif /* MBEDTLS_TEST_MUTEX_USAGE */
+
+/**
+ * \brief Record the current test case as a failure if two integers
+ * have a different value.
+ *
+ * This function is usually called via the macro
+ * #TEST_EQUAL.
+ *
+ * \param test Description of the failure or assertion that failed. This
+ * MUST be a string literal. This normally has the form
+ * "EXPR1 == EXPR2" where EXPR1 has the value \p value1
+ * and EXPR2 has the value \p value2.
+ * \param line_no Line number where the failure originated.
+ * \param filename Filename where the failure originated.
+ * \param value1 The first value to compare.
+ * \param value2 The second value to compare.
+ *
+ * \return \c 1 if the values are equal, otherwise \c 0.
+ */
+int mbedtls_test_equal(const char *test, int line_no, const char *filename,
+ unsigned long long value1, unsigned long long value2);
+
+/**
+ * \brief Record the current test case as a failure based
+ * on comparing two unsigned integers.
+ *
+ * This function is usually called via the macro
+ * #TEST_LE_U.
+ *
+ * \param test Description of the failure or assertion that failed. This
+ * MUST be a string literal. This normally has the form
+ * "EXPR1 <= EXPR2" where EXPR1 has the value \p value1
+ * and EXPR2 has the value \p value2.
+ * \param line_no Line number where the failure originated.
+ * \param filename Filename where the failure originated.
+ * \param value1 The first value to compare.
+ * \param value2 The second value to compare.
+ *
+ * \return \c 1 if \p value1 <= \p value2, otherwise \c 0.
+ */
+int mbedtls_test_le_u(const char *test, int line_no, const char *filename,
+ unsigned long long value1, unsigned long long value2);
+
+/**
+ * \brief Record the current test case as a failure based
+ * on comparing two signed integers.
+ *
+ * This function is usually called via the macro
+ * #TEST_LE_S.
+ *
+ * \param test Description of the failure or assertion that failed. This
+ * MUST be a string literal. This normally has the form
+ * "EXPR1 <= EXPR2" where EXPR1 has the value \p value1
+ * and EXPR2 has the value \p value2.
+ * \param line_no Line number where the failure originated.
+ * \param filename Filename where the failure originated.
+ * \param value1 The first value to compare.
+ * \param value2 The second value to compare.
+ *
+ * \return \c 1 if \p value1 <= \p value2, otherwise \c 0.
+ */
+int mbedtls_test_le_s(const char *test, int line_no, const char *filename,
+ long long value1, long long value2);
+
+/**
+ * \brief This function decodes the hexadecimal representation of
+ * data.
+ *
+ * \note The output buffer can be the same as the input buffer. For
+ * any other overlapping of the input and output buffers, the
+ * behavior is undefined.
+ *
+ * \param obuf Output buffer.
+ * \param obufmax Size in number of bytes of \p obuf.
+ * \param ibuf Input buffer.
+ * \param len The number of unsigned char written in \p obuf. This must
+ * not be \c NULL.
+ *
+ * \return \c 0 on success.
+ * \return \c -1 if the output buffer is too small or the input string
+ * is not a valid hexadecimal representation.
+ */
+int mbedtls_test_unhexify(unsigned char *obuf, size_t obufmax,
+ const char *ibuf, size_t *len);
+
+void mbedtls_test_hexify(unsigned char *obuf,
+ const unsigned char *ibuf,
+ int len);
+
+/**
+ * \brief Convert hexadecimal digit to an integer.
+ *
+ * \param c The digit to convert (`'0'` to `'9'`, `'A'` to `'F'` or
+ * `'a'` to `'f'`).
+ * \param[out] uc On success, the value of the digit (0 to 15).
+ *
+ * \return 0 on success, -1 if \p c is not a hexadecimal digit.
+ */
+int mbedtls_test_ascii2uc(const char c, unsigned char *uc);
+
+/**
+ * Allocate and zeroize a buffer.
+ *
+ * If the size if zero, a pointer to a zeroized 1-byte buffer is returned.
+ *
+ * For convenience, dies if allocation fails.
+ */
+unsigned char *mbedtls_test_zero_alloc(size_t len);
+
+/**
+ * Allocate and fill a buffer from hex data.
+ *
+ * The buffer is sized exactly as needed. This allows to detect buffer
+ * overruns (including overreads) when running the test suite under valgrind.
+ *
+ * If the size if zero, a pointer to a zeroized 1-byte buffer is returned.
+ *
+ * For convenience, dies if allocation fails.
+ */
+unsigned char *mbedtls_test_unhexify_alloc(const char *ibuf, size_t *olen);
+
+int mbedtls_test_hexcmp(uint8_t *a, uint8_t *b,
+ uint32_t a_len, uint32_t b_len);
+
+#if defined(MBEDTLS_PSA_CRYPTO_C) && defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+#include "test/fake_external_rng_for_test.h"
+#endif
+
+#if defined(MBEDTLS_TEST_HOOKS)
+/**
+ * \brief Check that only a pure high-level error code is being combined with
+ * a pure low-level error code as otherwise the resultant error code
+ * would be corrupted.
+ *
+ * \note Both high-level and low-level error codes cannot be greater than
+ * zero however can be zero. If one error code is zero then the
+ * other error code is returned even if both codes are zero.
+ *
+ * \note If the check fails, fail the test currently being run.
+ */
+void mbedtls_test_err_add_check(int high, int low,
+ const char *file, int line);
+#endif
+
+#endif /* TEST_HELPERS_H */
diff --git a/framework/tests/include/test/macros.h b/framework/tests/include/test/macros.h
new file mode 100644
index 0000000..a73e06f
--- /dev/null
+++ b/framework/tests/include/test/macros.h
@@ -0,0 +1,250 @@
+/**
+ * \file macros.h
+ *
+ * \brief This file contains generic macros for the purpose of testing.
+ */
+
+/*
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef TEST_MACROS_H
+#define TEST_MACROS_H
+
+#include "mbedtls/build_info.h"
+
+#include <stdlib.h>
+
+#include "mbedtls/platform.h"
+
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+#include "mbedtls/memory_buffer_alloc.h"
+#endif
+#include "common.h"
+
+/**
+ * \brief This macro tests the expression passed to it as a test step or
+ * individual test in a test case.
+ *
+ * It allows a library function to return a value and return an error
+ * code that can be tested.
+ *
+ * Failing the test means:
+ * - Mark this test case as failed.
+ * - Print a message identifying the failure.
+ * - Jump to the \c exit label.
+ *
+ * This macro expands to an instruction, not an expression.
+ * It may jump to the \c exit label.
+ *
+ * \param TEST The test expression to be tested.
+ */
+#define TEST_ASSERT(TEST) \
+ do { \
+ if (!(TEST)) \
+ { \
+ mbedtls_test_fail( #TEST, __LINE__, __FILE__); \
+ goto exit; \
+ } \
+ } while (0)
+
+/** This macro asserts fails the test with given output message.
+ *
+ * \param MESSAGE The message to be outputed on assertion
+ */
+#define TEST_FAIL(MESSAGE) \
+ do { \
+ mbedtls_test_fail(MESSAGE, __LINE__, __FILE__); \
+ goto exit; \
+ } while (0)
+
+/** Evaluate two integer expressions and fail the test case if they have
+ * different values.
+ *
+ * The two expressions should have the same signedness, otherwise the
+ * comparison is not meaningful if the signed value is negative.
+ *
+ * \param expr1 An integral-typed expression to evaluate.
+ * \param expr2 Another integral-typed expression to evaluate.
+ */
+#define TEST_EQUAL(expr1, expr2) \
+ do { \
+ if (!mbedtls_test_equal( #expr1 " == " #expr2, __LINE__, __FILE__, \
+ (unsigned long long) (expr1), (unsigned long long) (expr2))) \
+ goto exit; \
+ } while (0)
+
+/** Evaluate two unsigned integer expressions and fail the test case
+ * if they are not in increasing order (left <= right).
+ *
+ * \param expr1 An integral-typed expression to evaluate.
+ * \param expr2 Another integral-typed expression to evaluate.
+ */
+#define TEST_LE_U(expr1, expr2) \
+ do { \
+ if (!mbedtls_test_le_u( #expr1 " <= " #expr2, __LINE__, __FILE__, \
+ expr1, expr2)) \
+ goto exit; \
+ } while (0)
+
+/** Evaluate two signed integer expressions and fail the test case
+ * if they are not in increasing order (left <= right).
+ *
+ * \param expr1 An integral-typed expression to evaluate.
+ * \param expr2 Another integral-typed expression to evaluate.
+ */
+#define TEST_LE_S(expr1, expr2) \
+ do { \
+ if (!mbedtls_test_le_s( #expr1 " <= " #expr2, __LINE__, __FILE__, \
+ expr1, expr2)) \
+ goto exit; \
+ } while (0)
+
+/** Allocate memory dynamically and fail the test case if this fails.
+ * The allocated memory will be filled with zeros.
+ *
+ * You must set \p pointer to \c NULL before calling this macro and
+ * put `mbedtls_free(pointer)` in the test's cleanup code.
+ *
+ * If \p item_count is zero, the resulting \p pointer will be \c NULL.
+ * This is usually what we want in tests since API functions are
+ * supposed to accept null pointers when a buffer size is zero.
+ *
+ * This macro expands to an instruction, not an expression.
+ * It may jump to the \c exit label.
+ *
+ * \param pointer An lvalue where the address of the allocated buffer
+ * will be stored.
+ * This expression may be evaluated multiple times.
+ * \param item_count Number of elements to allocate.
+ * This expression may be evaluated multiple times.
+ *
+ */
+#define TEST_CALLOC(pointer, item_count) \
+ do { \
+ TEST_ASSERT((pointer) == NULL); \
+ if ((item_count) != 0) { \
+ (pointer) = mbedtls_calloc((item_count), \
+ sizeof(*(pointer))); \
+ TEST_ASSERT((pointer) != NULL); \
+ } \
+ } while (0)
+
+/** Allocate memory dynamically and fail the test case if this fails.
+ * The allocated memory will be filled with zeros.
+ *
+ * You must set \p pointer to \c NULL before calling this macro and
+ * put `mbedtls_free(pointer)` in the test's cleanup code.
+ *
+ * If \p item_count is zero, the resulting \p pointer will not be \c NULL.
+ *
+ * This macro expands to an instruction, not an expression.
+ * It may jump to the \c exit label.
+ *
+ * \param pointer An lvalue where the address of the allocated buffer
+ * will be stored.
+ * This expression may be evaluated multiple times.
+ * \param item_count Number of elements to allocate.
+ * This expression may be evaluated multiple times.
+ *
+ * Note: if passing size 0, mbedtls_calloc may return NULL. In this case,
+ * we reattempt to allocate with the smallest possible buffer to assure a
+ * non-NULL pointer.
+ */
+#define TEST_CALLOC_NONNULL(pointer, item_count) \
+ do { \
+ TEST_ASSERT((pointer) == NULL); \
+ (pointer) = mbedtls_calloc((item_count), \
+ sizeof(*(pointer))); \
+ if (((pointer) == NULL) && ((item_count) == 0)) { \
+ (pointer) = mbedtls_calloc(1, 1); \
+ } \
+ TEST_ASSERT((pointer) != NULL); \
+ } while (0)
+
+/* For backwards compatibility */
+#define ASSERT_ALLOC(pointer, item_count) TEST_CALLOC(pointer, item_count)
+
+/** Allocate memory dynamically. If the allocation fails, skip the test case.
+ *
+ * This macro behaves like #TEST_CALLOC, except that if the allocation
+ * fails, it marks the test as skipped rather than failed.
+ */
+#define TEST_CALLOC_OR_SKIP(pointer, item_count) \
+ do { \
+ TEST_ASSERT((pointer) == NULL); \
+ if ((item_count) != 0) { \
+ (pointer) = mbedtls_calloc((item_count), \
+ sizeof(*(pointer))); \
+ TEST_ASSUME((pointer) != NULL); \
+ } \
+ } while (0)
+
+/* For backwards compatibility */
+#define ASSERT_ALLOC_WEAK(pointer, item_count) TEST_CALLOC_OR_SKIP(pointer, item_count)
+
+/** Compare two buffers and fail the test case if they differ.
+ *
+ * This macro expands to an instruction, not an expression.
+ * It may jump to the \c exit label.
+ *
+ * \param p1 Pointer to the start of the first buffer.
+ * \param size1 Size of the first buffer in bytes.
+ * This expression may be evaluated multiple times.
+ * \param p2 Pointer to the start of the second buffer.
+ * \param size2 Size of the second buffer in bytes.
+ * This expression may be evaluated multiple times.
+ */
+#define TEST_MEMORY_COMPARE(p1, size1, p2, size2) \
+ do { \
+ TEST_EQUAL((size1), (size2)); \
+ if ((size1) != 0) { \
+ TEST_ASSERT(memcmp((p1), (p2), (size1)) == 0); \
+ } \
+ } while (0)
+
+/* For backwards compatibility */
+#define ASSERT_COMPARE(p1, size1, p2, size2) TEST_MEMORY_COMPARE(p1, size1, p2, size2)
+
+/**
+ * \brief This macro tests the expression passed to it and skips the
+ * running test if it doesn't evaluate to 'true'.
+ *
+ * \param TEST The test expression to be tested.
+ */
+#define TEST_ASSUME(TEST) \
+ do { \
+ if (!(TEST)) \
+ { \
+ mbedtls_test_skip( #TEST, __LINE__, __FILE__); \
+ goto exit; \
+ } \
+ } while (0)
+
+#define TEST_HELPER_ASSERT(a) if (!(a)) \
+ { \
+ mbedtls_fprintf(stderr, "Assertion Failed at %s:%d - %s\n", \
+ __FILE__, __LINE__, #a); \
+ mbedtls_exit(1); \
+ }
+
+/** Return the smaller of two values.
+ *
+ * \param x An integer-valued expression without side effects.
+ * \param y An integer-valued expression without side effects.
+ *
+ * \return The smaller of \p x and \p y.
+ */
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+
+/** Return the larger of two values.
+ *
+ * \param x An integer-valued expression without side effects.
+ * \param y An integer-valued expression without side effects.
+ *
+ * \return The larger of \p x and \p y.
+ */
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+
+#endif /* TEST_MACROS_H */
diff --git a/framework/tests/include/test/memory.h b/framework/tests/include/test/memory.h
new file mode 100644
index 0000000..940d9e6
--- /dev/null
+++ b/framework/tests/include/test/memory.h
@@ -0,0 +1,108 @@
+/**
+ * \file memory.h
+ *
+ * \brief Helper macros and functions related to testing memory management.
+ */
+
+/*
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef TEST_MEMORY_H
+#define TEST_MEMORY_H
+
+#include "mbedtls/build_info.h"
+#include "mbedtls/platform.h"
+#include "test/helpers.h"
+
+/** \def MBEDTLS_TEST_MEMORY_CAN_POISON
+ *
+ * This macro is defined if the tests are compiled with a method to mark
+ * memory as poisoned, which can be used to enforce some memory access
+ * policies.
+ *
+ * Support for the C11 thread_local keyword is also required.
+ *
+ * Currently, only Asan (Address Sanitizer) is supported.
+ */
+#if defined(MBEDTLS_TEST_HAVE_ASAN) && \
+ (__STDC_VERSION__ >= 201112L) && \
+ !defined(PSA_CRYPTO_DRIVER_TEST)
+# define MBEDTLS_TEST_MEMORY_CAN_POISON
+#endif
+
+/** \def MBEDTLS_TEST_MEMORY_POISON(buf, size)
+ *
+ * Poison a memory area so that any attempt to read or write from it will
+ * cause a runtime failure.
+ *
+ * Depending on the implementation, this may poison a few bytes beyond the
+ * indicated region, but will never poison a separate object on the heap
+ * or a separate object with more than the alignment of a long long.
+ *
+ * The behavior is undefined if any part of the memory area is invalid.
+ *
+ * This is a no-op in builds without a poisoning method.
+ * See #MBEDTLS_TEST_MEMORY_CAN_POISON.
+ *
+ * \param buf Pointer to the beginning of the memory area to poison.
+ * \param size Size of the memory area in bytes.
+ */
+
+/** \def MBEDTLS_TEST_MEMORY_UNPOISON(buf, size)
+ *
+ * Undo the effect of #MBEDTLS_TEST_MEMORY_POISON.
+ *
+ * The behavior is undefined if any part of the memory area is invalid,
+ * or if the memory area contains a mixture of poisoned and unpoisoned parts.
+ *
+ * This is a no-op in builds without a poisoning method.
+ * See #MBEDTLS_TEST_MEMORY_CAN_POISON.
+ *
+ * \param buf Pointer to the beginning of the memory area to unpoison.
+ * \param size Size of the memory area in bytes.
+ */
+
+#if defined(MBEDTLS_TEST_MEMORY_CAN_POISON)
+
+/** Thread-local variable used to enable memory poisoning. This is set and
+ * unset in the test wrappers so that calls to PSA functions from the library
+ * do not poison memory.
+ */
+extern _Thread_local unsigned int mbedtls_test_memory_poisoning_count;
+
+/** Poison a memory area so that any attempt to read or write from it will
+ * cause a runtime failure.
+ *
+ * The behavior is undefined if any part of the memory area is invalid.
+ */
+void mbedtls_test_memory_poison(const unsigned char *ptr, size_t size);
+#define MBEDTLS_TEST_MEMORY_POISON(ptr, size) \
+ do { \
+ mbedtls_test_memory_poisoning_count++; \
+ mbedtls_test_memory_poison(ptr, size); \
+ } while (0)
+
+/** Undo the effect of mbedtls_test_memory_poison().
+ *
+ * This is a no-op if the given area is entirely valid, unpoisoned memory.
+ *
+ * The behavior is undefined if any part of the memory area is invalid,
+ * or if the memory area contains a mixture of poisoned and unpoisoned parts.
+ */
+void mbedtls_test_memory_unpoison(const unsigned char *ptr, size_t size);
+#define MBEDTLS_TEST_MEMORY_UNPOISON(ptr, size) \
+ do { \
+ mbedtls_test_memory_unpoison(ptr, size); \
+ if (mbedtls_test_memory_poisoning_count != 0) { \
+ mbedtls_test_memory_poisoning_count--; \
+ } \
+ } while (0)
+
+#else /* MBEDTLS_TEST_MEMORY_CAN_POISON */
+#define MBEDTLS_TEST_MEMORY_POISON(ptr, size) ((void) (ptr), (void) (size))
+#define MBEDTLS_TEST_MEMORY_UNPOISON(ptr, size) ((void) (ptr), (void) (size))
+#endif /* MBEDTLS_TEST_MEMORY_CAN_POISON */
+
+#endif /* TEST_MEMORY_H */
diff --git a/framework/tests/include/test/psa_crypto_helpers.h b/framework/tests/include/test/psa_crypto_helpers.h
new file mode 100644
index 0000000..7ae0e30
--- /dev/null
+++ b/framework/tests/include/test/psa_crypto_helpers.h
@@ -0,0 +1,533 @@
+/*
+ * Helper functions for tests that use the PSA Crypto API.
+ */
+/*
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef PSA_CRYPTO_HELPERS_H
+#define PSA_CRYPTO_HELPERS_H
+
+#include "test/helpers.h"
+
+#if (MBEDTLS_VERSION_MAJOR < 4 && defined(MBEDTLS_PSA_CRYPTO_C)) || \
+ (MBEDTLS_VERSION_MAJOR >= 4 && defined(MBEDTLS_PSA_CRYPTO_CLIENT))
+#include "test/psa_helpers.h"
+#endif
+
+#include <psa/crypto.h>
+#include <mbedtls/ctr_drbg.h>
+
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+/** Initialize the PSA Crypto subsystem. */
+#define PSA_INIT() PSA_ASSERT(psa_crypto_init())
+
+/** Shut down the PSA Crypto subsystem and destroy persistent keys.
+ * Expect a clean shutdown, with no slots in use.
+ *
+ * If some key slots are still in use, record the test case as failed,
+ * but continue executing. This macro is suitable (and primarily intended)
+ * for use in the cleanup section of test functions.
+ *
+ * \note Persistent keys must be recorded with #TEST_USES_KEY_ID before
+ * creating them.
+ */
+#define PSA_DONE() \
+ do \
+ { \
+ mbedtls_test_fail_if_psa_leaking(__LINE__, __FILE__); \
+ mbedtls_test_psa_purge_key_storage(); \
+ mbedtls_psa_crypto_free(); \
+ } \
+ while (0)
+#elif MBEDTLS_VERSION_MAJOR >= 4 && defined(MBEDTLS_PSA_CRYPTO_CLIENT)
+#define PSA_INIT() PSA_ASSERT(psa_crypto_init())
+#define PSA_DONE() mbedtls_psa_crypto_free();
+#else /* MBEDTLS_PSA_CRYPTO_CLIENT && !MBEDTLS_PSA_CRYPTO_C */
+#define PSA_INIT() ((void) 0)
+#define PSA_DONE() ((void) 0)
+#endif /* MBEDTLS_PSA_CRYPTO_C */
+
+#if (MBEDTLS_VERSION_MAJOR < 4 && defined(MBEDTLS_PSA_CRYPTO_C)) || \
+ (MBEDTLS_VERSION_MAJOR >= 4 && defined(MBEDTLS_PSA_CRYPTO_CLIENT))
+
+#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
+
+/* Internal function for #TEST_USES_KEY_ID. Return 1 on success, 0 on failure. */
+int mbedtls_test_uses_key_id(mbedtls_svc_key_id_t key_id);
+
+/** Destroy persistent keys recorded with #TEST_USES_KEY_ID.
+ */
+void mbedtls_test_psa_purge_key_storage(void);
+
+/** Purge the in-memory cache of persistent keys recorded with
+ * #TEST_USES_KEY_ID.
+ *
+ * Call this function before calling PSA_DONE() if it's ok for
+ * persistent keys to still exist at this point.
+ */
+void mbedtls_test_psa_purge_key_cache(void);
+
+/** \def TEST_USES_KEY_ID
+ *
+ * Call this macro in a test function before potentially creating a
+ * persistent key. Test functions that use this mechanism must call
+ * mbedtls_test_psa_purge_key_storage() in their cleanup code.
+ *
+ * This macro records a persistent key identifier as potentially used in the
+ * current test case. Recorded key identifiers will be cleaned up at the end
+ * of the test case, even on failure.
+ *
+ * This macro has no effect on volatile keys. Therefore, it is safe to call
+ * this macro in a test function that creates either volatile or persistent
+ * keys depending on the test data.
+ *
+ * This macro currently has no effect on special identifiers
+ * used to store implementation-specific files.
+ *
+ * Calling this macro multiple times on the same key identifier in the same
+ * test case has no effect.
+ *
+ * This macro can fail the test case if there isn't enough memory to
+ * record the key id.
+ *
+ * \param key_id The PSA key identifier to record.
+ */
+#define TEST_USES_KEY_ID(key_id) \
+ TEST_ASSERT(mbedtls_test_uses_key_id(key_id))
+
+#else /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
+
+#define TEST_USES_KEY_ID(key_id) ((void) (key_id))
+#define mbedtls_test_psa_purge_key_storage() ((void) 0)
+#define mbedtls_test_psa_purge_key_cache() ((void) 0)
+
+#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
+
+/** Check for things that have not been cleaned up properly in the
+ * PSA subsystem.
+ *
+ * \return NULL if nothing has leaked.
+ * \return A string literal explaining what has not been cleaned up
+ * if applicable.
+ */
+const char *mbedtls_test_helper_is_psa_leaking(void);
+
+/** Check that no PSA Crypto key slots are in use.
+ *
+ * If any slots are in use, mark the current test as failed and jump to
+ * the exit label. This is equivalent to
+ * `TEST_ASSERT( ! mbedtls_test_helper_is_psa_leaking( ) )`
+ * but with a more informative message.
+ */
+#define ASSERT_PSA_PRISTINE() \
+ do \
+ { \
+ if (mbedtls_test_fail_if_psa_leaking(__LINE__, __FILE__)) \
+ goto exit; \
+ } \
+ while (0)
+
+/** Shut down the PSA Crypto subsystem, allowing persistent keys to survive.
+ * Expect a clean shutdown, with no slots in use.
+ *
+ * If some key slots are still in use, record the test case as failed and
+ * jump to the `exit` label.
+ */
+#define PSA_SESSION_DONE() \
+ do \
+ { \
+ mbedtls_test_psa_purge_key_cache(); \
+ ASSERT_PSA_PRISTINE(); \
+ mbedtls_psa_crypto_free(); \
+ } \
+ while (0)
+
+
+
+#if defined(RECORD_PSA_STATUS_COVERAGE_LOG)
+psa_status_t mbedtls_test_record_status(psa_status_t status,
+ const char *func,
+ const char *file, int line,
+ const char *expr);
+
+/** Return value logging wrapper macro.
+ *
+ * Evaluate \p expr. Write a line recording its value to the log file
+ * #STATUS_LOG_FILE_NAME and return the value. The line is a colon-separated
+ * list of fields:
+ * ```
+ * value of expr:string:__FILE__:__LINE__:expr
+ * ```
+ *
+ * The test code does not call this macro explicitly because that would
+ * be very invasive. Instead, we instrument the source code by defining
+ * a bunch of wrapper macros like
+ * ```
+ * #define psa_crypto_init() RECORD_STATUS("psa_crypto_init", psa_crypto_init())
+ * ```
+ * These macro definitions must be present in `instrument_record_status.h`
+ * when building the test suites.
+ *
+ * \param string A string, normally a function name.
+ * \param expr An expression to evaluate, normally a call of the function
+ * whose name is in \p string. This expression must return
+ * a value of type #psa_status_t.
+ * \return The value of \p expr.
+ */
+#define RECORD_STATUS(string, expr) \
+ mbedtls_test_record_status((expr), string, __FILE__, __LINE__, #expr)
+
+#include "instrument_record_status.h"
+
+#endif /* defined(RECORD_PSA_STATUS_COVERAGE_LOG) */
+
+/** Return extended key usage policies.
+ *
+ * Do a key policy permission extension on key usage policies always involves
+ * permissions of other usage policies
+ * (like PSA_KEY_USAGE_SIGN_HASH involves PSA_KEY_USAGE_SIGN_MESSAGE).
+ */
+psa_key_usage_t mbedtls_test_update_key_usage_flags(psa_key_usage_t usage_flags);
+
+/** Check that no PSA Crypto key slots are in use.
+ *
+ * If any slots are in use, mark the current test as failed.
+ *
+ * \return 0 if the key store is empty, 1 otherwise.
+ */
+int mbedtls_test_fail_if_psa_leaking(int line_no, const char *filename);
+
+
+
+#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
+/* The #MBEDTLS_PSA_INJECT_ENTROPY feature requires two extra platform
+ * functions, which must be configured as #MBEDTLS_PLATFORM_NV_SEED_READ_MACRO
+ * and #MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO. The job of these functions
+ * is to read and write from the entropy seed file, which is located
+ * in the PSA ITS file whose uid is #PSA_CRYPTO_ITS_RANDOM_SEED_UID.
+ * (These could have been provided as library functions, but for historical
+ * reasons, they weren't, and so each integrator has to provide a copy
+ * of these functions.)
+ *
+ * Provide implementations of these functions for testing. */
+int mbedtls_test_inject_entropy_seed_read(unsigned char *buf, size_t len);
+int mbedtls_test_inject_entropy_seed_write(unsigned char *buf, size_t len);
+
+
+/** Make sure that the injected entropy is present.
+ *
+ * When MBEDTLS_PSA_INJECT_ENTROPY is enabled, psa_crypto_init()
+ * will fail if the PSA entropy seed is not present.
+ * This function must be called at least once in a test suite or other
+ * program before any call to psa_crypto_init().
+ * It does not need to be called in each test case.
+ *
+ * The test framework calls this function before running any test case.
+ *
+ * The few tests that might remove the entropy file must call this function
+ * in their cleanup.
+ */
+int mbedtls_test_inject_entropy_restore(void);
+#endif /* MBEDTLS_PSA_INJECT_ENTROPY */
+
+/** Parse binary string and convert it to a long integer
+ */
+uint64_t mbedtls_test_parse_binary_string(data_t *bin_string);
+
+/** Skip a test case if the given key is a 192 bits AES key and the AES
+ * implementation is at least partially provided by an accelerator or
+ * alternative implementation.
+ *
+ * Call this macro in a test case when a cryptographic operation that may
+ * involve an AES operation returns a #PSA_ERROR_NOT_SUPPORTED error code.
+ * The macro call will skip and not fail the test case in case the operation
+ * involves a 192 bits AES key and the AES implementation is at least
+ * partially provided by an accelerator or alternative implementation.
+ *
+ * Hardware AES implementations not supporting 192 bits keys commonly exist.
+ * Consequently, PSA test cases aim at not failing when an AES operation with
+ * a 192 bits key performed by an alternative AES implementation returns
+ * with the #PSA_ERROR_NOT_SUPPORTED error code. The purpose of this macro
+ * is to facilitate this and make the test case code more readable.
+ *
+ * \param key_type Key type
+ * \param key_bits Key length in number of bits.
+ */
+#if defined(MBEDTLS_AES_ALT) || \
+ defined(MBEDTLS_AES_SETKEY_ENC_ALT) || \
+ defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_AES)
+#define MBEDTLS_TEST_HAVE_ACCEL_AES 1
+#else
+#define MBEDTLS_TEST_HAVE_ACCEL_AES 0
+#endif
+
+#define MBEDTLS_TEST_PSA_SKIP_IF_ALT_AES_192(key_type, key_bits) \
+ do \
+ { \
+ if ((MBEDTLS_TEST_HAVE_ACCEL_AES) && \
+ ((key_type) == PSA_KEY_TYPE_AES) && \
+ (key_bits == 192)) \
+ { \
+ mbedtls_test_skip("AES-192 not supported", __LINE__, __FILE__); \
+ goto exit; \
+ } \
+ } \
+ while (0)
+
+/** Skip a test case if a GCM operation with a nonce length different from
+ * 12 bytes fails and was performed by an accelerator or alternative
+ * implementation.
+ *
+ * Call this macro in a test case when an AEAD cryptography operation that
+ * may involve the GCM mode returns with a #PSA_ERROR_NOT_SUPPORTED error
+ * code. The macro call will skip and not fail the test case in case the
+ * operation involves the GCM mode, a nonce with a length different from
+ * 12 bytes and the GCM mode implementation is an alternative one.
+ *
+ * Hardware GCM implementations not supporting nonce lengths different from
+ * 12 bytes commonly exist, as supporting a non-12-byte nonce requires
+ * additional computations involving the GHASH function.
+ * Consequently, PSA test cases aim at not failing when an AEAD operation in
+ * GCM mode with a nonce length different from 12 bytes is performed by an
+ * alternative GCM implementation and returns with a #PSA_ERROR_NOT_SUPPORTED
+ * error code. The purpose of this macro is to facilitate this check and make
+ * the test case code more readable.
+ *
+ * \param alg The AEAD algorithm.
+ * \param nonce_length The nonce length in number of bytes.
+ */
+
+#if defined(MBEDTLS_GCM_ALT) || \
+ defined(MBEDTLS_PSA_ACCEL_ALG_GCM)
+#define MBEDTLS_TEST_HAVE_ACCEL_GCM 1
+#else
+#define MBEDTLS_TEST_HAVE_ACCEL_GCM 0
+#endif
+
+#define MBEDTLS_TEST_PSA_SKIP_IF_ALT_GCM_NOT_12BYTES_NONCE(alg, \
+ nonce_length) \
+ do \
+ { \
+ if ((MBEDTLS_TEST_HAVE_ACCEL_GCM) && \
+ (PSA_ALG_AEAD_WITH_SHORTENED_TAG((alg), 0) == \
+ PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, 0)) && \
+ ((nonce_length) != 12)) \
+ { \
+ mbedtls_test_skip("GCM with non-12-byte IV is not supported", __LINE__, __FILE__); \
+ goto exit; \
+ } \
+ } \
+ while (0)
+
+#endif /* MBEDTLS_PSA_CRYPTO_CLIENT || MBEDTLS_PSA_CRYPTO_C */
+
+#if MBEDTLS_VERSION_MAJOR >= 4
+/* Legacy PSA_INIT() / PSA_DONE() variants from 3.6 */
+#define USE_PSA_INIT() PSA_INIT()
+#define USE_PSA_DONE() PSA_DONE()
+#define MD_PSA_INIT() PSA_INIT()
+#define MD_PSA_DONE() PSA_DONE()
+#define BLOCK_CIPHER_PSA_INIT() PSA_INIT()
+#define BLOCK_CIPHER_PSA_DONE() PSA_DONE()
+#define MD_OR_USE_PSA_INIT() PSA_INIT()
+#define MD_OR_USE_PSA_DONE() PSA_DONE()
+#define AES_PSA_INIT() PSA_INIT()
+#define AES_PSA_DONE() PSA_DONE()
+
+#else /* MBEDTLS_VERSION_MAJOR < 4 */
+
+/** \def USE_PSA_INIT
+ *
+ * Call this macro to initialize the PSA subsystem if #MBEDTLS_USE_PSA_CRYPTO
+ * or #MBEDTLS_SSL_PROTO_TLS1_3 (In contrast to TLS 1.2 implementation, the
+ * TLS 1.3 one uses PSA independently of the definition of
+ * #MBEDTLS_USE_PSA_CRYPTO) is enabled and do nothing otherwise.
+ *
+ * If the initialization fails, mark the test case as failed and jump to the
+ * \p exit label.
+ */
+/** \def USE_PSA_DONE
+ *
+ * Call this macro at the end of a test case if you called #USE_PSA_INIT.
+ *
+ * This is like #PSA_DONE except it does nothing under the same conditions as
+ * #USE_PSA_INIT.
+ */
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#define USE_PSA_INIT() PSA_INIT()
+#define USE_PSA_DONE() PSA_DONE()
+#elif defined(MBEDTLS_SSL_PROTO_TLS1_3)
+/* TLS 1.3 must work without having called psa_crypto_init(), for backward
+ * compatibility with Mbed TLS <= 3.5 when connecting with a peer that
+ * supports both TLS 1.2 and TLS 1.3. See mbedtls_ssl_tls13_crypto_init()
+ * and https://github.com/Mbed-TLS/mbedtls/issues/9072 . */
+#define USE_PSA_INIT() ((void) 0)
+/* TLS 1.3 may have initialized the PSA subsystem. Shut it down cleanly,
+ * otherwise Asan and Valgrind would notice a resource leak. */
+#define USE_PSA_DONE() PSA_DONE()
+#else /* MBEDTLS_USE_PSA_CRYPTO || MBEDTLS_SSL_PROTO_TLS1_3 */
+/* Define empty macros so that we can use them in the preamble and teardown
+ * of every test function that uses PSA conditionally based on
+ * MBEDTLS_USE_PSA_CRYPTO. */
+#define USE_PSA_INIT() ((void) 0)
+#define USE_PSA_DONE() ((void) 0)
+#endif /* !MBEDTLS_USE_PSA_CRYPTO && !MBEDTLS_SSL_PROTO_TLS1_3 */
+
+/** \def MD_PSA_INIT
+ *
+ * Call this macro to initialize the PSA subsystem if MD uses a driver,
+ * and do nothing otherwise.
+ *
+ * If the initialization fails, mark the test case as failed and jump to the
+ * \p exit label.
+ */
+/** \def MD_PSA_DONE
+ *
+ * Call this macro at the end of a test case if you called #MD_PSA_INIT.
+ *
+ * This is like #PSA_DONE except it does nothing under the same conditions as
+ * #MD_PSA_INIT.
+ */
+#if defined(MBEDTLS_MD_SOME_PSA)
+#define MD_PSA_INIT() PSA_INIT()
+#define MD_PSA_DONE() PSA_DONE()
+#else /* MBEDTLS_MD_SOME_PSA */
+#define MD_PSA_INIT() ((void) 0)
+#define MD_PSA_DONE() ((void) 0)
+#endif /* MBEDTLS_MD_SOME_PSA */
+
+/** \def BLOCK_CIPHER_PSA_INIT
+ *
+ * Call this macro to initialize the PSA subsystem if BLOCK_CIPHER uses a driver,
+ * and do nothing otherwise.
+ *
+ * If the initialization fails, mark the test case as failed and jump to the
+ * \p exit label.
+ */
+/** \def BLOCK_CIPHER_PSA_DONE
+ *
+ * Call this macro at the end of a test case if you called #BLOCK_CIPHER_PSA_INIT.
+ *
+ * This is like #PSA_DONE except it does nothing under the same conditions as
+ * #BLOCK_CIPHER_PSA_INIT.
+ */
+#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA)
+#define BLOCK_CIPHER_PSA_INIT() PSA_INIT()
+#define BLOCK_CIPHER_PSA_DONE() PSA_DONE()
+#else /* MBEDTLS_MD_SOME_PSA */
+#define BLOCK_CIPHER_PSA_INIT() ((void) 0)
+#define BLOCK_CIPHER_PSA_DONE() ((void) 0)
+#endif /* MBEDTLS_MD_SOME_PSA */
+
+
+/** \def MD_OR_USE_PSA_INIT
+ *
+ * Call this macro to initialize the PSA subsystem if MD uses a driver,
+ * or if #MBEDTLS_USE_PSA_CRYPTO or #MBEDTLS_SSL_PROTO_TLS1_3 is enabled,
+ * and do nothing otherwise.
+ *
+ * If the initialization fails, mark the test case as failed and jump to the
+ * \p exit label.
+ */
+/** \def MD_OR_USE_PSA_DONE
+ *
+ * Call this macro at the end of a test case if you called #MD_OR_USE_PSA_INIT.
+ *
+ * This is like #PSA_DONE except it does nothing under the same conditions as
+ * #MD_OR_USE_PSA_INIT.
+ */
+#if defined(MBEDTLS_MD_SOME_PSA)
+#define MD_OR_USE_PSA_INIT() PSA_INIT()
+#define MD_OR_USE_PSA_DONE() PSA_DONE()
+#else
+#define MD_OR_USE_PSA_INIT() USE_PSA_INIT()
+#define MD_OR_USE_PSA_DONE() USE_PSA_DONE()
+#endif
+
+/** \def AES_PSA_INIT
+ *
+ * Call this macro to initialize the PSA subsystem if AES_C is not defined,
+ * so that CTR_DRBG uses PSA implementation to get AES-ECB.
+ *
+ * If the initialization fails, mark the test case as failed and jump to the
+ * \p exit label.
+ */
+/** \def AES_PSA_DONE
+ *
+ * Call this macro at the end of a test case if you called #AES_PSA_INIT.
+ *
+ * This is like #PSA_DONE except it does nothing under the same conditions as
+ * #AES_PSA_INIT.
+ */
+#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO)
+#define AES_PSA_INIT() PSA_INIT()
+#define AES_PSA_DONE() PSA_DONE()
+#else /* MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO */
+#define AES_PSA_INIT() ((void) 0)
+#define AES_PSA_DONE() ((void) 0)
+#endif /* MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO */
+
+#endif /* MBEDTLS_VERSION_MAJOR >= 4 */
+
+#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) && \
+ defined(MBEDTLS_CTR_DRBG_C) && \
+ defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO)
+/* When AES_C is not defined and PSA does not have an external RNG,
+ * then CTR_DRBG uses PSA to perform AES-ECB. In this scenario 1 key
+ * slot is used internally from PSA to hold the AES key and it should
+ * not be taken into account when evaluating remaining open slots. */
+#define MBEDTLS_TEST_PSA_INTERNAL_KEYS_FOR_DRBG 1
+#else
+#define MBEDTLS_TEST_PSA_INTERNAL_KEYS_FOR_DRBG 0
+#endif
+
+/** The number of volatile keys that PSA crypto uses internally.
+ *
+ * We expect that many volatile keys to be in use after a successful
+ * psa_crypto_init().
+ */
+#define MBEDTLS_TEST_PSA_INTERNAL_KEYS \
+ MBEDTLS_TEST_PSA_INTERNAL_KEYS_FOR_DRBG
+
+/* A couple of helper macros to verify if MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE is
+ * large enough to contain an RSA key pair of the given size. This is meant to be
+ * used in test cases where MBEDTLS_PSA_STATIC_KEY_SLOTS is enabled. */
+#if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
+
+#if (MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE >= PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(4096))
+#define MBEDTLS_TEST_STATIC_KEY_SLOTS_SUPPORT_RSA_4096
+#endif
+
+#if (MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE >= PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(2048))
+#define MBEDTLS_TEST_STATIC_KEY_SLOTS_SUPPORT_RSA_2048
+#endif
+
+#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */
+
+/* Helper macro to get the size of the each key slot buffer. */
+#if defined(MBEDTLS_PSA_STATIC_KEY_SLOTS)
+#define MBEDTLS_PSA_KEY_BUFFER_MAX_SIZE MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE
+#else
+#define MBEDTLS_PSA_KEY_BUFFER_MAX_SIZE SIZE_MAX
+#endif
+
+/* Helper macro for the PK module to check whether MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE
+ * is large enough to contain 4096-bit RSA key pairs. Of course this check is only
+ * necessary if PK relies on PSA (i.e. MBEDTLS_USE_PSA_CRYPTO) to store and manage
+ * the key. */
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+
+#if !defined(MBEDTLS_PSA_STATIC_KEY_SLOTS) || \
+ defined(MBEDTLS_TEST_STATIC_KEY_SLOTS_SUPPORT_RSA_4096)
+#define MBEDTLS_TEST_PK_ALLOW_RSA_KEY_PAIR_4096
+#endif
+
+#else /* MBEDTLS_USE_PSA_CRYPTO */
+
+#define MBEDTLS_TEST_PK_ALLOW_RSA_KEY_PAIR_4096
+
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+#endif /* PSA_CRYPTO_HELPERS_H */
diff --git a/framework/tests/include/test/psa_exercise_key.h b/framework/tests/include/test/psa_exercise_key.h
new file mode 100644
index 0000000..f44608b
--- /dev/null
+++ b/framework/tests/include/test/psa_exercise_key.h
@@ -0,0 +1,286 @@
+/** 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
+ */
+
+#ifndef PSA_EXERCISE_KEY_H
+#define PSA_EXERCISE_KEY_H
+
+#include "test/helpers.h"
+#include "test/psa_crypto_helpers.h"
+
+#include <psa/crypto.h>
+
+#if defined(MBEDTLS_PK_C)
+#include <mbedtls/pk.h>
+#endif
+
+/** \def KNOWN_SUPPORTED_HASH_ALG
+ *
+ * A hash algorithm that is known to be supported.
+ *
+ * This is used in some smoke tests.
+ */
+#if defined(PSA_WANT_ALG_SHA_256)
+#define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_SHA_256
+#elif defined(PSA_WANT_ALG_SHA_384)
+#define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_SHA_384
+#elif defined(PSA_WANT_ALG_SHA_512)
+#define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_SHA_512
+#elif defined(PSA_WANT_ALG_SHA3_256)
+#define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_SHA3_256
+#elif defined(PSA_WANT_ALG_SHA_1)
+#define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_SHA_1
+#elif defined(PSA_WANT_ALG_MD5)
+#define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_MD5
+/* PSA_WANT_ALG_RIPEMD160 omitted. This is necessary for the sake of
+ * exercise_signature_key() because Mbed TLS doesn't support RIPEMD160
+ * in RSA PKCS#1v1.5 signatures. A RIPEMD160-only configuration would be
+ * implausible anyway. */
+#else
+#undef KNOWN_SUPPORTED_HASH_ALG
+#endif
+
+/** \def KNOWN_SUPPORTED_BLOCK_CIPHER
+ *
+ * A block cipher that is known to be supported.
+ *
+ * For simplicity's sake, stick to block ciphers with 16-byte blocks.
+ */
+#if defined(PSA_WANT_KEY_TYPE_AES)
+#define KNOWN_SUPPORTED_BLOCK_CIPHER PSA_KEY_TYPE_AES
+#elif defined(PSA_WANT_KEY_TYPE_ARIA)
+#define KNOWN_SUPPORTED_BLOCK_CIPHER PSA_KEY_TYPE_ARIA
+#elif defined(PSA_WANT_KEY_TYPE_CAMELLIA)
+#define KNOWN_SUPPORTED_BLOCK_CIPHER PSA_KEY_TYPE_CAMELLIA
+#else
+#undef KNOWN_SUPPORTED_BLOCK_CIPHER
+#endif
+
+/** \def KNOWN_SUPPORTED_MAC_ALG
+ *
+ * A MAC mode that is known to be supported.
+ *
+ * It must either be HMAC with #KNOWN_SUPPORTED_HASH_ALG or
+ * a block cipher-based MAC with #KNOWN_SUPPORTED_BLOCK_CIPHER.
+ *
+ * This is used in some smoke tests.
+ */
+#if defined(KNOWN_SUPPORTED_HASH_ALG) && defined(PSA_WANT_ALG_HMAC)
+#define KNOWN_SUPPORTED_MAC_ALG (PSA_ALG_HMAC(KNOWN_SUPPORTED_HASH_ALG))
+#define KNOWN_SUPPORTED_MAC_KEY_TYPE PSA_KEY_TYPE_HMAC
+#elif defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(MBEDTLS_CMAC_C)
+#define KNOWN_SUPPORTED_MAC_ALG PSA_ALG_CMAC
+#define KNOWN_SUPPORTED_MAC_KEY_TYPE KNOWN_SUPPORTED_BLOCK_CIPHER
+#else
+#undef KNOWN_SUPPORTED_MAC_ALG
+#undef KNOWN_SUPPORTED_MAC_KEY_TYPE
+#endif
+
+/** \def KNOWN_SUPPORTED_BLOCK_CIPHER_ALG
+ *
+ * A cipher algorithm and key type that are known to be supported.
+ *
+ * This is used in some smoke tests.
+ */
+#if defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(PSA_WANT_ALG_CTR)
+#define KNOWN_SUPPORTED_BLOCK_CIPHER_ALG PSA_ALG_CTR
+#elif defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(PSA_WANT_ALG_CBC_NO_PADDING)
+#define KNOWN_SUPPORTED_BLOCK_CIPHER_ALG PSA_ALG_CBC_NO_PADDING
+#elif defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(PSA_WANT_ALG_CFB)
+#define KNOWN_SUPPORTED_BLOCK_CIPHER_ALG PSA_ALG_CFB
+#elif defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(PSA_WANT_ALG_OFB)
+#define KNOWN_SUPPORTED_BLOCK_CIPHER_ALG PSA_ALG_OFB
+#else
+#undef KNOWN_SUPPORTED_BLOCK_CIPHER_ALG
+#endif
+#if defined(KNOWN_SUPPORTED_BLOCK_CIPHER_ALG)
+#define KNOWN_SUPPORTED_CIPHER_ALG KNOWN_SUPPORTED_BLOCK_CIPHER_ALG
+#define KNOWN_SUPPORTED_CIPHER_KEY_TYPE KNOWN_SUPPORTED_BLOCK_CIPHER
+#else
+#undef KNOWN_SUPPORTED_CIPHER_ALG
+#undef KNOWN_SUPPORTED_CIPHER_KEY_TYPE
+#endif
+
+/** Convenience function to set up a key derivation.
+ *
+ * In case of failure, mark the current test case as failed.
+ *
+ * The inputs \p input1 and \p input2 are, in order:
+ * - HKDF: salt, info.
+ * - TKS 1.2 PRF, TLS 1.2 PSK-to-MS: seed, label.
+ * - PBKDF2: input cost, salt.
+ *
+ * \param operation The operation object to use.
+ * It must be in the initialized state.
+ * \param key The key to use.
+ * \param alg The algorithm to use.
+ * \param input1 The first input to pass.
+ * \param input1_length The length of \p input1 in bytes.
+ * \param input2 The first input to pass.
+ * \param input2_length The length of \p input2 in bytes.
+ * \param capacity The capacity to set.
+ * \param key_destroyable If set to 1, a failure due to the key not existing
+ * or the key being destroyed mid-operation will only
+ * be reported if the error code is unexpected.
+ *
+ * \return \c 1 on success, \c 0 on failure.
+ */
+int mbedtls_test_psa_setup_key_derivation_wrap(
+ psa_key_derivation_operation_t *operation,
+ mbedtls_svc_key_id_t key,
+ psa_algorithm_t alg,
+ const unsigned char *input1, size_t input1_length,
+ const unsigned char *input2, size_t input2_length,
+ size_t capacity, int key_destroyable);
+
+/** Perform a key agreement using the given key pair against its public key
+ * using psa_raw_key_agreement() and psa_key_agreement().
+ *
+ * The result is discarded. The purpose of this function is to smoke-test a key.
+ *
+ * In case of failure, mark the current test case as failed.
+ *
+ * \param alg A key agreement algorithm compatible with \p key.
+ * \param key A key that allows key agreement with \p alg.
+ * \param key_destroyable If set to 1, a failure due to the key not existing
+ * or the key being destroyed mid-operation will only
+ * be reported if the error code is unexpected.
+ *
+ * \return \c 1 on success, \c 0 on failure.
+ */
+psa_status_t mbedtls_test_psa_raw_key_agreement_with_self(
+ psa_algorithm_t alg,
+ mbedtls_svc_key_id_t key, int key_destroyable);
+
+/** Perform a key agreement using the given key pair against its public key
+ * using psa_key_derivation_raw_key().
+ *
+ * The result is discarded. The purpose of this function is to smoke-test a key.
+ *
+ * In case of failure, mark the current test case as failed.
+ *
+ * \param operation An operation that has been set up for a key
+ * agreement algorithm that is compatible with
+ * \p key.
+ * \param key A key pair object that is suitable for a key
+ * agreement with \p operation.
+ * \param key_destroyable If set to 1, a failure due to the key not existing
+ * or the key being destroyed mid-operation will only
+ * be reported if the error code is unexpected.
+ *
+ * \return \c 1 on success, \c 0 on failure.
+ */
+psa_status_t mbedtls_test_psa_key_agreement_with_self(
+ psa_key_derivation_operation_t *operation,
+ mbedtls_svc_key_id_t key, int key_destroyable);
+
+/** Perform sanity checks on the given key representation.
+ *
+ * If any of the checks fail, mark the current test case as failed.
+ *
+ * The checks depend on the key type.
+ * - All types: check the export size against maximum-size macros.
+ * - DES: parity bits.
+ * - RSA: check the ASN.1 structure and the size and parity of the integers.
+ * - ECC private or public key: exact representation length.
+ * - Montgomery public key: first byte.
+ *
+ * \param type The key type.
+ * \param bits The key size in bits.
+ * \param exported A buffer containing the key representation.
+ * \param exported_length The length of \p exported in bytes.
+ *
+ * \return \c 1 if all checks passed, \c 0 on failure.
+ */
+int mbedtls_test_psa_exported_key_sanity_check(
+ psa_key_type_t type, size_t bits,
+ const uint8_t *exported, size_t exported_length);
+
+/** Do smoke tests on a key.
+ *
+ * Perform one of each operation indicated by \p alg (decrypt/encrypt,
+ * sign/verify, or derivation) that is permitted according to \p usage.
+ * \p usage and \p alg should correspond to the expected policy on the
+ * key.
+ *
+ * Export the key if permitted by \p usage, and check that the output
+ * looks sensible. If \p usage forbids export, check that
+ * \p psa_export_key correctly rejects the attempt. If the key is
+ * asymmetric, also check \p psa_export_public_key.
+ *
+ * If the key fails the tests, this function calls the test framework's
+ * `mbedtls_test_fail` function and returns false. Otherwise this function
+ * returns true. Therefore it should be used as follows:
+ * ```
+ * if( ! exercise_key( ... ) ) goto exit;
+ * ```
+ * To use this function for multi-threaded tests where the key
+ * may be destroyed at any point: call this function with key_destroyable set
+ * to 1, while another thread calls psa_destroy_key on the same key;
+ * this will test whether destroying the key in use leads to any corruption.
+ *
+ * There cannot be a set of concurrent calls:
+ * `mbedtls_test_psa_exercise_key(ki,...)` such that each ki is a unique
+ * persistent key not loaded into any key slot, and i is greater than the
+ * number of free key slots.
+ * This is because such scenarios can lead to unsupported
+ * `PSA_ERROR_INSUFFICIENT_MEMORY` return codes.
+ *
+ *
+ * \param key The key to exercise. It should be capable of performing
+ * \p alg.
+ * \param usage The usage flags to assume.
+ * \param alg The algorithm to exercise.
+ * \param key_destroyable If set to 1, a failure due to the key not existing
+ * or the key being destroyed mid-operation will only
+ * be reported if the error code is unexpected.
+ *
+ * \retval 0 The key failed the smoke tests.
+ * \retval 1 The key passed the smoke tests.
+ */
+int mbedtls_test_psa_exercise_key(mbedtls_svc_key_id_t key,
+ psa_key_usage_t usage,
+ psa_algorithm_t alg,
+ int key_destroyable);
+
+psa_key_usage_t mbedtls_test_psa_usage_to_exercise(psa_key_type_t type,
+ psa_algorithm_t alg);
+
+/** Whether the specified algorithm can be exercised.
+ *
+ * \note This function is solely based on the algorithm and does not
+ * consider potential issues with the compatibility of a key.
+ * The idea is that you already have a key, so you know that the
+ * key type is supported, and you want to exercise the key but
+ * only if the algorithm given in its policy is enabled in the
+ * compile-time configuration.
+ *
+ * \note This function currently only supports signature algorithms
+ * (including wildcards).
+ * TODO: a more general mechanism, which should be automatically
+ * generated and possibly available as a library function?
+ */
+int mbedtls_test_can_exercise_psa_algorithm(psa_algorithm_t alg);
+
+#if defined(MBEDTLS_PK_C)
+/** PK-PSA key consistency test.
+ *
+ * This function tests that the pk context and the PSA key are
+ * consistent. At a minimum:
+ *
+ * - The two objects must contain keys of the same type,
+ * or a key pair and a public key of the matching type.
+ * - The two objects must have the same public key.
+ *
+ * \retval 0 The key failed the consistency tests.
+ * \retval 1 The key passed the consistency tests.
+ */
+int mbedtls_test_key_consistency_psa_pk(mbedtls_svc_key_id_t psa_key,
+ const mbedtls_pk_context *pk);
+#endif /* MBEDTLS_PK_C */
+
+#endif /* PSA_EXERCISE_KEY_H */
diff --git a/framework/tests/include/test/psa_helpers.h b/framework/tests/include/test/psa_helpers.h
new file mode 100644
index 0000000..b617189
--- /dev/null
+++ b/framework/tests/include/test/psa_helpers.h
@@ -0,0 +1,24 @@
+/*
+ * Helper functions for tests that use any PSA API.
+ */
+/*
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef PSA_HELPERS_H
+#define PSA_HELPERS_H
+
+#if defined(MBEDTLS_PSA_CRYPTO_SPM)
+#include "spm/psa_defs.h"
+#endif
+
+/** Evaluate an expression and fail the test case if it returns an error.
+ *
+ * \param expr The expression to evaluate. This is typically a call
+ * to a \c psa_xxx function that returns a value of type
+ * #psa_status_t.
+ */
+#define PSA_ASSERT(expr) TEST_EQUAL((expr), PSA_SUCCESS)
+
+#endif /* PSA_HELPERS_H */
diff --git a/framework/tests/include/test/psa_memory_poisoning_wrappers.h b/framework/tests/include/test/psa_memory_poisoning_wrappers.h
new file mode 100644
index 0000000..3f30b65
--- /dev/null
+++ b/framework/tests/include/test/psa_memory_poisoning_wrappers.h
@@ -0,0 +1,40 @@
+/** Support for memory poisoning wrappers for PSA functions.
+ *
+ * The wrappers poison the input and output buffers of each function
+ * before calling it, to ensure that it does not access the buffers
+ * except by calling the approved buffer-copying functions.
+ *
+ * This header declares support functions. The wrappers themselves are
+ * decalred in the automatically generated file `test/psa_test_wrappers.h`.
+ */
+/*
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef PSA_MEMORY_POISONING_WRAPPERS_H
+#define PSA_MEMORY_POISONING_WRAPPERS_H
+
+#include "psa/crypto.h"
+
+#include "test/memory.h"
+
+#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_TEST_MEMORY_CAN_POISON)
+
+/**
+ * \brief Setup the memory poisoning test hooks used by
+ * psa_crypto_copy_input() and psa_crypto_copy_output() for
+ * memory poisoning.
+ */
+void mbedtls_poison_test_hooks_setup(void);
+
+/**
+ * \brief Teardown the memory poisoning test hooks used by
+ * psa_crypto_copy_input() and psa_crypto_copy_output() for
+ * memory poisoning.
+ */
+void mbedtls_poison_test_hooks_teardown(void);
+
+#endif /* MBEDTLS_TEST_HOOKS && MBEDTLS_TEST_MEMORY_CAN_POISON */
+
+#endif /* PSA_MEMORY_POISONING_WRAPPERS_H */
diff --git a/framework/tests/include/test/random.h b/framework/tests/include/test/random.h
new file mode 100644
index 0000000..6304e05
--- /dev/null
+++ b/framework/tests/include/test/random.h
@@ -0,0 +1,91 @@
+/**
+ * \file random.h
+ *
+ * \brief This file contains the prototypes of 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
+ */
+
+#ifndef TEST_RANDOM_H
+#define TEST_RANDOM_H
+
+#include "mbedtls/build_info.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+ unsigned char *buf; /* Pointer to a buffer of length bytes. */
+ size_t length;
+ /* If fallback_f_rng is NULL, fail after delivering length bytes. */
+ int (*fallback_f_rng)(void *, unsigned char *, size_t);
+ void *fallback_p_rng;
+} mbedtls_test_rnd_buf_info;
+
+/**
+ * Info structure for the pseudo random function
+ *
+ * Key should be set at the start to a test-unique value.
+ * Do not forget endianness!
+ * State( v0, v1 ) should be set to zero.
+ */
+typedef struct {
+ uint32_t key[16];
+ uint32_t v0, v1;
+} mbedtls_test_rnd_pseudo_info;
+
+/**
+ * This function just returns data from rand().
+ * Although predictable and often similar on multiple
+ * runs, this does not result in identical random on
+ * each run. So do not use this if the results of a
+ * test depend on the random data that is generated.
+ *
+ * rng_state shall be NULL.
+ */
+int mbedtls_test_rnd_std_rand(void *rng_state,
+ unsigned char *output,
+ size_t len);
+
+/**
+ * This function only returns zeros.
+ *
+ * \p rng_state shall be \c NULL.
+ */
+int mbedtls_test_rnd_zero_rand(void *rng_state,
+ unsigned char *output,
+ size_t len);
+
+/**
+ * This function returns random data based on a buffer it receives.
+ *
+ * \p rng_state shall be a pointer to a #mbedtls_test_rnd_buf_info structure.
+ *
+ * The number of bytes released from the buffer on each call to
+ * the random function is specified by \p len.
+ *
+ * After the buffer is empty, this function will call the fallback RNG in the
+ * #mbedtls_test_rnd_buf_info structure if there is one, and
+ * will return #MBEDTLS_ERR_ENTROPY_SOURCE_FAILED otherwise.
+ */
+int mbedtls_test_rnd_buffer_rand(void *rng_state,
+ unsigned char *output,
+ size_t len);
+
+/**
+ * This function returns random based on a pseudo random function.
+ * This means the results should be identical on all systems.
+ * Pseudo random is based on the XTEA encryption algorithm to
+ * generate pseudorandom.
+ *
+ * \p rng_state shall be a pointer to a #mbedtls_test_rnd_pseudo_info structure.
+ */
+int mbedtls_test_rnd_pseudo_rand(void *rng_state,
+ unsigned char *output,
+ size_t len);
+
+#endif /* TEST_RANDOM_H */
diff --git a/framework/tests/include/test/threading_helpers.h b/framework/tests/include/test/threading_helpers.h
new file mode 100644
index 0000000..79bc6c0
--- /dev/null
+++ b/framework/tests/include/test/threading_helpers.h
@@ -0,0 +1,112 @@
+/**
+ * \file threading_helpers.h
+ *
+ * \brief This file contains the prototypes of helper functions for the purpose
+ * of testing threading.
+ */
+
+/*
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef THREADING_HELPERS_H
+#define THREADING_HELPERS_H
+
+#if defined MBEDTLS_THREADING_C
+
+#include "mbedtls/private_access.h"
+#include "mbedtls/build_info.h"
+
+/* Most fields of publicly available structs are private and are wrapped with
+ * MBEDTLS_PRIVATE macro. This define allows tests to access the private fields
+ * directly (without using the MBEDTLS_PRIVATE wrapper). */
+#define MBEDTLS_ALLOW_PRIVATE_ACCESS
+
+#define MBEDTLS_ERR_THREADING_THREAD_ERROR -0x001F
+
+#if defined(MBEDTLS_THREADING_PTHREAD)
+#include <pthread.h>
+#endif /* MBEDTLS_THREADING_PTHREAD */
+
+#if defined(MBEDTLS_THREADING_ALT)
+/* You should define the mbedtls_test_thread_t type in your header */
+#include "threading_alt.h"
+
+/**
+ * \brief Set your alternate threading implementation
+ * function pointers for test threads. If used, this
+ * function must be called once in the main thread
+ * before any other MbedTLS function is called.
+ *
+ * \note These functions are part of the testing API only and
+ * thus not considered part of the public API of
+ * MbedTLS and thus may change without notice.
+ *
+ * \param thread_create The thread create function implementation.
+ * \param thread_join The thread join function implementation.
+
+ */
+void mbedtls_test_thread_set_alt(int (*thread_create)(mbedtls_test_thread_t *thread,
+ void *(*thread_func)(
+ void *),
+ void *thread_data),
+ int (*thread_join)(mbedtls_test_thread_t *thread));
+
+#else /* MBEDTLS_THREADING_ALT*/
+
+typedef struct mbedtls_test_thread_t {
+
+#if defined(MBEDTLS_THREADING_PTHREAD)
+ pthread_t MBEDTLS_PRIVATE(thread);
+#else /* MBEDTLS_THREADING_PTHREAD */
+ /* Make sure this struct is always non-empty */
+ unsigned dummy;
+#endif
+
+} mbedtls_test_thread_t;
+
+#endif /* MBEDTLS_THREADING_ALT*/
+
+/**
+ * \brief The function pointers for thread create and thread
+ * join.
+ *
+ * \note These functions are part of the testing API only
+ * and thus not considered part of the public API of
+ * MbedTLS and thus may change without notice.
+ *
+ * \note All these functions are expected to work or
+ * the result will be undefined.
+ */
+extern int (*mbedtls_test_thread_create)(mbedtls_test_thread_t *thread,
+ void *(*thread_func)(void *), void *thread_data);
+extern int (*mbedtls_test_thread_join)(mbedtls_test_thread_t *thread);
+
+#if defined(MBEDTLS_THREADING_PTHREAD) && defined(MBEDTLS_TEST_HOOKS)
+#define MBEDTLS_TEST_MUTEX_USAGE
+#endif
+
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+/**
+ * Activate the mutex usage verification framework. See threading_helpers.c for
+ * information.
+ */
+void mbedtls_test_mutex_usage_init(void);
+
+/**
+ * Deactivate the mutex usage verification framework. See threading_helpers.c
+ * for information.
+ */
+void mbedtls_test_mutex_usage_end(void);
+
+/**
+ * Call this function after executing a test case to check for mutex usage
+ * errors.
+ */
+void mbedtls_test_mutex_usage_check(void);
+#endif /* MBEDTLS_TEST_MUTEX_USAGE */
+
+#endif /* MBEDTLS_THREADING_C */
+
+#endif /* THREADING_HELPERS_H */
diff --git a/framework/tests/programs/dlopen_demo.sh b/framework/tests/programs/dlopen_demo.sh
new file mode 100755
index 0000000..6e1e8f1
--- /dev/null
+++ b/framework/tests/programs/dlopen_demo.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+# Run the shared library dynamic loading demo program.
+# This is only expected to work when Mbed TLS is built as a shared library.
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+. "${0%/*}/../../scripts/demo_common.sh"
+
+msg "Test the dynamic loading of libmbed*"
+
+program="$programs_dir/test/dlopen"
+library_dir="$root_dir/library"
+
+# Skip this test if we don't have a shared library build. Detect this
+# through the absence of the demo program.
+if [ ! -e "$program" ]; then
+ msg "$0: this demo requires a shared library build."
+ # Exit with a success status so that this counts as a pass for run_demos.py.
+ exit
+fi
+
+# ELF-based Unix-like (Linux, *BSD, Solaris, ...)
+if [ -n "${LD_LIBRARY_PATH-}" ]; then
+ LD_LIBRARY_PATH="$library_dir:$LD_LIBRARY_PATH"
+else
+ LD_LIBRARY_PATH="$library_dir"
+fi
+export LD_LIBRARY_PATH
+
+# OSX/macOS
+if [ -n "${DYLD_LIBRARY_PATH-}" ]; then
+ DYLD_LIBRARY_PATH="$library_dir:$DYLD_LIBRARY_PATH"
+else
+ DYLD_LIBRARY_PATH="$library_dir"
+fi
+export DYLD_LIBRARY_PATH
+
+msg "Running dynamic loading test program: $program"
+msg "Loading libraries from: $library_dir"
+"$program"
diff --git a/framework/tests/programs/metatest.c b/framework/tests/programs/metatest.c
new file mode 100644
index 0000000..f39cb54
--- /dev/null
+++ b/framework/tests/programs/metatest.c
@@ -0,0 +1,484 @@
+/** \file metatest.c
+ *
+ * \brief Test features of the test framework.
+ *
+ * When you run this program, it runs a single "meta-test". A meta-test
+ * performs an operation which should be caught as a failure by our
+ * test framework. The meta-test passes if this program calls `exit` with
+ * a nonzero status, or aborts, or is terminated by a signal, or if the
+ * framework running the program considers the run an error (this happens
+ * with Valgrind for a memory leak). The non-success of the meta-test
+ * program means that the test failure has been caught correctly.
+ *
+ * Some failures are purely functional: the logic of the code causes the
+ * test result to be set to FAIL. Other failures come from extra
+ * instrumentation which is not present in a normal build; for example,
+ * Asan or Valgrind to detect memory leaks. This is reflected by the
+ * "platform" associated with each meta-test.
+ *
+ * Use the companion script `tests/scripts/run-metatests.sh` to run all
+ * the meta-tests for a given platform and validate that they trigger a
+ * detected failure as expected.
+ */
+
+/*
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+
+#include <mbedtls/debug.h>
+#include <mbedtls/platform.h>
+#include <mbedtls/platform_util.h>
+#include "test/helpers.h"
+#include "test/threading_helpers.h"
+#include "test/macros.h"
+#include "test/memory.h"
+#include "common.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#if defined(MBEDTLS_THREADING_C)
+#include <mbedtls/threading.h>
+#endif
+
+
+/* This is an external variable, so the compiler doesn't know that we're never
+ * changing its value.
+ */
+volatile int false_but_the_compiler_does_not_know = 0;
+
+/* Hide calls to calloc/free from static checkers such as
+ * `gcc-12 -Wuse-after-free`, to avoid compile-time complaints about
+ * code where we do mean to cause a runtime error. */
+void * (* volatile calloc_but_the_compiler_does_not_know)(size_t, size_t) = mbedtls_calloc;
+void(*volatile free_but_the_compiler_does_not_know)(void *) = mbedtls_free;
+
+/* Set n bytes at the address p to all-bits-zero, in such a way that
+ * the compiler should not know that p is all-bits-zero. */
+static void set_to_zero_but_the_compiler_does_not_know(volatile void *p, size_t n)
+{
+ memset((void *) p, false_but_the_compiler_does_not_know, n);
+}
+
+/* Simulate an access to the given object, to avoid compiler optimizations
+ * in code that prepares or consumes the object. */
+static void do_nothing_with_object(void *p)
+{
+ (void) p;
+}
+void(*volatile do_nothing_with_object_but_the_compiler_does_not_know)(void *) =
+ do_nothing_with_object;
+
+
+/****************************************************************/
+/* Test framework features */
+/****************************************************************/
+
+static void meta_test_fail(const char *name)
+{
+ (void) name;
+ mbedtls_test_fail("Forced test failure", __LINE__, __FILE__);
+}
+
+static void meta_test_not_equal(const char *name)
+{
+ int left = 20;
+ int right = 10;
+
+ (void) name;
+
+ TEST_EQUAL(left, right);
+exit:
+ ;
+}
+
+static void meta_test_not_le_s(const char *name)
+{
+ int left = 20;
+ int right = 10;
+
+ (void) name;
+
+ TEST_LE_S(left, right);
+exit:
+ ;
+}
+
+static void meta_test_not_le_u(const char *name)
+{
+ size_t left = 20;
+ size_t right = 10;
+
+ (void) name;
+
+ TEST_LE_U(left, right);
+exit:
+ ;
+}
+
+/****************************************************************/
+/* Platform features */
+/****************************************************************/
+
+static void null_pointer_dereference(const char *name)
+{
+ (void) name;
+ volatile char *volatile p;
+ set_to_zero_but_the_compiler_does_not_know(&p, sizeof(p));
+ /* Undefined behavior (read from null data pointer) */
+ mbedtls_printf("%p -> %u\n", (void *) p, (unsigned) *p);
+}
+
+static void null_pointer_call(const char *name)
+{
+ (void) name;
+ unsigned(*volatile p)(void);
+ set_to_zero_but_the_compiler_does_not_know(&p, sizeof(p));
+ /* Undefined behavior (execute null function pointer) */
+ /* The pointer representation may be truncated, but we don't care:
+ * the only point of printing it is to have some use of the pointer
+ * to dissuade the compiler from optimizing it away. */
+ mbedtls_printf("%lx() -> %u\n", (unsigned long) (uintptr_t) p, p());
+}
+
+
+/****************************************************************/
+/* Memory */
+/****************************************************************/
+
+static void read_after_free(const char *name)
+{
+ (void) name;
+ volatile char *p = calloc_but_the_compiler_does_not_know(1, 1);
+ *p = 'a';
+ free_but_the_compiler_does_not_know((void *) p);
+ /* Undefined behavior (read after free) */
+ mbedtls_printf("%u\n", (unsigned) *p);
+}
+
+static void double_free(const char *name)
+{
+ (void) name;
+ volatile char *p = calloc_but_the_compiler_does_not_know(1, 1);
+ *p = 'a';
+ free_but_the_compiler_does_not_know((void *) p);
+ /* Undefined behavior (double free) */
+ free_but_the_compiler_does_not_know((void *) p);
+}
+
+static void read_uninitialized_stack(const char *name)
+{
+ (void) name;
+ char buf[1];
+ if (false_but_the_compiler_does_not_know) {
+ buf[0] = '!';
+ }
+ char *volatile p = buf;
+ if (*p != 0) {
+ /* Unspecified result (read from uninitialized memory) */
+ mbedtls_printf("%u\n", (unsigned) *p);
+ }
+}
+
+static void memory_leak(const char *name)
+{
+ (void) name;
+ volatile char *p = calloc_but_the_compiler_does_not_know(1, 1);
+ mbedtls_printf("%u\n", (unsigned) *p);
+ /* Leak of a heap object */
+}
+
+/* name = "test_memory_poison_%(start)_%(offset)_%(count)_%(direction)"
+ * Poison a region starting at start from an 8-byte aligned origin,
+ * encompassing count bytes. Access the region at offset from the start.
+ * %(start), %(offset) and %(count) are decimal integers.
+ * %(direction) is either the character 'r' for read or 'w' for write.
+ */
+static void test_memory_poison(const char *name)
+{
+ size_t start = 0, offset = 0, count = 0;
+ char direction = 'r';
+ if (sscanf(name,
+ "%*[^0-9]%" MBEDTLS_PRINTF_SIZET
+ "%*[^0-9]%" MBEDTLS_PRINTF_SIZET
+ "%*[^0-9]%" MBEDTLS_PRINTF_SIZET
+ "_%c",
+ &start, &offset, &count, &direction) != 4) {
+ mbedtls_fprintf(stderr, "%s: Bad name format: %s\n", __func__, name);
+ return;
+ }
+
+ union {
+ long long ll;
+ unsigned char buf[32];
+ } aligned;
+ memset(aligned.buf, 'a', sizeof(aligned.buf));
+
+ if (start > sizeof(aligned.buf)) {
+ mbedtls_fprintf(stderr,
+ "%s: start=%" MBEDTLS_PRINTF_SIZET
+ " > size=%" MBEDTLS_PRINTF_SIZET,
+ __func__, start, sizeof(aligned.buf));
+ return;
+ }
+ if (start + count > sizeof(aligned.buf)) {
+ mbedtls_fprintf(stderr,
+ "%s: start+count=%" MBEDTLS_PRINTF_SIZET
+ " > size=%" MBEDTLS_PRINTF_SIZET,
+ __func__, start + count, sizeof(aligned.buf));
+ return;
+ }
+ if (offset >= count) {
+ mbedtls_fprintf(stderr,
+ "%s: offset=%" MBEDTLS_PRINTF_SIZET
+ " >= count=%" MBEDTLS_PRINTF_SIZET,
+ __func__, offset, count);
+ return;
+ }
+
+ MBEDTLS_TEST_MEMORY_POISON(aligned.buf + start, count);
+
+ if (direction == 'w') {
+ aligned.buf[start + offset] = 'b';
+ do_nothing_with_object_but_the_compiler_does_not_know(aligned.buf);
+ } else {
+ do_nothing_with_object_but_the_compiler_does_not_know(aligned.buf);
+ mbedtls_printf("%u\n", (unsigned) aligned.buf[start + offset]);
+ }
+}
+
+
+/****************************************************************/
+/* Threading */
+/****************************************************************/
+
+static void mutex_lock_not_initialized(const char *name)
+{
+ (void) name;
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_threading_mutex_t mutex;
+ memset(&mutex, 0, sizeof(mutex));
+ /* This mutex usage error is detected by our test framework's mutex usage
+ * verification framework. See framework/tests/src/threading_helpers.c. Other
+ * threading implementations (e.g. pthread without our instrumentation)
+ * might consider this normal usage. */
+ TEST_ASSERT(mbedtls_mutex_lock(&mutex) == 0);
+exit:
+ ;
+#endif
+}
+
+static void mutex_unlock_not_initialized(const char *name)
+{
+ (void) name;
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_threading_mutex_t mutex;
+ memset(&mutex, 0, sizeof(mutex));
+ /* This mutex usage error is detected by our test framework's mutex usage
+ * verification framework. See framework/tests/src/threading_helpers.c. Other
+ * threading implementations (e.g. pthread without our instrumentation)
+ * might consider this normal usage. */
+ TEST_ASSERT(mbedtls_mutex_unlock(&mutex) == 0);
+exit:
+ ;
+#endif
+}
+
+static void mutex_free_not_initialized(const char *name)
+{
+ (void) name;
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_threading_mutex_t mutex;
+ memset(&mutex, 0, sizeof(mutex));
+ /* This mutex usage error is detected by our test framework's mutex usage
+ * verification framework. See framework/tests/src/threading_helpers.c. Other
+ * threading implementations (e.g. pthread without our instrumentation)
+ * might consider this normal usage. */
+ mbedtls_mutex_free(&mutex);
+#endif
+}
+
+static void mutex_double_init(const char *name)
+{
+ (void) name;
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_threading_mutex_t mutex;
+ mbedtls_mutex_init(&mutex);
+ /* This mutex usage error is detected by our test framework's mutex usage
+ * verification framework. See framework/tests/src/threading_helpers.c. Other
+ * threading implementations (e.g. pthread without our instrumentation)
+ * might consider this normal usage. */
+ mbedtls_mutex_init(&mutex);
+ mbedtls_mutex_free(&mutex);
+#endif
+}
+
+static void mutex_double_free(const char *name)
+{
+ (void) name;
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_threading_mutex_t mutex;
+ mbedtls_mutex_init(&mutex);
+ mbedtls_mutex_free(&mutex);
+ /* This mutex usage error is detected by our test framework's mutex usage
+ * verification framework. See framework/tests/src/threading_helpers.c. Other
+ * threading implementations (e.g. pthread without our instrumentation)
+ * might consider this normal usage. */
+ mbedtls_mutex_free(&mutex);
+#endif
+}
+
+static void mutex_leak(const char *name)
+{
+ (void) name;
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_threading_mutex_t mutex;
+ mbedtls_mutex_init(&mutex);
+#endif
+ /* This mutex usage error is detected by our test framework's mutex usage
+ * verification framework. See framework/tests/src/threading_helpers.c. Other
+ * threading implementations (e.g. pthread without our instrumentation)
+ * might consider this normal usage. */
+}
+
+
+/****************************************************************/
+/* Command line entry point */
+/****************************************************************/
+
+typedef struct {
+ /** Command line argument that will trigger that metatest.
+ *
+ * Conventionally matches "[a-z0-9_]+". */
+ const char *name;
+
+ /** Platform under which that metatest is valid.
+ *
+ * - "any": should work anywhere.
+ * - "asan": triggers ASan (Address Sanitizer).
+ * - "msan": triggers MSan (Memory Sanitizer).
+ * - "pthread": requires MBEDTLS_THREADING_PTHREAD and MBEDTLS_TEST_HOOKS,
+ * which enables MBEDTLS_TEST_MUTEX_USAGE internally in the test
+ * framework (see framework/tests/src/threading_helpers.c).
+ */
+ const char *platform;
+
+ /** Function that performs the metatest.
+ *
+ * The function receives the name as an argument. This allows using the
+ * same function to perform multiple variants of a test based on the name.
+ *
+ * When executed on a conforming platform, the function is expected to
+ * either cause a test failure (mbedtls_test_fail()), or cause the
+ * program to abort in some way (e.g. by causing a segfault or by
+ * triggering a sanitizer).
+ *
+ * When executed on a non-conforming platform, the function may return
+ * normally or may have unpredictable behavior.
+ */
+ void (*entry_point)(const char *name);
+} metatest_t;
+
+/* The list of available meta-tests. Remember to register new functions here!
+ *
+ * Note that we always compile all the functions, so that `metatest --list`
+ * will always list all the available meta-tests.
+ *
+ * See the documentation of metatest_t::platform for the meaning of
+ * platform values.
+ */
+metatest_t metatests[] = {
+ { "test_fail", "any", meta_test_fail },
+ { "test_not_equal", "any", meta_test_not_equal },
+ { "test_not_le_s", "any", meta_test_not_le_s },
+ { "test_not_le_u", "any", meta_test_not_le_u },
+ { "null_dereference", "any", null_pointer_dereference },
+ { "null_call", "any", null_pointer_call },
+ { "read_after_free", "asan", read_after_free },
+ { "double_free", "asan", double_free },
+ { "read_uninitialized_stack", "msan", read_uninitialized_stack },
+ { "memory_leak", "asan", memory_leak },
+ { "test_memory_poison_0_0_8_r", "poison", test_memory_poison },
+ { "test_memory_poison_0_0_8_w", "poison", test_memory_poison },
+ { "test_memory_poison_0_7_8_r", "poison", test_memory_poison },
+ { "test_memory_poison_0_7_8_w", "poison", test_memory_poison },
+ { "test_memory_poison_0_0_1_r", "poison", test_memory_poison },
+ { "test_memory_poison_0_0_1_w", "poison", test_memory_poison },
+ { "test_memory_poison_0_1_2_r", "poison", test_memory_poison },
+ { "test_memory_poison_0_1_2_w", "poison", test_memory_poison },
+ { "test_memory_poison_7_0_8_r", "poison", test_memory_poison },
+ { "test_memory_poison_7_0_8_w", "poison", test_memory_poison },
+ { "test_memory_poison_7_7_8_r", "poison", test_memory_poison },
+ { "test_memory_poison_7_7_8_w", "poison", test_memory_poison },
+ { "test_memory_poison_7_0_1_r", "poison", test_memory_poison },
+ { "test_memory_poison_7_0_1_w", "poison", test_memory_poison },
+ { "test_memory_poison_7_1_2_r", "poison", test_memory_poison },
+ { "test_memory_poison_7_1_2_w", "poison", test_memory_poison },
+ { "mutex_lock_not_initialized", "pthread", mutex_lock_not_initialized },
+ { "mutex_unlock_not_initialized", "pthread", mutex_unlock_not_initialized },
+ { "mutex_free_not_initialized", "pthread", mutex_free_not_initialized },
+ { "mutex_double_init", "pthread", mutex_double_init },
+ { "mutex_double_free", "pthread", mutex_double_free },
+ { "mutex_leak", "pthread", mutex_leak },
+ { NULL, NULL, NULL }
+};
+
+static void help(FILE *out, const char *argv0)
+{
+ mbedtls_fprintf(out, "Usage: %s list|TEST\n", argv0);
+ mbedtls_fprintf(out, "Run a meta-test that should cause a test failure.\n");
+ mbedtls_fprintf(out, "With 'list', list the available tests and their platform requirement.\n");
+}
+
+int main(int argc, char *argv[])
+{
+ const char *argv0 = argc > 0 ? argv[0] : "metatest";
+ if (argc != 2) {
+ help(stderr, argv0);
+ mbedtls_exit(MBEDTLS_EXIT_FAILURE);
+ }
+
+ /* Support "-help", "--help", "--list", etc. */
+ const char *command = argv[1];
+ while (*command == '-') {
+ ++command;
+ }
+
+ if (strcmp(argv[1], "help") == 0) {
+ help(stdout, argv0);
+ mbedtls_exit(MBEDTLS_EXIT_SUCCESS);
+ }
+ if (strcmp(argv[1], "list") == 0) {
+ for (const metatest_t *p = metatests; p->name != NULL; p++) {
+ mbedtls_printf("%s %s\n", p->name, p->platform);
+ }
+ mbedtls_exit(MBEDTLS_EXIT_SUCCESS);
+ }
+
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+ mbedtls_test_mutex_usage_init();
+#endif
+
+ for (const metatest_t *p = metatests; p->name != NULL; p++) {
+ if (strcmp(argv[1], p->name) == 0) {
+ mbedtls_printf("Running metatest %s...\n", argv[1]);
+ p->entry_point(argv[1]);
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+ mbedtls_test_mutex_usage_check();
+#endif
+ int result = (int) mbedtls_test_get_result();
+
+ mbedtls_printf("Running metatest %s... done, result=%d\n",
+ argv[1], result);
+ mbedtls_exit(result == MBEDTLS_TEST_RESULT_SUCCESS ?
+ MBEDTLS_EXIT_SUCCESS :
+ MBEDTLS_EXIT_FAILURE);
+ }
+ }
+
+ mbedtls_fprintf(stderr, "%s: FATAL: No such metatest: %s\n",
+ argv0, command);
+ mbedtls_exit(MBEDTLS_EXIT_FAILURE);
+}
diff --git a/framework/tests/programs/query_compile_time_config.c b/framework/tests/programs/query_compile_time_config.c
new file mode 100644
index 0000000..a70e6da
--- /dev/null
+++ b/framework/tests/programs/query_compile_time_config.c
@@ -0,0 +1,66 @@
+/*
+ * Query the Mbed TLS compile time configuration
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "mbedtls/build_info.h"
+
+#include "mbedtls/platform.h"
+
+#define USAGE \
+ "usage: %s [ -all | -any | -l ] <MBEDTLS_CONFIG> ...\n\n" \
+ "This program takes command line arguments which correspond to\n" \
+ "the string representation of Mbed TLS compile time configurations.\n\n" \
+ "If \"--all\" and \"--any\" are not used, then, if all given arguments\n" \
+ "are defined in the Mbed TLS build, 0 is returned; otherwise 1 is\n" \
+ "returned. Macro expansions of configurations will be printed (if any).\n" \
+ "-l\tPrint all available configuration.\n" \
+ "-all\tReturn 0 if all configurations are defined. Otherwise, return 1\n" \
+ "-any\tReturn 0 if any configuration is defined. Otherwise, return 1\n" \
+ "-h\tPrint this usage\n"
+
+#include <string.h>
+#include "query_config.h"
+
+int main(int argc, char *argv[])
+{
+ int i;
+
+ if (argc < 2 || strcmp(argv[1], "-h") == 0) {
+ mbedtls_printf(USAGE, argv[0]);
+ return MBEDTLS_EXIT_FAILURE;
+ }
+
+ if (strcmp(argv[1], "-l") == 0) {
+ list_config();
+ return 0;
+ }
+
+ if (strcmp(argv[1], "-all") == 0) {
+ for (i = 2; i < argc; i++) {
+ if (query_config(argv[i]) != 0) {
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ if (strcmp(argv[1], "-any") == 0) {
+ for (i = 2; i < argc; i++) {
+ if (query_config(argv[i]) == 0) {
+ return 0;
+ }
+ }
+ return 1;
+ }
+
+ for (i = 1; i < argc; i++) {
+ if (query_config(argv[i]) != 0) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/framework/tests/programs/query_config.h b/framework/tests/programs/query_config.h
new file mode 100644
index 0000000..43f120b
--- /dev/null
+++ b/framework/tests/programs/query_config.h
@@ -0,0 +1,34 @@
+/*
+ * Query Mbed TLS compile time configurations from mbedtls_config.h
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef MBEDTLS_PROGRAMS_TEST_QUERY_CONFIG_H
+#define MBEDTLS_PROGRAMS_TEST_QUERY_CONFIG_H
+
+#include "mbedtls/build_info.h"
+
+/** Check whether a given configuration symbol is enabled.
+ *
+ * \param config The symbol to query (e.g. "MBEDTLS_RSA_C").
+ * \return \c 0 if the symbol was defined at compile time
+ * (in MBEDTLS_CONFIG_FILE or mbedtls_config.h),
+ * \c 1 otherwise.
+ *
+ * \note This function is defined in `programs/test/query_config.c`
+ * which is automatically generated by
+ * `scripts/generate_query_config.pl`.
+ */
+int query_config(const char *config);
+
+/** List all enabled configuration symbols
+ *
+ * \note This function is defined in `programs/test/query_config.c`
+ * which is automatically generated by
+ * `scripts/generate_query_config.pl`.
+ */
+void list_config(void);
+
+#endif /* MBEDTLS_PROGRAMS_TEST_QUERY_CONFIG_H */
diff --git a/framework/tests/programs/query_included_headers.c b/framework/tests/programs/query_included_headers.c
new file mode 100644
index 0000000..cdafa16
--- /dev/null
+++ b/framework/tests/programs/query_included_headers.c
@@ -0,0 +1,29 @@
+/* Ad hoc report on included headers. */
+/*
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <psa/crypto.h>
+#include <mbedtls/platform.h>
+
+int main(void)
+{
+
+ /* Which PSA platform header? */
+#if defined(PSA_CRYPTO_PLATFORM_H)
+ mbedtls_printf("PSA_CRYPTO_PLATFORM_H\n");
+#endif
+#if defined(PSA_CRYPTO_PLATFORM_ALT_H)
+ mbedtls_printf("PSA_CRYPTO_PLATFORM_ALT_H\n");
+#endif
+
+ /* Which PSA struct header? */
+#if defined(PSA_CRYPTO_STRUCT_H)
+ mbedtls_printf("PSA_CRYPTO_STRUCT_H\n");
+#endif
+#if defined(PSA_CRYPTO_STRUCT_ALT_H)
+ mbedtls_printf("PSA_CRYPTO_STRUCT_ALT_H\n");
+#endif
+
+}
diff --git a/framework/tests/programs/test_zeroize.gdb b/framework/tests/programs/test_zeroize.gdb
new file mode 100644
index 0000000..6eaf61b
--- /dev/null
+++ b/framework/tests/programs/test_zeroize.gdb
@@ -0,0 +1,64 @@
+# test_zeroize.gdb
+#
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+#
+# Purpose
+#
+# Run a test using the debugger to check that the mbedtls_platform_zeroize()
+# function in platform_util.h is not being optimized out by the compiler. To do
+# so, the script loads the test program at programs/test/zeroize and sets a
+# breakpoint at the last return statement in main(). When the breakpoint is
+# hit, the debugger manually checks the contents to be zeroized and checks that
+# it is actually cleared.
+#
+# The mbedtls_platform_zeroize() test is debugger driven because there does not
+# seem to be a mechanism to reliably check whether the zeroize calls are being
+# eliminated by compiler optimizations from within the compiled program. The
+# problem is that a compiler would typically remove what it considers to be
+# "unnecessary" assignments as part of redundant code elimination. To identify
+# such code, the compilar will create some form dependency graph between
+# reads and writes to variables (among other situations). It will then use this
+# data structure to remove redundant code that does not have an impact on the
+# program's observable behavior. In the case of mbedtls_platform_zeroize(), an
+# intelligent compiler could determine that this function clears a block of
+# memory that is not accessed later in the program, so removing the call to
+# mbedtls_platform_zeroize() does not have an observable behavior. However,
+# inserting a test after a call to mbedtls_platform_zeroize() to check whether
+# the block of memory was correctly zeroed would force the compiler to not
+# eliminate the mbedtls_platform_zeroize() call. If this does not occur, then
+# the compiler potentially has a bug.
+#
+# Note: This test requires that the test program is compiled with -g3.
+
+set confirm off
+
+file ./programs/test/zeroize
+
+search GDB_BREAK_HERE
+break $_
+
+set args ./framework/tests/programs/zeroize.c
+run
+
+set $i = 0
+set $len = sizeof(buf)
+set $buf = buf
+
+while $i < $len
+ if $buf[$i++] != 0
+ echo The buffer at was not zeroized\n
+ quit 1
+ end
+end
+
+echo The buffer was correctly zeroized\n
+
+continue
+
+if $_exitcode != 0
+ echo The program did not terminate correctly\n
+ quit 1
+end
+
+quit 0
diff --git a/framework/tests/programs/zeroize.c b/framework/tests/programs/zeroize.c
new file mode 100644
index 0000000..d81358e
--- /dev/null
+++ b/framework/tests/programs/zeroize.c
@@ -0,0 +1,72 @@
+/*
+ * Zeroize application for debugger-driven testing
+ *
+ * This is a simple test application used for debugger-driven testing to check
+ * whether calls to mbedtls_platform_zeroize() are being eliminated by compiler
+ * optimizations. This application is used by the GDB script at
+ * tests/programs/test_zeroize.gdb: the script sets a breakpoint at the last
+ * return statement in the main() function of this program. The debugger
+ * facilities are then used to manually inspect the memory and verify that the
+ * call to mbedtls_platform_zeroize() was not eliminated.
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "mbedtls/build_info.h"
+
+#include <stdio.h>
+
+#include "mbedtls/platform.h"
+
+#include "mbedtls/platform_util.h"
+
+#define BUFFER_LEN 1024
+
+static void usage(void)
+{
+ mbedtls_printf("Zeroize is a simple program to assist with testing\n");
+ mbedtls_printf("the mbedtls_platform_zeroize() function by using the\n");
+ mbedtls_printf("debugger. This program takes a file as input and\n");
+ mbedtls_printf("prints the first %d characters. Usage:\n\n", BUFFER_LEN);
+ mbedtls_printf(" zeroize <FILE>\n");
+}
+
+int main(int argc, char **argv)
+{
+ int exit_code = MBEDTLS_EXIT_FAILURE;
+ FILE *fp;
+ char buf[BUFFER_LEN];
+ char *p = buf;
+ char *end = p + BUFFER_LEN;
+ int c;
+
+ if (argc != 2) {
+ mbedtls_printf("This program takes exactly 1 argument\n");
+ usage();
+ mbedtls_exit(exit_code);
+ }
+
+ fp = fopen(argv[1], "r");
+ if (fp == NULL) {
+ mbedtls_printf("Could not open file '%s'\n", argv[1]);
+ mbedtls_exit(exit_code);
+ }
+
+ while ((c = fgetc(fp)) != EOF && p < end - 1) {
+ *p++ = (char) c;
+ }
+ *p = '\0';
+
+ if (p - buf != 0) {
+ mbedtls_printf("%s\n", buf);
+ exit_code = MBEDTLS_EXIT_SUCCESS;
+ } else {
+ mbedtls_printf("The file is empty!\n");
+ }
+
+ fclose(fp);
+ mbedtls_platform_zeroize(buf, sizeof(buf));
+
+ mbedtls_exit(exit_code); // GDB_BREAK_HERE -- don't remove this comment!
+}
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 */