SE support: Test sign and verify hooks with a passthrough driver
diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal.data b/tests/suites/test_suite_psa_crypto_se_driver_hal.data
index 0bec841..bdd5703 100644
--- a/tests/suites/test_suite_psa_crypto_se_driver_hal.data
+++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.data
@@ -137,3 +137,19 @@
 
 Key registration: with driver validation (rejected)
 register_key_smoke_test:MIN_DRIVER_LIFETIME:0:PSA_ERROR_NOT_PERMITTED
+
+Import-sign-verify: sign in driver, ECDSA
+depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+sign_verify:1:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:0:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e"
+
+Import-sign-verify: sign in software, ECDSA
+depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+sign_verify:0:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:0:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e"
+
+Generate-sign-verify: sign in driver, ECDSA
+depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+sign_verify:1:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:256:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e"
+
+Generate-sign-verify: sign in software, ECDSA
+depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+sign_verify:0:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:256:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e"
diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal.function b/tests/suites/test_suite_psa_crypto_se_driver_hal.function
index d13e2f2..e14fa58 100644
--- a/tests/suites/test_suite_psa_crypto_se_driver_hal.function
+++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.function
@@ -18,7 +18,25 @@
  * This is probably a bug in the library. */
 #define PSA_ERROR_DETECTED_BY_DRIVER ((psa_status_t)( -500 ))
 
