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( );
}