Merge pull request #3527 from ronald-cron-arm/key-extended-id

PSA key identifiers rework
diff --git a/.travis.yml b/.travis.yml
index c67c0cd..76cb1c5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -28,10 +28,6 @@
       script:
         - tests/scripts/all.sh -k test_full_cmake_gcc_asan
 
-    - name: check compilation guards
-      script:
-        - tests/scripts/all.sh -k 'test_depends_*' 'build_key_exchanges'
-
     - name: macOS
       os: osx
       compiler: clang
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8833246..5af4c81 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -261,7 +261,7 @@
 # to define the test executables.
 #
 if(ENABLE_TESTING OR ENABLE_PROGRAMS)
-    file(GLOB MBEDTLS_TEST_FILES ${CMAKE_CURRENT_SOURCE_DIR}/tests/src/*.c)
+    file(GLOB MBEDTLS_TEST_FILES ${CMAKE_CURRENT_SOURCE_DIR}/tests/src/*.c ${CMAKE_CURRENT_SOURCE_DIR}/tests/src/drivers/*.c)
     add_library(mbedtls_test OBJECT ${MBEDTLS_TEST_FILES})
     target_include_directories(mbedtls_test
         PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tests/include
diff --git a/ChangeLog.d/add-aes-ecb-to-psa.txt b/ChangeLog.d/add-aes-ecb-to-psa.txt
new file mode 100644
index 0000000..b0de67c
--- /dev/null
+++ b/ChangeLog.d/add-aes-ecb-to-psa.txt
@@ -0,0 +1,2 @@
+Features
+   * Add support for ECB to the PSA cipher API.
diff --git a/ChangeLog.d/add_cipher_transparent_driver.txt b/ChangeLog.d/add_cipher_transparent_driver.txt
new file mode 100644
index 0000000..ce6f33d
--- /dev/null
+++ b/ChangeLog.d/add_cipher_transparent_driver.txt
@@ -0,0 +1,4 @@
+Features
+   * Partial implementation of the new PSA Crypto accelerator APIs for
+     enabling symmetric cipher acceleration through crypto accelerators.
+     Contributed by Steven Cooreman in #3644.
diff --git a/ChangeLog.d/add_sign_verify_keygen_transparent_driver.txt b/ChangeLog.d/add_sign_verify_keygen_transparent_driver.txt
new file mode 100644
index 0000000..fe43899
--- /dev/null
+++ b/ChangeLog.d/add_sign_verify_keygen_transparent_driver.txt
@@ -0,0 +1,4 @@
+Features
+   * Partial implementation of the new PSA Crypto accelerator APIs for
+     enabling key generation and asymmetric signing/verification through crypto
+     accelerators. Contributed by Steven Cooreman in #3501.
diff --git a/ChangeLog.d/adjusting sliding_window_size_PR3592.txt b/ChangeLog.d/adjusting sliding_window_size_PR3592.txt
new file mode 100644
index 0000000..6089565
--- /dev/null
+++ b/ChangeLog.d/adjusting sliding_window_size_PR3592.txt
@@ -0,0 +1,3 @@
+Changes
+   * Reduce stack usage significantly during sliding window exponentiation.
+     Reported in #3591 and fix contributed in #3592 by Daniel Otte.
diff --git a/ChangeLog.d/bugfix_PR3294.txt b/ChangeLog.d/bugfix_PR3294.txt
new file mode 100644
index 0000000..a6ea75e
--- /dev/null
+++ b/ChangeLog.d/bugfix_PR3294.txt
@@ -0,0 +1,4 @@
+Bugfix
+   * Fix build failure in configurations where MBEDTLS_USE_PSA_CRYPTO is
+     enabled but ECDSA is disabled. Contributed by jdurkop. Fixes #3294.
+
diff --git a/ChangeLog.d/comment_typo_in_mbedtls_ssl_set_bio.txt b/ChangeLog.d/comment_typo_in_mbedtls_ssl_set_bio.txt
new file mode 100644
index 0000000..2f94c16
--- /dev/null
+++ b/ChangeLog.d/comment_typo_in_mbedtls_ssl_set_bio.txt
@@ -0,0 +1,2 @@
+Changes
+   * Fix comment typo in documentation of mbedtls_ssl_set_bio.
diff --git a/ChangeLog.d/fix-typo.txt b/ChangeLog.d/fix-typo.txt
new file mode 100644
index 0000000..8e961d2
--- /dev/null
+++ b/ChangeLog.d/fix-typo.txt
@@ -0,0 +1,3 @@
+Changes
+   * Fixes a typo in the example code located in
+     program/pkey/ecdh_curve25519.c
diff --git a/docs/proposed/Makefile b/docs/proposed/Makefile
index 2132b08..1c31464 100644
--- a/docs/proposed/Makefile
+++ b/docs/proposed/Makefile
@@ -3,6 +3,7 @@
 default: all
 
 all_markdown = \
+	       psa-conditional-inclusion-c.md \
 	       psa-driver-developer-guide.md \
 	       psa-driver-integration-guide.md \
 	       psa-driver-interface.md \
diff --git a/docs/proposed/psa-conditional-inclusion-c.md b/docs/proposed/psa-conditional-inclusion-c.md
new file mode 100644
index 0000000..08306d2
--- /dev/null
+++ b/docs/proposed/psa-conditional-inclusion-c.md
@@ -0,0 +1,202 @@
+Conditional inclusion of cryptographic mechanism through the PSA API in Mbed TLS
+================================================================================
+
+This document is a proposed interface for deciding at build time which cryptographic mechanisms to include in the PSA Cryptography interface.
+
+This is currently a proposal for Mbed TLS. It is not currently on track for standardization in PSA.
+
+Time-stamp: "2020/09/07 08:27:32 GMT"
+
+## Introduction
+
+### Purpose of this specification
+
+The [PSA Cryptography API specification](https://armmbed.github.io/mbed-crypto/psa/#application-programming-interface) specifies the interface between a PSA Cryptography implementation and an application. The interface defines a number of categories of cryptographic algorithms (hashes, MAC, signatures, etc.). In each category, a typical implementation offers many algorithms (e.g. for signatures: RSA-PKCS#1v1.5, RSA-PSS, ECDSA). When building the implementation for a specific use case, it is often desirable to include only a subset of the available cryptographic mechanisms, primarily in order to reduce the code footprint of the compiled system.
+
+The present document proposes a way for an application using the PSA cryptography interface to declare which mechanisms it requires.
+
+### Conditional inclusion of legacy cryptography modules
+
+Mbed TLS offers a way to select which cryptographic mechanisms are included in a build through its configuration file (`config.h`). This mechanism is based on two main sets of symbols: `MBEDTLS_xxx_C` controls the availability of the mechanism to the application, and `MBEDTLS_xxx_ALT` controls the availability of an alternative implementation, so the software implementation is only included if `MBEDTLS_xxx_C` is defined but not `MBEDTLS_xxx_ALT`.
+
+### PSA evolution
+
+In the PSA cryptography interface, the **core** (built-in implementations of cryptographic mechanisms) can be augmented with drivers. **Transparent drivers** replace the built-in implementation of a cryptographic mechanism (or, with **fallback**, the built-in implementation is tried if the driver only has partial support for the mechanism). **Opaque drivers** implement cryptographic mechanisms on keys which are stored in a separate domain such as a secure element, for which the core only does key management and dispatch using wrapped key blobs or key identifiers.
+
+The current model is difficult to adapt to the PSA interface for several reasons. The `MBEDTLS_xxx_ALT` symbols are somewhat inconsistent, and in particular do not work well for asymmetric cryptography. For example, many parts of the ECC code have no `MBEDTLS_xxx_ALT` symbol, so a platform with ECC acceleration that can perform all ECDSA and ECDH operations in the accelerator would still embark the `bignum` module and large parts of the `ecp_curves`, `ecp` and `ecdsa` modules. Also the availability of a transparent driver for a mechanism does not translate directly to `MBEDTLS_xxx` symbols.
+
+### Requirements
+
+[Req.interface] The application can declare which cryptographic mechanisms it needs.
+
+[Req.inclusion] If the application does not require a mechanism, a suitably configured Mbed TLS build must not include it. The granularity of mechanisms must work for typical use cases and has [acceptable limitations](#acceptable-limitations).
+
+[Req.drivers] If a PSA driver is available in the build, a suitably configured Mbed TLS build must not include the corresponding software code (unless a software fallback is needed).
+
+[Req.c] The configuration mechanism consists of C preprocessor definitions, and the build does not require tools other than a C compiler. This is necessary to allow building an application and Mbed TLS in development environments that do not allow third-party tools.
+
+[Req.adaptability] The implementation of the mechanism must be adaptable with future evolution of the PSA cryptography specifications and Mbed TLS. Therefore the interface must remain sufficiently simple and abstract.
+
+### Acceptable limitations
+
+[Limitation.matrix] If a mechanism is defined by a combination of algorithms and key types, for example a block cipher mode (CBC, CTR, CFB, …) and a block permutation (AES, CAMELLIA, ARIA, …), there is no requirement to include only specific combinations.
+
+[Limitation.direction] For mechanisms that have multiple directions (for example encrypt/decrypt, sign/verify), there is no requirement to include only one direction.
+
+[Limitation.size] There is no requirement to include only support for certain key sizes.
+
+[Limitation.multipart] Where there are multiple ways to perform an operation, for example single-part and multi-part, there is no mechanism to select only one or a subset of the possible ways.
+
+## Interface
+
+### PSA Crypto configuration file
+
+The PSA crypto configuration file `psa/crypto_config.h` defines a series of symbols of the form `PSA_WANT_xxx` where `xxx` . The symbols are documented in the section [“PSA Crypto configuration symbols”](#psa-crypto-configuration-symbols) below.
+
+The symbol `MBEDTLS_PSA_CRYPTO_CONFIG` in `mbedtls/config.h` determines whether `psa/crypto_config.h`. is used.
+
+* If `MBEDTLS_PSA_CRYPTO_CONFIG` is unset, which is the default at least in Mbed TLS 2.x versions, things are as they are today: the PSA subsystem includes generic code unconditionally, and includes support for specific mechanisms conditionally based on the existing `MBEDTLS_xxx_` symbols.
+* If `MBEDTLS_PSA_CRYPTO_CONFIG` is set, the necessary software implementations of cryptographic algorithms are included based on both the content of the PSA crypto configuration file and the Mbed TLS configuration file. For example, the code in `aes.c` is enabled if either `mbedtls/config.h` contains `MBEDTLS_AES_C` or `psa/crypto_config.h` contains `PSA_WANT_KEY_TYPE_AES`.
+
+### PSA Crypto configuration symbols
+
+#### Configuration symbol syntax
+
+A PSA crypto configuration symbol is a C preprocessor symbol whose name starts with `PSA_WANT_`.
+
+* If the symbol is not defined, the corresponding feature is not included.
+* If the symbol is defined to a preprocessor expression with the value `1`, the corresponding feature is included.
+* If the symbol is defined with a different value, the behavior is currently undefined and reserved for future use.
+
+#### Configuration symbol semantics
+
+If a feature is not requested for inclusion in the PSA crypto configuration file, it may still be included in the build, either because the feature has been requested in some other way, or because the library does not support the exclusion of this feature. Mbed TLS should make a best effort to support the exclusion of all features, but in some cases this may be judged too much effort for too little benefit.
+
+#### Configuration symbols for key types
+
+For each constant or constructor macro of the form `PSA_KEY_TYPE_xxx`, the symbol **`PSA_WANT_KEY_TYPE_xxx`** indicates that support for this key type is desired.
+
+For asymmetric cryptography, `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR` determines whether private-key operations are desired, and `PSA_WANT_KEY_TYPE_xxx_PUBLIC_KEY` determines whether public-key operations are desired. `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR` implicitly enables `PSA_WANT_KEY_TYPE_xxx_PUBLIC_KEY`: there is no way to only include private-key operations (which typically saves little code).
+
+#### Configuration symbols for curves
+
+For elliptic curve key types, only the specified curves are included. To include a curve, include a symbol of the form **`PSA_WANT_ECC_family_size`**. For example: `PSA_WANT_ECC_SECP_R1_256` for secp256r1, `PSA_WANT_ECC_MONTGOMERY_CURVE25519`. It is an error to require an ECC key type but no curve, and Mbed TLS will reject this at compile time.
+
+#### Configuration symbols for algorithms
+
+For each constant or constructor macro of the form `PSA_ALG_xxx`, the symbol **`PSA_WANT_ALG_xxx`** indicates that support for this algorithm is desired.
+
+For parametrized algorithms, the `PSA_WANT_ALG_xxx` symbol indicates whether the base mechanism is supported. Parameters must themselves be included through their own `PSA_WANT_ALG_xxx` symbols. It is an error to include a base mechanism without at least one possible parameter, and Mbed TLS will reject this at compile time. For example, `PSA_WANT_ALG_ECDSA` requires the inclusion of randomized ECDSA for all hash algorithms whose corresponding symbol `PSA_WANT_ALG_xxx` is enabled.
+
+## Implementation
+
+### Additional non-public symbols
+
+#### Accounting for transparent drivers
+
+In addition to the [configuration symbols](#psa-crypto-configuration-symbols), we need two parallel or mostly parallel sets of symbols:
+
+* **`MBEDTLS_PSA_ACCEL_xxx`** indicates whether a fully-featured, fallback-free transparent driver is available.
+* **`MBEDTLS_PSA_BUILTIN_xxx`** indicates whether the software implementation is needed.
+
+`MBEDTLS_PSA_ACCEL_xxx` is one of the outputs of the transpilation of a driver description, alongside the glue code for calling the drivers.
+
+`MBEDTLS_PSA_BUILTIN_xxx` is enabled when `PSA_WANT_xxx` is enabled and `MBEDTLS_PSA_ACCEL_xxx` is disabled.
+
+These symbols are not part of the public interface of Mbed TLS towards applications or to drivers, regardless of whether the symbols are actually visible.
+
+### Architecture of symbol definitions
+
+#### Definition of internal inclusion symbols
+
+The header file `mbedtls/config.h` needs to define all the `MBEDTLS_xxx_C` configuration symbols, including the ones deduced from the PSA crypto configuration. It does this by including the new header file **`mbedtls/config_psa.h`**, which defines the `MBEDTLS_PSA_BUILTIN_xxx` symbols and deduces the corresponding `MBEDTLS_xxx_C` (and other) symbols.
+
+#### Visibility of internal symbols
+
+Ideally, the `MBEDTLS_PSA_ACCEL_xxx` and `MBEDTLS_PSA_BUILTIN_xxx` symbols should not be visible to application code or driver code, since they are not part of the public interface of the library. However these symbols are needed to deduce whether to include library modules (for example `MBEDTLS_AES_C` has to be enabled if `MBEDTLS_PSA_BUILTIN_KEY_TYPE_AES` is enabled), which makes it difficult to keep them private.
+
+#### Compile-time checks
+
+The header file **`library/psa_check_config.h`** applies sanity checks to the configuration, throwing `#error` if something is wrong.
+
+A mechanism similar to `mbedtls/check_config.h` detects errors such as enabling ECDSA but no curve.
+
+Since configuration symbols must be undefined or 1, any other value should trigger an `#error`.
+
+#### Automatic generation of preprocessor symbol manipulations
+
+A lot of the preprocessor symbol manipulation is systematic calculations that analyze the configuration. `mbedtls/config_psa.h` and `library/psa_check_config.h` should be generated automatically, in the same manner as `version_features.c`.
+
+### Structure of PSA crypto library code
+
+#### Conditional inclusion of library entry points
+
+An entry point can be eliminated entirely if no algorithm requires it.
+
+#### Conditional inclusion of mechanism-specific code
+
+Code that is specific to certain key types or to certain algorithms must be guarded by the applicable symbols: `PSA_WANT_xxx` for code that is independent of the application, and `MBEDTLS_PSA_BUILTIN_xxx` for code that calls an Mbed TLS software implementation.
+
+## PSA standardization
+
+### JSON configuration mechanism
+
+At the time of writing, the preferred configuration mechanism for a PSA service is in JSON syntax. The translation from JSON to build instructions is not specified by PSA.
+
+For PSA Crypto, the preferred configuration mechanism would be similar to capability specifications of transparent drivers. The same JSON properties that are used to mean “this driver can perform that mechanism” in a driver description would be used to mean “the application wants to perform that mechanism” in the application configuration.
+
+### From JSON to C
+
+The JSON capability language allows a more fine-grained selection than the C mechanism proposed here. For example, it allows requesting only single-part mechanisms, only certain key sizes, or only certain combinations of algorithms and key types.
+
+The JSON capability language can be translated approximately to the boolean symbol mechanism proposed here. The approximation considers a feature to be enabled if any part of it is enabled. For example, if there is a capability for AES-CTR and one for CAMELLIA-GCM, the translation to boolean symbols will also include AES-GCM and CAMELLIA-CTR. If there is a capability for AES-128, the translation will also include AES-192 and AES-256.
+
+The boolean symbol mechanism proposed here can be translated to a list of JSON capabilities: for each included algorithm, include a capability with that algorithm, the key types that apply to that algorithm, no size restriction, and all the entry points that apply to that algorithm.
+
+## Open questions
+
+### Open questions about the interface
+
+#### Naming of symbols
+
+The names of [elliptic curve symbols](#configuration-symbols-for-curves) are a bit weird: `SECP_R1_256` instead of `SECP256R1`. Should we make them more classical, but less systematic?
+
+#### Impossible combinations
+
+What does it mean to have `PSA_WANT_ALG_ECDSA` enabled but with only Curve25519? Is it a mandatory error?
+
+#### Diffie-Hellman
+
+Way to request only specific groups? Not a priority: constrained devices don't do FFDH. Specify it as may change in future versions.
+
+#### Coexistence with the current Mbed TLS configuration
+
+The two mechanisms have very different designs. Is there serious potential for confusion? Do we understand how the combinations work?
+
+### Open questions about the design
+
+#### Algorithms without a key type or vice versa
+
+Is it realistic to mandate a compile-time error if a key type is required, but no matching algorithm, or vice versa? Is it always the right thing, for example if there is an opaque driver that manipulates this key type?
+
+#### Opaque-only mechanisms
+
+If a mechanism should only be supported in an opaque driver, what does the core need to know about it? Do we have all the information we need?
+
+This is especially relevant to suppress a mechanism completely if there is no matching algorithm. For example, if there is no transparent implementation of RSA or ECDSA, `psa_sign_hash` and `psa_verify_hash` may still be needed if there is an opaque signature driver.
+
+### Open questions about the implementation
+
+#### Testability
+
+Is this proposal decently testable? There are a lot of combinations. What combinations should we test?
+
+<!--
+Local Variables:
+time-stamp-line-limit: 40
+time-stamp-start: "Time-stamp: *\""
+time-stamp-end: "\""
+time-stamp-format: "%04Y/%02m/%02d %02H:%02M:%02S %Z"
+time-stamp-time-zone: "GMT"
+End:
+-->
diff --git a/include/mbedtls/bignum.h b/include/mbedtls/bignum.h
index 0d019b9..637360e 100644
--- a/include/mbedtls/bignum.h
+++ b/include/mbedtls/bignum.h
@@ -61,12 +61,12 @@
  * Maximum window size used for modular exponentiation. Default: 6
  * Minimum value: 1. Maximum value: 6.
  *
- * Result is an array of ( 2 << MBEDTLS_MPI_WINDOW_SIZE ) MPIs used
+ * Result is an array of ( 2 ** MBEDTLS_MPI_WINDOW_SIZE ) MPIs used
  * for the sliding window calculation. (So 64 by default)
  *
  * Reduction in size, reduces speed.
  */
-#define MBEDTLS_MPI_WINDOW_SIZE                           6        /**< Maximum windows size used. */
+#define MBEDTLS_MPI_WINDOW_SIZE                           6        /**< Maximum window size used. */
 #endif /* !MBEDTLS_MPI_WINDOW_SIZE */
 
 #if !defined(MBEDTLS_MPI_MAX_SIZE)
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index e76c9be..b77b34b 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -1326,6 +1326,17 @@
  */
 #define MBEDTLS_PKCS1_V21
 
+/** \def MBEDTLS_PSA_CRYPTO_DRIVERS
+ *
+ * Enable support for the experimental PSA crypto driver interface.
+ *
+ * Requires: MBEDTLS_PSA_CRYPTO_C.
+ *
+ * \warning This interface is experimental and may change or be removed
+ * without notice.
+ */
+//#define MBEDTLS_PSA_CRYPTO_DRIVERS
+
 /**
  * \def MBEDTLS_PSA_CRYPTO_SPM
  *
@@ -3447,7 +3458,7 @@
  */
 
 /* MPI / BIGNUM options */
-//#define MBEDTLS_MPI_WINDOW_SIZE            6 /**< Maximum windows size used. */
+//#define MBEDTLS_MPI_WINDOW_SIZE            6 /**< Maximum window size used. */
 //#define MBEDTLS_MPI_MAX_SIZE            1024 /**< Maximum number of bytes for usable MPIs. */
 
 /* CTR_DRBG options */
diff --git a/include/mbedtls/psa_util.h b/include/mbedtls/psa_util.h
index 3c03706..d8a32c5 100644
--- a/include/mbedtls/psa_util.h
+++ b/include/mbedtls/psa_util.h
@@ -83,6 +83,8 @@
 {
     switch( mode )
     {
+        case MBEDTLS_MODE_ECB:
+            return( PSA_ALG_ECB_NO_PADDING );
         case MBEDTLS_MODE_GCM:
             return( PSA_ALG_AEAD_WITH_TAG_LENGTH( PSA_ALG_GCM, taglen ) );
         case MBEDTLS_MODE_CCM:
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index f086bdf..a091261 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -1559,7 +1559,7 @@
  * \note           For DTLS, you need to provide either a non-NULL
  *                 f_recv_timeout callback, or a f_recv that doesn't block.
  *
- * \note           See the documentations of \c mbedtls_ssl_sent_t,
+ * \note           See the documentations of \c mbedtls_ssl_send_t,
  *                 \c mbedtls_ssl_recv_t and \c mbedtls_ssl_recv_timeout_t for
  *                 the conventions those callbacks must follow.
  *
diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h
index 065c6b1..be0e280 100644
--- a/include/psa/crypto_struct.h
+++ b/include/psa/crypto_struct.h
@@ -77,6 +77,16 @@
 #include "mbedtls/sha256.h"
 #include "mbedtls/sha512.h"
 
+typedef struct {
+    /** Unique ID indicating which driver got assigned to do the
+     * operation. Since driver contexts are driver-specific, swapping
+     * drivers halfway through the operation is not supported.
+     * ID values are auto-generated in psa_driver_wrappers.h */
+    unsigned int id;
+    /** Context structure for the assigned driver, when id is not zero. */
+    void* ctx;
+} psa_operation_driver_context_t;
+
 struct psa_hash_operation_s
 {
     psa_algorithm_t alg;
@@ -158,16 +168,18 @@
     unsigned int key_set : 1;
     unsigned int iv_required : 1;
     unsigned int iv_set : 1;
+    unsigned int mbedtls_in_use : 1; /* Indicates mbed TLS is handling the operation. */
     uint8_t iv_size;
     uint8_t block_size;
     union
     {
         unsigned dummy; /* Enable easier initializing of the union. */
         mbedtls_cipher_context_t cipher;
+        psa_operation_driver_context_t driver;
     } ctx;
 };
 
-#define PSA_CIPHER_OPERATION_INIT {0, 0, 0, 0, 0, 0, {0}}
+#define PSA_CIPHER_OPERATION_INIT {0, 0, 0, 0, 0, 0, 0, {0}}
 static inline struct psa_cipher_operation_s psa_cipher_operation_init( void )
 {
     const struct psa_cipher_operation_s v = PSA_CIPHER_OPERATION_INIT;
diff --git a/include/psa/crypto_values.h b/include/psa/crypto_values.h
index 199bcac..3eb64d8 100644
--- a/include/psa/crypto_values.h
+++ b/include/psa/crypto_values.h
@@ -978,6 +978,26 @@
  */
 #define PSA_ALG_XTS                             ((psa_algorithm_t)0x044000ff)
 
+/** The Electronic Code Book (ECB) mode of a block cipher, with no padding.
+ *
+ * \warning ECB mode does not protect the confidentiality of the encrypted data
+ * except in extremely narrow circumstances. It is recommended that applications
+ * only use ECB if they need to construct an operating mode that the
+ * implementation does not provide. Implementations are encouraged to provide
+ * the modes that applications need in preference to supporting direct access
+ * to ECB.
+ *
+ * The underlying block cipher is determined by the key type.
+ *
+ * This symmetric cipher mode can only be used with messages whose lengths are a
+ * multiple of the block size of the chosen block cipher.
+ *
+ * ECB mode does not accept an initialization vector (IV). When using a
+ * multi-part cipher operation with this algorithm, psa_cipher_generate_iv()
+ * and psa_cipher_set_iv() must not be called.
+ */
+#define PSA_ALG_ECB_NO_PADDING                  ((psa_algorithm_t)0x04404400)
+
 /** The CBC block cipher chaining mode, with no padding.
  *
  * The underlying block cipher is determined by the key type.
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 33e2cfc..91ac8bc 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -61,6 +61,7 @@
     platform_util.c
     poly1305.c
     psa_crypto.c
+    psa_crypto_driver_wrappers.c
     psa_crypto_se.c
     psa_crypto_slot_management.c
     psa_crypto_storage.c
diff --git a/library/Makefile b/library/Makefile
index b76a84b..c7d4a06 100644
--- a/library/Makefile
+++ b/library/Makefile
@@ -118,6 +118,7 @@
 	     platform_util.o \
 	     poly1305.o \
 	     psa_crypto.o \
+	     psa_crypto_driver_wrappers.o \
 	     psa_crypto_se.o \
 	     psa_crypto_slot_management.o \
 	     psa_crypto_storage.o \
diff --git a/library/bignum.c b/library/bignum.c
index 9325632..fa97d19 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -2101,7 +2101,7 @@
     size_t i, j, nblimbs;
     size_t bufsize, nbits;
     mbedtls_mpi_uint ei, mm, state;
-    mbedtls_mpi RR, T, W[ 2 << MBEDTLS_MPI_WINDOW_SIZE ], Apos;
+    mbedtls_mpi RR, T, W[ 1 << MBEDTLS_MPI_WINDOW_SIZE ], Apos;
     int neg;
 
     MPI_VALIDATE_RET( X != NULL );
diff --git a/library/md2.c b/library/md2.c
index 5ebf072..b4f7cc6 100644
--- a/library/md2.c
+++ b/library/md2.c
@@ -287,8 +287,7 @@
     { "message digest" },
     { "abcdefghijklmnopqrstuvwxyz" },
     { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
-    { "12345678901234567890123456789012345678901234567890123456789012"
-      "345678901234567890" }
+    { "12345678901234567890123456789012345678901234567890123456789012345678901234567890" }
 };
 
 static const size_t md2_test_strlen[7] =
diff --git a/library/md4.c b/library/md4.c
index ac95074..1cac0a4 100644
--- a/library/md4.c
+++ b/library/md4.c
@@ -408,8 +408,7 @@
     { "message digest" },
     { "abcdefghijklmnopqrstuvwxyz" },
     { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
-    { "12345678901234567890123456789012345678901234567890123456789012"
-      "345678901234567890" }
+    { "12345678901234567890123456789012345678901234567890123456789012345678901234567890" }
 };
 
 static const size_t md4_test_strlen[7] =
diff --git a/library/md5.c b/library/md5.c
index 8cea902..1e702b4 100644
--- a/library/md5.c
+++ b/library/md5.c
@@ -422,8 +422,7 @@
     { "message digest" },
     { "abcdefghijklmnopqrstuvwxyz" },
     { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
-    { "12345678901234567890123456789012345678901234567890123456789012"
-      "345678901234567890" }
+    { "12345678901234567890123456789012345678901234567890123456789012345678901234567890" }
 };
 
 static const size_t md5_test_buflen[7] =
diff --git a/library/pk.c b/library/pk.c
index 8ffbed2..9a3bcb0 100644
--- a/library/pk.c
+++ b/library/pk.c
@@ -591,6 +591,9 @@
                                psa_algorithm_t hash_alg )
 {
 #if !defined(MBEDTLS_ECP_C)
+    ((void) pk);
+    ((void) handle);
+    ((void) hash_alg);
     return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
 #else
     const mbedtls_ecp_keypair *ec;
diff --git a/library/pk_wrap.c b/library/pk_wrap.c
index 6bf3169..903c53b 100644
--- a/library/pk_wrap.c
+++ b/library/pk_wrap.c
@@ -551,11 +551,12 @@
     unsigned char buf[30 + 2 * MBEDTLS_ECP_MAX_BYTES];
     unsigned char *p;
     mbedtls_pk_info_t pk_info = mbedtls_eckey_info;
-    psa_algorithm_t psa_sig_md, psa_md;
+    psa_algorithm_t psa_sig_md = PSA_ALG_ECDSA_ANY;
     size_t curve_bits;
     psa_ecc_family_t curve =
         mbedtls_ecc_group_to_psa( ctx->grp.id, &curve_bits );
     const size_t signature_part_size = ( ctx->grp.nbits + 7 ) / 8;
+    ((void) md_alg);
 
     if( curve == 0 )
         return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
@@ -569,11 +570,6 @@
     if( key_len <= 0 )
         return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
 
-    psa_md = mbedtls_psa_translate_md( md_alg );
-    if( psa_md == 0 )
-        return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
-    psa_sig_md = PSA_ALG_ECDSA( psa_md );
-
     psa_set_key_type( &attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY( curve ) );
     psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_VERIFY_HASH );
     psa_set_key_algorithm( &attributes, psa_sig_md );
@@ -910,6 +906,8 @@
             type == MBEDTLS_PK_ECDSA );
 }
 
+#if defined(MBEDTLS_ECDSA_C)
+
 /*
  * Simultaneously convert and move raw MPI from the beginning of a buffer
  * to an ASN.1 MPI at the end of the buffer.
@@ -992,11 +990,24 @@
     return( 0 );
 }
 
+#endif /* MBEDTLS_ECDSA_C */
+
 static int pk_opaque_sign_wrap( void *ctx, mbedtls_md_type_t md_alg,
                    const unsigned char *hash, size_t hash_len,
                    unsigned char *sig, size_t *sig_len,
                    int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
 {
+#if !defined(MBEDTLS_ECDSA_C)
+    ((void) ctx);
+    ((void) md_alg);
+    ((void) hash);
+    ((void) hash_len);
+    ((void) sig);
+    ((void) sig_len);
+    ((void) f_rng);
+    ((void) p_rng);
+    return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
+#else /* !MBEDTLS_ECDSA_C */
     const psa_key_handle_t *key = (const psa_key_handle_t *) ctx;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
     psa_algorithm_t alg = PSA_ALG_ECDSA( mbedtls_psa_translate_md( md_alg ) );
@@ -1027,6 +1038,7 @@
 
     /* transcode it to ASN.1 sequence */
     return( pk_ecdsa_sig_asn1_from_psa( sig, sig_len, buf_len ) );
+#endif /* !MBEDTLS_ECDSA_C */
 }
 
 const mbedtls_pk_info_t mbedtls_pk_opaque_info = {
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index bffddc9..931e2e9 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -27,6 +27,7 @@
 
 #include "psa_crypto_core.h"
 #include "psa_crypto_invasive.h"
+#include "psa_crypto_driver_wrappers.h"
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
 #include "psa_crypto_se.h"
 #endif
@@ -124,7 +125,7 @@
     if( global_data.initialized == 0 )  \
         return( PSA_ERROR_BAD_STATE );
 
-static psa_status_t mbedtls_to_psa_error( int ret )
+psa_status_t mbedtls_to_psa_error( int ret )
 {
     /* If there's both a high-level code and low-level code, dispatch on
      * the high-level code. */
@@ -2751,6 +2752,9 @@
             case PSA_ALG_OFB:
                 mode = MBEDTLS_MODE_OFB;
                 break;
+            case PSA_ALG_ECB_NO_PADDING:
+                mode = MBEDTLS_MODE_ECB;
+                break;
             case PSA_ALG_CBC_NO_PADDING:
                 mode = MBEDTLS_MODE_CBC;
                 break;
@@ -3637,10 +3641,6 @@
 {
     psa_key_slot_t *slot;
     psa_status_t status;
-#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
-    const psa_drv_se_t *drv;
-    psa_drv_se_context_t *drv_context;
-#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
 
     *signature_length = signature_size;
     /* Immediately reject a zero-length signature buffer. This guarantees
@@ -3659,24 +3659,19 @@
         goto exit;
     }
 
-#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
-    if( psa_get_se_driver( slot->attr.lifetime, &drv, &drv_context ) )
-    {
-        if( drv->asymmetric == NULL ||
-            drv->asymmetric->p_sign == NULL )
-        {
-            status = PSA_ERROR_NOT_SUPPORTED;
-            goto exit;
-        }
-        status = drv->asymmetric->p_sign( drv_context,
-                                          slot->data.se.slot_number,
-                                          alg,
-                                          hash, hash_length,
-                                          signature, signature_size,
-                                          signature_length );
-    }
-    else
-#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+    /* Try any of the available accelerators first */
+    status = psa_driver_wrapper_sign_hash( slot,
+                                           alg,
+                                           hash,
+                                           hash_length,
+                                           signature,
+                                           signature_size,
+                                           signature_length );
+    if( status != PSA_ERROR_NOT_SUPPORTED ||
+        psa_key_lifetime_is_external( slot->attr.lifetime ) )
+        goto exit;
+
+    /* If the operation was not supported by any accelerator, try fallback. */
 #if defined(MBEDTLS_RSA_C)
     if( slot->attr.type == PSA_KEY_TYPE_RSA_KEY_PAIR )
     {
@@ -3763,29 +3758,22 @@
 {
     psa_key_slot_t *slot;
     psa_status_t status;
-#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
-    const psa_drv_se_t *drv;
-    psa_drv_se_context_t *drv_context;
-#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
 
     status = psa_get_key_from_slot( handle, &slot, PSA_KEY_USAGE_VERIFY_HASH, alg );
     if( status != PSA_SUCCESS )
         return( status );
 
-#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
-    if( psa_get_se_driver( slot->attr.lifetime, &drv, &drv_context ) )
-    {
-        if( drv->asymmetric == NULL ||
-            drv->asymmetric->p_verify == NULL )
-            return( PSA_ERROR_NOT_SUPPORTED );
-        return( drv->asymmetric->p_verify( drv_context,
-                                           slot->data.se.slot_number,
-                                           alg,
-                                           hash, hash_length,
-                                           signature, signature_length ) );
-    }
-    else
-#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+    /* Try any of the available accelerators first */
+    status = psa_driver_wrapper_verify_hash( slot,
+                                             alg,
+                                             hash,
+                                             hash_length,
+                                             signature,
+                                             signature_length );
+    if( status != PSA_ERROR_NOT_SUPPORTED ||
+        psa_key_lifetime_is_external( slot->attr.lifetime ) )
+        return status;
+
 #if defined(MBEDTLS_RSA_C)
     if( PSA_KEY_TYPE_IS_RSA( slot->attr.type ) )
     {
@@ -4049,27 +4037,6 @@
 /* Symmetric cryptography */
 /****************************************************************/
 
-/* Initialize the cipher operation structure. Once this function has been
- * called, psa_cipher_abort can run and will do the right thing. */
-static psa_status_t psa_cipher_init( psa_cipher_operation_t *operation,
-                                     psa_algorithm_t alg )
-{
-    if( ! PSA_ALG_IS_CIPHER( alg ) )
-    {
-        memset( operation, 0, sizeof( *operation ) );
-        return( PSA_ERROR_INVALID_ARGUMENT );
-    }
-
-    operation->alg = alg;
-    operation->key_set = 0;
-    operation->iv_set = 0;
-    operation->iv_required = 1;
-    operation->iv_size = 0;
-    operation->block_size = 0;
-    mbedtls_cipher_init( &operation->ctx.cipher );
-    return( PSA_SUCCESS );
-}
-
 static psa_status_t psa_cipher_setup( psa_cipher_operation_t *operation,
                                       psa_key_handle_t handle,
                                       psa_algorithm_t alg,
@@ -4086,19 +4053,63 @@
 
     /* A context must be freshly initialized before it can be set up. */
     if( operation->alg != 0 )
-    {
         return( PSA_ERROR_BAD_STATE );
-    }
 
-    status = psa_cipher_init( operation, alg );
-    if( status != PSA_SUCCESS )
-        return( status );
+    /* The requested algorithm must be one that can be processed by cipher. */
+    if( ! PSA_ALG_IS_CIPHER( alg ) )
+        return( PSA_ERROR_INVALID_ARGUMENT );
 
-    status = psa_get_transparent_key( handle, &slot, usage, alg);
+    /* Fetch key material from key storage. */
+    status = psa_get_key_from_slot( handle, &slot, usage, alg );
     if( status != PSA_SUCCESS )
         goto exit;
-    key_bits = psa_get_key_slot_bits( slot );
 
+    /* Initialize the operation struct members, except for alg. The alg member
+     * is used to indicate to psa_cipher_abort that there are resources to free,
+     * so we only set it after resources have been allocated/initialized. */
+    operation->key_set = 0;
+    operation->iv_set = 0;
+    operation->mbedtls_in_use = 0;
+    operation->iv_size = 0;
+    operation->block_size = 0;
+    if( alg == PSA_ALG_ECB_NO_PADDING )
+        operation->iv_required = 0;
+    else
+        operation->iv_required = 1;
+
+    /* Try doing the operation through a driver before using software fallback. */
+    if( cipher_operation == MBEDTLS_ENCRYPT )
+        status = psa_driver_wrapper_cipher_encrypt_setup( &operation->ctx.driver,
+                                                          slot,
+                                                          alg );
+    else
+        status = psa_driver_wrapper_cipher_decrypt_setup( &operation->ctx.driver,
+                                                          slot,
+                                                          alg );
+
+    if( status == PSA_SUCCESS )
+    {
+        /* Once the driver context is initialised, it needs to be freed using
+        * psa_cipher_abort. Indicate this through setting alg. */
+        operation->alg = alg;
+    }
+
+    if( status != PSA_ERROR_NOT_SUPPORTED ||
+        psa_key_lifetime_is_external( slot->attr.lifetime ) )
+        goto exit;
+
+    /* Proceed with initializing an mbed TLS cipher context if no driver is
+     * available for the given algorithm & key. */
+    mbedtls_cipher_init( &operation->ctx.cipher );
+
+    /* Once the cipher context is initialised, it needs to be freed using
+     * psa_cipher_abort. Indicate there is something to be freed through setting
+     * alg, and indicate the operation is being done using mbedtls crypto through
+     * setting mbedtls_in_use. */
+    operation->alg = alg;
+    operation->mbedtls_in_use = 1;
+
+    key_bits = psa_get_key_slot_bits( slot );
     cipher_info = mbedtls_cipher_info_from_psa( alg, slot->attr.type, key_bits, NULL );
     if( cipher_info == NULL )
     {
@@ -4151,10 +4162,10 @@
         goto exit;
 #endif //MBEDTLS_CIPHER_MODE_WITH_PADDING
 
-    operation->key_set = 1;
     operation->block_size = ( PSA_ALG_IS_STREAM_CIPHER( alg ) ? 1 :
                               PSA_BLOCK_CIPHER_BLOCK_SIZE( slot->attr.type ) );
-    if( alg & PSA_ALG_CIPHER_FROM_BLOCK_FLAG )
+    if( ( alg & PSA_ALG_CIPHER_FROM_BLOCK_FLAG ) != 0 &&
+        alg != PSA_ALG_ECB_NO_PADDING )
     {
         operation->iv_size = PSA_BLOCK_CIPHER_BLOCK_SIZE( slot->attr.type );
     }
@@ -4164,10 +4175,17 @@
         operation->iv_size = 12;
 #endif
 
+    status = PSA_SUCCESS;
+
 exit:
-    if( status == 0 )
+    if( ret != 0 )
         status = mbedtls_to_psa_error( ret );
-    if( status != 0 )
+    if( status == PSA_SUCCESS )
+    {
+        /* Update operation flags for both driver and software implementations */
+        operation->key_set = 1;
+    }
+    else
         psa_cipher_abort( operation );
     return( status );
 }
@@ -4197,6 +4215,16 @@
     {
         return( PSA_ERROR_BAD_STATE );
     }
+
+    if( operation->mbedtls_in_use == 0 )
+    {
+        status = psa_driver_wrapper_cipher_generate_iv( &operation->ctx.driver,
+                                                        iv,
+                                                        iv_size,
+                                                        iv_length );
+        goto exit;
+    }
+
     if( iv_size < operation->iv_size )
     {
         status = PSA_ERROR_BUFFER_TOO_SMALL;
@@ -4214,7 +4242,9 @@
     status = psa_cipher_set_iv( operation, iv, *iv_length );
 
 exit:
-    if( status != PSA_SUCCESS )
+    if( status == PSA_SUCCESS )
+        operation->iv_set = 1;
+    else
         psa_cipher_abort( operation );
     return( status );
 }
@@ -4229,6 +4259,15 @@
     {
         return( PSA_ERROR_BAD_STATE );
     }
+
+    if( operation->mbedtls_in_use == 0 )
+    {
+        status = psa_driver_wrapper_cipher_set_iv( &operation->ctx.driver,
+                                                   iv,
+                                                   iv_length );
+        goto exit;
+    }
+
     if( iv_length != operation->iv_size )
     {
         status = PSA_ERROR_INVALID_ARGUMENT;
@@ -4244,6 +4283,94 @@
     return( status );
 }
 
+/* Process input for which the algorithm is set to ECB mode. This requires
+ * manual processing, since the PSA API is defined as being able to process
+ * arbitrary-length calls to psa_cipher_update() with ECB mode, but the
+ * underlying mbedtls_cipher_update only takes full blocks. */
+static psa_status_t psa_cipher_update_ecb_internal(
+    mbedtls_cipher_context_t *ctx,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length )
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    size_t block_size = ctx->cipher_info->block_size;
+    size_t internal_output_length = 0;
+    *output_length = 0;
+
+    if( input_length == 0 )
+    {
+        status = PSA_SUCCESS;
+        goto exit;
+    }
+
+    if( ctx->unprocessed_len > 0 )
+    {
+        /* Fill up to block size, and run the block if there's a full one. */
+        size_t bytes_to_copy = block_size - ctx->unprocessed_len;
+
+        if( input_length < bytes_to_copy )
+            bytes_to_copy = input_length;
+
+        memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ),
+                input, bytes_to_copy );
+        input_length -= bytes_to_copy;
+        input += bytes_to_copy;
+        ctx->unprocessed_len += bytes_to_copy;
+
+        if( ctx->unprocessed_len == block_size )
+        {
+            status = mbedtls_to_psa_error(
+                mbedtls_cipher_update( ctx,
+                                       ctx->unprocessed_data,
+                                       block_size,
+                                       output, &internal_output_length ) );
+
+            if( status != PSA_SUCCESS )
+                goto exit;
+
+            output += internal_output_length;
+            output_size -= internal_output_length;
+            *output_length += internal_output_length;
+            ctx->unprocessed_len = 0;
+        }
+    }
+
+    while( input_length >= block_size )
+    {
+        /* Run all full blocks we have, one by one */
+        status = mbedtls_to_psa_error(
+            mbedtls_cipher_update( ctx, input,
+                                   block_size,
+                                   output, &internal_output_length ) );
+
+        if( status != PSA_SUCCESS )
+            goto exit;
+
+        input_length -= block_size;
+        input += block_size;
+
+        output += internal_output_length;
+        output_size -= internal_output_length;
+        *output_length += internal_output_length;
+    }
+
+    if( input_length > 0 )
+    {
+        /* Save unprocessed bytes for later processing */
+        memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ),
+                input, input_length );
+        ctx->unprocessed_len += input_length;
+    }
+
+    status = PSA_SUCCESS;
+
+exit:
+    return( status );
+}
+
 psa_status_t psa_cipher_update( psa_cipher_operation_t *operation,
                                 const uint8_t *input,
                                 size_t input_length,
@@ -4251,14 +4378,27 @@
                                 size_t output_size,
                                 size_t *output_length )
 {
-    psa_status_t status;
-    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     size_t expected_output_size;
-
     if( operation->alg == 0 )
     {
         return( PSA_ERROR_BAD_STATE );
     }
+    if( operation->iv_required && ! operation->iv_set )
+    {
+        return( PSA_ERROR_BAD_STATE );
+    }
+
+    if( operation->mbedtls_in_use == 0 )
+    {
+        status = psa_driver_wrapper_cipher_update( &operation->ctx.driver,
+                                                   input,
+                                                   input_length,
+                                                   output,
+                                                   output_size,
+                                                   output_length );
+        goto exit;
+    }
 
     if( ! PSA_ALG_IS_STREAM_CIPHER( operation->alg ) )
     {
@@ -4281,9 +4421,24 @@
         goto exit;
     }
 
-    ret = mbedtls_cipher_update( &operation->ctx.cipher, input,
-                                 input_length, output, output_length );
-    status = mbedtls_to_psa_error( ret );
+    if( operation->alg == PSA_ALG_ECB_NO_PADDING )
+    {
+        /* mbedtls_cipher_update has an API inconsistency: it will only
+        * process a single block at a time in ECB mode. Abstract away that
+        * inconsistency here to match the PSA API behaviour. */
+        status = psa_cipher_update_ecb_internal( &operation->ctx.cipher,
+                                                 input,
+                                                 input_length,
+                                                 output,
+                                                 output_size,
+                                                 output_length );
+    }
+    else
+    {
+        status = mbedtls_to_psa_error(
+            mbedtls_cipher_update( &operation->ctx.cipher, input,
+                                   input_length, output, output_length ) );
+    }
 exit:
     if( status != PSA_SUCCESS )
         psa_cipher_abort( operation );
@@ -4296,10 +4451,8 @@
                                 size_t *output_length )
 {
     psa_status_t status = PSA_ERROR_GENERIC_ERROR;
-    int cipher_ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
     uint8_t temp_output_buffer[MBEDTLS_MAX_BLOCK_LENGTH];
-
-    if( ! operation->key_set )
+    if( operation->alg == 0 )
     {
         return( PSA_ERROR_BAD_STATE );
     }
@@ -4308,53 +4461,60 @@
         return( PSA_ERROR_BAD_STATE );
     }
 
-    if( operation->ctx.cipher.operation == MBEDTLS_ENCRYPT &&
-        operation->alg == PSA_ALG_CBC_NO_PADDING &&
-        operation->ctx.cipher.unprocessed_len != 0 )
+    if( operation->mbedtls_in_use == 0 )
     {
-            status = PSA_ERROR_INVALID_ARGUMENT;
-            goto error;
+        status = psa_driver_wrapper_cipher_finish( &operation->ctx.driver,
+                                                   output,
+                                                   output_size,
+                                                   output_length );
+        goto exit;
     }
 
-    cipher_ret = mbedtls_cipher_finish( &operation->ctx.cipher,
-                                        temp_output_buffer,
-                                        output_length );
-    if( cipher_ret != 0 )
+    if( operation->ctx.cipher.unprocessed_len != 0 )
     {
-        status = mbedtls_to_psa_error( cipher_ret );
-        goto error;
+        if( operation->alg == PSA_ALG_ECB_NO_PADDING ||
+            ( operation->alg == PSA_ALG_CBC_NO_PADDING &&
+              operation->ctx.cipher.operation == MBEDTLS_ENCRYPT ) )
+        {
+            status = PSA_ERROR_INVALID_ARGUMENT;
+            goto exit;
+        }
     }
 
+    status = mbedtls_to_psa_error(
+        mbedtls_cipher_finish( &operation->ctx.cipher,
+                               temp_output_buffer,
+                               output_length ) );
+    if( status != PSA_SUCCESS )
+        goto exit;
+
     if( *output_length == 0 )
         ; /* Nothing to copy. Note that output may be NULL in this case. */
     else if( output_size >= *output_length )
         memcpy( output, temp_output_buffer, *output_length );
     else
-    {
         status = PSA_ERROR_BUFFER_TOO_SMALL;
-        goto error;
+
+exit:
+    if( operation->mbedtls_in_use == 1 )
+        mbedtls_platform_zeroize( temp_output_buffer, sizeof( temp_output_buffer ) );
+
+    if( status == PSA_SUCCESS )
+        return( psa_cipher_abort( operation ) );
+    else
+    {
+        *output_length = 0;
+        (void) psa_cipher_abort( operation );
+
+        return( status );
     }
-
-    mbedtls_platform_zeroize( temp_output_buffer, sizeof( temp_output_buffer ) );
-    status = psa_cipher_abort( operation );
-
-    return( status );
-
-error:
-
-    *output_length = 0;
-
-    mbedtls_platform_zeroize( temp_output_buffer, sizeof( temp_output_buffer ) );
-    (void) psa_cipher_abort( operation );
-
-    return( status );
 }
 
 psa_status_t psa_cipher_abort( psa_cipher_operation_t *operation )
 {
     if( operation->alg == 0 )
     {
-        /* The object has (apparently) been initialized but it is not
+        /* The object has (apparently) been initialized but it is not (yet)
          * in use. It's ok to call abort on such an object, and there's
          * nothing to do. */
         return( PSA_SUCCESS );
@@ -4365,11 +4525,15 @@
     if( ! PSA_ALG_IS_CIPHER( operation->alg ) )
         return( PSA_ERROR_BAD_STATE );
 
-    mbedtls_cipher_free( &operation->ctx.cipher );
+    if( operation->mbedtls_in_use == 0 )
+        psa_driver_wrapper_cipher_abort( &operation->ctx.driver );
+    else
+        mbedtls_cipher_free( &operation->ctx.cipher );
 
     operation->alg = 0;
     operation->key_set = 0;
     operation->iv_set = 0;
+    operation->mbedtls_in_use = 0;
     operation->iv_size = 0;
     operation->block_size = 0;
     operation->iv_required = 0;
@@ -6004,29 +6168,15 @@
     if( status != PSA_SUCCESS )
         goto exit;
 
-#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
-    if( driver != NULL )
-    {
-        const psa_drv_se_t *drv = psa_get_se_driver_methods( driver );
-        size_t pubkey_length = 0; /* We don't support this feature yet */
-        if( drv->key_management == NULL ||
-            drv->key_management->p_generate == NULL )
-        {
-            status = PSA_ERROR_NOT_SUPPORTED;
-            goto exit;
-        }
-        status = drv->key_management->p_generate(
-            psa_get_se_driver_context( driver ),
-            slot->data.se.slot_number, attributes,
-            NULL, 0, &pubkey_length );
-    }
-    else
-#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
-    {
-        status = psa_generate_key_internal(
-            slot, attributes->core.bits,
-            attributes->domain_parameters, attributes->domain_parameters_size );
-    }
+    status = psa_driver_wrapper_generate_key( attributes,
+                                              slot );
+    if( status != PSA_ERROR_NOT_SUPPORTED ||
+        psa_key_lifetime_is_external( attributes->core.lifetime ) )
+        goto exit;
+
+    status = psa_generate_key_internal(
+        slot, attributes->core.bits,
+        attributes->domain_parameters, attributes->domain_parameters_size );
 
 exit:
     if( status == PSA_SUCCESS )
diff --git a/library/psa_crypto_core.h b/library/psa_crypto_core.h
index 9a61bab..6ee17fc 100644
--- a/library/psa_crypto_core.h
+++ b/library/psa_crypto_core.h
@@ -161,4 +161,16 @@
                                        const uint8_t *data,
                                        size_t data_length );
 
+
+/** Convert an mbed TLS error code to a PSA error code
+ *
+ * \note This function is provided solely for the convenience of
+ *       Mbed TLS and may be removed at any time without notice.
+ *
+ * \param ret           An mbed TLS-thrown error code
+ *
+ * \return              The corresponding PSA error code
+ */
+psa_status_t mbedtls_to_psa_error( int ret );
+
 #endif /* PSA_CRYPTO_CORE_H */
diff --git a/library/psa_crypto_driver_wrappers.c b/library/psa_crypto_driver_wrappers.c
new file mode 100644
index 0000000..d41209b
--- /dev/null
+++ b/library/psa_crypto_driver_wrappers.c
@@ -0,0 +1,878 @@
+/*
+ *  Functions to delegate cryptographic operations to an available
+ *  and appropriate accelerator.
+ *  Warning: This file will be auto-generated in the future.
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#include "psa_crypto_core.h"
+#include "psa_crypto_driver_wrappers.h"
+#include "mbedtls/platform.h"
+
+#if defined(MBEDTLS_PSA_CRYPTO_DRIVERS)
+
+/* Include test driver definition when running tests */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#ifndef PSA_CRYPTO_DRIVER_PRESENT
+#define PSA_CRYPTO_DRIVER_PRESENT
+#endif
+#ifndef PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT
+#define PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT
+#endif
+#include "test/drivers/test_driver.h"
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+
+/* Repeat above block for each JSON-declared driver during autogeneration */
+
+/* Auto-generated values depending on which drivers are registered. ID 0 is
+ * reserved for unallocated operations. */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#define PSA_CRYPTO_TRANSPARENT_TEST_DRIVER_ID (1)
+#define PSA_CRYPTO_OPAQUE_TEST_DRIVER_ID (2)
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* MBEDTLS_PSA_CRYPTO_DRIVERS */
+
+/* Support the 'old' SE interface when asked to */
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+/* PSA_CRYPTO_DRIVER_PRESENT is defined when either a new-style or old-style
+ * SE driver is present, to avoid unused argument errors at compile time. */
+#ifndef PSA_CRYPTO_DRIVER_PRESENT
+#define PSA_CRYPTO_DRIVER_PRESENT
+#endif
+#include "psa_crypto_se.h"
+#endif
+
+/* Start delegation functions */
+psa_status_t psa_driver_wrapper_sign_hash( psa_key_slot_t *slot,
+                                           psa_algorithm_t alg,
+                                           const uint8_t *hash,
+                                           size_t hash_length,
+                                           uint8_t *signature,
+                                           size_t signature_size,
+                                           size_t *signature_length )
+{
+#if defined(PSA_CRYPTO_DRIVER_PRESENT)
+    /* Try dynamically-registered SE interface first */
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+    const psa_drv_se_t *drv;
+    psa_drv_se_context_t *drv_context;
+
+    if( psa_get_se_driver( slot->attr.lifetime, &drv, &drv_context ) )
+    {
+        if( drv->asymmetric == NULL ||
+            drv->asymmetric->p_sign == NULL )
+        {
+            /* Key is defined in SE, but we have no way to exercise it */
+            return( PSA_ERROR_NOT_SUPPORTED );
+        }
+        return( drv->asymmetric->p_sign( drv_context,
+                                         slot->data.se.slot_number,
+                                         alg,
+                                         hash, hash_length,
+                                         signature, signature_size,
+                                         signature_length ) );
+    }
+#endif /* PSA_CRYPTO_SE_C */
+
+    /* Then try accelerator API */
+#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+    psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+    psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime);
+    psa_key_attributes_t attributes = {
+      .core = slot->attr
+    };
+
+    switch( location )
+    {
+        case PSA_KEY_LOCATION_LOCAL_STORAGE:
+            /* Key is stored in the slot in export representation, so
+             * cycle through all known transparent accelerators */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+            status = test_transparent_signature_sign_hash( &attributes,
+                                                           slot->data.key.data,
+                                                           slot->data.key.bytes,
+                                                           alg,
+                                                           hash,
+                                                           hash_length,
+                                                           signature,
+                                                           signature_size,
+                                                           signature_length );
+            /* Declared with fallback == true */
+            if( status != PSA_ERROR_NOT_SUPPORTED )
+                return( status );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+            /* Fell through, meaning no accelerator supports this operation */
+            return( PSA_ERROR_NOT_SUPPORTED );
+        /* Add cases for opaque driver here */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+        case PSA_CRYPTO_TEST_DRIVER_LIFETIME:
+            return( test_opaque_signature_sign_hash( &attributes,
+                                                     slot->data.key.data,
+                                                     slot->data.key.bytes,
+                                                     alg,
+                                                     hash,
+                                                     hash_length,
+                                                     signature,
+                                                     signature_size,
+                                                     signature_length ) );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+        default:
+            /* Key is declared with a lifetime not known to us */
+            return( status );
+    }
+#else /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
+    return( PSA_ERROR_NOT_SUPPORTED );
+#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
+#else /* PSA_CRYPTO_DRIVER_PRESENT */
+    (void)slot;
+    (void)alg;
+    (void)hash;
+    (void)hash_length;
+    (void)signature;
+    (void)signature_size;
+    (void)signature_length;
+
+    return( PSA_ERROR_NOT_SUPPORTED );
+#endif /* PSA_CRYPTO_DRIVER_PRESENT */
+}
+
+psa_status_t psa_driver_wrapper_verify_hash( psa_key_slot_t *slot,
+                                             psa_algorithm_t alg,
+                                             const uint8_t *hash,
+                                             size_t hash_length,
+                                             const uint8_t *signature,
+                                             size_t signature_length )
+{
+#if defined(PSA_CRYPTO_DRIVER_PRESENT)
+    /* Try dynamically-registered SE interface first */
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+    const psa_drv_se_t *drv;
+    psa_drv_se_context_t *drv_context;
+
+    if( psa_get_se_driver( slot->attr.lifetime, &drv, &drv_context ) )
+    {
+        if( drv->asymmetric == NULL ||
+            drv->asymmetric->p_verify == NULL )
+        {
+            /* Key is defined in SE, but we have no way to exercise it */
+            return( PSA_ERROR_NOT_SUPPORTED );
+        }
+        return( drv->asymmetric->p_verify( drv_context,
+                                           slot->data.se.slot_number,
+                                           alg,
+                                           hash, hash_length,
+                                           signature, signature_length ) );
+    }
+#endif /* PSA_CRYPTO_SE_C */
+
+    /* Then try accelerator API */
+#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+    psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+    psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime);
+    psa_key_attributes_t attributes = {
+      .core = slot->attr
+    };
+
+    switch( location )
+    {
+        case PSA_KEY_LOCATION_LOCAL_STORAGE:
+            /* Key is stored in the slot in export representation, so
+             * cycle through all known transparent accelerators */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+            status = test_transparent_signature_verify_hash( &attributes,
+                                                             slot->data.key.data,
+                                                             slot->data.key.bytes,
+                                                             alg,
+                                                             hash,
+                                                             hash_length,
+                                                             signature,
+                                                             signature_length );
+            /* Declared with fallback == true */
+            if( status != PSA_ERROR_NOT_SUPPORTED )
+                return( status );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+            /* Fell through, meaning no accelerator supports this operation */
+            return( PSA_ERROR_NOT_SUPPORTED );
+        /* Add cases for opaque driver here */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+        case PSA_CRYPTO_TEST_DRIVER_LIFETIME:
+            return( test_opaque_signature_verify_hash( &attributes,
+                                                       slot->data.key.data,
+                                                       slot->data.key.bytes,
+                                                       alg,
+                                                       hash,
+                                                       hash_length,
+                                                       signature,
+                                                       signature_length ) );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+        default:
+            /* Key is declared with a lifetime not known to us */
+            return( status );
+    }
+#else /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
+    return( PSA_ERROR_NOT_SUPPORTED );
+#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
+#else /* PSA_CRYPTO_DRIVER_PRESENT */
+    (void)slot;
+    (void)alg;
+    (void)hash;
+    (void)hash_length;
+    (void)signature;
+    (void)signature_length;
+
+    return( PSA_ERROR_NOT_SUPPORTED );
+#endif /* PSA_CRYPTO_DRIVER_PRESENT */
+}
+
+#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+/** Calculate the size to allocate for buffering a key with given attributes.
+ *
+ * This function provides a way to get the expected size for storing a key with
+ * the given attributes. This will be the size of the export representation for
+ * cleartext keys, and a driver-defined size for keys stored by opaque drivers.
+ *
+ * \param[in] attributes        The key attribute structure of the key to store.
+ * \param[out] expected_size    On success, a byte size large enough to contain
+ *                              the declared key.
+ *
+ * \retval #PSA_SUCCESS
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ */
+static psa_status_t get_expected_key_size( const psa_key_attributes_t *attributes,
+                                           size_t *expected_size )
+{
+    size_t buffer_size = 0;
+    if( PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime ) == PSA_KEY_LOCATION_LOCAL_STORAGE )
+    {
+        buffer_size = PSA_KEY_EXPORT_MAX_SIZE( attributes->core.type,
+                                               attributes->core.bits );
+
+        if( buffer_size == 0 )
+            return( PSA_ERROR_NOT_SUPPORTED );
+
+        *expected_size = buffer_size;
+        return( PSA_SUCCESS );
+    }
+    else
+    {
+        /* TBD: opaque driver support: need to calculate size through a
+         * driver-defined size function, since the size of an opaque (wrapped)
+         * key will be different for each implementation. */
+        return( PSA_ERROR_NOT_SUPPORTED );
+    }
+}
+#endif /* PSA_CRYPTO_DRIVER_PRESENT */
+
+psa_status_t psa_driver_wrapper_generate_key( const psa_key_attributes_t *attributes,
+                                              psa_key_slot_t *slot )
+{
+#if defined(PSA_CRYPTO_DRIVER_PRESENT)
+    /* Try dynamically-registered SE interface first */
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+    const psa_drv_se_t *drv;
+    psa_drv_se_context_t *drv_context;
+
+    if( psa_get_se_driver( slot->attr.lifetime, &drv, &drv_context ) )
+    {
+        size_t pubkey_length = 0; /* We don't support this feature yet */
+        if( drv->key_management == NULL ||
+            drv->key_management->p_generate == NULL )
+        {
+            /* Key is defined as being in SE, but we have no way to generate it */
+            return( PSA_ERROR_NOT_SUPPORTED );
+        }
+        return( drv->key_management->p_generate(
+            drv_context,
+            slot->data.se.slot_number, attributes,
+            NULL, 0, &pubkey_length ) );
+    }
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+
+    /* Then try accelerator API */
+#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+    psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+    psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime);
+    size_t export_size = 0;
+
+    status = get_expected_key_size( attributes, &export_size );
+    if( status != PSA_SUCCESS )
+        return( status );
+
+    slot->data.key.data = mbedtls_calloc(1, export_size);
+    if( slot->data.key.data == NULL )
+        return( PSA_ERROR_INSUFFICIENT_MEMORY );
+    slot->data.key.bytes = export_size;
+
+    switch( location )
+    {
+        case PSA_KEY_LOCATION_LOCAL_STORAGE:
+            /* Key is stored in the slot in export representation, so
+             * cycle through all known transparent accelerators */
+
+            /* Transparent drivers are limited to generating asymmetric keys */
+            if( ! PSA_KEY_TYPE_IS_ASYMMETRIC( slot->attr.type ) )
+            {
+                status = PSA_ERROR_NOT_SUPPORTED;
+                break;
+            }
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+            status = test_transparent_generate_key( attributes,
+                                                    slot->data.key.data,
+                                                    slot->data.key.bytes,
+                                                    &slot->data.key.bytes );
+            /* Declared with fallback == true */
+            if( status != PSA_ERROR_NOT_SUPPORTED )
+                break;
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+            /* Fell through, meaning no accelerator supports this operation */
+            status = PSA_ERROR_NOT_SUPPORTED;
+            break;
+        /* Add cases for opaque driver here */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+        case PSA_CRYPTO_TEST_DRIVER_LIFETIME:
+            status = test_opaque_generate_key( attributes,
+                                               slot->data.key.data,
+                                               slot->data.key.bytes,
+                                               &slot->data.key.bytes );
+            break;
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+        default:
+            /* Key is declared with a lifetime not known to us */
+            status = PSA_ERROR_INVALID_ARGUMENT;
+            break;
+    }
+
+    if( status != PSA_SUCCESS )
+    {
+        /* free allocated buffer */
+        mbedtls_free( slot->data.key.data );
+        slot->data.key.data = NULL;
+        slot->data.key.bytes = 0;
+    }
+
+    return( status );
+#else /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
+    return( PSA_ERROR_NOT_SUPPORTED );
+#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
+#else /* PSA_CRYPTO_DRIVER_PRESENT */
+    (void) attributes;
+    (void) slot;
+
+    return( PSA_ERROR_NOT_SUPPORTED );
+#endif /* PSA_CRYPTO_DRIVER_PRESENT */
+}
+
+/*
+ * Cipher functions
+ */
+psa_status_t psa_driver_wrapper_cipher_encrypt(
+    psa_key_slot_t *slot,
+    psa_algorithm_t alg,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length )
+{
+#if defined(PSA_CRYPTO_DRIVER_PRESENT) && defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+    psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+    psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime);
+    psa_key_attributes_t attributes = {
+      .core = slot->attr
+    };
+
+    switch( location )
+    {
+        case PSA_KEY_LOCATION_LOCAL_STORAGE:
+            /* Key is stored in the slot in export representation, so
+             * cycle through all known transparent accelerators */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+            status = test_transparent_cipher_encrypt( &attributes,
+                                                      slot->data.key.data,
+                                                      slot->data.key.bytes,
+                                                      alg,
+                                                      input,
+                                                      input_length,
+                                                      output,
+                                                      output_size,
+                                                      output_length );
+            /* Declared with fallback == true */
+            if( status != PSA_ERROR_NOT_SUPPORTED )
+                return( status );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+            /* Fell through, meaning no accelerator supports this operation */
+            return( PSA_ERROR_NOT_SUPPORTED );
+        /* Add cases for opaque driver here */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+        case PSA_CRYPTO_TEST_DRIVER_LIFETIME:
+            return( test_opaque_cipher_encrypt( &attributes,
+                                                slot->data.key.data,
+                                                slot->data.key.bytes,
+                                                alg,
+                                                input,
+                                                input_length,
+                                                output,
+                                                output_size,
+                                                output_length ) );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+        default:
+            /* Key is declared with a lifetime not known to us */
+            return( status );
+    }
+#else /* PSA_CRYPTO_DRIVER_PRESENT */
+    (void) slot;
+    (void) alg;
+    (void) input;
+    (void) input_length;
+    (void) output;
+    (void) output_size;
+    (void) output_length;
+
+    return( PSA_ERROR_NOT_SUPPORTED );
+#endif /* PSA_CRYPTO_DRIVER_PRESENT */
+}
+
+psa_status_t psa_driver_wrapper_cipher_decrypt(
+    psa_key_slot_t *slot,
+    psa_algorithm_t alg,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length )
+{
+#if defined(PSA_CRYPTO_DRIVER_PRESENT) && defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+    psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+    psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime);
+    psa_key_attributes_t attributes = {
+      .core = slot->attr
+    };
+
+    switch( location )
+    {
+        case PSA_KEY_LOCATION_LOCAL_STORAGE:
+            /* Key is stored in the slot in export representation, so
+             * cycle through all known transparent accelerators */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+            status = test_transparent_cipher_decrypt( &attributes,
+                                                      slot->data.key.data,
+                                                      slot->data.key.bytes,
+                                                      alg,
+                                                      input,
+                                                      input_length,
+                                                      output,
+                                                      output_size,
+                                                      output_length );
+            /* Declared with fallback == true */
+            if( status != PSA_ERROR_NOT_SUPPORTED )
+                return( status );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+            /* Fell through, meaning no accelerator supports this operation */
+            return( PSA_ERROR_NOT_SUPPORTED );
+        /* Add cases for opaque driver here */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+        case PSA_CRYPTO_TEST_DRIVER_LIFETIME:
+            return( test_opaque_cipher_decrypt( &attributes,
+                                                slot->data.key.data,
+                                                slot->data.key.bytes,
+                                                alg,
+                                                input,
+                                                input_length,
+                                                output,
+                                                output_size,
+                                                output_length ) );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+        default:
+            /* Key is declared with a lifetime not known to us */
+            return( status );
+    }
+#else /* PSA_CRYPTO_DRIVER_PRESENT */
+    (void) slot;
+    (void) alg;
+    (void) input;
+    (void) input_length;
+    (void) output;
+    (void) output_size;
+    (void) output_length;
+
+    return( PSA_ERROR_NOT_SUPPORTED );
+#endif /* PSA_CRYPTO_DRIVER_PRESENT */
+}
+
+psa_status_t psa_driver_wrapper_cipher_encrypt_setup(
+    psa_operation_driver_context_t *operation,
+    psa_key_slot_t *slot,
+    psa_algorithm_t alg )
+{
+#if defined(PSA_CRYPTO_DRIVER_PRESENT) && defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+    psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+    psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime);
+    psa_key_attributes_t attributes = {
+      .core = slot->attr
+    };
+
+    switch( location )
+    {
+        case PSA_KEY_LOCATION_LOCAL_STORAGE:
+            /* Key is stored in the slot in export representation, so
+             * cycle through all known transparent accelerators */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+            operation->ctx = mbedtls_calloc( 1, sizeof(test_transparent_cipher_operation_t) );
+            if( operation->ctx == NULL )
+                return PSA_ERROR_INSUFFICIENT_MEMORY;
+
+            status = test_transparent_cipher_encrypt_setup( operation->ctx,
+                                                            &attributes,
+                                                            slot->data.key.data,
+                                                            slot->data.key.bytes,
+                                                            alg );
+            /* Declared with fallback == true */
+            if( status == PSA_SUCCESS )
+                operation->id = PSA_CRYPTO_TRANSPARENT_TEST_DRIVER_ID;
+            else
+            {
+                mbedtls_platform_zeroize(
+                    operation->ctx,
+                    sizeof( test_transparent_cipher_operation_t ) );
+                mbedtls_free( operation->ctx );
+                operation->ctx = NULL;
+            }
+
+            return( status );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+            /* Fell through, meaning no accelerator supports this operation */
+            return( PSA_ERROR_NOT_SUPPORTED );
+        /* Add cases for opaque driver here */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+        case PSA_CRYPTO_TEST_DRIVER_LIFETIME:
+            operation->ctx = mbedtls_calloc( 1, sizeof(test_opaque_cipher_operation_t) );
+            if( operation->ctx == NULL )
+                return( PSA_ERROR_INSUFFICIENT_MEMORY );
+
+            status = test_opaque_cipher_encrypt_setup( operation->ctx,
+                                                       &attributes,
+                                                       slot->data.key.data,
+                                                       slot->data.key.bytes,
+                                                       alg );
+            if( status == PSA_SUCCESS )
+                operation->id = PSA_CRYPTO_OPAQUE_TEST_DRIVER_ID;
+            else
+            {
+                mbedtls_platform_zeroize(
+                    operation->ctx,
+                    sizeof( test_opaque_cipher_operation_t ) );
+                mbedtls_free( operation->ctx );
+                operation->ctx = NULL;
+            }
+
+            return( status );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+        default:
+            /* Key is declared with a lifetime not known to us */
+            return( PSA_ERROR_BAD_STATE );
+    }
+#else /* PSA_CRYPTO_DRIVER_PRESENT */
+    (void)slot;
+    (void)alg;
+    (void)operation;
+
+    return( PSA_ERROR_NOT_SUPPORTED );
+#endif /* PSA_CRYPTO_DRIVER_PRESENT */
+}
+
+psa_status_t psa_driver_wrapper_cipher_decrypt_setup(
+    psa_operation_driver_context_t *operation,
+    psa_key_slot_t *slot,
+    psa_algorithm_t alg )
+{
+#if defined(PSA_CRYPTO_DRIVER_PRESENT) && defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+    psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+    psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime);
+    psa_key_attributes_t attributes = {
+      .core = slot->attr
+    };
+
+    switch( location )
+    {
+        case PSA_KEY_LOCATION_LOCAL_STORAGE:
+            /* Key is stored in the slot in export representation, so
+             * cycle through all known transparent accelerators */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+            operation->ctx = mbedtls_calloc( 1, sizeof(test_transparent_cipher_operation_t) );
+            if( operation->ctx == NULL )
+                return( PSA_ERROR_INSUFFICIENT_MEMORY );
+
+            status = test_transparent_cipher_decrypt_setup( operation->ctx,
+                                                            &attributes,
+                                                            slot->data.key.data,
+                                                            slot->data.key.bytes,
+                                                            alg );
+            /* Declared with fallback == true */
+            if( status == PSA_SUCCESS )
+                operation->id = PSA_CRYPTO_TRANSPARENT_TEST_DRIVER_ID;
+            else
+            {
+                mbedtls_platform_zeroize(
+                    operation->ctx,
+                    sizeof( test_transparent_cipher_operation_t ) );
+                mbedtls_free( operation->ctx );
+                operation->ctx = NULL;
+            }
+
+            return( status );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+            /* Fell through, meaning no accelerator supports this operation */
+            return( PSA_ERROR_NOT_SUPPORTED );
+        /* Add cases for opaque driver here */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+        case PSA_CRYPTO_TEST_DRIVER_LIFETIME:
+            operation->ctx = mbedtls_calloc( 1, sizeof(test_opaque_cipher_operation_t) );
+            if( operation->ctx == NULL )
+                return PSA_ERROR_INSUFFICIENT_MEMORY;
+
+            status = test_opaque_cipher_decrypt_setup( operation->ctx,
+                                                       &attributes,
+                                                       slot->data.key.data,
+                                                       slot->data.key.bytes,
+                                                       alg );
+            if( status == PSA_SUCCESS )
+                operation->id = PSA_CRYPTO_OPAQUE_TEST_DRIVER_ID;
+            else
+            {
+                mbedtls_platform_zeroize(
+                    operation->ctx,
+                    sizeof( test_opaque_cipher_operation_t ) );
+                mbedtls_free( operation->ctx );
+                operation->ctx = NULL;
+            }
+
+            return( status );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+        default:
+            /* Key is declared with a lifetime not known to us */
+            return( PSA_ERROR_BAD_STATE );
+    }
+#else /* PSA_CRYPTO_DRIVER_PRESENT */
+    (void)slot;
+    (void)alg;
+    (void)operation;
+
+    return( PSA_ERROR_NOT_SUPPORTED );
+#endif /* PSA_CRYPTO_DRIVER_PRESENT */
+}
+
+psa_status_t psa_driver_wrapper_cipher_generate_iv(
+    psa_operation_driver_context_t *operation,
+    uint8_t *iv,
+    size_t iv_size,
+    size_t *iv_length )
+{
+#if defined(PSA_CRYPTO_DRIVER_PRESENT) && defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+    switch( operation->id )
+    {
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+        case PSA_CRYPTO_TRANSPARENT_TEST_DRIVER_ID:
+            return( test_transparent_cipher_generate_iv( operation->ctx,
+                                                         iv,
+                                                         iv_size,
+                                                         iv_length ) );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+        case PSA_CRYPTO_OPAQUE_TEST_DRIVER_ID:
+            return( test_opaque_cipher_generate_iv( operation->ctx,
+                                                    iv,
+                                                    iv_size,
+                                                    iv_length ) );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+        default:
+            /* Key is attached to a driver not known to us */
+            return( PSA_ERROR_BAD_STATE );
+    }
+#else /* PSA_CRYPTO_DRIVER_PRESENT */
+    (void) operation;
+    (void) iv;
+    (void) iv_size;
+    (void) iv_length;
+
+    return( PSA_ERROR_NOT_SUPPORTED );
+#endif /* PSA_CRYPTO_DRIVER_PRESENT */
+}
+
+psa_status_t psa_driver_wrapper_cipher_set_iv(
+    psa_operation_driver_context_t *operation,
+    const uint8_t *iv,
+    size_t iv_length )
+{
+#if defined(PSA_CRYPTO_DRIVER_PRESENT) && defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+    switch( operation->id )
+    {
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+        case PSA_CRYPTO_TRANSPARENT_TEST_DRIVER_ID:
+            return( test_transparent_cipher_set_iv( operation->ctx,
+                                                    iv,
+                                                    iv_length ) );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+        case PSA_CRYPTO_OPAQUE_TEST_DRIVER_ID:
+            return( test_opaque_cipher_set_iv( operation->ctx,
+                                               iv,
+                                               iv_length ) );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+        default:
+            /* Key is attached to a driver not known to us */
+            return( PSA_ERROR_BAD_STATE );
+    }
+#else /* PSA_CRYPTO_DRIVER_PRESENT */
+    (void) operation;
+    (void) iv;
+    (void) iv_length;
+
+    return( PSA_ERROR_NOT_SUPPORTED );
+#endif /* PSA_CRYPTO_DRIVER_PRESENT */
+}
+
+psa_status_t psa_driver_wrapper_cipher_update(
+    psa_operation_driver_context_t *operation,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length )
+{
+#if defined(PSA_CRYPTO_DRIVER_PRESENT) && defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+    switch( operation->id )
+    {
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+        case PSA_CRYPTO_TRANSPARENT_TEST_DRIVER_ID:
+            return( test_transparent_cipher_update( operation->ctx,
+                                                    input,
+                                                    input_length,
+                                                    output,
+                                                    output_size,
+                                                    output_length ) );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+        case PSA_CRYPTO_OPAQUE_TEST_DRIVER_ID:
+            return( test_opaque_cipher_update( operation->ctx,
+                                               input,
+                                               input_length,
+                                               output,
+                                               output_size,
+                                               output_length ) );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+        default:
+            /* Key is attached to a driver not known to us */
+            return( PSA_ERROR_BAD_STATE );
+    }
+#else /* PSA_CRYPTO_DRIVER_PRESENT */
+    (void) operation;
+    (void) input;
+    (void) input_length;
+    (void) output;
+    (void) output_length;
+    (void) output_size;
+
+    return( PSA_ERROR_NOT_SUPPORTED );
+#endif /* PSA_CRYPTO_DRIVER_PRESENT */
+}
+
+psa_status_t psa_driver_wrapper_cipher_finish(
+    psa_operation_driver_context_t *operation,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length )
+{
+#if defined(PSA_CRYPTO_DRIVER_PRESENT) && defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+    switch( operation->id )
+    {
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+        case PSA_CRYPTO_TRANSPARENT_TEST_DRIVER_ID:
+            return( test_transparent_cipher_finish( operation->ctx,
+                                                    output,
+                                                    output_size,
+                                                    output_length ) );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+        case PSA_CRYPTO_OPAQUE_TEST_DRIVER_ID:
+            return( test_opaque_cipher_finish( operation->ctx,
+                                               output,
+                                               output_size,
+                                               output_length ) );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+        default:
+            /* Key is attached to a driver not known to us */
+            return( PSA_ERROR_BAD_STATE );
+    }
+#else /* PSA_CRYPTO_DRIVER_PRESENT */
+    (void) operation;
+    (void) output;
+    (void) output_size;
+    (void) output_length;
+
+    return( PSA_ERROR_NOT_SUPPORTED );
+#endif /* PSA_CRYPTO_DRIVER_PRESENT */
+}
+
+psa_status_t psa_driver_wrapper_cipher_abort(
+    psa_operation_driver_context_t *operation )
+{
+#if defined(PSA_CRYPTO_DRIVER_PRESENT) && defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+    psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+
+    /* The object has (apparently) been initialized but it is not in use. It's
+     * ok to call abort on such an object, and there's nothing to do. */
+    if( operation->ctx == NULL && operation->id == 0 )
+        return( PSA_SUCCESS );
+
+    switch( operation->id )
+    {
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+        case PSA_CRYPTO_TRANSPARENT_TEST_DRIVER_ID:
+            status = test_transparent_cipher_abort( operation->ctx );
+            mbedtls_platform_zeroize(
+                operation->ctx,
+                sizeof( test_transparent_cipher_operation_t ) );
+            mbedtls_free( operation->ctx );
+            operation->ctx = NULL;
+            operation->id = 0;
+
+            return( status );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+        case PSA_CRYPTO_OPAQUE_TEST_DRIVER_ID:
+            status = test_opaque_cipher_abort( operation->ctx );
+            mbedtls_platform_zeroize(
+                operation->ctx,
+                sizeof( test_opaque_cipher_operation_t ) );
+            mbedtls_free( operation->ctx );
+            operation->ctx = NULL;
+            operation->id = 0;
+
+            return( status );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+        default:
+            /* Operation is attached to a driver not known to us */
+            return( PSA_ERROR_BAD_STATE );
+    }
+#else /* PSA_CRYPTO_DRIVER_PRESENT */
+    (void)operation;
+
+    return( PSA_ERROR_NOT_SUPPORTED );
+#endif /* PSA_CRYPTO_DRIVER_PRESENT */
+}
+
+/* End of automatically generated file. */
diff --git a/library/psa_crypto_driver_wrappers.h b/library/psa_crypto_driver_wrappers.h
new file mode 100644
index 0000000..0db15d6
--- /dev/null
+++ b/library/psa_crypto_driver_wrappers.h
@@ -0,0 +1,110 @@
+/*
+ *  Function signatures for functionality that can be provided by
+ *  cryptographic accelerators.
+ *  Warning: This file will be auto-generated in the future.
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#ifndef PSA_CRYPTO_DRIVER_WRAPPERS_H
+#define PSA_CRYPTO_DRIVER_WRAPPERS_H
+
+#include "psa/crypto.h"
+#include "psa/crypto_driver_common.h"
+
+/*
+ * Signature functions
+ */
+psa_status_t psa_driver_wrapper_sign_hash( psa_key_slot_t *slot,
+                                           psa_algorithm_t alg,
+                                           const uint8_t *hash,
+                                           size_t hash_length,
+                                           uint8_t *signature,
+                                           size_t signature_size,
+                                           size_t *signature_length );
+
+psa_status_t psa_driver_wrapper_verify_hash( psa_key_slot_t *slot,
+                                             psa_algorithm_t alg,
+                                             const uint8_t *hash,
+                                             size_t hash_length,
+                                             const uint8_t *signature,
+                                             size_t signature_length );
+
+psa_status_t psa_driver_wrapper_generate_key( const psa_key_attributes_t *attributes,
+                                              psa_key_slot_t *slot );
+
+/*
+ * Cipher functions
+ */
+psa_status_t psa_driver_wrapper_cipher_encrypt(
+    psa_key_slot_t *slot,
+    psa_algorithm_t alg,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length );
+
+psa_status_t psa_driver_wrapper_cipher_decrypt(
+    psa_key_slot_t *slot,
+    psa_algorithm_t alg,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length );
+
+psa_status_t psa_driver_wrapper_cipher_encrypt_setup(
+    psa_operation_driver_context_t *operation,
+    psa_key_slot_t *slot,
+    psa_algorithm_t alg );
+
+psa_status_t psa_driver_wrapper_cipher_decrypt_setup(
+    psa_operation_driver_context_t *operation,
+    psa_key_slot_t *slot,
+    psa_algorithm_t alg );
+
+psa_status_t psa_driver_wrapper_cipher_generate_iv(
+    psa_operation_driver_context_t *operation,
+    uint8_t *iv,
+    size_t iv_size,
+    size_t *iv_length );
+
+psa_status_t psa_driver_wrapper_cipher_set_iv(
+    psa_operation_driver_context_t *operation,
+    const uint8_t *iv,
+    size_t iv_length );
+
+psa_status_t psa_driver_wrapper_cipher_update(
+    psa_operation_driver_context_t *operation,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length );
+
+psa_status_t psa_driver_wrapper_cipher_finish(
+    psa_operation_driver_context_t *operation,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length );
+
+psa_status_t psa_driver_wrapper_cipher_abort(
+    psa_operation_driver_context_t *operation );
+
+#endif /* PSA_CRYPTO_DRIVER_WRAPPERS_H */
+
+/* End of automatically generated file. */
diff --git a/library/ripemd160.c b/library/ripemd160.c
index 830f61b..603b6ba 100644
--- a/library/ripemd160.c
+++ b/library/ripemd160.c
@@ -478,8 +478,7 @@
     { "abcdefghijklmnopqrstuvwxyz" },
     { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
     { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
-    { "12345678901234567890123456789012345678901234567890123456789012"
-      "345678901234567890" },
+    { "12345678901234567890123456789012345678901234567890123456789012345678901234567890" },
 };
 
 static const size_t ripemd160_test_strlen[TESTS] =
diff --git a/library/sha512.c b/library/sha512.c
index 80219d4..e881198 100644
--- a/library/sha512.c
+++ b/library/sha512.c
@@ -516,8 +516,7 @@
 static const unsigned char sha512_test_buf[3][113] =
 {
     { "abc" },
-    { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
-      "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" },
+    { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" },
     { "" }
 };
 
diff --git a/library/version_features.c b/library/version_features.c
index 80263f7..478d8fa 100644
--- a/library/version_features.c
+++ b/library/version_features.c
@@ -435,6 +435,9 @@
 #if defined(MBEDTLS_PKCS1_V21)
     "MBEDTLS_PKCS1_V21",
 #endif /* MBEDTLS_PKCS1_V21 */
+#if defined(MBEDTLS_PSA_CRYPTO_DRIVERS)
+    "MBEDTLS_PSA_CRYPTO_DRIVERS",
+#endif /* MBEDTLS_PSA_CRYPTO_DRIVERS */
 #if defined(MBEDTLS_PSA_CRYPTO_SPM)
     "MBEDTLS_PSA_CRYPTO_SPM",
 #endif /* MBEDTLS_PSA_CRYPTO_SPM */
diff --git a/library/x509.c b/library/x509.c
index 1579c1a..2a7be32 100644
--- a/library/x509.c
+++ b/library/x509.c
@@ -154,7 +154,7 @@
         return( MBEDTLS_ERR_X509_INVALID_ALG +
                 MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
 
-    p = (unsigned char *) alg->p;
+    p = alg->p;
     end = p + alg->len;
 
     if( p >= end )
diff --git a/programs/Makefile b/programs/Makefile
index f9c2608..dfe0555 100644
--- a/programs/Makefile
+++ b/programs/Makefile
@@ -8,7 +8,7 @@
 LDFLAGS ?=
 
 MBEDTLS_TEST_PATH:=../tests/src
-MBEDTLS_TEST_OBJS:=$(patsubst %.c,%.o,$(wildcard ${MBEDTLS_TEST_PATH}/*.c))
+MBEDTLS_TEST_OBJS:=$(patsubst %.c,%.o,$(wildcard ${MBEDTLS_TEST_PATH}/*.c ${MBEDTLS_TEST_PATH}/drivers/*.c))
 
 LOCAL_CFLAGS = $(WARNING_CFLAGS) -I../tests/include -I../include -D_FILE_OFFSET_BITS=64
 LOCAL_CXXFLAGS = $(WARNING_CXXFLAGS) -I../include -D_FILE_OFFSET_BITS=64
diff --git a/programs/fuzz/Makefile b/programs/fuzz/Makefile
index 8196f39..fa17918 100644
--- a/programs/fuzz/Makefile
+++ b/programs/fuzz/Makefile
@@ -1,5 +1,5 @@
 MBEDTLS_TEST_PATH:=../../tests/src
-MBEDTLS_TEST_OBJS:=$(patsubst %.c,%.o,$(wildcard ${MBEDTLS_TEST_PATH}/*.c))
+MBEDTLS_TEST_OBJS:=$(patsubst %.c,%.o,$(wildcard ${MBEDTLS_TEST_PATH}/*.c ${MBEDTLS_TEST_PATH}/drivers/*.c))
 
 LOCAL_CFLAGS = -I../../tests/include -I../../include -D_FILE_OFFSET_BITS=64
 LOCAL_LDFLAGS = ${MBEDTLS_TEST_OBJS}		\
diff --git a/programs/pkey/ecdh_curve25519.c b/programs/pkey/ecdh_curve25519.c
index a76266f..67f1363 100644
--- a/programs/pkey/ecdh_curve25519.c
+++ b/programs/pkey/ecdh_curve25519.c
@@ -86,7 +86,7 @@
     mbedtls_printf( " ok\n" );
 
     /*
-     * Client: inialize context and generate keypair
+     * Client: initialize context and generate keypair
      */
     mbedtls_printf( "  . Setting up client context..." );
     fflush( stdout );
diff --git a/programs/test/query_config.c b/programs/test/query_config.c
index fd3b826..8873734 100644
--- a/programs/test/query_config.c
+++ b/programs/test/query_config.c
@@ -1216,6 +1216,14 @@
     }
 #endif /* MBEDTLS_PKCS1_V21 */
 
+#if defined(MBEDTLS_PSA_CRYPTO_DRIVERS)
+    if( strcmp( "MBEDTLS_PSA_CRYPTO_DRIVERS", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PSA_CRYPTO_DRIVERS );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PSA_CRYPTO_DRIVERS */
+
 #if defined(MBEDTLS_PSA_CRYPTO_SPM)
     if( strcmp( "MBEDTLS_PSA_CRYPTO_SPM", config ) == 0 )
     {
diff --git a/scripts/generate_visualc_files.pl b/scripts/generate_visualc_files.pl
index 3d4baca..6c2b5e4 100755
--- a/scripts/generate_visualc_files.pl
+++ b/scripts/generate_visualc_files.pl
@@ -39,6 +39,7 @@
 my $source_dir = 'library';
 my $test_source_dir = 'tests/src';
 my $test_header_dir = 'tests/include/test';
+my $test_drivers_header_dir = 'tests/include/test/drivers';
 
 my @thirdparty_header_dirs = qw(
     3rdparty/everest/include/everest
@@ -116,6 +117,7 @@
         && -d $source_dir
         && -d $test_source_dir
         && -d $test_header_dir
+        && -d $test_drivers_header_dir
         && -d $programs_dir;
 }
 
@@ -262,6 +264,7 @@
                        $mbedtls_header_dir,
                        $psa_header_dir,
                        $test_header_dir,
+                       $test_drivers_header_dir,
                        $source_dir,
                        @thirdparty_header_dirs,
                       );
diff --git a/tests/.gitignore b/tests/.gitignore
index d49611c..d9f4b51 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -11,4 +11,5 @@
 include/test/instrument_record_status.h
 
 src/*.o
+src/drivers/*.o
 src/libmbed*
diff --git a/tests/Makefile b/tests/Makefile
index ffa4812..511db9d 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -80,7 +80,7 @@
 $(MBEDLIBS):
 	$(MAKE) -C ../library
 
-MBEDTLS_TEST_OBJS=$(patsubst %.c,%.o,$(wildcard src/*.c))
+MBEDTLS_TEST_OBJS=$(patsubst %.c,%.o,$(wildcard src/*.c src/drivers/*.c))
 
 mbedtls_test: $(MBEDTLS_TEST_OBJS)
 
@@ -89,6 +89,10 @@
 	echo "  CC    $<"
 	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) -o $@ -c $<
 
+src/drivers/%.o : src/drivers/%.c
+	echo "  CC    $<"
+	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) -o $@ -c $<
+
 C_FILES := $(addsuffix .c,$(APPS))
 
 # Wildcard target for test code generation:
@@ -130,12 +134,13 @@
 clean:
 ifndef WINDOWS
 	rm -rf $(BINARIES) *.c *.datax TESTS
-	rm -f src/*.o src/libmbed*
+	rm -f src/*.o src/drivers/*.o src/libmbed*
 else
 	if exist *.c del /Q /F *.c
 	if exist *.exe del /Q /F *.exe
 	if exist *.datax del /Q /F *.datax
 	if exist src/*.o del /Q /F src/*.o
+	if exist src/drivers/*.o del /Q /F src/drivers/*.o
 	if exist src/libmbed* del /Q /F src/libmed*
 ifneq ($(wildcard TESTS/.*),)
 	rmdir /Q /S TESTS
diff --git a/tests/include/test/drivers/cipher.h b/tests/include/test/drivers/cipher.h
new file mode 100644
index 0000000..ef787f7
--- /dev/null
+++ b/tests/include/test/drivers/cipher.h
@@ -0,0 +1,180 @@
+/*
+ * Test driver for cipher functions
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#ifndef PSA_CRYPTO_TEST_DRIVERS_CIPHER_H
+#define PSA_CRYPTO_TEST_DRIVERS_CIPHER_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include <psa/crypto_driver_common.h>
+
+#include "mbedtls/cipher.h"
+typedef struct {
+    psa_algorithm_t alg;
+    unsigned int key_set : 1;
+    unsigned int iv_required : 1;
+    unsigned int iv_set : 1;
+    uint8_t iv_size;
+    uint8_t block_size;
+    mbedtls_cipher_context_t cipher;
+} test_transparent_cipher_operation_t;
+
+typedef struct{
+    unsigned int initialised : 1;
+    test_transparent_cipher_operation_t ctx;
+} test_opaque_cipher_operation_t;
+
+typedef struct {
+    /* If non-null, on success, copy this to the output. */
+    void *forced_output;
+    size_t forced_output_length;
+    /* If not PSA_SUCCESS, return this error code instead of processing the
+     * function call. */
+    psa_status_t forced_status;
+    /* Count the amount of times one of the cipher driver functions is called. */
+    unsigned long hits;
+} test_driver_cipher_hooks_t;
+
+#define TEST_DRIVER_CIPHER_INIT { NULL, 0, PSA_SUCCESS, 0 }
+static inline test_driver_cipher_hooks_t test_driver_cipher_hooks_init( void )
+{
+    const test_driver_cipher_hooks_t v = TEST_DRIVER_CIPHER_INIT;
+    return( v );
+}
+
+extern test_driver_cipher_hooks_t test_driver_cipher_hooks;
+
+psa_status_t test_transparent_cipher_encrypt(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *input, size_t input_length,
+    uint8_t *output, size_t output_size, size_t *output_length);
+
+psa_status_t test_transparent_cipher_decrypt(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *input, size_t input_length,
+    uint8_t *output, size_t output_size, size_t *output_length);
+
+psa_status_t test_transparent_cipher_encrypt_setup(
+    test_transparent_cipher_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg);
+
+psa_status_t test_transparent_cipher_decrypt_setup(
+    test_transparent_cipher_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg);
+
+psa_status_t test_transparent_cipher_abort(
+    test_transparent_cipher_operation_t *operation);
+
+psa_status_t test_transparent_cipher_generate_iv(
+    test_transparent_cipher_operation_t *operation,
+    uint8_t *iv,
+    size_t iv_size,
+    size_t *iv_length);
+
+psa_status_t test_transparent_cipher_set_iv(
+    test_transparent_cipher_operation_t *operation,
+    const uint8_t *iv,
+    size_t iv_length);
+
+psa_status_t test_transparent_cipher_update(
+    test_transparent_cipher_operation_t *operation,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length);
+
+psa_status_t test_transparent_cipher_finish(
+    test_transparent_cipher_operation_t *operation,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length);
+
+/*
+ * opaque versions
+ */
+psa_status_t test_opaque_cipher_encrypt(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *input, size_t input_length,
+    uint8_t *output, size_t output_size, size_t *output_length);
+
+psa_status_t test_opaque_cipher_decrypt(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *input, size_t input_length,
+    uint8_t *output, size_t output_size, size_t *output_length);
+
+psa_status_t test_opaque_cipher_encrypt_setup(
+    test_opaque_cipher_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg);
+
+psa_status_t test_opaque_cipher_decrypt_setup(
+    test_opaque_cipher_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg);
+
+psa_status_t test_opaque_cipher_abort(
+    test_opaque_cipher_operation_t *operation);
+
+psa_status_t test_opaque_cipher_generate_iv(
+    test_opaque_cipher_operation_t *operation,
+    uint8_t *iv,
+    size_t iv_size,
+    size_t *iv_length);
+
+psa_status_t test_opaque_cipher_set_iv(
+    test_opaque_cipher_operation_t *operation,
+    const uint8_t *iv,
+    size_t iv_length);
+
+psa_status_t test_opaque_cipher_update(
+    test_opaque_cipher_operation_t *operation,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length);
+
+psa_status_t test_opaque_cipher_finish(
+    test_opaque_cipher_operation_t *operation,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length);
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_TEST_DRIVERS_CIPHER_H */
diff --git a/tests/include/test/drivers/keygen.h b/tests/include/test/drivers/keygen.h
new file mode 100644
index 0000000..b72c65c
--- /dev/null
+++ b/tests/include/test/drivers/keygen.h
@@ -0,0 +1,61 @@
+/*
+ * Test driver for generating keys.
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#ifndef PSA_CRYPTO_TEST_DRIVERS_KEYGEN_H
+#define PSA_CRYPTO_TEST_DRIVERS_KEYGEN_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include <psa/crypto_driver_common.h>
+
+typedef struct {
+    /* If non-null, on success, copy this to the output. */
+    void *forced_output;
+    size_t forced_output_length;
+    /* If not PSA_SUCCESS, return this error code instead of processing the
+     * function call. */
+    psa_status_t forced_status;
+    /* Count the amount of times one of the keygen driver functions is called. */
+    unsigned long hits;
+} test_driver_keygen_hooks_t;
+
+#define TEST_DRIVER_KEYGEN_INIT { NULL, 0, PSA_ERROR_NOT_SUPPORTED, 0 }
+static inline test_driver_keygen_hooks_t test_driver_keygen_hooks_init( void )
+{
+    const test_driver_keygen_hooks_t v = TEST_DRIVER_KEYGEN_INIT;
+    return( v );
+}
+
+extern test_driver_keygen_hooks_t test_driver_keygen_hooks;
+
+psa_status_t test_transparent_generate_key(
+    const psa_key_attributes_t *attributes,
+    uint8_t *key, size_t key_size, size_t *key_length );
+
+psa_status_t test_opaque_generate_key(
+    const psa_key_attributes_t *attributes,
+    uint8_t *key, size_t key_size, size_t *key_length );
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_TEST_DRIVERS_KEYGEN_H */
diff --git a/tests/include/test/drivers/signature.h b/tests/include/test/drivers/signature.h
new file mode 100644
index 0000000..e41892e
--- /dev/null
+++ b/tests/include/test/drivers/signature.h
@@ -0,0 +1,82 @@
+/*
+ * Test driver for signature functions.
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#ifndef PSA_CRYPTO_TEST_DRIVERS_SIGNATURE_H
+#define PSA_CRYPTO_TEST_DRIVERS_SIGNATURE_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include <psa/crypto_driver_common.h>
+
+typedef struct {
+    /* If non-null, on success, copy this to the output. */
+    void *forced_output;
+    size_t forced_output_length;
+    /* If not PSA_SUCCESS, return this error code instead of processing the
+     * function call. */
+    psa_status_t forced_status;
+    /* Count the amount of times one of the keygen driver functions is called. */
+    unsigned long hits;
+} test_driver_signature_hooks_t;
+
+#define TEST_DRIVER_SIGNATURE_INIT { NULL, 0, PSA_ERROR_NOT_SUPPORTED, 0 }
+static inline test_driver_signature_hooks_t test_driver_signature_hooks_init( void )
+{
+    const test_driver_signature_hooks_t v = TEST_DRIVER_SIGNATURE_INIT;
+    return( v );
+}
+
+extern test_driver_signature_hooks_t test_driver_signature_sign_hooks;
+extern test_driver_signature_hooks_t test_driver_signature_verify_hooks;
+
+psa_status_t test_transparent_signature_sign_hash(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *hash, size_t hash_length,
+    uint8_t *signature, size_t signature_size, size_t *signature_length );
+
+psa_status_t test_opaque_signature_sign_hash(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *hash, size_t hash_length,
+    uint8_t *signature, size_t signature_size, size_t *signature_length );
+
+psa_status_t test_transparent_signature_verify_hash(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *hash, size_t hash_length,
+    const uint8_t *signature, size_t signature_length );
+
+psa_status_t test_opaque_signature_verify_hash(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *hash, size_t hash_length,
+    const uint8_t *signature, size_t signature_length );
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_TEST_DRIVERS_SIGNATURE_H */
diff --git a/tests/include/test/drivers/test_driver.h b/tests/include/test/drivers/test_driver.h
new file mode 100644
index 0000000..7ee8e5e
--- /dev/null
+++ b/tests/include/test/drivers/test_driver.h
@@ -0,0 +1,29 @@
+/*
+ * Umbrella include for all of the test driver functionality
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#ifndef PSA_CRYPTO_TEST_DRIVER_H
+#define PSA_CRYPTO_TEST_DRIVER_H
+
+#define PSA_CRYPTO_TEST_DRIVER_LIFETIME 0x7fffff
+
+#include "test/drivers/signature.h"
+#include "test/drivers/keygen.h"
+#include "test/drivers/cipher.h"
+
+#endif /* PSA_CRYPTO_TEST_DRIVER_H */
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 4fafe02..578d03e 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -1217,16 +1217,34 @@
     record_status tests/scripts/curves.pl
 }
 
+component_test_depends_curves_psa () {
+    msg "test/build: curves.pl with MBEDTLS_USE_PSA_CRYPTO defined (gcc)"
+    scripts/config.py set MBEDTLS_USE_PSA_CRYPTO
+    record_status tests/scripts/curves.pl
+}
+
 component_test_depends_hashes () {
     msg "test/build: depends-hashes.pl (gcc)" # ~ 2 min
     record_status tests/scripts/depends-hashes.pl
 }
 
+component_test_depends_hashes_psa () {
+    msg "test/build: depends-hashes.pl with MBEDTLS_USE_PSA_CRYPTO defined (gcc)"
+    scripts/config.py set MBEDTLS_USE_PSA_CRYPTO
+    record_status tests/scripts/depends-hashes.pl
+}
+
 component_test_depends_pkalgs () {
     msg "test/build: depends-pkalgs.pl (gcc)" # ~ 2 min
     record_status tests/scripts/depends-pkalgs.pl
 }
 
+component_test_depends_pkalgs_psa () {
+    msg "test/build: depends-pkalgs.pl with MBEDTLS_USE_PSA_CRYPTO defined (gcc)"
+    scripts/config.py set MBEDTLS_USE_PSA_CRYPTO
+    record_status tests/scripts/depends-pkalgs.pl
+}
+
 component_build_key_exchanges () {
     msg "test/build: key-exchanges (gcc)" # ~ 1 min
     record_status tests/scripts/key-exchanges.pl
@@ -1656,6 +1674,16 @@
     make test
 }
 
+component_test_psa_crypto_drivers () {
+    msg "build: MBEDTLS_PSA_CRYPTO_DRIVERS w/ driver hooks"
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_DRIVERS
+    # Need to define the correct symbol and include the test driver header path in order to build with the test driver
+    make CC=gcc CFLAGS="$ASAN_CFLAGS -DPSA_CRYPTO_DRIVER_TEST -I../tests/include -O2" LDFLAGS="$ASAN_CFLAGS"
+
+    msg "test: MBEDTLS_PSA_CRYPTO_DRIVERS, signature"
+    make test
+}
+
 component_test_make_shared () {
     msg "build/test: make shared" # ~ 40s
     make SHARED=1 all check
diff --git a/tests/src/drivers/cipher.c b/tests/src/drivers/cipher.c
new file mode 100644
index 0000000..fa7c6a9
--- /dev/null
+++ b/tests/src/drivers/cipher.c
@@ -0,0 +1,611 @@
+/*
+ * Test driver for cipher functions.
+ * Currently only supports multi-part operations using AES-CTR.
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_PSA_CRYPTO_DRIVERS) && defined(PSA_CRYPTO_DRIVER_TEST)
+#include "psa/crypto.h"
+#include "psa_crypto_core.h"
+#include "mbedtls/cipher.h"
+
+#include "test/drivers/cipher.h"
+
+#include "test/random.h"
+
+#include <string.h>
+
+/* Test driver implements AES-CTR only. Its default behaviour (when its return
+ * status is not overridden through the hooks) is to take care of all AES-CTR
+ * operations, and return PSA_ERROR_NOT_SUPPORTED for all others.
+ * Set test_driver_cipher_hooks.forced_status to PSA_ERROR_NOT_SUPPORTED to use
+ * fallback even for AES-CTR. */
+test_driver_cipher_hooks_t test_driver_cipher_hooks = TEST_DRIVER_CIPHER_INIT;
+
+static psa_status_t test_transparent_cipher_oneshot(
+    mbedtls_operation_t direction,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *input, size_t input_length,
+    uint8_t *output, size_t output_size, size_t *output_length)
+{
+    test_driver_cipher_hooks.hits++;
+
+    /* Test driver supports AES-CTR only, to verify operation calls. */
+    if( alg != PSA_ALG_CTR ||
+        psa_get_key_type( attributes ) != PSA_KEY_TYPE_AES )
+        return( PSA_ERROR_NOT_SUPPORTED );
+
+    /* If test driver response code is not SUCCESS, we can return early */
+    if( test_driver_cipher_hooks.forced_status != PSA_SUCCESS )
+        return( test_driver_cipher_hooks.forced_status );
+
+    /* If test driver output is overridden, we don't need to do actual crypto */
+    if( test_driver_cipher_hooks.forced_output != NULL )
+    {
+        if( output_size < test_driver_cipher_hooks.forced_output_length )
+            return( PSA_ERROR_BUFFER_TOO_SMALL );
+
+        memcpy( output,
+                test_driver_cipher_hooks.forced_output,
+                test_driver_cipher_hooks.forced_output_length );
+        *output_length = test_driver_cipher_hooks.forced_output_length;
+
+        return( test_driver_cipher_hooks.forced_status );
+    }
+
+    /* Run AES-CTR using the cipher module */
+    {
+        mbedtls_test_rnd_pseudo_info rnd_info;
+        memset( &rnd_info, 0x5A, sizeof( mbedtls_test_rnd_pseudo_info ) );
+
+        const mbedtls_cipher_info_t *cipher_info =
+            mbedtls_cipher_info_from_values( MBEDTLS_CIPHER_ID_AES,
+                                             key_length * 8,
+                                             MBEDTLS_MODE_CTR );
+        mbedtls_cipher_context_t cipher;
+        int ret = 0;
+        uint8_t temp_output_buffer[16] = {0};
+        size_t temp_output_length = 0;
+
+        if( direction == MBEDTLS_ENCRYPT )
+        {
+            /* Oneshot encrypt needs to prepend the IV to the output */
+            if( output_size < ( input_length + 16 ) )
+                return( PSA_ERROR_BUFFER_TOO_SMALL );
+        }
+        else
+        {
+            /* Oneshot decrypt has the IV prepended to the input */
+            if( output_size < ( input_length - 16 ) )
+                return( PSA_ERROR_BUFFER_TOO_SMALL );
+        }
+
+        if( cipher_info == NULL )
+            return( PSA_ERROR_NOT_SUPPORTED );
+
+        mbedtls_cipher_init( &cipher );
+        ret = mbedtls_cipher_setup( &cipher, cipher_info );
+        if( ret != 0 )
+            goto exit;
+
+        ret = mbedtls_cipher_setkey( &cipher,
+                                     key,
+                                     key_length * 8, direction );
+        if( ret != 0 )
+            goto exit;
+
+        if( direction == MBEDTLS_ENCRYPT )
+        {
+            mbedtls_test_rnd_pseudo_info rnd_info;
+            memset( &rnd_info, 0x5A, sizeof( mbedtls_test_rnd_pseudo_info ) );
+
+            ret = mbedtls_test_rnd_pseudo_rand( &rnd_info,
+                                                temp_output_buffer,
+                                                16 );
+            if( ret != 0 )
+                goto exit;
+
+            ret = mbedtls_cipher_set_iv( &cipher, temp_output_buffer, 16 );
+        }
+        else
+            ret = mbedtls_cipher_set_iv( &cipher, input, 16 );
+
+        if( ret != 0 )
+            goto exit;
+
+        if( direction == MBEDTLS_ENCRYPT )
+        {
+            ret = mbedtls_cipher_update( &cipher,
+                                         input, input_length,
+                                         &output[16], output_length );
+            if( ret == 0 )
+            {
+                memcpy( output, temp_output_buffer, 16 );
+                *output_length += 16;
+            }
+        }
+        else
+            ret = mbedtls_cipher_update( &cipher,
+                                         &input[16], input_length - 16,
+                                         output, output_length );
+
+        if( ret != 0 )
+            goto exit;
+
+        ret = mbedtls_cipher_finish( &cipher,
+                                     temp_output_buffer,
+                                     &temp_output_length );
+
+exit:
+        if( ret != 0 )
+        {
+            *output_length = 0;
+            memset(output, 0, output_size);
+        }
+
+        mbedtls_cipher_free( &cipher );
+        return( mbedtls_to_psa_error( ret ) );
+    }
+}
+
+psa_status_t test_transparent_cipher_encrypt(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *input, size_t input_length,
+    uint8_t *output, size_t output_size, size_t *output_length)
+{
+    return (
+        test_transparent_cipher_oneshot(
+            MBEDTLS_ENCRYPT,
+            attributes,
+            key, key_length,
+            alg,
+            input, input_length,
+            output, output_size, output_length) );
+}
+
+psa_status_t test_transparent_cipher_decrypt(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *input, size_t input_length,
+    uint8_t *output, size_t output_size, size_t *output_length)
+{
+    return (
+        test_transparent_cipher_oneshot(
+            MBEDTLS_DECRYPT,
+            attributes,
+            key, key_length,
+            alg,
+            input, input_length,
+            output, output_size, output_length) );
+}
+
+static psa_status_t test_transparent_cipher_setup(
+    mbedtls_operation_t direction,
+    test_transparent_cipher_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg)
+{
+    const mbedtls_cipher_info_t *cipher_info = NULL;
+    int ret = 0;
+
+    test_driver_cipher_hooks.hits++;
+
+    if( operation->alg != 0 )
+        return( PSA_ERROR_BAD_STATE );
+
+    /* Wiping the entire struct here, instead of member-by-member. This is useful
+     * for the test suite, since it gives a chance of catching memory corruption
+     * errors should the core not have allocated (enough) memory for our context
+     * struct. */
+    memset( operation, 0, sizeof( *operation ) );
+
+    /* Allow overriding return value for testing purposes */
+    if( test_driver_cipher_hooks.forced_status != PSA_SUCCESS )
+        return( test_driver_cipher_hooks.forced_status );
+
+    /* Test driver supports AES-CTR only, to verify operation calls. */
+    if( alg != PSA_ALG_CTR ||
+        psa_get_key_type( attributes ) != PSA_KEY_TYPE_AES )
+        return( PSA_ERROR_NOT_SUPPORTED );
+
+    operation->alg = alg;
+    operation->iv_size = 16;
+
+    cipher_info = mbedtls_cipher_info_from_values( MBEDTLS_CIPHER_ID_AES,
+                                                   key_length * 8,
+                                                   MBEDTLS_MODE_CTR );
+    if( cipher_info == NULL )
+        return( PSA_ERROR_NOT_SUPPORTED );
+
+    mbedtls_cipher_init( &operation->cipher );
+    ret = mbedtls_cipher_setup( &operation->cipher, cipher_info );
+    if( ret != 0 ) {
+        mbedtls_cipher_free( &operation->cipher );
+        return( mbedtls_to_psa_error( ret ) );
+    }
+
+    ret = mbedtls_cipher_setkey( &operation->cipher,
+                                 key,
+                                 key_length * 8, direction );
+    if( ret != 0 ) {
+        mbedtls_cipher_free( &operation->cipher );
+        return( mbedtls_to_psa_error( ret ) );
+    }
+
+    operation->iv_set = 0;
+    operation->iv_required = 1;
+    operation->key_set = 1;
+
+    return( test_driver_cipher_hooks.forced_status );
+}
+
+psa_status_t test_transparent_cipher_encrypt_setup(
+    test_transparent_cipher_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg)
+{
+    return ( test_transparent_cipher_setup( MBEDTLS_ENCRYPT,
+                                            operation,
+                                            attributes,
+                                            key,
+                                            key_length,
+                                            alg ) );
+}
+
+psa_status_t test_transparent_cipher_decrypt_setup(
+    test_transparent_cipher_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg)
+{
+    return ( test_transparent_cipher_setup( MBEDTLS_DECRYPT,
+                                            operation,
+                                            attributes,
+                                            key,
+                                            key_length,
+                                            alg ) );
+}
+
+psa_status_t test_transparent_cipher_abort(
+    test_transparent_cipher_operation_t *operation)
+{
+    test_driver_cipher_hooks.hits++;
+
+    if( operation->alg == 0 )
+        return( PSA_SUCCESS );
+    if( operation->alg != PSA_ALG_CTR )
+        return( PSA_ERROR_BAD_STATE );
+
+    mbedtls_cipher_free( &operation->cipher );
+
+    /* Wiping the entire struct here, instead of member-by-member. This is useful
+     * for the test suite, since it gives a chance of catching memory corruption
+     * errors should the core not have allocated (enough) memory for our context
+     * struct. */
+    memset( operation, 0, sizeof( *operation ) );
+
+    return( PSA_SUCCESS );
+}
+
+psa_status_t test_transparent_cipher_generate_iv(
+    test_transparent_cipher_operation_t *operation,
+    uint8_t *iv,
+    size_t iv_size,
+    size_t *iv_length)
+{
+    psa_status_t status;
+    mbedtls_test_rnd_pseudo_info rnd_info;
+    memset( &rnd_info, 0x5A, sizeof( mbedtls_test_rnd_pseudo_info ) );
+
+    test_driver_cipher_hooks.hits++;
+
+    if( test_driver_cipher_hooks.forced_status != PSA_SUCCESS )
+        return( test_driver_cipher_hooks.forced_status );
+
+    if( operation->alg != PSA_ALG_CTR )
+        return( PSA_ERROR_BAD_STATE );
+
+    if( operation->iv_set || ! operation->iv_required )
+        return( PSA_ERROR_BAD_STATE );
+
+    if( iv_size < operation->iv_size )
+        return( PSA_ERROR_BUFFER_TOO_SMALL );
+
+    status = mbedtls_to_psa_error(
+        mbedtls_test_rnd_pseudo_rand( &rnd_info,
+                                      iv,
+                                      operation->iv_size ) );
+    if( status != PSA_SUCCESS )
+        return( status );
+
+    *iv_length = operation->iv_size;
+    status = test_transparent_cipher_set_iv( operation, iv, *iv_length );
+
+    return( status );
+}
+
+psa_status_t test_transparent_cipher_set_iv(
+    test_transparent_cipher_operation_t *operation,
+    const uint8_t *iv,
+    size_t iv_length)
+{
+    psa_status_t status;
+
+    test_driver_cipher_hooks.hits++;
+
+    if( test_driver_cipher_hooks.forced_status != PSA_SUCCESS )
+        return( test_driver_cipher_hooks.forced_status );
+
+    if( operation->alg != PSA_ALG_CTR )
+        return( PSA_ERROR_BAD_STATE );
+
+    if( operation->iv_set || ! operation->iv_required )
+        return( PSA_ERROR_BAD_STATE );
+
+    if( iv_length != operation->iv_size )
+        return( PSA_ERROR_INVALID_ARGUMENT );
+
+    status = mbedtls_to_psa_error(
+        mbedtls_cipher_set_iv( &operation->cipher, iv, iv_length ) );
+
+    if( status == PSA_SUCCESS )
+        operation->iv_set = 1;
+
+    return( status );
+}
+
+psa_status_t test_transparent_cipher_update(
+    test_transparent_cipher_operation_t *operation,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length)
+{
+    psa_status_t status;
+
+    test_driver_cipher_hooks.hits++;
+
+    if( test_driver_cipher_hooks.forced_status != PSA_SUCCESS )
+        return( test_driver_cipher_hooks.forced_status );
+
+    if( operation->alg != PSA_ALG_CTR )
+        return( PSA_ERROR_BAD_STATE );
+
+    /* CTR is a stream cipher, so data in and out are always the same size */
+    if( output_size < input_length )
+        return( PSA_ERROR_BUFFER_TOO_SMALL );
+
+    status = mbedtls_to_psa_error(
+        mbedtls_cipher_update( &operation->cipher, input,
+                               input_length, output, output_length ) );
+
+    if( status != PSA_SUCCESS )
+        return status;
+
+    if( test_driver_cipher_hooks.forced_output != NULL )
+    {
+        if( output_size < test_driver_cipher_hooks.forced_output_length )
+            return PSA_ERROR_BUFFER_TOO_SMALL;
+
+        memcpy( output,
+                test_driver_cipher_hooks.forced_output,
+                test_driver_cipher_hooks.forced_output_length );
+        *output_length = test_driver_cipher_hooks.forced_output_length;
+    }
+
+    return( test_driver_cipher_hooks.forced_status );
+}
+
+psa_status_t test_transparent_cipher_finish(
+    test_transparent_cipher_operation_t *operation,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length)
+{
+    psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+    uint8_t temp_output_buffer[MBEDTLS_MAX_BLOCK_LENGTH];
+
+    test_driver_cipher_hooks.hits++;
+
+    if( test_driver_cipher_hooks.forced_status != PSA_SUCCESS )
+        return( test_driver_cipher_hooks.forced_status );
+
+    if( operation->alg != PSA_ALG_CTR )
+        return( PSA_ERROR_BAD_STATE );
+
+    if( ! operation->key_set )
+        return( PSA_ERROR_BAD_STATE );
+
+    if( operation->iv_required && ! operation->iv_set )
+        return( PSA_ERROR_BAD_STATE );
+
+    status = mbedtls_to_psa_error(
+        mbedtls_cipher_finish( &operation->cipher,
+                               temp_output_buffer,
+                               output_length ) );
+
+    mbedtls_cipher_free( &operation->cipher );
+
+    if( status != PSA_SUCCESS )
+        return( status );
+
+    if( *output_length == 0 )
+        ; /* Nothing to copy. Note that output may be NULL in this case. */
+    else if( output_size >= *output_length )
+        memcpy( output, temp_output_buffer, *output_length );
+    else
+        return( PSA_ERROR_BUFFER_TOO_SMALL );
+
+
+    if( test_driver_cipher_hooks.forced_output != NULL )
+    {
+        if( output_size < test_driver_cipher_hooks.forced_output_length )
+            return PSA_ERROR_BUFFER_TOO_SMALL;
+
+        memcpy( output,
+                test_driver_cipher_hooks.forced_output,
+                test_driver_cipher_hooks.forced_output_length );
+        *output_length = test_driver_cipher_hooks.forced_output_length;
+    }
+
+    return( test_driver_cipher_hooks.forced_status );
+}
+
+/*
+ * opaque versions, to do
+ */
+psa_status_t test_opaque_cipher_encrypt(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *input, size_t input_length,
+    uint8_t *output, size_t output_size, size_t *output_length)
+{
+    (void) attributes;
+    (void) key;
+    (void) key_length;
+    (void) alg;
+    (void) input;
+    (void) input_length;
+    (void) output;
+    (void) output_size;
+    (void) output_length;
+    return( PSA_ERROR_NOT_SUPPORTED );
+}
+
+psa_status_t test_opaque_cipher_decrypt(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *input, size_t input_length,
+    uint8_t *output, size_t output_size, size_t *output_length)
+{
+    (void) attributes;
+    (void) key;
+    (void) key_length;
+    (void) alg;
+    (void) input;
+    (void) input_length;
+    (void) output;
+    (void) output_size;
+    (void) output_length;
+    return( PSA_ERROR_NOT_SUPPORTED );
+}
+
+psa_status_t test_opaque_cipher_encrypt_setup(
+    test_opaque_cipher_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg)
+{
+    (void) operation;
+    (void) attributes;
+    (void) key;
+    (void) key_length;
+    (void) alg;
+    return( PSA_ERROR_NOT_SUPPORTED );
+}
+
+psa_status_t test_opaque_cipher_decrypt_setup(
+    test_opaque_cipher_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg)
+{
+    (void) operation;
+    (void) attributes;
+    (void) key;
+    (void) key_length;
+    (void) alg;
+    return( PSA_ERROR_NOT_SUPPORTED );
+}
+
+psa_status_t test_opaque_cipher_abort(
+    test_opaque_cipher_operation_t *operation)
+{
+    (void) operation;
+    return( PSA_ERROR_NOT_SUPPORTED );
+}
+
+psa_status_t test_opaque_cipher_generate_iv(
+    test_opaque_cipher_operation_t *operation,
+    uint8_t *iv,
+    size_t iv_size,
+    size_t *iv_length)
+{
+    (void) operation;
+    (void) iv;
+    (void) iv_size;
+    (void) iv_length;
+    return( PSA_ERROR_NOT_SUPPORTED );
+}
+
+psa_status_t test_opaque_cipher_set_iv(
+    test_opaque_cipher_operation_t *operation,
+    const uint8_t *iv,
+    size_t iv_length)
+{
+    (void) operation;
+    (void) iv;
+    (void) iv_length;
+    return( PSA_ERROR_NOT_SUPPORTED );
+}
+
+psa_status_t test_opaque_cipher_update(
+    test_opaque_cipher_operation_t *operation,
+    const uint8_t *input,
+    size_t input_length,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length)
+{
+    (void) operation;
+    (void) input;
+    (void) input_length;
+    (void) output;
+    (void) output_size;
+    (void) output_length;
+    return( PSA_ERROR_NOT_SUPPORTED );
+}
+
+psa_status_t test_opaque_cipher_finish(
+    test_opaque_cipher_operation_t *operation,
+    uint8_t *output,
+    size_t output_size,
+    size_t *output_length)
+{
+    (void) operation;
+    (void) output;
+    (void) output_size;
+    (void) output_length;
+    return( PSA_ERROR_NOT_SUPPORTED );
+}
+#endif /* MBEDTLS_PSA_CRYPTO_DRIVERS && PSA_CRYPTO_DRIVER_TEST */
diff --git a/tests/src/drivers/keygen.c b/tests/src/drivers/keygen.c
new file mode 100644
index 0000000..f15a4bc
--- /dev/null
+++ b/tests/src/drivers/keygen.c
@@ -0,0 +1,125 @@
+/*
+ * Test driver for generating keys.
+ * Currently only supports generating ECC keys.
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_PSA_CRYPTO_DRIVERS) && defined(PSA_CRYPTO_DRIVER_TEST)
+#include "psa/crypto.h"
+#include "psa_crypto_core.h"
+#include "mbedtls/ecp.h"
+#include "mbedtls/error.h"
+
+#include "test/drivers/keygen.h"
+
+#include "test/random.h"
+
+#include <string.h>
+
+test_driver_keygen_hooks_t test_driver_keygen_hooks = TEST_DRIVER_KEYGEN_INIT;
+
+psa_status_t test_transparent_generate_key(
+    const psa_key_attributes_t *attributes,
+    uint8_t *key, size_t key_size, size_t *key_length )
+{
+    ++test_driver_keygen_hooks.hits;
+
+    if( test_driver_keygen_hooks.forced_status != PSA_SUCCESS )
+        return( test_driver_keygen_hooks.forced_status );
+
+    if( test_driver_keygen_hooks.forced_output != NULL )
+    {
+        if( test_driver_keygen_hooks.forced_output_length > key_size )
+            return( PSA_ERROR_BUFFER_TOO_SMALL );
+        memcpy( key, test_driver_keygen_hooks.forced_output,
+                test_driver_keygen_hooks.forced_output_length );
+        *key_length = test_driver_keygen_hooks.forced_output_length;
+        return( PSA_SUCCESS );
+    }
+
+    /* Copied from psa_crypto.c */
+#if defined(MBEDTLS_ECP_C)
+    if ( PSA_KEY_TYPE_IS_ECC( psa_get_key_type( attributes ) )
+         && PSA_KEY_TYPE_IS_KEY_PAIR( psa_get_key_type( attributes ) ) )
+    {
+        psa_ecc_family_t curve = PSA_KEY_TYPE_ECC_GET_FAMILY( psa_get_key_type( attributes ) );
+        mbedtls_ecp_group_id grp_id =
+            mbedtls_ecc_group_of_psa( curve, PSA_BITS_TO_BYTES( psa_get_key_bits( attributes ) ) );
+        const mbedtls_ecp_curve_info *curve_info =
+            mbedtls_ecp_curve_info_from_grp_id( grp_id );
+        mbedtls_ecp_keypair ecp;
+        mbedtls_test_rnd_pseudo_info rnd_info;
+        memset( &rnd_info, 0x5A, sizeof( mbedtls_test_rnd_pseudo_info ) );
+
+        int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+        if( attributes->domain_parameters_size != 0 )
+            return( PSA_ERROR_NOT_SUPPORTED );
+        if( grp_id == MBEDTLS_ECP_DP_NONE || curve_info == NULL )
+            return( PSA_ERROR_NOT_SUPPORTED );
+        if( curve_info->bit_size != psa_get_key_bits( attributes ) )
+            return( PSA_ERROR_INVALID_ARGUMENT );
+        mbedtls_ecp_keypair_init( &ecp );
+        ret = mbedtls_ecp_gen_key( grp_id, &ecp,
+                                   &mbedtls_test_rnd_pseudo_rand,
+                                   &rnd_info );
+        if( ret != 0 )
+        {
+            mbedtls_ecp_keypair_free( &ecp );
+            return( mbedtls_to_psa_error( ret ) );
+        }
+
+        /* Make sure to use export representation */
+        size_t bytes = PSA_BITS_TO_BYTES( psa_get_key_bits( attributes ) );
+        if( key_size < bytes )
+        {
+            mbedtls_ecp_keypair_free( &ecp );
+            return( PSA_ERROR_BUFFER_TOO_SMALL );
+        }
+        psa_status_t status = mbedtls_to_psa_error(
+            mbedtls_mpi_write_binary( &ecp.d, key, bytes ) );
+
+        if( status == PSA_SUCCESS )
+        {
+            *key_length = bytes;
+        }
+
+        mbedtls_ecp_keypair_free( &ecp );
+        return( status );
+    }
+    else
+#endif /* MBEDTLS_ECP_C */
+    return( PSA_ERROR_NOT_SUPPORTED );
+}
+
+psa_status_t test_opaque_generate_key(
+    const psa_key_attributes_t *attributes,
+    uint8_t *key, size_t key_size, size_t *key_length )
+{
+    (void) attributes;
+    (void) key;
+    (void) key_size;
+    (void) key_length;
+    return( PSA_ERROR_NOT_SUPPORTED );
+}
+
+#endif /* MBEDTLS_PSA_CRYPTO_DRIVERS && PSA_CRYPTO_DRIVER_TEST */
diff --git a/tests/src/drivers/signature.c b/tests/src/drivers/signature.c
new file mode 100644
index 0000000..028d24a
--- /dev/null
+++ b/tests/src/drivers/signature.c
@@ -0,0 +1,289 @@
+/*
+ * Test driver for signature functions.
+ * Currently supports signing and verifying precalculated hashes, using
+ * only deterministic ECDSA on curves secp256r1, secp384r1 and secp521r1.
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_PSA_CRYPTO_DRIVERS) && defined(PSA_CRYPTO_DRIVER_TEST)
+#include "psa/crypto.h"
+#include "psa_crypto_core.h"
+#include "mbedtls/ecp.h"
+
+#include "test/drivers/signature.h"
+
+#include "mbedtls/md.h"
+#include "mbedtls/ecdsa.h"
+
+#include "test/random.h"
+
+#include <string.h>
+
+test_driver_signature_hooks_t test_driver_signature_sign_hooks = TEST_DRIVER_SIGNATURE_INIT;
+test_driver_signature_hooks_t test_driver_signature_verify_hooks = TEST_DRIVER_SIGNATURE_INIT;
+
+psa_status_t test_transparent_signature_sign_hash(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *hash, size_t hash_length,
+    uint8_t *signature, size_t signature_size, size_t *signature_length )
+{
+    ++test_driver_signature_sign_hooks.hits;
+
+    if( test_driver_signature_sign_hooks.forced_status != PSA_SUCCESS )
+        return( test_driver_signature_sign_hooks.forced_status );
+
+    if( test_driver_signature_sign_hooks.forced_output != NULL )
+    {
+        if( test_driver_signature_sign_hooks.forced_output_length > signature_size )
+            return( PSA_ERROR_BUFFER_TOO_SMALL );
+        memcpy( signature, test_driver_signature_sign_hooks.forced_output,
+                test_driver_signature_sign_hooks.forced_output_length );
+        *signature_length = test_driver_signature_sign_hooks.forced_output_length;
+        return( PSA_SUCCESS );
+    }
+
+    psa_status_t status = PSA_ERROR_NOT_SUPPORTED;
+
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECDSA_DETERMINISTIC) && \
+    defined(MBEDTLS_SHA256_C)
+    if( alg != PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ) )
+        return( PSA_ERROR_NOT_SUPPORTED );
+    mbedtls_ecp_group_id grp_id;
+    switch( psa_get_key_type( attributes ) )
+    {
+        case PSA_ECC_CURVE_SECP_R1:
+            switch( psa_get_key_bits( attributes ) )
+            {
+                case 256:
+                    grp_id = MBEDTLS_ECP_DP_SECP256R1;
+                    break;
+                case 384:
+                    grp_id = MBEDTLS_ECP_DP_SECP384R1;
+                    break;
+                case 521:
+                    grp_id = MBEDTLS_ECP_DP_SECP521R1;
+                    break;
+                default:
+                    return( PSA_ERROR_NOT_SUPPORTED );
+            }
+            break;
+        default:
+            return( PSA_ERROR_NOT_SUPPORTED );
+    }
+
+    /* Beyond this point, the driver is actually doing the work of
+     * calculating the signature. */
+
+    status = PSA_ERROR_GENERIC_ERROR;
+    int ret = 0;
+    mbedtls_mpi r, s;
+    mbedtls_mpi_init( &r );
+    mbedtls_mpi_init( &s );
+    mbedtls_ecp_keypair ecp;
+    mbedtls_ecp_keypair_init( &ecp );
+    size_t curve_bytes = PSA_BITS_TO_BYTES( ecp.grp.pbits );
+
+    MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ecp.grp, grp_id ) );
+    MBEDTLS_MPI_CHK( mbedtls_ecp_point_read_binary( &ecp.grp, &ecp.Q,
+                                                    key, key_length ) );
+
+    /* Code adapted from psa_ecdsa_sign() in psa_crypto.c. */
+    mbedtls_md_type_t md_alg = MBEDTLS_MD_SHA256;
+    if( signature_size < 2 * curve_bytes )
+    {
+        status = PSA_ERROR_BUFFER_TOO_SMALL;
+        goto cleanup;
+    }
+    MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign_det( &ecp.grp, &r, &s, &ecp.d,
+                                  hash, hash_length, md_alg ) );
+    MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &r,
+                                               signature,
+                                               curve_bytes ) );
+    MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &s,
+                                               signature + curve_bytes,
+                                               curve_bytes ) );
+cleanup:
+    status = mbedtls_to_psa_error( ret );
+    mbedtls_mpi_free( &r );
+    mbedtls_mpi_free( &s );
+    mbedtls_ecp_keypair_free( &ecp );
+    if( status == PSA_SUCCESS )
+        *signature_length = 2 * curve_bytes;
+#else /* defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECDSA_DETERMINISTIC) && \
+         defined(MBEDTLS_SHA256_C) */
+    (void) attributes;
+    (void) key;
+    (void) key_length;
+    (void) alg;
+    (void) hash;
+    (void) hash_length;
+#endif /* defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECDSA_DETERMINISTIC) && \
+          defined(MBEDTLS_SHA256_C) */
+
+    return( status );
+}
+
+psa_status_t test_opaque_signature_sign_hash(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *hash, size_t hash_length,
+    uint8_t *signature, size_t signature_size, size_t *signature_length )
+{
+    (void) attributes;
+    (void) key;
+    (void) key_length;
+    (void) alg;
+    (void) hash;
+    (void) hash_length;
+    (void) signature;
+    (void) signature_size;
+    (void) signature_length;
+    return( PSA_ERROR_NOT_SUPPORTED );
+}
+
+psa_status_t test_transparent_signature_verify_hash(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *hash, size_t hash_length,
+    const uint8_t *signature, size_t signature_length )
+{
+    ++test_driver_signature_verify_hooks.hits;
+
+    if( test_driver_signature_verify_hooks.forced_status != PSA_SUCCESS )
+        return( test_driver_signature_verify_hooks.forced_status );
+
+    psa_status_t status = PSA_ERROR_NOT_SUPPORTED;
+
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECDSA_DETERMINISTIC) && \
+    defined(MBEDTLS_SHA256_C)
+    if( alg != PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ) )
+        return( PSA_ERROR_NOT_SUPPORTED );
+    mbedtls_ecp_group_id grp_id;
+    switch( psa_get_key_type( attributes ) )
+    {
+        case PSA_ECC_CURVE_SECP_R1:
+            switch( psa_get_key_bits( attributes ) )
+            {
+                case 256:
+                    grp_id = MBEDTLS_ECP_DP_SECP256R1;
+                    break;
+                case 384:
+                    grp_id = MBEDTLS_ECP_DP_SECP384R1;
+                    break;
+                case 521:
+                    grp_id = MBEDTLS_ECP_DP_SECP521R1;
+                    break;
+                default:
+                    return( PSA_ERROR_NOT_SUPPORTED );
+            }
+            break;
+        default:
+            return( PSA_ERROR_NOT_SUPPORTED );
+    }
+
+    /* Beyond this point, the driver is actually doing the work of
+     * calculating the signature. */
+
+    status = PSA_ERROR_GENERIC_ERROR;
+    int ret = 0;
+    mbedtls_mpi r, s;
+    mbedtls_mpi_init( &r );
+    mbedtls_mpi_init( &s );
+    mbedtls_ecp_keypair ecp;
+    mbedtls_ecp_keypair_init( &ecp );
+    mbedtls_test_rnd_pseudo_info rnd_info;
+    memset( &rnd_info, 0x5A, sizeof( mbedtls_test_rnd_pseudo_info ) );
+    size_t curve_bytes = PSA_BITS_TO_BYTES( ecp.grp.pbits );
+
+    MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ecp.grp, grp_id ) );
+
+    /* Code adapted from psa_ecdsa_verify() in psa_crypto.c. */
+    if( signature_length < 2 * curve_bytes )
+    {
+        status = PSA_ERROR_BUFFER_TOO_SMALL;
+        goto cleanup;
+    }
+
+    MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &r,
+                                              signature,
+                                              curve_bytes ) );
+    MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &s,
+                                              signature + curve_bytes,
+                                              curve_bytes ) );
+
+    if( PSA_KEY_TYPE_IS_PUBLIC_KEY( psa_get_key_type( attributes ) ) )
+        MBEDTLS_MPI_CHK( mbedtls_ecp_point_read_binary( &ecp.grp, &ecp.Q,
+                                                    key, key_length ) );
+    else
+    {
+        MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ecp.d, key, key_length ) );
+        MBEDTLS_MPI_CHK(
+            mbedtls_ecp_mul( &ecp.grp, &ecp.Q, &ecp.d, &ecp.grp.G,
+                             &mbedtls_test_rnd_pseudo_rand,
+                             &rnd_info ) );
+    }
+
+    MBEDTLS_MPI_CHK( mbedtls_ecdsa_verify( &ecp.grp, hash, hash_length,
+                                &ecp.Q, &r, &s ) );
+cleanup:
+    status = mbedtls_to_psa_error( ret );
+    mbedtls_mpi_free( &r );
+    mbedtls_mpi_free( &s );
+    mbedtls_ecp_keypair_free( &ecp );
+#else /* defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECDSA_DETERMINISTIC) && \
+         defined(MBEDTLS_SHA256_C) */
+    (void) attributes;
+    (void) key;
+    (void) key_length;
+    (void) alg;
+    (void) hash;
+    (void) hash_length;
+#endif /* defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECDSA_DETERMINISTIC) && \
+          defined(MBEDTLS_SHA256_C) */
+
+    return( status );
+}
+
+psa_status_t test_opaque_signature_verify_hash(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key, size_t key_length,
+    psa_algorithm_t alg,
+    const uint8_t *hash, size_t hash_length,
+    const uint8_t *signature, size_t signature_length )
+{
+    (void) attributes;
+    (void) key;
+    (void) key_length;
+    (void) alg;
+    (void) hash;
+    (void) hash_length;
+    (void) signature;
+    (void) signature_length;
+    return( PSA_ERROR_NOT_SUPPORTED );
+}
+
+#endif /* MBEDTLS_PSA_CRYPTO_DRIVERS && PSA_CRYPTO_DRIVER_TEST */
diff --git a/tests/suites/helpers.function b/tests/suites/helpers.function
index 7425a35..ec43d13 100644
--- a/tests/suites/helpers.function
+++ b/tests/suites/helpers.function
@@ -407,6 +407,12 @@
 
 void test_fail( const char *test, int line_no, const char* filename )
 {
+    if( test_info.result == TEST_RESULT_FAILED )
+    {
+        /* We've already recorded the test as having failed. Don't
+         * overwrite any previous information about the failure. */
+        return;
+    }
     test_info.result = TEST_RESULT_FAILED;
     test_info.test = test;
     test_info.line_no = line_no;
diff --git a/tests/suites/test_suite_mpi.function b/tests/suites/test_suite_mpi.function
index e54aaff..2b2daf6 100644
--- a/tests/suites/test_suite_mpi.function
+++ b/tests/suites/test_suite_mpi.function
@@ -596,7 +596,7 @@
                             int size_Y, char * input_Y,
                             int input_ret, int input_err )
 {
-    unsigned ret;
+    unsigned ret = -1;
     unsigned input_uret = input_ret;
     mbedtls_mpi X, Y;
     mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y );
diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function
index 43b4914..c6041b2 100644
--- a/tests/suites/test_suite_pk.function
+++ b/tests/suites/test_suite_pk.function
@@ -775,8 +775,8 @@
     TEST_ASSERT( mbedtls_ecp_point_read_binary( &eckey->grp, &eckey->Q,
                                         key->x, key->len ) == 0 );
 
-    // MBEDTLS_MD_SHA1 is a dummy - it is ignored, but has to be other than MBEDTLS_MD_NONE.
-    TEST_ASSERT( mbedtls_pk_verify( &pk, MBEDTLS_MD_SHA1,
+    // MBEDTLS_MD_NONE is used since it will be ignored.
+    TEST_ASSERT( mbedtls_pk_verify( &pk, MBEDTLS_MD_NONE,
                             hash->x, hash->len, sig->x, sig->len ) == ret );
 
 exit:
diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data
index ae8c081..2c6924a 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -366,7 +366,11 @@
 depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C
 import_rsa_made_up:PSA_VENDOR_RSA_MAX_KEY_BITS+8:0:PSA_ERROR_NOT_SUPPORTED
 
-PSA key policy: AES
+PSA key policy: AES ECB
+depends_on:MBEDTLS_AES_C
+check_key_policy:PSA_KEY_TYPE_AES:128:PSA_KEY_USAGE_ENCRYPT:PSA_ALG_ECB_NO_PADDING
+
+PSA key policy: AES CBC
 depends_on:MBEDTLS_AES_C
 check_key_policy:PSA_KEY_TYPE_AES:128:PSA_KEY_USAGE_ENCRYPT:PSA_ALG_CBC_NO_PADDING
 
@@ -1150,6 +1154,18 @@
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC
 cipher_bad_order:
 
+PSA symmetric encrypt: AES-ECB, 0 bytes, good
+depends_on:MBEDTLS_AES_C
+cipher_encrypt:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"":"":"":PSA_SUCCESS
+
+PSA symmetric encrypt: AES-ECB, 16 bytes, good
+depends_on:MBEDTLS_AES_C
+cipher_encrypt:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"":"6bc1bee22e409f96e93d7e117393172a":"3ad77bb40d7a3660a89ecaf32466ef97":PSA_SUCCESS
+
+PSA symmetric encrypt: AES-ECB, 32 bytes, good
+depends_on:MBEDTLS_AES_C
+cipher_encrypt:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"":"6bc1bee22e409f96e93d7e117393172a3ad77bb40d7a3660a89ecaf32466ef97":"3ad77bb40d7a3660a89ecaf32466ef972249a2638c6f1c755a84f9681a9f08c1":PSA_SUCCESS
+
 PSA symmetric encrypt: AES-CBC-nopad, 16 bytes, good
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC
 cipher_encrypt:PSA_ALG_CBC_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":"a076ec9dfbe47d52afc357336f20743b":PSA_SUCCESS
@@ -1162,6 +1178,10 @@
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC
 cipher_encrypt:PSA_ALG_CBC_PKCS7:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e11739317":"6279b49d7f7a8dd87b685175d4276e24":PSA_SUCCESS
 
+PSA symmetric encrypt: AES-ECB, input too short (15 bytes)
+depends_on:MBEDTLS_AES_C
+cipher_encrypt:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"":"6bc1bee22e409f96e93d7e11739317":"":PSA_ERROR_INVALID_ARGUMENT
+
 PSA symmetric encrypt: AES-CBC-nopad, input too short
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC
 cipher_encrypt:PSA_ALG_CBC_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee223":"6bc1bee223":PSA_ERROR_INVALID_ARGUMENT
@@ -1186,6 +1206,26 @@
 depends_on:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC
 cipher_encrypt:PSA_ALG_CBC_NO_PADDING:PSA_KEY_TYPE_DES:"01020407080b0d0ec1c2c4c7c8cbcdce31323437383b3d3e":"2a2a2a2a2a2a2a2a":"eda4011239bc3ac9":"817ca7d69b80d86a":PSA_SUCCESS
 
+PSA symmetric encrypt: 2-key 3DES-ECB, 8 bytes, good
+depends_on:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC
+cipher_encrypt:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_DES:"01020407080b0d0ec1c2c4c7c8cbcdce":"":"c78e2b38139610e3":"5d0652429c5b0ac7":PSA_SUCCESS
+
+PSA symmetric encrypt: 3-key 3DES-ECB, 8 bytes, good
+depends_on:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC
+cipher_encrypt:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_DES:"01020407080b0d0ec1c2c4c7c8cbcdce31323437383b3d3e":"":"c78e2b38139610e3":"817ca7d69b80d86a":PSA_SUCCESS
+
+PSA symmetric decrypt: AES-ECB, 0 bytes, good
+depends_on:MBEDTLS_AES_C
+cipher_decrypt:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"":"":"":PSA_SUCCESS
+
+PSA symmetric decrypt: AES-ECB, 16 bytes, good
+depends_on:MBEDTLS_AES_C
+cipher_decrypt:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"":"396ee84fb75fdbb5c2b13c7fe5a654aa":"63cecc46a382414d5fa7d2b79387437f":PSA_SUCCESS
+
+PSA symmetric decrypt: AES-ECB, 32 bytes, good
+depends_on:MBEDTLS_AES_C
+cipher_decrypt:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"":"3ad77bb40d7a3660a89ecaf32466ef972249a2638c6f1c755a84f9681a9f08c1":"6bc1bee22e409f96e93d7e117393172a3ad77bb40d7a3660a89ecaf32466ef97":PSA_SUCCESS
+
 PSA symmetric decrypt: AES-CBC-nopad, 16 bytes, good
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC
 cipher_decrypt:PSA_ALG_CBC_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"396ee84fb75fdbb5c2b13c7fe5a654aa":"49e4e66c89a86b67758df89db9ad6955":PSA_SUCCESS
@@ -1206,6 +1246,10 @@
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_MODE_CTR
 cipher_decrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"396ee84fb75fdbb5c2b13c7fe5a654aa":"dd3b5e5319b7591daab1e1a92687feb2":PSA_SUCCESS
 
+PSA symmetric decrypt: AES-ECB, input too short (15 bytes)
+depends_on:MBEDTLS_AES_C
+cipher_decrypt:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"":"396ee84fb75fdbb5c2b13c7fe5a654":"63cecc46a382414d5fa7d2b7938743":PSA_ERROR_INVALID_ARGUMENT
+
 PSA symmetric decrypt: AES-CBC-nopad, input too short (5 bytes)
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC
 cipher_decrypt:PSA_ALG_CBC_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee223":"6bc1bee223":PSA_ERROR_BAD_STATE
@@ -1222,6 +1266,18 @@
 depends_on:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC
 cipher_decrypt:PSA_ALG_CBC_NO_PADDING:PSA_KEY_TYPE_DES:"01020407080b0d0ec1c2c4c7c8cbcdce31323437383b3d3e":"2a2a2a2a2a2a2a2a":"817ca7d69b80d86a":"eda4011239bc3ac9":PSA_SUCCESS
 
+PSA symmetric decrypt: 2-key 3DES-ECB, 8 bytes, good
+depends_on:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC
+cipher_decrypt:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_DES:"01020407080b0d0ec1c2c4c7c8cbcdce":"":"5d0652429c5b0ac7":"c78e2b38139610e3":PSA_SUCCESS
+
+PSA symmetric decrypt: 3-key 3DES-ECB, 8 bytes, good
+depends_on:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC
+cipher_decrypt:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_DES:"01020407080b0d0ec1c2c4c7c8cbcdce31323437383b3d3e":"":"817ca7d69b80d86a":"c78e2b38139610e3":PSA_SUCCESS
+
+PSA symmetric encrypt/decrypt: AES-ECB, 16 bytes, good
+depends_on:MBEDTLS_AES_C
+cipher_verify_output:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"6bc1bee22e409f96e93d7e117393172a"
+
 PSA symmetric encrypt/decrypt: AES-CBC-nopad, 16 bytes, good
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC
 cipher_verify_output:PSA_ALG_CBC_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"6bc1bee22e409f96e93d7e117393172a"
@@ -1238,6 +1294,18 @@
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
 cipher_verify_output:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"6bc1bee22e409f96e93d7e117393172a"
 
+PSA symmetric encryption multipart: AES-ECB, 16+16 bytes
+depends_on:MBEDTLS_AES_C
+cipher_encrypt_multipart:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":16:16:16:"3ad77bb40d7a3660a89ecaf32466ef9755ed5e9e066820fa52c729886d18854c"
+
+PSA symmetric encryption multipart: AES-ECB, 13+19 bytes
+depends_on:MBEDTLS_AES_C
+cipher_encrypt_multipart:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":13:0:32:"3ad77bb40d7a3660a89ecaf32466ef9755ed5e9e066820fa52c729886d18854c"
+
+PSA symmetric encryption multipart: AES-ECB, 24+12 bytes
+depends_on:MBEDTLS_AES_C
+cipher_encrypt_multipart:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":24:16:16:"3ad77bb40d7a3660a89ecaf32466ef9755ed5e9e066820fa52c729886d18854c"
+
 PSA symmetric encryption multipart: AES-CBC-nopad, 7+9 bytes
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC
 cipher_encrypt_multipart:PSA_ALG_CBC_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":7:0:16:"a076ec9dfbe47d52afc357336f20743b"
@@ -1266,23 +1334,23 @@
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC
 cipher_encrypt_multipart:PSA_ALG_CBC_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":20:16:16:"a076ec9dfbe47d52afc357336f20743b89906f2f9207ac02aa658cb4ef19c61f"
 
-PSA symmetric encryption multipart: AES-CTR, 11+5 bytes [#1]
+PSA symmetric encryption multipart: AES-CTR, 11+5 bytes
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
 cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":11:11:5:"8f9408fe80a81d3e813da3c7b0b2bd32"
 
-PSA symmetric encryption multipart: AES-CTR, 16+16 bytes [#1]
+PSA symmetric encryption multipart: AES-CTR, 16+16 bytes
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
 cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":16:16:16:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7baf71025f6ef6393ca587"
 
-PSA symmetric encryption multipart: AES-CTR, 12+20 bytes [#1]
+PSA symmetric encryption multipart: AES-CTR, 12+20 bytes
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
 cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":12:12:20:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7baf71025f6ef6393ca587"
 
-PSA symmetric encryption multipart: AES-CTR, 20+12 bytes [#1]
+PSA symmetric encryption multipart: AES-CTR, 20+12 bytes
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
 cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":20:20:12:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7baf71025f6ef6393ca587"
 
-PSA symmetric encryption multipart: AES-CTR, 12+10 bytes [#1]
+PSA symmetric encryption multipart: AES-CTR, 12+10 bytes
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
 cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597":12:12:10:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7b"
 
@@ -1302,6 +1370,18 @@
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
 cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":16:16:0:"8f9408fe80a81d3e813da3c7b0b2bd32"
 
+PSA symmetric decryption multipart: AES-ECB, 16+16 bytes
+depends_on:MBEDTLS_AES_C
+cipher_decrypt_multipart:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"":"3ad77bb40d7a3660a89ecaf32466ef9755ed5e9e066820fa52c729886d18854c":16:16:16:"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef"
+
+PSA symmetric decryption multipart: AES-ECB, 11+21 bytes
+depends_on:MBEDTLS_AES_C
+cipher_decrypt_multipart:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"":"3ad77bb40d7a3660a89ecaf32466ef9755ed5e9e066820fa52c729886d18854c":11:0:32:"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef"
+
+PSA symmetric decryption multipart: AES-ECB, 28+4 bytes
+depends_on:MBEDTLS_AES_C
+cipher_decrypt_multipart:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"":"3ad77bb40d7a3660a89ecaf32466ef9755ed5e9e066820fa52c729886d18854c":28:16:16:"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef"
+
 PSA symmetric decryption multipart: AES-CBC-nopad, 7+9 bytes
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC
 cipher_decrypt_multipart:PSA_ALG_CBC_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"a076ec9dfbe47d52afc357336f20743b":7:0:16:"6bc1bee22e409f96e93d7e117393172a"
@@ -1326,23 +1406,23 @@
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC
 cipher_decrypt_multipart:PSA_ALG_CBC_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"a076ec9dfbe47d52afc357336f20743b89906f2f9207ac02aa658cb4ef19c61f":20:16:16:"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef"
 
-PSA symmetric encryption multipart: AES-CTR, 11+5 bytes [#2]
+PSA symmetric decryption multipart: AES-CTR, 11+5 bytes
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
 cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":11:11:5:"8f9408fe80a81d3e813da3c7b0b2bd32"
 
-PSA symmetric encryption multipart: AES-CTR, 16+16 bytes [#2]
+PSA symmetric decryption multipart: AES-CTR, 16+16 bytes
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
 cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":16:16:16:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7baf71025f6ef6393ca587"
 
-PSA symmetric encryption multipart: AES-CTR, 12+20 bytes [#2]
+PSA symmetric decryption multipart: AES-CTR, 12+20 bytes
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
 cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":12:12:20:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7baf71025f6ef6393ca587"
 
-PSA symmetric encryption multipart: AES-CTR, 20+12 bytes [#2]
+PSA symmetric decryption multipart: AES-CTR, 20+12 bytes
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
 cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":20:20:12:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7baf71025f6ef6393ca587"
 
-PSA symmetric encryption multipart: AES-CTR, 12+10 bytes [#2]
+PSA symmetric decryption multipart: AES-CTR, 12+10 bytes
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
 cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597":12:12:10:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7b"
 
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index 7f199e2..45916b9 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -3447,7 +3447,11 @@
     PSA_ASSERT( psa_cipher_encrypt_setup( &operation,
                                           handle, alg ) );
 
-    PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) );
+    if( iv->len > 0 )
+    {
+        PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) );
+    }
+
     output_buffer_size = ( (size_t) input->len +
                            PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) );
     ASSERT_ALLOC( output, output_buffer_size );
@@ -3511,7 +3515,11 @@
     PSA_ASSERT( psa_cipher_encrypt_setup( &operation,
                                           handle, alg ) );
 
-    PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) );
+    if( iv->len > 0 )
+    {
+        PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) );
+    }
+
     output_buffer_size = ( (size_t) input->len +
                            PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) );
     ASSERT_ALLOC( output, output_buffer_size );
@@ -3581,7 +3589,10 @@
     PSA_ASSERT( psa_cipher_decrypt_setup( &operation,
                                           handle, alg ) );
 
-    PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) );
+    if( iv->len > 0 )
+    {
+        PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) );
+    }
 
     output_buffer_size = ( (size_t) input->len +
                            PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) );