-/** Like #TEST_ASSERT for use in a driver method.
+/** Like #TEST_ASSERT for use in a driver method, with no cleanup.
+ *
+ * If an error happens, this macro returns from the calling function.
+ *
+ * Use this macro to assert on guarantees provided by the core.
+ */
+#define DRIVER_ASSERT_RETURN( TEST )                        \
+    do {                                                    \
+       if( ! (TEST) )                                       \
+       {                                                    \
+          test_fail( #TEST, __LINE__, __FILE__ );           \
+          return( PSA_ERROR_DETECTED_BY_DRIVER );           \
+       }                                                    \
+    } while( 0 )
+
+/** Like #TEST_ASSERT for use in a driver method, with cleanup.
+ *
+ * In case of error, this macro sets `status` and jumps to the
+ * label `exit`.
  *
  * Use this macro to assert on guarantees provided by the core.
  */
@@ -27,10 +45,34 @@
        if( ! (TEST) )                                       \
        {                                                    \
           test_fail( #TEST, __LINE__, __FILE__ );           \
-          return( PSA_ERROR_DETECTED_BY_DRIVER );           \
+          status = PSA_ERROR_DETECTED_BY_DRIVER;            \
+          goto exit;                                        \
        }                                                    \
     } while( 0 )
 
+/** Like #PSA_ASSERT for a PSA API call that calls a driver underneath.
+ *
+ * Run the code \p expr. If this returns \p expected_status,
+ * do nothing. If this returns #PSA_ERROR_DETECTED_BY_DRIVER,
+ * jump directly to the `exit` label. If this returns any other
+ * status, call test_fail() then jump to `exit`.
+ *
+ * The special case for #PSA_ERROR_DETECTED_BY_DRIVER is because in this
+ * case, the test driver code is expected to have called test_fail()
+ * already, so we make sure not to overwrite the failure information.
+ */
+#define PSA_ASSERT_VIA_DRIVER( expr, expected_status )                  \
+    do {                                                                \
+        psa_status_t PSA_ASSERT_VIA_DRIVER_status = ( expr );           \
+        if( PSA_ASSERT_VIA_DRIVER_status == PSA_ERROR_DETECTED_BY_DRIVER ) \
+            goto exit;                                                  \
+        if( PSA_ASSERT_VIA_DRIVER_status != ( expected_status ) )       \
+        {                                                               \
+            test_fail( #expr, __LINE__, __FILE__ );                     \
+            goto exit;                                                  \
+        }                                                               \
+    } while( 0 )
+
 
 
 /****************************************************************/
@@ -54,8 +96,10 @@
 {
     (void) context;
     (void) attributes;
-    DRIVER_ASSERT( slot_number == validate_slot_number_directions.slot_number );
-    DRIVER_ASSERT( method == validate_slot_number_directions.method );
+    DRIVER_ASSERT_RETURN( slot_number ==
+                          validate_slot_number_directions.slot_number );
+    DRIVER_ASSERT_RETURN( method ==
+                          validate_slot_number_directions.method );
     return( validate_slot_number_directions.status );
 }
 
@@ -108,11 +152,11 @@
     (void) slot_number;
     (void) attributes;
 
-    DRIVER_ASSERT( *pubkey_length == 0 );
+    DRIVER_ASSERT_RETURN( *pubkey_length == 0 );
     if( ! PSA_KEY_TYPE_IS_KEY_PAIR( psa_get_key_type( attributes ) ) )
     {
-        DRIVER_ASSERT( pubkey == NULL );
-        DRIVER_ASSERT( pubkey_size == 0 );
+        DRIVER_ASSERT_RETURN( pubkey == NULL );
+        DRIVER_ASSERT_RETURN( pubkey_size == 0 );
     }
 
     return( PSA_SUCCESS );
@@ -146,6 +190,42 @@
     ram_min_slot = 0;
 }
 
+/* This function does everything except actually generating key material.
+ * After calling it, you must copy the desired key material to
+ * ram_slots[slot_number].content. */
+static psa_status_t ram_fake_generate( psa_drv_se_context_t *context,
+                                       psa_key_slot_number_t slot_number,
+                                       const psa_key_attributes_t *attributes,
+                                       uint8_t *pubkey,
+                                       size_t pubkey_size,
+                                       size_t *pubkey_length )
+{
+    (void) context;
+
+    DRIVER_ASSERT_RETURN( *pubkey_length == 0 );
+    if( ! PSA_KEY_TYPE_IS_KEY_PAIR( psa_get_key_type( attributes ) ) )
+    {
+        DRIVER_ASSERT_RETURN( pubkey == NULL );
+        DRIVER_ASSERT_RETURN( pubkey_size == 0 );
+    }
+
+    {
+        /* Check that the key can be stored in the memory slot.
+         * This check only works for key in a "raw" representation:
+         * symmetric keys or ECC are ok, but not RSA or FFDH. */
+        size_t required_storage =
+            PSA_BITS_TO_BYTES( psa_get_key_bits( attributes ) );
+        size_t available_storage = sizeof( ram_slots[slot_number].content );
+        if( required_storage > available_storage )
+            return( PSA_ERROR_INSUFFICIENT_STORAGE );
+    }
+
+    ram_slots[slot_number].lifetime = psa_get_key_lifetime( attributes );
+    ram_slots[slot_number].type = psa_get_key_type( attributes );
+    ram_slots[slot_number].bits = psa_get_key_bits( attributes );
+    return( PSA_SUCCESS );
+}
+
 static psa_status_t ram_import( psa_drv_se_context_t *context,
                                 psa_key_slot_number_t slot_number,
                                 const psa_key_attributes_t *attributes,
@@ -154,7 +234,7 @@
                                 size_t *bits )
 {
     (void) context;
-    DRIVER_ASSERT( slot_number < ARRAY_LENGTH( ram_slots ) );
+    DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) );
     if( data_length > sizeof( ram_slots[slot_number].content ) )
         return( PSA_ERROR_INSUFFICIENT_STORAGE );
     ram_slots[slot_number].lifetime = psa_get_key_lifetime( attributes );
@@ -173,7 +253,7 @@
 {
     size_t actual_size;
     (void) context;
-    DRIVER_ASSERT( slot_number < ARRAY_LENGTH( ram_slots ) );
+    DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) );
     actual_size = PSA_BITS_TO_BYTES( ram_slots[slot_number].bits );
     if( actual_size > data_size )
         return( PSA_ERROR_BUFFER_TOO_SMALL );
@@ -187,8 +267,8 @@
                                  psa_key_slot_number_t slot_number )
 {
     ram_slot_usage_t *slot_usage = persistent_data;
-    DRIVER_ASSERT( context->persistent_data_size == sizeof( ram_slot_usage_t ) );
-    DRIVER_ASSERT( slot_number < ARRAY_LENGTH( ram_slots ) );
+    DRIVER_ASSERT_RETURN( context->persistent_data_size == sizeof( ram_slot_usage_t ) );
+    DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) );
     memset( &ram_slots[slot_number], 0, sizeof( ram_slots[slot_number] ) );
     *slot_usage &= ~(ram_slot_usage_t)( 1 << slot_number );
     return( PSA_SUCCESS );
