Merge pull request #3501 from stevew817/feature/transparent_drivers_trial

Add partial implementation of accelerator API defined in #3493
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_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/include/mbedtls/config.h b/include/mbedtls/config.h
index 1e6e052..a2f408f 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -1329,6 +1329,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
  *
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/psa_crypto.c b/library/psa_crypto.c
index bffddc9..77e6304 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. */
@@ -3637,10 +3638,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 +3656,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 +3755,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 ) )
     {
@@ -6004,29 +5989,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..cc51e24
--- /dev/null
+++ b/library/psa_crypto_driver_wrappers.c
@@ -0,0 +1,373 @@
+/*
+ *  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 */
+
+#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 */
+}
+
+/* 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..4299379
--- /dev/null
+++ b/library/psa_crypto_driver_wrappers.h
@@ -0,0 +1,48 @@
+/*
+ *  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"
+
+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 );
+
+#endif /* PSA_CRYPTO_DRIVER_WRAPPERS_H */
+
+/* End of automatically generated file. */
diff --git a/library/version_features.c b/library/version_features.c
index d2840fa..051fb19 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/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/test/query_config.c b/programs/test/query_config.c
index f4c14d6..f64eb88 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/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..75135e0
--- /dev/null
+++ b/tests/include/test/drivers/test_driver.h
@@ -0,0 +1,28 @@
+/*
+ * 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"
+
+#endif /* PSA_CRYPTO_TEST_DRIVER_H */
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 4fafe02..596e1a9 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -1656,6 +1656,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/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/test_suite_psa_crypto_driver_wrappers.data b/tests/suites/test_suite_psa_crypto_driver_wrappers.data
new file mode 100644
index 0000000..74e6172
--- /dev/null
+++ b/tests/suites/test_suite_psa_crypto_driver_wrappers.data
@@ -0,0 +1,41 @@
+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
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..9177982
--- /dev/null
+++ b/tests/suites/test_suite_psa_crypto_driver_wrappers.function
@@ -0,0 +1,185 @@
+/* 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 */
diff --git a/visualc/VS2010/mbedTLS.vcxproj b/visualc/VS2010/mbedTLS.vcxproj
index 578289f..9d79298 100644
--- a/visualc/VS2010/mbedTLS.vcxproj
+++ b/visualc/VS2010/mbedTLS.vcxproj
@@ -238,8 +238,12 @@
     <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\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 +311,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" />