@@ -3649,7 +3660,10 @@
     PSA_ASSERT( psa_cipher_decrypt_setup( &operation,
                                           handle, alg ) );
 
-    PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) );
+    if( iv->len > 0 )
+    {
+        PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) );
+    }
 
     output_buffer_size = ( (size_t) input->len +
                            PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) );
@@ -3717,9 +3731,12 @@
     PSA_ASSERT( psa_cipher_decrypt_setup( &operation2,
                                           handle, alg ) );
 
-    PSA_ASSERT( psa_cipher_generate_iv( &operation1,
-                                        iv, iv_size,
-                                        &iv_length ) );
+    if( alg != PSA_ALG_ECB_NO_PADDING )
+    {
+        PSA_ASSERT( psa_cipher_generate_iv( &operation1,
+                                            iv, iv_size,
+                                            &iv_length ) );
+    }
     output1_size = ( (size_t) input->len +
                      PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) );
     ASSERT_ALLOC( output1, output1_size );
@@ -3739,8 +3756,12 @@
     output2_size = output1_length;
     ASSERT_ALLOC( output2, output2_size );
 
-    PSA_ASSERT( psa_cipher_set_iv( &operation2,
-                                   iv, iv_length ) );
+    if( iv_length > 0 )
+    {
+        PSA_ASSERT( psa_cipher_set_iv( &operation2,
+                                       iv, iv_length ) );
+    }
+
     PSA_ASSERT( psa_cipher_update( &operation2, output1, output1_length,
                                    output2, output2_size,
                                    &output2_length ) );