@@ -203,7 +283,7 @@
     ram_slot_usage_t *slot_usage = persistent_data;
     (void) attributes;
     (void) method;
-    DRIVER_ASSERT( context->persistent_data_size == sizeof( ram_slot_usage_t ) );
+    DRIVER_ASSERT_RETURN( context->persistent_data_size == sizeof( ram_slot_usage_t ) );
     for( *slot_number = ram_min_slot;
          *slot_number < ARRAY_LENGTH( ram_slots );
          ++( *slot_number ) )
@@ -228,6 +308,76 @@
     return( PSA_SUCCESS );
 }
 
+static psa_status_t ram_sign( psa_drv_se_context_t *context,
+                              psa_key_slot_number_t slot_number,
+                              psa_algorithm_t alg,
+                              const uint8_t *hash,
+                              size_t hash_length,
+                              uint8_t *signature,
+                              size_t signature_size,
+                              size_t *signature_length )
+{
+    ram_slot_t *slot;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_handle_t handle = 0;
+    psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+
+    (void) context;
+    DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) );
+    slot = &ram_slots[slot_number];
+
+    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN );
+    psa_set_key_algorithm( &attributes, alg );
+    psa_set_key_type( &attributes, slot->type );
+    DRIVER_ASSERT( psa_import_key( &attributes,
+                                   slot->content,
+                                   PSA_BITS_TO_BYTES( slot->bits ),
+                                   &handle ) == PSA_SUCCESS );
+    status = psa_asymmetric_sign( handle, alg,
+                                  hash, hash_length,
+                                  signature, signature_size,
+                                  signature_length );
+
+exit:
+    psa_destroy_key( handle );
+    return( status );
+}
+
+static psa_status_t ram_verify( psa_drv_se_context_t *context,
+                                psa_key_slot_number_t slot_number,
+                                psa_algorithm_t alg,
+                                const uint8_t *hash,
+                                size_t hash_length,
+                                const uint8_t *signature,
+                                size_t signature_length )
+{
+    ram_slot_t *slot;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_handle_t handle = 0;
+    psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+
+    (void) context;
+    DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) );
+    slot = &ram_slots[slot_number];
+
+    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_VERIFY );
+    psa_set_key_algorithm( &attributes, alg );
+    psa_set_key_type( &attributes, slot->type );
+    DRIVER_ASSERT( psa_import_key( &attributes,
+                                   slot->content,
+                                   PSA_BITS_TO_BYTES( slot->bits ),
+                                   &handle ) ==
+                   PSA_SUCCESS );
+    status = psa_asymmetric_verify( handle, alg,
+                                    hash, hash_length,
+                                    signature, signature_length );
+
+exit:
+    psa_destroy_key( handle );
+    return( status );
+}
+
+
 
 
 /****************************************************************/
@@ -709,7 +859,6 @@
 
 exit:
     PSA_DONE( );
-    ram_slots_reset( );
     psa_purge_storage( );
 }
 /* END_CASE */
@@ -746,7 +895,6 @@
 
 exit:
     PSA_DONE( );
-    ram_slots_reset( );
     psa_purge_storage( );
 }
 /* END_CASE */
@@ -804,6 +952,126 @@
 
 exit:
     PSA_DONE( );
