Merge pull request #8987 from valeriosetti/issue8903

Test gap: mbedtls_pk_check_pair with MBEDTLS_PK_OPAQUE
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 9d30412..892ed28 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -9,7 +9,8 @@
 Please tick as appropriate and edit the reasons (e.g.: "backport: not needed because this is a new feature")
 
 - [ ] **changelog** provided, or not required
-- [ ] **backport** done, or not required
+- [ ] **3.6 backport** done, or not required
+- [ ] **2.28 backport** done, or not required
 - [ ] **tests** provided, or not required
 
 
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e37ca2c..fb9e1c3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -36,12 +36,12 @@
 if(TEST_CPP)
     project("Mbed TLS"
         LANGUAGES C CXX
-        VERSION 3.5.2
+        VERSION 3.6.0
     )
 else()
     project("Mbed TLS"
         LANGUAGES C
-        VERSION 3.5.2
+        VERSION 3.6.0
     )
 endif()
 
@@ -319,6 +319,8 @@
         PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tests/include
         PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
         PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/library)
+    # Request C11, needed for memory poisoning tests
+    set_target_properties(mbedtls_test PROPERTIES C_STANDARD 11)
 
     file(GLOB MBEDTLS_TEST_HELPER_FILES
          ${CMAKE_CURRENT_SOURCE_DIR}/tests/src/test_helpers/*.c)
@@ -399,7 +401,7 @@
     write_basic_package_version_file(
         "cmake/MbedTLSConfigVersion.cmake"
             COMPATIBILITY SameMajorVersion
-            VERSION 3.5.2)
+            VERSION 3.6.0)
 
     install(
         FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/MbedTLSConfig.cmake"
diff --git a/ChangeLog b/ChangeLog
index 28f2654..eae2a19 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,265 @@
 Mbed TLS ChangeLog (Sorted per branch, date)
 
+= Mbed TLS 3.6.0 branch released 2024-03-28
+
+API changes
+   * Remove `tls13_` in mbedtls_ssl_tls13_conf_early_data() and
+     mbedtls_ssl_tls13_conf_max_early_data_size() API names. Early data
+     feature may not be TLS 1.3 specific in the future. Fixes #6909.
+
+Default behavior changes
+   * psa_import_key() now only accepts RSA keys in the PSA standard formats.
+     The undocumented ability to import other formats (PKCS#8, SubjectPublicKey,
+     PEM) accepted by the pkparse module has been removed. Applications that
+     need these formats can call mbedtls_pk_parse_{public,}key() followed by
+     mbedtls_pk_import_into_psa().
+
+Requirement changes
+   * Drop support for Visual Studio 2013 and 2015, and Arm Compiler 5.
+
+New deprecations
+   * Rename the MBEDTLS_SHA256_USE_A64_CRYPTO_xxx config options to
+     MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_xxx. The old names may still
+     be used, but are deprecated.
+   * In the PSA API, domain parameters are no longer used for anything.
+     They are deprecated and will be removed in a future version of the
+     library.
+   * mbedtls_ecp_write_key() is deprecated in favor of
+     mbedtls_ecp_write_key_ext().
+
+Removals
+   * In the PSA API, the experimental way to encode the public exponent of
+     an RSA key as a domain parameter is no longer supported. Use
+     psa_generate_key_ext() instead.
+   * Temporary function mbedtls_pk_wrap_as_opaque() is removed. To mimic the
+     same behavior mbedtls_pk_get_psa_attributes() and
+     mbedtls_pk_import_into_psa() can be used to import a PK key into PSA,
+     while mbedtls_pk_setup_opaque() can be used to wrap a PSA key into a opaque
+     PK context.
+
+Features
+   * Added an example program showing how to hash with the PSA API.
+   * Support Armv8-A Crypto Extension acceleration for SHA-256
+     when compiling for Thumb (T32) or 32-bit Arm (A32).
+   * AES-NI is now supported in Windows builds with clang and clang-cl.
+     Resolves #8372.
+   * Add new mbedtls_x509_csr_parse_der_with_ext_cb() routine which allows
+     parsing unsupported certificate extensions via user provided callback.
+   * Enable the new option MBEDTLS_BLOCK_CIPHER_NO_DECRYPT to omit
+     the decryption direction of block ciphers (AES, ARIA, Camellia).
+     This affects both the low-level modules and the high-level APIs
+     (the cipher and PSA interfaces). This option is incompatible with modes
+     that use the decryption direction (ECB in PSA, CBC, XTS, KW) and with DES.
+   * Support use of Armv8-A Cryptographic Extensions for hardware acclerated
+     AES when compiling for Thumb (T32) or 32-bit Arm (A32).
+   * If a cipher or AEAD mechanism has a PSA driver, you can now build the
+     library without the corresponding built-in implementation. Generally
+     speaking that requires both the key type and algorithm to be accelerated
+     or they'll both be built in. However, for CCM and GCM the built-in
+     implementation is able to take advantage of a driver that only
+     accelerates the key type (that is, the block cipher primitive). See
+     docs/driver-only-builds.md for full details and current limitations.
+   * The CTR_DRBG module will now use AES from a PSA driver if MBEDTLS_AES_C is
+     disabled. This requires PSA_WANT_ALG_ECB_NO_PADDING in addition to
+     MBEDTLS_PSA_CRYPTO_C and PSA_WANT_KEY_TYPE_AES.
+   * Fewer modules depend on MBEDTLS_CIPHER_C, making it possible to save code
+     size by disabling it in more circumstances. In particular, the CCM and
+     GCM modules no longer depend on MBEDTLS_CIPHER_C. Also,
+     MBEDTLS_PSA_CRYPTO can now be enabled without MBEDTLS_CIPHER_C if all
+     unauthenticated (non-AEAD) ciphers are disabled, or if they're all
+     fully provided by drivers. See docs/driver-only-builds.md for full
+     details and current limitations; in particular, NIST_KW and PKCS5/PKCS12
+     decryption still unconditionally depend on MBEDTLS_CIPHER_C.
+   * Add support for record size limit extension as defined by RFC 8449
+     and configured with MBEDTLS_SSL_RECORD_SIZE_LIMIT.
+     Application data sent and received will be fragmented according to
+     Record size limits negotiated during handshake.
+   * Improve performance of AES-GCM, AES-CTR and CTR-DRBG when
+     hardware accelerated AES is not present (around 13-23% on 64-bit Arm).
+   * Add functions mbedtls_ecc_group_to_psa() and mbedtls_ecc_group_from_psa()
+     to convert between Mbed TLS and PSA curve identifiers.
+   * Add utility functions to manipulate mbedtls_ecp_keypair objects, filling
+     gaps made by making its fields private: mbedtls_ecp_set_public_key(),
+     mbedtls_ecp_write_public_key(), mbedtls_ecp_keypair_calc_public(),
+     mbedtls_ecp_keypair_get_group_id(). Fixes #5017, #5441, #8367, #8652.
+   * Add functions mbedtls_md_psa_alg_from_type() and
+     mbedtls_md_type_from_psa_alg() to convert between mbedtls_md_type_t and
+     psa_algorithm_t.
+   * Add partial platform support for z/OS.
+   * Improve performance for gcc (versions older than 9.3.0) and IAR.
+   * Add functions mbedtls_ecdsa_raw_to_der() and mbedtls_ecdsa_der_to_raw() to
+     convert ECDSA signatures between raw and DER (ASN.1) formats.
+   * Add support for using AES-CBC 128, 192, and 256 bit schemes
+     with PKCS#5 PBES2. Keys encrypted this way can now be parsed by PK parse.
+   * The new function mbedtls_rsa_get_bitlen() returns the length of the modulus
+     in bits, i.e. the key size for an RSA key.
+   * Add pc files for pkg-config, e.g.:
+     pkg-config --cflags --libs (mbedtls|mbedcrypto|mbedx509)
+   * Add getter (mbedtls_ssl_session_get_ticket_creation_time()) to access
+     `mbedtls_ssl_session.ticket_creation_time`.
+   * The new functions mbedtls_pk_get_psa_attributes() and
+     mbedtls_pk_import_into_psa() provide a uniform way to create a PSA
+     key from a PK key.
+   * The benchmark program now reports times for both ephemeral and static
+     ECDH in all ECDH configurations.
+   * Add support for 8-bit GCM tables for Shoup's algorithm to speedup GCM
+     operations when hardware accelerated AES is not present. Improves
+     performance by around 30% on 64-bit Intel; 125% on Armv7-M.
+   * The new function psa_generate_key_ext() allows generating an RSA
+     key pair with a custom public exponent.
+   * The new function mbedtls_ecp_write_key_ext() is similar to
+     mbedtls_ecp_write_key(), but can be used without separately calculating
+     the output length.
+   * Add new accessor to expose the private group id member of
+     `mbedtls_ecdh_context` structure.
+   * Add new accessor to expose the `MBEDTLS_PRIVATE(ca_istrue)` member of
+     `mbedtls_x509_crt` structure. This requires setting
+     the MBEDTLS_X509_EXT_BASIC_CONSTRAINTS bit in the certificate's
+     ext_types field.
+   * mbedtls_psa_get_random() is always available as soon as
+     MBEDTLS_PSA_CRYPTO_CLIENT is enabled at build time and psa_crypto_init() is
+     called at runtime. This together with MBEDTLS_PSA_RANDOM_STATE can be
+     used as random number generator function (f_rng) and context (p_rng) in
+     legacy functions.
+   * The new functions mbedtls_pk_copy_from_psa() and
+     mbedtls_pk_copy_public_from_psa() provide ways to set up a PK context
+     with the same content as a PSA key.
+   * Add new accessors to expose the private session-id,
+     session-id length, and ciphersuite-id members of
+     `mbedtls_ssl_session` structure.
+     Add new accessor to expose the ciphersuite-id of
+     `mbedtls_ssl_ciphersuite_t` structure.Design ref: #8529
+   * Mbed TLS now supports the writing and reading of TLS 1.3 early data (see
+     docs/tls13-early-data.md). The support enablement is controlled at build
+     time by the MBEDTLS_SSL_EARLY_DATA configuration option and at runtime by
+     the mbedtls_ssl_conf_early_data() API (by default disabled in both cases).
+   * Add protection for multithreaded access to the PSA keystore and protection
+     for multithreaded access to the the PSA global state, including
+     concurrently calling psa_crypto_init() when MBEDTLS_THREADING_C and
+     MBEDTLS_THREADING_PTHREAD are defined. See
+     docs/architecture/psa-thread-safety/psa-thread-safety.md for more details.
+     Resolves issues #3263 and #7945.
+
+Security
+   * Fix a stack buffer overread (less than 256 bytes) when parsing a TLS 1.3
+     ClientHello in a TLS 1.3 server supporting some PSK key exchange mode. A
+     malicious client could cause information disclosure or a denial of service.
+   * Passing buffers that are stored in untrusted memory as arguments
+     to PSA functions is now secure by default.
+     The PSA core now protects against modification of inputs or exposure
+     of intermediate outputs during operations. This is currently implemented
+     by copying buffers.
+     This feature increases code size and memory usage. If buffers passed to
+     PSA functions are owned exclusively by the PSA core for the duration of
+     the function call (i.e. no buffer parameters are in shared memory),
+     copying may be disabled by setting MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS.
+     Note that setting this option will cause input-output buffer overlap to
+     be only partially supported (#3266).
+     Fixes CVE-2024-28960.
+   * Restore the maximum TLS version to be negotiated to the configured one
+     when an SSL context is reset with the mbedtls_ssl_session_reset() API.
+     An attacker was able to prevent an Mbed TLS server from establishing any
+     TLS 1.3 connection potentially resulting in a Denial of Service or forced
+     version downgrade from TLS 1.3 to TLS 1.2. Fixes #8654 reported by hey3e.
+     Fixes CVE-2024-28755.
+   * When negotiating TLS version on server side, do not fall back to the
+     TLS 1.2 implementation of the protocol if it is disabled.
+     - If the TLS 1.2 implementation was disabled at build time, a TLS 1.2
+       client could put the TLS 1.3-only server in an infinite loop processing
+       a TLS 1.2 ClientHello, resulting in a denial of service. Reported by
+       Matthias Mucha and Thomas Blattmann, SICK AG.
+     - If the TLS 1.2 implementation was disabled at runtime, a TLS 1.2 client
+       was able to successfully establish a TLS 1.2 connection with the server.
+       Reported by alluettiv on GitHub.
+    Fixes CVE-2024-28836.
+
+Bugfix
+   * Fix the build with CMake when Everest or P256-m is enabled through
+     a user configuration file or the compiler command line. Fixes #8165.
+   * Fix compilation error in C++ programs when MBEDTLS_ASN1_PARSE_C is
+     disabled.
+   * Fix possible NULL dereference issue in X509 cert_req program if an entry
+     in the san parameter is not separated by a colon.
+   * Fix possible NULL dereference issue in X509 cert_write program if an entry
+     in the san parameter is not separated by a colon.
+   * Fix an inconsistency between implementations and usages of `__cpuid`,
+     which mainly causes failures when building Windows target using
+     mingw or clang. Fixes #8334 & #8332.
+   * Fix build failure in conda-forge.  Fixes #8422.
+   * Fix parsing of CSRs with critical extensions.
+   * Switch to milliseconds as the unit for ticket creation and reception time
+     instead of seconds. That avoids rounding errors when computing the age of
+     tickets compared to peer using a millisecond clock (observed with GnuTLS).
+     Fixes #6623.
+   * Fix TLS server accepting TLS 1.2 handshake while TLS 1.2
+     is disabled at runtime. Fixes #8593.
+   * Remove accidental introduction of RSA signature algorithms
+     in TLS Suite B Profile. Fixes #8221.
+   * Fix unsupported PSA asymmetric encryption and decryption
+     (psa_asymmetric_[en|de]crypt) with opaque keys.
+     Resolves #8461.
+   * On Linux on ARMv8, fix a build error with SHA-256 and SHA-512
+     acceleration detection when the libc headers do not define the
+     corresponding constant. Reported by valord577.
+   * Correct initial capacities for key derivation algorithms:TLS12_PRF,
+     TLS12_PSK_TO_MS, PBKDF2-HMAC, PBKDF2-CMAC
+   * Fix mbedtls_pk_get_bitlen() for RSA keys whose size is not a
+     multiple of 8. Fixes #868.
+   * Avoid segmentation fault caused by releasing not initialized
+     entropy resource in gen_key example. Fixes #8809.
+   * mbedtls_pem_read_buffer() now performs a check on the padding data of
+     decrypted keys and it rejects invalid ones.
+   * Fix mbedtls_pk_sign(), mbedtls_pk_verify(), mbedtls_pk_decrypt() and
+     mbedtls_pk_encrypt() on non-opaque RSA keys to honor the padding mode in
+     the RSA context. Before, if MBEDTLS_USE_PSA_CRYPTO was enabled and the
+     RSA context was configured for PKCS#1 v2.1 (PSS/OAEP), the sign/verify
+     functions performed a PKCS#1 v1.5 signature instead and the
+     encrypt/decrypt functions returned an error. Fixes #8824.
+   * Fix missing bitflags in SSL session serialization headers. Their absence
+     allowed SSL sessions saved in one configuration to be loaded in a
+     different, incompatible configuration.
+   * In TLS 1.3 clients, fix an interoperability problem due to the client
+     generating a new random after a HelloRetryRequest. Fixes #8669.
+   * Fix the restoration of the ALPN when loading serialized connection with
+     the mbedtls_ssl_context_load() API.
+   * Fix NULL pointer dereference in mbedtls_pk_verify_ext() when called using
+     an opaque RSA context and specifying MBEDTLS_PK_RSASSA_PSS as key type.
+   * Fix RSA opaque keys always using PKCS1 v1.5 algorithms instead of the
+     primary algorithm of the wrapped PSA key.
+   * Fully support arbitrary overlap between inputs and outputs of PSA
+     functions. Note that overlap is still only partially supported when
+     MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS is set (#3266).
+
+Changes
+   * Use heap memory to allocate DER encoded public/private key.
+     This reduces stack usage significantly for writing a public/private
+     key to a PEM string.
+   * PSA_WANT_ALG_CCM and PSA_WANT_ALG_CCM_STAR_NO_TAG are no more synonyms and
+     they are now treated separately. This means that they should be
+     individually enabled in order to enable respective support; also the
+     corresponding MBEDTLS_PSA_ACCEL symbol should be defined in case
+     acceleration is required.
+   * Moved declaration of functions mbedtls_ecc_group_to_psa and
+     mbedtls_ecc_group_of_psa from psa/crypto_extra.h to mbedtls/psa_util.h
+   * mbedtls_pk_sign_ext() is now always available, not just when
+     PSA (MBEDTLS_PSA_CRYPTO_C) is enabled.
+   * Extended PSA Crypto configurations options for FFDH by making it possible
+     to select only some of the parameters / groups, with the macros
+     PSA_WANT_DH_RFC7919_XXXX. You now need to defined the corresponding macro
+     for each size you want to support. Also, if you have an FFDH accelerator,
+     you'll need to define the appropriate MBEDTLS_PSA_ACCEL macros to signal
+     support for these domain parameters.
+   * RSA support in PSA no longer auto-enables the pkparse and pkwrite modules,
+     saving code size when those are not otherwise enabled.
+   * mbedtls_mpi_exp_mod and code that uses it, notably RSA and DHM operations,
+     have changed their speed/memory compromise as part of a proactive security
+     improvement. The new default value of MBEDTLS_MPI_WINDOW_SIZE roughly
+     preserves the current speed, at the expense of increasing memory
+     consumption.
+   * Rename directory containing Visual Studio files from visualc/VS2013 to
+     visualc/VS2017.
+   * The TLS 1.3 protocol is now enabled in the default configuration.
+
 = Mbed TLS 3.5.2 branch released 2024-01-26
 
 Security
diff --git a/ChangeLog.d/7764.txt b/ChangeLog.d/7764.txt
deleted file mode 100644
index 4cd2079..0000000
--- a/ChangeLog.d/7764.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Features
-   * Add functions mbedtls_ecc_group_to_psa() and mbedtls_ecc_group_from_psa()
-     to convert between Mbed TLS and PSA curve identifiers.
diff --git a/ChangeLog.d/7765.txt b/ChangeLog.d/7765.txt
deleted file mode 100644
index 3dd6b5d..0000000
--- a/ChangeLog.d/7765.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Features
-   * Add functions mbedtls_ecdsa_raw_to_der() and mbedtls_ecdsa_der_to_raw() to
-     convert ECDSA signatures between raw and DER (ASN.1) formats.
diff --git a/ChangeLog.d/8030.txt b/ChangeLog.d/8030.txt
deleted file mode 100644
index d99c9e7..0000000
--- a/ChangeLog.d/8030.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-Changes
-   * Extended PSA Crypto configurations options for FFDH by making it possible
-     to select only some of the parameters / groups, with the macros
-     PSA_WANT_DH_RFC7919_XXXX. You now need to defined the corresponding macro
-     for each size you want to support. Also, if you have an FFDH accelerator,
-     you'll need to define the appropriate MBEDTLS_PSA_ACCEL macros to signal
-     support for these domain parameters.
diff --git a/ChangeLog.d/8340.txt b/ChangeLog.d/8340.txt
deleted file mode 100644
index 5664bf1..0000000
--- a/ChangeLog.d/8340.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Features
-   * Add functions mbedtls_md_psa_alg_from_type() and
-     mbedtls_md_type_from_psa_alg() to convert between mbedtls_md_type_t and
-     psa_algorithm_t.
diff --git a/ChangeLog.d/8372.txt b/ChangeLog.d/8372.txt
deleted file mode 100644
index 4a72edf..0000000
--- a/ChangeLog.d/8372.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Features
-   *  AES-NI is now supported in Windows builds with clang and clang-cl.
-      Resolves #8372.
diff --git a/ChangeLog.d/8461.txt b/ChangeLog.d/8461.txt
deleted file mode 100644
index d6a65f0..0000000
--- a/ChangeLog.d/8461.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Bugfix
-   * Fix unsupported PSA asymmetric encryption and decryption
-     (psa_asymmetric_[en|de]crypt) with opaque keys.
-     Resolves #8461.
diff --git a/ChangeLog.d/8482.txt b/ChangeLog.d/8482.txt
deleted file mode 100644
index a392232..0000000
--- a/ChangeLog.d/8482.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Changes
-    * PSA_WANT_ALG_CCM and PSA_WANT_ALG_CCM_STAR_NO_TAG are no more synonyms and
-      they are now treated separately. This means that they should be
-      individually enabled in order to enable respective support; also the
-      corresponding MBEDTLS_PSA_ACCEL symbol should be defined in case
-      acceleration is required.
diff --git a/ChangeLog.d/8647.txt b/ChangeLog.d/8647.txt
deleted file mode 100644
index 98326dc..0000000
--- a/ChangeLog.d/8647.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Default behavior changes
-   * psa_import_key() now only accepts RSA keys in the PSA standard formats.
-     The undocumented ability to import other formats (PKCS#8, SubjectPublicKey,
-     PEM) accepted by the pkparse module has been removed. Applications that
-     need these formats can call mbedtls_pk_parse_{public,}key() followed by
-     mbedtls_pk_import_into_psa().
-
-Changes
-   * RSA support in PSA no longer auto-enables the pkparse and pkwrite modules,
-     saving code size when those are not otherwise enabled.
diff --git a/ChangeLog.d/8709.txt b/ChangeLog.d/8709.txt
deleted file mode 100644
index e0bea44..0000000
--- a/ChangeLog.d/8709.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Features
-   * The new functions mbedtls_pk_copy_from_psa() and
-     mbedtls_pk_copy_public_from_psa() provide ways to set up a PK context
-     with the same content as a PSA key.
diff --git a/ChangeLog.d/8726.txt b/ChangeLog.d/8726.txt
deleted file mode 100644
index c1e5a40..0000000
--- a/ChangeLog.d/8726.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Features
-   * Add partial platform support for z/OS.
diff --git a/ChangeLog.d/8799.txt b/ChangeLog.d/8799.txt
deleted file mode 100644
index 50e7c11..0000000
--- a/ChangeLog.d/8799.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * mbedtls_pem_read_buffer() now performs a check on the padding data of
-     decrypted keys and it rejects invalid ones.
diff --git a/ChangeLog.d/8824.txt b/ChangeLog.d/8824.txt
deleted file mode 100644
index 6d6bcb7..0000000
--- a/ChangeLog.d/8824.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-Bugfix
-   * Fix mbedtls_pk_sign(), mbedtls_pk_verify(), mbedtls_pk_decrypt() and
-     mbedtls_pk_encrypt() on non-opaque RSA keys to honor the padding mode in
-     the RSA context. Before, if MBEDTLS_USE_PSA_CRYPTO was enabled and the
-     RSA context was configured for PKCS#1 v2.1 (PSS/OAEP), the sign/verify
-     functions performed a PKCS#1 v1.5 signature instead and the
-     encrypt/decrypt functions returned an error. Fixes #8824.
-
diff --git a/ChangeLog.d/8825.txt b/ChangeLog.d/8825.txt
deleted file mode 100644
index 914bd08..0000000
--- a/ChangeLog.d/8825.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Features
-   * mbedtls_psa_get_random() is always available as soon as
-     MBEDTLS_PSA_CRYPTO_CLIENT is enabled at build time and psa_crypto_init() is
-     called at runtime. This together with MBEDTLS_PSA_RANDOM_STATE can be
-     used as random number generator function (f_rng) and context (p_rng) in
-     legacy functions.
diff --git a/ChangeLog.d/8848.txt b/ChangeLog.d/8848.txt
deleted file mode 100644
index 71bb7e3..0000000
--- a/ChangeLog.d/8848.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Removals
-   * Temporary function mbedtls_pk_wrap_as_opaque() is removed. To mimic the
-     same behavior mbedtls_pk_get_psa_attributes() and
-     mbedtls_pk_import_into_psa() can be used to import a PK key into PSA,
-     while mbedtls_pk_setup_opaque() can be used to wrap a PSA key into a opaque
-     PK context.
diff --git a/ChangeLog.d/8938.txt b/ChangeLog.d/8938.txt
deleted file mode 100644
index 68a1c08..0000000
--- a/ChangeLog.d/8938.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix RSA opaque keys always using PKCS1 v1.5 algorithms instead of the
-     primary algorithm of the wrapped PSA key.
diff --git a/ChangeLog.d/add-aes-cbc-to-pkcs5-pbes2.txt b/ChangeLog.d/add-aes-cbc-to-pkcs5-pbes2.txt
deleted file mode 100644
index 7f0fbc7..0000000
--- a/ChangeLog.d/add-aes-cbc-to-pkcs5-pbes2.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Features
-   * Add support for using AES-CBC 128, 192, and 256 bit schemes
-     with PKCS#5 PBES2. Keys encrypted this way can now be parsed by PK parse.
diff --git a/ChangeLog.d/add-block-cipher-no-decrypt.txt b/ChangeLog.d/add-block-cipher-no-decrypt.txt
deleted file mode 100644
index d05bf86..0000000
--- a/ChangeLog.d/add-block-cipher-no-decrypt.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Features
-   * Enable the new option MBEDTLS_BLOCK_CIPHER_NO_DECRYPT to omit
-     the decryption direction of block ciphers (AES, ARIA, Camellia).
-     This affects both the low-level modules and the high-level APIs
-     (the cipher and PSA interfaces). This option is incompatible with modes
-     that use the decryption direction (ECB in PSA, CBC, XTS, KW) and with DES.
diff --git a/ChangeLog.d/add-psa-example-program-hash.txt b/ChangeLog.d/add-psa-example-program-hash.txt
deleted file mode 100644
index ba4da20..0000000
--- a/ChangeLog.d/add-psa-example-program-hash.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Features
-   * Added an example program showing how to hash with the PSA API.
diff --git a/ChangeLog.d/add-record-size-limit-extension-support.txt b/ChangeLog.d/add-record-size-limit-extension-support.txt
deleted file mode 100644
index 3562b85..0000000
--- a/ChangeLog.d/add-record-size-limit-extension-support.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Features
-   * Add support for record size limit extension as defined by RFC 8449
-     and configured with MBEDTLS_SSL_RECORD_SIZE_LIMIT.
-     Application data sent and received will be fragmented according to
-     Record size limits negotiated during handshake.
diff --git a/ChangeLog.d/add_get_ecp_group_id.txt b/ChangeLog.d/add_get_ecp_group_id.txt
deleted file mode 100644
index 3328062..0000000
--- a/ChangeLog.d/add_get_ecp_group_id.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Features
-   * Add new accessor to expose the private group id member of
-     `mbedtls_ecdh_context` structure.
diff --git a/ChangeLog.d/add_ssl_session_accessors.txt b/ChangeLog.d/add_ssl_session_accessors.txt
deleted file mode 100644
index 516a3bf..0000000
--- a/ChangeLog.d/add_ssl_session_accessors.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Features
-   * Add new accessors to expose the private session-id,
-     session-id length, and ciphersuite-id members of
-     `mbedtls_ssl_session` structure.
-     Add new accessor to expose the ciphersuite-id of
-     `mbedtls_ssl_ciphersuite_t` structure.Design ref: #8529
diff --git a/ChangeLog.d/add_threading_changelog.txt b/ChangeLog.d/add_threading_changelog.txt
deleted file mode 100644
index e9f6cc7..0000000
--- a/ChangeLog.d/add_threading_changelog.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-Features
-   * Add protection for multithreaded access to the PSA keystore and protection
-     for multithreaded access to the the PSA global state, including
-     concurrently calling psa_crypto_init() when MBEDTLS_THREADING_C and
-     MBEDTLS_THREADING_PTHREAD are defined. See
-     docs/architecture/psa-thread-safety/psa-thread-safety.md for more details.
-     Resolves issues #3263 and #7945.
diff --git a/ChangeLog.d/armv8-aesce.txt b/ChangeLog.d/armv8-aesce.txt
deleted file mode 100644
index ec5889c..0000000
--- a/ChangeLog.d/armv8-aesce.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Features
-   * Support use of Armv8-A Cryptographic Extensions for hardware acclerated
-     AES when compiling for Thumb (T32) or 32-bit Arm (A32).
diff --git a/ChangeLog.d/benchmark-ecdh.txt b/ChangeLog.d/benchmark-ecdh.txt
deleted file mode 100644
index ef243b8..0000000
--- a/ChangeLog.d/benchmark-ecdh.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Features
-   * The benchmark program now reports times for both ephemeral and static
-     ECDH in all ECDH configurations.
diff --git a/ChangeLog.d/ctr-perf.txt b/ChangeLog.d/ctr-perf.txt
deleted file mode 100644
index bc04080..0000000
--- a/ChangeLog.d/ctr-perf.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Features
-   * Improve performance of AES-GCM, AES-CTR and CTR-DRBG when
-     hardware accelerated AES is not present (around 13-23% on 64-bit Arm).
diff --git a/ChangeLog.d/domain_parameters.txt b/ChangeLog.d/domain_parameters.txt
deleted file mode 100644
index d860cc4..0000000
--- a/ChangeLog.d/domain_parameters.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-New deprecations
-   * In the PSA API, domain parameters are no longer used for anything.
-     They are deprecated and will be removed in a future version of the
-     library.
-
-Removals
-   * In the PSA API, the experimental way to encode the public exponent of
-     an RSA key as a domain parameter is no longer supported. Use
-     psa_generate_key_ext() instead.
diff --git a/ChangeLog.d/driver-only-cipher.txt b/ChangeLog.d/driver-only-cipher.txt
deleted file mode 100644
index 331b2f9..0000000
--- a/ChangeLog.d/driver-only-cipher.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Features
-   * If a cipher or AEAD mechanism has a PSA driver, you can now build the
-     library without the corresponding built-in implementation. Generally
-     speaking that requires both the key type and algorithm to be accelerated
-     or they'll both be built in. However, for CCM and GCM the built-in
-     implementation is able to take advantage of a driver that only
-     accelerates the key type (that is, the block cipher primitive). See
-     docs/driver-only-builds.md for full details and current limitations.
-   * The CTR_DRBG module will now use AES from a PSA driver if MBEDTLS_AES_C is
-     disabled. This requires PSA_WANT_ALG_ECB_NO_PADDING in addition to
-     MBEDTLS_PSA_CRYPTO_C and PSA_WANT_KEY_TYPE_AES.
diff --git a/ChangeLog.d/drop-msvc-2015-and-armcc-5.txt b/ChangeLog.d/drop-msvc-2015-and-armcc-5.txt
deleted file mode 100644
index 435cc98..0000000
--- a/ChangeLog.d/drop-msvc-2015-and-armcc-5.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Requirement changes
-   * Drop support for Visual Studio 2013 and 2015, and Arm Compiler 5.
-Changes
-   * Rename directory containing Visual Studio files from visualc/VS2013 to
-     visualc/VS2017.
diff --git a/ChangeLog.d/early-data.txt b/ChangeLog.d/early-data.txt
deleted file mode 100644
index 3c3826c..0000000
--- a/ChangeLog.d/early-data.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Features
-   * Mbed TLS now supports the writing and reading of TLS 1.3 early data (see
-     docs/tls13-early-data.md). The support enablement is controlled at build
-     time by the MBEDTLS_SSL_EARLY_DATA configuration option and at runtime by
-     the mbedtls_ssl_conf_early_data() API (by default disabled in both cases).
diff --git a/ChangeLog.d/ecp-keypair-utilities.txt b/ChangeLog.d/ecp-keypair-utilities.txt
deleted file mode 100644
index 6f9714a..0000000
--- a/ChangeLog.d/ecp-keypair-utilities.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Features
-   * Add utility functions to manipulate mbedtls_ecp_keypair objects, filling
-     gaps made by making its fields private: mbedtls_ecp_set_public_key(),
-     mbedtls_ecp_write_public_key(), mbedtls_ecp_keypair_calc_public(),
-     mbedtls_ecp_keypair_get_group_id(). Fixes #5017, #5441, #8367, #8652.
diff --git a/ChangeLog.d/ecp_write_key.txt b/ChangeLog.d/ecp_write_key.txt
deleted file mode 100644
index 73354c8..0000000
--- a/ChangeLog.d/ecp_write_key.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-Features
-   * The new function mbedtls_ecp_write_key_ext() is similar to
-     mbedtls_ecp_write_key(), but can be used without separately calculating
-     the output length.
-
-New deprecations
-   * mbedtls_ecp_write_key() is deprecated in favor of
-     mbedtls_ecp_write_key_ext().
diff --git a/ChangeLog.d/enable-tls13-by-default.txt b/ChangeLog.d/enable-tls13-by-default.txt
deleted file mode 100644
index 636078c..0000000
--- a/ChangeLog.d/enable-tls13-by-default.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Changes
-   * The TLS 1.3 protocol is now enabled in the default configuration.
diff --git a/ChangeLog.d/fix-alpn-negotiating-bug.txt b/ChangeLog.d/fix-alpn-negotiating-bug.txt
deleted file mode 100644
index 3bceb37..0000000
--- a/ChangeLog.d/fix-alpn-negotiating-bug.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix the restoration of the ALPN when loading serialized connection with
-   * the mbedtls_ssl_context_load() API.
diff --git a/ChangeLog.d/fix-cmake-3rdparty-custom-config.txt b/ChangeLog.d/fix-cmake-3rdparty-custom-config.txt
deleted file mode 100644
index ec543aa..0000000
--- a/ChangeLog.d/fix-cmake-3rdparty-custom-config.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix the build with CMake when Everest or P256-m is enabled through
-     a user configuration file or the compiler command line. Fixes #8165.
diff --git a/ChangeLog.d/fix-cpp-compilation-error.txt b/ChangeLog.d/fix-cpp-compilation-error.txt
deleted file mode 100644
index 32d86dc..0000000
--- a/ChangeLog.d/fix-cpp-compilation-error.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix compilation error in C++ programs when MBEDTLS_ASN1_PARSE_C is
-     disabled.
diff --git a/ChangeLog.d/fix-csr-parsing-with-critical-fields-fails.txt b/ChangeLog.d/fix-csr-parsing-with-critical-fields-fails.txt
deleted file mode 100644
index 5b15512..0000000
--- a/ChangeLog.d/fix-csr-parsing-with-critical-fields-fails.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Features
-   * Add new mbedtls_x509_csr_parse_der_with_ext_cb() routine which allows
-     parsing unsupported certificate extensions via user provided callback.
-
-Bugfix
-   * Fix parsing of CSRs with critical extensions.
diff --git a/ChangeLog.d/fix-issue-x509-cert_req.txt b/ChangeLog.d/fix-issue-x509-cert_req.txt
deleted file mode 100644
index 3a5171b..0000000
--- a/ChangeLog.d/fix-issue-x509-cert_req.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix possible NULL dereference issue in X509 cert_req program if an entry
-     in the san parameter is not separated by a colon.
diff --git a/ChangeLog.d/fix-issue-x509-cert_write.txt b/ChangeLog.d/fix-issue-x509-cert_write.txt
deleted file mode 100644
index 43d67c2..0000000
--- a/ChangeLog.d/fix-issue-x509-cert_write.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix possible NULL dereference issue in X509 cert_write program if an entry
-     in the san parameter is not separated by a colon.
diff --git a/ChangeLog.d/fix-linux-builds-in-conda-forge.txt b/ChangeLog.d/fix-linux-builds-in-conda-forge.txt
deleted file mode 100644
index 5cfee85..0000000
--- a/ChangeLog.d/fix-linux-builds-in-conda-forge.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Bugfix
-   * Fix build failure in conda-forge.  Fixes #8422.
diff --git a/ChangeLog.d/fix-mingw32-build.txt b/ChangeLog.d/fix-mingw32-build.txt
deleted file mode 100644
index feef0a2..0000000
--- a/ChangeLog.d/fix-mingw32-build.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Bugfix
-  * Fix an inconsistency between implementations and usages of `__cpuid`,
-    which mainly causes failures when building Windows target using
-    mingw or clang. Fixes #8334 & #8332.
diff --git a/ChangeLog.d/fix-new-rn-on-hrr.txt b/ChangeLog.d/fix-new-rn-on-hrr.txt
deleted file mode 100644
index 1b4f5e6..0000000
--- a/ChangeLog.d/fix-new-rn-on-hrr.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * In TLS 1.3 clients, fix an interoperability problem due to the client
-     generating a new random after a HelloRetryRequest. Fixes #8669.
diff --git a/ChangeLog.d/fix-null-dereference-verify-ext.txt b/ChangeLog.d/fix-null-dereference-verify-ext.txt
deleted file mode 100644
index 4654178..0000000
--- a/ChangeLog.d/fix-null-dereference-verify-ext.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix NULL pointer dereference in mbedtls_pk_verify_ext() when called using
-     an opaque RSA context and specifying MBEDTLS_PK_RSASSA_PSS as key type.
diff --git a/ChangeLog.d/fix-ssl-session-serialization-config.txt b/ChangeLog.d/fix-ssl-session-serialization-config.txt
deleted file mode 100644
index ca1cc81..0000000
--- a/ChangeLog.d/fix-ssl-session-serialization-config.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Bugfix
-   * Fix missing bitflags in SSL session serialization headers. Their absence
-     allowed SSL sessions saved in one configuration to be loaded in a
-     different, incompatible configuration.
diff --git a/ChangeLog.d/fix-tls-SuiteB.txt b/ChangeLog.d/fix-tls-SuiteB.txt
deleted file mode 100644
index 0be753a..0000000
--- a/ChangeLog.d/fix-tls-SuiteB.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Remove accidental introduction of RSA signature algorithms
-     in TLS Suite B Profile. Fixes #8221.
diff --git a/ChangeLog.d/fix-tls13-server-min-version-check.txt b/ChangeLog.d/fix-tls13-server-min-version-check.txt
deleted file mode 100644
index 258ec6d..0000000
--- a/ChangeLog.d/fix-tls13-server-min-version-check.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix TLS server accepting TLS 1.2 handshake while TLS 1.2
-     is disabled at runtime. Fixes #8593.
diff --git a/ChangeLog.d/fix_kdf_incorrect_initial_capacity.txt b/ChangeLog.d/fix_kdf_incorrect_initial_capacity.txt
deleted file mode 100644
index 10e2795..0000000
--- a/ChangeLog.d/fix_kdf_incorrect_initial_capacity.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Correct initial capacities for key derivation algorithms:TLS12_PRF,
-     TLS12_PSK_TO_MS, PBKDF2-HMAC, PBKDF2-CMAC
diff --git a/ChangeLog.d/gcm-large-tables.txt b/ChangeLog.d/gcm-large-tables.txt
deleted file mode 100644
index f9bba5b..0000000
--- a/ChangeLog.d/gcm-large-tables.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Features
-    * Add support for 8-bit GCM tables for Shoup's algorithm to speedup GCM
-      operations when hardware accelerated AES is not present. Improves
-      performance by around 30% on 64-bit Intel; 125% on Armv7-M.
diff --git a/ChangeLog.d/gen-key-segfault.txt b/ChangeLog.d/gen-key-segfault.txt
deleted file mode 100644
index fefc702..0000000
--- a/ChangeLog.d/gen-key-segfault.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Avoid segmentation fault caused by releasing not initialized
-     entropy resource in gen_key example. Fixes #8809.
diff --git a/ChangeLog.d/get_ticket_creation_time.txt b/ChangeLog.d/get_ticket_creation_time.txt
deleted file mode 100644
index 7b5166c..0000000
--- a/ChangeLog.d/get_ticket_creation_time.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Features
-   * Add getter (mbedtls_ssl_session_get_ticket_creation_time()) to access
-     `mbedtls_ssl_session.ticket_creation_time`.
diff --git a/ChangeLog.d/gnutls_anti_replay_fail.txt b/ChangeLog.d/gnutls_anti_replay_fail.txt
deleted file mode 100644
index cb35284..0000000
--- a/ChangeLog.d/gnutls_anti_replay_fail.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Bugfix
-    * Switch to milliseconds as the unit for ticket creation and reception time
-      instead of seconds. That avoids rounding errors when computing the age of
-      tickets compared to peer using a millisecond clock (observed with GnuTLS).
-      Fixes #6623.
diff --git a/ChangeLog.d/iar-gcc-perf.txt b/ChangeLog.d/iar-gcc-perf.txt
deleted file mode 100644
index fb0fbb1..0000000
--- a/ChangeLog.d/iar-gcc-perf.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Features
-   * Improve performance for gcc (versions older than 9.3.0) and IAR.
diff --git a/ChangeLog.d/linux-aarch64-hwcap.txt b/ChangeLog.d/linux-aarch64-hwcap.txt
deleted file mode 100644
index 23af878..0000000
--- a/ChangeLog.d/linux-aarch64-hwcap.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Bugfix
-   * On Linux on ARMv8, fix a build error with SHA-256 and SHA-512
-     acceleration detection when the libc headers do not define the
-     corresponding constant. Reported by valord577.
diff --git a/ChangeLog.d/mbedtls_pk_import_into_psa.txt b/ChangeLog.d/mbedtls_pk_import_into_psa.txt
deleted file mode 100644
index c294f44..0000000
--- a/ChangeLog.d/mbedtls_pk_import_into_psa.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Features
-   * The new functions mbedtls_pk_get_psa_attributes() and
-     mbedtls_pk_import_into_psa() provide a uniform way to create a PSA
-     key from a PK key.
diff --git a/ChangeLog.d/move-mbedtls-ecc-psa-helpers.txt b/ChangeLog.d/move-mbedtls-ecc-psa-helpers.txt
deleted file mode 100644
index 85d970c..0000000
--- a/ChangeLog.d/move-mbedtls-ecc-psa-helpers.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Changes
-    * Moved declaration of functions mbedtls_ecc_group_to_psa and
-      mbedtls_ecc_group_of_psa from psa/crypto_extra.h to mbedtls/psa_util.h
diff --git a/ChangeLog.d/no-cipher.txt b/ChangeLog.d/no-cipher.txt
deleted file mode 100644
index 87f2f6d..0000000
--- a/ChangeLog.d/no-cipher.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Features
-   * Fewer modules depend on MBEDTLS_CIPHER_C, making it possible to save code
-     size by disabling it in more circumstances. In particular, the CCM and
-     GCM modules no longer depend on MBEDTLS_CIPHER_C. Also,
-     MBEDTLS_PSA_CRYPTO can now be enabled without MBEDTLS_CIPHER_C if all
-     unauthenticated (non-AEAD) ciphers are disabled, or if they're all
-     fully provided by drivers. See docs/driver-only-builds.md for full
-     details and current limitations; in particular, NIST_KW and PKCS5/PKCS12
-     decryption still unconditionally depend on MBEDTLS_CIPHER_C.
diff --git a/ChangeLog.d/non-psa-pk-implementation.txt b/ChangeLog.d/non-psa-pk-implementation.txt
deleted file mode 100644
index 535bbf5..0000000
--- a/ChangeLog.d/non-psa-pk-implementation.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Changes
-   * mbedtls_pk_sign_ext() is now always available, not just when
-     PSA (MBEDTLS_PSA_CRYPTO_C) is enabled.
diff --git a/ChangeLog.d/pkg-config-files-addition.txt b/ChangeLog.d/pkg-config-files-addition.txt
deleted file mode 100644
index e459470..0000000
--- a/ChangeLog.d/pkg-config-files-addition.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Features
-   * Add pc files for pkg-config, e.g.:
-     pkg-config --cflags --libs (mbedtls|mbedcrypto|mbedx509)
-
diff --git a/ChangeLog.d/pkwrite-pem-use-heap.txt b/ChangeLog.d/pkwrite-pem-use-heap.txt
deleted file mode 100644
index 11db7b6..0000000
--- a/ChangeLog.d/pkwrite-pem-use-heap.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Changes
-   * Use heap memory to allocate DER encoded public/private key.
-     This reduces stack usage significantly for writing a public/private
-     key to a PEM string.
diff --git a/ChangeLog.d/psa_generate_key_ext.txt b/ChangeLog.d/psa_generate_key_ext.txt
deleted file mode 100644
index 8340f01..0000000
--- a/ChangeLog.d/psa_generate_key_ext.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Features
-   * The new function psa_generate_key_ext() allows generating an RSA
-     key pair with a custom public exponent.
diff --git a/ChangeLog.d/rename-conf-early-data-API.txt b/ChangeLog.d/rename-conf-early-data-API.txt
deleted file mode 100644
index d436811..0000000
--- a/ChangeLog.d/rename-conf-early-data-API.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-API changes
-   * Remove `tls13_` in mbedtls_ssl_tls13_conf_early_data() and
-     mbedtls_ssl_tls13_conf_max_early_data_size() API names. Early data
-     feature may not be TLS 1.3 specific in the future. Fixes #6909.
diff --git a/ChangeLog.d/rsa-bitlen.txt b/ChangeLog.d/rsa-bitlen.txt
deleted file mode 100644
index bcd185f..0000000
--- a/ChangeLog.d/rsa-bitlen.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-Bugfix
-   * Fix mbedtls_pk_get_bitlen() for RSA keys whose size is not a
-     multiple of 8. Fixes #868.
-
-Features
-   * The new function mbedtls_rsa_get_bitlen() returns the length of the modulus
-     in bits, i.e. the key size for an RSA key.
diff --git a/ChangeLog.d/sha256-armce-arm.txt b/ChangeLog.d/sha256-armce-arm.txt
deleted file mode 100644
index 5b18eb3..0000000
--- a/ChangeLog.d/sha256-armce-arm.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-Features
-    * Support Armv8-A Crypto Extension acceleration for SHA-256
-      when compiling for Thumb (T32) or 32-bit Arm (A32).
-New deprecations
-    * Rename the MBEDTLS_SHA256_USE_A64_CRYPTO_xxx config options to
-      MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_xxx. The old names may still
-      be used, but are deprecated.
diff --git a/ChangeLog.d/use_exp_mod_core.txt b/ChangeLog.d/use_exp_mod_core.txt
deleted file mode 100644
index 8f7193a..0000000
--- a/ChangeLog.d/use_exp_mod_core.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Changes
-   * mbedtls_mpi_exp_mod and code that uses it, notably RSA and DHM operations,
-     have changed their speed/memory compromise as part of a proactive security
-     improvement. The new default value of MBEDTLS_MPI_WINDOW_SIZE roughly
-     preserves the current speed, at the expense of increasing memory
-     consumption.
diff --git a/ChangeLog.d/x509-add-ca_istrue.txt b/ChangeLog.d/x509-add-ca_istrue.txt
deleted file mode 100644
index c950dbc..0000000
--- a/ChangeLog.d/x509-add-ca_istrue.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Features
-   * Add new accessor to expose the `MBEDTLS_PRIVATE(ca_istrue)` member of
-     `mbedtls_x509_crt` structure. This requires setting
-     the MBEDTLS_X509_EXT_BASIC_CONSTRAINTS bit in the certificate's
-     ext_types field.
diff --git a/docs/architecture/Makefile b/docs/architecture/Makefile
index 6252ab0..5bee504 100644
--- a/docs/architecture/Makefile
+++ b/docs/architecture/Makefile
@@ -2,20 +2,7 @@
 
 default: all
 
-all_markdown = \
-               alternative-implementations.md \
-               mbed-crypto-storage-specification.md \
-               psa-crypto-implementation-structure.md \
-               psa-migration/psa-limitations.md \
-               psa-migration/strategy.md \
-               psa-migration/tasks-g2.md \
-               psa-migration/testing.md \
-               testing/driver-interface-test-strategy.md \
-               testing/invasive-testing.md \
-               testing/psa-storage-format-testing.md \
-               testing/test-framework.md \
-               tls13-support.md \
-	       # This line is intentionally left blank
+all_markdown = $(wildcard *.md */*.md)
 
 html: $(all_markdown:.md=.html)
 pdf: $(all_markdown:.md=.pdf)
diff --git a/docs/architecture/psa-shared-memory.md b/docs/architecture/psa-shared-memory.md
new file mode 100644
index 0000000..ef3a6b0
--- /dev/null
+++ b/docs/architecture/psa-shared-memory.md
@@ -0,0 +1,685 @@
+PSA API functions and shared memory
+===================================
+
+## Introduction
+
+This document discusses the security architecture of systems where PSA API functions might receive arguments that are in memory that is shared with an untrusted process. On such systems, the untrusted process might access a shared memory buffer while the cryptography library is using it, and thus cause unexpected behavior in the cryptography code.
+
+### Core assumptions
+
+We assume the following scope limitations:
+
+* Only PSA Crypto API functions are in scope (including Mbed TLS extensions to the official API specification). Legacy crypto, X.509, TLS, or any other function which is not called `psa_xxx` is out of scope.
+* We only consider [input buffers](https://arm-software.github.io/psa-api/crypto/1.1/overview/conventions.html#input-buffer-sizes) and [output buffers](https://arm-software.github.io/psa-api/crypto/1.1/overview/conventions.html#output-buffer-sizes). Any other data is assumed to be in non-shared memory.
+
+## System architecture discussion
+
+### Architecture overview
+
+We consider a system that has memory separation between partitions: a partition can't access another partition's memory directly. Partitions are meant to be isolated from each other: a partition may only affect the integrity of another partition via well-defined system interfaces. For example, this can be a Unix/POSIX-like system that isolates processes, or isolation between the secure world and the non-secure world relying on a mechanism such as TrustZone, or isolation between secure-world applications on such a system.
+
+More precisely, we consider such a system where our PSA Crypto implementation is running inside one partition, called the **crypto service**. The crypto service receives remote procedure calls (RPC) from other partitions, validates their arguments (e.g. validation of key identifier ownership), and calls a PSA Crypto API function. This document is concerned with environments where the arguments passed to a PSA Crypto API function may be in shared memory (as opposed to environments where the inputs are always copied into memory that is solely accessible by the crypto service before calling the API function, and likewise with output buffers after the function returns).
+
+When the data is accessible to another partition, there is a risk that this other partition will access it while the crypto implementation is working. Although this could be prevented by suspending the whole system while crypto is working, such a limitation is rarely desirable and most systems don't offer a way to do it. (Even systems that have absolute thread priorities, and where crypto has a higher priority than any untrusted partition, may be vulnerable due to having multiple cores or asynchronous data transfers with peripherals.)
+
+The crypto service must guarantee that it behaves as if the rest of the world was suspended while it is executed. A behavior that is only possible if an untrusted entity accesses a buffer while the crypto service is processing the data is a security violation.
+
+### Risks and vulnerabilities
+
+We consider a security architecture with two or three entities:
+
+* a crypto service, which offers PSA crypto API calls over RPC (remote procedure call) using shared memory for some input or output arguments;
+* a client of the crypto service, which makes a RPC to the crypto service;
+* in some scenarios, a client of the client, which makes a RPC to the crypto client which re-shares the memory with the crypto service.
+
+The behavior of RPC is defined for in terms of values of inputs and outputs. This models an ideal world where the content of input and output buffers is not accessible outside the crypto service while it is processing an RPC. It is a security violation if the crypto service behaves in a way that cannot be achieved by setting the inputs before the RPC call, and reading the outputs after the RPC call is finished.
+
+#### Read-read inconsistency
+
+If an input argument is in shared memory, there is a risk of a **read-read inconsistency**:
+
+1. The crypto code reads part of the input and validates it, or injects it into a calculation.
+2. The client (or client's client) modifies the input.
+3. The crypto code reads the same part again, and performs an action which would be impossible if the input had had the same value all along.
+
+Vulnerability example (parsing): suppose the input contains data with a type-length-value or length-value encoding (for example, importing an RSA key). The crypto code reads the length field and checks that it fits within the buffer. (This could be the length of the overall data, or the length of an embedded field) Later, the crypto code reads the length again and uses it without validation. A malicious client can modify the length field in the shared memory between the two reads and thus cause a buffer overread on the second read.
+
+Vulnerability example (dual processing): consider an RPC to perform authenticated encryption, using a mechanism with an encrypt-and-MAC structure. The authenticated encryption implementation separately calculates the ciphertext and the MAC from the plaintext. A client sets the plaintext input to `"PPPP"`, then starts the RPC call, then changes the input buffer to `"QQQQ"` while the crypto service is working.
+
+* Any of `enc("PPPP")+mac("PPPP")`, `enc("PPQQ")+mac("PPQQ")` or `enc("QQQQ")+mac("QQQQ")` are valid outputs: they are outputs that can be produced by this authenticated encryption RPC.
+* If the authenticated encryption calculates the ciphertext before the client changes the output buffer and calculates the MAC after that change, reading the input buffer again each time, the output will be `enc("PPPP")+mac("QQQQ")`. There is no input that can lead to this output, hence this behavior violates the security guarantees of the crypto service.
+
+#### Write-read inconsistency
+
+If an output argument is in shared memory, there is a risk of a **write-read inconsistency**:
+
+1. The crypto code writes some intermediate data into the output buffer.
+2. The client (or client's client) modifies the intermediate data.
+3. The crypto code reads the intermediate data back and continues the calculation, leading to an outcome that would not be possible if the intermediate data had not been modified.
+
+Vulnerability example: suppose that an RSA signature function works by formatting the data in place in the output buffer, then applying the RSA private-key operation in place. (This is how `mbedtls_rsa_pkcs1_sign` works.) A malicious client may write badly formatted data into the buffer, so that the private-key operation is not a valid signature (e.g. it could be a decryption), violating the RSA key's usage policy.
+
+Vulnerability example with chained calls: we consider the same RSA signature operation as before. In this example, we additionally assume that the data to sign comes from an attestation application which signs some data on behalf of a final client: the key and the data to sign are under the attestation application's control, and the final client must not be able to obtain arbitrary signatures. The final client shares an output buffer for the signature with the attestation application, and the attestation application re-shares this buffer with the crypto service. A malicious final client can modify the intermediate data and thus sign arbitrary data.
+
+#### Write-write disclosure
+
+If an output argument is in shared memory, there is a risk of a **write-write disclosure**:
+
+1. The crypto code writes some intermediate data into the output buffer. This intermediate data must remain confidential.
+2. The client (or client's client) reads the intermediate data.
+3. The crypto code overwrites the intermediate data.
+
+Vulnerability example with chained calls (temporary exposure): an application encrypts some data, and lets its clients store the ciphertext. Clients may not have access to the plaintext. To save memory, when it calls the crypto service, it passes an output buffer that is in the final client's memory. Suppose the encryption mechanism works by copying its input to the output buffer then encrypting in place (for example, to simplify considerations related to overlap, or because the implementation relies on a low-level API that works in place). In this scenario, the plaintext is exposed to the final client while the encryption in progress, which violates the confidentiality of the plaintext.
+
+Vulnerability example with chained calls (backtrack): we consider a provisioning application that provides a data encryption service on behalf of multiple clients, using a single shared key. Clients are not allowed to access each other's data. The provisioning application isolates clients by including the client identity in the associated data. Suppose that an AEAD decryption function processes the ciphertext incrementally by simultaneously writing the plaintext to the output buffer and calculating the tag. (This is how AEAD decryption usually works.) At the end, if the tag is wrong, the decryption function wipes the output buffer. Assume that the output buffer for the plaintext is shared from the client to the provisioning application, which re-shares it with the crypto service. A malicious client can read another client (the victim)'s encrypted data by passing the ciphertext to the provisioning application, which will attempt to decrypt it with associated data identifying the requesting client. Although the operation will fail beacuse the tag is wrong, the malicious client still reads the victim plaintext.
+
+#### Write-read feedback
+
+If a function both has an input argument and an output argument in shared memory, and processes its input incrementally to emit output incrementally, the following sequence of events is possible:
+
+1. The crypto code processes part of the input and writes the corresponding part of the output.
+2. The client reads the early output and uses that to calculate the next part of the input.
+3. The crypto code processes the rest of the input.
+
+There are cryptographic mechanisms for which this breaks security properties. An example is [CBC encryption](https://link.springer.com/content/pdf/10.1007/3-540-45708-9_2.pdf): if the client can choose the content of a plaintext block after seeing the immediately preceding ciphertext block, this gives the client a decryption oracle. This is a security violation if the key policy only allowed the client to encrypt, not to decrypt.
+
+TODO: is this a risk we want to take into account? Although this extends the possible behaviors of the one-shot interface, the client can do the same thing legitimately with the multipart interface.
+
+### Possible countermeasures
+
+In this section, we briefly discuss generic countermeasures.
+
+#### Copying
+
+Copying is a valid countermeasure. It is conceptually simple. However, it is often unattractive because it requires additional memory and time.
+
+Note that although copying is very easy to write into a program, there is a risk that a compiler (especially with whole-program optimization) may optimize the copy away, if it does not understand that copies between shared memory and non-shared memory are semantically meaningful.
+
+Example: the PSA Firmware Framework 1.0 forbids shared memory between partitions. This restriction is lifted in version 1.1 due to concerns over RAM usage.
+
+#### Careful accesses
+
+The following rules guarantee that shared memory cannot result in a security violation other than [write-read feedback](#write-read-feedback):
+
+* Never read the same input twice at the same index.
+* Never read back from an output.
+* Never write to the output twice at the same index.
+    * This rule can usefully be relaxed in many circumstances. It is ok to write data that is independent of the inputs (and not otherwise confidential), then overwrite it. For example, it is ok to zero the output buffer before starting to process the input.
+
+These rules are very difficult to enforce.
+
+Example: these are the rules that a GlobalPlatform TEE Trusted Application (application running on the secure side of TrustZone on Cortex-A) must follow.
+
+## Protection requirements
+
+### Responsibility for protection
+
+A call to a crypto service to perform a crypto operation involves the following components:
+
+1. The remote procedure call framework provided by the operating system.
+2. The code of the crypto service.
+3. The code of the PSA Crypto dispatch layer (also known as the core), which is provided by Mbed TLS.
+4. The driver implementing the cryptographic mechanism, which may be provided by Mbed TLS (built-in driver) or by a third-party driver.
+
+The [PSA Crypto API specification](https://arm-software.github.io/psa-api/crypto/1.1/overview/conventions.html#stability-of-parameters) puts the responsibility for protection on the implementation of the PSA Crypto API, i.e. (3) or (4).
+
+> In an environment with multiple threads or with shared memory, the implementation carefully accesses non-overlapping buffer parameters in order to prevent any security risk resulting from the content of the buffer being modified or observed during the execution of the function. (...)
+
+In Mbed TLS 2.x and 3.x up to and including 3.5.0, there is no defense against buffers in shared memory. The responsibility shifts to (1) or (2), but this is not documented.
+
+In the remainder of this chapter, we will discuss how to implement this high-level requirement where it belongs: inside the implementation of the PSA Crypto API. Note that this allows two possible levels: in the dispatch layer (independently of the implementation of each mechanism) or in the driver (specific to each implementation).
+
+#### Protection in the dispatch layer
+
+The dispatch layer has no control over how the driver layer will access buffers. Therefore the only possible protection at this layer method is to ensure that drivers have no access to shared memory. This means that any buffer located in shared memory must be copied into or out of a buffer in memory owned by the crypto service (heap or stack). This adds inefficiency, mostly in terms of RAM usage.
+
+For buffers with a small static size limit, this is something we often do for convenience, especially with output buffers. However, as of Mbed TLS 3.5.0, it is not done systematically.
+
+It is ok to skip the copy if it is known for sure that a buffer is not in shared memory. However, the location of the buffer is not under the control of Mbed TLS. This means skipping the copy would have to be a compile-time or run-time option which has to be set by the application using Mbed TLS. This is both an additional maintenance cost (more code to analyze, more testing burden), and a residual security risk in case the party who is responsible for setting this option does not set it correctly. As a consequence, Mbed TLS will not offer this configurability unless there is a compelling argument.
+
+#### Protection in the driver layer
+
+Putting the responsibility for protection in the driver layer increases the overall amount of work since there are more driver implementations than dispatch implementations. (This is true even inside Mbed TLS: almost all API functions have multiple underlying implementations, one for each algorithm.) It also increases the risk to the ecosystem since some drivers might not protect correctly. Therefore having drivers be responsible for protection is only a good choice if there is a definite benefit to it, compared to allocating an internal buffer and copying. An expected benefit in some cases is that there are practical protection methods other than copying.
+
+Some cryptographic mechanisms are naturally implemented by processing the input in a single pass, with a low risk of ever reading the same byte twice, and by writing the final output directly into the output buffer. For such mechanism, it is sensible to mandate that drivers respect these rules.
+
+In the next section, we will analyze how susceptible various cryptographic mechanisms are to shared memory vulnerabilities.
+
+### Susceptibility of different mechanisms
+
+#### Operations involving small buffers
+
+For operations involving **small buffers**, the cost of copying is low. For many of those, the risk of not copying is high:
+
+* Any parsing of formatted data has a high risk of [read-read inconsistency](#read-read-inconsistency).
+* An internal review shows that for RSA operations, it is natural for an implementation to have a [write-read inconsistency](#write-read-inconsistency) or a [write-write disclosure](#write-write-disclosure).
+
+Note that in this context, a “small buffer” is one with a size limit that is known at compile time, and small enough that copying the data is not prohibitive. For example, an RSA key fits in a small buffer. A hash input is not a small buffer, even if it happens to be only a few bytes long in one particular call.
+
+The following buffers are considered small buffers:
+
+* Any input or output directly related to asymmetric cryptography (signature, encryption/decryption, key exchange, PAKE), including key import and export.
+    * Note that this does not include inputs or outputs that are not processed by an asymmetric primitives, for example the message input to `psa_sign_message` or `psa_verify_message`.
+* Cooked key derivation output.
+* The output of a hash or MAC operation.
+
+**Design decision: the dispatch layer shall copy all small buffers**.
+
+#### Symmetric cryptography inputs with small output
+
+Message inputs to hash, MAC and key derivation operations are at a low risk of [read-read inconsistency](#read-read-inconsistency) because they are unformatted data, and for all specified algorithms, it is natural to process the input one byte at a time.
+
+**Design decision: require symmetric cryptography drivers to read their input without a risk of read-read inconsistency**.
+
+TODO: what about IV/nonce inputs? They are typically small, but don't necessarily have a static size limit (e.g. GCM recommends a 12-byte nonce, but also allows large nonces).
+
+#### Key derivation outputs
+
+Key derivation typically emits its output as a stream, with no error condition detected after setup other than operational failures (e.g. communication failure with an accelerator) or running out of data to emit (which can easily be checked before emitting any data, since the data size is known in advance).
+
+(Note that this is about raw byte output, not about cooked key derivation, i.e. deriving a structured key, which is considered a [small buffer](#operations-involving-small-buffers).)
+
+**Design decision: require key derivation drivers to emit their output without reading back from the output buffer**.
+
+#### Cipher and AEAD
+
+AEAD decryption is at risk of [write-write disclosure](#write-write-disclosure) when the tag does not match.
+
+AEAD encryption and decryption are at risk of [read-read inconsistency](#read-read-inconsistency) if they process the input multiple times, which is natural in a number of cases:
+
+* when encrypting with an encrypt-and-authenticate or authenticate-then-encrypt structure (one read to calculate the authentication tag and another read to encrypt);
+* when decrypting with an encrypt-then-authenticate structure (one read to decrypt and one read to calculate the authentication tag);
+* with SIV modes (not yet present in the PSA API, but likely to come one day) (one full pass to calculate the IV, then another full pass for the core authenticated encryption);
+
+Cipher and AEAD outputs are at risk of [write-read inconsistency](#write-read-inconsistency) and [write-write disclosure](#write-write-disclosure) if they are implemented by copying the input into the output buffer with `memmove`, then processing the data in place. In particular, this approach makes it easy to fully support overlapping, since `memmove` will take care of overlapping cases correctly, which is otherwise hard to do portably (C99 does not offer an efficient, portable way to check whether two buffers overlap).
+
+**Design decision: the dispatch layer shall allocate an intermediate buffer for cipher and AEAD plaintext/ciphertext inputs and outputs**.
+
+Note that this can be a single buffer for the input and the output if the driver supports in-place operation (which it is supposed to, since it is supposed to support arbitrary overlap, although this is not always the case in Mbed TLS, a [known issue](https://github.com/Mbed-TLS/mbedtls/issues/3266)). A side benefit of doing this intermediate copy is that overlap will be supported.
+
+For all currently implemented AEAD modes, the associated data is only processed once to calculate an intermediate value of the authentication tag.
+
+**Design decision: for now, require AEAD drivers to read the additional data without a risk of read-read inconsistency**. Make a note to revisit this when we start supporting an SIV mode, at which point the dispatch layer shall copy the input for modes that are not known to be low-risk.
+
+#### Message signature
+
+For signature algorithms with a hash-and-sign framework, the input to sign/verify-message is passed to a hash, and thus can follow the same rules as [symmetric cryptography inputs with small output](#symmetric-cryptography-inputs-with-small-output). This is also true for `PSA_ALG_RSA_PKCS1V15_SIGN_RAW`, which is the only non-hash-and-sign signature mechanism implemented in Mbed TLS 3.5. This is not true for PureEdDSA (`#PSA_ALG_PURE_EDDSA`), which is not yet implemented: [PureEdDSA signature](https://www.rfc-editor.org/rfc/rfc8032#section-5.1.6) processes the message twice. (However, PureEdDSA verification only processes the message once.)
+
+**Design decision: for now, require sign/verify-message drivers to read their input without a risk of read-read inconsistency**. Make a note to revisit this when we start supporting PureEdDSA, at which point the dispatch layer shall copy the input for algorithms such as PureEdDSA that are not known to be low-risk.
+
+## Design of shared memory protection
+
+This section explains how Mbed TLS implements the shared memory protection strategy summarized below.
+
+### Shared memory protection strategy
+
+* The core (dispatch layer) shall make a copy of the following buffers, so that drivers do not receive arguments that are in shared memory:
+    * Any input or output from asymmetric cryptography (signature, encryption/decryption, key exchange, PAKE), including key import and export.
+    * Plaintext/ciphertext inputs and outputs for cipher and AEAD.
+    * The output of a hash or MAC operation.
+    * Cooked key derivation output.
+
+* A document shall explain the requirements on drivers for arguments whose access needs to be protected:
+    * Hash and MAC input.
+    * Cipher/AEAD IV/nonce (to be confirmed).
+    * AEAD associated data (to be confirmed).
+    * Key derivation input (excluding key agreement).
+    * Raw key derivation output (excluding cooked key derivation output).
+
+* The built-in implementations of cryptographic mechanisms with arguments whose access needs to be protected shall protect those arguments.
+
+Justification: see “[Susceptibility of different mechanisms](#susceptibility-of-different-mechanisms)”.
+
+### Implementation of copying
+
+Copy what needs copying. This is broadly straightforward, however there are a few things to consider.
+
+#### Compiler optimization of copies
+
+It is unclear whether the compiler will attempt to optimize away copying operations.
+
+Once the copying code is implemented, it should be evaluated to see whether compiler optimization is a problem. Specifically, for the major compilers supported by Mbed TLS:
+* Write a small program that uses a PSA function which copies inputs or outputs.
+* Build the program with link-time optimization / full-program optimization enabled (e.g. `-flto` with `gcc`). Try also enabling the most extreme optimization options such as `-Ofast` (`gcc`) and `-Oz` (`clang`).
+* Inspect the generated code with `objdump` or a similar tool to see if copying operations are preserved.
+
+If copying behaviour is preserved by all major compilers then assume that compiler optimization is not a problem.
+
+If copying behaviour is optimized away by the compiler, further investigation is needed. Experiment with using the `volatile` keyword to force the compiler not to optimize accesses to the copied buffers. If the `volatile` keyword is not sufficient, we may be able to use compiler or target-specific techniques to prevent optimization, for example memory barriers or empty `asm` blocks. These may be implemented and verified for important platforms while retaining a C implementation that is likely to be correct on most platforms as a fallback - the same approach taken by the constant-time module.
+
+**Open questions: Will the compiler optimize away copies? If so, can it be prevented from doing so in a portable way?**
+
+#### Copying code
+
+We may either copy buffers on an ad-hoc basis using `memcpy()` in each PSA function, or use a unified set of functions for copying input and output data. The advantages of the latter are obvious:
+
+* Any test hooks need only be added in one place.
+* Copying code must only be reviewed for correctness in one place, rather than in all functions where it occurs.
+* Copy bypass is simpler as we can just replace these functions with no-ops in a single place.
+* Any complexity needed to prevent the compiler optimizing copies away does not have to be duplicated.
+
+On the other hand, the only advantage of ad-hoc copying is slightly greater flexibility.
+
+**Design decision: Create a unified set of functions for copying input and output data.**
+
+#### Copying in multipart APIs
+
+Multipart APIs may follow one of 2 possible approaches for copying of input:
+
+##### 1. Allocate a buffer and copy input on each call to `update()`
+
+This is simple and mirrors the approach for one-shot APIs nicely. However, allocating memory in the middle of a multi-part operation is likely to be bad for performance. Multipart APIs are designed in part for systems that do not have time to perform an operation at once, so introducing poor performance may be a problem here.
+
+**Open question: Does memory allocation in `update()` cause a performance problem? If so, to what extent?**
+
+##### 2. Allocate a buffer at the start of the operation and subdivide calls to `update()`
+
+In this approach, input and output buffers are allocated at the start of the operation that are large enough to hold the expected average call to `update()`. When `update()` is called with larger buffers than these, the PSA API layer makes multiple calls to the driver, chopping the input into chunks of the temporary buffer size and filling the output from the results until the operation is finished.
+
+This would be more complicated than approach (1) and introduces some extra issues. For example, if one of the intermediate calls to the driver's `update()` returns an error, it is not possible for the driver's state to be rolled back to before the first call to `update()`. It is unclear how this could be solved.
+
+However, this approach would reduce memory usage in some cases and prevent memory allocation during an operation. Additionally, since the input and output buffers would be fixed-size it would be possible to allocate them statically, avoiding the need for any dynamic memory allocation at all.
+
+**Design decision: Initially use approach (1) and treat approach (2) as an optimization to be done if necessary.**
+
+### Validation of copying
+
+#### Validation of copying by review
+
+This is fairly self-explanatory. Review all functions that use shared memory and ensure that they each copy memory. This is the simplest strategy to implement but is less reliable than automated validation.
+
+#### Validation of copying with memory pools
+
+Proposed general idea: have tests where the test code calling API functions allocates memory in a certain pool, and code in the library allocates memory in a different pool. Test drivers check that needs-copying arguments are within the library pool, not within the test pool.
+
+#### Validation of copying by memory poisoning
+
+Proposed general idea: in test code, “poison” the memory area used by input and output parameters that must be copied. Poisoning means something that prevents accessing memory while it is poisoned. This could be via memory protection (allocate with `mmap` then disable access with `mprotect`), or some kind of poisoning for an analyzer such as MSan or Valgrind.
+
+In the library, the code that does the copying temporarily unpoisons the memory by calling a test hook.
+
+```c
+static void copy_to_user(void *copy_buffer, void *const input_buffer, size_t length) {
+#if defined(MBEDTLS_TEST_HOOKS)
+    if (memory_poison_hook != NULL) {
+        memory_poison_hook(copy_buffer, length);
+    }
+#endif
+    memcpy(copy_buffer, input_buffer, length);
+#if defined(MBEDTLS_TEST_HOOKS)
+    if (memory_unpoison_hook != NULL) {
+        memory_unpoison_hook(copy_buffer, length);
+    }
+#endif
+}
+```
+The reason to poison the memory before calling the library, rather than after the copy-in (and symmetrically for output buffers) is so that the test will fail if we forget to copy, or we copy the wrong thing. This would not be the case if we relied on the library's copy function to do the poisoning: that would only validate that the driver code does not access the memory on the condition that the copy is done as expected.
+
+##### Options for implementing poisoning
+
+There are several different ways that poisoning could be implemented:
+
+1. Using Valgrind's memcheck tool. Valgrind provides a macro `VALGRIND_MAKE_MEM_NO_ACCESS` that allows manual memory poisoning. Valgrind memory poisoning is already used for constant-flow testing in Mbed TLS.
+2. Using Memory Sanitizer (MSan), which allows us to mark memory as uninitialized. This is also used for constant-flow testing. It is suitable for input buffers only, since it allows us to detect when a poisoned buffer is read but not when it is written.
+3. Using Address Sanitizer (ASan). This provides `ASAN_POISON_MEMORY_REGION` which marks memory as inaccessible.
+4. Allocating buffers separate pages and calling `mprotect()` to set pages as inaccessible. This has the disadvantage that we will have to manually ensure that buffers sit in their own pages, which likely means making a copy.
+5. Filling buffers with random data, keeping a copy of the original. For input buffers, keep a copy of the original and copy it back once the PSA function returns. For output buffers, fill them with random data and keep a separate copy of it. In the memory poisoning hooks, compare the copy of random data with the original to ensure that the output buffer has not been written directly.
+
+Approach (2) is insufficient for the full testing we require as we need to be able to check both input and output buffers.
+
+Approach (5) is simple and requires no extra tooling. It is likely to have good performance as it does not use any sanitizers. However, it requires the memory poisoning test hooks to maintain extra copies of the buffers, which seems difficult to implement in practice. Additionally, it does not precisely test the property we want to validate, so we are relying on the tests to fail if given random data as input. It is possible (if unlikely) that the PSA function will access the poisoned buffer without causing the test to fail. This becomes more likely when we consider test cases that call PSA functions on incorrect inputs to check that the correct error is returned. For these reasons, this memory poisoning approach seems unsuitable.
+
+All three remaining approaches are suitable for our purposes. However, approach (4) is more complex than the other two. To implement it, we would need to allocate poisoned buffers in separate memory pages. They would require special handling and test code would likely have to be designed around this special handling.
+
+Meanwhile, approaches (1) and (3) are much more convenient. We are simply required to call a special macro on some buffer that was allocated by us and the sanitizer takes care of everything else. Of these two, ASan appears to have a limitation related to buffer alignment. From code comments quoted in [the documentation](https://github.com/google/sanitizers/wiki/AddressSanitizerManualPoisoning):
+
+> This function is not guaranteed to poison the whole region - it may poison only subregion of [addr, addr+size) due to ASan alignment restrictions.
+
+Specifically, ASan will round the buffer size down to 8 bytes before poisoning due to details of its implementation. For more information on this, see [Microsoft documentation of this feature](https://learn.microsoft.com/en-us/cpp/sanitizers/asan-runtime?view=msvc-170#alignment-requirements-for-addresssanitizer-poisoning).
+
+It should be possible to work around this by manually rounding buffer lengths up to the nearest multiple of 8 in the poisoning function, although it's remotely possible that this will cause other problems. Valgrind does not appear to have this limitation (unless Valgrind is simply more poorly documented). However, running tests under Valgrind causes a much greater slowdown compared with ASan. As a result, it would be beneficial to implement support for both Valgrind and ASan, to give the extra flexibility to choose either performance or accuracy as required. This should be simple as both have very similar memory poisoning interfaces.
+
+**Design decision: Implement memory poisoning tests with both Valgrind's memcheck and ASan manual poisoning.**
+
+##### Validation with new tests
+
+Validation with newly created tests would be simpler to implement than using existing tests, since the tests can be written to take into account memory poisoning. It is also possible to build such a testsuite using existing tests as a starting point - `mbedtls_test_psa_exercise_key` is a test helper that already exercises many PSA operations on a key. This would need to be extended to cover operations without keys (e.g. hashes) and multipart operations, but it provides a good base from which to build all of the required testing.
+
+Additionally, we can ensure that all functions are exercised by automatically generating test data files.
+
+##### Validation with existing tests
+
+An alternative approach would be to integrate memory poisoning validation with existing tests. This has two main advantages:
+
+* All of the tests are written already, potentially saving development time.
+* The code coverage of these tests is greater than would be achievable writing new tests from scratch. In practice this advantage is small as buffer copying will take place in the dispatch layer. The tests are therefore independent of the values of parameters passed to the driver, so extra coverage in these parameters does not gain anything.
+
+It may be possible to transparently implement memory poisoning so that existing tests can work without modification. This would be achieved by replacing the implementation of `malloc()` with one that allocates poisoned buffers. However, there are some difficulties with this:
+
+* Not all buffers allocated by tests are used as inputs and outputs to PSA functions being tested.
+* Those buffers that are inputs to a PSA function need to be unpoisoned right up until the function is called, so that they can be filled with input data.
+* Those buffers that are outputs from a PSA function need to be unpoisoned straight after the function returns, so that they can be read to check the output is correct.
+
+These issues may be solved by creating some kind of test wrapper around every PSA function call that poisons the memory. However, it is unclear how straightforward this will be in practice. If this is simple to achieve, the extra coverage and time saved on new tests will be a benefit. If not, writing new tests is the best strategy.
+
+**Design decision: Add memory poisoning transparently to existing tests.**
+
+#### Discussion of copying validation
+
+Of all discussed approaches, validation by memory poisoning appears as the best. This is because it:
+
+* Does not require complex linking against different versions of `malloc()` (as is the case with the memory pool approach).
+* Allows automated testing (unlike the review approach).
+
+**Design decision: Use a memory poisoning approach to validate copying.**
+
+### Shared memory protection requirements
+
+TODO: write document and reference it here.
+
+### Validation of careful access for built-in drivers
+
+For PSA functions whose inputs and outputs are not copied, it is important that we validate that the builtin drivers are correctly accessing their inputs and outputs so as not to cause a security issue. Specifically, we must check that each memory location in a shared buffer is not accessed more than once by a driver function. In this section we examine various possible methods for performing this validation.
+
+Note: We are focusing on read-read inconsistencies for now, as most of the cases where we aren't copying are inputs.
+
+#### Review
+
+As with validation of copying, the simplest method of validation we can implement is careful code review. This is the least desirable method of validation for several reasons:
+
+1. It is tedious for the reviewers.
+2. Reviewers are prone to make mistakes (especially when performing tedious tasks).
+3. It requires engineering time linear in the number of PSA functions to be tested.
+4. It cannot assure the quality of third-party drivers, whereas automated tests can be ported to any driver implementation in principle.
+
+If all other approaches turn out to be prohibitively difficult, code review exists as a fallback option. However, it should be understood that this is far from ideal.
+
+#### Tests using `mprotect()`
+
+Checking that a memory location is not accessed more than once may be achieved by using `mprotect()` on a Linux system to cause a segmentation fault whenever a memory access happens. Tests based on this approach are sketched below.
+
+##### Linux mprotect+ptrace
+
+Idea: call `mmap` to allocate memory for arguments and `mprotect` to deny or reenable access. Use `ptrace` from a parent process to react to SIGSEGV from a denied access. On SIGSEGV happening in the faulting region:
+
+1. Use `ptrace` to execute a `mprotect` system call in the child to enable access. TODO: How? `ptrace` can modify registers and memory in the child, which includes changing parameters of a syscall that's about to be executed, but not directly cause the child process to execute a syscall that it wasn't about to execute.
+2. Use `ptrace` with `PTRACE_SINGLESTEP` to re-execute the failed load/store instrution.
+3. Use `ptrace` to execute a `mprotect` system call in the child to disable access.
+4. Use `PTRACE_CONT` to resume the child execution.
+
+Record the addresses that are accessed. Mark the test as failed if the same address is read twice.
+
+##### Debugger + mprotect
+
+Idea: call `mmap` to allocate memory for arguments and `mprotect` to deny or reenable access. Use a debugger to handle SIGSEGV (Gdb: set signal catchpoint). If the segfault was due to accessing the protected region:
+
+1. Execute `mprotect` to allow access.
+2. Single-step the load/store instruction.
+3. Execute `mprotect` to disable access.
+4. Continue execution.
+
+Record the addresses that are accessed. Mark the test as failed if the same address is read twice. This part might be hard to do in the gdb language, so we may want to just log the addresses and then use a separate program to analyze the logs, or do the gdb tasks from Python.
+
+#### Instrumentation (Valgrind)
+
+An alternative approach is to use a dynamic instrumentation tool (the most obvious being Valgrind) to trace memory accesses and check that each of the important memory addresses is accessed no more than once.
+
+Valgrind has no tool specifically that checks the property that we are looking for. However, it is possible to generate a memory trace with Valgrind using the following:
+
+```
+valgrind --tool=lackey --trace-mem=yes --log-file=logfile ./myprogram
+```
+This will execute `myprogram` and dump a record of every memory access to `logfile`, with its address and data width. If `myprogram` is a test that does the following:
+
+1. Set up input and output buffers for a PSA function call.
+2. Leak the start and end address of each buffer via `print()`.
+3. Write data into the input buffer exactly once.
+4. Call the PSA function.
+5. Read data from the output buffer exactly once.
+
+Then it should be possible to parse the output from the program and from Valgrind and check that each location was accessed exactly twice: once by the program's setup and once by the PSA function.
+
+#### Fixed Virtual Platform testing
+
+It may be possible to measure double accesses by running tests on a Fixed Virtual Platform such as Corstone 310 ecosystem FVP, available [here](https://developer.arm.com/downloads/-/arm-ecosystem-fvps). There exists a pre-packaged example program for the Corstone 310 FVP available as part of the Open IoT SDK [here](https://git.gitlab.arm.com/iot/open-iot-sdk/examples/sdk-examples/-/tree/main/examples/mbedtls/cmsis-rtx/corstone-310) that could provide a starting point for a set of tests.
+
+Running on an FVP allows two approaches to careful-access testing:
+
+* Convenient scripted use of a debugger with [Iris](https://developer.arm.com/documentation/101196/latest/). This allows memory watchpoints to be set, perhaps more flexibly than with GDB.
+* Tracing of all memory accesses with [Tarmac Trace](https://developer.arm.com/documentation/100964/1123/Plug-ins-for-Fast-Models/TarmacTrace). To validate the single-access properties, the [processor memory access trace source](https://developer.arm.com/documentation/100964/1123/Plug-ins-for-Fast-Models/TarmacTrace/Processor-memory-access-trace) can be used to output all memory accesses happening on the FVP. This output can then be easily parsed and processed to ensure that the input and output buffers are accessed only once. The addresses of buffers can either be leaked by the program through printing to the serial port or set to fixed values in the FVP's linker script.
+
+#### Discussion of careful-access validation
+
+The best approach for validating the correctness of memory accesses is an open question that requires further investigation. To answer this question, each of the test strategies discussed above must be prototyped as follows:
+
+1. Take 1-2 days to create a basic prototype of a test that uses the approach.
+2. Document the prototype - write a short guide that can be followed to arrive at the same prototype.
+3. Evaluate the prototype according to its usefulness. The criteria of evaluation should include:
+   * Ease of implementation - Was the prototype simple to implement? Having implemented it, is it simple to extend it to do all of the required testing?
+   * Flexibility - Could the prototype be extended to cover other careful-access testing that may be needed in future?
+   * Performance - Does the test method perform well? Will it cause significant slowdown to CI jobs?
+   * Ease of reproduction - Does the prototype require a particular platform or tool to be set up? How easy would it be for an external user to run the prototype?
+   * Comprehensibility - Accounting for the lower code quality of a prototype, would developers unfamiliar with the tests based on the prototype be able to understand them easily?
+   * Portability - How well can this approach be ported to multiple platforms? This would allow us to ensure that there are no double-accesses due to a bug that only affects a specific target.
+
+Once each prototype is complete, choose the best approach to implement the careful-access testing. Implement tests using this approach for each of the PSA interfaces that require careful-access testing:
+
+* Hash
+* MAC
+* AEAD (additional data only)
+* Key derivation
+* Asymmetric signature (input only)
+
+##### New vs existing tests
+
+Most of the test methods discussed above need extra setup. Some require leaking of buffer bounds, predictable memory access patterns or allocation of special buffers. FVP testing even requires the tests to be run on a non-host target.
+
+With this complexity in mind it does not seem feasible to run careful-access tests using existing testsuites. Instead, new tests should be written that exercise the drivers in the required way. Fortunately, the only interfaces that need testing are hash, MAC, AEAD (testing over AD only), Key derivation and Asymmetric signature, which limits the number of new tests that must be written.
+
+#### Validation of validation for careful-access
+
+In order to ensure that the careful-access validation works, it is necessary to write tests to check that we can correctly detect careful-access violations when they occur. To do this, write a test function that:
+
+* Reads its input multiple times at the same location.
+* Writes to its output multiple times at the same location.
+
+Then, write a careful-access test for this function and ensure that it fails.
+
+## Analysis of argument protection in built-in drivers
+
+TODO: analyze the built-in implementations of mechanisms for which there is a requirement on drivers. By code inspection, how satisfied are we that they meet the requirement?
+
+## Copy bypass
+
+For efficiency, we are likely to want mechanisms to bypass the copy and process buffers directly in builds that are not affected by shared memory considerations.
+
+Expand this section to document any mechanisms that bypass the copy.
+
+Make sure that such mechanisms preserve the guarantees when buffers overlap.
+
+## Detailed design
+
+### Implementation by module
+
+Module | Input protection strategy | Output protection strategy | Notes
+---|---|---|---
+Hash and MAC | Careful access | Careful access | Low risk of multiple-access as the input and output are raw unformatted data.
+Cipher | Copying | Copying |
+AEAD | Copying (careful access for additional data) | Copying |
+Key derivation | Careful access | Careful access |
+Asymmetric signature | Careful access | Copying | Inputs to signatures are passed to a hash. This will no longer hold once PureEdDSA support is implemented.
+Asymmetric encryption | Copying | Copying |
+Key agreement | Copying | Copying |
+PAKE | Copying | Copying |
+Key import / export | Copying | Copying | Keys may be imported and exported in DER format, which is a structured format and therefore susceptible to read-read inconsistencies and potentially write-read inconsistencies.
+
+### Copying functions
+
+As discussed in [Copying code](#copying-code), it is simpler to use a single unified API for copying. Therefore, we create the following functions:
+
+* `psa_crypto_copy_input(const uint8_t *input, size_t input_length, uint8_t *input_copy, size_t input_copy_length)`
+* `psa_crypto_copy_output(const uint8_t *output_copy, size_t output_copy_length, uint8_t *output, size_t output_length)`
+
+These seem to be a repeat of the same function, however it is useful to retain two separate functions for input and output parameters so that we can use different test hooks in each when using memory poisoning for tests.
+
+Given that the majority of functions will be allocating memory on the heap to copy, it is helpful to build convenience functions that allocate the memory as well.
+
+In order to keep track of allocated copies on the heap, we can create new structs:
+
+```c
+typedef struct psa_crypto_local_input_s {
+    uint8_t *buffer;
+    size_t length;
+} psa_crypto_local_input_t;
+
+typedef struct psa_crypto_local_output_s {
+    uint8_t *original;
+    uint8_t *buffer;
+    size_t length;
+} psa_crypto_local_output_t;
+```
+
+These may be used to keep track of input and output copies' state, and ensure that their length is always stored with them. In the case of output copies, we keep a pointer to the original buffer so that it is easy to perform a writeback to the original once we have finished outputting.
+
+With these structs we may create 2 pairs of functions, one pair for input copies:
+
+```c
+psa_status_t psa_crypto_local_input_alloc(const uint8_t *input, size_t input_len,
+                                          psa_crypto_local_input_t *local_input);
+
+void psa_crypto_local_input_free(psa_crypto_local_input_t *local_input);
+```
+
+* `psa_crypto_local_input_alloc()` calls `calloc()` to allocate a new buffer of length `input_len`, copies the contents across from `input`. It then stores `input_len` and the pointer to the copy in the struct `local_input`.
+* `psa_crypto_local_input_free()` calls `free()` on the local input that is referred to by `local_input` and sets the pointer in the struct to `NULL`.
+
+We also create a pair of functions for output copies:
+
+```c
+psa_status_t psa_crypto_local_output_alloc(uint8_t *output, size_t output_len,
+                                           psa_crypto_local_output_t *local_output);
+
+psa_status_t psa_crypto_local_output_free(psa_crypto_local_output_t *local_output);
+```
+
+* `psa_crypto_local_output_alloc()` calls `calloc()` to allocate a new buffer of length `output_len` and stores `output_len` and the pointer to the buffer in the struct `local_output`. It also stores a pointer to `output` in `local_output->original`.
+* `psa_crypto_local_output_free()` copies the contents of the output buffer `local_output->buffer` into the buffer `local_output->original`, calls `free()` on `local_output->buffer` and sets it to `NULL`.
+
+Some PSA functions may not use these convenience functions as they may have local optimizations that reduce memory usage. For example, ciphers may be able to use a single intermediate buffer for both input and output.
+
+In order to abstract the management of the copy state further, to make it simpler to add, we create the following 6 convenience macros:
+
+For inputs:
+
+* `LOCAL_INPUT_DECLARE(input, input_copy_name)`, which declares and initializes a `psa_crypto_local_input_t` and a pointer with the name `input_copy_name` in the current scope.
+* `LOCAL_INPUT_ALLOC(input, input_size, input_copy)`, which tries to allocate an input using `psa_crypto_local_input_alloc()`. On failure, it sets an error code and jumps to an exit label. On success, it sets `input_copy` to point to the copy of the buffer.
+* `LOCAL_INPUT_FREE(input, input_copy)`, which frees the input copy using `psa_crypto_local_input_free()` and sets `input_copy` to `NULL`.
+
+For outputs:
+
+* `LOCAL_OUTPUT_DECLARE(output, output_copy_name)`, analogous to `LOCAL_INPUT_DECLARE()` for `psa_crypto_local_output_t`.
+* `LOCAL_OUTPUT_ALLOC(output, output_size, output_copy)`, analogous to `LOCAL_INPUT_ALLOC()` for outputs, calling `psa_crypto_local_output_alloc()`.
+* `LOCAL_OUTPUT_FREE(output, output_copy)`, analogous to `LOCAL_INPUT_FREE()` for outputs. If the `psa_crypto_local_output_t` is in an invalid state (the copy pointer is valid, but the original pointer is `NULL`) this macro sets an error status.
+
+These macros allow PSA functions to have copying added while keeping the code mostly unmodified. Consider a hypothetical PSA function:
+
+```c
+psa_status_t psa_foo(const uint8_t *input, size_t input_length,
+                     uint8_t *output, size_t output_size, size_t *output_length)
+{
+    /* Do some operation on input and output */
+}
+```
+
+By changing the name of the input and output parameters, we can retain the original variable name as the name of the local copy while using a new name (e.g. with the suffix `_external`) for the original buffer. This allows copying to be added near-seamlessly as follows:
+
+```c
+psa_status_t psa_foo(const uint8_t *input_external, size_t input_length,
+                     uint8_t *output_external, size_t output_size, size_t *output_length)
+{
+    psa_status_t status;
+
+    LOCAL_INPUT_DECLARE(input_external, input);
+    LOCAL_OUTPUT_DECLARE(output_external, output);
+
+    LOCAL_INPUT_ALLOC(input_external, input);
+    LOCAL_OUTPUT_ALLOC(output_external, output);
+
+    /* Do some operation on input and output */
+
+exit:
+    LOCAL_INPUT_FREE(input_external, input);
+    LOCAL_OUTPUT_FREE(output_external, output);
+}
+```
+
+A second advantage of using macros for the copying (other than simple convenience) is that it allows copying to be easily disabled by defining alternate macros that function as no-ops. Since buffer copying is specific to systems where shared memory is passed to PSA functions, it is useful to be able to disable it where it is not needed, to save code size.
+
+To this end, the macros above are defined conditionally on a new config option, `MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS`, which may be set whenever PSA functions are assumed to have exclusive access to their input and output buffers. When `MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS` is set, the macros do not perform copying.
+
+### Implementation of copying validation
+
+As discussed in the [design exploration of copying validation](#validation-of-copying), the best strategy for validation of copies appears to be validation by memory poisoning, implemented using Valgrind and ASan.
+
+To perform memory poisoning, we must implement the functions alluded to in [Validation of copying by memory poisoning](#validation-of-copying-by-memory-poisoning):
+```c
+void mbedtls_test_memory_poison(const unsigned char *ptr, size_t size);
+void mbedtls_test_memory_unpoison(const unsigned char *ptr, size_t size);
+```
+This should poison or unpoison the given buffer, respectively.
+
+* `mbedtls_test_memory_poison()` is equivalent to calling `VALGRIND_MAKE_MEM_NOACCESS(ptr, size)` or `ASAN_POISON_MEMORY_REGION(ptr, size)`.
+* `mbedtls_test_memory_unpoison()` is equivalent to calling `VALGRIND_MAKE_MEM_DEFINED(ptr, size)` or `ASAN_UNPOISON_MEMORY_REGION(ptr, size)`.
+
+The PSA copying function must then have test hooks implemented as outlined in [Validation of copying by memory poisoning](#validation-of-copying-by-memory-poisoning).
+
+As discussed in [the design exploration](#validation-with-existing-tests), the preferred approach for implementing copy-testing is to implement it transparently using existing tests. This is specified in more detail below.
+
+#### Transparent allocation-based memory poisoning
+
+In order to implement transparent memory poisoning we require a wrapper around all PSA function calls that poisons any input and output buffers.
+
+The easiest way to do this is to create wrapper functions that poison the memory and then `#define` PSA function names to be wrapped versions of themselves. For example, to replace `psa_aead_update()`:
+```c
+psa_status_t mem_poison_psa_aead_update(psa_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_memory_poison(input, input_length);
+    mbedtls_test_memory_poison(output, output_size);
+    psa_status_t status = psa_aead_update(operation, input, input_length,
+                                          output, output_size, output_length);
+    mbedtls_test_memory_unpoison(input, input_length);
+    mbedtls_test_memory_unpoison(output, output_size);
+
+    return status;
+}
+
+#define psa_aead_update(...) mem_poison_psa_aead_update(__VA_ARGS__)
+```
+
+There now exists a more generic mechanism for making exactly this kind of transformation - the PSA test wrappers, which exist in the files `tests/include/test/psa_test_wrappers.h` and `tests/src/psa_test_wrappers.c`. These are wrappers around all PSA functions that allow testing code to be inserted at the start and end of a PSA function call.
+
+The test wrappers are generated by a script, although they are not automatically generated as part of the build process. Instead, they are checked into source control and must be manually updated when functions change by running `tests/scripts/generate_psa_wrappers.py`.
+
+Poisoning code is added to these test wrappers where relevant in order to pre-poison and post-unpoison the parameters to the functions.
+
+#### Configuration of poisoning tests
+
+Since the memory poisoning tests will require the use of interfaces specific to the sanitizers used to poison memory, they must only be enabled when we are building with ASan or Valgrind. For now, we can auto-detect ASan at compile-time and set an option: `MBEDTLS_TEST_MEMORY_CAN_POISON`. When this option is enabled, we build with memory-poisoning support. This enables transparent testing with ASan without needing any extra configuration options.
+
+Auto-detection and memory-poisoning with Valgrind is left for future work.
+
+#### Validation of validation for copying
+
+To make sure that we can correctly detect functions that access their input/output buffers rather than the copies, it would be best to write a test function that misbehaves and test it with memory poisoning. Specifically, the function should:
+
+* Read its input buffer and after calling the input-buffer-copying function to create a local copy of its input.
+* Write to its output buffer before and after calling the output-buffer-copying function to copy-back its output.
+
+Then, we could write a test that uses this function with memory poisoning and ensure that it fails. Since we are expecting a failure due to memory-poisoning, we would run this test separately from the rest of the memory-poisoning testing.
+
+This testing is implemented in `programs/test/metatest.c`, which is a program designed to check that test failures happen correctly. It may be run via the script `tests/scripts/run-metatests.sh`.
diff --git a/docs/use-psa-crypto.md b/docs/use-psa-crypto.md
index 92d0985..f2983bd 100644
--- a/docs/use-psa-crypto.md
+++ b/docs/use-psa-crypto.md
@@ -75,13 +75,8 @@
 
 **Benefits:** isolation of long-term secrets, use of PSA Crypto drivers.
 
-**Limitations:** can only wrap a key pair, can only use it for private key
-operations. (That is, signature generation, and for RSA decryption too.)
-Note: for ECDSA, currently this uses randomized ECDSA while Mbed TLS uses
-deterministic ECDSA by default. The following operations are not supported
-with a context set this way, while they would be available with a normal
-context: `mbedtls_pk_check_pair()`, `mbedtls_pk_debug()`, all public key
-operations.
+**Limitations:** please refer to the documentation of `mbedtls_pk_setup_opaque()`
+for a full list of supported operations and limitations.
 
 **Use in X.509 and TLS:** opt-in. The application needs to construct the PK context
 using the new API in order to get the benefits; it can then pass the
diff --git a/doxygen/input/doc_mainpage.h b/doxygen/input/doc_mainpage.h
index 17762d7..3eb5f75 100644
--- a/doxygen/input/doc_mainpage.h
+++ b/doxygen/input/doc_mainpage.h
@@ -10,7 +10,7 @@
  */
 
 /**
- * @mainpage Mbed TLS v3.5.2 API Documentation
+ * @mainpage Mbed TLS v3.6.0 API Documentation
  *
  * This documentation describes the internal structure of Mbed TLS.  It was
  * automatically generated from specially formatted comment blocks in
diff --git a/doxygen/mbedtls.doxyfile b/doxygen/mbedtls.doxyfile
index f2695a1..c4505ac 100644
--- a/doxygen/mbedtls.doxyfile
+++ b/doxygen/mbedtls.doxyfile
@@ -1,4 +1,4 @@
-PROJECT_NAME           = "Mbed TLS v3.5.2"
+PROJECT_NAME           = "Mbed TLS v3.6.0"
 OUTPUT_DIRECTORY       = ../apidoc/
 FULL_PATH_NAMES        = NO
 OPTIMIZE_OUTPUT_FOR_C  = YES
diff --git a/include/mbedtls/build_info.h b/include/mbedtls/build_info.h
index 99a449b..eab167f 100644
--- a/include/mbedtls/build_info.h
+++ b/include/mbedtls/build_info.h
@@ -25,17 +25,17 @@
  * Major, Minor, Patchlevel
  */
 #define MBEDTLS_VERSION_MAJOR  3
-#define MBEDTLS_VERSION_MINOR  5
-#define MBEDTLS_VERSION_PATCH  2
+#define MBEDTLS_VERSION_MINOR  6
+#define MBEDTLS_VERSION_PATCH  0
 
 /**
  * The single version number has the following structure:
  *    MMNNPP00
  *    Major version | Minor version | Patch version
  */
-#define MBEDTLS_VERSION_NUMBER         0x03050200
-#define MBEDTLS_VERSION_STRING         "3.5.2"
-#define MBEDTLS_VERSION_STRING_FULL    "Mbed TLS 3.5.2"
+#define MBEDTLS_VERSION_NUMBER         0x03060000
+#define MBEDTLS_VERSION_STRING         "3.6.0"
+#define MBEDTLS_VERSION_STRING_FULL    "Mbed TLS 3.6.0"
 
 /* Macros for build-time platform detection */
 
diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h
index b9790b9..3592141 100644
--- a/include/mbedtls/mbedtls_config.h
+++ b/include/mbedtls/mbedtls_config.h
@@ -1469,6 +1469,26 @@
 //#define MBEDTLS_PSA_INJECT_ENTROPY
 
 /**
+ * \def MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS
+ *
+ * Assume all buffers passed to PSA functions are owned exclusively by the
+ * PSA function and are not stored in shared memory.
+ *
+ * This option may be enabled if all buffers passed to any PSA function reside
+ * in memory that is accessible only to the PSA function during its execution.
+ *
+ * This option MUST be disabled whenever buffer arguments are in memory shared
+ * with an untrusted party, for example where arguments to PSA calls are passed
+ * across a trust boundary.
+ *
+ * \note Enabling this option reduces memory usage and code size.
+ *
+ * \note Enabling this option causes overlap of input and output buffers
+ *       not to be supported by PSA functions.
+ */
+//#define MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS
+
+/**
  * \def MBEDTLS_RSA_NO_CRT
  *
  * Do not use the Chinese Remainder Theorem
@@ -1724,9 +1744,6 @@
  *
  * Enable support for RFC 8449 record_size_limit extension in SSL (TLS 1.3 only).
  *
- * \warning This extension is currently in development and must NOT be used except
- *          for testing purposes.
- *
  * Requires: MBEDTLS_SSL_PROTO_TLS1_3
  *
  * Uncomment this macro to enable support for the record_size_limit extension
diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h
index fde302f..52f4cc6 100644
--- a/include/mbedtls/pk.h
+++ b/include/mbedtls/pk.h
@@ -359,32 +359,40 @@
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
 /**
- * \brief           Initialize a PK context to wrap a PSA key.
+ * \brief Initialize a PK context to wrap a PSA key.
  *
- * \note            This function replaces mbedtls_pk_setup() for contexts
- *                  that wrap a (possibly opaque) PSA key instead of
- *                  storing and manipulating the key material directly.
+ * This function creates a PK context which wraps a PSA key. The PSA wrapped
+ * key must be an EC or RSA key pair (DH is not suported in the PK module).
  *
- * \param ctx       The context to initialize. It must be empty (type NONE).
- * \param key       The PSA key to wrap, which must hold an ECC or RSA key
- *                  pair (see notes below).
+ * Under the hood PSA functions will be used to perform the required
+ * operations and, based on the key type, used algorithms will be:
+ * * EC:
+ *     * verify, verify_ext, sign, sign_ext: ECDSA.
+ * * RSA:
+ *     * sign, decrypt: use the primary algorithm in the wrapped PSA key;
+ *     * sign_ext: RSA PSS if the pk_type is #MBEDTLS_PK_RSASSA_PSS, otherwise
+ *       it falls back to the sign() case;
+ *     * verify, verify_ext, encrypt: not supported.
  *
- * \note            The wrapped key must remain valid as long as the
- *                  wrapping PK context is in use, that is at least between
- *                  the point this function is called and the point
- *                  mbedtls_pk_free() is called on this context. The wrapped
- *                  key might then be independently used or destroyed.
+ * In order for the above operations to succeed, the policy of the wrapped PSA
+ * key must allow the specified algorithm.
  *
- * \note            This function is currently only available for ECC or RSA
- *                  key pairs (that is, keys containing private key material).
- *                  Support for other key types may be added later.
+ * Opaque PK contexts wrapping an EC keys also support \c mbedtls_pk_check_pair(),
+ * whereas RSA ones do not.
  *
- * \return          \c 0 on success.
- * \return          #MBEDTLS_ERR_PK_BAD_INPUT_DATA on invalid input
- *                  (context already used, invalid key identifier).
- * \return          #MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE if the key is not an
- *                  ECC key pair.
- * \return          #MBEDTLS_ERR_PK_ALLOC_FAILED on allocation failure.
+ * \warning The PSA wrapped key must remain valid as long as the wrapping PK
+ *          context is in use, that is at least between the point this function
+ *          is called and the point mbedtls_pk_free() is called on this context.
+ *
+ * \param ctx The context to initialize. It must be empty (type NONE).
+ * \param key The PSA key to wrap, which must hold an ECC or RSA key pair.
+ *
+ * \return    \c 0 on success.
+ * \return    #MBEDTLS_ERR_PK_BAD_INPUT_DATA on invalid input (context already
+ *            used, invalid key identifier).
+ * \return    #MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE if the key is not an ECC or
+ *            RSA key pair.
+ * \return    #MBEDTLS_ERR_PK_ALLOC_FAILED on allocation failure.
  */
 int mbedtls_pk_setup_opaque(mbedtls_pk_context *ctx,
                             const mbedtls_svc_key_id_t key);
diff --git a/include/psa/crypto_types.h b/include/psa/crypto_types.h
index 31ea686..c21bad8 100644
--- a/include/psa/crypto_types.h
+++ b/include/psa/crypto_types.h
@@ -469,7 +469,7 @@
  *     - \c flags: must be 0.
  *     - \c data: the public exponent, in little-endian order.
  *       This must be an odd integer and must not be 1.
- *       Implementations must support 65535, should support 3 and may
+ *       Implementations must support 65537, should support 3 and may
  *       support other values.
  *       When not using a driver, Mbed TLS supports values up to \c INT_MAX.
  *       If this is empty or if the custom production parameters are omitted
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 835604f..37a9724 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -220,11 +220,13 @@
     set(libs ${libs} ws2_32 bcrypt)
 endif(WIN32)
 
-if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
-    SET(CMAKE_C_ARCHIVE_CREATE   "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
-    SET(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
-    SET(CMAKE_C_ARCHIVE_FINISH   "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
-    SET(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
+if(CMAKE_C_COMPILER_ID MATCHES "AppleClang")
+    set(CMAKE_C_ARCHIVE_CREATE   "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
+    set(CMAKE_C_ARCHIVE_FINISH   "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
+endif()
+if(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang")
+    set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
+    set(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
 endif()
 
 if(HAIKU)
@@ -298,7 +300,7 @@
 if(USE_SHARED_MBEDTLS_LIBRARY)
     set(CMAKE_LIBRARY_PATH ${CMAKE_CURRENT_BINARY_DIR})
     add_library(${mbedcrypto_target} SHARED ${src_crypto})
-    set_target_properties(${mbedcrypto_target} PROPERTIES VERSION 3.5.2 SOVERSION 15)
+    set_target_properties(${mbedcrypto_target} PROPERTIES VERSION 3.6.0 SOVERSION 16)
     target_link_libraries(${mbedcrypto_target} PUBLIC ${libs})
 
     if(TARGET ${everest_target})
@@ -310,11 +312,11 @@
     endif()
 
     add_library(${mbedx509_target} SHARED ${src_x509})
-    set_target_properties(${mbedx509_target} PROPERTIES VERSION 3.5.2 SOVERSION 6)
+    set_target_properties(${mbedx509_target} PROPERTIES VERSION 3.6.0 SOVERSION 7)
     target_link_libraries(${mbedx509_target} PUBLIC ${libs} ${mbedcrypto_target})
 
     add_library(${mbedtls_target} SHARED ${src_tls})
-    set_target_properties(${mbedtls_target} PROPERTIES VERSION 3.5.2 SOVERSION 20)
+    set_target_properties(${mbedtls_target} PROPERTIES VERSION 3.6.0 SOVERSION 21)
     target_link_libraries(${mbedtls_target} PUBLIC ${libs} ${mbedx509_target})
 endif(USE_SHARED_MBEDTLS_LIBRARY)
 
diff --git a/library/Makefile b/library/Makefile
index 52d7944..388fcea 100644
--- a/library/Makefile
+++ b/library/Makefile
@@ -74,9 +74,9 @@
 endif
 endif
 
-SOEXT_TLS?=so.20
-SOEXT_X509?=so.6
-SOEXT_CRYPTO?=so.15
+SOEXT_TLS?=so.21
+SOEXT_X509?=so.7
+SOEXT_CRYPTO?=so.16
 
 # Set AR_DASH= (empty string) to use an ar implementation that does not accept
 # the - prefix for command line options (e.g. llvm-ar)
diff --git a/library/cmac.c b/library/cmac.c
index c4f0b54..eda10d0 100644
--- a/library/cmac.c
+++ b/library/cmac.c
@@ -34,6 +34,7 @@
 #include "mbedtls/platform_util.h"
 #include "mbedtls/error.h"
 #include "mbedtls/platform.h"
+#include "constant_time_internal.h"
 
 #include <string.h>
 
@@ -56,7 +57,7 @@
                               size_t blocksize)
 {
     const unsigned char R_128 = 0x87;
-    unsigned char R_n, mask;
+    unsigned char R_n;
     uint32_t overflow = 0x00;
     int i;
 
@@ -81,21 +82,8 @@
         overflow = new_overflow;
     }
 
-    /* mask = ( input[0] >> 7 ) ? 0xff : 0x00
-     * using bit operations to avoid branches */
-
-    /* MSVC has a warning about unary minus on unsigned, but this is
-     * well-defined and precisely what we want to do here */
-#if defined(_MSC_VER)
-#pragma warning( push )
-#pragma warning( disable : 4146 )
-#endif
-    mask = -(input[0] >> 7);
-#if defined(_MSC_VER)
-#pragma warning( pop )
-#endif
-
-    output[blocksize - 1] ^= R_n & mask;
+    R_n = (unsigned char) mbedtls_ct_uint_if_else_0(mbedtls_ct_bool(input[0] >> 7), R_n);
+    output[blocksize - 1] ^= R_n;
 
     return 0;
 }
diff --git a/library/pk.c b/library/pk.c
index 097777f..c29318d 100644
--- a/library/pk.c
+++ b/library/pk.c
@@ -1327,43 +1327,19 @@
     }
 
     if (mbedtls_pk_get_type(ctx) == MBEDTLS_PK_OPAQUE) {
-        psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
-        psa_algorithm_t psa_alg, sign_alg;
-#if defined(MBEDTLS_PSA_CRYPTO_C)
-        psa_algorithm_t psa_enrollment_alg;
-#endif /* MBEDTLS_PSA_CRYPTO_C */
         psa_status_t status;
 
-        status = psa_get_key_attributes(ctx->priv_id, &key_attr);
-        if (status != PSA_SUCCESS) {
-            return PSA_PK_RSA_TO_MBEDTLS_ERR(status);
-        }
-        psa_alg = psa_get_key_algorithm(&key_attr);
-#if defined(MBEDTLS_PSA_CRYPTO_C)
-        psa_enrollment_alg = psa_get_key_enrollment_algorithm(&key_attr);
-#endif /* MBEDTLS_PSA_CRYPTO_C */
-        psa_reset_key_attributes(&key_attr);
-
-        /* Since we're PK type is MBEDTLS_PK_RSASSA_PSS at least one between
-         * alg and enrollment alg should be of type RSA_PSS. */
-        if (PSA_ALG_IS_RSA_PSS(psa_alg)) {
-            sign_alg = psa_alg;
-        }
-#if defined(MBEDTLS_PSA_CRYPTO_C)
-        else if (PSA_ALG_IS_RSA_PSS(psa_enrollment_alg)) {
-            sign_alg = psa_enrollment_alg;
-        }
-#endif /* MBEDTLS_PSA_CRYPTO_C */
-        else {
-            /* The opaque key has no RSA PSS algorithm associated. */
-            return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
-        }
-        /* Adjust the hashing algorithm. */
-        sign_alg = (sign_alg & ~PSA_ALG_HASH_MASK) | PSA_ALG_GET_HASH(psa_md_alg);
-
-        status = psa_sign_hash(ctx->priv_id, sign_alg,
+        /* PSA_ALG_RSA_PSS() behaves the same as PSA_ALG_RSA_PSS_ANY_SALT() when
+         * performing a signature, but they are encoded differently. Instead of
+         * extracting the proper one from the wrapped key policy, just try both. */
+        status = psa_sign_hash(ctx->priv_id, PSA_ALG_RSA_PSS(psa_md_alg),
                                hash, hash_len,
                                sig, sig_size, sig_len);
+        if (status == PSA_ERROR_NOT_PERMITTED) {
+            status = psa_sign_hash(ctx->priv_id, PSA_ALG_RSA_PSS_ANY_SALT(psa_md_alg),
+                                   hash, hash_len,
+                                   sig, sig_size, sig_len);
+        }
         return PSA_PK_RSA_TO_MBEDTLS_ERR(status);
     }
 
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index a0a002a..969c695 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -169,6 +169,118 @@
     if (psa_get_initialized() == 0)     \
     return PSA_ERROR_BAD_STATE;
 
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+
+/* Declare a local copy of an input buffer and a variable that will be used
+ * to store a pointer to the start of the buffer.
+ *
+ * Note: This macro must be called before any operations which may jump to
+ * the exit label, so that the local input copy object is safe to be freed.
+ *
+ * Assumptions:
+ * - input is the name of a pointer to the buffer to be copied
+ * - The name LOCAL_INPUT_COPY_OF_input is unused in the current scope
+ * - input_copy_name is a name that is unused in the current scope
+ */
+#define LOCAL_INPUT_DECLARE(input, input_copy_name) \
+    psa_crypto_local_input_t LOCAL_INPUT_COPY_OF_##input = PSA_CRYPTO_LOCAL_INPUT_INIT; \
+    const uint8_t *input_copy_name = NULL;
+
+/* Allocate a copy of the buffer input and set the pointer input_copy to
+ * point to the start of the copy.
+ *
+ * Assumptions:
+ * - psa_status_t status exists
+ * - An exit label is declared
+ * - input is the name of a pointer to the buffer to be copied
+ * - LOCAL_INPUT_DECLARE(input, input_copy) has previously been called
+ */
+#define LOCAL_INPUT_ALLOC(input, length, input_copy) \
+    status = psa_crypto_local_input_alloc(input, length, \
+                                          &LOCAL_INPUT_COPY_OF_##input); \
+    if (status != PSA_SUCCESS) { \
+        goto exit; \
+    } \
+    input_copy = LOCAL_INPUT_COPY_OF_##input.buffer;
+
+/* Free the local input copy allocated previously by LOCAL_INPUT_ALLOC()
+ *
+ * Assumptions:
+ * - input_copy is the name of the input copy pointer set by LOCAL_INPUT_ALLOC()
+ * - input is the name of the original buffer that was copied
+ */
+#define LOCAL_INPUT_FREE(input, input_copy) \
+    input_copy = NULL; \
+    psa_crypto_local_input_free(&LOCAL_INPUT_COPY_OF_##input);
+
+/* Declare a local copy of an output buffer and a variable that will be used
+ * to store a pointer to the start of the buffer.
+ *
+ * Note: This macro must be called before any operations which may jump to
+ * the exit label, so that the local output copy object is safe to be freed.
+ *
+ * Assumptions:
+ * - output is the name of a pointer to the buffer to be copied
+ * - The name LOCAL_OUTPUT_COPY_OF_output is unused in the current scope
+ * - output_copy_name is a name that is unused in the current scope
+ */
+#define LOCAL_OUTPUT_DECLARE(output, output_copy_name) \
+    psa_crypto_local_output_t LOCAL_OUTPUT_COPY_OF_##output = PSA_CRYPTO_LOCAL_OUTPUT_INIT; \
+    uint8_t *output_copy_name = NULL;
+
+/* Allocate a copy of the buffer output and set the pointer output_copy to
+ * point to the start of the copy.
+ *
+ * Assumptions:
+ * - psa_status_t status exists
+ * - An exit label is declared
+ * - output is the name of a pointer to the buffer to be copied
+ * - LOCAL_OUTPUT_DECLARE(output, output_copy) has previously been called
+ */
+#define LOCAL_OUTPUT_ALLOC(output, length, output_copy) \
+    status = psa_crypto_local_output_alloc(output, length, \
+                                           &LOCAL_OUTPUT_COPY_OF_##output); \
+    if (status != PSA_SUCCESS) { \
+        goto exit; \
+    } \
+    output_copy = LOCAL_OUTPUT_COPY_OF_##output.buffer;
+
+/* Free the local output copy allocated previously by LOCAL_OUTPUT_ALLOC()
+ * after first copying back its contents to the original buffer.
+ *
+ * Assumptions:
+ * - psa_status_t status exists
+ * - output_copy is the name of the output copy pointer set by LOCAL_OUTPUT_ALLOC()
+ * - output is the name of the original buffer that was copied
+ */
+#define LOCAL_OUTPUT_FREE(output, output_copy) \
+    output_copy = NULL; \
+    do { \
+        psa_status_t local_output_status; \
+        local_output_status = psa_crypto_local_output_free(&LOCAL_OUTPUT_COPY_OF_##output); \
+        if (local_output_status != PSA_SUCCESS) { \
+            /* Since this error case is an internal error, it's more serious than \
+             * any existing error code and so it's fine to overwrite the existing \
+             * status. */ \
+            status = local_output_status; \
+        } \
+    } while (0)
+#else /* !MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS */
+#define LOCAL_INPUT_DECLARE(input, input_copy_name) \
+    const uint8_t *input_copy_name = NULL;
+#define LOCAL_INPUT_ALLOC(input, length, input_copy) \
+    input_copy = input;
+#define LOCAL_INPUT_FREE(input, input_copy) \
+    input_copy = NULL;
+#define LOCAL_OUTPUT_DECLARE(output, output_copy_name) \
+    uint8_t *output_copy_name = NULL;
+#define LOCAL_OUTPUT_ALLOC(output, length, output_copy) \
+    output_copy = output;
+#define LOCAL_OUTPUT_FREE(output, output_copy) \
+    output_copy = NULL;
+#endif /* !MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS */
+
+
 int psa_can_do_hash(psa_algorithm_t hash_alg)
 {
     (void) hash_alg;
@@ -1361,13 +1473,14 @@
 }
 
 psa_status_t psa_export_key(mbedtls_svc_key_id_t key,
-                            uint8_t *data,
+                            uint8_t *data_external,
                             size_t data_size,
                             size_t *data_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot;
+    LOCAL_OUTPUT_DECLARE(data_external, data);
 
     /* Reject a zero-length output buffer now, since this can never be a
      * valid key representation. This way we know that data must be a valid
@@ -1392,12 +1505,18 @@
         return status;
     }
 
+    LOCAL_OUTPUT_ALLOC(data_external, data_size, data);
+
     status = psa_driver_wrapper_export_key(&slot->attr,
                                            slot->key.data, slot->key.bytes,
                                            data, data_size, data_length);
 
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+exit:
+#endif
     unlock_status = psa_unregister_read_under_mutex(slot);
 
+    LOCAL_OUTPUT_FREE(data_external, data);
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
 
@@ -1469,7 +1588,7 @@
 }
 
 psa_status_t psa_export_public_key(mbedtls_svc_key_id_t key,
-                                   uint8_t *data,
+                                   uint8_t *data_external,
                                    size_t data_size,
                                    size_t *data_length)
 {
@@ -1477,6 +1596,8 @@
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot;
 
+    LOCAL_OUTPUT_DECLARE(data_external, data);
+
     /* Reject a zero-length output buffer now, since this can never be a
      * valid key representation. This way we know that data must be a valid
      * pointer and we can do things like memset(data, ..., data_size). */
@@ -1496,6 +1617,8 @@
         return status;
     }
 
+    LOCAL_OUTPUT_ALLOC(data_external, data_size, data);
+
     if (!PSA_KEY_TYPE_IS_ASYMMETRIC(slot->attr.type)) {
         status = PSA_ERROR_INVALID_ARGUMENT;
         goto exit;
@@ -1508,6 +1631,7 @@
 exit:
     unlock_status = psa_unregister_read_under_mutex(slot);
 
+    LOCAL_OUTPUT_FREE(data_external, data);
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
 
@@ -1913,11 +2037,12 @@
 }
 
 psa_status_t psa_import_key(const psa_key_attributes_t *attributes,
-                            const uint8_t *data,
+                            const uint8_t *data_external,
                             size_t data_length,
                             mbedtls_svc_key_id_t *key)
 {
     psa_status_t status;
+    LOCAL_INPUT_DECLARE(data_external, data);
     psa_key_slot_t *slot = NULL;
     psa_se_drv_table_entry_t *driver = NULL;
     size_t bits;
@@ -1937,6 +2062,8 @@
         return PSA_ERROR_NOT_SUPPORTED;
     }
 
+    LOCAL_INPUT_ALLOC(data_external, data_length, data);
+
     status = psa_start_key_creation(PSA_KEY_CREATION_IMPORT, attributes,
                                     &slot, &driver);
     if (status != PSA_SUCCESS) {
@@ -1991,6 +2118,7 @@
 
     status = psa_finish_key_creation(slot, driver, key);
 exit:
+    LOCAL_INPUT_FREE(data_external, data);
     if (status != PSA_SUCCESS) {
         psa_fail_key_creation(slot, driver);
     }
@@ -2192,10 +2320,11 @@
 }
 
 psa_status_t psa_hash_update(psa_hash_operation_t *operation,
-                             const uint8_t *input,
+                             const uint8_t *input_external,
                              size_t input_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    LOCAL_INPUT_DECLARE(input_external, input);
 
     if (operation->id == 0) {
         status = PSA_ERROR_BAD_STATE;
@@ -2208,6 +2337,7 @@
         return PSA_SUCCESS;
     }
 
+    LOCAL_INPUT_ALLOC(input_external, input_length, input);
     status = psa_driver_wrapper_hash_update(operation, input, input_length);
 
 exit:
@@ -2215,32 +2345,57 @@
         psa_hash_abort(operation);
     }
 
+    LOCAL_INPUT_FREE(input_external, input);
     return status;
 }
 
-psa_status_t psa_hash_finish(psa_hash_operation_t *operation,
-                             uint8_t *hash,
-                             size_t hash_size,
-                             size_t *hash_length)
+static psa_status_t psa_hash_finish_internal(psa_hash_operation_t *operation,
+                                             uint8_t *hash,
+                                             size_t hash_size,
+                                             size_t *hash_length)
 {
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
     *hash_length = 0;
     if (operation->id == 0) {
         return PSA_ERROR_BAD_STATE;
     }
 
-    psa_status_t status = psa_driver_wrapper_hash_finish(
+    status = psa_driver_wrapper_hash_finish(
         operation, hash, hash_size, hash_length);
     psa_hash_abort(operation);
+
+    return status;
+}
+
+psa_status_t psa_hash_finish(psa_hash_operation_t *operation,
+                             uint8_t *hash_external,
+                             size_t hash_size,
+                             size_t *hash_length)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    LOCAL_OUTPUT_DECLARE(hash_external, hash);
+
+    LOCAL_OUTPUT_ALLOC(hash_external, hash_size, hash);
+    status = psa_hash_finish_internal(operation, hash, hash_size, hash_length);
+
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+exit:
+#endif
+    LOCAL_OUTPUT_FREE(hash_external, hash);
     return status;
 }
 
 psa_status_t psa_hash_verify(psa_hash_operation_t *operation,
-                             const uint8_t *hash,
+                             const uint8_t *hash_external,
                              size_t hash_length)
 {
     uint8_t actual_hash[PSA_HASH_MAX_SIZE];
     size_t actual_hash_length;
-    psa_status_t status = psa_hash_finish(
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    LOCAL_INPUT_DECLARE(hash_external, hash);
+
+    status = psa_hash_finish_internal(
         operation,
         actual_hash, sizeof(actual_hash),
         &actual_hash_length);
@@ -2254,6 +2409,7 @@
         goto exit;
     }
 
+    LOCAL_INPUT_ALLOC(hash_external, hash_length, hash);
     if (mbedtls_ct_memcmp(hash, actual_hash, actual_hash_length) != 0) {
         status = PSA_ERROR_INVALID_SIGNATURE;
     }
@@ -2263,36 +2419,55 @@
     if (status != PSA_SUCCESS) {
         psa_hash_abort(operation);
     }
-
+    LOCAL_INPUT_FREE(hash_external, hash);
     return status;
 }
 
 psa_status_t psa_hash_compute(psa_algorithm_t alg,
-                              const uint8_t *input, size_t input_length,
-                              uint8_t *hash, size_t hash_size,
+                              const uint8_t *input_external, size_t input_length,
+                              uint8_t *hash_external, size_t hash_size,
                               size_t *hash_length)
 {
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    LOCAL_INPUT_DECLARE(input_external, input);
+    LOCAL_OUTPUT_DECLARE(hash_external, hash);
+
     *hash_length = 0;
     if (!PSA_ALG_IS_HASH(alg)) {
         return PSA_ERROR_INVALID_ARGUMENT;
     }
 
-    return psa_driver_wrapper_hash_compute(alg, input, input_length,
-                                           hash, hash_size, hash_length);
+    LOCAL_INPUT_ALLOC(input_external, input_length, input);
+    LOCAL_OUTPUT_ALLOC(hash_external, hash_size, hash);
+    status = psa_driver_wrapper_hash_compute(alg, input, input_length,
+                                             hash, hash_size, hash_length);
+
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+exit:
+#endif
+    LOCAL_INPUT_FREE(input_external, input);
+    LOCAL_OUTPUT_FREE(hash_external, hash);
+    return status;
 }
 
 psa_status_t psa_hash_compare(psa_algorithm_t alg,
-                              const uint8_t *input, size_t input_length,
-                              const uint8_t *hash, size_t hash_length)
+                              const uint8_t *input_external, size_t input_length,
+                              const uint8_t *hash_external, size_t hash_length)
 {
     uint8_t actual_hash[PSA_HASH_MAX_SIZE];
     size_t actual_hash_length;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    LOCAL_INPUT_DECLARE(input_external, input);
+    LOCAL_INPUT_DECLARE(hash_external, hash);
 
     if (!PSA_ALG_IS_HASH(alg)) {
-        return PSA_ERROR_INVALID_ARGUMENT;
+        status = PSA_ERROR_INVALID_ARGUMENT;
+        return status;
     }
 
-    psa_status_t status = psa_driver_wrapper_hash_compute(
+    LOCAL_INPUT_ALLOC(input_external, input_length, input);
+    status = psa_driver_wrapper_hash_compute(
         alg, input, input_length,
         actual_hash, sizeof(actual_hash),
         &actual_hash_length);
@@ -2303,12 +2478,18 @@
         status = PSA_ERROR_INVALID_SIGNATURE;
         goto exit;
     }
+
+    LOCAL_INPUT_ALLOC(hash_external, hash_length, hash);
     if (mbedtls_ct_memcmp(hash, actual_hash, actual_hash_length) != 0) {
         status = PSA_ERROR_INVALID_SIGNATURE;
     }
 
 exit:
     mbedtls_platform_zeroize(actual_hash, sizeof(actual_hash));
+
+    LOCAL_INPUT_FREE(input_external, input);
+    LOCAL_INPUT_FREE(hash_external, hash);
+
     return status;
 }
 
@@ -2473,35 +2654,48 @@
 }
 
 psa_status_t psa_mac_update(psa_mac_operation_t *operation,
-                            const uint8_t *input,
+                            const uint8_t *input_external,
                             size_t input_length)
 {
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    LOCAL_INPUT_DECLARE(input_external, input);
+
     if (operation->id == 0) {
-        return PSA_ERROR_BAD_STATE;
+        status = PSA_ERROR_BAD_STATE;
+        return status;
     }
 
     /* Don't require hash implementations to behave correctly on a
      * zero-length input, which may have an invalid pointer. */
     if (input_length == 0) {
-        return PSA_SUCCESS;
+        status = PSA_SUCCESS;
+        return status;
     }
 
-    psa_status_t status = psa_driver_wrapper_mac_update(operation,
-                                                        input, input_length);
+    LOCAL_INPUT_ALLOC(input_external, input_length, input);
+    status = psa_driver_wrapper_mac_update(operation, input, input_length);
+
     if (status != PSA_SUCCESS) {
         psa_mac_abort(operation);
     }
 
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+exit:
+#endif
+    LOCAL_INPUT_FREE(input_external, input);
+
     return status;
 }
 
 psa_status_t psa_mac_sign_finish(psa_mac_operation_t *operation,
-                                 uint8_t *mac,
+                                 uint8_t *mac_external,
                                  size_t mac_size,
                                  size_t *mac_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_status_t abort_status = PSA_ERROR_CORRUPTION_DETECTED;
+    LOCAL_OUTPUT_DECLARE(mac_external, mac);
+    LOCAL_OUTPUT_ALLOC(mac_external, mac_size, mac);
 
     if (operation->id == 0) {
         status = PSA_ERROR_BAD_STATE;
@@ -2525,6 +2719,7 @@
         goto exit;
     }
 
+
     status = psa_driver_wrapper_mac_sign_finish(operation,
                                                 mac, operation->mac_size,
                                                 mac_length);
@@ -2541,19 +2736,23 @@
         operation->mac_size = 0;
     }
 
-    psa_wipe_tag_output_buffer(mac, status, mac_size, *mac_length);
+    if (mac != NULL) {
+        psa_wipe_tag_output_buffer(mac, status, mac_size, *mac_length);
+    }
 
     abort_status = psa_mac_abort(operation);
+    LOCAL_OUTPUT_FREE(mac_external, mac);
 
     return status == PSA_SUCCESS ? abort_status : status;
 }
 
 psa_status_t psa_mac_verify_finish(psa_mac_operation_t *operation,
-                                   const uint8_t *mac,
+                                   const uint8_t *mac_external,
                                    size_t mac_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_status_t abort_status = PSA_ERROR_CORRUPTION_DETECTED;
+    LOCAL_INPUT_DECLARE(mac_external, mac);
 
     if (operation->id == 0) {
         status = PSA_ERROR_BAD_STATE;
@@ -2570,11 +2769,13 @@
         goto exit;
     }
 
+    LOCAL_INPUT_ALLOC(mac_external, mac_length, mac);
     status = psa_driver_wrapper_mac_verify_finish(operation,
                                                   mac, mac_length);
 
 exit:
     abort_status = psa_mac_abort(operation);
+    LOCAL_INPUT_FREE(mac_external, mac);
 
     return status == PSA_SUCCESS ? abort_status : status;
 }
@@ -2641,28 +2842,45 @@
 
 psa_status_t psa_mac_compute(mbedtls_svc_key_id_t key,
                              psa_algorithm_t alg,
-                             const uint8_t *input,
+                             const uint8_t *input_external,
                              size_t input_length,
-                             uint8_t *mac,
+                             uint8_t *mac_external,
                              size_t mac_size,
                              size_t *mac_length)
 {
-    return psa_mac_compute_internal(key, alg,
-                                    input, input_length,
-                                    mac, mac_size, mac_length, 1);
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    LOCAL_INPUT_DECLARE(input_external, input);
+    LOCAL_OUTPUT_DECLARE(mac_external, mac);
+
+    LOCAL_INPUT_ALLOC(input_external, input_length, input);
+    LOCAL_OUTPUT_ALLOC(mac_external, mac_size, mac);
+    status = psa_mac_compute_internal(key, alg,
+                                      input, input_length,
+                                      mac, mac_size, mac_length, 1);
+
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+exit:
+#endif
+    LOCAL_INPUT_FREE(input_external, input);
+    LOCAL_OUTPUT_FREE(mac_external, mac);
+
+    return status;
 }
 
 psa_status_t psa_mac_verify(mbedtls_svc_key_id_t key,
                             psa_algorithm_t alg,
-                            const uint8_t *input,
+                            const uint8_t *input_external,
                             size_t input_length,
-                            const uint8_t *mac,
+                            const uint8_t *mac_external,
                             size_t mac_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     uint8_t actual_mac[PSA_MAC_MAX_SIZE];
     size_t actual_mac_length;
+    LOCAL_INPUT_DECLARE(input_external, input);
+    LOCAL_INPUT_DECLARE(mac_external, mac);
 
+    LOCAL_INPUT_ALLOC(input_external, input_length, input);
     status = psa_mac_compute_internal(key, alg,
                                       input, input_length,
                                       actual_mac, sizeof(actual_mac),
@@ -2675,6 +2893,8 @@
         status = PSA_ERROR_INVALID_SIGNATURE;
         goto exit;
     }
+
+    LOCAL_INPUT_ALLOC(mac_external, mac_length, mac);
     if (mbedtls_ct_memcmp(mac, actual_mac, actual_mac_length) != 0) {
         status = PSA_ERROR_INVALID_SIGNATURE;
         goto exit;
@@ -2682,6 +2902,8 @@
 
 exit:
     mbedtls_platform_zeroize(actual_mac, sizeof(actual_mac));
+    LOCAL_INPUT_FREE(input_external, input);
+    LOCAL_INPUT_FREE(mac_external, mac);
 
     return status;
 }
@@ -2860,15 +3082,27 @@
 
 psa_status_t psa_sign_message(mbedtls_svc_key_id_t key,
                               psa_algorithm_t alg,
-                              const uint8_t *input,
+                              const uint8_t *input_external,
                               size_t input_length,
-                              uint8_t *signature,
+                              uint8_t *signature_external,
                               size_t signature_size,
                               size_t *signature_length)
 {
-    return psa_sign_internal(
-        key, 1, alg, input, input_length,
-        signature, signature_size, signature_length);
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    LOCAL_INPUT_DECLARE(input_external, input);
+    LOCAL_OUTPUT_DECLARE(signature_external, signature);
+
+    LOCAL_INPUT_ALLOC(input_external, input_length, input);
+    LOCAL_OUTPUT_ALLOC(signature_external, signature_size, signature);
+    status = psa_sign_internal(key, 1, alg, input, input_length, signature,
+                               signature_size, signature_length);
+
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+exit:
+#endif
+    LOCAL_INPUT_FREE(input_external, input);
+    LOCAL_OUTPUT_FREE(signature_external, signature);
+    return status;
 }
 
 psa_status_t psa_verify_message_builtin(
@@ -2907,14 +3141,27 @@
 
 psa_status_t psa_verify_message(mbedtls_svc_key_id_t key,
                                 psa_algorithm_t alg,
-                                const uint8_t *input,
+                                const uint8_t *input_external,
                                 size_t input_length,
-                                const uint8_t *signature,
+                                const uint8_t *signature_external,
                                 size_t signature_length)
 {
-    return psa_verify_internal(
-        key, 1, alg, input, input_length,
-        signature, signature_length);
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    LOCAL_INPUT_DECLARE(input_external, input);
+    LOCAL_INPUT_DECLARE(signature_external, signature);
+
+    LOCAL_INPUT_ALLOC(input_external, input_length, input);
+    LOCAL_INPUT_ALLOC(signature_external, signature_length, signature);
+    status = psa_verify_internal(key, 1, alg, input, input_length, signature,
+                                 signature_length);
+
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+exit:
+#endif
+    LOCAL_INPUT_FREE(input_external, input);
+    LOCAL_INPUT_FREE(signature_external, signature);
+
+    return status;
 }
 
 psa_status_t psa_sign_hash_builtin(
@@ -2967,15 +3214,28 @@
 
 psa_status_t psa_sign_hash(mbedtls_svc_key_id_t key,
                            psa_algorithm_t alg,
-                           const uint8_t *hash,
+                           const uint8_t *hash_external,
                            size_t hash_length,
-                           uint8_t *signature,
+                           uint8_t *signature_external,
                            size_t signature_size,
                            size_t *signature_length)
 {
-    return psa_sign_internal(
-        key, 0, alg, hash, hash_length,
-        signature, signature_size, signature_length);
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    LOCAL_INPUT_DECLARE(hash_external, hash);
+    LOCAL_OUTPUT_DECLARE(signature_external, signature);
+
+    LOCAL_INPUT_ALLOC(hash_external, hash_length, hash);
+    LOCAL_OUTPUT_ALLOC(signature_external, signature_size, signature);
+    status = psa_sign_internal(key, 0, alg, hash, hash_length, signature,
+                               signature_size, signature_length);
+
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+exit:
+#endif
+    LOCAL_INPUT_FREE(hash_external, hash);
+    LOCAL_OUTPUT_FREE(signature_external, signature);
+
+    return status;
 }
 
 psa_status_t psa_verify_hash_builtin(
@@ -3027,23 +3287,36 @@
 
 psa_status_t psa_verify_hash(mbedtls_svc_key_id_t key,
                              psa_algorithm_t alg,
-                             const uint8_t *hash,
+                             const uint8_t *hash_external,
                              size_t hash_length,
-                             const uint8_t *signature,
+                             const uint8_t *signature_external,
                              size_t signature_length)
 {
-    return psa_verify_internal(
-        key, 0, alg, hash, hash_length,
-        signature, signature_length);
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    LOCAL_INPUT_DECLARE(hash_external, hash);
+    LOCAL_INPUT_DECLARE(signature_external, signature);
+
+    LOCAL_INPUT_ALLOC(hash_external, hash_length, hash);
+    LOCAL_INPUT_ALLOC(signature_external, signature_length, signature);
+    status = psa_verify_internal(key, 0, alg, hash, hash_length, signature,
+                                 signature_length);
+
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+exit:
+#endif
+    LOCAL_INPUT_FREE(hash_external, hash);
+    LOCAL_INPUT_FREE(signature_external, signature);
+
+    return status;
 }
 
 psa_status_t psa_asymmetric_encrypt(mbedtls_svc_key_id_t key,
                                     psa_algorithm_t alg,
-                                    const uint8_t *input,
+                                    const uint8_t *input_external,
                                     size_t input_length,
-                                    const uint8_t *salt,
+                                    const uint8_t *salt_external,
                                     size_t salt_length,
-                                    uint8_t *output,
+                                    uint8_t *output_external,
                                     size_t output_size,
                                     size_t *output_length)
 {
@@ -3051,6 +3324,10 @@
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot;
 
+    LOCAL_INPUT_DECLARE(input_external, input);
+    LOCAL_INPUT_DECLARE(salt_external, salt);
+    LOCAL_OUTPUT_DECLARE(output_external, output);
+
     (void) input;
     (void) input_length;
     (void) salt;
@@ -3074,6 +3351,10 @@
         goto exit;
     }
 
+    LOCAL_INPUT_ALLOC(input_external, input_length, input);
+    LOCAL_INPUT_ALLOC(salt_external, salt_length, salt);
+    LOCAL_OUTPUT_ALLOC(output_external, output_size, output);
+
     status = psa_driver_wrapper_asymmetric_encrypt(
         &slot->attr, slot->key.data, slot->key.bytes,
         alg, input, input_length, salt, salt_length,
@@ -3081,16 +3362,20 @@
 exit:
     unlock_status = psa_unregister_read_under_mutex(slot);
 
+    LOCAL_INPUT_FREE(input_external, input);
+    LOCAL_INPUT_FREE(salt_external, salt);
+    LOCAL_OUTPUT_FREE(output_external, output);
+
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
 
 psa_status_t psa_asymmetric_decrypt(mbedtls_svc_key_id_t key,
                                     psa_algorithm_t alg,
-                                    const uint8_t *input,
+                                    const uint8_t *input_external,
                                     size_t input_length,
-                                    const uint8_t *salt,
+                                    const uint8_t *salt_external,
                                     size_t salt_length,
-                                    uint8_t *output,
+                                    uint8_t *output_external,
                                     size_t output_size,
                                     size_t *output_length)
 {
@@ -3098,6 +3383,10 @@
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot;
 
+    LOCAL_INPUT_DECLARE(input_external, input);
+    LOCAL_INPUT_DECLARE(salt_external, salt);
+    LOCAL_OUTPUT_DECLARE(output_external, output);
+
     (void) input;
     (void) input_length;
     (void) salt;
@@ -3120,6 +3409,10 @@
         goto exit;
     }
 
+    LOCAL_INPUT_ALLOC(input_external, input_length, input);
+    LOCAL_INPUT_ALLOC(salt_external, salt_length, salt);
+    LOCAL_OUTPUT_ALLOC(output_external, output_size, output);
+
     status = psa_driver_wrapper_asymmetric_decrypt(
         &slot->attr, slot->key.data, slot->key.bytes,
         alg, input, input_length, salt, salt_length,
@@ -3128,6 +3421,10 @@
 exit:
     unlock_status = psa_unregister_read_under_mutex(slot);
 
+    LOCAL_INPUT_FREE(input_external, input);
+    LOCAL_INPUT_FREE(salt_external, salt);
+    LOCAL_OUTPUT_FREE(output_external, output);
+
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
 
@@ -3185,12 +3482,14 @@
 psa_status_t psa_sign_hash_start(
     psa_sign_hash_interruptible_operation_t *operation,
     mbedtls_svc_key_id_t key, psa_algorithm_t alg,
-    const uint8_t *hash, size_t hash_length)
+    const uint8_t *hash_external, size_t hash_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot;
 
+    LOCAL_INPUT_DECLARE(hash_external, hash);
+
     /* Check that start has not been previously called, or operation has not
      * previously errored. */
     if (operation->id != 0 || operation->error_occurred) {
@@ -3216,6 +3515,8 @@
         goto exit;
     }
 
+    LOCAL_INPUT_ALLOC(hash_external, hash_length, hash);
+
     /* Ensure ops count gets reset, in case of operation re-use. */
     operation->num_ops = 0;
 
@@ -3236,17 +3537,21 @@
         operation->error_occurred = 1;
     }
 
+    LOCAL_INPUT_FREE(hash_external, hash);
+
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
 
 
 psa_status_t psa_sign_hash_complete(
     psa_sign_hash_interruptible_operation_t *operation,
-    uint8_t *signature, size_t signature_size,
+    uint8_t *signature_external, size_t signature_size,
     size_t *signature_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
 
+    LOCAL_OUTPUT_DECLARE(signature_external, signature);
+
     *signature_length = 0;
 
     /* Check that start has been called first, and that operation has not
@@ -3263,6 +3568,8 @@
         goto exit;
     }
 
+    LOCAL_OUTPUT_ALLOC(signature_external, signature_size, signature);
+
     status = psa_driver_wrapper_sign_hash_complete(operation, signature,
                                                    signature_size,
                                                    signature_length);
@@ -3272,8 +3579,10 @@
 
 exit:
 
-    psa_wipe_tag_output_buffer(signature, status, signature_size,
-                               *signature_length);
+    if (signature != NULL) {
+        psa_wipe_tag_output_buffer(signature, status, signature_size,
+                                   *signature_length);
+    }
 
     if (status != PSA_OPERATION_INCOMPLETE) {
         if (status != PSA_SUCCESS) {
@@ -3283,6 +3592,8 @@
         psa_sign_hash_abort_internal(operation);
     }
 
+    LOCAL_OUTPUT_FREE(signature_external, signature);
+
     return status;
 }
 
@@ -3329,13 +3640,16 @@
 psa_status_t psa_verify_hash_start(
     psa_verify_hash_interruptible_operation_t *operation,
     mbedtls_svc_key_id_t key, psa_algorithm_t alg,
-    const uint8_t *hash, size_t hash_length,
-    const uint8_t *signature, size_t signature_length)
+    const uint8_t *hash_external, size_t hash_length,
+    const uint8_t *signature_external, size_t signature_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot;
 
+    LOCAL_INPUT_DECLARE(hash_external, hash);
+    LOCAL_INPUT_DECLARE(signature_external, signature);
+
     /* Check that start has not been previously called, or operation has not
      * previously errored. */
     if (operation->id != 0 || operation->error_occurred) {
@@ -3357,6 +3671,9 @@
         return status;
     }
 
+    LOCAL_INPUT_ALLOC(hash_external, hash_length, hash);
+    LOCAL_INPUT_ALLOC(signature_external, signature_length, signature);
+
     /* Ensure ops count gets reset, in case of operation re-use. */
     operation->num_ops = 0;
 
@@ -3365,6 +3682,9 @@
                                                   slot->key.bytes,
                                                   alg, hash, hash_length,
                                                   signature, signature_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+exit:
+#endif
 
     if (status != PSA_SUCCESS) {
         operation->error_occurred = 1;
@@ -3377,6 +3697,9 @@
         operation->error_occurred = 1;
     }
 
+    LOCAL_INPUT_FREE(hash_external, hash);
+    LOCAL_INPUT_FREE(signature_external, signature);
+
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
 
@@ -3874,6 +4197,52 @@
         * defined( MBEDTLS_ECP_RESTARTABLE ) */
 }
 
+static psa_status_t psa_generate_random_internal(uint8_t *output,
+                                                 size_t output_size)
+{
+    GUARD_MODULE_INITIALIZED;
+
+#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+
+    psa_status_t status;
+    size_t output_length = 0;
+    status = mbedtls_psa_external_get_random(&global_data.rng,
+                                             output, output_size,
+                                             &output_length);
+    if (status != PSA_SUCCESS) {
+        return status;
+    }
+    /* Breaking up a request into smaller chunks is currently not supported
+     * for the external RNG interface. */
+    if (output_length != output_size) {
+        return PSA_ERROR_INSUFFICIENT_ENTROPY;
+    }
+    return PSA_SUCCESS;
+
+#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+
+    while (output_size > 0) {
+        int ret = MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED;
+        size_t request_size =
+            (output_size > MBEDTLS_PSA_RANDOM_MAX_REQUEST ?
+             MBEDTLS_PSA_RANDOM_MAX_REQUEST :
+             output_size);
+#if defined(MBEDTLS_CTR_DRBG_C)
+        ret = mbedtls_ctr_drbg_random(&global_data.rng.drbg, output, request_size);
+#elif defined(MBEDTLS_HMAC_DRBG_C)
+        ret = mbedtls_hmac_drbg_random(&global_data.rng.drbg, output, request_size);
+#endif /* !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C */
+        if (ret != 0) {
+            return mbedtls_to_psa_error(ret);
+        }
+        output_size -= request_size;
+        output += request_size;
+    }
+    return PSA_SUCCESS;
+#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+}
+
+
 /****************************************************************/
 /* Symmetric cryptography */
 /****************************************************************/
@@ -3958,14 +4327,15 @@
 }
 
 psa_status_t psa_cipher_generate_iv(psa_cipher_operation_t *operation,
-                                    uint8_t *iv,
+                                    uint8_t *iv_external,
                                     size_t iv_size,
                                     size_t *iv_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
-    uint8_t local_iv[PSA_CIPHER_IV_MAX_SIZE];
     size_t default_iv_length = 0;
 
+    LOCAL_OUTPUT_DECLARE(iv_external, iv);
+
     if (operation->id == 0) {
         status = PSA_ERROR_BAD_STATE;
         goto exit;
@@ -3987,33 +4357,40 @@
         goto exit;
     }
 
-    status = psa_generate_random(local_iv, default_iv_length);
+    LOCAL_OUTPUT_ALLOC(iv_external, default_iv_length, iv);
+
+    status = psa_generate_random_internal(iv, default_iv_length);
     if (status != PSA_SUCCESS) {
         goto exit;
     }
 
     status = psa_driver_wrapper_cipher_set_iv(operation,
-                                              local_iv, default_iv_length);
+                                              iv, default_iv_length);
 
 exit:
     if (status == PSA_SUCCESS) {
-        memcpy(iv, local_iv, default_iv_length);
         *iv_length = default_iv_length;
         operation->iv_set = 1;
     } else {
         *iv_length = 0;
         psa_cipher_abort(operation);
+        if (iv != NULL) {
+            mbedtls_platform_zeroize(iv, default_iv_length);
+        }
     }
 
+    LOCAL_OUTPUT_FREE(iv_external, iv);
     return status;
 }
 
 psa_status_t psa_cipher_set_iv(psa_cipher_operation_t *operation,
-                               const uint8_t *iv,
+                               const uint8_t *iv_external,
                                size_t iv_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
 
+    LOCAL_INPUT_DECLARE(iv_external, iv);
+
     if (operation->id == 0) {
         status = PSA_ERROR_BAD_STATE;
         goto exit;
@@ -4029,6 +4406,8 @@
         goto exit;
     }
 
+    LOCAL_INPUT_ALLOC(iv_external, iv_length, iv);
+
     status = psa_driver_wrapper_cipher_set_iv(operation,
                                               iv,
                                               iv_length);
@@ -4039,18 +4418,24 @@
     } else {
         psa_cipher_abort(operation);
     }
+
+    LOCAL_INPUT_FREE(iv_external, iv);
+
     return status;
 }
 
 psa_status_t psa_cipher_update(psa_cipher_operation_t *operation,
-                               const uint8_t *input,
+                               const uint8_t *input_external,
                                size_t input_length,
-                               uint8_t *output,
+                               uint8_t *output_external,
                                size_t output_size,
                                size_t *output_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
 
+    LOCAL_INPUT_DECLARE(input_external, input);
+    LOCAL_OUTPUT_DECLARE(output_external, output);
+
     if (operation->id == 0) {
         status = PSA_ERROR_BAD_STATE;
         goto exit;
@@ -4061,6 +4446,9 @@
         goto exit;
     }
 
+    LOCAL_INPUT_ALLOC(input_external, input_length, input);
+    LOCAL_OUTPUT_ALLOC(output_external, output_size, output);
+
     status = psa_driver_wrapper_cipher_update(operation,
                                               input,
                                               input_length,
@@ -4073,16 +4461,21 @@
         psa_cipher_abort(operation);
     }
 
+    LOCAL_INPUT_FREE(input_external, input);
+    LOCAL_OUTPUT_FREE(output_external, output);
+
     return status;
 }
 
 psa_status_t psa_cipher_finish(psa_cipher_operation_t *operation,
-                               uint8_t *output,
+                               uint8_t *output_external,
                                size_t output_size,
                                size_t *output_length)
 {
     psa_status_t status = PSA_ERROR_GENERIC_ERROR;
 
+    LOCAL_OUTPUT_DECLARE(output_external, output);
+
     if (operation->id == 0) {
         status = PSA_ERROR_BAD_STATE;
         goto exit;
@@ -4093,6 +4486,8 @@
         goto exit;
     }
 
+    LOCAL_OUTPUT_ALLOC(output_external, output_size, output);
+
     status = psa_driver_wrapper_cipher_finish(operation,
                                               output,
                                               output_size,
@@ -4100,13 +4495,15 @@
 
 exit:
     if (status == PSA_SUCCESS) {
-        return psa_cipher_abort(operation);
+        status = psa_cipher_abort(operation);
     } else {
         *output_length = 0;
         (void) psa_cipher_abort(operation);
-
-        return status;
     }
+
+    LOCAL_OUTPUT_FREE(output_external, output);
+
+    return status;
 }
 
 psa_status_t psa_cipher_abort(psa_cipher_operation_t *operation)
@@ -4129,9 +4526,9 @@
 
 psa_status_t psa_cipher_encrypt(mbedtls_svc_key_id_t key,
                                 psa_algorithm_t alg,
-                                const uint8_t *input,
+                                const uint8_t *input_external,
                                 size_t input_length,
-                                uint8_t *output,
+                                uint8_t *output_external,
                                 size_t output_size,
                                 size_t *output_length)
 {
@@ -4141,6 +4538,9 @@
     uint8_t local_iv[PSA_CIPHER_IV_MAX_SIZE];
     size_t default_iv_length = 0;
 
+    LOCAL_INPUT_DECLARE(input_external, input);
+    LOCAL_OUTPUT_DECLARE(output_external, output);
+
     if (!PSA_ALG_IS_CIPHER(alg)) {
         status = PSA_ERROR_INVALID_ARGUMENT;
         goto exit;
@@ -4165,12 +4565,15 @@
             goto exit;
         }
 
-        status = psa_generate_random(local_iv, default_iv_length);
+        status = psa_generate_random_internal(local_iv, default_iv_length);
         if (status != PSA_SUCCESS) {
             goto exit;
         }
     }
 
+    LOCAL_INPUT_ALLOC(input_external, input_length, input);
+    LOCAL_OUTPUT_ALLOC(output_external, output_size, output);
+
     status = psa_driver_wrapper_cipher_encrypt(
         &slot->attr, slot->key.data, slot->key.bytes,
         alg, local_iv, default_iv_length, input, input_length,
@@ -4192,14 +4595,17 @@
         *output_length = 0;
     }
 
+    LOCAL_INPUT_FREE(input_external, input);
+    LOCAL_OUTPUT_FREE(output_external, output);
+
     return status;
 }
 
 psa_status_t psa_cipher_decrypt(mbedtls_svc_key_id_t key,
                                 psa_algorithm_t alg,
-                                const uint8_t *input,
+                                const uint8_t *input_external,
                                 size_t input_length,
-                                uint8_t *output,
+                                uint8_t *output_external,
                                 size_t output_size,
                                 size_t *output_length)
 {
@@ -4207,6 +4613,9 @@
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot = NULL;
 
+    LOCAL_INPUT_DECLARE(input_external, input);
+    LOCAL_OUTPUT_DECLARE(output_external, output);
+
     if (!PSA_ALG_IS_CIPHER(alg)) {
         status = PSA_ERROR_INVALID_ARGUMENT;
         goto exit;
@@ -4228,6 +4637,9 @@
         goto exit;
     }
 
+    LOCAL_INPUT_ALLOC(input_external, input_length, input);
+    LOCAL_OUTPUT_ALLOC(output_external, output_size, output);
+
     status = psa_driver_wrapper_cipher_decrypt(
         &slot->attr, slot->key.data, slot->key.bytes,
         alg, input, input_length,
@@ -4243,6 +4655,9 @@
         *output_length = 0;
     }
 
+    LOCAL_INPUT_FREE(input_external, input);
+    LOCAL_OUTPUT_FREE(output_external, output);
+
     return status;
 }
 
@@ -4312,19 +4727,24 @@
 
 psa_status_t psa_aead_encrypt(mbedtls_svc_key_id_t key,
                               psa_algorithm_t alg,
-                              const uint8_t *nonce,
+                              const uint8_t *nonce_external,
                               size_t nonce_length,
-                              const uint8_t *additional_data,
+                              const uint8_t *additional_data_external,
                               size_t additional_data_length,
-                              const uint8_t *plaintext,
+                              const uint8_t *plaintext_external,
                               size_t plaintext_length,
-                              uint8_t *ciphertext,
+                              uint8_t *ciphertext_external,
                               size_t ciphertext_size,
                               size_t *ciphertext_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot;
 
+    LOCAL_INPUT_DECLARE(nonce_external, nonce);
+    LOCAL_INPUT_DECLARE(additional_data_external, additional_data);
+    LOCAL_INPUT_DECLARE(plaintext_external, plaintext);
+    LOCAL_OUTPUT_DECLARE(ciphertext_external, ciphertext);
+
     *ciphertext_length = 0;
 
     status = psa_aead_check_algorithm(alg);
@@ -4338,6 +4758,11 @@
         return status;
     }
 
+    LOCAL_INPUT_ALLOC(nonce_external, nonce_length, nonce);
+    LOCAL_INPUT_ALLOC(additional_data_external, additional_data_length, additional_data);
+    LOCAL_INPUT_ALLOC(plaintext_external, plaintext_length, plaintext);
+    LOCAL_OUTPUT_ALLOC(ciphertext_external, ciphertext_size, ciphertext);
+
     status = psa_aead_check_nonce_length(alg, nonce_length);
     if (status != PSA_SUCCESS) {
         goto exit;
@@ -4356,6 +4781,11 @@
     }
 
 exit:
+    LOCAL_INPUT_FREE(nonce_external, nonce);
+    LOCAL_INPUT_FREE(additional_data_external, additional_data);
+    LOCAL_INPUT_FREE(plaintext_external, plaintext);
+    LOCAL_OUTPUT_FREE(ciphertext_external, ciphertext);
+
     psa_unregister_read_under_mutex(slot);
 
     return status;
@@ -4363,19 +4793,24 @@
 
 psa_status_t psa_aead_decrypt(mbedtls_svc_key_id_t key,
                               psa_algorithm_t alg,
-                              const uint8_t *nonce,
+                              const uint8_t *nonce_external,
                               size_t nonce_length,
-                              const uint8_t *additional_data,
+                              const uint8_t *additional_data_external,
                               size_t additional_data_length,
-                              const uint8_t *ciphertext,
+                              const uint8_t *ciphertext_external,
                               size_t ciphertext_length,
-                              uint8_t *plaintext,
+                              uint8_t *plaintext_external,
                               size_t plaintext_size,
                               size_t *plaintext_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot;
 
+    LOCAL_INPUT_DECLARE(nonce_external, nonce);
+    LOCAL_INPUT_DECLARE(additional_data_external, additional_data);
+    LOCAL_INPUT_DECLARE(ciphertext_external, ciphertext);
+    LOCAL_OUTPUT_DECLARE(plaintext_external, plaintext);
+
     *plaintext_length = 0;
 
     status = psa_aead_check_algorithm(alg);
@@ -4389,6 +4824,12 @@
         return status;
     }
 
+    LOCAL_INPUT_ALLOC(nonce_external, nonce_length, nonce);
+    LOCAL_INPUT_ALLOC(additional_data_external, additional_data_length,
+                      additional_data);
+    LOCAL_INPUT_ALLOC(ciphertext_external, ciphertext_length, ciphertext);
+    LOCAL_OUTPUT_ALLOC(plaintext_external, plaintext_size, plaintext);
+
     status = psa_aead_check_nonce_length(alg, nonce_length);
     if (status != PSA_SUCCESS) {
         goto exit;
@@ -4407,6 +4848,11 @@
     }
 
 exit:
+    LOCAL_INPUT_FREE(nonce_external, nonce);
+    LOCAL_INPUT_FREE(additional_data_external, additional_data);
+    LOCAL_INPUT_FREE(ciphertext_external, ciphertext);
+    LOCAL_OUTPUT_FREE(plaintext_external, plaintext);
+
     psa_unregister_read_under_mutex(slot);
 
     return status;
@@ -4543,9 +4989,44 @@
     return psa_aead_setup(operation, 0, key, alg);
 }
 
+static psa_status_t psa_aead_set_nonce_internal(psa_aead_operation_t *operation,
+                                                const uint8_t *nonce,
+                                                size_t nonce_length)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    if (operation->id == 0) {
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
+    }
+
+    if (operation->nonce_set) {
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
+    }
+
+    status = psa_aead_check_nonce_length(operation->alg, nonce_length);
+    if (status != PSA_SUCCESS) {
+        status = PSA_ERROR_INVALID_ARGUMENT;
+        goto exit;
+    }
+
+    status = psa_driver_wrapper_aead_set_nonce(operation, nonce,
+                                               nonce_length);
+
+exit:
+    if (status == PSA_SUCCESS) {
+        operation->nonce_set = 1;
+    } else {
+        psa_aead_abort(operation);
+    }
+
+    return status;
+}
+
 /* Generate a random nonce / IV for multipart AEAD operation */
 psa_status_t psa_aead_generate_nonce(psa_aead_operation_t *operation,
-                                     uint8_t *nonce,
+                                     uint8_t *nonce_external,
                                      size_t nonce_size,
                                      size_t *nonce_length)
 {
@@ -4553,6 +5034,9 @@
     uint8_t local_nonce[PSA_AEAD_NONCE_MAX_SIZE];
     size_t required_nonce_size = 0;
 
+    LOCAL_OUTPUT_DECLARE(nonce_external, nonce);
+    LOCAL_OUTPUT_ALLOC(nonce_external, nonce_size, nonce);
+
     *nonce_length = 0;
 
     if (operation->id == 0) {
@@ -4581,12 +5065,13 @@
         goto exit;
     }
 
-    status = psa_generate_random(local_nonce, required_nonce_size);
+    status = psa_generate_random_internal(local_nonce, required_nonce_size);
     if (status != PSA_SUCCESS) {
         goto exit;
     }
 
-    status = psa_aead_set_nonce(operation, local_nonce, required_nonce_size);
+    status = psa_aead_set_nonce_internal(operation, local_nonce,
+                                         required_nonce_size);
 
 exit:
     if (status == PSA_SUCCESS) {
@@ -4596,42 +5081,30 @@
         psa_aead_abort(operation);
     }
 
+    LOCAL_OUTPUT_FREE(nonce_external, nonce);
+
     return status;
 }
 
 /* Set the nonce for a multipart authenticated encryption or decryption
    operation.*/
 psa_status_t psa_aead_set_nonce(psa_aead_operation_t *operation,
-                                const uint8_t *nonce,
+                                const uint8_t *nonce_external,
                                 size_t nonce_length)
 {
-    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    psa_status_t status;
 
-    if (operation->id == 0) {
-        status = PSA_ERROR_BAD_STATE;
-        goto exit;
-    }
+    LOCAL_INPUT_DECLARE(nonce_external, nonce);
+    LOCAL_INPUT_ALLOC(nonce_external, nonce_length, nonce);
 
-    if (operation->nonce_set) {
-        status = PSA_ERROR_BAD_STATE;
-        goto exit;
-    }
+    status = psa_aead_set_nonce_internal(operation, nonce, nonce_length);
 
-    status = psa_aead_check_nonce_length(operation->alg, nonce_length);
-    if (status != PSA_SUCCESS) {
-        status = PSA_ERROR_INVALID_ARGUMENT;
-        goto exit;
-    }
-
-    status = psa_driver_wrapper_aead_set_nonce(operation, nonce,
-                                               nonce_length);
-
+/* Exit label is only needed for buffer copying, prevent unused warnings. */
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
 exit:
-    if (status == PSA_SUCCESS) {
-        operation->nonce_set = 1;
-    } else {
-        psa_aead_abort(operation);
-    }
+#endif
+
+    LOCAL_INPUT_FREE(nonce_external, nonce);
 
     return status;
 }
@@ -4703,11 +5176,14 @@
 
 /* Pass additional data to an active multipart AEAD operation. */
 psa_status_t psa_aead_update_ad(psa_aead_operation_t *operation,
-                                const uint8_t *input,
+                                const uint8_t *input_external,
                                 size_t input_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
 
+    LOCAL_INPUT_DECLARE(input_external, input);
+    LOCAL_INPUT_ALLOC(input_external, input_length, input);
+
     if (operation->id == 0) {
         status = PSA_ERROR_BAD_STATE;
         goto exit;
@@ -4743,20 +5219,29 @@
         psa_aead_abort(operation);
     }
 
+    LOCAL_INPUT_FREE(input_external, input);
+
     return status;
 }
 
 /* Encrypt or decrypt a message fragment in an active multipart AEAD
    operation.*/
 psa_status_t psa_aead_update(psa_aead_operation_t *operation,
-                             const uint8_t *input,
+                             const uint8_t *input_external,
                              size_t input_length,
-                             uint8_t *output,
+                             uint8_t *output_external,
                              size_t output_size,
                              size_t *output_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
 
+
+    LOCAL_INPUT_DECLARE(input_external, input);
+    LOCAL_OUTPUT_DECLARE(output_external, output);
+
+    LOCAL_INPUT_ALLOC(input_external, input_length, input);
+    LOCAL_OUTPUT_ALLOC(output_external, output_size, output);
+
     *output_length = 0;
 
     if (operation->id == 0) {
@@ -4803,6 +5288,9 @@
         psa_aead_abort(operation);
     }
 
+    LOCAL_INPUT_FREE(input_external, input);
+    LOCAL_OUTPUT_FREE(output_external, output);
+
     return status;
 }
 
@@ -4822,15 +5310,21 @@
 
 /* Finish encrypting a message in a multipart AEAD operation. */
 psa_status_t psa_aead_finish(psa_aead_operation_t *operation,
-                             uint8_t *ciphertext,
+                             uint8_t *ciphertext_external,
                              size_t ciphertext_size,
                              size_t *ciphertext_length,
-                             uint8_t *tag,
+                             uint8_t *tag_external,
                              size_t tag_size,
                              size_t *tag_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
 
+    LOCAL_OUTPUT_DECLARE(ciphertext_external, ciphertext);
+    LOCAL_OUTPUT_DECLARE(tag_external, tag);
+
+    LOCAL_OUTPUT_ALLOC(ciphertext_external, ciphertext_size, ciphertext);
+    LOCAL_OUTPUT_ALLOC(tag_external, tag_size, tag);
+
     *ciphertext_length = 0;
     *tag_length = tag_size;
 
@@ -4861,20 +5355,29 @@
 
     psa_aead_abort(operation);
 
+    LOCAL_OUTPUT_FREE(ciphertext_external, ciphertext);
+    LOCAL_OUTPUT_FREE(tag_external, tag);
+
     return status;
 }
 
 /* Finish authenticating and decrypting a message in a multipart AEAD
    operation.*/
 psa_status_t psa_aead_verify(psa_aead_operation_t *operation,
-                             uint8_t *plaintext,
+                             uint8_t *plaintext_external,
                              size_t plaintext_size,
                              size_t *plaintext_length,
-                             const uint8_t *tag,
+                             const uint8_t *tag_external,
                              size_t tag_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
 
+    LOCAL_OUTPUT_DECLARE(plaintext_external, plaintext);
+    LOCAL_INPUT_DECLARE(tag_external, tag);
+
+    LOCAL_OUTPUT_ALLOC(plaintext_external, plaintext_size, plaintext);
+    LOCAL_INPUT_ALLOC(tag_external, tag_length, tag);
+
     *plaintext_length = 0;
 
     status = psa_aead_final_checks(operation);
@@ -4895,6 +5398,9 @@
 exit:
     psa_aead_abort(operation);
 
+    LOCAL_OUTPUT_FREE(plaintext_external, plaintext);
+    LOCAL_INPUT_FREE(tag_external, tag);
+
     return status;
 }
 
@@ -5501,10 +6007,12 @@
 
 psa_status_t psa_key_derivation_output_bytes(
     psa_key_derivation_operation_t *operation,
-    uint8_t *output,
+    uint8_t *output_external,
     size_t output_length)
 {
     psa_status_t status;
+    LOCAL_OUTPUT_DECLARE(output_external, output);
+
     psa_algorithm_t kdf_alg = psa_key_derivation_get_kdf_alg(operation);
 
     if (operation->alg == 0) {
@@ -5512,13 +6020,6 @@
         return PSA_ERROR_BAD_STATE;
     }
 
-    if (output_length > operation->capacity) {
-        operation->capacity = 0;
-        /* Go through the error path to wipe all confidential data now
-         * that the operation object is useless. */
-        status = PSA_ERROR_INSUFFICIENT_DATA;
-        goto exit;
-    }
     if (output_length == 0 && operation->capacity == 0) {
         /* Edge case: this is a finished operation, and 0 bytes
          * were requested. The right error in this case could
@@ -5528,6 +6029,16 @@
          * output_length > 0. */
         return PSA_ERROR_INSUFFICIENT_DATA;
     }
+
+    LOCAL_OUTPUT_ALLOC(output_external, output_length, output);
+    if (output_length > operation->capacity) {
+        operation->capacity = 0;
+        /* Go through the error path to wipe all confidential data now
+         * that the operation object is useless. */
+        status = PSA_ERROR_INSUFFICIENT_DATA;
+        goto exit;
+    }
+
     operation->capacity -= output_length;
 
 #if defined(BUILTIN_ALG_ANY_HKDF)
@@ -5561,7 +6072,10 @@
 
     {
         (void) kdf_alg;
-        return PSA_ERROR_BAD_STATE;
+        status = PSA_ERROR_BAD_STATE;
+        LOCAL_OUTPUT_FREE(output_external, output);
+
+        return status;
     }
 
 exit:
@@ -5573,8 +6087,12 @@
         psa_algorithm_t alg = operation->alg;
         psa_key_derivation_abort(operation);
         operation->alg = alg;
-        memset(output, '!', output_length);
+        if (output != NULL) {
+            memset(output, '!', output_length);
+        }
     }
+
+    LOCAL_OUTPUT_FREE(output_external, output);
     return status;
 }
 
@@ -6633,12 +7151,12 @@
 {
     psa_status_t status = PSA_SUCCESS;
     if (input_len > PSA_HASH_BLOCK_LENGTH(hash_alg)) {
-        status = psa_hash_compute(hash_alg, input, input_len, output,
-                                  PSA_HMAC_MAX_HASH_BLOCK_SIZE, output_len);
-    } else {
+        return psa_hash_compute(hash_alg, input, input_len, output,
+                                PSA_HMAC_MAX_HASH_BLOCK_SIZE, output_len);
+    } else if (input_len > 0) {
         memcpy(output, input, input_len);
-        *output_len = PSA_HASH_BLOCK_LENGTH(hash_alg);
     }
+    *output_len = PSA_HASH_BLOCK_LENGTH(hash_alg);
     return status;
 }
 #endif /* MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC */
@@ -6872,12 +7390,22 @@
 psa_status_t psa_key_derivation_input_bytes(
     psa_key_derivation_operation_t *operation,
     psa_key_derivation_step_t step,
-    const uint8_t *data,
+    const uint8_t *data_external,
     size_t data_length)
 {
-    return psa_key_derivation_input_internal(operation, step,
-                                             PSA_KEY_TYPE_NONE,
-                                             data, data_length);
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    LOCAL_INPUT_DECLARE(data_external, data);
+
+    LOCAL_INPUT_ALLOC(data_external, data_length, data);
+
+    status = psa_key_derivation_input_internal(operation, step,
+                                               PSA_KEY_TYPE_NONE,
+                                               data, data_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+exit:
+#endif
+    LOCAL_INPUT_FREE(data_external, data);
+    return status;
 }
 
 psa_status_t psa_key_derivation_input_integer(
@@ -7041,12 +7569,13 @@
 psa_status_t psa_key_derivation_key_agreement(psa_key_derivation_operation_t *operation,
                                               psa_key_derivation_step_t step,
                                               mbedtls_svc_key_id_t private_key,
-                                              const uint8_t *peer_key,
+                                              const uint8_t *peer_key_external,
                                               size_t peer_key_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot;
+    LOCAL_INPUT_DECLARE(peer_key_external, peer_key);
 
     if (!PSA_ALG_IS_KEY_AGREEMENT(operation->alg)) {
         return PSA_ERROR_INVALID_ARGUMENT;
@@ -7056,9 +7585,15 @@
     if (status != PSA_SUCCESS) {
         return status;
     }
+
+    LOCAL_INPUT_ALLOC(peer_key_external, peer_key_length, peer_key);
     status = psa_key_agreement_internal(operation, step,
                                         slot,
                                         peer_key, peer_key_length);
+
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+exit:
+#endif
     if (status != PSA_SUCCESS) {
         psa_key_derivation_abort(operation);
     } else {
@@ -7070,15 +7605,16 @@
     }
 
     unlock_status = psa_unregister_read_under_mutex(slot);
+    LOCAL_INPUT_FREE(peer_key_external, peer_key);
 
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
 
 psa_status_t psa_raw_key_agreement(psa_algorithm_t alg,
                                    mbedtls_svc_key_id_t private_key,
-                                   const uint8_t *peer_key,
+                                   const uint8_t *peer_key_external,
                                    size_t peer_key_length,
-                                   uint8_t *output,
+                                   uint8_t *output_external,
                                    size_t output_size,
                                    size_t *output_length)
 {
@@ -7086,6 +7622,9 @@
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_slot_t *slot = NULL;
     size_t expected_length;
+    LOCAL_INPUT_DECLARE(peer_key_external, peer_key);
+    LOCAL_OUTPUT_DECLARE(output_external, output);
+    LOCAL_OUTPUT_ALLOC(output_external, output_size, output);
 
     if (!PSA_ALG_IS_KEY_AGREEMENT(alg)) {
         status = PSA_ERROR_INVALID_ARGUMENT;
@@ -7112,13 +7651,16 @@
         goto exit;
     }
 
+    LOCAL_INPUT_ALLOC(peer_key_external, peer_key_length, peer_key);
     status = psa_key_agreement_raw_internal(alg, slot,
                                             peer_key, peer_key_length,
                                             output, output_size,
                                             output_length);
 
 exit:
-    if (status != PSA_SUCCESS) {
+    /* Check for successful allocation of output,
+     * with an unsuccessful status. */
+    if (output != NULL && status != PSA_SUCCESS) {
         /* If an error happens and is not handled properly, the output
          * may be used as a key to protect sensitive data. Arrange for such
          * a key to be random, which is likely to result in decryption or
@@ -7126,17 +7668,23 @@
          * some constant data such as zeros, which would result in the data
          * being protected with a reproducible, easily knowable key.
          */
-        psa_generate_random(output, output_size);
+        psa_generate_random_internal(output, output_size);
         *output_length = output_size;
     }
 
+    if (output == NULL) {
+        /* output allocation failed. */
+        *output_length = 0;
+    }
+
     unlock_status = psa_unregister_read_under_mutex(slot);
 
+    LOCAL_INPUT_FREE(peer_key_external, peer_key);
+    LOCAL_OUTPUT_FREE(output_external, output);
     return (status == PSA_SUCCESS) ? unlock_status : status;
 }
 
 
-
 /****************************************************************/
 /* Random generation */
 /****************************************************************/
@@ -7211,48 +7759,21 @@
 #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
 }
 
-psa_status_t psa_generate_random(uint8_t *output,
+psa_status_t psa_generate_random(uint8_t *output_external,
                                  size_t output_size)
 {
-    GUARD_MODULE_INITIALIZED;
+    psa_status_t status;
 
-#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+    LOCAL_OUTPUT_DECLARE(output_external, output);
+    LOCAL_OUTPUT_ALLOC(output_external, output_size, output);
 
-    size_t output_length = 0;
-    psa_status_t status = mbedtls_psa_external_get_random(&global_data.rng,
-                                                          output, output_size,
-                                                          &output_length);
-    if (status != PSA_SUCCESS) {
-        return status;
-    }
-    /* Breaking up a request into smaller chunks is currently not supported
-     * for the external RNG interface. */
-    if (output_length != output_size) {
-        return PSA_ERROR_INSUFFICIENT_ENTROPY;
-    }
-    return PSA_SUCCESS;
+    status = psa_generate_random_internal(output, output_size);
 
-#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
-
-    while (output_size > 0) {
-        int ret = MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED;
-        size_t request_size =
-            (output_size > MBEDTLS_PSA_RANDOM_MAX_REQUEST ?
-             MBEDTLS_PSA_RANDOM_MAX_REQUEST :
-             output_size);
-#if defined(MBEDTLS_CTR_DRBG_C)
-        ret = mbedtls_ctr_drbg_random(&global_data.rng.drbg, output, request_size);
-#elif defined(MBEDTLS_HMAC_DRBG_C)
-        ret = mbedtls_hmac_drbg_random(&global_data.rng.drbg, output, request_size);
-#endif /* !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C */
-        if (ret != 0) {
-            return mbedtls_to_psa_error(ret);
-        }
-        output_size -= request_size;
-        output += request_size;
-    }
-    return PSA_SUCCESS;
-#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+exit:
+#endif
+    LOCAL_OUTPUT_FREE(output_external, output);
+    return status;
 }
 
 #if defined(MBEDTLS_PSA_INJECT_ENTROPY)
@@ -7348,7 +7869,7 @@
     (void) params_data_length;
 
     if (key_type_is_raw_bytes(type)) {
-        status = psa_generate_random(key_buffer, key_buffer_size);
+        status = psa_generate_random_internal(key_buffer, key_buffer_size);
         if (status != PSA_SUCCESS) {
             return status;
         }
@@ -7969,10 +8490,11 @@
 
 psa_status_t psa_pake_set_user(
     psa_pake_operation_t *operation,
-    const uint8_t *user_id,
+    const uint8_t *user_id_external,
     size_t user_id_len)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    LOCAL_INPUT_DECLARE(user_id_external, user_id);
 
     if (operation->stage != PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS) {
         status = PSA_ERROR_BAD_STATE;
@@ -7995,21 +8517,28 @@
         goto exit;
     }
 
+    LOCAL_INPUT_ALLOC(user_id_external, user_id_len, user_id);
+
     memcpy(operation->data.inputs.user, user_id, user_id_len);
     operation->data.inputs.user_len = user_id_len;
 
-    return PSA_SUCCESS;
+    status = PSA_SUCCESS;
+
 exit:
-    psa_pake_abort(operation);
+    LOCAL_INPUT_FREE(user_id_external, user_id);
+    if (status != PSA_SUCCESS) {
+        psa_pake_abort(operation);
+    }
     return status;
 }
 
 psa_status_t psa_pake_set_peer(
     psa_pake_operation_t *operation,
-    const uint8_t *peer_id,
+    const uint8_t *peer_id_external,
     size_t peer_id_len)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    LOCAL_INPUT_DECLARE(peer_id_external, peer_id);
 
     if (operation->stage != PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS) {
         status = PSA_ERROR_BAD_STATE;
@@ -8032,12 +8561,18 @@
         goto exit;
     }
 
+    LOCAL_INPUT_ALLOC(peer_id_external, peer_id_len, peer_id);
+
     memcpy(operation->data.inputs.peer, peer_id, peer_id_len);
     operation->data.inputs.peer_len = peer_id_len;
 
-    return PSA_SUCCESS;
+    status = PSA_SUCCESS;
+
 exit:
-    psa_pake_abort(operation);
+    LOCAL_INPUT_FREE(peer_id_external, peer_id);
+    if (status != PSA_SUCCESS) {
+        psa_pake_abort(operation);
+    }
     return status;
 }
 
@@ -8223,12 +8758,13 @@
 psa_status_t psa_pake_output(
     psa_pake_operation_t *operation,
     psa_pake_step_t step,
-    uint8_t *output,
+    uint8_t *output_external,
     size_t output_size,
     size_t *output_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_crypto_driver_pake_step_t driver_step = PSA_JPAKE_STEP_INVALID;
+    LOCAL_OUTPUT_DECLARE(output_external, output);
     *output_length = 0;
 
     if (operation->stage == PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS) {
@@ -8265,6 +8801,8 @@
             goto exit;
     }
 
+    LOCAL_OUTPUT_ALLOC(output_external, output_size, output);
+
     status = psa_driver_wrapper_pake_output(operation, driver_step,
                                             output, output_size, output_length);
 
@@ -8286,16 +8824,18 @@
             goto exit;
     }
 
-    return PSA_SUCCESS;
 exit:
-    psa_pake_abort(operation);
+    LOCAL_OUTPUT_FREE(output_external, output);
+    if (status != PSA_SUCCESS) {
+        psa_pake_abort(operation);
+    }
     return status;
 }
 
 psa_status_t psa_pake_input(
     psa_pake_operation_t *operation,
     psa_pake_step_t step,
-    const uint8_t *input,
+    const uint8_t *input_external,
     size_t input_length)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
@@ -8303,6 +8843,7 @@
     const size_t max_input_length = (size_t) PSA_PAKE_INPUT_SIZE(operation->alg,
                                                                  operation->primitive,
                                                                  step);
+    LOCAL_INPUT_DECLARE(input_external, input);
 
     if (operation->stage == PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS) {
         status = psa_pake_complete_inputs(operation);
@@ -8338,6 +8879,7 @@
             goto exit;
     }
 
+    LOCAL_INPUT_ALLOC(input_external, input_length, input);
     status = psa_driver_wrapper_pake_input(operation, driver_step,
                                            input, input_length);
 
@@ -8359,9 +8901,11 @@
             goto exit;
     }
 
-    return PSA_SUCCESS;
 exit:
-    psa_pake_abort(operation);
+    LOCAL_INPUT_FREE(input_external, input);
+    if (status != PSA_SUCCESS) {
+        psa_pake_abort(operation);
+    }
     return status;
 }
 
@@ -8441,4 +8985,182 @@
 }
 #endif /* PSA_WANT_ALG_SOME_PAKE */
 
+/* Memory copying test hooks. These are called before input copy, after input
+ * copy, before output copy and after output copy, respectively.
+ * They are used by memory-poisoning tests to temporarily unpoison buffers
+ * while they are copied. */
+#if defined(MBEDTLS_TEST_HOOKS)
+void (*psa_input_pre_copy_hook)(const uint8_t *input, size_t input_len) = NULL;
+void (*psa_input_post_copy_hook)(const uint8_t *input, size_t input_len) = NULL;
+void (*psa_output_pre_copy_hook)(const uint8_t *output, size_t output_len) = NULL;
+void (*psa_output_post_copy_hook)(const uint8_t *output, size_t output_len) = NULL;
+#endif
+
+/** Copy from an input buffer to a local copy.
+ *
+ * \param[in] input             Pointer to input buffer.
+ * \param[in] input_len         Length of the input buffer.
+ * \param[out] input_copy       Pointer to a local copy in which to store the input data.
+ * \param[out] input_copy_len   Length of the local copy buffer.
+ * \return                      #PSA_SUCCESS, if the buffer was successfully
+ *                              copied.
+ * \return                      #PSA_ERROR_CORRUPTION_DETECTED, if the local
+ *                              copy is too small to hold contents of the
+ *                              input buffer.
+ */
+MBEDTLS_STATIC_TESTABLE
+psa_status_t psa_crypto_copy_input(const uint8_t *input, size_t input_len,
+                                   uint8_t *input_copy, size_t input_copy_len)
+{
+    if (input_len > input_copy_len) {
+        return PSA_ERROR_CORRUPTION_DETECTED;
+    }
+
+#if defined(MBEDTLS_TEST_HOOKS)
+    if (psa_input_pre_copy_hook != NULL) {
+        psa_input_pre_copy_hook(input, input_len);
+    }
+#endif
+
+    if (input_len > 0) {
+        memcpy(input_copy, input, input_len);
+    }
+
+#if defined(MBEDTLS_TEST_HOOKS)
+    if (psa_input_post_copy_hook != NULL) {
+        psa_input_post_copy_hook(input, input_len);
+    }
+#endif
+
+    return PSA_SUCCESS;
+}
+
+/** Copy from a local output buffer into a user-supplied one.
+ *
+ * \param[in] output_copy       Pointer to a local buffer containing the output.
+ * \param[in] output_copy_len   Length of the local buffer.
+ * \param[out] output           Pointer to user-supplied output buffer.
+ * \param[out] output_len       Length of the user-supplied output buffer.
+ * \return                      #PSA_SUCCESS, if the buffer was successfully
+ *                              copied.
+ * \return                      #PSA_ERROR_BUFFER_TOO_SMALL, if the
+ *                              user-supplied output buffer is too small to
+ *                              hold the contents of the local buffer.
+ */
+MBEDTLS_STATIC_TESTABLE
+psa_status_t psa_crypto_copy_output(const uint8_t *output_copy, size_t output_copy_len,
+                                    uint8_t *output, size_t output_len)
+{
+    if (output_len < output_copy_len) {
+        return PSA_ERROR_BUFFER_TOO_SMALL;
+    }
+
+#if defined(MBEDTLS_TEST_HOOKS)
+    if (psa_output_pre_copy_hook != NULL) {
+        psa_output_pre_copy_hook(output, output_len);
+    }
+#endif
+
+    if (output_copy_len > 0) {
+        memcpy(output, output_copy, output_copy_len);
+    }
+
+#if defined(MBEDTLS_TEST_HOOKS)
+    if (psa_output_post_copy_hook != NULL) {
+        psa_output_post_copy_hook(output, output_len);
+    }
+#endif
+
+    return PSA_SUCCESS;
+}
+
+psa_status_t psa_crypto_local_input_alloc(const uint8_t *input, size_t input_len,
+                                          psa_crypto_local_input_t *local_input)
+{
+    psa_status_t status;
+
+    *local_input = PSA_CRYPTO_LOCAL_INPUT_INIT;
+
+    if (input_len == 0) {
+        return PSA_SUCCESS;
+    }
+
+    local_input->buffer = mbedtls_calloc(input_len, 1);
+    if (local_input->buffer == NULL) {
+        /* Since we dealt with the zero-length case above, we know that
+         * a NULL return value means a failure of allocation. */
+        return PSA_ERROR_INSUFFICIENT_MEMORY;
+    }
+    /* From now on, we must free local_input->buffer on error. */
+
+    local_input->length = input_len;
+
+    status = psa_crypto_copy_input(input, input_len,
+                                   local_input->buffer, local_input->length);
+    if (status != PSA_SUCCESS) {
+        goto error;
+    }
+
+    return PSA_SUCCESS;
+
+error:
+    mbedtls_free(local_input->buffer);
+    local_input->buffer = NULL;
+    local_input->length = 0;
+    return status;
+}
+
+void psa_crypto_local_input_free(psa_crypto_local_input_t *local_input)
+{
+    mbedtls_free(local_input->buffer);
+    local_input->buffer = NULL;
+    local_input->length = 0;
+}
+
+psa_status_t psa_crypto_local_output_alloc(uint8_t *output, size_t output_len,
+                                           psa_crypto_local_output_t *local_output)
+{
+    *local_output = PSA_CRYPTO_LOCAL_OUTPUT_INIT;
+
+    if (output_len == 0) {
+        return PSA_SUCCESS;
+    }
+    local_output->buffer = mbedtls_calloc(output_len, 1);
+    if (local_output->buffer == NULL) {
+        /* Since we dealt with the zero-length case above, we know that
+         * a NULL return value means a failure of allocation. */
+        return PSA_ERROR_INSUFFICIENT_MEMORY;
+    }
+    local_output->length = output_len;
+    local_output->original = output;
+
+    return PSA_SUCCESS;
+}
+
+psa_status_t psa_crypto_local_output_free(psa_crypto_local_output_t *local_output)
+{
+    psa_status_t status;
+
+    if (local_output->buffer == NULL) {
+        local_output->length = 0;
+        return PSA_SUCCESS;
+    }
+    if (local_output->original == NULL) {
+        /* We have an internal copy but nothing to copy back to. */
+        return PSA_ERROR_CORRUPTION_DETECTED;
+    }
+
+    status = psa_crypto_copy_output(local_output->buffer, local_output->length,
+                                    local_output->original, local_output->length);
+    if (status != PSA_SUCCESS) {
+        return status;
+    }
+
+    mbedtls_free(local_output->buffer);
+    local_output->buffer = NULL;
+    local_output->length = 0;
+
+    return PSA_SUCCESS;
+}
+
 #endif /* MBEDTLS_PSA_CRYPTO_C */
diff --git a/library/psa_crypto_cipher.c b/library/psa_crypto_cipher.c
index a45fb0f..881d673 100644
--- a/library/psa_crypto_cipher.c
+++ b/library/psa_crypto_cipher.c
@@ -532,7 +532,11 @@
                                        output_length);
     } else
 #endif /* MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING */
-    {
+    if (input_length == 0) {
+        /* There is no input, nothing to be done */
+        *output_length = 0;
+        status = PSA_SUCCESS;
+    } else {
         status = mbedtls_to_psa_error(
             mbedtls_cipher_update(&operation->ctx.cipher, input,
                                   input_length, output, output_length));
diff --git a/library/psa_crypto_core.h b/library/psa_crypto_core.h
index d4bdf92..9462d2e 100644
--- a/library/psa_crypto_core.h
+++ b/library/psa_crypto_core.h
@@ -884,4 +884,74 @@
 psa_status_t mbedtls_psa_verify_hash_abort(
     mbedtls_psa_verify_hash_interruptible_operation_t *operation);
 
+typedef struct psa_crypto_local_input_s {
+    uint8_t *buffer;
+    size_t length;
+} psa_crypto_local_input_t;
+
+#define PSA_CRYPTO_LOCAL_INPUT_INIT ((psa_crypto_local_input_t) { NULL, 0 })
+
+/** Allocate a local copy of an input buffer and copy the contents into it.
+ *
+ * \param[in] input             Pointer to input buffer.
+ * \param[in] input_len         Length of the input buffer.
+ * \param[out] local_input      Pointer to a psa_crypto_local_input_t struct
+ *                              containing a local input copy.
+ * \return                      #PSA_SUCCESS, if the buffer was successfully
+ *                              copied.
+ * \return                      #PSA_ERROR_INSUFFICIENT_MEMORY, if a copy of
+ *                              the buffer cannot be allocated.
+ */
+psa_status_t psa_crypto_local_input_alloc(const uint8_t *input, size_t input_len,
+                                          psa_crypto_local_input_t *local_input);
+
+/** Free a local copy of an input buffer.
+ *
+ * \param[in] local_input       Pointer to a psa_crypto_local_input_t struct
+ *                              populated by a previous call to
+ *                              psa_crypto_local_input_alloc().
+ */
+void psa_crypto_local_input_free(psa_crypto_local_input_t *local_input);
+
+typedef struct psa_crypto_local_output_s {
+    uint8_t *original;
+    uint8_t *buffer;
+    size_t length;
+} psa_crypto_local_output_t;
+
+#define PSA_CRYPTO_LOCAL_OUTPUT_INIT ((psa_crypto_local_output_t) { NULL, NULL, 0 })
+
+/** Allocate a local copy of an output buffer.
+ *
+ * \note                        This does not copy any data from the original
+ *                              output buffer but only allocates a buffer
+ *                              whose contents will be copied back to the
+ *                              original in a future call to
+ *                              psa_crypto_local_output_free().
+ *
+ * \param[in] output            Pointer to output buffer.
+ * \param[in] output_len        Length of the output buffer.
+ * \param[out] local_output     Pointer to a psa_crypto_local_output_t struct to
+ *                              populate with the local output copy.
+ * \return                      #PSA_SUCCESS, if the buffer was successfully
+ *                              copied.
+ * \return                      #PSA_ERROR_INSUFFICIENT_MEMORY, if a copy of
+ *                              the buffer cannot be allocated.
+ */
+psa_status_t psa_crypto_local_output_alloc(uint8_t *output, size_t output_len,
+                                           psa_crypto_local_output_t *local_output);
+
+/** Copy from a local copy of an output buffer back to the original, then
+ *  free the local copy.
+ *
+ * \param[in] local_output      Pointer to a psa_crypto_local_output_t struct
+ *                              populated by a previous call to
+ *                              psa_crypto_local_output_alloc().
+ * \return                      #PSA_SUCCESS, if the local output was
+ *                              successfully copied back to the original.
+ * \return                      #PSA_ERROR_CORRUPTION_DETECTED, if the output
+ *                              could not be copied back to the original.
+ */
+psa_status_t psa_crypto_local_output_free(psa_crypto_local_output_t *local_output);
+
 #endif /* PSA_CRYPTO_CORE_H */
diff --git a/library/psa_crypto_invasive.h b/library/psa_crypto_invasive.h
index 8b445a1..51c90c6 100644
--- a/library/psa_crypto_invasive.h
+++ b/library/psa_crypto_invasive.h
@@ -72,6 +72,21 @@
 psa_status_t psa_mac_key_can_do(
     psa_algorithm_t algorithm,
     psa_key_type_t key_type);
+
+psa_status_t psa_crypto_copy_input(const uint8_t *input, size_t input_len,
+                                   uint8_t *input_copy, size_t input_copy_len);
+
+psa_status_t psa_crypto_copy_output(const uint8_t *output_copy, size_t output_copy_len,
+                                    uint8_t *output, size_t output_len);
+
+/*
+ * Test hooks to use for memory unpoisoning/poisoning in copy functions.
+ */
+extern void (*psa_input_pre_copy_hook)(const uint8_t *input, size_t input_len);
+extern void (*psa_input_post_copy_hook)(const uint8_t *input, size_t input_len);
+extern void (*psa_output_pre_copy_hook)(const uint8_t *output, size_t output_len);
+extern void (*psa_output_post_copy_hook)(const uint8_t *output, size_t output_len);
+
 #endif /* MBEDTLS_TEST_HOOKS && MBEDTLS_PSA_CRYPTO_C */
 
 #endif /* PSA_CRYPTO_INVASIVE_H */
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index ac53853..c5e0649 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -1566,6 +1566,7 @@
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
 
     ssl->state = MBEDTLS_SSL_HELLO_REQUEST;
+    ssl->tls_version = ssl->conf->max_tls_version;
 
     mbedtls_ssl_session_reset_msg_layer(ssl, partial);
 
diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c
index e8afe45..2760d76 100644
--- a/library/ssl_tls13_server.c
+++ b/library/ssl_tls13_server.c
@@ -414,6 +414,10 @@
     size_t psk_len;
     unsigned char server_computed_binder[PSA_HASH_MAX_SIZE];
 
+    if (binder_len != PSA_HASH_LENGTH(psk_hash_alg)) {
+        return SSL_TLS1_3_BINDER_DOES_NOT_MATCH;
+    }
+
     /* Get current state of handshake transcript. */
     ret = mbedtls_ssl_get_handshake_transcript(
         ssl, mbedtls_md_type_from_psa_alg(psk_hash_alg),
@@ -443,7 +447,9 @@
                           server_computed_binder, transcript_len);
     MBEDTLS_SSL_DEBUG_BUF(3, "psk binder ( received ): ", binder, binder_len);
 
-    if (mbedtls_ct_memcmp(server_computed_binder, binder, binder_len) == 0) {
+    if (mbedtls_ct_memcmp(server_computed_binder,
+                          binder,
+                          PSA_HASH_LENGTH(psk_hash_alg)) == 0) {
         return SSL_TLS1_3_BINDER_MATCH;
     }
 
diff --git a/programs/Makefile b/programs/Makefile
index 6baf465..8d1da6d 100644
--- a/programs/Makefile
+++ b/programs/Makefile
@@ -7,6 +7,9 @@
 DLOPEN_LDFLAGS ?=
 endif
 
+ifdef RECORD_PSA_STATUS_COVERAGE_LOG
+LOCAL_CFLAGS += -Werror -DRECORD_PSA_STATUS_COVERAGE_LOG
+endif
 DEP=${MBEDLIBS} ${MBEDTLS_TEST_OBJS}
 
 # Only build the dlopen test in shared library builds, and not when building
diff --git a/programs/test/CMakeLists.txt b/programs/test/CMakeLists.txt
index f91f786..0d43ffd 100644
--- a/programs/test/CMakeLists.txt
+++ b/programs/test/CMakeLists.txt
@@ -78,6 +78,9 @@
         target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
     endif()
 
+    # Request C11, required for memory poisoning
+    set_target_properties(${exe} PROPERTIES C_STANDARD 11)
+
     # This emulates "if ( ... IN_LIST ... )" which becomes available in CMake 3.3
     list(FIND executables_libs ${exe} exe_index)
     if (${exe_index} GREATER -1)
diff --git a/programs/test/metatest.c b/programs/test/metatest.c
index 5cd09bf..c52e579 100644
--- a/programs/test/metatest.c
+++ b/programs/test/metatest.c
@@ -27,11 +27,14 @@
  */
 
 
+#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>
@@ -59,6 +62,15 @@
     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 */
@@ -178,6 +190,65 @@
     /* 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.
+ */
+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 */
@@ -329,6 +400,22 @@
     { "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 },
diff --git a/scripts/config.py b/scripts/config.py
index ab0e5ea..c53f9e7 100755
--- a/scripts/config.py
+++ b/scripts/config.py
@@ -198,6 +198,7 @@
     'MBEDTLS_NO_UDBL_DIVISION', # influences anything that uses bignum
     'MBEDTLS_PSA_P256M_DRIVER_ENABLED', # influences SECP256R1 KeyGen/ECDH/ECDSA
     'MBEDTLS_PLATFORM_NO_STD_FUNCTIONS', # removes a feature
+    'MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS', # removes a feature
     'MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG', # behavior change + build dependency
     'MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER', # incompatible with USE_PSA_CRYPTO
     'MBEDTLS_PSA_CRYPTO_SPM', # platform dependency (PSA SPM)
diff --git a/scripts/data_files/driver_templates/psa_crypto_driver_wrappers_no_static.c.jinja b/scripts/data_files/driver_templates/psa_crypto_driver_wrappers_no_static.c.jinja
index 261cd2a..f612cf0 100644
--- a/scripts/data_files/driver_templates/psa_crypto_driver_wrappers_no_static.c.jinja
+++ b/scripts/data_files/driver_templates/psa_crypto_driver_wrappers_no_static.c.jinja
@@ -206,11 +206,11 @@
     psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
     switch( location )
     {
-#if defined(PSA_CRYPTO_DRIVER_TEST)
+#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
 {% with nest_indent=8 %}
 {% include "OS-template-opaque.jinja" -%}
 {% endwith -%}
-#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
         default:
             (void) slot_number;
             (void) key_buffer;
diff --git a/scripts/mbedtls_dev/c_parsing_helper.py b/scripts/mbedtls_dev/c_parsing_helper.py
new file mode 100644
index 0000000..2657b7d
--- /dev/null
+++ b/scripts/mbedtls_dev/c_parsing_helper.py
@@ -0,0 +1,131 @@
+"""Helper functions to parse C code in heavily constrained scenarios.
+
+Currently supported functionality:
+
+* read_function_declarations: read function declarations from a header file.
+"""
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+### WARNING: the code in this file has not been extensively reviewed yet.
+### We do not think it is harmful, but it may be below our normal standards
+### for robustness and maintainability.
+
+import re
+from typing import Dict, Iterable, Iterator, List, Optional, Tuple
+
+
+class ArgumentInfo:
+    """Information about an argument to an API function."""
+    #pylint: disable=too-few-public-methods
+
+    _KEYWORDS = [
+        'const', 'register', 'restrict',
+        'int', 'long', 'short', 'signed', 'unsigned',
+    ]
+    _DECLARATION_RE = re.compile(
+        r'(?P<type>\w[\w\s*]*?)\s*' +
+        r'(?!(?:' + r'|'.join(_KEYWORDS) + r'))(?P<name>\b\w+\b)?' +
+        r'\s*(?P<suffix>\[[^][]*\])?\Z',
+        re.A | re.S)
+
+    @classmethod
+    def normalize_type(cls, typ: str) -> str:
+        """Normalize whitespace in a type."""
+        typ = re.sub(r'\s+', r' ', typ)
+        typ = re.sub(r'\s*\*', r' *', typ)
+        return typ
+
+    def __init__(self, decl: str) -> None:
+        self.decl = decl.strip()
+        m = self._DECLARATION_RE.match(self.decl)
+        if not m:
+            raise ValueError(self.decl)
+        self.type = self.normalize_type(m.group('type')) #type: str
+        self.name = m.group('name') #type: Optional[str]
+        self.suffix = m.group('suffix') if m.group('suffix') else '' #type: str
+
+
+class FunctionInfo:
+    """Information about an API function."""
+    #pylint: disable=too-few-public-methods
+
+    # Regex matching the declaration of a function that returns void.
+    VOID_RE = re.compile(r'\s*\bvoid\s*\Z', re.A)
+
+    def __init__(self, #pylint: disable=too-many-arguments
+                 filename: str,
+                 line_number: int,
+                 qualifiers: Iterable[str],
+                 return_type: str,
+                 name: str,
+                 arguments: List[str]) -> None:
+        self.filename = filename
+        self.line_number = line_number
+        self.qualifiers = frozenset(qualifiers)
+        self.return_type = return_type
+        self.name = name
+        self.arguments = [ArgumentInfo(arg) for arg in arguments]
+
+    def returns_void(self) -> bool:
+        """Whether the function returns void."""
+        return bool(self.VOID_RE.search(self.return_type))
+
+
+# Match one C comment.
+# Note that we match both comment types, so things like // in a /*...*/
+# comment are handled correctly.
+_C_COMMENT_RE = re.compile(r'//(?:[^\n]|\\\n)*|/\*.*?\*/', re.S)
+_NOT_NEWLINES_RE = re.compile(r'[^\n]+')
+
+def read_logical_lines(filename: str) -> Iterator[Tuple[int, str]]:
+    """Read logical lines from a file.
+
+    Logical lines are one or more physical line, with balanced parentheses.
+    """
+    with open(filename, encoding='utf-8') as inp:
+        content = inp.read()
+    # Strip comments, but keep newlines for line numbering
+    content = re.sub(_C_COMMENT_RE,
+                     lambda m: re.sub(_NOT_NEWLINES_RE, "", m.group(0)),
+                     content)
+    lines = enumerate(content.splitlines(), 1)
+    for line_number, line in lines:
+        # Read a logical line, containing balanced parentheses.
+        # We assume that parentheses are balanced (this should be ok
+        # since comments have been stripped), otherwise there will be
+        # a gigantic logical line at the end.
+        paren_level = line.count('(') - line.count(')')
+        while paren_level > 0:
+            _, more = next(lines) #pylint: disable=stop-iteration-return
+            paren_level += more.count('(') - more.count(')')
+            line += '\n' + more
+        yield line_number, line
+
+_C_FUNCTION_DECLARATION_RE = re.compile(
+    r'(?P<qualifiers>(?:(?:extern|inline|static)\b\s*)*)'
+    r'(?P<return_type>\w[\w\s*]*?)\s*' +
+    r'\b(?P<name>\w+)' +
+    r'\s*\((?P<arguments>.*)\)\s*;',
+    re.A | re.S)
+
+def read_function_declarations(functions: Dict[str, FunctionInfo],
+                               filename: str) -> None:
+    """Collect function declarations from a C header file."""
+    for line_number, line in read_logical_lines(filename):
+        m = _C_FUNCTION_DECLARATION_RE.match(line)
+        if not m:
+            continue
+        qualifiers = m.group('qualifiers').split()
+        return_type = m.group('return_type')
+        name = m.group('name')
+        arguments = m.group('arguments').split(',')
+        if len(arguments) == 1 and re.match(FunctionInfo.VOID_RE, arguments[0]):
+            arguments = []
+        # Note: we replace any existing declaration for the same name.
+        functions[name] = FunctionInfo(filename, line_number,
+                                       qualifiers,
+                                       return_type,
+                                       name,
+                                       arguments)
diff --git a/scripts/mbedtls_dev/c_wrapper_generator.py b/scripts/mbedtls_dev/c_wrapper_generator.py
new file mode 100644
index 0000000..3cf1e05
--- /dev/null
+++ b/scripts/mbedtls_dev/c_wrapper_generator.py
@@ -0,0 +1,473 @@
+"""Generate C wrapper functions.
+"""
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+### WARNING: the code in this file has not been extensively reviewed yet.
+### We do not think it is harmful, but it may be below our normal standards
+### for robustness and maintainability.
+
+import os
+import re
+import sys
+import typing
+from typing import Dict, List, Optional, Tuple
+
+from .c_parsing_helper import ArgumentInfo, FunctionInfo
+from . import typing_util
+
+
+def c_declare(prefix: str, name: str, suffix: str) -> str:
+    """Format a declaration of name with the given type prefix and suffix."""
+    if not prefix.endswith('*'):
+        prefix += ' '
+    return prefix + name + suffix
+
+
+WrapperInfo = typing.NamedTuple('WrapperInfo', [
+    ('argument_names', List[str]),
+    ('guard', Optional[str]),
+    ('wrapper_name', str),
+])
+
+
+class Base:
+    """Generate a C source file containing wrapper functions."""
+
+    # This class is designed to have many methods potentially overloaded.
+    # Tell pylint not to complain about methods that have unused arguments:
+    # child classes are likely to override those methods and need the
+    # arguments in question.
+    #pylint: disable=no-self-use,unused-argument
+
+    # Prefix prepended to the function's name to form the wrapper name.
+    _WRAPPER_NAME_PREFIX = ''
+    # Suffix appended to the function's name to form the wrapper name.
+    _WRAPPER_NAME_SUFFIX = '_wrap'
+
+    # Functions with one of these qualifiers are skipped.
+    _SKIP_FUNCTION_WITH_QUALIFIERS = frozenset(['inline', 'static'])
+
+    def __init__(self):
+        """Construct a wrapper generator object.
+        """
+        self.program_name = os.path.basename(sys.argv[0])
+        # To be populated in a derived class
+        self.functions = {} #type: Dict[str, FunctionInfo]
+        # Preprocessor symbol used as a guard against multiple inclusion in the
+        # header. Must be set before writing output to a header.
+        # Not used when writing .c output.
+        self.header_guard = None #type: Optional[str]
+
+    def _write_prologue(self, out: typing_util.Writable, header: bool) -> None:
+        """Write the prologue of a C file.
+
+        This includes a description comment and some include directives.
+        """
+        out.write("""/* Automatically generated by {}, do not edit! */
+
+/* Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+"""
+                  .format(self.program_name))
+        if header:
+            out.write("""
+#ifndef {guard}
+#define {guard}
+
+#ifdef __cplusplus
+extern "C" {{
+#endif
+"""
+                      .format(guard=self.header_guard))
+        out.write("""
+#include <mbedtls/build_info.h>
+""")
+
+    def _write_epilogue(self, out: typing_util.Writable, header: bool) -> None:
+        """Write the epilogue of a C file.
+        """
+        if header:
+            out.write("""
+#ifdef __cplusplus
+}}
+#endif
+
+#endif /* {guard} */
+"""
+                      .format(guard=self.header_guard))
+        out.write("""
+/* End of automatically generated file. */
+""")
+
+    def _wrapper_function_name(self, original_name: str) -> str:
+        """The name of the wrapper function.
+
+        By default, this adds a suffix.
+        """
+        return (self._WRAPPER_NAME_PREFIX +
+                original_name +
+                self._WRAPPER_NAME_SUFFIX)
+
+    def _wrapper_declaration_start(self,
+                                   function: FunctionInfo,
+                                   wrapper_name: str) -> str:
+        """The beginning of the wrapper function declaration.
+
+        This ends just before the opening parenthesis of the argument list.
+
+        This is a string containing at least the return type and the
+        function name. It may start with additional qualifiers or attributes
+        such as `static`, `__attribute__((...))`, etc.
+        """
+        return c_declare(function.return_type, wrapper_name, '')
+
+    def _argument_name(self,
+                       function_name: str,
+                       num: int,
+                       arg: ArgumentInfo) -> str:
+        """Name to use for the given argument in the wrapper function.
+
+        Argument numbers count from 0.
+        """
+        name = 'arg' + str(num)
+        if arg.name:
+            name += '_' + arg.name
+        return name
+
+    def _wrapper_declaration_argument(self,
+                                      function_name: str,
+                                      num: int, name: str,
+                                      arg: ArgumentInfo) -> str:
+        """One argument definition in the wrapper function declaration.
+
+        Argument numbers count from 0.
+        """
+        return c_declare(arg.type, name, arg.suffix)
+
+    def _underlying_function_name(self, function: FunctionInfo) -> str:
+        """The name of the underlying function.
+
+        By default, this is the name of the wrapped function.
+        """
+        return function.name
+
+    def _return_variable_name(self, function: FunctionInfo) -> str:
+        """The name of the variable that will contain the return value."""
+        return 'retval'
+
+    def _write_function_call(self, out: typing_util.Writable,
+                             function: FunctionInfo,
+                             argument_names: List[str]) -> None:
+        """Write the call to the underlying function.
+        """
+        # Note that the function name is in parentheses, to avoid calling
+        # a function-like macro with the same name, since in typical usage
+        # there is a function-like macro with the same name which is the
+        # wrapper.
+        call = '({})({})'.format(self._underlying_function_name(function),
+                                 ', '.join(argument_names))
+        if function.returns_void():
+            out.write('    {};\n'.format(call))
+        else:
+            ret_name = self._return_variable_name(function)
+            ret_decl = c_declare(function.return_type, ret_name, '')
+            out.write('    {} = {};\n'.format(ret_decl, call))
+
+    def _write_function_return(self, out: typing_util.Writable,
+                               function: FunctionInfo,
+                               if_void: bool = False) -> None:
+        """Write a return statement.
+
+        If the function returns void, only write a statement if if_void is true.
+        """
+        if function.returns_void():
+            if if_void:
+                out.write('    return;\n')
+        else:
+            ret_name = self._return_variable_name(function)
+            out.write('    return {};\n'.format(ret_name))
+
+    def _write_function_body(self, out: typing_util.Writable,
+                             function: FunctionInfo,
+                             argument_names: List[str]) -> None:
+        """Write the body of the wrapper code for the specified function.
+        """
+        self._write_function_call(out, function, argument_names)
+        self._write_function_return(out, function)
+
+    def _skip_function(self, function: FunctionInfo) -> bool:
+        """Whether to skip this function.
+
+        By default, static or inline functions are skipped.
+        """
+        if not self._SKIP_FUNCTION_WITH_QUALIFIERS.isdisjoint(function.qualifiers):
+            return True
+        return False
+
+    _FUNCTION_GUARDS = {
+    } #type: Dict[str, str]
+
+    def _function_guard(self, function: FunctionInfo) -> Optional[str]:
+        """A preprocessor condition for this function.
+
+        The wrapper will be guarded with `#if` on this condition, if not None.
+        """
+        return self._FUNCTION_GUARDS.get(function.name)
+
+    def _wrapper_info(self, function: FunctionInfo) -> Optional[WrapperInfo]:
+        """Information about the wrapper for one function.
+
+        Return None if the function should be skipped.
+        """
+        if self._skip_function(function):
+            return None
+        argument_names = [self._argument_name(function.name, num, arg)
+                          for num, arg in enumerate(function.arguments)]
+        return WrapperInfo(
+            argument_names=argument_names,
+            guard=self._function_guard(function),
+            wrapper_name=self._wrapper_function_name(function.name),
+        )
+
+    def _write_function_prototype(self, out: typing_util.Writable,
+                                  function: FunctionInfo,
+                                  wrapper: WrapperInfo,
+                                  header: bool) -> None:
+        """Write the prototype of a wrapper function.
+
+        If header is true, write a function declaration, with a semicolon at
+        the end. Otherwise just write the prototype, intended to be followed
+        by the function's body.
+        """
+        declaration_start = self._wrapper_declaration_start(function,
+                                                            wrapper.wrapper_name)
+        arg_indent = '    '
+        terminator = ';\n' if header else '\n'
+        if function.arguments:
+            out.write(declaration_start + '(\n')
+            for num in range(len(function.arguments)):
+                arg_def = self._wrapper_declaration_argument(
+                    function.name,
+                    num, wrapper.argument_names[num], function.arguments[num])
+                arg_terminator = \
+                    (')' + terminator if num == len(function.arguments) - 1 else
+                     ',\n')
+                out.write(arg_indent + arg_def + arg_terminator)
+        else:
+            out.write(declaration_start + '(void)' + terminator)
+
+    def _write_c_function(self, out: typing_util.Writable,
+                          function: FunctionInfo) -> None:
+        """Write wrapper code for one function.
+
+        Do nothing if the function is skipped.
+        """
+        wrapper = self._wrapper_info(function)
+        if wrapper is None:
+            return
+        out.write("""
+/* Wrapper for {} */
+"""
+                  .format(function.name))
+        if wrapper.guard is not None:
+            out.write('#if {}\n'.format(wrapper.guard))
+        self._write_function_prototype(out, function, wrapper, False)
+        out.write('{\n')
+        self._write_function_body(out, function, wrapper.argument_names)
+        out.write('}\n')
+        if wrapper.guard is not None:
+            out.write('#endif /* {} */\n'.format(wrapper.guard))
+
+    def _write_h_function_declaration(self, out: typing_util.Writable,
+                                      function: FunctionInfo,
+                                      wrapper: WrapperInfo) -> None:
+        """Write the declaration of one wrapper function.
+        """
+        self._write_function_prototype(out, function, wrapper, True)
+
+    def _write_h_macro_definition(self, out: typing_util.Writable,
+                                  function: FunctionInfo,
+                                  wrapper: WrapperInfo) -> None:
+        """Write the macro definition for one wrapper.
+        """
+        arg_list = ', '.join(wrapper.argument_names)
+        out.write('#define {function_name}({args}) \\\n    {wrapper_name}({args})\n'
+                  .format(function_name=function.name,
+                          wrapper_name=wrapper.wrapper_name,
+                          args=arg_list))
+
+    def _write_h_function(self, out: typing_util.Writable,
+                          function: FunctionInfo) -> None:
+        """Write the complete header content for one wrapper.
+
+        This is the declaration of the wrapper function, and the
+        definition of a function-like macro that calls the wrapper function.
+
+        Do nothing if the function is skipped.
+        """
+        wrapper = self._wrapper_info(function)
+        if wrapper is None:
+            return
+        out.write('\n')
+        if wrapper.guard is not None:
+            out.write('#if {}\n'.format(wrapper.guard))
+        self._write_h_function_declaration(out, function, wrapper)
+        self._write_h_macro_definition(out, function, wrapper)
+        if wrapper.guard is not None:
+            out.write('#endif /* {} */\n'.format(wrapper.guard))
+
+    def write_c_file(self, filename: str) -> None:
+        """Output a whole C file containing function wrapper definitions."""
+        with open(filename, 'w', encoding='utf-8') as out:
+            self._write_prologue(out, False)
+            for name in sorted(self.functions):
+                self._write_c_function(out, self.functions[name])
+            self._write_epilogue(out, False)
+
+    def _header_guard_from_file_name(self, filename: str) -> str:
+        """Preprocessor symbol used as a guard against multiple inclusion."""
+        # Heuristic to strip irrelevant leading directories
+        filename = re.sub(r'.*include[\\/]', r'', filename)
+        return re.sub(r'[^0-9A-Za-z]', r'_', filename, re.A).upper()
+
+    def write_h_file(self, filename: str) -> None:
+        """Output a header file with function wrapper declarations and macro definitions."""
+        self.header_guard = self._header_guard_from_file_name(filename)
+        with open(filename, 'w', encoding='utf-8') as out:
+            self._write_prologue(out, True)
+            for name in sorted(self.functions):
+                self._write_h_function(out, self.functions[name])
+            self._write_epilogue(out, True)
+
+
+class UnknownTypeForPrintf(Exception):
+    """Exception raised when attempting to generate code that logs a value of an unknown type."""
+
+    def __init__(self, typ: str) -> None:
+        super().__init__("Unknown type for printf format generation: " + typ)
+
+
+class Logging(Base):
+    """Generate wrapper functions that log the inputs and outputs."""
+
+    def __init__(self) -> None:
+        """Construct a wrapper generator including logging of inputs and outputs.
+
+        Log to stdout by default. Call `set_stream` to change this.
+        """
+        super().__init__()
+        self.stream = 'stdout'
+
+    def set_stream(self, stream: str) -> None:
+        """Set the stdio stream to log to.
+
+        Call this method before calling `write_c_output` or `write_h_output`.
+        """
+        self.stream = stream
+
+    def _write_prologue(self, out: typing_util.Writable, header: bool) -> None:
+        super()._write_prologue(out, header)
+        if not header:
+            out.write("""
+#if defined(MBEDTLS_FS_IO) && defined(MBEDTLS_TEST_HOOKS)
+#include <stdio.h>
+#include <inttypes.h>
+#include <mbedtls/debug.h> // for MBEDTLS_PRINTF_SIZET
+#include <mbedtls/platform.h> // for mbedtls_fprintf
+#endif /* defined(MBEDTLS_FS_IO) && defined(MBEDTLS_TEST_HOOKS) */
+""")
+
+    _PRINTF_SIMPLE_FORMAT = {
+        'int': '%d',
+        'long': '%ld',
+        'long long': '%lld',
+        'size_t': '%"MBEDTLS_PRINTF_SIZET"',
+        'unsigned': '0x%08x',
+        'unsigned int': '0x%08x',
+        'unsigned long': '0x%08lx',
+        'unsigned long long': '0x%016llx',
+    }
+
+    def _printf_simple_format(self, typ: str) -> Optional[str]:
+        """Use this printf format for a value of typ.
+
+        Return None if values of typ need more complex handling.
+        """
+        return self._PRINTF_SIMPLE_FORMAT.get(typ)
+
+    _PRINTF_TYPE_CAST = {
+        'int32_t': 'int',
+        'uint32_t': 'unsigned',
+        'uint64_t': 'unsigned long long',
+    } #type: Dict[str, str]
+
+    def _printf_type_cast(self, typ: str) -> Optional[str]:
+        """Cast values of typ to this type before passing them to printf.
+
+        Return None if values of the given type do not need a cast.
+        """
+        return self._PRINTF_TYPE_CAST.get(typ)
+
+    _POINTER_TYPE_RE = re.compile(r'\s*\*\Z')
+
+    def _printf_parameters(self, typ: str, var: str) -> Tuple[str, List[str]]:
+        """The printf format and arguments for a value of type typ stored in var.
+        """
+        expr = var
+        base_type = typ
+        # For outputs via a pointer, get the value that has been written.
+        # Note: we don't support pointers to pointers here.
+        pointer_match = self._POINTER_TYPE_RE.search(base_type)
+        if pointer_match:
+            base_type = base_type[:pointer_match.start(0)]
+            expr = '*({})'.format(expr)
+        # Maybe cast the value to a standard type.
+        cast_to = self._printf_type_cast(base_type)
+        if cast_to is not None:
+            expr = '({}) {}'.format(cast_to, expr)
+            base_type = cast_to
+        # Try standard types.
+        fmt = self._printf_simple_format(base_type)
+        if fmt is not None:
+            return '{}={}'.format(var, fmt), [expr]
+        raise UnknownTypeForPrintf(typ)
+
+    def _write_function_logging(self, out: typing_util.Writable,
+                                function: FunctionInfo,
+                                argument_names: List[str]) -> None:
+        """Write code to log the function's inputs and outputs."""
+        formats, values = '%s', ['"' + function.name + '"']
+        for arg_info, arg_name in zip(function.arguments, argument_names):
+            fmt, vals = self._printf_parameters(arg_info.type, arg_name)
+            if fmt:
+                formats += ' ' + fmt
+                values += vals
+        if not function.returns_void():
+            ret_name = self._return_variable_name(function)
+            fmt, vals = self._printf_parameters(function.return_type, ret_name)
+            if fmt:
+                formats += ' ' + fmt
+                values += vals
+        out.write("""\
+#if defined(MBEDTLS_FS_IO) && defined(MBEDTLS_TEST_HOOKS)
+    if ({stream}) {{
+        mbedtls_fprintf({stream}, "{formats}\\n",
+                        {values});
+    }}
+#endif /* defined(MBEDTLS_FS_IO) && defined(MBEDTLS_TEST_HOOKS) */
+"""
+                  .format(stream=self.stream,
+                          formats=formats,
+                          values=', '.join(values)))
+
+    def _write_function_body(self, out: typing_util.Writable,
+                             function: FunctionInfo,
+                             argument_names: List[str]) -> None:
+        """Write the body of the wrapper code for the specified function.
+        """
+        self._write_function_call(out, function, argument_names)
+        self._write_function_logging(out, function, argument_names)
+        self._write_function_return(out, function)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 70f5bc9..589643a 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -252,6 +252,8 @@
     target_include_directories(test_suite_${data_name}
         PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
         PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../library)
+    # Request C11, which is needed for memory poisoning tests
+    set_target_properties(test_suite_${data_name} PROPERTIES C_STANDARD 11)
 
     if(${data_name} MATCHES ${SKIP_TEST_SUITES_REGEX})
         message(STATUS "The test suite ${data_name} will not be executed.")
diff --git a/tests/include/test/memory.h b/tests/include/test/memory.h
new file mode 100644
index 0000000..940d9e6
--- /dev/null
+++ b/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/tests/include/test/psa_crypto_helpers.h b/tests/include/test/psa_crypto_helpers.h
index 41d204d..7306d8e 100644
--- a/tests/include/test/psa_crypto_helpers.h
+++ b/tests/include/test/psa_crypto_helpers.h
@@ -16,7 +16,6 @@
 #include <psa/crypto.h>
 #endif
 
-
 #if defined(MBEDTLS_PSA_CRYPTO_C)
 /** Initialize the PSA Crypto subsystem. */
 #define PSA_INIT() PSA_ASSERT(psa_crypto_init())
diff --git a/tests/include/test/psa_memory_poisoning_wrappers.h b/tests/include/test/psa_memory_poisoning_wrappers.h
new file mode 100644
index 0000000..3f30b65
--- /dev/null
+++ b/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/tests/include/test/psa_test_wrappers.h b/tests/include/test/psa_test_wrappers.h
new file mode 100644
index 0000000..ecf926e
--- /dev/null
+++ b/tests/include/test/psa_test_wrappers.h
@@ -0,0 +1,739 @@
+/* Automatically generated by generate_psa_wrappers.py, do not edit! */
+
+/* Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef TEST_PSA_TEST_WRAPPERS_H
+#define TEST_PSA_TEST_WRAPPERS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <mbedtls/build_info.h>
+
+#if defined(MBEDTLS_PSA_CRYPTO_C) && defined(MBEDTLS_TEST_HOOKS) && \
+    !defined(RECORD_PSA_STATUS_COVERAGE_LOG)
+
+#include <psa/crypto.h>
+
+#include <test/memory.h>
+#include <test/psa_crypto_helpers.h>
+#include <test/psa_test_wrappers.h>
+
+#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
+psa_status_t mbedtls_test_wrap_mbedtls_psa_inject_entropy(
+    const uint8_t *arg0_seed,
+    size_t arg1_seed_size);
+#define mbedtls_psa_inject_entropy(arg0_seed, arg1_seed_size) \
+    mbedtls_test_wrap_mbedtls_psa_inject_entropy(arg0_seed, arg1_seed_size)
+#endif /* defined(MBEDTLS_PSA_INJECT_ENTROPY) */
+
+#if defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)
+psa_status_t mbedtls_test_wrap_mbedtls_psa_platform_get_builtin_key(
+    mbedtls_svc_key_id_t arg0_key_id,
+    psa_key_lifetime_t *arg1_lifetime,
+    psa_drv_slot_number_t *arg2_slot_number);
+#define mbedtls_psa_platform_get_builtin_key(arg0_key_id, arg1_lifetime, arg2_slot_number) \
+    mbedtls_test_wrap_mbedtls_psa_platform_get_builtin_key(arg0_key_id, arg1_lifetime, arg2_slot_number)
+#endif /* defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS) */
+
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+psa_status_t mbedtls_test_wrap_mbedtls_psa_register_se_key(
+    const psa_key_attributes_t *arg0_attributes);
+#define mbedtls_psa_register_se_key(arg0_attributes) \
+    mbedtls_test_wrap_mbedtls_psa_register_se_key(arg0_attributes)
+#endif /* defined(MBEDTLS_PSA_CRYPTO_SE_C) */
+
+psa_status_t mbedtls_test_wrap_psa_aead_abort(
+    psa_aead_operation_t *arg0_operation);
+#define psa_aead_abort(arg0_operation) \
+    mbedtls_test_wrap_psa_aead_abort(arg0_operation)
+
+psa_status_t mbedtls_test_wrap_psa_aead_decrypt(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_nonce,
+    size_t arg3_nonce_length,
+    const uint8_t *arg4_additional_data,
+    size_t arg5_additional_data_length,
+    const uint8_t *arg6_ciphertext,
+    size_t arg7_ciphertext_length,
+    uint8_t *arg8_plaintext,
+    size_t arg9_plaintext_size,
+    size_t *arg10_plaintext_length);
+#define psa_aead_decrypt(arg0_key, arg1_alg, arg2_nonce, arg3_nonce_length, arg4_additional_data, arg5_additional_data_length, arg6_ciphertext, arg7_ciphertext_length, arg8_plaintext, arg9_plaintext_size, arg10_plaintext_length) \
+    mbedtls_test_wrap_psa_aead_decrypt(arg0_key, arg1_alg, arg2_nonce, arg3_nonce_length, arg4_additional_data, arg5_additional_data_length, arg6_ciphertext, arg7_ciphertext_length, arg8_plaintext, arg9_plaintext_size, arg10_plaintext_length)
+
+psa_status_t mbedtls_test_wrap_psa_aead_decrypt_setup(
+    psa_aead_operation_t *arg0_operation,
+    mbedtls_svc_key_id_t arg1_key,
+    psa_algorithm_t arg2_alg);
+#define psa_aead_decrypt_setup(arg0_operation, arg1_key, arg2_alg) \
+    mbedtls_test_wrap_psa_aead_decrypt_setup(arg0_operation, arg1_key, arg2_alg)
+
+psa_status_t mbedtls_test_wrap_psa_aead_encrypt(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_nonce,
+    size_t arg3_nonce_length,
+    const uint8_t *arg4_additional_data,
+    size_t arg5_additional_data_length,
+    const uint8_t *arg6_plaintext,
+    size_t arg7_plaintext_length,
+    uint8_t *arg8_ciphertext,
+    size_t arg9_ciphertext_size,
+    size_t *arg10_ciphertext_length);
+#define psa_aead_encrypt(arg0_key, arg1_alg, arg2_nonce, arg3_nonce_length, arg4_additional_data, arg5_additional_data_length, arg6_plaintext, arg7_plaintext_length, arg8_ciphertext, arg9_ciphertext_size, arg10_ciphertext_length) \
+    mbedtls_test_wrap_psa_aead_encrypt(arg0_key, arg1_alg, arg2_nonce, arg3_nonce_length, arg4_additional_data, arg5_additional_data_length, arg6_plaintext, arg7_plaintext_length, arg8_ciphertext, arg9_ciphertext_size, arg10_ciphertext_length)
+
+psa_status_t mbedtls_test_wrap_psa_aead_encrypt_setup(
+    psa_aead_operation_t *arg0_operation,
+    mbedtls_svc_key_id_t arg1_key,
+    psa_algorithm_t arg2_alg);
+#define psa_aead_encrypt_setup(arg0_operation, arg1_key, arg2_alg) \
+    mbedtls_test_wrap_psa_aead_encrypt_setup(arg0_operation, arg1_key, arg2_alg)
+
+psa_status_t mbedtls_test_wrap_psa_aead_finish(
+    psa_aead_operation_t *arg0_operation,
+    uint8_t *arg1_ciphertext,
+    size_t arg2_ciphertext_size,
+    size_t *arg3_ciphertext_length,
+    uint8_t *arg4_tag,
+    size_t arg5_tag_size,
+    size_t *arg6_tag_length);
+#define psa_aead_finish(arg0_operation, arg1_ciphertext, arg2_ciphertext_size, arg3_ciphertext_length, arg4_tag, arg5_tag_size, arg6_tag_length) \
+    mbedtls_test_wrap_psa_aead_finish(arg0_operation, arg1_ciphertext, arg2_ciphertext_size, arg3_ciphertext_length, arg4_tag, arg5_tag_size, arg6_tag_length)
+
+psa_status_t mbedtls_test_wrap_psa_aead_generate_nonce(
+    psa_aead_operation_t *arg0_operation,
+    uint8_t *arg1_nonce,
+    size_t arg2_nonce_size,
+    size_t *arg3_nonce_length);
+#define psa_aead_generate_nonce(arg0_operation, arg1_nonce, arg2_nonce_size, arg3_nonce_length) \
+    mbedtls_test_wrap_psa_aead_generate_nonce(arg0_operation, arg1_nonce, arg2_nonce_size, arg3_nonce_length)
+
+psa_status_t mbedtls_test_wrap_psa_aead_set_lengths(
+    psa_aead_operation_t *arg0_operation,
+    size_t arg1_ad_length,
+    size_t arg2_plaintext_length);
+#define psa_aead_set_lengths(arg0_operation, arg1_ad_length, arg2_plaintext_length) \
+    mbedtls_test_wrap_psa_aead_set_lengths(arg0_operation, arg1_ad_length, arg2_plaintext_length)
+
+psa_status_t mbedtls_test_wrap_psa_aead_set_nonce(
+    psa_aead_operation_t *arg0_operation,
+    const uint8_t *arg1_nonce,
+    size_t arg2_nonce_length);
+#define psa_aead_set_nonce(arg0_operation, arg1_nonce, arg2_nonce_length) \
+    mbedtls_test_wrap_psa_aead_set_nonce(arg0_operation, arg1_nonce, arg2_nonce_length)
+
+psa_status_t mbedtls_test_wrap_psa_aead_update(
+    psa_aead_operation_t *arg0_operation,
+    const uint8_t *arg1_input,
+    size_t arg2_input_length,
+    uint8_t *arg3_output,
+    size_t arg4_output_size,
+    size_t *arg5_output_length);
+#define psa_aead_update(arg0_operation, arg1_input, arg2_input_length, arg3_output, arg4_output_size, arg5_output_length) \
+    mbedtls_test_wrap_psa_aead_update(arg0_operation, arg1_input, arg2_input_length, arg3_output, arg4_output_size, arg5_output_length)
+
+psa_status_t mbedtls_test_wrap_psa_aead_update_ad(
+    psa_aead_operation_t *arg0_operation,
+    const uint8_t *arg1_input,
+    size_t arg2_input_length);
+#define psa_aead_update_ad(arg0_operation, arg1_input, arg2_input_length) \
+    mbedtls_test_wrap_psa_aead_update_ad(arg0_operation, arg1_input, arg2_input_length)
+
+psa_status_t mbedtls_test_wrap_psa_aead_verify(
+    psa_aead_operation_t *arg0_operation,
+    uint8_t *arg1_plaintext,
+    size_t arg2_plaintext_size,
+    size_t *arg3_plaintext_length,
+    const uint8_t *arg4_tag,
+    size_t arg5_tag_length);
+#define psa_aead_verify(arg0_operation, arg1_plaintext, arg2_plaintext_size, arg3_plaintext_length, arg4_tag, arg5_tag_length) \
+    mbedtls_test_wrap_psa_aead_verify(arg0_operation, arg1_plaintext, arg2_plaintext_size, arg3_plaintext_length, arg4_tag, arg5_tag_length)
+
+psa_status_t mbedtls_test_wrap_psa_asymmetric_decrypt(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_input,
+    size_t arg3_input_length,
+    const uint8_t *arg4_salt,
+    size_t arg5_salt_length,
+    uint8_t *arg6_output,
+    size_t arg7_output_size,
+    size_t *arg8_output_length);
+#define psa_asymmetric_decrypt(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_salt, arg5_salt_length, arg6_output, arg7_output_size, arg8_output_length) \
+    mbedtls_test_wrap_psa_asymmetric_decrypt(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_salt, arg5_salt_length, arg6_output, arg7_output_size, arg8_output_length)
+
+psa_status_t mbedtls_test_wrap_psa_asymmetric_encrypt(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_input,
+    size_t arg3_input_length,
+    const uint8_t *arg4_salt,
+    size_t arg5_salt_length,
+    uint8_t *arg6_output,
+    size_t arg7_output_size,
+    size_t *arg8_output_length);
+#define psa_asymmetric_encrypt(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_salt, arg5_salt_length, arg6_output, arg7_output_size, arg8_output_length) \
+    mbedtls_test_wrap_psa_asymmetric_encrypt(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_salt, arg5_salt_length, arg6_output, arg7_output_size, arg8_output_length)
+
+psa_status_t mbedtls_test_wrap_psa_cipher_abort(
+    psa_cipher_operation_t *arg0_operation);
+#define psa_cipher_abort(arg0_operation) \
+    mbedtls_test_wrap_psa_cipher_abort(arg0_operation)
+
+psa_status_t mbedtls_test_wrap_psa_cipher_decrypt(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_input,
+    size_t arg3_input_length,
+    uint8_t *arg4_output,
+    size_t arg5_output_size,
+    size_t *arg6_output_length);
+#define psa_cipher_decrypt(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_output, arg5_output_size, arg6_output_length) \
+    mbedtls_test_wrap_psa_cipher_decrypt(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_output, arg5_output_size, arg6_output_length)
+
+psa_status_t mbedtls_test_wrap_psa_cipher_decrypt_setup(
+    psa_cipher_operation_t *arg0_operation,
+    mbedtls_svc_key_id_t arg1_key,
+    psa_algorithm_t arg2_alg);
+#define psa_cipher_decrypt_setup(arg0_operation, arg1_key, arg2_alg) \
+    mbedtls_test_wrap_psa_cipher_decrypt_setup(arg0_operation, arg1_key, arg2_alg)
+
+psa_status_t mbedtls_test_wrap_psa_cipher_encrypt(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_input,
+    size_t arg3_input_length,
+    uint8_t *arg4_output,
+    size_t arg5_output_size,
+    size_t *arg6_output_length);
+#define psa_cipher_encrypt(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_output, arg5_output_size, arg6_output_length) \
+    mbedtls_test_wrap_psa_cipher_encrypt(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_output, arg5_output_size, arg6_output_length)
+
+psa_status_t mbedtls_test_wrap_psa_cipher_encrypt_setup(
+    psa_cipher_operation_t *arg0_operation,
+    mbedtls_svc_key_id_t arg1_key,
+    psa_algorithm_t arg2_alg);
+#define psa_cipher_encrypt_setup(arg0_operation, arg1_key, arg2_alg) \
+    mbedtls_test_wrap_psa_cipher_encrypt_setup(arg0_operation, arg1_key, arg2_alg)
+
+psa_status_t mbedtls_test_wrap_psa_cipher_finish(
+    psa_cipher_operation_t *arg0_operation,
+    uint8_t *arg1_output,
+    size_t arg2_output_size,
+    size_t *arg3_output_length);
+#define psa_cipher_finish(arg0_operation, arg1_output, arg2_output_size, arg3_output_length) \
+    mbedtls_test_wrap_psa_cipher_finish(arg0_operation, arg1_output, arg2_output_size, arg3_output_length)
+
+psa_status_t mbedtls_test_wrap_psa_cipher_generate_iv(
+    psa_cipher_operation_t *arg0_operation,
+    uint8_t *arg1_iv,
+    size_t arg2_iv_size,
+    size_t *arg3_iv_length);
+#define psa_cipher_generate_iv(arg0_operation, arg1_iv, arg2_iv_size, arg3_iv_length) \
+    mbedtls_test_wrap_psa_cipher_generate_iv(arg0_operation, arg1_iv, arg2_iv_size, arg3_iv_length)
+
+psa_status_t mbedtls_test_wrap_psa_cipher_set_iv(
+    psa_cipher_operation_t *arg0_operation,
+    const uint8_t *arg1_iv,
+    size_t arg2_iv_length);
+#define psa_cipher_set_iv(arg0_operation, arg1_iv, arg2_iv_length) \
+    mbedtls_test_wrap_psa_cipher_set_iv(arg0_operation, arg1_iv, arg2_iv_length)
+
+psa_status_t mbedtls_test_wrap_psa_cipher_update(
+    psa_cipher_operation_t *arg0_operation,
+    const uint8_t *arg1_input,
+    size_t arg2_input_length,
+    uint8_t *arg3_output,
+    size_t arg4_output_size,
+    size_t *arg5_output_length);
+#define psa_cipher_update(arg0_operation, arg1_input, arg2_input_length, arg3_output, arg4_output_size, arg5_output_length) \
+    mbedtls_test_wrap_psa_cipher_update(arg0_operation, arg1_input, arg2_input_length, arg3_output, arg4_output_size, arg5_output_length)
+
+psa_status_t mbedtls_test_wrap_psa_copy_key(
+    mbedtls_svc_key_id_t arg0_source_key,
+    const psa_key_attributes_t *arg1_attributes,
+    mbedtls_svc_key_id_t *arg2_target_key);
+#define psa_copy_key(arg0_source_key, arg1_attributes, arg2_target_key) \
+    mbedtls_test_wrap_psa_copy_key(arg0_source_key, arg1_attributes, arg2_target_key)
+
+psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_cipher_suite(
+    const psa_crypto_driver_pake_inputs_t *arg0_inputs,
+    psa_pake_cipher_suite_t *arg1_cipher_suite);
+#define psa_crypto_driver_pake_get_cipher_suite(arg0_inputs, arg1_cipher_suite) \
+    mbedtls_test_wrap_psa_crypto_driver_pake_get_cipher_suite(arg0_inputs, arg1_cipher_suite)
+
+psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_password(
+    const psa_crypto_driver_pake_inputs_t *arg0_inputs,
+    uint8_t *arg1_buffer,
+    size_t arg2_buffer_size,
+    size_t *arg3_buffer_length);
+#define psa_crypto_driver_pake_get_password(arg0_inputs, arg1_buffer, arg2_buffer_size, arg3_buffer_length) \
+    mbedtls_test_wrap_psa_crypto_driver_pake_get_password(arg0_inputs, arg1_buffer, arg2_buffer_size, arg3_buffer_length)
+
+psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_password_len(
+    const psa_crypto_driver_pake_inputs_t *arg0_inputs,
+    size_t *arg1_password_len);
+#define psa_crypto_driver_pake_get_password_len(arg0_inputs, arg1_password_len) \
+    mbedtls_test_wrap_psa_crypto_driver_pake_get_password_len(arg0_inputs, arg1_password_len)
+
+psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_peer(
+    const psa_crypto_driver_pake_inputs_t *arg0_inputs,
+    uint8_t *arg1_peer_id,
+    size_t arg2_peer_id_size,
+    size_t *arg3_peer_id_length);
+#define psa_crypto_driver_pake_get_peer(arg0_inputs, arg1_peer_id, arg2_peer_id_size, arg3_peer_id_length) \
+    mbedtls_test_wrap_psa_crypto_driver_pake_get_peer(arg0_inputs, arg1_peer_id, arg2_peer_id_size, arg3_peer_id_length)
+
+psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_peer_len(
+    const psa_crypto_driver_pake_inputs_t *arg0_inputs,
+    size_t *arg1_peer_len);
+#define psa_crypto_driver_pake_get_peer_len(arg0_inputs, arg1_peer_len) \
+    mbedtls_test_wrap_psa_crypto_driver_pake_get_peer_len(arg0_inputs, arg1_peer_len)
+
+psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_user(
+    const psa_crypto_driver_pake_inputs_t *arg0_inputs,
+    uint8_t *arg1_user_id,
+    size_t arg2_user_id_size,
+    size_t *arg3_user_id_len);
+#define psa_crypto_driver_pake_get_user(arg0_inputs, arg1_user_id, arg2_user_id_size, arg3_user_id_len) \
+    mbedtls_test_wrap_psa_crypto_driver_pake_get_user(arg0_inputs, arg1_user_id, arg2_user_id_size, arg3_user_id_len)
+
+psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_user_len(
+    const psa_crypto_driver_pake_inputs_t *arg0_inputs,
+    size_t *arg1_user_len);
+#define psa_crypto_driver_pake_get_user_len(arg0_inputs, arg1_user_len) \
+    mbedtls_test_wrap_psa_crypto_driver_pake_get_user_len(arg0_inputs, arg1_user_len)
+
+psa_status_t mbedtls_test_wrap_psa_crypto_init(void);
+#define psa_crypto_init() \
+    mbedtls_test_wrap_psa_crypto_init()
+
+psa_status_t mbedtls_test_wrap_psa_destroy_key(
+    mbedtls_svc_key_id_t arg0_key);
+#define psa_destroy_key(arg0_key) \
+    mbedtls_test_wrap_psa_destroy_key(arg0_key)
+
+psa_status_t mbedtls_test_wrap_psa_export_key(
+    mbedtls_svc_key_id_t arg0_key,
+    uint8_t *arg1_data,
+    size_t arg2_data_size,
+    size_t *arg3_data_length);
+#define psa_export_key(arg0_key, arg1_data, arg2_data_size, arg3_data_length) \
+    mbedtls_test_wrap_psa_export_key(arg0_key, arg1_data, arg2_data_size, arg3_data_length)
+
+psa_status_t mbedtls_test_wrap_psa_export_public_key(
+    mbedtls_svc_key_id_t arg0_key,
+    uint8_t *arg1_data,
+    size_t arg2_data_size,
+    size_t *arg3_data_length);
+#define psa_export_public_key(arg0_key, arg1_data, arg2_data_size, arg3_data_length) \
+    mbedtls_test_wrap_psa_export_public_key(arg0_key, arg1_data, arg2_data_size, arg3_data_length)
+
+psa_status_t mbedtls_test_wrap_psa_generate_key(
+    const psa_key_attributes_t *arg0_attributes,
+    mbedtls_svc_key_id_t *arg1_key);
+#define psa_generate_key(arg0_attributes, arg1_key) \
+    mbedtls_test_wrap_psa_generate_key(arg0_attributes, arg1_key)
+
+psa_status_t mbedtls_test_wrap_psa_generate_key_ext(
+    const psa_key_attributes_t *arg0_attributes,
+    const psa_key_production_parameters_t *arg1_params,
+    size_t arg2_params_data_length,
+    mbedtls_svc_key_id_t *arg3_key);
+#define psa_generate_key_ext(arg0_attributes, arg1_params, arg2_params_data_length, arg3_key) \
+    mbedtls_test_wrap_psa_generate_key_ext(arg0_attributes, arg1_params, arg2_params_data_length, arg3_key)
+
+psa_status_t mbedtls_test_wrap_psa_generate_random(
+    uint8_t *arg0_output,
+    size_t arg1_output_size);
+#define psa_generate_random(arg0_output, arg1_output_size) \
+    mbedtls_test_wrap_psa_generate_random(arg0_output, arg1_output_size)
+
+psa_status_t mbedtls_test_wrap_psa_get_key_attributes(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_key_attributes_t *arg1_attributes);
+#define psa_get_key_attributes(arg0_key, arg1_attributes) \
+    mbedtls_test_wrap_psa_get_key_attributes(arg0_key, arg1_attributes)
+
+psa_status_t mbedtls_test_wrap_psa_hash_abort(
+    psa_hash_operation_t *arg0_operation);
+#define psa_hash_abort(arg0_operation) \
+    mbedtls_test_wrap_psa_hash_abort(arg0_operation)
+
+psa_status_t mbedtls_test_wrap_psa_hash_clone(
+    const psa_hash_operation_t *arg0_source_operation,
+    psa_hash_operation_t *arg1_target_operation);
+#define psa_hash_clone(arg0_source_operation, arg1_target_operation) \
+    mbedtls_test_wrap_psa_hash_clone(arg0_source_operation, arg1_target_operation)
+
+psa_status_t mbedtls_test_wrap_psa_hash_compare(
+    psa_algorithm_t arg0_alg,
+    const uint8_t *arg1_input,
+    size_t arg2_input_length,
+    const uint8_t *arg3_hash,
+    size_t arg4_hash_length);
+#define psa_hash_compare(arg0_alg, arg1_input, arg2_input_length, arg3_hash, arg4_hash_length) \
+    mbedtls_test_wrap_psa_hash_compare(arg0_alg, arg1_input, arg2_input_length, arg3_hash, arg4_hash_length)
+
+psa_status_t mbedtls_test_wrap_psa_hash_compute(
+    psa_algorithm_t arg0_alg,
+    const uint8_t *arg1_input,
+    size_t arg2_input_length,
+    uint8_t *arg3_hash,
+    size_t arg4_hash_size,
+    size_t *arg5_hash_length);
+#define psa_hash_compute(arg0_alg, arg1_input, arg2_input_length, arg3_hash, arg4_hash_size, arg5_hash_length) \
+    mbedtls_test_wrap_psa_hash_compute(arg0_alg, arg1_input, arg2_input_length, arg3_hash, arg4_hash_size, arg5_hash_length)
+
+psa_status_t mbedtls_test_wrap_psa_hash_finish(
+    psa_hash_operation_t *arg0_operation,
+    uint8_t *arg1_hash,
+    size_t arg2_hash_size,
+    size_t *arg3_hash_length);
+#define psa_hash_finish(arg0_operation, arg1_hash, arg2_hash_size, arg3_hash_length) \
+    mbedtls_test_wrap_psa_hash_finish(arg0_operation, arg1_hash, arg2_hash_size, arg3_hash_length)
+
+psa_status_t mbedtls_test_wrap_psa_hash_setup(
+    psa_hash_operation_t *arg0_operation,
+    psa_algorithm_t arg1_alg);
+#define psa_hash_setup(arg0_operation, arg1_alg) \
+    mbedtls_test_wrap_psa_hash_setup(arg0_operation, arg1_alg)
+
+psa_status_t mbedtls_test_wrap_psa_hash_update(
+    psa_hash_operation_t *arg0_operation,
+    const uint8_t *arg1_input,
+    size_t arg2_input_length);
+#define psa_hash_update(arg0_operation, arg1_input, arg2_input_length) \
+    mbedtls_test_wrap_psa_hash_update(arg0_operation, arg1_input, arg2_input_length)
+
+psa_status_t mbedtls_test_wrap_psa_hash_verify(
+    psa_hash_operation_t *arg0_operation,
+    const uint8_t *arg1_hash,
+    size_t arg2_hash_length);
+#define psa_hash_verify(arg0_operation, arg1_hash, arg2_hash_length) \
+    mbedtls_test_wrap_psa_hash_verify(arg0_operation, arg1_hash, arg2_hash_length)
+
+psa_status_t mbedtls_test_wrap_psa_import_key(
+    const psa_key_attributes_t *arg0_attributes,
+    const uint8_t *arg1_data,
+    size_t arg2_data_length,
+    mbedtls_svc_key_id_t *arg3_key);
+#define psa_import_key(arg0_attributes, arg1_data, arg2_data_length, arg3_key) \
+    mbedtls_test_wrap_psa_import_key(arg0_attributes, arg1_data, arg2_data_length, arg3_key)
+
+psa_status_t mbedtls_test_wrap_psa_key_derivation_abort(
+    psa_key_derivation_operation_t *arg0_operation);
+#define psa_key_derivation_abort(arg0_operation) \
+    mbedtls_test_wrap_psa_key_derivation_abort(arg0_operation)
+
+psa_status_t mbedtls_test_wrap_psa_key_derivation_get_capacity(
+    const psa_key_derivation_operation_t *arg0_operation,
+    size_t *arg1_capacity);
+#define psa_key_derivation_get_capacity(arg0_operation, arg1_capacity) \
+    mbedtls_test_wrap_psa_key_derivation_get_capacity(arg0_operation, arg1_capacity)
+
+psa_status_t mbedtls_test_wrap_psa_key_derivation_input_bytes(
+    psa_key_derivation_operation_t *arg0_operation,
+    psa_key_derivation_step_t arg1_step,
+    const uint8_t *arg2_data,
+    size_t arg3_data_length);
+#define psa_key_derivation_input_bytes(arg0_operation, arg1_step, arg2_data, arg3_data_length) \
+    mbedtls_test_wrap_psa_key_derivation_input_bytes(arg0_operation, arg1_step, arg2_data, arg3_data_length)
+
+psa_status_t mbedtls_test_wrap_psa_key_derivation_input_integer(
+    psa_key_derivation_operation_t *arg0_operation,
+    psa_key_derivation_step_t arg1_step,
+    uint64_t arg2_value);
+#define psa_key_derivation_input_integer(arg0_operation, arg1_step, arg2_value) \
+    mbedtls_test_wrap_psa_key_derivation_input_integer(arg0_operation, arg1_step, arg2_value)
+
+psa_status_t mbedtls_test_wrap_psa_key_derivation_input_key(
+    psa_key_derivation_operation_t *arg0_operation,
+    psa_key_derivation_step_t arg1_step,
+    mbedtls_svc_key_id_t arg2_key);
+#define psa_key_derivation_input_key(arg0_operation, arg1_step, arg2_key) \
+    mbedtls_test_wrap_psa_key_derivation_input_key(arg0_operation, arg1_step, arg2_key)
+
+psa_status_t mbedtls_test_wrap_psa_key_derivation_key_agreement(
+    psa_key_derivation_operation_t *arg0_operation,
+    psa_key_derivation_step_t arg1_step,
+    mbedtls_svc_key_id_t arg2_private_key,
+    const uint8_t *arg3_peer_key,
+    size_t arg4_peer_key_length);
+#define psa_key_derivation_key_agreement(arg0_operation, arg1_step, arg2_private_key, arg3_peer_key, arg4_peer_key_length) \
+    mbedtls_test_wrap_psa_key_derivation_key_agreement(arg0_operation, arg1_step, arg2_private_key, arg3_peer_key, arg4_peer_key_length)
+
+psa_status_t mbedtls_test_wrap_psa_key_derivation_output_bytes(
+    psa_key_derivation_operation_t *arg0_operation,
+    uint8_t *arg1_output,
+    size_t arg2_output_length);
+#define psa_key_derivation_output_bytes(arg0_operation, arg1_output, arg2_output_length) \
+    mbedtls_test_wrap_psa_key_derivation_output_bytes(arg0_operation, arg1_output, arg2_output_length)
+
+psa_status_t mbedtls_test_wrap_psa_key_derivation_output_key(
+    const psa_key_attributes_t *arg0_attributes,
+    psa_key_derivation_operation_t *arg1_operation,
+    mbedtls_svc_key_id_t *arg2_key);
+#define psa_key_derivation_output_key(arg0_attributes, arg1_operation, arg2_key) \
+    mbedtls_test_wrap_psa_key_derivation_output_key(arg0_attributes, arg1_operation, arg2_key)
+
+psa_status_t mbedtls_test_wrap_psa_key_derivation_output_key_ext(
+    const psa_key_attributes_t *arg0_attributes,
+    psa_key_derivation_operation_t *arg1_operation,
+    const psa_key_production_parameters_t *arg2_params,
+    size_t arg3_params_data_length,
+    mbedtls_svc_key_id_t *arg4_key);
+#define psa_key_derivation_output_key_ext(arg0_attributes, arg1_operation, arg2_params, arg3_params_data_length, arg4_key) \
+    mbedtls_test_wrap_psa_key_derivation_output_key_ext(arg0_attributes, arg1_operation, arg2_params, arg3_params_data_length, arg4_key)
+
+psa_status_t mbedtls_test_wrap_psa_key_derivation_set_capacity(
+    psa_key_derivation_operation_t *arg0_operation,
+    size_t arg1_capacity);
+#define psa_key_derivation_set_capacity(arg0_operation, arg1_capacity) \
+    mbedtls_test_wrap_psa_key_derivation_set_capacity(arg0_operation, arg1_capacity)
+
+psa_status_t mbedtls_test_wrap_psa_key_derivation_setup(
+    psa_key_derivation_operation_t *arg0_operation,
+    psa_algorithm_t arg1_alg);
+#define psa_key_derivation_setup(arg0_operation, arg1_alg) \
+    mbedtls_test_wrap_psa_key_derivation_setup(arg0_operation, arg1_alg)
+
+psa_status_t mbedtls_test_wrap_psa_mac_abort(
+    psa_mac_operation_t *arg0_operation);
+#define psa_mac_abort(arg0_operation) \
+    mbedtls_test_wrap_psa_mac_abort(arg0_operation)
+
+psa_status_t mbedtls_test_wrap_psa_mac_compute(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_input,
+    size_t arg3_input_length,
+    uint8_t *arg4_mac,
+    size_t arg5_mac_size,
+    size_t *arg6_mac_length);
+#define psa_mac_compute(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_mac, arg5_mac_size, arg6_mac_length) \
+    mbedtls_test_wrap_psa_mac_compute(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_mac, arg5_mac_size, arg6_mac_length)
+
+psa_status_t mbedtls_test_wrap_psa_mac_sign_finish(
+    psa_mac_operation_t *arg0_operation,
+    uint8_t *arg1_mac,
+    size_t arg2_mac_size,
+    size_t *arg3_mac_length);
+#define psa_mac_sign_finish(arg0_operation, arg1_mac, arg2_mac_size, arg3_mac_length) \
+    mbedtls_test_wrap_psa_mac_sign_finish(arg0_operation, arg1_mac, arg2_mac_size, arg3_mac_length)
+
+psa_status_t mbedtls_test_wrap_psa_mac_sign_setup(
+    psa_mac_operation_t *arg0_operation,
+    mbedtls_svc_key_id_t arg1_key,
+    psa_algorithm_t arg2_alg);
+#define psa_mac_sign_setup(arg0_operation, arg1_key, arg2_alg) \
+    mbedtls_test_wrap_psa_mac_sign_setup(arg0_operation, arg1_key, arg2_alg)
+
+psa_status_t mbedtls_test_wrap_psa_mac_update(
+    psa_mac_operation_t *arg0_operation,
+    const uint8_t *arg1_input,
+    size_t arg2_input_length);
+#define psa_mac_update(arg0_operation, arg1_input, arg2_input_length) \
+    mbedtls_test_wrap_psa_mac_update(arg0_operation, arg1_input, arg2_input_length)
+
+psa_status_t mbedtls_test_wrap_psa_mac_verify(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_input,
+    size_t arg3_input_length,
+    const uint8_t *arg4_mac,
+    size_t arg5_mac_length);
+#define psa_mac_verify(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_mac, arg5_mac_length) \
+    mbedtls_test_wrap_psa_mac_verify(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_mac, arg5_mac_length)
+
+psa_status_t mbedtls_test_wrap_psa_mac_verify_finish(
+    psa_mac_operation_t *arg0_operation,
+    const uint8_t *arg1_mac,
+    size_t arg2_mac_length);
+#define psa_mac_verify_finish(arg0_operation, arg1_mac, arg2_mac_length) \
+    mbedtls_test_wrap_psa_mac_verify_finish(arg0_operation, arg1_mac, arg2_mac_length)
+
+psa_status_t mbedtls_test_wrap_psa_mac_verify_setup(
+    psa_mac_operation_t *arg0_operation,
+    mbedtls_svc_key_id_t arg1_key,
+    psa_algorithm_t arg2_alg);
+#define psa_mac_verify_setup(arg0_operation, arg1_key, arg2_alg) \
+    mbedtls_test_wrap_psa_mac_verify_setup(arg0_operation, arg1_key, arg2_alg)
+
+psa_status_t mbedtls_test_wrap_psa_pake_abort(
+    psa_pake_operation_t *arg0_operation);
+#define psa_pake_abort(arg0_operation) \
+    mbedtls_test_wrap_psa_pake_abort(arg0_operation)
+
+psa_status_t mbedtls_test_wrap_psa_pake_get_implicit_key(
+    psa_pake_operation_t *arg0_operation,
+    psa_key_derivation_operation_t *arg1_output);
+#define psa_pake_get_implicit_key(arg0_operation, arg1_output) \
+    mbedtls_test_wrap_psa_pake_get_implicit_key(arg0_operation, arg1_output)
+
+psa_status_t mbedtls_test_wrap_psa_pake_input(
+    psa_pake_operation_t *arg0_operation,
+    psa_pake_step_t arg1_step,
+    const uint8_t *arg2_input,
+    size_t arg3_input_length);
+#define psa_pake_input(arg0_operation, arg1_step, arg2_input, arg3_input_length) \
+    mbedtls_test_wrap_psa_pake_input(arg0_operation, arg1_step, arg2_input, arg3_input_length)
+
+psa_status_t mbedtls_test_wrap_psa_pake_output(
+    psa_pake_operation_t *arg0_operation,
+    psa_pake_step_t arg1_step,
+    uint8_t *arg2_output,
+    size_t arg3_output_size,
+    size_t *arg4_output_length);
+#define psa_pake_output(arg0_operation, arg1_step, arg2_output, arg3_output_size, arg4_output_length) \
+    mbedtls_test_wrap_psa_pake_output(arg0_operation, arg1_step, arg2_output, arg3_output_size, arg4_output_length)
+
+psa_status_t mbedtls_test_wrap_psa_pake_set_password_key(
+    psa_pake_operation_t *arg0_operation,
+    mbedtls_svc_key_id_t arg1_password);
+#define psa_pake_set_password_key(arg0_operation, arg1_password) \
+    mbedtls_test_wrap_psa_pake_set_password_key(arg0_operation, arg1_password)
+
+psa_status_t mbedtls_test_wrap_psa_pake_set_peer(
+    psa_pake_operation_t *arg0_operation,
+    const uint8_t *arg1_peer_id,
+    size_t arg2_peer_id_len);
+#define psa_pake_set_peer(arg0_operation, arg1_peer_id, arg2_peer_id_len) \
+    mbedtls_test_wrap_psa_pake_set_peer(arg0_operation, arg1_peer_id, arg2_peer_id_len)
+
+psa_status_t mbedtls_test_wrap_psa_pake_set_role(
+    psa_pake_operation_t *arg0_operation,
+    psa_pake_role_t arg1_role);
+#define psa_pake_set_role(arg0_operation, arg1_role) \
+    mbedtls_test_wrap_psa_pake_set_role(arg0_operation, arg1_role)
+
+psa_status_t mbedtls_test_wrap_psa_pake_set_user(
+    psa_pake_operation_t *arg0_operation,
+    const uint8_t *arg1_user_id,
+    size_t arg2_user_id_len);
+#define psa_pake_set_user(arg0_operation, arg1_user_id, arg2_user_id_len) \
+    mbedtls_test_wrap_psa_pake_set_user(arg0_operation, arg1_user_id, arg2_user_id_len)
+
+psa_status_t mbedtls_test_wrap_psa_pake_setup(
+    psa_pake_operation_t *arg0_operation,
+    const psa_pake_cipher_suite_t *arg1_cipher_suite);
+#define psa_pake_setup(arg0_operation, arg1_cipher_suite) \
+    mbedtls_test_wrap_psa_pake_setup(arg0_operation, arg1_cipher_suite)
+
+psa_status_t mbedtls_test_wrap_psa_purge_key(
+    mbedtls_svc_key_id_t arg0_key);
+#define psa_purge_key(arg0_key) \
+    mbedtls_test_wrap_psa_purge_key(arg0_key)
+
+psa_status_t mbedtls_test_wrap_psa_raw_key_agreement(
+    psa_algorithm_t arg0_alg,
+    mbedtls_svc_key_id_t arg1_private_key,
+    const uint8_t *arg2_peer_key,
+    size_t arg3_peer_key_length,
+    uint8_t *arg4_output,
+    size_t arg5_output_size,
+    size_t *arg6_output_length);
+#define psa_raw_key_agreement(arg0_alg, arg1_private_key, arg2_peer_key, arg3_peer_key_length, arg4_output, arg5_output_size, arg6_output_length) \
+    mbedtls_test_wrap_psa_raw_key_agreement(arg0_alg, arg1_private_key, arg2_peer_key, arg3_peer_key_length, arg4_output, arg5_output_size, arg6_output_length)
+
+psa_status_t mbedtls_test_wrap_psa_sign_hash(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_hash,
+    size_t arg3_hash_length,
+    uint8_t *arg4_signature,
+    size_t arg5_signature_size,
+    size_t *arg6_signature_length);
+#define psa_sign_hash(arg0_key, arg1_alg, arg2_hash, arg3_hash_length, arg4_signature, arg5_signature_size, arg6_signature_length) \
+    mbedtls_test_wrap_psa_sign_hash(arg0_key, arg1_alg, arg2_hash, arg3_hash_length, arg4_signature, arg5_signature_size, arg6_signature_length)
+
+psa_status_t mbedtls_test_wrap_psa_sign_hash_abort(
+    psa_sign_hash_interruptible_operation_t *arg0_operation);
+#define psa_sign_hash_abort(arg0_operation) \
+    mbedtls_test_wrap_psa_sign_hash_abort(arg0_operation)
+
+psa_status_t mbedtls_test_wrap_psa_sign_hash_complete(
+    psa_sign_hash_interruptible_operation_t *arg0_operation,
+    uint8_t *arg1_signature,
+    size_t arg2_signature_size,
+    size_t *arg3_signature_length);
+#define psa_sign_hash_complete(arg0_operation, arg1_signature, arg2_signature_size, arg3_signature_length) \
+    mbedtls_test_wrap_psa_sign_hash_complete(arg0_operation, arg1_signature, arg2_signature_size, arg3_signature_length)
+
+psa_status_t mbedtls_test_wrap_psa_sign_hash_start(
+    psa_sign_hash_interruptible_operation_t *arg0_operation,
+    mbedtls_svc_key_id_t arg1_key,
+    psa_algorithm_t arg2_alg,
+    const uint8_t *arg3_hash,
+    size_t arg4_hash_length);
+#define psa_sign_hash_start(arg0_operation, arg1_key, arg2_alg, arg3_hash, arg4_hash_length) \
+    mbedtls_test_wrap_psa_sign_hash_start(arg0_operation, arg1_key, arg2_alg, arg3_hash, arg4_hash_length)
+
+psa_status_t mbedtls_test_wrap_psa_sign_message(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_input,
+    size_t arg3_input_length,
+    uint8_t *arg4_signature,
+    size_t arg5_signature_size,
+    size_t *arg6_signature_length);
+#define psa_sign_message(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_signature, arg5_signature_size, arg6_signature_length) \
+    mbedtls_test_wrap_psa_sign_message(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_signature, arg5_signature_size, arg6_signature_length)
+
+psa_status_t mbedtls_test_wrap_psa_verify_hash(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_hash,
+    size_t arg3_hash_length,
+    const uint8_t *arg4_signature,
+    size_t arg5_signature_length);
+#define psa_verify_hash(arg0_key, arg1_alg, arg2_hash, arg3_hash_length, arg4_signature, arg5_signature_length) \
+    mbedtls_test_wrap_psa_verify_hash(arg0_key, arg1_alg, arg2_hash, arg3_hash_length, arg4_signature, arg5_signature_length)
+
+psa_status_t mbedtls_test_wrap_psa_verify_hash_abort(
+    psa_verify_hash_interruptible_operation_t *arg0_operation);
+#define psa_verify_hash_abort(arg0_operation) \
+    mbedtls_test_wrap_psa_verify_hash_abort(arg0_operation)
+
+psa_status_t mbedtls_test_wrap_psa_verify_hash_complete(
+    psa_verify_hash_interruptible_operation_t *arg0_operation);
+#define psa_verify_hash_complete(arg0_operation) \
+    mbedtls_test_wrap_psa_verify_hash_complete(arg0_operation)
+
+psa_status_t mbedtls_test_wrap_psa_verify_hash_start(
+    psa_verify_hash_interruptible_operation_t *arg0_operation,
+    mbedtls_svc_key_id_t arg1_key,
+    psa_algorithm_t arg2_alg,
+    const uint8_t *arg3_hash,
+    size_t arg4_hash_length,
+    const uint8_t *arg5_signature,
+    size_t arg6_signature_length);
+#define psa_verify_hash_start(arg0_operation, arg1_key, arg2_alg, arg3_hash, arg4_hash_length, arg5_signature, arg6_signature_length) \
+    mbedtls_test_wrap_psa_verify_hash_start(arg0_operation, arg1_key, arg2_alg, arg3_hash, arg4_hash_length, arg5_signature, arg6_signature_length)
+
+psa_status_t mbedtls_test_wrap_psa_verify_message(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_input,
+    size_t arg3_input_length,
+    const uint8_t *arg4_signature,
+    size_t arg5_signature_length);
+#define psa_verify_message(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_signature, arg5_signature_length) \
+    mbedtls_test_wrap_psa_verify_message(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_signature, arg5_signature_length)
+
+#endif /* defined(MBEDTLS_PSA_CRYPTO_C) && defined(MBEDTLS_TEST_HOOKS) && \
+    !defined(RECORD_PSA_STATUS_COVERAGE_LOG) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TEST_PSA_TEST_WRAPPERS_H */
+
+/* End of automatically generated file. */
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index e17d5ac..a1203f7 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -1091,7 +1091,7 @@
     grep 'depends_on' \
         tests/suites/test_suite_psa*.data tests/suites/test_suite_psa*.function |
         grep -Eo '!?MBEDTLS_[^: ]*' |
-        grep -v MBEDTLS_PSA_ |
+        grep -v -e MBEDTLS_PSA_ -e MBEDTLS_TEST_ |
         sort -u > $found
 
     # Expected ones with justification - keep in sorted order by ASCII table!
@@ -1169,7 +1169,7 @@
     programs/test/selftest
 
     msg "test: metatests (GCC, ASan build)"
-    tests/scripts/run-metatests.sh any asan
+    tests/scripts/run-metatests.sh any asan poison
 
     msg "test: ssl-opt.sh (ASan build)" # ~ 1 min
     tests/ssl-opt.sh
@@ -1260,6 +1260,17 @@
     make test
 }
 
+component_test_psa_assume_exclusive_buffers () {
+    msg "build: full config + MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS, cmake, gcc, ASan"
+    scripts/config.py full
+    scripts/config.py set MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
+
+    msg "test: full config + MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS, cmake, gcc, ASan"
+    make test
+}
+
 # check_renamed_symbols HEADER LIB
 # Check that if HEADER contains '#define MACRO ...' then MACRO is not a symbol
 # name is LIB.
@@ -2049,7 +2060,7 @@
     make test
 
     msg "test: metatests (clang, ASan)"
-    tests/scripts/run-metatests.sh any asan
+    tests/scripts/run-metatests.sh any asan poison
 
     msg "test: Everest ECDH context - ECDH-related part of ssl-opt.sh (ASan build)" # ~ 5s
     tests/ssl-opt.sh -f ECDH
diff --git a/tests/scripts/check-generated-files.sh b/tests/scripts/check-generated-files.sh
index 792885f..2f20026 100755
--- a/tests/scripts/check-generated-files.sh
+++ b/tests/scripts/check-generated-files.sh
@@ -144,3 +144,8 @@
     # the step that creates or updates these files.
     check scripts/generate_visualc_files.pl visualc/VS2017
 fi
+
+# Generated files that are present in the repository even in the development
+# branch. (This is intended to be temporary, until the generator scripts are
+# fully reviewed and the build scripts support a generated header file.)
+check tests/scripts/generate_psa_wrappers.py tests/include/test/psa_test_wrappers.h tests/src/psa_test_wrappers.c
diff --git a/tests/scripts/generate_psa_wrappers.py b/tests/scripts/generate_psa_wrappers.py
new file mode 100755
index 0000000..07d1450
--- /dev/null
+++ b/tests/scripts/generate_psa_wrappers.py
@@ -0,0 +1,257 @@
+#!/usr/bin/env python3
+"""Generate wrapper functions for PSA function calls.
+"""
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+### WARNING: the code in this file has not been extensively reviewed yet.
+### We do not think it is harmful, but it may be below our normal standards
+### for robustness and maintainability.
+
+import argparse
+import itertools
+import os
+from typing import Iterator, List, Optional, Tuple
+
+import scripts_path #pylint: disable=unused-import
+from mbedtls_dev import build_tree
+from mbedtls_dev import c_parsing_helper
+from mbedtls_dev import c_wrapper_generator
+from mbedtls_dev import typing_util
+
+
+class BufferParameter:
+    """Description of an input or output buffer parameter sequence to a PSA function."""
+    #pylint: disable=too-few-public-methods
+
+    def __init__(self, i: int, is_output: bool,
+                 buffer_name: str, size_name: str) -> None:
+        """Initialize the parameter information.
+
+        i is the index of the function argument that is the pointer to the buffer.
+        The size is argument i+1. For a variable-size output, the actual length
+        goes in argument i+2.
+
+        buffer_name and size_names are the names of arguments i and i+1.
+        This class does not yet help with the output length.
+        """
+        self.index = i
+        self.buffer_name = buffer_name
+        self.size_name = size_name
+        self.is_output = is_output
+
+
+class PSAWrapperGenerator(c_wrapper_generator.Base):
+    """Generate a C source file containing wrapper functions for PSA Crypto API calls."""
+
+    _CPP_GUARDS = ('defined(MBEDTLS_PSA_CRYPTO_C) && ' +
+                   'defined(MBEDTLS_TEST_HOOKS) && \\\n    ' +
+                   '!defined(RECORD_PSA_STATUS_COVERAGE_LOG)')
+    _WRAPPER_NAME_PREFIX = 'mbedtls_test_wrap_'
+    _WRAPPER_NAME_SUFFIX = ''
+
+    def gather_data(self) -> None:
+        root_dir = build_tree.guess_mbedtls_root()
+        for header_name in ['crypto.h', 'crypto_extra.h']:
+            header_path = os.path.join(root_dir, 'include', 'psa', header_name)
+            c_parsing_helper.read_function_declarations(self.functions, header_path)
+
+    _SKIP_FUNCTIONS = frozenset([
+        'mbedtls_psa_external_get_random', # not a library function
+        'psa_get_key_domain_parameters', # client-side function
+        'psa_get_key_slot_number', # client-side function
+        'psa_key_derivation_verify_bytes', # not implemented yet
+        'psa_key_derivation_verify_key', # not implemented yet
+        'psa_set_key_domain_parameters', # client-side function
+    ])
+
+    def _skip_function(self, function: c_wrapper_generator.FunctionInfo) -> bool:
+        if function.return_type != 'psa_status_t':
+            return True
+        if function.name in self._SKIP_FUNCTIONS:
+            return True
+        return False
+
+    # PAKE stuff: not implemented yet
+    _PAKE_STUFF = frozenset([
+        'psa_crypto_driver_pake_inputs_t *',
+        'psa_pake_cipher_suite_t *',
+    ])
+
+    def _return_variable_name(self,
+                              function: c_wrapper_generator.FunctionInfo) -> str:
+        """The name of the variable that will contain the return value."""
+        if function.return_type == 'psa_status_t':
+            return 'status'
+        return super()._return_variable_name(function)
+
+    _FUNCTION_GUARDS = c_wrapper_generator.Base._FUNCTION_GUARDS.copy() \
+        #pylint: disable=protected-access
+    _FUNCTION_GUARDS.update({
+        'mbedtls_psa_register_se_key': 'defined(MBEDTLS_PSA_CRYPTO_SE_C)',
+        'mbedtls_psa_inject_entropy': 'defined(MBEDTLS_PSA_INJECT_ENTROPY)',
+        'mbedtls_psa_external_get_random': 'defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)',
+        'mbedtls_psa_platform_get_builtin_key': 'defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)',
+    })
+
+    @staticmethod
+    def _detect_buffer_parameters(arguments: List[c_parsing_helper.ArgumentInfo],
+                                  argument_names: List[str]) -> Iterator[BufferParameter]:
+        """Detect function arguments that are buffers (pointer, size [,length])."""
+        types = ['' if arg.suffix else arg.type for arg in arguments]
+        # pairs = list of (type_of_arg_N, type_of_arg_N+1)
+        # where each type_of_arg_X is the empty string if the type is an array
+        # or there is no argument X.
+        pairs = enumerate(itertools.zip_longest(types, types[1:], fillvalue=''))
+        for i, t01 in pairs:
+            if (t01[0] == 'const uint8_t *' or t01[0] == 'uint8_t *') and \
+               t01[1] == 'size_t':
+                yield BufferParameter(i, not t01[0].startswith('const '),
+                                      argument_names[i], argument_names[i+1])
+
+    @staticmethod
+    def _write_poison_buffer_parameter(out: typing_util.Writable,
+                                       param: BufferParameter,
+                                       poison: bool) -> None:
+        """Write poisoning or unpoisoning code for a buffer parameter.
+
+        Write poisoning code if poison is true, unpoisoning code otherwise.
+        """
+        out.write('    MBEDTLS_TEST_MEMORY_{}({}, {});\n'.format(
+            'POISON' if poison else 'UNPOISON',
+            param.buffer_name, param.size_name
+        ))
+
+    def _write_poison_buffer_parameters(self, out: typing_util.Writable,
+                                        buffer_parameters: List[BufferParameter],
+                                        poison: bool) -> None:
+        """Write poisoning or unpoisoning code for the buffer parameters.
+
+        Write poisoning code if poison is true, unpoisoning code otherwise.
+        """
+        if not buffer_parameters:
+            return
+        out.write('#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)\n')
+        for param in buffer_parameters:
+            self._write_poison_buffer_parameter(out, param, poison)
+        out.write('#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */\n')
+
+    @staticmethod
+    def _parameter_should_be_copied(function_name: str,
+                                    _buffer_name: Optional[str]) -> bool:
+        """Whether the specified buffer argument to a PSA function should be copied.
+        """
+        # False-positives that do not need buffer copying
+        if function_name in ('mbedtls_psa_inject_entropy',
+                             'psa_crypto_driver_pake_get_password',
+                             'psa_crypto_driver_pake_get_user',
+                             'psa_crypto_driver_pake_get_peer'):
+            return False
+
+        return True
+
+    def _write_function_call(self, out: typing_util.Writable,
+                             function: c_wrapper_generator.FunctionInfo,
+                             argument_names: List[str]) -> None:
+        buffer_parameters = list(
+            param
+            for param in self._detect_buffer_parameters(function.arguments,
+                                                        argument_names)
+            if self._parameter_should_be_copied(function.name,
+                                                function.arguments[param.index].name))
+        self._write_poison_buffer_parameters(out, buffer_parameters, True)
+        super()._write_function_call(out, function, argument_names)
+        self._write_poison_buffer_parameters(out, buffer_parameters, False)
+
+    def _write_prologue(self, out: typing_util.Writable, header: bool) -> None:
+        super()._write_prologue(out, header)
+        out.write("""
+#if {}
+
+#include <psa/crypto.h>
+
+#include <test/memory.h>
+#include <test/psa_crypto_helpers.h>
+#include <test/psa_test_wrappers.h>
+"""
+                  .format(self._CPP_GUARDS))
+
+    def _write_epilogue(self, out: typing_util.Writable, header: bool) -> None:
+        out.write("""
+#endif /* {} */
+"""
+                  .format(self._CPP_GUARDS))
+        super()._write_epilogue(out, header)
+
+
+class PSALoggingWrapperGenerator(PSAWrapperGenerator, c_wrapper_generator.Logging):
+    """Generate a C source file containing wrapper functions that log PSA Crypto API calls."""
+
+    def __init__(self, stream: str) -> None:
+        super().__init__()
+        self.set_stream(stream)
+
+    _PRINTF_TYPE_CAST = c_wrapper_generator.Logging._PRINTF_TYPE_CAST.copy()
+    _PRINTF_TYPE_CAST.update({
+        'mbedtls_svc_key_id_t': 'unsigned',
+        'psa_algorithm_t': 'unsigned',
+        'psa_drv_slot_number_t': 'unsigned long long',
+        'psa_key_derivation_step_t': 'int',
+        'psa_key_id_t': 'unsigned',
+        'psa_key_slot_number_t': 'unsigned long long',
+        'psa_key_lifetime_t': 'unsigned',
+        'psa_key_type_t': 'unsigned',
+        'psa_key_usage_flags_t': 'unsigned',
+        'psa_pake_role_t': 'int',
+        'psa_pake_step_t': 'int',
+        'psa_status_t': 'int',
+    })
+
+    def _printf_parameters(self, typ: str, var: str) -> Tuple[str, List[str]]:
+        if typ.startswith('const '):
+            typ = typ[6:]
+        if typ == 'uint8_t *':
+            # Skip buffers
+            return '', []
+        if typ.endswith('operation_t *'):
+            return '', []
+        if typ in self._PAKE_STUFF:
+            return '', []
+        if typ == 'psa_key_attributes_t *':
+            return (var + '={id=%u, lifetime=0x%08x, type=0x%08x, bits=%u, alg=%08x, usage=%08x}',
+                    ['(unsigned) psa_get_key_{}({})'.format(field, var)
+                     for field in ['id', 'lifetime', 'type', 'bits', 'algorithm', 'usage_flags']])
+        return super()._printf_parameters(typ, var)
+
+
+DEFAULT_C_OUTPUT_FILE_NAME = 'tests/src/psa_test_wrappers.c'
+DEFAULT_H_OUTPUT_FILE_NAME = 'tests/include/test/psa_test_wrappers.h'
+
+def main() -> None:
+    parser = argparse.ArgumentParser(description=globals()['__doc__'])
+    parser.add_argument('--log',
+                        help='Stream to log to (default: no logging code)')
+    parser.add_argument('--output-c',
+                        metavar='FILENAME',
+                        default=DEFAULT_C_OUTPUT_FILE_NAME,
+                        help=('Output .c file path (default: {}; skip .c output if empty)'
+                              .format(DEFAULT_C_OUTPUT_FILE_NAME)))
+    parser.add_argument('--output-h',
+                        metavar='FILENAME',
+                        default=DEFAULT_H_OUTPUT_FILE_NAME,
+                        help=('Output .h file path (default: {}; skip .h output if empty)'
+                              .format(DEFAULT_H_OUTPUT_FILE_NAME)))
+    options = parser.parse_args()
+    if options.log:
+        generator = PSALoggingWrapperGenerator(options.log) #type: PSAWrapperGenerator
+    else:
+        generator = PSAWrapperGenerator()
+    generator.gather_data()
+    if options.output_h:
+        generator.write_h_file(options.output_h)
+    if options.output_c:
+        generator.write_c_file(options.output_c)
+
+if __name__ == '__main__':
+    main()
diff --git a/tests/src/helpers.c b/tests/src/helpers.c
index 2433422..065d17d 100644
--- a/tests/src/helpers.c
+++ b/tests/src/helpers.c
@@ -13,6 +13,9 @@
 #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_THREADING_C)
 #include "mbedtls/threading.h"
 #endif
@@ -314,6 +317,12 @@
 {
     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
@@ -338,6 +347,11 @@
 
 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 */
diff --git a/tests/src/psa_memory_poisoning_wrappers.c b/tests/src/psa_memory_poisoning_wrappers.c
new file mode 100644
index 0000000..05cba18
--- /dev/null
+++ b/tests/src/psa_memory_poisoning_wrappers.c
@@ -0,0 +1,31 @@
+/** 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 "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/tests/src/psa_test_wrappers.c b/tests/src/psa_test_wrappers.c
new file mode 100644
index 0000000..809f1cd
--- /dev/null
+++ b/tests/src/psa_test_wrappers.c
@@ -0,0 +1,1321 @@
+/* Automatically generated by generate_psa_wrappers.py, do not edit! */
+
+/* Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <mbedtls/build_info.h>
+
+#if defined(MBEDTLS_PSA_CRYPTO_C) && defined(MBEDTLS_TEST_HOOKS) && \
+    !defined(RECORD_PSA_STATUS_COVERAGE_LOG)
+
+#include <psa/crypto.h>
+
+#include <test/memory.h>
+#include <test/psa_crypto_helpers.h>
+#include <test/psa_test_wrappers.h>
+
+/* Wrapper for mbedtls_psa_inject_entropy */
+#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
+psa_status_t mbedtls_test_wrap_mbedtls_psa_inject_entropy(
+    const uint8_t *arg0_seed,
+    size_t arg1_seed_size)
+{
+    psa_status_t status = (mbedtls_psa_inject_entropy)(arg0_seed, arg1_seed_size);
+    return status;
+}
+#endif /* defined(MBEDTLS_PSA_INJECT_ENTROPY) */
+
+/* Wrapper for mbedtls_psa_platform_get_builtin_key */
+#if defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)
+psa_status_t mbedtls_test_wrap_mbedtls_psa_platform_get_builtin_key(
+    mbedtls_svc_key_id_t arg0_key_id,
+    psa_key_lifetime_t *arg1_lifetime,
+    psa_drv_slot_number_t *arg2_slot_number)
+{
+    psa_status_t status = (mbedtls_psa_platform_get_builtin_key)(arg0_key_id, arg1_lifetime, arg2_slot_number);
+    return status;
+}
+#endif /* defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS) */
+
+/* Wrapper for mbedtls_psa_register_se_key */
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+psa_status_t mbedtls_test_wrap_mbedtls_psa_register_se_key(
+    const psa_key_attributes_t *arg0_attributes)
+{
+    psa_status_t status = (mbedtls_psa_register_se_key)(arg0_attributes);
+    return status;
+}
+#endif /* defined(MBEDTLS_PSA_CRYPTO_SE_C) */
+
+/* Wrapper for psa_aead_abort */
+psa_status_t mbedtls_test_wrap_psa_aead_abort(
+    psa_aead_operation_t *arg0_operation)
+{
+    psa_status_t status = (psa_aead_abort)(arg0_operation);
+    return status;
+}
+
+/* Wrapper for psa_aead_decrypt */
+psa_status_t mbedtls_test_wrap_psa_aead_decrypt(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_nonce,
+    size_t arg3_nonce_length,
+    const uint8_t *arg4_additional_data,
+    size_t arg5_additional_data_length,
+    const uint8_t *arg6_ciphertext,
+    size_t arg7_ciphertext_length,
+    uint8_t *arg8_plaintext,
+    size_t arg9_plaintext_size,
+    size_t *arg10_plaintext_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg2_nonce, arg3_nonce_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg4_additional_data, arg5_additional_data_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg6_ciphertext, arg7_ciphertext_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg8_plaintext, arg9_plaintext_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_aead_decrypt)(arg0_key, arg1_alg, arg2_nonce, arg3_nonce_length, arg4_additional_data, arg5_additional_data_length, arg6_ciphertext, arg7_ciphertext_length, arg8_plaintext, arg9_plaintext_size, arg10_plaintext_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg2_nonce, arg3_nonce_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg4_additional_data, arg5_additional_data_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg6_ciphertext, arg7_ciphertext_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg8_plaintext, arg9_plaintext_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_aead_decrypt_setup */
+psa_status_t mbedtls_test_wrap_psa_aead_decrypt_setup(
+    psa_aead_operation_t *arg0_operation,
+    mbedtls_svc_key_id_t arg1_key,
+    psa_algorithm_t arg2_alg)
+{
+    psa_status_t status = (psa_aead_decrypt_setup)(arg0_operation, arg1_key, arg2_alg);
+    return status;
+}
+
+/* Wrapper for psa_aead_encrypt */
+psa_status_t mbedtls_test_wrap_psa_aead_encrypt(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_nonce,
+    size_t arg3_nonce_length,
+    const uint8_t *arg4_additional_data,
+    size_t arg5_additional_data_length,
+    const uint8_t *arg6_plaintext,
+    size_t arg7_plaintext_length,
+    uint8_t *arg8_ciphertext,
+    size_t arg9_ciphertext_size,
+    size_t *arg10_ciphertext_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg2_nonce, arg3_nonce_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg4_additional_data, arg5_additional_data_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg6_plaintext, arg7_plaintext_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg8_ciphertext, arg9_ciphertext_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_aead_encrypt)(arg0_key, arg1_alg, arg2_nonce, arg3_nonce_length, arg4_additional_data, arg5_additional_data_length, arg6_plaintext, arg7_plaintext_length, arg8_ciphertext, arg9_ciphertext_size, arg10_ciphertext_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg2_nonce, arg3_nonce_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg4_additional_data, arg5_additional_data_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg6_plaintext, arg7_plaintext_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg8_ciphertext, arg9_ciphertext_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_aead_encrypt_setup */
+psa_status_t mbedtls_test_wrap_psa_aead_encrypt_setup(
+    psa_aead_operation_t *arg0_operation,
+    mbedtls_svc_key_id_t arg1_key,
+    psa_algorithm_t arg2_alg)
+{
+    psa_status_t status = (psa_aead_encrypt_setup)(arg0_operation, arg1_key, arg2_alg);
+    return status;
+}
+
+/* Wrapper for psa_aead_finish */
+psa_status_t mbedtls_test_wrap_psa_aead_finish(
+    psa_aead_operation_t *arg0_operation,
+    uint8_t *arg1_ciphertext,
+    size_t arg2_ciphertext_size,
+    size_t *arg3_ciphertext_length,
+    uint8_t *arg4_tag,
+    size_t arg5_tag_size,
+    size_t *arg6_tag_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_ciphertext, arg2_ciphertext_size);
+    MBEDTLS_TEST_MEMORY_POISON(arg4_tag, arg5_tag_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_aead_finish)(arg0_operation, arg1_ciphertext, arg2_ciphertext_size, arg3_ciphertext_length, arg4_tag, arg5_tag_size, arg6_tag_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_ciphertext, arg2_ciphertext_size);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg4_tag, arg5_tag_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_aead_generate_nonce */
+psa_status_t mbedtls_test_wrap_psa_aead_generate_nonce(
+    psa_aead_operation_t *arg0_operation,
+    uint8_t *arg1_nonce,
+    size_t arg2_nonce_size,
+    size_t *arg3_nonce_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_nonce, arg2_nonce_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_aead_generate_nonce)(arg0_operation, arg1_nonce, arg2_nonce_size, arg3_nonce_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_nonce, arg2_nonce_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_aead_set_lengths */
+psa_status_t mbedtls_test_wrap_psa_aead_set_lengths(
+    psa_aead_operation_t *arg0_operation,
+    size_t arg1_ad_length,
+    size_t arg2_plaintext_length)
+{
+    psa_status_t status = (psa_aead_set_lengths)(arg0_operation, arg1_ad_length, arg2_plaintext_length);
+    return status;
+}
+
+/* Wrapper for psa_aead_set_nonce */
+psa_status_t mbedtls_test_wrap_psa_aead_set_nonce(
+    psa_aead_operation_t *arg0_operation,
+    const uint8_t *arg1_nonce,
+    size_t arg2_nonce_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_nonce, arg2_nonce_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_aead_set_nonce)(arg0_operation, arg1_nonce, arg2_nonce_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_nonce, arg2_nonce_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_aead_update */
+psa_status_t mbedtls_test_wrap_psa_aead_update(
+    psa_aead_operation_t *arg0_operation,
+    const uint8_t *arg1_input,
+    size_t arg2_input_length,
+    uint8_t *arg3_output,
+    size_t arg4_output_size,
+    size_t *arg5_output_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_input, arg2_input_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg3_output, arg4_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_aead_update)(arg0_operation, arg1_input, arg2_input_length, arg3_output, arg4_output_size, arg5_output_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_input, arg2_input_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg3_output, arg4_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_aead_update_ad */
+psa_status_t mbedtls_test_wrap_psa_aead_update_ad(
+    psa_aead_operation_t *arg0_operation,
+    const uint8_t *arg1_input,
+    size_t arg2_input_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_input, arg2_input_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_aead_update_ad)(arg0_operation, arg1_input, arg2_input_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_input, arg2_input_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_aead_verify */
+psa_status_t mbedtls_test_wrap_psa_aead_verify(
+    psa_aead_operation_t *arg0_operation,
+    uint8_t *arg1_plaintext,
+    size_t arg2_plaintext_size,
+    size_t *arg3_plaintext_length,
+    const uint8_t *arg4_tag,
+    size_t arg5_tag_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_plaintext, arg2_plaintext_size);
+    MBEDTLS_TEST_MEMORY_POISON(arg4_tag, arg5_tag_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_aead_verify)(arg0_operation, arg1_plaintext, arg2_plaintext_size, arg3_plaintext_length, arg4_tag, arg5_tag_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_plaintext, arg2_plaintext_size);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg4_tag, arg5_tag_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_asymmetric_decrypt */
+psa_status_t mbedtls_test_wrap_psa_asymmetric_decrypt(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_input,
+    size_t arg3_input_length,
+    const uint8_t *arg4_salt,
+    size_t arg5_salt_length,
+    uint8_t *arg6_output,
+    size_t arg7_output_size,
+    size_t *arg8_output_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg2_input, arg3_input_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg4_salt, arg5_salt_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg6_output, arg7_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_asymmetric_decrypt)(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_salt, arg5_salt_length, arg6_output, arg7_output_size, arg8_output_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg2_input, arg3_input_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg4_salt, arg5_salt_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg6_output, arg7_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_asymmetric_encrypt */
+psa_status_t mbedtls_test_wrap_psa_asymmetric_encrypt(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_input,
+    size_t arg3_input_length,
+    const uint8_t *arg4_salt,
+    size_t arg5_salt_length,
+    uint8_t *arg6_output,
+    size_t arg7_output_size,
+    size_t *arg8_output_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg2_input, arg3_input_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg4_salt, arg5_salt_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg6_output, arg7_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_asymmetric_encrypt)(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_salt, arg5_salt_length, arg6_output, arg7_output_size, arg8_output_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg2_input, arg3_input_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg4_salt, arg5_salt_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg6_output, arg7_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_cipher_abort */
+psa_status_t mbedtls_test_wrap_psa_cipher_abort(
+    psa_cipher_operation_t *arg0_operation)
+{
+    psa_status_t status = (psa_cipher_abort)(arg0_operation);
+    return status;
+}
+
+/* Wrapper for psa_cipher_decrypt */
+psa_status_t mbedtls_test_wrap_psa_cipher_decrypt(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_input,
+    size_t arg3_input_length,
+    uint8_t *arg4_output,
+    size_t arg5_output_size,
+    size_t *arg6_output_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg2_input, arg3_input_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg4_output, arg5_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_cipher_decrypt)(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_output, arg5_output_size, arg6_output_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg2_input, arg3_input_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg4_output, arg5_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_cipher_decrypt_setup */
+psa_status_t mbedtls_test_wrap_psa_cipher_decrypt_setup(
+    psa_cipher_operation_t *arg0_operation,
+    mbedtls_svc_key_id_t arg1_key,
+    psa_algorithm_t arg2_alg)
+{
+    psa_status_t status = (psa_cipher_decrypt_setup)(arg0_operation, arg1_key, arg2_alg);
+    return status;
+}
+
+/* Wrapper for psa_cipher_encrypt */
+psa_status_t mbedtls_test_wrap_psa_cipher_encrypt(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_input,
+    size_t arg3_input_length,
+    uint8_t *arg4_output,
+    size_t arg5_output_size,
+    size_t *arg6_output_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg2_input, arg3_input_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg4_output, arg5_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_cipher_encrypt)(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_output, arg5_output_size, arg6_output_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg2_input, arg3_input_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg4_output, arg5_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_cipher_encrypt_setup */
+psa_status_t mbedtls_test_wrap_psa_cipher_encrypt_setup(
+    psa_cipher_operation_t *arg0_operation,
+    mbedtls_svc_key_id_t arg1_key,
+    psa_algorithm_t arg2_alg)
+{
+    psa_status_t status = (psa_cipher_encrypt_setup)(arg0_operation, arg1_key, arg2_alg);
+    return status;
+}
+
+/* Wrapper for psa_cipher_finish */
+psa_status_t mbedtls_test_wrap_psa_cipher_finish(
+    psa_cipher_operation_t *arg0_operation,
+    uint8_t *arg1_output,
+    size_t arg2_output_size,
+    size_t *arg3_output_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_output, arg2_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_cipher_finish)(arg0_operation, arg1_output, arg2_output_size, arg3_output_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_output, arg2_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_cipher_generate_iv */
+psa_status_t mbedtls_test_wrap_psa_cipher_generate_iv(
+    psa_cipher_operation_t *arg0_operation,
+    uint8_t *arg1_iv,
+    size_t arg2_iv_size,
+    size_t *arg3_iv_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_iv, arg2_iv_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_cipher_generate_iv)(arg0_operation, arg1_iv, arg2_iv_size, arg3_iv_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_iv, arg2_iv_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_cipher_set_iv */
+psa_status_t mbedtls_test_wrap_psa_cipher_set_iv(
+    psa_cipher_operation_t *arg0_operation,
+    const uint8_t *arg1_iv,
+    size_t arg2_iv_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_iv, arg2_iv_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_cipher_set_iv)(arg0_operation, arg1_iv, arg2_iv_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_iv, arg2_iv_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_cipher_update */
+psa_status_t mbedtls_test_wrap_psa_cipher_update(
+    psa_cipher_operation_t *arg0_operation,
+    const uint8_t *arg1_input,
+    size_t arg2_input_length,
+    uint8_t *arg3_output,
+    size_t arg4_output_size,
+    size_t *arg5_output_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_input, arg2_input_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg3_output, arg4_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_cipher_update)(arg0_operation, arg1_input, arg2_input_length, arg3_output, arg4_output_size, arg5_output_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_input, arg2_input_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg3_output, arg4_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_copy_key */
+psa_status_t mbedtls_test_wrap_psa_copy_key(
+    mbedtls_svc_key_id_t arg0_source_key,
+    const psa_key_attributes_t *arg1_attributes,
+    mbedtls_svc_key_id_t *arg2_target_key)
+{
+    psa_status_t status = (psa_copy_key)(arg0_source_key, arg1_attributes, arg2_target_key);
+    return status;
+}
+
+/* Wrapper for psa_crypto_driver_pake_get_cipher_suite */
+psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_cipher_suite(
+    const psa_crypto_driver_pake_inputs_t *arg0_inputs,
+    psa_pake_cipher_suite_t *arg1_cipher_suite)
+{
+    psa_status_t status = (psa_crypto_driver_pake_get_cipher_suite)(arg0_inputs, arg1_cipher_suite);
+    return status;
+}
+
+/* Wrapper for psa_crypto_driver_pake_get_password */
+psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_password(
+    const psa_crypto_driver_pake_inputs_t *arg0_inputs,
+    uint8_t *arg1_buffer,
+    size_t arg2_buffer_size,
+    size_t *arg3_buffer_length)
+{
+    psa_status_t status = (psa_crypto_driver_pake_get_password)(arg0_inputs, arg1_buffer, arg2_buffer_size, arg3_buffer_length);
+    return status;
+}
+
+/* Wrapper for psa_crypto_driver_pake_get_password_len */
+psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_password_len(
+    const psa_crypto_driver_pake_inputs_t *arg0_inputs,
+    size_t *arg1_password_len)
+{
+    psa_status_t status = (psa_crypto_driver_pake_get_password_len)(arg0_inputs, arg1_password_len);
+    return status;
+}
+
+/* Wrapper for psa_crypto_driver_pake_get_peer */
+psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_peer(
+    const psa_crypto_driver_pake_inputs_t *arg0_inputs,
+    uint8_t *arg1_peer_id,
+    size_t arg2_peer_id_size,
+    size_t *arg3_peer_id_length)
+{
+    psa_status_t status = (psa_crypto_driver_pake_get_peer)(arg0_inputs, arg1_peer_id, arg2_peer_id_size, arg3_peer_id_length);
+    return status;
+}
+
+/* Wrapper for psa_crypto_driver_pake_get_peer_len */
+psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_peer_len(
+    const psa_crypto_driver_pake_inputs_t *arg0_inputs,
+    size_t *arg1_peer_len)
+{
+    psa_status_t status = (psa_crypto_driver_pake_get_peer_len)(arg0_inputs, arg1_peer_len);
+    return status;
+}
+
+/* Wrapper for psa_crypto_driver_pake_get_user */
+psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_user(
+    const psa_crypto_driver_pake_inputs_t *arg0_inputs,
+    uint8_t *arg1_user_id,
+    size_t arg2_user_id_size,
+    size_t *arg3_user_id_len)
+{
+    psa_status_t status = (psa_crypto_driver_pake_get_user)(arg0_inputs, arg1_user_id, arg2_user_id_size, arg3_user_id_len);
+    return status;
+}
+
+/* Wrapper for psa_crypto_driver_pake_get_user_len */
+psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_user_len(
+    const psa_crypto_driver_pake_inputs_t *arg0_inputs,
+    size_t *arg1_user_len)
+{
+    psa_status_t status = (psa_crypto_driver_pake_get_user_len)(arg0_inputs, arg1_user_len);
+    return status;
+}
+
+/* Wrapper for psa_crypto_init */
+psa_status_t mbedtls_test_wrap_psa_crypto_init(void)
+{
+    psa_status_t status = (psa_crypto_init)();
+    return status;
+}
+
+/* Wrapper for psa_destroy_key */
+psa_status_t mbedtls_test_wrap_psa_destroy_key(
+    mbedtls_svc_key_id_t arg0_key)
+{
+    psa_status_t status = (psa_destroy_key)(arg0_key);
+    return status;
+}
+
+/* Wrapper for psa_export_key */
+psa_status_t mbedtls_test_wrap_psa_export_key(
+    mbedtls_svc_key_id_t arg0_key,
+    uint8_t *arg1_data,
+    size_t arg2_data_size,
+    size_t *arg3_data_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_data, arg2_data_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_export_key)(arg0_key, arg1_data, arg2_data_size, arg3_data_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_data, arg2_data_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_export_public_key */
+psa_status_t mbedtls_test_wrap_psa_export_public_key(
+    mbedtls_svc_key_id_t arg0_key,
+    uint8_t *arg1_data,
+    size_t arg2_data_size,
+    size_t *arg3_data_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_data, arg2_data_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_export_public_key)(arg0_key, arg1_data, arg2_data_size, arg3_data_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_data, arg2_data_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_generate_key */
+psa_status_t mbedtls_test_wrap_psa_generate_key(
+    const psa_key_attributes_t *arg0_attributes,
+    mbedtls_svc_key_id_t *arg1_key)
+{
+    psa_status_t status = (psa_generate_key)(arg0_attributes, arg1_key);
+    return status;
+}
+
+/* Wrapper for psa_generate_key_ext */
+psa_status_t mbedtls_test_wrap_psa_generate_key_ext(
+    const psa_key_attributes_t *arg0_attributes,
+    const psa_key_production_parameters_t *arg1_params,
+    size_t arg2_params_data_length,
+    mbedtls_svc_key_id_t *arg3_key)
+{
+    psa_status_t status = (psa_generate_key_ext)(arg0_attributes, arg1_params, arg2_params_data_length, arg3_key);
+    return status;
+}
+
+/* Wrapper for psa_generate_random */
+psa_status_t mbedtls_test_wrap_psa_generate_random(
+    uint8_t *arg0_output,
+    size_t arg1_output_size)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg0_output, arg1_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_generate_random)(arg0_output, arg1_output_size);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg0_output, arg1_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_get_key_attributes */
+psa_status_t mbedtls_test_wrap_psa_get_key_attributes(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_key_attributes_t *arg1_attributes)
+{
+    psa_status_t status = (psa_get_key_attributes)(arg0_key, arg1_attributes);
+    return status;
+}
+
+/* Wrapper for psa_hash_abort */
+psa_status_t mbedtls_test_wrap_psa_hash_abort(
+    psa_hash_operation_t *arg0_operation)
+{
+    psa_status_t status = (psa_hash_abort)(arg0_operation);
+    return status;
+}
+
+/* Wrapper for psa_hash_clone */
+psa_status_t mbedtls_test_wrap_psa_hash_clone(
+    const psa_hash_operation_t *arg0_source_operation,
+    psa_hash_operation_t *arg1_target_operation)
+{
+    psa_status_t status = (psa_hash_clone)(arg0_source_operation, arg1_target_operation);
+    return status;
+}
+
+/* Wrapper for psa_hash_compare */
+psa_status_t mbedtls_test_wrap_psa_hash_compare(
+    psa_algorithm_t arg0_alg,
+    const uint8_t *arg1_input,
+    size_t arg2_input_length,
+    const uint8_t *arg3_hash,
+    size_t arg4_hash_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_input, arg2_input_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg3_hash, arg4_hash_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_hash_compare)(arg0_alg, arg1_input, arg2_input_length, arg3_hash, arg4_hash_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_input, arg2_input_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg3_hash, arg4_hash_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_hash_compute */
+psa_status_t mbedtls_test_wrap_psa_hash_compute(
+    psa_algorithm_t arg0_alg,
+    const uint8_t *arg1_input,
+    size_t arg2_input_length,
+    uint8_t *arg3_hash,
+    size_t arg4_hash_size,
+    size_t *arg5_hash_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_input, arg2_input_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg3_hash, arg4_hash_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_hash_compute)(arg0_alg, arg1_input, arg2_input_length, arg3_hash, arg4_hash_size, arg5_hash_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_input, arg2_input_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg3_hash, arg4_hash_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_hash_finish */
+psa_status_t mbedtls_test_wrap_psa_hash_finish(
+    psa_hash_operation_t *arg0_operation,
+    uint8_t *arg1_hash,
+    size_t arg2_hash_size,
+    size_t *arg3_hash_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_hash, arg2_hash_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_hash_finish)(arg0_operation, arg1_hash, arg2_hash_size, arg3_hash_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_hash, arg2_hash_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_hash_setup */
+psa_status_t mbedtls_test_wrap_psa_hash_setup(
+    psa_hash_operation_t *arg0_operation,
+    psa_algorithm_t arg1_alg)
+{
+    psa_status_t status = (psa_hash_setup)(arg0_operation, arg1_alg);
+    return status;
+}
+
+/* Wrapper for psa_hash_update */
+psa_status_t mbedtls_test_wrap_psa_hash_update(
+    psa_hash_operation_t *arg0_operation,
+    const uint8_t *arg1_input,
+    size_t arg2_input_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_input, arg2_input_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_hash_update)(arg0_operation, arg1_input, arg2_input_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_input, arg2_input_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_hash_verify */
+psa_status_t mbedtls_test_wrap_psa_hash_verify(
+    psa_hash_operation_t *arg0_operation,
+    const uint8_t *arg1_hash,
+    size_t arg2_hash_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_hash, arg2_hash_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_hash_verify)(arg0_operation, arg1_hash, arg2_hash_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_hash, arg2_hash_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_import_key */
+psa_status_t mbedtls_test_wrap_psa_import_key(
+    const psa_key_attributes_t *arg0_attributes,
+    const uint8_t *arg1_data,
+    size_t arg2_data_length,
+    mbedtls_svc_key_id_t *arg3_key)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_data, arg2_data_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_import_key)(arg0_attributes, arg1_data, arg2_data_length, arg3_key);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_data, arg2_data_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_key_derivation_abort */
+psa_status_t mbedtls_test_wrap_psa_key_derivation_abort(
+    psa_key_derivation_operation_t *arg0_operation)
+{
+    psa_status_t status = (psa_key_derivation_abort)(arg0_operation);
+    return status;
+}
+
+/* Wrapper for psa_key_derivation_get_capacity */
+psa_status_t mbedtls_test_wrap_psa_key_derivation_get_capacity(
+    const psa_key_derivation_operation_t *arg0_operation,
+    size_t *arg1_capacity)
+{
+    psa_status_t status = (psa_key_derivation_get_capacity)(arg0_operation, arg1_capacity);
+    return status;
+}
+
+/* Wrapper for psa_key_derivation_input_bytes */
+psa_status_t mbedtls_test_wrap_psa_key_derivation_input_bytes(
+    psa_key_derivation_operation_t *arg0_operation,
+    psa_key_derivation_step_t arg1_step,
+    const uint8_t *arg2_data,
+    size_t arg3_data_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg2_data, arg3_data_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_key_derivation_input_bytes)(arg0_operation, arg1_step, arg2_data, arg3_data_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg2_data, arg3_data_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_key_derivation_input_integer */
+psa_status_t mbedtls_test_wrap_psa_key_derivation_input_integer(
+    psa_key_derivation_operation_t *arg0_operation,
+    psa_key_derivation_step_t arg1_step,
+    uint64_t arg2_value)
+{
+    psa_status_t status = (psa_key_derivation_input_integer)(arg0_operation, arg1_step, arg2_value);
+    return status;
+}
+
+/* Wrapper for psa_key_derivation_input_key */
+psa_status_t mbedtls_test_wrap_psa_key_derivation_input_key(
+    psa_key_derivation_operation_t *arg0_operation,
+    psa_key_derivation_step_t arg1_step,
+    mbedtls_svc_key_id_t arg2_key)
+{
+    psa_status_t status = (psa_key_derivation_input_key)(arg0_operation, arg1_step, arg2_key);
+    return status;
+}
+
+/* Wrapper for psa_key_derivation_key_agreement */
+psa_status_t mbedtls_test_wrap_psa_key_derivation_key_agreement(
+    psa_key_derivation_operation_t *arg0_operation,
+    psa_key_derivation_step_t arg1_step,
+    mbedtls_svc_key_id_t arg2_private_key,
+    const uint8_t *arg3_peer_key,
+    size_t arg4_peer_key_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg3_peer_key, arg4_peer_key_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_key_derivation_key_agreement)(arg0_operation, arg1_step, arg2_private_key, arg3_peer_key, arg4_peer_key_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg3_peer_key, arg4_peer_key_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_key_derivation_output_bytes */
+psa_status_t mbedtls_test_wrap_psa_key_derivation_output_bytes(
+    psa_key_derivation_operation_t *arg0_operation,
+    uint8_t *arg1_output,
+    size_t arg2_output_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_output, arg2_output_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_key_derivation_output_bytes)(arg0_operation, arg1_output, arg2_output_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_output, arg2_output_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_key_derivation_output_key */
+psa_status_t mbedtls_test_wrap_psa_key_derivation_output_key(
+    const psa_key_attributes_t *arg0_attributes,
+    psa_key_derivation_operation_t *arg1_operation,
+    mbedtls_svc_key_id_t *arg2_key)
+{
+    psa_status_t status = (psa_key_derivation_output_key)(arg0_attributes, arg1_operation, arg2_key);
+    return status;
+}
+
+/* Wrapper for psa_key_derivation_output_key_ext */
+psa_status_t mbedtls_test_wrap_psa_key_derivation_output_key_ext(
+    const psa_key_attributes_t *arg0_attributes,
+    psa_key_derivation_operation_t *arg1_operation,
+    const psa_key_production_parameters_t *arg2_params,
+    size_t arg3_params_data_length,
+    mbedtls_svc_key_id_t *arg4_key)
+{
+    psa_status_t status = (psa_key_derivation_output_key_ext)(arg0_attributes, arg1_operation, arg2_params, arg3_params_data_length, arg4_key);
+    return status;
+}
+
+/* Wrapper for psa_key_derivation_set_capacity */
+psa_status_t mbedtls_test_wrap_psa_key_derivation_set_capacity(
+    psa_key_derivation_operation_t *arg0_operation,
+    size_t arg1_capacity)
+{
+    psa_status_t status = (psa_key_derivation_set_capacity)(arg0_operation, arg1_capacity);
+    return status;
+}
+
+/* Wrapper for psa_key_derivation_setup */
+psa_status_t mbedtls_test_wrap_psa_key_derivation_setup(
+    psa_key_derivation_operation_t *arg0_operation,
+    psa_algorithm_t arg1_alg)
+{
+    psa_status_t status = (psa_key_derivation_setup)(arg0_operation, arg1_alg);
+    return status;
+}
+
+/* Wrapper for psa_mac_abort */
+psa_status_t mbedtls_test_wrap_psa_mac_abort(
+    psa_mac_operation_t *arg0_operation)
+{
+    psa_status_t status = (psa_mac_abort)(arg0_operation);
+    return status;
+}
+
+/* Wrapper for psa_mac_compute */
+psa_status_t mbedtls_test_wrap_psa_mac_compute(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_input,
+    size_t arg3_input_length,
+    uint8_t *arg4_mac,
+    size_t arg5_mac_size,
+    size_t *arg6_mac_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg2_input, arg3_input_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg4_mac, arg5_mac_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_mac_compute)(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_mac, arg5_mac_size, arg6_mac_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg2_input, arg3_input_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg4_mac, arg5_mac_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_mac_sign_finish */
+psa_status_t mbedtls_test_wrap_psa_mac_sign_finish(
+    psa_mac_operation_t *arg0_operation,
+    uint8_t *arg1_mac,
+    size_t arg2_mac_size,
+    size_t *arg3_mac_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_mac, arg2_mac_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_mac_sign_finish)(arg0_operation, arg1_mac, arg2_mac_size, arg3_mac_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_mac, arg2_mac_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_mac_sign_setup */
+psa_status_t mbedtls_test_wrap_psa_mac_sign_setup(
+    psa_mac_operation_t *arg0_operation,
+    mbedtls_svc_key_id_t arg1_key,
+    psa_algorithm_t arg2_alg)
+{
+    psa_status_t status = (psa_mac_sign_setup)(arg0_operation, arg1_key, arg2_alg);
+    return status;
+}
+
+/* Wrapper for psa_mac_update */
+psa_status_t mbedtls_test_wrap_psa_mac_update(
+    psa_mac_operation_t *arg0_operation,
+    const uint8_t *arg1_input,
+    size_t arg2_input_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_input, arg2_input_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_mac_update)(arg0_operation, arg1_input, arg2_input_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_input, arg2_input_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_mac_verify */
+psa_status_t mbedtls_test_wrap_psa_mac_verify(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_input,
+    size_t arg3_input_length,
+    const uint8_t *arg4_mac,
+    size_t arg5_mac_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg2_input, arg3_input_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg4_mac, arg5_mac_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_mac_verify)(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_mac, arg5_mac_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg2_input, arg3_input_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg4_mac, arg5_mac_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_mac_verify_finish */
+psa_status_t mbedtls_test_wrap_psa_mac_verify_finish(
+    psa_mac_operation_t *arg0_operation,
+    const uint8_t *arg1_mac,
+    size_t arg2_mac_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_mac, arg2_mac_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_mac_verify_finish)(arg0_operation, arg1_mac, arg2_mac_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_mac, arg2_mac_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_mac_verify_setup */
+psa_status_t mbedtls_test_wrap_psa_mac_verify_setup(
+    psa_mac_operation_t *arg0_operation,
+    mbedtls_svc_key_id_t arg1_key,
+    psa_algorithm_t arg2_alg)
+{
+    psa_status_t status = (psa_mac_verify_setup)(arg0_operation, arg1_key, arg2_alg);
+    return status;
+}
+
+/* Wrapper for psa_pake_abort */
+psa_status_t mbedtls_test_wrap_psa_pake_abort(
+    psa_pake_operation_t *arg0_operation)
+{
+    psa_status_t status = (psa_pake_abort)(arg0_operation);
+    return status;
+}
+
+/* Wrapper for psa_pake_get_implicit_key */
+psa_status_t mbedtls_test_wrap_psa_pake_get_implicit_key(
+    psa_pake_operation_t *arg0_operation,
+    psa_key_derivation_operation_t *arg1_output)
+{
+    psa_status_t status = (psa_pake_get_implicit_key)(arg0_operation, arg1_output);
+    return status;
+}
+
+/* Wrapper for psa_pake_input */
+psa_status_t mbedtls_test_wrap_psa_pake_input(
+    psa_pake_operation_t *arg0_operation,
+    psa_pake_step_t arg1_step,
+    const uint8_t *arg2_input,
+    size_t arg3_input_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg2_input, arg3_input_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_pake_input)(arg0_operation, arg1_step, arg2_input, arg3_input_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg2_input, arg3_input_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_pake_output */
+psa_status_t mbedtls_test_wrap_psa_pake_output(
+    psa_pake_operation_t *arg0_operation,
+    psa_pake_step_t arg1_step,
+    uint8_t *arg2_output,
+    size_t arg3_output_size,
+    size_t *arg4_output_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg2_output, arg3_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_pake_output)(arg0_operation, arg1_step, arg2_output, arg3_output_size, arg4_output_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg2_output, arg3_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_pake_set_password_key */
+psa_status_t mbedtls_test_wrap_psa_pake_set_password_key(
+    psa_pake_operation_t *arg0_operation,
+    mbedtls_svc_key_id_t arg1_password)
+{
+    psa_status_t status = (psa_pake_set_password_key)(arg0_operation, arg1_password);
+    return status;
+}
+
+/* Wrapper for psa_pake_set_peer */
+psa_status_t mbedtls_test_wrap_psa_pake_set_peer(
+    psa_pake_operation_t *arg0_operation,
+    const uint8_t *arg1_peer_id,
+    size_t arg2_peer_id_len)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_peer_id, arg2_peer_id_len);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_pake_set_peer)(arg0_operation, arg1_peer_id, arg2_peer_id_len);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_peer_id, arg2_peer_id_len);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_pake_set_role */
+psa_status_t mbedtls_test_wrap_psa_pake_set_role(
+    psa_pake_operation_t *arg0_operation,
+    psa_pake_role_t arg1_role)
+{
+    psa_status_t status = (psa_pake_set_role)(arg0_operation, arg1_role);
+    return status;
+}
+
+/* Wrapper for psa_pake_set_user */
+psa_status_t mbedtls_test_wrap_psa_pake_set_user(
+    psa_pake_operation_t *arg0_operation,
+    const uint8_t *arg1_user_id,
+    size_t arg2_user_id_len)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_user_id, arg2_user_id_len);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_pake_set_user)(arg0_operation, arg1_user_id, arg2_user_id_len);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_user_id, arg2_user_id_len);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_pake_setup */
+psa_status_t mbedtls_test_wrap_psa_pake_setup(
+    psa_pake_operation_t *arg0_operation,
+    const psa_pake_cipher_suite_t *arg1_cipher_suite)
+{
+    psa_status_t status = (psa_pake_setup)(arg0_operation, arg1_cipher_suite);
+    return status;
+}
+
+/* Wrapper for psa_purge_key */
+psa_status_t mbedtls_test_wrap_psa_purge_key(
+    mbedtls_svc_key_id_t arg0_key)
+{
+    psa_status_t status = (psa_purge_key)(arg0_key);
+    return status;
+}
+
+/* Wrapper for psa_raw_key_agreement */
+psa_status_t mbedtls_test_wrap_psa_raw_key_agreement(
+    psa_algorithm_t arg0_alg,
+    mbedtls_svc_key_id_t arg1_private_key,
+    const uint8_t *arg2_peer_key,
+    size_t arg3_peer_key_length,
+    uint8_t *arg4_output,
+    size_t arg5_output_size,
+    size_t *arg6_output_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg2_peer_key, arg3_peer_key_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg4_output, arg5_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_raw_key_agreement)(arg0_alg, arg1_private_key, arg2_peer_key, arg3_peer_key_length, arg4_output, arg5_output_size, arg6_output_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg2_peer_key, arg3_peer_key_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg4_output, arg5_output_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_sign_hash */
+psa_status_t mbedtls_test_wrap_psa_sign_hash(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_hash,
+    size_t arg3_hash_length,
+    uint8_t *arg4_signature,
+    size_t arg5_signature_size,
+    size_t *arg6_signature_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg2_hash, arg3_hash_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg4_signature, arg5_signature_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_sign_hash)(arg0_key, arg1_alg, arg2_hash, arg3_hash_length, arg4_signature, arg5_signature_size, arg6_signature_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg2_hash, arg3_hash_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg4_signature, arg5_signature_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_sign_hash_abort */
+psa_status_t mbedtls_test_wrap_psa_sign_hash_abort(
+    psa_sign_hash_interruptible_operation_t *arg0_operation)
+{
+    psa_status_t status = (psa_sign_hash_abort)(arg0_operation);
+    return status;
+}
+
+/* Wrapper for psa_sign_hash_complete */
+psa_status_t mbedtls_test_wrap_psa_sign_hash_complete(
+    psa_sign_hash_interruptible_operation_t *arg0_operation,
+    uint8_t *arg1_signature,
+    size_t arg2_signature_size,
+    size_t *arg3_signature_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg1_signature, arg2_signature_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_sign_hash_complete)(arg0_operation, arg1_signature, arg2_signature_size, arg3_signature_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg1_signature, arg2_signature_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_sign_hash_start */
+psa_status_t mbedtls_test_wrap_psa_sign_hash_start(
+    psa_sign_hash_interruptible_operation_t *arg0_operation,
+    mbedtls_svc_key_id_t arg1_key,
+    psa_algorithm_t arg2_alg,
+    const uint8_t *arg3_hash,
+    size_t arg4_hash_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg3_hash, arg4_hash_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_sign_hash_start)(arg0_operation, arg1_key, arg2_alg, arg3_hash, arg4_hash_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg3_hash, arg4_hash_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_sign_message */
+psa_status_t mbedtls_test_wrap_psa_sign_message(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_input,
+    size_t arg3_input_length,
+    uint8_t *arg4_signature,
+    size_t arg5_signature_size,
+    size_t *arg6_signature_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg2_input, arg3_input_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg4_signature, arg5_signature_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_sign_message)(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_signature, arg5_signature_size, arg6_signature_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg2_input, arg3_input_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg4_signature, arg5_signature_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_verify_hash */
+psa_status_t mbedtls_test_wrap_psa_verify_hash(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_hash,
+    size_t arg3_hash_length,
+    const uint8_t *arg4_signature,
+    size_t arg5_signature_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg2_hash, arg3_hash_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg4_signature, arg5_signature_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_verify_hash)(arg0_key, arg1_alg, arg2_hash, arg3_hash_length, arg4_signature, arg5_signature_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg2_hash, arg3_hash_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg4_signature, arg5_signature_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_verify_hash_abort */
+psa_status_t mbedtls_test_wrap_psa_verify_hash_abort(
+    psa_verify_hash_interruptible_operation_t *arg0_operation)
+{
+    psa_status_t status = (psa_verify_hash_abort)(arg0_operation);
+    return status;
+}
+
+/* Wrapper for psa_verify_hash_complete */
+psa_status_t mbedtls_test_wrap_psa_verify_hash_complete(
+    psa_verify_hash_interruptible_operation_t *arg0_operation)
+{
+    psa_status_t status = (psa_verify_hash_complete)(arg0_operation);
+    return status;
+}
+
+/* Wrapper for psa_verify_hash_start */
+psa_status_t mbedtls_test_wrap_psa_verify_hash_start(
+    psa_verify_hash_interruptible_operation_t *arg0_operation,
+    mbedtls_svc_key_id_t arg1_key,
+    psa_algorithm_t arg2_alg,
+    const uint8_t *arg3_hash,
+    size_t arg4_hash_length,
+    const uint8_t *arg5_signature,
+    size_t arg6_signature_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg3_hash, arg4_hash_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg5_signature, arg6_signature_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_verify_hash_start)(arg0_operation, arg1_key, arg2_alg, arg3_hash, arg4_hash_length, arg5_signature, arg6_signature_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg3_hash, arg4_hash_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg5_signature, arg6_signature_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_verify_message */
+psa_status_t mbedtls_test_wrap_psa_verify_message(
+    mbedtls_svc_key_id_t arg0_key,
+    psa_algorithm_t arg1_alg,
+    const uint8_t *arg2_input,
+    size_t arg3_input_length,
+    const uint8_t *arg4_signature,
+    size_t arg5_signature_length)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg2_input, arg3_input_length);
+    MBEDTLS_TEST_MEMORY_POISON(arg4_signature, arg5_signature_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_verify_message)(arg0_key, arg1_alg, arg2_input, arg3_input_length, arg4_signature, arg5_signature_length);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg2_input, arg3_input_length);
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg4_signature, arg5_signature_length);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+#endif /* defined(MBEDTLS_PSA_CRYPTO_C) && defined(MBEDTLS_TEST_HOOKS) && \
+    !defined(RECORD_PSA_STATUS_COVERAGE_LOG) */
+
+/* End of automatically generated file. */
diff --git a/tests/src/test_memory.c b/tests/src/test_memory.c
new file mode 100644
index 0000000..ac9dde6
--- /dev/null
+++ b/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/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 3377f15..a7c4020 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -12155,6 +12155,30 @@
             -s "ECDH/FFDH group: " \
             -s "selected signature algorithm ecdsa_secp256r1_sha256"
 
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
+requires_config_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED
+requires_any_configs_enabled $TLS1_2_KEY_EXCHANGES_WITH_CERT
+run_test    "Establish TLS 1.2 then TLS 1.3 session" \
+            "$P_SRV" \
+            "( $P_CLI force_version=tls12; \
+               $P_CLI force_version=tls13 )" \
+            0 \
+            -s "Protocol is TLSv1.2" \
+            -s "Protocol is TLSv1.3" \
+
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
+requires_config_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED
+requires_any_configs_enabled $TLS1_2_KEY_EXCHANGES_WITH_CERT
+run_test    "Establish TLS 1.3 then TLS 1.2 session" \
+            "$P_SRV" \
+            "( $P_CLI force_version=tls13; \
+               $P_CLI force_version=tls12 )" \
+            0 \
+            -s "Protocol is TLSv1.3" \
+            -s "Protocol is TLSv1.2" \
+
 requires_openssl_tls1_3_with_compatible_ephemeral
 requires_config_enabled MBEDTLS_DEBUG_C
 requires_config_enabled MBEDTLS_SSL_CLI_C
diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function
index 73d27fe..442a362 100644
--- a/tests/suites/test_suite_pk.function
+++ b/tests/suites/test_suite_pk.function
@@ -2089,6 +2089,19 @@
     memset(hash, 0x2a, sizeof(hash));
     memset(sig, 0, sizeof(sig));
 
+#if defined(MBEDTLS_PKCS1_V21)
+    /* Check that trying to use the wrong pk_type in sign_ext() results in a failure.
+     * The PSA key was setup to use PKCS1 v1.5 signature algorithm, but here we try
+     * to use it for PSS (PKCS1 v2.1) and it should fail. */
+    if (key_pk_type == MBEDTLS_PK_RSA) {
+        TEST_EQUAL(mbedtls_pk_sign_ext(MBEDTLS_PK_RSASSA_PSS, &pk, md_alg, hash, hash_len,
+                                       sig, sizeof(sig), &sig_len,
+                                       mbedtls_test_rnd_std_rand, NULL),
+                   MBEDTLS_ERR_RSA_BAD_INPUT_DATA);
+    }
+#endif /* MBEDTLS_PKCS1_V21 */
+
+    /* Perform sign_ext() with the correct pk_type. */
     TEST_EQUAL(mbedtls_pk_sign_ext(key_pk_type, &pk, md_alg, hash, hash_len,
                                    sig, sizeof(sig), &sig_len,
                                    mbedtls_test_rnd_std_rand, NULL), 0);
diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data
index a3a457d..4f29a7a 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -2736,6 +2736,11 @@
 depends_on:PSA_WANT_ALG_CBC_NO_PADDING:PSA_WANT_KEY_TYPE_AES
 cipher_verify_output_multipart:PSA_ALG_CBC_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"6bc1bee22e409f96e93d7e117393172a":16
 
+# Encrypt 48 bytes total, initially 16. This forces both calls to update() to output data.
+PSA symmetric encrypt/decrypt multipart: AES-CBC-nopad, 48 bytes, good
+depends_on:PSA_WANT_ALG_CBC_NO_PADDING:PSA_WANT_KEY_TYPE_AES
+cipher_verify_output_multipart:PSA_ALG_CBC_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"6bc1bee22e409f96e93d7e117393172a6bc1bee22e409f96e93d7e117393172a6bc1bee22e409f96e93d7e117393172a":16
+
 PSA symmetric encrypt/decrypt multipart: AES-CBC-PKCS#7, 16 bytes
 depends_on:PSA_WANT_ALG_CBC_PKCS7:PSA_WANT_KEY_TYPE_AES
 cipher_verify_output_multipart:PSA_ALG_CBC_PKCS7:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"6bc1bee22e409f96e93d7e117393172a":16
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index 7a242fd..0c8552b 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -15,7 +15,6 @@
 #include "psa/crypto.h"
 #include "psa_crypto_slot_management.h"
 
-/* For psa_can_do_hash() */
 #include "psa_crypto_core.h"
 
 #include "test/asn1_helpers.h"
@@ -747,37 +746,37 @@
             /* Server first round Output */
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_KEY_SHARE,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_g1_len));
+                                       buffer_length - buffer0_off, &s_g1_len));
             TEST_EQUAL(s_g1_len, expected_size_key_share);
             s_g1_off = buffer0_off;
             buffer0_off += s_g1_len;
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PUBLIC,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_x1_pk_len));
+                                       buffer_length - buffer0_off, &s_x1_pk_len));
             TEST_EQUAL(s_x1_pk_len, expected_size_zk_public);
             s_x1_pk_off = buffer0_off;
             buffer0_off += s_x1_pk_len;
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PROOF,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_x1_pr_len));
+                                       buffer_length - buffer0_off, &s_x1_pr_len));
             TEST_LE_U(s_x1_pr_len, max_expected_size_zk_proof);
             s_x1_pr_off = buffer0_off;
             buffer0_off += s_x1_pr_len;
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_KEY_SHARE,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_g2_len));
+                                       buffer_length - buffer0_off, &s_g2_len));
             TEST_EQUAL(s_g2_len, expected_size_key_share);
             s_g2_off = buffer0_off;
             buffer0_off += s_g2_len;
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PUBLIC,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_x2_pk_len));
+                                       buffer_length - buffer0_off, &s_x2_pk_len));
             TEST_EQUAL(s_x2_pk_len, expected_size_zk_public);
             s_x2_pk_off = buffer0_off;
             buffer0_off += s_x2_pk_len;
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PROOF,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_x2_pr_len));
+                                       buffer_length - buffer0_off, &s_x2_pr_len));
             TEST_LE_U(s_x2_pr_len, max_expected_size_zk_proof);
             s_x2_pr_off = buffer0_off;
             buffer0_off += s_x2_pr_len;
@@ -867,37 +866,37 @@
             /* Client first round Output */
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_KEY_SHARE,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_g1_len));
+                                       buffer_length - buffer1_off, &c_g1_len));
             TEST_EQUAL(c_g1_len, expected_size_key_share);
             c_g1_off = buffer1_off;
             buffer1_off += c_g1_len;
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PUBLIC,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_x1_pk_len));
+                                       buffer_length - buffer1_off, &c_x1_pk_len));
             TEST_EQUAL(c_x1_pk_len, expected_size_zk_public);
             c_x1_pk_off = buffer1_off;
             buffer1_off += c_x1_pk_len;
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PROOF,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_x1_pr_len));
+                                       buffer_length - buffer1_off, &c_x1_pr_len));
             TEST_LE_U(c_x1_pr_len, max_expected_size_zk_proof);
             c_x1_pr_off = buffer1_off;
             buffer1_off += c_x1_pr_len;
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_KEY_SHARE,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_g2_len));
+                                       buffer_length - buffer1_off, &c_g2_len));
             TEST_EQUAL(c_g2_len, expected_size_key_share);
             c_g2_off = buffer1_off;
             buffer1_off += c_g2_len;
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PUBLIC,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_x2_pk_len));
+                                       buffer_length - buffer1_off, &c_x2_pk_len));
             TEST_EQUAL(c_x2_pk_len, expected_size_zk_public);
             c_x2_pk_off = buffer1_off;
             buffer1_off += c_x2_pk_len;
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PROOF,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_x2_pr_len));
+                                       buffer_length - buffer1_off, &c_x2_pr_len));
             TEST_LE_U(c_x2_pr_len, max_expected_size_zk_proof);
             c_x2_pr_off = buffer1_off;
             buffer1_off += c_x2_pr_len;
@@ -1045,19 +1044,19 @@
 
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_KEY_SHARE,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_a_len));
+                                       buffer_length - buffer0_off, &s_a_len));
             TEST_EQUAL(s_a_len, expected_size_key_share);
             s_a_off = buffer0_off;
             buffer0_off += s_a_len;
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PUBLIC,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_x2s_pk_len));
+                                       buffer_length - buffer0_off, &s_x2s_pk_len));
             TEST_EQUAL(s_x2s_pk_len, expected_size_zk_public);
             s_x2s_pk_off = buffer0_off;
             buffer0_off += s_x2s_pk_len;
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PROOF,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_x2s_pr_len));
+                                       buffer_length - buffer0_off, &s_x2s_pr_len));
             TEST_LE_U(s_x2s_pr_len, max_expected_size_zk_proof);
             s_x2s_pr_off = buffer0_off;
             buffer0_off += s_x2s_pr_len;
@@ -1110,19 +1109,19 @@
 
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_KEY_SHARE,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_a_len));
+                                       buffer_length - buffer1_off, &c_a_len));
             TEST_EQUAL(c_a_len, expected_size_key_share);
             c_a_off = buffer1_off;
             buffer1_off += c_a_len;
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PUBLIC,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_x2s_pk_len));
+                                       buffer_length - buffer1_off, &c_x2s_pk_len));
             TEST_EQUAL(c_x2s_pk_len, expected_size_zk_public);
             c_x2s_pk_off = buffer1_off;
             buffer1_off += c_x2s_pk_len;
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PROOF,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_x2s_pr_len));
+                                       buffer_length - buffer1_off, &c_x2s_pr_len));
             TEST_LE_U(c_x2s_pr_len, max_expected_size_zk_proof);
             c_x2s_pr_off = buffer1_off;
             buffer1_off += c_x2s_pr_len;
@@ -4950,7 +4949,8 @@
     PSA_ASSERT(psa_cipher_update(&operation1,
                                  input->x + first_part_size,
                                  input->len - first_part_size,
-                                 output1, output1_buffer_size,
+                                 output1 + output1_length,
+                                 output1_buffer_size - output1_length,
                                  &function_output_length));
     TEST_LE_U(function_output_length,
               PSA_CIPHER_UPDATE_OUTPUT_SIZE(key_type,
@@ -4996,7 +4996,8 @@
     PSA_ASSERT(psa_cipher_update(&operation2,
                                  output1 + first_part_size,
                                  output1_length - first_part_size,
-                                 output2, output2_buffer_size,
+                                 output2 + output2_length,
+                                 output2_buffer_size - output2_length,
                                  &function_output_length));
     TEST_LE_U(function_output_length,
               PSA_CIPHER_UPDATE_OUTPUT_SIZE(key_type,
@@ -5464,7 +5465,9 @@
     psa_key_type_t key_type = key_type_arg;
     psa_algorithm_t alg = alg_arg;
     psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT;
-    uint8_t nonce_buffer[PSA_AEAD_NONCE_MAX_SIZE];
+    /* Some tests try to get more than the maximum nonce length,
+     * so allocate double. */
+    uint8_t nonce_buffer[PSA_AEAD_NONCE_MAX_SIZE * 2];
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
     psa_status_t status = PSA_ERROR_GENERIC_ERROR;
     psa_status_t expected_status = expected_status_arg;
diff --git a/tests/suites/test_suite_psa_crypto_driver_wrappers.function b/tests/suites/test_suite_psa_crypto_driver_wrappers.function
index 032fa47..a788827 100644
--- a/tests/suites/test_suite_psa_crypto_driver_wrappers.function
+++ b/tests/suites/test_suite_psa_crypto_driver_wrappers.function
@@ -57,7 +57,7 @@
             /* Server first round Output */
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_KEY_SHARE,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_g1_len));
+                                       buffer_length - buffer0_off, &s_g1_len));
             TEST_EQUAL(mbedtls_test_driver_pake_hooks.hits.total,
                        pake_in_driver ? pake_expected_hit_count++ : pake_expected_hit_count);
             TEST_EQUAL(s_g1_len, expected_size_key_share);
@@ -65,7 +65,7 @@
             buffer0_off += s_g1_len;
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PUBLIC,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_x1_pk_len));
+                                       buffer_length - buffer0_off, &s_x1_pk_len));
             TEST_EQUAL(mbedtls_test_driver_pake_hooks.hits.total,
                        pake_in_driver ? pake_expected_hit_count++ : pake_expected_hit_count);
             TEST_EQUAL(s_x1_pk_len, expected_size_zk_public);
@@ -73,7 +73,7 @@
             buffer0_off += s_x1_pk_len;
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PROOF,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_x1_pr_len));
+                                       buffer_length - buffer0_off, &s_x1_pr_len));
             TEST_EQUAL(mbedtls_test_driver_pake_hooks.hits.total,
                        pake_in_driver ? pake_expected_hit_count++ : pake_expected_hit_count);
             TEST_LE_U(s_x1_pr_len, max_expected_size_zk_proof);
@@ -81,7 +81,7 @@
             buffer0_off += s_x1_pr_len;
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_KEY_SHARE,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_g2_len));
+                                       buffer_length - buffer0_off, &s_g2_len));
             TEST_EQUAL(mbedtls_test_driver_pake_hooks.hits.total,
                        pake_in_driver ? pake_expected_hit_count++ : pake_expected_hit_count);
             TEST_EQUAL(s_g2_len, expected_size_key_share);
@@ -89,7 +89,7 @@
             buffer0_off += s_g2_len;
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PUBLIC,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_x2_pk_len));
+                                       buffer_length - buffer0_off, &s_x2_pk_len));
             TEST_EQUAL(mbedtls_test_driver_pake_hooks.hits.total,
                        pake_in_driver ? pake_expected_hit_count++ : pake_expected_hit_count);
             TEST_EQUAL(s_x2_pk_len, expected_size_zk_public);
@@ -97,7 +97,7 @@
             buffer0_off += s_x2_pk_len;
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PROOF,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_x2_pr_len));
+                                       buffer_length - buffer0_off, &s_x2_pr_len));
             TEST_EQUAL(mbedtls_test_driver_pake_hooks.hits.total,
                        pake_in_driver ? pake_expected_hit_count++ : pake_expected_hit_count);
             TEST_LE_U(s_x2_pr_len, max_expected_size_zk_proof);
@@ -154,7 +154,7 @@
             /* Client first round Output */
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_KEY_SHARE,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_g1_len));
+                                       buffer_length - buffer1_off, &c_g1_len));
             TEST_EQUAL(mbedtls_test_driver_pake_hooks.hits.total,
                        pake_in_driver ? pake_expected_hit_count++ : pake_expected_hit_count);
             TEST_EQUAL(c_g1_len, expected_size_key_share);
@@ -162,7 +162,7 @@
             buffer1_off += c_g1_len;
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PUBLIC,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_x1_pk_len));
+                                       buffer_length - buffer1_off, &c_x1_pk_len));
             TEST_EQUAL(mbedtls_test_driver_pake_hooks.hits.total,
                        pake_in_driver ? pake_expected_hit_count++ : pake_expected_hit_count);
             TEST_EQUAL(c_x1_pk_len, expected_size_zk_public);
@@ -170,7 +170,7 @@
             buffer1_off += c_x1_pk_len;
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PROOF,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_x1_pr_len));
+                                       buffer_length - buffer1_off, &c_x1_pr_len));
             TEST_EQUAL(mbedtls_test_driver_pake_hooks.hits.total,
                        pake_in_driver ? pake_expected_hit_count++ : pake_expected_hit_count);
             TEST_LE_U(c_x1_pr_len, max_expected_size_zk_proof);
@@ -178,7 +178,7 @@
             buffer1_off += c_x1_pr_len;
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_KEY_SHARE,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_g2_len));
+                                       buffer_length - buffer1_off, &c_g2_len));
             TEST_EQUAL(mbedtls_test_driver_pake_hooks.hits.total,
                        pake_in_driver ? pake_expected_hit_count++ : pake_expected_hit_count);
             TEST_EQUAL(c_g2_len, expected_size_key_share);
@@ -186,7 +186,7 @@
             buffer1_off += c_g2_len;
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PUBLIC,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_x2_pk_len));
+                                       buffer_length - buffer1_off, &c_x2_pk_len));
             TEST_EQUAL(mbedtls_test_driver_pake_hooks.hits.total,
                        pake_in_driver ? pake_expected_hit_count++ : pake_expected_hit_count);
             TEST_EQUAL(c_x2_pk_len, expected_size_zk_public);
@@ -194,7 +194,7 @@
             buffer1_off += c_x2_pk_len;
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PROOF,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_x2_pr_len));
+                                       buffer_length - buffer1_off, &c_x2_pr_len));
             TEST_EQUAL(mbedtls_test_driver_pake_hooks.hits.total,
                        pake_in_driver ? pake_expected_hit_count++ : pake_expected_hit_count);
             TEST_LE_U(c_x2_pr_len, max_expected_size_zk_proof);
@@ -290,7 +290,7 @@
 
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_KEY_SHARE,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_a_len));
+                                       buffer_length - buffer0_off, &s_a_len));
             TEST_EQUAL(mbedtls_test_driver_pake_hooks.hits.total,
                        pake_in_driver ? pake_expected_hit_count++ : pake_expected_hit_count);
             TEST_EQUAL(s_a_len, expected_size_key_share);
@@ -298,7 +298,7 @@
             buffer0_off += s_a_len;
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PUBLIC,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_x2s_pk_len));
+                                       buffer_length - buffer0_off, &s_x2s_pk_len));
             TEST_EQUAL(mbedtls_test_driver_pake_hooks.hits.total,
                        pake_in_driver ? pake_expected_hit_count++ : pake_expected_hit_count);
             TEST_EQUAL(s_x2s_pk_len, expected_size_zk_public);
@@ -306,7 +306,7 @@
             buffer0_off += s_x2s_pk_len;
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PROOF,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_x2s_pr_len));
+                                       buffer_length - buffer0_off, &s_x2s_pr_len));
             TEST_EQUAL(mbedtls_test_driver_pake_hooks.hits.total,
                        pake_in_driver ? pake_expected_hit_count++ : pake_expected_hit_count);
             TEST_LE_U(s_x2s_pr_len, max_expected_size_zk_proof);
@@ -341,7 +341,7 @@
 
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_KEY_SHARE,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_a_len));
+                                       buffer_length - buffer1_off, &c_a_len));
             TEST_EQUAL(mbedtls_test_driver_pake_hooks.hits.total,
                        pake_in_driver ? pake_expected_hit_count++ : pake_expected_hit_count);
             TEST_EQUAL(c_a_len, expected_size_key_share);
@@ -349,7 +349,7 @@
             buffer1_off += c_a_len;
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PUBLIC,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_x2s_pk_len));
+                                       buffer_length - buffer1_off, &c_x2s_pk_len));
             TEST_EQUAL(mbedtls_test_driver_pake_hooks.hits.total,
                        pake_in_driver ? pake_expected_hit_count++ : pake_expected_hit_count);
             TEST_EQUAL(c_x2s_pk_len, expected_size_zk_public);
@@ -357,7 +357,7 @@
             buffer1_off += c_x2s_pk_len;
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PROOF,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_x2s_pr_len));
+                                       buffer_length - buffer1_off, &c_x2s_pr_len));
             TEST_EQUAL(mbedtls_test_driver_pake_hooks.hits.total,
                        pake_in_driver ? pake_expected_hit_count++ : pake_expected_hit_count);
             TEST_LE_U(c_x2s_pr_len, max_expected_size_zk_proof);
@@ -1495,14 +1495,7 @@
         output, output_buffer_size, &function_output_length);
     TEST_EQUAL(mbedtls_test_driver_cipher_hooks.hits_encrypt, 1);
     TEST_EQUAL(status, PSA_ERROR_GENERIC_ERROR);
-    /*
-     * Check that the output buffer is still in the same state.
-     * This will fail if the output buffer is used by the core to pass the IV
-     * it generated to the driver (and is not restored).
-     */
-    for (size_t i = 0; i < output_buffer_size; i++) {
-        TEST_EQUAL(output[i], 0xa5);
-    }
+
     mbedtls_test_driver_cipher_hooks.hits = 0;
 
     /* Test setup call, encrypt */
@@ -1566,14 +1559,6 @@
     TEST_EQUAL(mbedtls_test_driver_cipher_hooks.hits_set_iv, 1);
     TEST_EQUAL(status, mbedtls_test_driver_cipher_hooks.forced_status_set_iv);
     mbedtls_test_driver_cipher_hooks.forced_status_set_iv = PSA_SUCCESS;
-    /*
-     * Check that the output buffer is still in the same state.
-     * This will fail if the output buffer is used by the core to pass the IV
-     * it generated to the driver (and is not restored).
-     */
-    for (size_t i = 0; i < 16; i++) {
-        TEST_EQUAL(output[i], 0xa5);
-    }
     /* Failure should prevent further operations from executing on the driver */
     mbedtls_test_driver_cipher_hooks.hits = 0;
     status = psa_cipher_update(&operation,
diff --git a/tests/suites/test_suite_psa_crypto_memory.data b/tests/suites/test_suite_psa_crypto_memory.data
new file mode 100644
index 0000000..2a828f5
--- /dev/null
+++ b/tests/suites/test_suite_psa_crypto_memory.data
@@ -0,0 +1,62 @@
+PSA input buffer copy: straightforward copy
+copy_input:20:20:PSA_SUCCESS
+
+PSA input buffer copy: copy buffer larger than required
+copy_input:10:20:PSA_SUCCESS
+
+PSA input buffer copy: copy buffer too small
+copy_input:20:10:PSA_ERROR_CORRUPTION_DETECTED
+
+PSA input buffer copy: zero-length source buffer
+copy_input:0:10:PSA_SUCCESS
+
+PSA input buffer copy: zero-length both buffers
+copy_input:0:0:PSA_SUCCESS
+
+PSA output buffer copy: straightforward copy
+copy_output:20:20:PSA_SUCCESS
+
+PSA output buffer copy: output buffer larger than required
+copy_output:10:20:PSA_SUCCESS
+
+PSA output buffer copy: output buffer too small
+copy_output:20:10:PSA_ERROR_BUFFER_TOO_SMALL
+
+PSA output buffer copy: zero-length source buffer
+copy_output:0:10:PSA_SUCCESS
+
+PSA output buffer copy: zero-length both buffers
+copy_output:0:0:PSA_SUCCESS
+
+PSA crypto local input alloc
+local_input_alloc:200:PSA_SUCCESS
+
+PSA crypto local input alloc, NULL buffer
+local_input_alloc:0:PSA_SUCCESS
+
+PSA crypto local input free
+local_input_free:200
+
+PSA crypto local input free, NULL buffer
+local_input_free:0
+
+PSA crypto local input round-trip
+local_input_round_trip
+
+PSA crypto local output alloc
+local_output_alloc:200:PSA_SUCCESS
+
+PSA crypto local output alloc, NULL buffer
+local_output_alloc:0:PSA_SUCCESS
+
+PSA crypto local output free
+local_output_free:200:0:PSA_SUCCESS
+
+PSA crypto local output free, NULL buffer
+local_output_free:0:0:PSA_SUCCESS
+
+PSA crypto local output free, NULL original buffer
+local_output_free:200:1:PSA_ERROR_CORRUPTION_DETECTED
+
+PSA crypto local output round-trip
+local_output_round_trip
diff --git a/tests/suites/test_suite_psa_crypto_memory.function b/tests/suites/test_suite_psa_crypto_memory.function
new file mode 100644
index 0000000..55c0092
--- /dev/null
+++ b/tests/suites/test_suite_psa_crypto_memory.function
@@ -0,0 +1,258 @@
+/* BEGIN_HEADER */
+#include <stdint.h>
+
+#include "common.h"
+
+#include "psa/crypto.h"
+
+#include "psa_crypto_core.h"
+#include "psa_crypto_invasive.h"
+
+#include "test/psa_crypto_helpers.h"
+#include "test/memory.h"
+
+/* Helper to fill a buffer with a data pattern. The pattern is not
+ * important, it just allows a basic check that the correct thing has
+ * been written, in a way that will detect an error in offset. */
+static void fill_buffer_pattern(uint8_t *buffer, size_t len)
+{
+    for (size_t i = 0; i < len; i++) {
+        buffer[i] = (uint8_t) (i % 256);
+    }
+}
+/* END_HEADER */
+
+/* BEGIN_DEPENDENCIES
+ * depends_on:MBEDTLS_PSA_CRYPTO_C:MBEDTLS_TEST_HOOKS
+ * END_DEPENDENCIES
+ */
+
+/* BEGIN_CASE */
+void copy_input(int src_len, int dst_len, psa_status_t exp_status)
+{
+    uint8_t *src_buffer = NULL;
+    uint8_t *dst_buffer = NULL;
+    psa_status_t status;
+
+    TEST_CALLOC(src_buffer, src_len);
+    TEST_CALLOC(dst_buffer, dst_len);
+
+    fill_buffer_pattern(src_buffer, src_len);
+
+    status = psa_crypto_copy_input(src_buffer, src_len, dst_buffer, dst_len);
+    TEST_EQUAL(status, exp_status);
+
+    if (exp_status == PSA_SUCCESS) {
+        MBEDTLS_TEST_MEMORY_UNPOISON(src_buffer, src_len);
+        /* Note: We compare the first src_len bytes of each buffer, as this is what was copied. */
+        TEST_MEMORY_COMPARE(src_buffer, src_len, dst_buffer, src_len);
+    }
+
+exit:
+    mbedtls_free(src_buffer);
+    mbedtls_free(dst_buffer);
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void copy_output(int src_len, int dst_len, psa_status_t exp_status)
+{
+    uint8_t *src_buffer = NULL;
+    uint8_t *dst_buffer = NULL;
+    psa_status_t status;
+
+    TEST_CALLOC(src_buffer, src_len);
+    TEST_CALLOC(dst_buffer, dst_len);
+
+    fill_buffer_pattern(src_buffer, src_len);
+
+    status = psa_crypto_copy_output(src_buffer, src_len, dst_buffer, dst_len);
+    TEST_EQUAL(status, exp_status);
+
+    if (exp_status == PSA_SUCCESS) {
+        MBEDTLS_TEST_MEMORY_UNPOISON(dst_buffer, dst_len);
+        /* Note: We compare the first src_len bytes of each buffer, as this is what was copied. */
+        TEST_MEMORY_COMPARE(src_buffer, src_len, dst_buffer, src_len);
+    }
+
+exit:
+    mbedtls_free(src_buffer);
+    mbedtls_free(dst_buffer);
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void local_input_alloc(int input_len, psa_status_t exp_status)
+{
+    uint8_t *input = NULL;
+    psa_crypto_local_input_t local_input;
+    psa_status_t status;
+
+    local_input.buffer = NULL;
+
+    TEST_CALLOC(input, input_len);
+    fill_buffer_pattern(input, input_len);
+
+    status = psa_crypto_local_input_alloc(input, input_len, &local_input);
+    TEST_EQUAL(status, exp_status);
+
+    if (exp_status == PSA_SUCCESS) {
+        MBEDTLS_TEST_MEMORY_UNPOISON(input, input_len);
+        if (input_len != 0) {
+            TEST_ASSERT(local_input.buffer != input);
+        }
+        TEST_MEMORY_COMPARE(input, input_len,
+                            local_input.buffer, local_input.length);
+    }
+
+exit:
+    mbedtls_free(local_input.buffer);
+    mbedtls_free(input);
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void local_input_free(int input_len)
+{
+    psa_crypto_local_input_t local_input;
+
+    local_input.buffer = NULL;
+    local_input.length = input_len;
+    TEST_CALLOC(local_input.buffer, local_input.length);
+
+    psa_crypto_local_input_free(&local_input);
+
+    TEST_ASSERT(local_input.buffer == NULL);
+    TEST_EQUAL(local_input.length, 0);
+
+exit:
+    mbedtls_free(local_input.buffer);
+    local_input.buffer = NULL;
+    local_input.length = 0;
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void local_input_round_trip()
+{
+    psa_crypto_local_input_t local_input;
+    uint8_t input[200];
+    psa_status_t status;
+
+    fill_buffer_pattern(input, sizeof(input));
+
+    status = psa_crypto_local_input_alloc(input, sizeof(input), &local_input);
+    TEST_EQUAL(status, PSA_SUCCESS);
+
+    MBEDTLS_TEST_MEMORY_UNPOISON(input, sizeof(input));
+    TEST_MEMORY_COMPARE(local_input.buffer, local_input.length,
+                        input, sizeof(input));
+    TEST_ASSERT(local_input.buffer != input);
+
+    psa_crypto_local_input_free(&local_input);
+    TEST_ASSERT(local_input.buffer == NULL);
+    TEST_EQUAL(local_input.length, 0);
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void local_output_alloc(int output_len, psa_status_t exp_status)
+{
+    uint8_t *output = NULL;
+    psa_crypto_local_output_t local_output;
+    psa_status_t status;
+
+    local_output.buffer = NULL;
+
+    TEST_CALLOC(output, output_len);
+
+    status = psa_crypto_local_output_alloc(output, output_len, &local_output);
+    TEST_EQUAL(status, exp_status);
+
+    if (exp_status == PSA_SUCCESS) {
+        TEST_ASSERT(local_output.original == output);
+        TEST_EQUAL(local_output.length, output_len);
+    }
+
+exit:
+    mbedtls_free(local_output.buffer);
+    local_output.original = NULL;
+    local_output.buffer = NULL;
+    local_output.length = 0;
+    mbedtls_free(output);
+    output = NULL;
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void local_output_free(int output_len, int original_is_null,
+                       psa_status_t exp_status)
+{
+    uint8_t *output = NULL;
+    uint8_t *buffer_copy_for_comparison = NULL;
+    psa_crypto_local_output_t local_output = PSA_CRYPTO_LOCAL_OUTPUT_INIT;
+    psa_status_t status;
+
+    if (!original_is_null) {
+        TEST_CALLOC(output, output_len);
+    }
+    TEST_CALLOC(buffer_copy_for_comparison, output_len);
+    TEST_CALLOC(local_output.buffer, output_len);
+    local_output.length = output_len;
+    local_output.original = output;
+
+    if (local_output.length != 0) {
+        fill_buffer_pattern(local_output.buffer, local_output.length);
+        memcpy(buffer_copy_for_comparison, local_output.buffer, local_output.length);
+    }
+
+    status = psa_crypto_local_output_free(&local_output);
+    TEST_EQUAL(status, exp_status);
+
+    if (exp_status == PSA_SUCCESS) {
+        MBEDTLS_TEST_MEMORY_UNPOISON(output, output_len);
+        TEST_ASSERT(local_output.buffer == NULL);
+        TEST_EQUAL(local_output.length, 0);
+        TEST_MEMORY_COMPARE(buffer_copy_for_comparison, output_len,
+                            output, output_len);
+    }
+
+exit:
+    mbedtls_free(output);
+    mbedtls_free(buffer_copy_for_comparison);
+    mbedtls_free(local_output.buffer);
+    local_output.length = 0;
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void local_output_round_trip()
+{
+    psa_crypto_local_output_t local_output;
+    uint8_t output[200];
+    uint8_t *buffer_copy_for_comparison = NULL;
+    psa_status_t status;
+
+    status = psa_crypto_local_output_alloc(output, sizeof(output), &local_output);
+    TEST_EQUAL(status, PSA_SUCCESS);
+    TEST_ASSERT(local_output.buffer != output);
+
+    /* Simulate the function generating output */
+    fill_buffer_pattern(local_output.buffer, local_output.length);
+
+    TEST_CALLOC(buffer_copy_for_comparison, local_output.length);
+    memcpy(buffer_copy_for_comparison, local_output.buffer, local_output.length);
+
+    psa_crypto_local_output_free(&local_output);
+    TEST_ASSERT(local_output.buffer == NULL);
+    TEST_EQUAL(local_output.length, 0);
+
+    MBEDTLS_TEST_MEMORY_UNPOISON(output, sizeof(output));
+    /* Check that the buffer was correctly copied back */
+    TEST_MEMORY_COMPARE(output, sizeof(output),
+                        buffer_copy_for_comparison, sizeof(output));
+
+exit:
+    mbedtls_free(buffer_copy_for_comparison);
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_psa_crypto_op_fail.function b/tests/suites/test_suite_psa_crypto_op_fail.function
index 20942bf..9878237 100644
--- a/tests/suites/test_suite_psa_crypto_op_fail.function
+++ b/tests/suites/test_suite_psa_crypto_op_fail.function
@@ -359,9 +359,9 @@
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
     mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
     uint8_t public_key[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE] = { 0 };
-    size_t public_key_length = SIZE_MAX;
+    size_t public_key_length = 0;
     uint8_t output[PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE] = { 0 };
-    size_t length = SIZE_MAX;
+    size_t length = 0;
     psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT;
 
     PSA_INIT();
diff --git a/tests/suites/test_suite_psa_crypto_pake.function b/tests/suites/test_suite_psa_crypto_pake.function
index fed2c41..1cc69a7 100644
--- a/tests/suites/test_suite_psa_crypto_pake.function
+++ b/tests/suites/test_suite_psa_crypto_pake.function
@@ -147,7 +147,7 @@
             /* Server first round Output */
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_KEY_SHARE,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_g1_len));
+                                       buffer_length - buffer0_off, &s_g1_len));
             TEST_EQUAL(s_g1_len, expected_size_key_share);
             DO_ROUND_CONDITIONAL_INJECT(
                 ERR_INJECT_ROUND1_SERVER_KEY_SHARE_PART1,
@@ -156,7 +156,7 @@
 
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PUBLIC,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_x1_pk_len));
+                                       buffer_length - buffer0_off, &s_x1_pk_len));
             TEST_EQUAL(s_x1_pk_len, expected_size_zk_public);
             DO_ROUND_CONDITIONAL_INJECT(
                 ERR_INJECT_ROUND1_SERVER_ZK_PUBLIC_PART1,
@@ -165,7 +165,7 @@
 
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PROOF,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_x1_pr_len));
+                                       buffer_length - buffer0_off, &s_x1_pr_len));
             TEST_LE_U(s_x1_pr_len, max_expected_size_zk_proof);
             DO_ROUND_CONDITIONAL_INJECT(
                 ERR_INJECT_ROUND1_SERVER_ZK_PROOF_PART1,
@@ -174,7 +174,7 @@
 
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_KEY_SHARE,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_g2_len));
+                                       buffer_length - buffer0_off, &s_g2_len));
             TEST_EQUAL(s_g2_len, expected_size_key_share);
             DO_ROUND_CONDITIONAL_INJECT(
                 ERR_INJECT_ROUND1_SERVER_KEY_SHARE_PART2,
@@ -183,7 +183,7 @@
 
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PUBLIC,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_x2_pk_len));
+                                       buffer_length - buffer0_off, &s_x2_pk_len));
             TEST_EQUAL(s_x2_pk_len, expected_size_zk_public);
             DO_ROUND_CONDITIONAL_INJECT(
                 ERR_INJECT_ROUND1_SERVER_ZK_PUBLIC_PART2,
@@ -192,7 +192,7 @@
 
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PROOF,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_x2_pr_len));
+                                       buffer_length - buffer0_off, &s_x2_pr_len));
             TEST_LE_U(s_x2_pr_len, max_expected_size_zk_proof);
             DO_ROUND_CONDITIONAL_INJECT(
                 ERR_INJECT_ROUND1_SERVER_ZK_PROOF_PART2,
@@ -203,7 +203,7 @@
             DO_ROUND_CONDITIONAL_CHECK_FAILURE(
                 ERR_INJECT_EXTRA_OUTPUT,
                 psa_pake_output(server, PSA_PAKE_STEP_KEY_SHARE,
-                                buffer0 + s_g2_off, 512 - s_g2_off, &extra_output_len));
+                                buffer0 + s_g2_off, buffer_length - s_g2_off, &extra_output_len));
             (void) extra_output_len;
             /*
              * When injecting errors in inputs, the implementation is
@@ -260,7 +260,7 @@
             /* Client first round Output */
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_KEY_SHARE,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_g1_len));
+                                       buffer_length - buffer1_off, &c_g1_len));
             TEST_EQUAL(c_g1_len, expected_size_key_share);
             DO_ROUND_CONDITIONAL_INJECT(
                 ERR_INJECT_ROUND1_CLIENT_KEY_SHARE_PART1,
@@ -269,7 +269,7 @@
 
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PUBLIC,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_x1_pk_len));
+                                       buffer_length - buffer1_off, &c_x1_pk_len));
             TEST_EQUAL(c_x1_pk_len, expected_size_zk_public);
             DO_ROUND_CONDITIONAL_INJECT(
                 ERR_INJECT_ROUND1_CLIENT_ZK_PUBLIC_PART1,
@@ -278,7 +278,7 @@
 
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PROOF,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_x1_pr_len));
+                                       buffer_length - buffer1_off, &c_x1_pr_len));
             TEST_LE_U(c_x1_pr_len, max_expected_size_zk_proof);
             DO_ROUND_CONDITIONAL_INJECT(
                 ERR_INJECT_ROUND1_CLIENT_ZK_PROOF_PART1,
@@ -287,7 +287,7 @@
 
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_KEY_SHARE,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_g2_len));
+                                       buffer_length - buffer1_off, &c_g2_len));
             TEST_EQUAL(c_g2_len, expected_size_key_share);
             DO_ROUND_CONDITIONAL_INJECT(
                 ERR_INJECT_ROUND1_CLIENT_KEY_SHARE_PART2,
@@ -296,7 +296,7 @@
 
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PUBLIC,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_x2_pk_len));
+                                       buffer_length - buffer1_off, &c_x2_pk_len));
             TEST_EQUAL(c_x2_pk_len, expected_size_zk_public);
             DO_ROUND_CONDITIONAL_INJECT(
                 ERR_INJECT_ROUND1_CLIENT_ZK_PUBLIC_PART2,
@@ -305,7 +305,7 @@
 
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PROOF,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_x2_pr_len));
+                                       buffer_length - buffer1_off, &c_x2_pr_len));
             TEST_LE_U(c_x2_pr_len, max_expected_size_zk_proof);
             DO_ROUND_CONDITIONAL_INJECT(
                 ERR_INJECT_ROUND1_CLIENT_ZK_PROOF_PART2,
@@ -391,7 +391,7 @@
 
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_KEY_SHARE,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_a_len));
+                                       buffer_length - buffer0_off, &s_a_len));
             TEST_EQUAL(s_a_len, expected_size_key_share);
             DO_ROUND_CONDITIONAL_INJECT(
                 ERR_INJECT_ROUND2_SERVER_KEY_SHARE,
@@ -400,7 +400,7 @@
 
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PUBLIC,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_x2s_pk_len));
+                                       buffer_length - buffer0_off, &s_x2s_pk_len));
             TEST_EQUAL(s_x2s_pk_len, expected_size_zk_public);
             DO_ROUND_CONDITIONAL_INJECT(
                 ERR_INJECT_ROUND2_SERVER_ZK_PUBLIC,
@@ -409,7 +409,7 @@
 
             PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PROOF,
                                        buffer0 + buffer0_off,
-                                       512 - buffer0_off, &s_x2s_pr_len));
+                                       buffer_length - buffer0_off, &s_x2s_pr_len));
             TEST_LE_U(s_x2s_pr_len, max_expected_size_zk_proof);
             DO_ROUND_CONDITIONAL_INJECT(
                 ERR_INJECT_ROUND2_SERVER_ZK_PROOF,
@@ -445,7 +445,7 @@
 
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_KEY_SHARE,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_a_len));
+                                       buffer_length - buffer1_off, &c_a_len));
             TEST_EQUAL(c_a_len, expected_size_key_share);
             DO_ROUND_CONDITIONAL_INJECT(
                 ERR_INJECT_ROUND2_CLIENT_KEY_SHARE,
@@ -454,7 +454,7 @@
 
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PUBLIC,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_x2s_pk_len));
+                                       buffer_length - buffer1_off, &c_x2s_pk_len));
             TEST_EQUAL(c_x2s_pk_len, expected_size_zk_public);
             DO_ROUND_CONDITIONAL_INJECT(
                 ERR_INJECT_ROUND2_CLIENT_ZK_PUBLIC,
@@ -463,7 +463,7 @@
 
             PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PROOF,
                                        buffer1 + buffer1_off,
-                                       512 - buffer1_off, &c_x2s_pr_len));
+                                       buffer_length - buffer1_off, &c_x2s_pr_len));
             TEST_LE_U(c_x2s_pr_len, max_expected_size_zk_proof);
             DO_ROUND_CONDITIONAL_INJECT(
                 ERR_INJECT_ROUND2_CLIENT_ZK_PROOF,
@@ -475,7 +475,7 @@
                 DO_ROUND_CONDITIONAL_CHECK_FAILURE(
                     ERR_INJECT_EXTRA_OUTPUT_AT_END,
                     psa_pake_output(client, PSA_PAKE_STEP_KEY_SHARE,
-                                    buffer1 + c_a_off, 512 - c_a_off,
+                                    buffer1 + c_a_off, buffer_length - c_a_off,
                                     &extra_output_at_end_len));
                 (void) extra_output_at_end_len;
             }
diff --git a/tests/suites/test_suite_test_helpers.data b/tests/suites/test_suite_test_helpers.data
new file mode 100644
index 0000000..1d221d7
--- /dev/null
+++ b/tests/suites/test_suite_test_helpers.data
@@ -0,0 +1,23 @@
+Memory poison+unpoison: offset=0 len=42
+memory_poison_unpoison:0:42
+
+Memory poison+unpoison: offset=0 len=1
+memory_poison_unpoison:0:1
+
+Memory poison+unpoison: offset=0 len=2
+memory_poison_unpoison:0:2
+
+Memory poison+unpoison: offset=1 len=1
+memory_poison_unpoison:1:1
+
+Memory poison+unpoison: offset=1 len=2
+memory_poison_unpoison:1:2
+
+Memory poison+unpoison: offset=7 len=1
+memory_poison_unpoison:7:1
+
+Memory poison+unpoison: offset=7 len=2
+memory_poison_unpoison:7:2
+
+Memory poison+unpoison: offset=0 len=0
+memory_poison_unpoison:0:0
diff --git a/tests/suites/test_suite_test_helpers.function b/tests/suites/test_suite_test_helpers.function
new file mode 100644
index 0000000..8c5d5ad
--- /dev/null
+++ b/tests/suites/test_suite_test_helpers.function
@@ -0,0 +1,40 @@
+/* BEGIN_HEADER */
+
+/* Test some parts of the test framework. */
+
+#include <test/helpers.h>
+#include <test/memory.h>
+
+/* END_HEADER */
+
+/* BEGIN_DEPENDENCIES */
+
+/* END_DEPENDENCIES */
+
+/* BEGIN_CASE depends_on:MBEDTLS_TEST_MEMORY_CAN_POISON */
+/* Test that poison+unpoison leaves the memory accessible. */
+/* We can't test that poisoning makes the memory inaccessible:
+ * there's no sane way to catch an Asan/Valgrind complaint.
+ * That negative testing is done in programs/test/metatest.c. */
+void memory_poison_unpoison(int align, int size)
+{
+    unsigned char *buf = NULL;
+    const size_t buffer_size = align + size;
+    TEST_CALLOC(buf, buffer_size);
+
+    for (size_t i = 0; i < buffer_size; i++) {
+        buf[i] = (unsigned char) (i & 0xff);
+    }
+
+    const unsigned char *start = buf == NULL ? NULL : buf + align;
+    mbedtls_test_memory_poison(start, (size_t) size);
+    mbedtls_test_memory_unpoison(start, (size_t) size);
+
+    for (size_t i = 0; i < buffer_size; i++) {
+        TEST_EQUAL(buf[i], (unsigned char) (i & 0xff));
+    }
+
+exit:
+    mbedtls_free(buf);
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_version.data b/tests/suites/test_suite_version.data
index 6290331..0edee96 100644
--- a/tests/suites/test_suite_version.data
+++ b/tests/suites/test_suite_version.data
@@ -1,8 +1,8 @@
 Check compile time library version
-check_compiletime_version:"3.5.2"
+check_compiletime_version:"3.6.0"
 
 Check runtime library version
-check_runtime_version:"3.5.2"
+check_runtime_version:"3.6.0"
 
 Check for MBEDTLS_VERSION_C
 check_feature:"MBEDTLS_VERSION_C":0