@@ -3804,9 +3825,13 @@
     PSA_ASSERT( psa_cipher_decrypt_setup( &operation2,
                                           handle, alg ) );
 
-    PSA_ASSERT( psa_cipher_generate_iv( &operation1,
-                                        iv, iv_size,
-                                        &iv_length ) );
+    if( alg != PSA_ALG_ECB_NO_PADDING )
+    {
+        PSA_ASSERT( psa_cipher_generate_iv( &operation1,
+                                            iv, iv_size,
+                                            &iv_length ) );
+    }
+
     output1_buffer_size = ( (size_t) input->len +
                             PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) );
     ASSERT_ALLOC( output1, output1_buffer_size );
@@ -3836,8 +3861,11 @@
     output2_buffer_size = output1_length;
     ASSERT_ALLOC( output2, output2_buffer_size );
 
-    PSA_ASSERT( psa_cipher_set_iv( &operation2,
-                                   iv, iv_length ) );
+    if( iv_length > 0 )
+    {
+        PSA_ASSERT( psa_cipher_set_iv( &operation2,
+                                       iv, iv_length ) );
+    }
 
     PSA_ASSERT( psa_cipher_update( &operation2, output1, first_part_size,
                                    output2, output2_buffer_size,
diff --git a/tests/suites/test_suite_psa_crypto_driver_wrappers.data b/tests/suites/test_suite_psa_crypto_driver_wrappers.data
new file mode 100644
index 0000000..7abc256
--- /dev/null
+++ b/tests/suites/test_suite_psa_crypto_driver_wrappers.data
@@ -0,0 +1,152 @@
+sign_hash through transparent driver: calculate in driver
+ecdsa_sign:PSA_SUCCESS:"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f":0:PSA_SUCCESS
+
+sign_hash through transparent driver: fallback
+ecdsa_sign:PSA_ERROR_NOT_SUPPORTED:"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f":0:PSA_SUCCESS
+
+sign_hash through transparent driver: error
+ecdsa_sign:PSA_ERROR_GENERIC_ERROR:"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f":0:PSA_ERROR_GENERIC_ERROR
+
+sign_hash through transparent driver: fake
+ecdsa_sign:PSA_SUCCESS:"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"000102030405060708090A0B0C0D0E0F":1:PSA_SUCCESS
+
+verify_hash using private key through transparent driver: calculate in driver
+ecdsa_verify:PSA_SUCCESS:0:"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f":PSA_SUCCESS
+
+verify_hash using private key through transparent driver: fallback
+ecdsa_verify:PSA_ERROR_NOT_SUPPORTED:0:"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f":PSA_SUCCESS
+
+verify_hash using private key through transparent driver: error
+ecdsa_verify:PSA_ERROR_GENERIC_ERROR:0:"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f":PSA_ERROR_GENERIC_ERROR
+
+verify_hash using public key through transparent driver: calculate in driver
+ecdsa_verify:PSA_SUCCESS:1:"04dea5e45d0ea37fc566232a508f4ad20ea13d47e4bf5fa4d54a57a0ba012042087097496efc583fed8b24a5b9be9a51de063f5a00a8b698a16fd7f29b5485f320":"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f":PSA_SUCCESS
+
+verify_hash using public key through transparent driver: fallback
+ecdsa_verify:PSA_ERROR_NOT_SUPPORTED:1:"04dea5e45d0ea37fc566232a508f4ad20ea13d47e4bf5fa4d54a57a0ba012042087097496efc583fed8b24a5b9be9a51de063f5a00a8b698a16fd7f29b5485f320":"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f":PSA_SUCCESS
+
+verify_hash using public key through transparent driver: error
+ecdsa_verify:PSA_ERROR_GENERIC_ERROR:1:"04dea5e45d0ea37fc566232a508f4ad20ea13d47e4bf5fa4d54a57a0ba012042087097496efc583fed8b24a5b9be9a51de063f5a00a8b698a16fd7f29b5485f320":"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f":PSA_ERROR_GENERIC_ERROR
+
+generate_key through transparent driver: fake
+generate_key:PSA_SUCCESS:"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_SUCCESS
+
+generate_key through transparent driver: in-driver
+generate_key:PSA_SUCCESS:"":PSA_SUCCESS
+
+generate_key through transparent driver: fallback
+generate_key:PSA_ERROR_NOT_SUPPORTED:"":PSA_SUCCESS
+
+generate_key through transparent driver: error
+generate_key:PSA_ERROR_GENERIC_ERROR:"":PSA_ERROR_GENERIC_ERROR
+
+PSA symmetric encrypt: AES-CTR, 16 bytes, good
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_encrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":"8f9408fe80a81d3e813da3c7b0b2bd32":0:PSA_SUCCESS:PSA_SUCCESS
+
+PSA symmetric encrypt: AES-CTR, 15 bytes, good
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_encrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e11739317":"8f9408fe80a81d3e813da3c7b0b2bd":0:PSA_SUCCESS:PSA_SUCCESS
+
+PSA symmetric encrypt: AES-CTR, 16 bytes, fallback
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_encrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":"8f9408fe80a81d3e813da3c7b0b2bd32":0:PSA_ERROR_NOT_SUPPORTED:PSA_SUCCESS
+
+PSA symmetric encrypt: AES-CTR, 15 bytes, fallback
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_encrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e11739317":"8f9408fe80a81d3e813da3c7b0b2bd":0:PSA_ERROR_NOT_SUPPORTED:PSA_SUCCESS
+
+PSA symmetric encrypt: AES-CTR, 16 bytes, fake
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_encrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":"d07a6a6e2687feb2":1:PSA_SUCCESS:PSA_SUCCESS
+
+PSA symmetric encrypt: AES-CTR, 15 bytes, fake
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_encrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e11739317":"d07a6a6e2687feb2":1:PSA_SUCCESS:PSA_SUCCESS
+
+PSA symmetric decrypt: AES-CTR, 16 bytes, good
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_MODE_CTR
+cipher_decrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"396ee84fb75fdbb5c2b13c7fe5a654aa":"dd3b5e5319b7591daab1e1a92687feb2":0:PSA_SUCCESS:PSA_SUCCESS
+
+PSA symmetric decrypt: AES-CTR, 16 bytes, fallback
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_MODE_CTR
+cipher_decrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"396ee84fb75fdbb5c2b13c7fe5a654aa":"dd3b5e5319b7591daab1e1a92687feb2":0:PSA_ERROR_NOT_SUPPORTED:PSA_SUCCESS
+
+PSA symmetric decrypt: AES-CTR, 16 bytes, fake
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_MODE_CTR
+cipher_decrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"396ee84fb75fdbb5c2b13c7fe5a654aa":"d07a6a6e2687feb2":1:PSA_SUCCESS:PSA_SUCCESS
+
+PSA symmetric encryption multipart: AES-CTR, 11+5 bytes
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":11:11:5:"8f9408fe80a81d3e813da3c7b0b2bd32"
+
+PSA symmetric encryption multipart: AES-CTR, 16+16 bytes
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":16:16:16:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7baf71025f6ef6393ca587"
+
+PSA symmetric encryption multipart: AES-CTR, 12+20 bytes
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":12:12:20:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7baf71025f6ef6393ca587"
+
+PSA symmetric encryption multipart: AES-CTR, 20+12 bytes
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":20:20:12:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7baf71025f6ef6393ca587"
+
+PSA symmetric encryption multipart: AES-CTR, 12+10 bytes
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597":12:12:10:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7b"
+
+PSA symmetric encryption multipart: AES-CTR, 0+15 bytes
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e11739317":0:0:15:"8f9408fe80a81d3e813da3c7b0b2bd"
+
+PSA symmetric encryption multipart: AES-CTR, 15+0 bytes
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e11739317":15:15:0:"8f9408fe80a81d3e813da3c7b0b2bd"
+
+PSA symmetric encryption multipart: AES-CTR, 0+16 bytes
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":0:0:16:"8f9408fe80a81d3e813da3c7b0b2bd32"
+
+PSA symmetric encryption multipart: AES-CTR, 16+0 bytes
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":16:16:0:"8f9408fe80a81d3e813da3c7b0b2bd32"
+
+PSA symmetric decryption multipart: AES-CTR, 11+5 bytes
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":11:11:5:"8f9408fe80a81d3e813da3c7b0b2bd32"
+
+PSA symmetric decryption multipart: AES-CTR, 16+16 bytes
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":16:16:16:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7baf71025f6ef6393ca587"
+
+PSA symmetric decryption multipart: AES-CTR, 12+20 bytes
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":12:12:20:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7baf71025f6ef6393ca587"
+
+PSA symmetric decryption multipart: AES-CTR, 20+12 bytes
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":20:20:12:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7baf71025f6ef6393ca587"
+
+PSA symmetric decryption multipart: AES-CTR, 12+10 bytes
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597":12:12:10:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7b"
+
+PSA symmetric decryption multipart: AES-CTR, 0+15 bytes
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e11739317":0:0:15:"8f9408fe80a81d3e813da3c7b0b2bd"
+
+PSA symmetric decryption multipart: AES-CTR, 15+0 bytes
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e11739317":15:15:0:"8f9408fe80a81d3e813da3c7b0b2bd"
+
+PSA symmetric decryption multipart: AES-CTR, 0+16 bytes
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":0:0:16:"8f9408fe80a81d3e813da3c7b0b2bd32"
+
+PSA symmetric decryption multipart: AES-CTR, 16+0 bytes
+depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
+cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":16:16:0:"8f9408fe80a81d3e813da3c7b0b2bd32"
+
+Cipher driver: negative testing on all entry points
+cipher_entry_points:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a"
diff --git a/tests/suites/test_suite_psa_crypto_driver_wrappers.function b/tests/suites/test_suite_psa_crypto_driver_wrappers.function
new file mode 100644
index 0000000..951670d
--- /dev/null
+++ b/tests/suites/test_suite_psa_crypto_driver_wrappers.function
@@ -0,0 +1,718 @@
+/* BEGIN_HEADER */
+#include "test/psa_crypto_helpers.h"
+
+#include "test/drivers/test_driver.h"
+/* END_HEADER */
+
+/* BEGIN_DEPENDENCIES
+ * depends_on:MBEDTLS_PSA_CRYPTO_C:MBEDTLS_PSA_CRYPTO_DRIVERS:PSA_CRYPTO_DRIVER_TEST
+ * END_DEPENDENCIES
+ */
+
+/* BEGIN_CASE depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECDSA_DETERMINISTIC:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C */
+void ecdsa_sign( int force_status_arg,
+                 data_t *key_input,
+                 data_t *data_input,
+                 data_t *expected_output,
+                 int fake_output,
+                 int expected_status_arg )
+{
+    psa_status_t force_status = force_status_arg;
+    psa_status_t expected_status = expected_status_arg;
+    psa_key_handle_t handle = 0;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_algorithm_t alg = PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 );
+    uint8_t signature[64];
+    size_t signature_length = 0xdeadbeef;
+    psa_status_t actual_status;
+    test_driver_signature_sign_hooks = test_driver_signature_hooks_init();
+
+    PSA_ASSERT( psa_crypto_init( ) );
+    psa_set_key_type( &attributes,
+                      PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP_R1 ) );
+    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN_HASH );
+    psa_set_key_algorithm( &attributes, alg );
+    psa_import_key( &attributes,
+                    key_input->x, key_input->len,
+                    &handle );
+
+    test_driver_signature_sign_hooks.forced_status = force_status;
+    if( fake_output == 1 )
+    {
+        test_driver_signature_sign_hooks.forced_output = expected_output->x;
+        test_driver_signature_sign_hooks.forced_output_length = expected_output->len;
+    }
+
+    actual_status = psa_sign_hash( handle, alg,
+                                   data_input->x, data_input->len,
+                                   signature, sizeof( signature ),
+                                   &signature_length );
+    TEST_EQUAL( actual_status, expected_status );
+    if( expected_status == PSA_SUCCESS )
+    {
+        ASSERT_COMPARE( signature, signature_length,
+                        expected_output->x, expected_output->len );
+    }
+    TEST_EQUAL( test_driver_signature_sign_hooks.hits, 1 );
+
+exit:
+    psa_reset_key_attributes( &attributes );
+    psa_destroy_key( handle );
+    PSA_DONE( );
+    test_driver_signature_sign_hooks = test_driver_signature_hooks_init();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECDSA_DETERMINISTIC:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C */
+void ecdsa_verify( int force_status_arg,
+                   int register_public_key,
+                   data_t *key_input,
+                   data_t *data_input,
+                   data_t *signature_input,
+                   int expected_status_arg )
+{
+    psa_status_t force_status = force_status_arg;
+    psa_status_t expected_status = expected_status_arg;
+    psa_key_handle_t handle = 0;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_algorithm_t alg = PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 );
+    psa_status_t actual_status;
+    test_driver_signature_verify_hooks = test_driver_signature_hooks_init();
+
+    PSA_ASSERT( psa_crypto_init( ) );
+    if( register_public_key )
+    {
+        psa_set_key_type( &attributes,
+                      PSA_KEY_TYPE_ECC_PUBLIC_KEY( PSA_ECC_CURVE_SECP_R1 ) );
+        psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_VERIFY_HASH );
+        psa_set_key_algorithm( &attributes, alg );
+        psa_import_key( &attributes,
+                        key_input->x, key_input->len,
+                        &handle );
+    }
+    else
+    {
+        psa_set_key_type( &attributes,
+                      PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP_R1 ) );
+        psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_VERIFY_HASH );
+        psa_set_key_algorithm( &attributes, alg );
+        psa_import_key( &attributes,
+                        key_input->x, key_input->len,
+                        &handle );
+    }
+
+    test_driver_signature_verify_hooks.forced_status = force_status;
+
+    actual_status = psa_verify_hash( handle, alg,
+                                     data_input->x, data_input->len,
+                                     signature_input->x, signature_input->len );
+    TEST_EQUAL( actual_status, expected_status );
+    TEST_EQUAL( test_driver_signature_verify_hooks.hits, 1 );
+
+exit:
+    psa_reset_key_attributes( &attributes );
+    psa_destroy_key( handle );
+    PSA_DONE( );
+    test_driver_signature_verify_hooks = test_driver_signature_hooks_init();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED */
+void generate_key( int force_status_arg,
+                   data_t *fake_output,
+                   int expected_status_arg )
+{
+    psa_status_t force_status = force_status_arg;
+    psa_status_t expected_status = expected_status_arg;
+    psa_key_handle_t handle = 0;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_algorithm_t alg = PSA_ALG_ECDSA( PSA_ALG_SHA_256 );
+    const uint8_t *expected_output = NULL;
+    size_t expected_output_length = 0;
+    psa_status_t actual_status;
+    uint8_t actual_output[PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(256)] = {0};
+    size_t actual_output_length;
+    test_driver_keygen_hooks = test_driver_keygen_hooks_init();
+
+    psa_set_key_type( &attributes,
+                      PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP_R1 ) );
+    psa_set_key_bits( &attributes, 256 );
+    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_EXPORT );
+    psa_set_key_algorithm( &attributes, alg );
+
+    if( fake_output->len > 0 )
+    {
+        expected_output = test_driver_keygen_hooks.forced_output = fake_output->x;
+        expected_output_length = test_driver_keygen_hooks.forced_output_length =
+            fake_output->len;
+    }
+
+    test_driver_keygen_hooks.hits = 0;
+    test_driver_keygen_hooks.forced_status = force_status;
+
+    PSA_ASSERT( psa_crypto_init( ) );
+
+    actual_status = psa_generate_key( &attributes, &handle );
+    TEST_EQUAL( test_driver_keygen_hooks.hits, 1 );
+    TEST_EQUAL( actual_status, expected_status );
+
+    if( actual_status == PSA_SUCCESS )
+    {
+        psa_export_key( handle, actual_output, sizeof(actual_output), &actual_output_length );
+
+        if( fake_output->len > 0 )
+        {
+            ASSERT_COMPARE( actual_output, actual_output_length,
+                            expected_output, expected_output_length );
+        }
+        else
+        {
+            size_t zeroes = 0;
+            for( size_t i = 0; i < sizeof(actual_output); i++ )
+            {
+                if( actual_output[i] == 0)
+                    zeroes++;
+            }
+            TEST_ASSERT( zeroes != sizeof(actual_output) );
+        }
+    }
+exit:
+    psa_reset_key_attributes( &attributes );
+    psa_destroy_key( handle );
+    PSA_DONE( );
+    test_driver_keygen_hooks = test_driver_keygen_hooks_init();
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void cipher_encrypt( int alg_arg, int key_type_arg,
+                     data_t *key, data_t *iv,
+                     data_t *input, data_t *expected_output,
+                     int mock_output_arg,
+                     int force_status_arg,
+                     int expected_status_arg )
+{
+    psa_key_handle_t handle = 0;
+    psa_status_t status;
+    psa_key_type_t key_type = key_type_arg;
+    psa_algorithm_t alg = alg_arg;
+    psa_status_t expected_status = expected_status_arg;
+    psa_status_t force_status = force_status_arg;
+    unsigned char *output = NULL;
+    size_t output_buffer_size = 0;
+    size_t function_output_length = 0;
+    size_t total_output_length = 0;
+    psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    test_driver_cipher_hooks = test_driver_cipher_hooks_init();
+    test_driver_cipher_hooks.forced_status = force_status;
+
+    PSA_ASSERT( psa_crypto_init( ) );
+
+    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_ENCRYPT );
+    psa_set_key_algorithm( &attributes, alg );
+    psa_set_key_type( &attributes, key_type );
+
+    PSA_ASSERT( psa_import_key( &attributes, key->x, key->len, &handle ) );
+
+    PSA_ASSERT( psa_cipher_encrypt_setup( &operation,
+                                          handle, alg ) );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    test_driver_cipher_hooks.hits = 0;
+
+    PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 1 : 0 ) );
+    test_driver_cipher_hooks.hits = 0;
+
+    output_buffer_size = ( (size_t) input->len +
+                           PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) );
+    ASSERT_ALLOC( output, output_buffer_size );
+
+    if( mock_output_arg )
+    {
+        test_driver_cipher_hooks.forced_output = expected_output->x;
+        test_driver_cipher_hooks.forced_output_length = expected_output->len;
+    }
+
+    PSA_ASSERT( psa_cipher_update( &operation,
+                                   input->x, input->len,
+                                   output, output_buffer_size,
+                                   &function_output_length ) );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 1 : 0 ) );
+    test_driver_cipher_hooks.hits = 0;
+
+    if( mock_output_arg )
+    {
+        test_driver_cipher_hooks.forced_output = NULL;
+        test_driver_cipher_hooks.forced_output_length = 0;
+    }
+
+    total_output_length += function_output_length;
+    status = psa_cipher_finish( &operation,
+                                output + total_output_length,
+                                output_buffer_size - total_output_length,
+                                &function_output_length );
+    /* Finish will have called abort as well, so expecting two hits here */
+    TEST_EQUAL( test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 2 : 0 ) );
+    test_driver_cipher_hooks.hits = 0;
+
+    total_output_length += function_output_length;
+
+    TEST_EQUAL( status, expected_status );
+    if( expected_status == PSA_SUCCESS )
+    {
+        PSA_ASSERT( psa_cipher_abort( &operation ) );
+        // driver function should've been called as part of the finish() core routine
+        TEST_EQUAL( test_driver_cipher_hooks.hits, 0 );
+        ASSERT_COMPARE( expected_output->x, expected_output->len,
+                        output, total_output_length );
+    }
+
+exit:
+    psa_cipher_abort( &operation );
+    mbedtls_free( output );
+    psa_destroy_key( handle );
+    PSA_DONE( );
+    test_driver_cipher_hooks = test_driver_cipher_hooks_init();
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void cipher_encrypt_multipart( int alg_arg, int key_type_arg,
+                               data_t *key, data_t *iv,
+                               data_t *input,
+                               int first_part_size_arg,
+                               int output1_length_arg, int output2_length_arg,
+                               data_t *expected_output )
+{
+    psa_key_handle_t handle = 0;
+    psa_key_type_t key_type = key_type_arg;
+    psa_algorithm_t alg = alg_arg;
+    size_t first_part_size = first_part_size_arg;
+    size_t output1_length = output1_length_arg;
+    size_t output2_length = output2_length_arg;
+    unsigned char *output = NULL;
+    size_t output_buffer_size = 0;
+    size_t function_output_length = 0;
+    size_t total_output_length = 0;
+    psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    test_driver_cipher_hooks = test_driver_cipher_hooks_init();
+
+    PSA_ASSERT( psa_crypto_init( ) );
+
+    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_ENCRYPT );
+    psa_set_key_algorithm( &attributes, alg );
+    psa_set_key_type( &attributes, key_type );
+
+    PSA_ASSERT( psa_import_key( &attributes, key->x, key->len, &handle ) );
+
+    PSA_ASSERT( psa_cipher_encrypt_setup( &operation,
+                                          handle, alg ) );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    test_driver_cipher_hooks.hits = 0;
+
+    PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    test_driver_cipher_hooks.hits = 0;
+
+    output_buffer_size = ( (size_t) input->len +
+                           PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) );
+    ASSERT_ALLOC( output, output_buffer_size );
+
+    TEST_ASSERT( first_part_size <= input->len );
+    PSA_ASSERT( psa_cipher_update( &operation, input->x, first_part_size,
+                                   output, output_buffer_size,
+                                   &function_output_length ) );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    test_driver_cipher_hooks.hits = 0;
+
+    TEST_ASSERT( function_output_length == output1_length );
+    total_output_length += function_output_length;
+    PSA_ASSERT( psa_cipher_update( &operation,
+                                   input->x + first_part_size,
+                                   input->len - first_part_size,
+                                   output + total_output_length,
+                                   output_buffer_size - total_output_length,
+                                   &function_output_length ) );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    test_driver_cipher_hooks.hits = 0;
+    TEST_ASSERT( function_output_length == output2_length );
+    total_output_length += function_output_length;
+    PSA_ASSERT( psa_cipher_finish( &operation,
+                                   output + total_output_length,
+                                   output_buffer_size - total_output_length,
+                                   &function_output_length ) );
+    /* Finish will have called abort as well, so expecting two hits here */
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 2 );
+    test_driver_cipher_hooks.hits = 0 ;
+    total_output_length += function_output_length;
+    PSA_ASSERT( psa_cipher_abort( &operation ) );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 0 );
+
+    ASSERT_COMPARE( expected_output->x, expected_output->len,
+                    output, total_output_length );
+
+exit:
+    psa_cipher_abort( &operation );
+    mbedtls_free( output );
+    psa_destroy_key( handle );
+    PSA_DONE( );
+    test_driver_cipher_hooks = test_driver_cipher_hooks_init();
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void cipher_decrypt_multipart( int alg_arg, int key_type_arg,
+                               data_t *key, data_t *iv,
+                               data_t *input,
+                               int first_part_size_arg,
+                               int output1_length_arg, int output2_length_arg,
+                               data_t *expected_output )
+{
+    psa_key_handle_t handle = 0;
+
+    psa_key_type_t key_type = key_type_arg;
+    psa_algorithm_t alg = alg_arg;
+    size_t first_part_size = first_part_size_arg;
+    size_t output1_length = output1_length_arg;
+    size_t output2_length = output2_length_arg;
+    unsigned char *output = NULL;
+    size_t output_buffer_size = 0;
+    size_t function_output_length = 0;
+    size_t total_output_length = 0;
+    psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    test_driver_cipher_hooks = test_driver_cipher_hooks_init();
+
+    PSA_ASSERT( psa_crypto_init( ) );
+
+    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DECRYPT );
+    psa_set_key_algorithm( &attributes, alg );
+    psa_set_key_type( &attributes, key_type );
+
+    PSA_ASSERT( psa_import_key( &attributes, key->x, key->len, &handle ) );
+
+    PSA_ASSERT( psa_cipher_decrypt_setup( &operation,
+                                          handle, alg ) );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    test_driver_cipher_hooks.hits = 0;
+
+    PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    test_driver_cipher_hooks.hits = 0;
+
+    output_buffer_size = ( (size_t) input->len +
+                           PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) );
+    ASSERT_ALLOC( output, output_buffer_size );
+
+    TEST_ASSERT( first_part_size <= input->len );
+    PSA_ASSERT( psa_cipher_update( &operation,
+                                   input->x, first_part_size,
+                                   output, output_buffer_size,
+                                   &function_output_length ) );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    test_driver_cipher_hooks.hits = 0;
+
+    TEST_ASSERT( function_output_length == output1_length );
+    total_output_length += function_output_length;
+    PSA_ASSERT( psa_cipher_update( &operation,
+                                   input->x + first_part_size,
+                                   input->len - first_part_size,
+                                   output + total_output_length,
+                                   output_buffer_size - total_output_length,
+                                   &function_output_length ) );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    test_driver_cipher_hooks.hits = 0;
+
+    TEST_ASSERT( function_output_length == output2_length );
+    total_output_length += function_output_length;
+    PSA_ASSERT( psa_cipher_finish( &operation,
+                                   output + total_output_length,
+                                   output_buffer_size - total_output_length,
+                                   &function_output_length ) );
+    /* Finish will have called abort as well, so expecting two hits here */
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 2 );
+    test_driver_cipher_hooks.hits = 0;
+    total_output_length += function_output_length;
+    PSA_ASSERT( psa_cipher_abort( &operation ) );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 0 );
+
+    ASSERT_COMPARE( expected_output->x, expected_output->len,
+                    output, total_output_length );
+
+exit:
+    psa_cipher_abort( &operation );
+    mbedtls_free( output );
+    psa_destroy_key( handle );
+    PSA_DONE( );
+    test_driver_cipher_hooks = test_driver_cipher_hooks_init();
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void cipher_decrypt( int alg_arg, int key_type_arg,
+                     data_t *key, data_t *iv,
+                     data_t *input, data_t *expected_output,
+                     int mock_output_arg,
+                     int force_status_arg,
+                     int expected_status_arg )
+{
+    psa_key_handle_t handle = 0;
+    psa_status_t status;
+    psa_key_type_t key_type = key_type_arg;
+    psa_algorithm_t alg = alg_arg;
+    psa_status_t expected_status = expected_status_arg;
+    psa_status_t force_status = force_status_arg;
+    unsigned char *output = NULL;
+    size_t output_buffer_size = 0;
+    size_t function_output_length = 0;
+    size_t total_output_length = 0;
+    psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    test_driver_cipher_hooks = test_driver_cipher_hooks_init();
+    test_driver_cipher_hooks.forced_status = force_status;
+
+    PSA_ASSERT( psa_crypto_init( ) );
+
+    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DECRYPT );
+    psa_set_key_algorithm( &attributes, alg );
+    psa_set_key_type( &attributes, key_type );
+
+    PSA_ASSERT( psa_import_key( &attributes, key->x, key->len, &handle ) );
+
+    PSA_ASSERT( psa_cipher_decrypt_setup( &operation,
+                                          handle, alg ) );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    test_driver_cipher_hooks.hits = 0;
+
+    PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 1 : 0 ) );
+    test_driver_cipher_hooks.hits = 0;
+
+    output_buffer_size = ( (size_t) input->len +
+                           PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) );
+    ASSERT_ALLOC( output, output_buffer_size );
+
+    if( mock_output_arg )
+    {
+        test_driver_cipher_hooks.forced_output = expected_output->x;
+        test_driver_cipher_hooks.forced_output_length = expected_output->len;
+    }
+
+    PSA_ASSERT( psa_cipher_update( &operation,
+                                   input->x, input->len,
+                                   output, output_buffer_size,
+                                   &function_output_length ) );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 1 : 0 ) );
+    test_driver_cipher_hooks.hits = 0;
+
+    if( mock_output_arg )
+    {
+        test_driver_cipher_hooks.forced_output = NULL;
+        test_driver_cipher_hooks.forced_output_length = 0;
+    }
+
+    total_output_length += function_output_length;
+    status = psa_cipher_finish( &operation,
+                                output + total_output_length,
+                                output_buffer_size - total_output_length,
+                                &function_output_length );
+    /* Finish will have called abort as well, so expecting two hits here */
+    TEST_EQUAL( test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 2 : 0 ) );
+    test_driver_cipher_hooks.hits = 0;
+
+    total_output_length += function_output_length;
+    TEST_EQUAL( status, expected_status );
+
+    if( expected_status == PSA_SUCCESS )
+    {
+        PSA_ASSERT( psa_cipher_abort( &operation ) );
+        TEST_EQUAL( test_driver_cipher_hooks.hits, 0 );
+        ASSERT_COMPARE( expected_output->x, expected_output->len,
+                        output, total_output_length );
+    }
+
+exit:
+    psa_cipher_abort( &operation );
+    mbedtls_free( output );
+    psa_destroy_key( handle );
+    PSA_DONE( );
+    test_driver_cipher_hooks = test_driver_cipher_hooks_init();
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void cipher_entry_points( int alg_arg, int key_type_arg,
+                          data_t *key, data_t *iv,
+                          data_t *input )
+{
+    psa_key_handle_t handle = 0;
+    psa_status_t status;
+    psa_key_type_t key_type = key_type_arg;
+    psa_algorithm_t alg = alg_arg;
+    unsigned char *output = NULL;
+    size_t output_buffer_size = 0;
+    size_t function_output_length = 0;
+    psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    test_driver_cipher_hooks = test_driver_cipher_hooks_init();
+
+    ASSERT_ALLOC( output, input->len + 16 );
+    output_buffer_size = input->len + 16;
+
+    PSA_ASSERT( psa_crypto_init( ) );
+
+    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT );
+    psa_set_key_algorithm( &attributes, alg );
+    psa_set_key_type( &attributes, key_type );
+
+    PSA_ASSERT( psa_import_key( &attributes, key->x, key->len, &handle ) );
+
+    /* Test setup call, encrypt */
+    test_driver_cipher_hooks.forced_status = PSA_ERROR_GENERIC_ERROR;
+    status = psa_cipher_encrypt_setup( &operation,
+                                       handle, alg );
+    /* When setup fails, it shouldn't call any further entry points */
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    TEST_EQUAL( status, test_driver_cipher_hooks.forced_status );
+    test_driver_cipher_hooks.hits = 0;
+    status = psa_cipher_set_iv( &operation, iv->x, iv->len );
+    TEST_EQUAL( status, PSA_ERROR_BAD_STATE );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 0 );
+
+    /* Test setup call failure, decrypt */
+    status = psa_cipher_decrypt_setup( &operation,
+                                       handle, alg );
+    /* When setup fails, it shouldn't call any further entry points */
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    TEST_EQUAL( status, test_driver_cipher_hooks.forced_status );
+    test_driver_cipher_hooks.hits = 0;
+    status = psa_cipher_set_iv( &operation, iv->x, iv->len );
+    TEST_EQUAL( status, PSA_ERROR_BAD_STATE );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 0 );
+
+    /* Test IV setting failure */
+    test_driver_cipher_hooks.forced_status = PSA_SUCCESS;
+    status = psa_cipher_encrypt_setup( &operation,
+                                       handle, alg );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    TEST_EQUAL( status, test_driver_cipher_hooks.forced_status );
+    test_driver_cipher_hooks.hits = 0;
+
+    test_driver_cipher_hooks.forced_status = PSA_ERROR_GENERIC_ERROR;
+    status = psa_cipher_set_iv( &operation, iv->x, iv->len );
+    /* When setting the IV fails, it should call abort too */
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 2 );
+    TEST_EQUAL( status, test_driver_cipher_hooks.forced_status );
+    /* Failure should prevent further operations from executing on the driver */
+    test_driver_cipher_hooks.hits = 0;
+    status = psa_cipher_update( &operation,
+                                input->x, input->len,
+                                output, output_buffer_size,
+                                &function_output_length );
+    TEST_EQUAL( status, PSA_ERROR_BAD_STATE );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 0 );
+    psa_cipher_abort( &operation );
+
+    /* Test IV generation failure */
+    test_driver_cipher_hooks.forced_status = PSA_SUCCESS;
+    status = psa_cipher_encrypt_setup( &operation,
+                                       handle, alg );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    TEST_EQUAL( status, test_driver_cipher_hooks.forced_status );
+    test_driver_cipher_hooks.hits = 0;
+
+    test_driver_cipher_hooks.forced_status = PSA_ERROR_GENERIC_ERROR;
+    status = psa_cipher_generate_iv( &operation, output, 16, &function_output_length );
+    /* When generating the IV fails, it should call abort too */
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 2 );
+    TEST_EQUAL( status, test_driver_cipher_hooks.forced_status );
+    /* Failure should prevent further operations from executing on the driver */
+    test_driver_cipher_hooks.hits = 0;
+    status = psa_cipher_update( &operation,
+                                input->x, input->len,
+                                output, output_buffer_size,
+                                &function_output_length );
+    TEST_EQUAL( status, PSA_ERROR_BAD_STATE );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 0 );
+    psa_cipher_abort( &operation );
+
+    /* Test update failure */
+    test_driver_cipher_hooks.forced_status = PSA_SUCCESS;
+    status = psa_cipher_encrypt_setup( &operation,
+                                       handle, alg );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    TEST_EQUAL( status, test_driver_cipher_hooks.forced_status );
+    test_driver_cipher_hooks.hits = 0;
+
+    status = psa_cipher_set_iv( &operation, iv->x, iv->len );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    TEST_EQUAL( status, test_driver_cipher_hooks.forced_status );
+    test_driver_cipher_hooks.hits = 0;
+
+    test_driver_cipher_hooks.forced_status = PSA_ERROR_GENERIC_ERROR;
+    status = psa_cipher_update( &operation,
+                                input->x, input->len,
+                                output, output_buffer_size,
+                                &function_output_length );
+    /* When the update call fails, it should call abort too */
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 2 );
+    TEST_EQUAL( status, test_driver_cipher_hooks.forced_status );
+    /* Failure should prevent further operations from executing on the driver */
+    test_driver_cipher_hooks.hits = 0;
+    status = psa_cipher_update( &operation,
+                                input->x, input->len,
+                                output, output_buffer_size,
+                                &function_output_length );
+    TEST_EQUAL( status, PSA_ERROR_BAD_STATE );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 0 );
+    psa_cipher_abort( &operation );
+
+    /* Test finish failure */
+    test_driver_cipher_hooks.forced_status = PSA_SUCCESS;
+    status = psa_cipher_encrypt_setup( &operation,
+                                       handle, alg );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    TEST_EQUAL( status, test_driver_cipher_hooks.forced_status );
+    test_driver_cipher_hooks.hits = 0;
+
+    status = psa_cipher_set_iv( &operation, iv->x, iv->len );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    TEST_EQUAL( status, test_driver_cipher_hooks.forced_status );
+    test_driver_cipher_hooks.hits = 0;
+
+    status = psa_cipher_update( &operation,
+                                input->x, input->len,
+                                output, output_buffer_size,
+                                &function_output_length );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 1 );
+    TEST_EQUAL( status, test_driver_cipher_hooks.forced_status );
+    test_driver_cipher_hooks.hits = 0;
+
+    test_driver_cipher_hooks.forced_status = PSA_ERROR_GENERIC_ERROR;
+    status = psa_cipher_finish( &operation,
+                                output + function_output_length,
+                                output_buffer_size - function_output_length,
+                                &function_output_length );
+    /* When the finish call fails, it should call abort too */
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 2 );
+    TEST_EQUAL( status, test_driver_cipher_hooks.forced_status );
+    /* Failure should prevent further operations from executing on the driver */
+    test_driver_cipher_hooks.hits = 0;
+    status = psa_cipher_update( &operation,
+                                input->x, input->len,
+                                output, output_buffer_size,
+                                &function_output_length );
+    TEST_EQUAL( status, PSA_ERROR_BAD_STATE );
+    TEST_EQUAL( test_driver_cipher_hooks.hits, 0 );
+    psa_cipher_abort( &operation );
+
+exit:
+    psa_cipher_abort( &operation );
+    mbedtls_free( output );
+    psa_destroy_key( handle );
+    PSA_DONE( );
+    test_driver_cipher_hooks = test_driver_cipher_hooks_init();
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_psa_crypto_metadata.data b/tests/suites/test_suite_psa_crypto_metadata.data
index f2b16e4..14979d3 100644
--- a/tests/suites/test_suite_psa_crypto_metadata.data
+++ b/tests/suites/test_suite_psa_crypto_metadata.data
@@ -122,6 +122,10 @@
 depends_on:MBEDTLS_CIPHER_C:MBEDTLS_CIPHER_MODE_OFB
 cipher_algorithm:PSA_ALG_OFB:ALG_IS_STREAM_CIPHER
 