+    psa_purge_storage( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void sign_verify( int sign_in_driver,
+                  int type_arg, int alg_arg,
+                  int bits_arg, data_t *key_material,
+                  data_t *input )
+{
+    psa_key_type_t type = type_arg;
+    psa_algorithm_t alg = alg_arg;
+    size_t bits = bits_arg;
+    /* Pass bits=0 to import, bits>0 to fake-generate */
+    int generating = ( bits != 0 );
+
+    psa_drv_se_t driver;
+    psa_drv_se_key_management_t key_management;
+    psa_drv_se_asymmetric_t asymmetric;
+
+    psa_key_lifetime_t lifetime = 2;
+    psa_key_id_t id = 1;
+    psa_key_handle_t drv_handle = 0; /* key managed by the driver */
+    psa_key_handle_t sw_handle = 0; /* transparent key */
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    uint8_t signature[PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE];
+    size_t signature_length;
+
+    memset( &driver, 0, sizeof( driver ) );
+    memset( &key_management, 0, sizeof( key_management ) );
+    driver.hal_version = PSA_DRV_SE_HAL_VERSION;
+    driver.key_management = &key_management;
+    driver.asymmetric = &asymmetric;
+    driver.persistent_data_size = sizeof( psa_key_slot_number_t );
+    driver.persistent_data_size = sizeof( ram_slot_usage_t );
+    key_management.p_allocate = ram_allocate;
+    key_management.p_destroy = ram_destroy;
+    if( generating )
+        key_management.p_generate = ram_fake_generate;
+    else
+        key_management.p_import = ram_import;
+    if( sign_in_driver )
+        asymmetric.p_sign = ram_sign;
+    asymmetric.p_verify = ram_verify;
+
+    PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) );
+    PSA_ASSERT( psa_crypto_init( ) );
+
+    /* Create two keys with the same key material: a transparent key,
+     * and one that goes through the driver. */
+    psa_set_key_usage_flags( &attributes,
+                             PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY );
+    psa_set_key_algorithm( &attributes, alg );
+    psa_set_key_type( &attributes, type );
+    PSA_ASSERT( psa_import_key( &attributes,
+                                key_material->x, key_material->len,
+                                &sw_handle ) );
+    psa_set_key_id( &attributes, id );
+    psa_set_key_lifetime( &attributes, lifetime );
+    if( generating )
+    {
+        psa_set_key_bits( &attributes, bits );
+        PSA_ASSERT( psa_generate_key( &attributes, &drv_handle ) );
+        /* Since we called a generate method that does not actually
+         * generate material, store the desired result of generation in
+         * the mock secure element storage. */
+        PSA_ASSERT( psa_get_key_attributes( drv_handle, &attributes ) );
+        TEST_ASSERT( key_material->len == PSA_BITS_TO_BYTES( bits ) );
+        memcpy( ram_slots[ram_min_slot].content, key_material->x,
+                key_material->len );
+    }
+    else
+    {
+        PSA_ASSERT( psa_import_key( &attributes,
+                                    key_material->x, key_material->len,
+                                    &drv_handle ) );
+    }
+
+    /* Sign with the chosen key. */
+    if( sign_in_driver )
+        PSA_ASSERT_VIA_DRIVER(
+            psa_asymmetric_sign( drv_handle,
+                                 alg,
+                                 input->x, input->len,
+                                 signature, sizeof( signature ),
+                                 &signature_length ),
+            PSA_SUCCESS );
+    else
+        PSA_ASSERT( psa_asymmetric_sign( sw_handle,
+                                         alg,
+                                         input->x, input->len,
+                                         signature, sizeof( signature ),
+                                         &signature_length ) );
+
+    /* Verify with both keys. */
+    PSA_ASSERT( psa_asymmetric_verify( sw_handle, alg,
+                                       input->x, input->len,
+                                       signature, signature_length ) );
+    PSA_ASSERT_VIA_DRIVER(
+        psa_asymmetric_verify( drv_handle, alg,
+                               input->x, input->len,
+                               signature, signature_length ),
+        PSA_SUCCESS );
+
+    /* Change the signature and verify again. */
+    signature[0] ^= 1;
+    TEST_EQUAL( psa_asymmetric_verify( sw_handle, alg,
+                                       input->x, input->len,
+                                       signature, signature_length ),
+                PSA_ERROR_INVALID_SIGNATURE );
+    PSA_ASSERT_VIA_DRIVER(
+        psa_asymmetric_verify( drv_handle, alg,
+                               input->x, input->len,
+                               signature, signature_length ),
+        PSA_ERROR_INVALID_SIGNATURE );
+
+exit:
+    psa_destroy_key( drv_handle );
+    psa_destroy_key( sw_handle );
+    PSA_DONE( );
     ram_slots_reset( );
     psa_purge_storage( );
 }