+Cipher: ECB-nopad
+depends_on:MBEDTLS_CIPHER_C
+cipher_algorithm:PSA_ALG_ECB_NO_PADDING:0
+
 Cipher: CBC-nopad
 depends_on:MBEDTLS_CIPHER_C:MBEDTLS_CIPHER_MODE_CBC
 cipher_algorithm:PSA_ALG_CBC_NO_PADDING:0
diff --git a/visualc/VS2010/mbedTLS.vcxproj b/visualc/VS2010/mbedTLS.vcxproj
index 578289f..db8ec33 100644
--- a/visualc/VS2010/mbedTLS.vcxproj
+++ b/visualc/VS2010/mbedTLS.vcxproj
@@ -238,8 +238,13 @@
     <ClInclude Include="..\..\tests\include\test\psa_crypto_helpers.h" />

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

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

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

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

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

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

     <ClInclude Include="..\..\library\common.h" />

     <ClInclude Include="..\..\library\psa_crypto_core.h" />

+    <ClInclude Include="..\..\library\psa_crypto_driver_wrappers.h" />

     <ClInclude Include="..\..\library\psa_crypto_invasive.h" />

     <ClInclude Include="..\..\library\psa_crypto_its.h" />

     <ClInclude Include="..\..\library\psa_crypto_se.h" />

@@ -307,6 +312,7 @@
     <ClCompile Include="..\..\library\platform_util.c" />

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

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

+    <ClCompile Include="..\..\library\psa_crypto_driver_wrappers.c" />

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

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

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