From 3efcebbc5e9852082f06590f9325d53cf405e80f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 1 Oct 2019 14:18:35 +0200 Subject: [PATCH 1/6] SE support: Use a transaction when registering a key When registering a key in a secure element, go through the transaction mechanism. This makes the code simpler, at the expense of a few extra storage operations. Given that registering a key is typically very rare over the lifetime of a device, this is an acceptable loss. Drivers must now have a p_validate_slot_number method, otherwise registering a key is not possible. This reduces the risk that due to a mistake during the integration of a device, an application might claim a slot in a way that is not supported by the driver. --- include/psa/crypto_extra.h | 3 ++ library/psa_crypto.c | 42 ++++--------------- library/psa_crypto_se.c | 6 +++ .../test_suite_psa_crypto_se_driver_hal.data | 26 ++++++------ 4 files changed, 30 insertions(+), 47 deletions(-) diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h index f0e47821c..99bb0635a 100644 --- a/include/psa/crypto_extra.h +++ b/include/psa/crypto_extra.h @@ -186,6 +186,9 @@ static inline void psa_clear_key_slot_number( * \retval #PSA_ERROR_ALREADY_EXISTS * There is already a key with the identifier specified in * \p attributes. + * \retval #PSA_ERROR_NOT_SUPPORTED + * The secure element driver for the specified lifetime does not + * support registering a key. * \retval #PSA_ERROR_INVALID_ARGUMENT * \p attributes specifies a lifetime which is not located * in a secure element. diff --git a/library/psa_crypto.c b/library/psa_crypto.c index b9ea00f2c..90158f852 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -1579,7 +1579,7 @@ static psa_status_t psa_start_key_creation( #if defined(MBEDTLS_PSA_CRYPTO_SE_C) /* For a key in a secure element, we need to do three things - * when creating a key (but not when registering an existing key): + * when creating or registering a key: * create the key file in internal storage, create the * key inside the secure element, and update the driver's * persistent data. Start a transaction that will encompass these @@ -1592,7 +1592,7 @@ static psa_status_t psa_start_key_creation( * secure element driver updates its persistent state, but we do not yet * save the driver's persistent state, so that if the power fails, * we can roll back to a state where the key doesn't exist. */ - if( *p_drv != NULL && method != PSA_KEY_CREATION_REGISTER ) + if( *p_drv != NULL ) { status = psa_find_se_slot_for_key( attributes, method, *p_drv, &slot->data.se.slot_number ); @@ -1609,6 +1609,12 @@ static psa_status_t psa_start_key_creation( return( status ); } } + + if( *p_drv == NULL && method == PSA_KEY_CREATION_REGISTER ) + { + /* Key registration only makes sense with a secure element. */ + return( PSA_ERROR_INVALID_ARGUMENT ); + } #endif /* MBEDTLS_PSA_CRYPTO_SE_C */ return( status ); @@ -1883,7 +1889,6 @@ psa_status_t mbedtls_psa_register_se_key( psa_status_t status; psa_key_slot_t *slot = NULL; psa_se_drv_table_entry_t *driver = NULL; - const psa_drv_se_t *drv; psa_key_handle_t handle = 0; /* Leaving attributes unspecified is not currently supported. @@ -1900,37 +1905,6 @@ psa_status_t mbedtls_psa_register_se_key( if( status != PSA_SUCCESS ) goto exit; - if( driver == NULL ) - { - status = PSA_ERROR_INVALID_ARGUMENT; - goto exit; - } - drv = psa_get_se_driver_methods( driver ); - - if ( psa_get_key_slot_number( attributes, - &slot->data.se.slot_number ) != PSA_SUCCESS ) - { - /* The application didn't specify a slot number. This doesn't - * make sense when registering a slot. */ - status = PSA_ERROR_INVALID_ARGUMENT; - goto exit; - } - - /* If the driver has a slot number validation method, call it. - * If it doesn't, it means the secure element is unable to validate - * anything and so we have to trust the application. */ - if( drv->key_management != NULL && - drv->key_management->p_validate_slot_number != NULL ) - { - status = drv->key_management->p_validate_slot_number( - psa_get_se_driver_context( driver ), - attributes, - PSA_KEY_CREATION_REGISTER, - slot->data.se.slot_number ); - if( status != PSA_SUCCESS ) - goto exit; - } - status = psa_finish_key_creation( slot, driver ); exit: diff --git a/library/psa_crypto_se.c b/library/psa_crypto_se.c index 523c62105..2cda4ccdc 100644 --- a/library/psa_crypto_se.c +++ b/library/psa_crypto_se.c @@ -225,6 +225,12 @@ psa_status_t psa_find_se_slot_for_key( attributes, method, *slot_number ); } + else if( method == PSA_KEY_CREATION_REGISTER ) + { + /* The application didn't specify a slot number. This doesn't + * make sense when registering a slot. */ + return( PSA_ERROR_INVALID_ARGUMENT ); + } else { /* The application didn't tell us which slot to use. Let the 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 53e3fc5b8..1b0ef0494 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal.data +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.data @@ -121,23 +121,23 @@ Key generation smoke test: HMAC-SHA-256 generate_key_smoke:PSA_KEY_TYPE_HMAC:256:PSA_ALG_HMAC( PSA_ALG_SHA_256 ) Key registration: smoke test -register_key_smoke_test:MIN_DRIVER_LIFETIME:-1:PSA_SUCCESS - -Key registration: invalid lifetime (volatile) -register_key_smoke_test:PSA_KEY_LIFETIME_VOLATILE:-1:PSA_ERROR_INVALID_ARGUMENT - -Key registration: invalid lifetime (internal storage) -register_key_smoke_test:PSA_KEY_LIFETIME_PERSISTENT:-1:PSA_ERROR_INVALID_ARGUMENT - -Key registration: invalid lifetime (no registered driver) -register_key_smoke_test:MIN_DRIVER_LIFETIME + 1:-1:PSA_ERROR_INVALID_ARGUMENT - -Key registration: with driver validation (accepted) register_key_smoke_test:MIN_DRIVER_LIFETIME:1:PSA_SUCCESS -Key registration: with driver validation (rejected) +Key registration: invalid lifetime (volatile) +register_key_smoke_test:PSA_KEY_LIFETIME_VOLATILE:1:PSA_ERROR_INVALID_ARGUMENT + +Key registration: invalid lifetime (internal storage) +register_key_smoke_test:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_ERROR_INVALID_ARGUMENT + +Key registration: invalid lifetime (no registered driver) +register_key_smoke_test:MIN_DRIVER_LIFETIME + 1:1:PSA_ERROR_INVALID_ARGUMENT + +Key registration: rejected register_key_smoke_test:MIN_DRIVER_LIFETIME:0:PSA_ERROR_NOT_PERMITTED +Key registration: not supported +register_key_smoke_test:MIN_DRIVER_LIFETIME:-1:PSA_ERROR_NOT_SUPPORTED + Import-sign-verify: sign in driver, ECDSA depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED sign_verify:SIGN_IN_DRIVER_AND_PARALLEL_CREATION:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:0:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" From 5ec3a30edb344760738f565f83d193a2fe6bad79 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 1 Oct 2019 14:27:23 +0200 Subject: [PATCH 2/6] SE driver: validate_slot_number: support changing persistent data Add a parameter to the p_validate_slot_number method to allow the driver to modify the persistent data. With the current structure of the core, the persistent data is already updated. All it took was adding a way to modify it. --- include/psa/crypto_se_driver.h | 8 ++++++++ library/psa_crypto_se.c | 1 + tests/suites/test_suite_psa_crypto_se_driver_hal.function | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/include/psa/crypto_se_driver.h b/include/psa/crypto_se_driver.h index a43e0db48..7ac1ed1c4 100644 --- a/include/psa/crypto_se_driver.h +++ b/include/psa/crypto_se_driver.h @@ -927,7 +927,14 @@ typedef psa_status_t (*psa_drv_se_allocate_key_t)( * sake of initial device provisioning or onboarding. Such a mechanism may * be added to a future version of the PSA Cryptography API specification. * + * This function may update the driver's persistent data through + * \p persistent_data. The core will save the updated persistent data at the + * end of the key creation process. See the description of + * ::psa_drv_se_allocate_key_t for more information. + * * \param[in,out] drv_context The driver context structure. + * \param[in,out] persistent_data A pointer to the persistent data + * that allows writing. * \param[in] attributes Attributes of the key. * \param method The way in which the key is being created. * \param[in] key_slot Slot where the key is to be stored. @@ -946,6 +953,7 @@ typedef psa_status_t (*psa_drv_se_allocate_key_t)( */ typedef psa_status_t (*psa_drv_se_validate_slot_number_t)( psa_drv_se_context_t *drv_context, + void *persistent_data, const psa_key_attributes_t *attributes, psa_key_creation_method_t method, psa_key_slot_number_t key_slot); diff --git a/library/psa_crypto_se.c b/library/psa_crypto_se.c index 2cda4ccdc..81b310367 100644 --- a/library/psa_crypto_se.c +++ b/library/psa_crypto_se.c @@ -222,6 +222,7 @@ psa_status_t psa_find_se_slot_for_key( if( p_validate_slot_number == NULL ) return( PSA_ERROR_NOT_SUPPORTED ); status = p_validate_slot_number( &driver->context, + driver->internal.persistent_data, attributes, method, *slot_number ); } 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 fc6f66816..539c563c4 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal.function +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.function @@ -90,11 +90,13 @@ static validate_slot_number_directions_t validate_slot_number_directions; /* Validate a choice of slot number as directed. */ static psa_status_t validate_slot_number_as_directed( psa_drv_se_context_t *context, + void *persistent_data, const psa_key_attributes_t *attributes, psa_key_creation_method_t method, psa_key_slot_number_t slot_number ) { (void) context; + (void) persistent_data; (void) attributes; DRIVER_ASSERT_RETURN( slot_number == validate_slot_number_directions.slot_number ); @@ -367,11 +369,13 @@ static psa_status_t ram_allocate( psa_drv_se_context_t *context, static psa_status_t ram_validate_slot_number( psa_drv_se_context_t *context, + void *persistent_data, const psa_key_attributes_t *attributes, psa_key_creation_method_t method, psa_key_slot_number_t slot_number ) { (void) context; + (void) persistent_data; (void) attributes; (void) method; if( slot_number >= ARRAY_LENGTH( ram_slots ) ) From d9348f218e708dc99a300f624f4c1ccea0949109 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 1 Oct 2019 15:22:29 +0200 Subject: [PATCH 3/6] SE driver: call the p_init method during psa_crypto_init() --- library/psa_crypto.c | 6 ++ library/psa_crypto_se.c | 22 +++++++ library/psa_crypto_se.h | 6 ++ ..._suite_psa_crypto_se_driver_hal_mocks.data | 9 +++ ...te_psa_crypto_se_driver_hal_mocks.function | 57 +++++++++++++++++++ 5 files changed, 100 insertions(+) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 90158f852..e26a7ec01 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -5687,6 +5687,12 @@ psa_status_t psa_crypto_init( void ) if( status != PSA_SUCCESS ) goto exit; +#if defined(MBEDTLS_PSA_CRYPTO_SE_C) + status = psa_init_all_se_drivers( ); + if( status != PSA_SUCCESS ) + goto exit; +#endif /* MBEDTLS_PSA_CRYPTO_SE_C */ + #if defined(PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS) status = psa_crypto_load_transaction( ); if( status == PSA_SUCCESS ) diff --git a/library/psa_crypto_se.c b/library/psa_crypto_se.c index 81b310367..81f0a1a8f 100644 --- a/library/psa_crypto_se.c +++ b/library/psa_crypto_se.c @@ -272,6 +272,28 @@ psa_status_t psa_destroy_se_key( psa_se_drv_table_entry_t *driver, return( status == PSA_SUCCESS ? storage_status : status ); } +psa_status_t psa_init_all_se_drivers( void ) +{ + size_t i; + for( i = 0; i < PSA_MAX_SE_DRIVERS; i++ ) + { + psa_se_drv_table_entry_t *driver = &driver_table[i]; + if( driver->lifetime == 0 ) + continue; /* skipping unused entry */ + const psa_drv_se_t *methods = psa_get_se_driver_methods( driver ); + if( methods->p_init != NULL ) + { + psa_status_t status = methods->p_init( + &driver->context, + driver->internal.persistent_data, + driver->lifetime ); + if( status != PSA_SUCCESS ) + return( status ); + } + } + return( PSA_SUCCESS ); +} + /****************************************************************/ diff --git a/library/psa_crypto_se.h b/library/psa_crypto_se.h index 900a72bd3..86bf7a7b1 100644 --- a/library/psa_crypto_se.h +++ b/library/psa_crypto_se.h @@ -66,6 +66,12 @@ */ void psa_unregister_all_se_drivers( void ); +/** Initialize all secure element drivers. + * + * Called from psa_crypto_init(). + */ +psa_status_t psa_init_all_se_drivers( void ); + /** A structure that describes a registered secure element driver. * * A secure element driver table entry contains a pointer to the diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal_mocks.data b/tests/suites/test_suite_psa_crypto_se_driver_hal_mocks.data index dba68758f..f60bd7602 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal_mocks.data +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal_mocks.data @@ -1,3 +1,12 @@ +SE init mock test: success +mock_init:2:PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS:1 + +SE init mock test: failure +mock_init:2:PSA_SUCCESS:PSA_ERROR_HARDWARE_FAILURE:PSA_ERROR_HARDWARE_FAILURE:1 + +SE init mock test: invalid lifetime +mock_init:1:PSA_ERROR_INVALID_ARGUMENT:PSA_ERROR_BAD_STATE:PSA_SUCCESS:0 + SE key importing mock test mock_import:PSA_SUCCESS:PSA_SUCCESS:0:PSA_SUCCESS diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal_mocks.function b/tests/suites/test_suite_psa_crypto_se_driver_hal_mocks.function index e6b3f7b1f..7088a5226 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal_mocks.function +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal_mocks.function @@ -5,6 +5,13 @@ #include "psa_crypto_se.h" #include "psa_crypto_storage.h" +static struct +{ + uint16_t called; + psa_key_lifetime_t lifetime; + psa_status_t return_value; +} mock_init_data; + static struct { uint16_t called; @@ -92,6 +99,7 @@ static void psa_purge_storage( void ) static void mock_teardown( void ) { + memset( &mock_init_data, 0, sizeof( mock_init_data ) ); memset( &mock_import_data, 0, sizeof( mock_import_data ) ); memset( &mock_export_data, 0, sizeof( mock_export_data ) ); memset( &mock_export_public_data, 0, sizeof( mock_export_public_data ) ); @@ -103,6 +111,18 @@ static void mock_teardown( void ) psa_purge_storage( ); } +static psa_status_t mock_init( psa_drv_se_context_t *drv_context, + void *persistent_data, + psa_key_lifetime_t lifetime ) +{ + (void) drv_context; + (void) persistent_data; + + mock_init_data.called++; + mock_init_data.lifetime = lifetime; + return( mock_init_data.return_value ); +} + static psa_status_t mock_generate( psa_drv_se_context_t *drv_context, psa_key_slot_number_t key_slot, const psa_key_attributes_t *attributes, @@ -258,6 +278,42 @@ psa_status_t mock_destroy( psa_drv_se_context_t *context, * END_DEPENDENCIES */ +/* BEGIN_CASE */ +void mock_init( int lifetime_arg, + int expected_register_status_arg, + int driver_status_arg, + int expected_psa_status_arg, + int expected_called ) +{ + psa_key_lifetime_t lifetime = lifetime_arg; + psa_status_t expected_register_status = expected_register_status_arg; + psa_status_t driver_status = driver_status_arg; + psa_status_t expected_psa_status = expected_psa_status_arg; + psa_drv_se_t driver = { + .hal_version = PSA_DRV_SE_HAL_VERSION, + .p_init = mock_init, + }; + int psa_crypto_init_called = 0; + + mock_init_data.return_value = driver_status; + + TEST_EQUAL( psa_register_se_driver( lifetime, &driver ), + expected_register_status ); + + psa_crypto_init_called = 1; + TEST_EQUAL( psa_crypto_init( ), expected_psa_status ); + + TEST_EQUAL( mock_init_data.called, expected_called ); + if( expected_called ) + TEST_EQUAL( mock_init_data.lifetime, lifetime ); + +exit: + if( psa_crypto_init_called ) + PSA_DONE( ); + mock_teardown( ); +} +/* END_CASE */ + /* BEGIN_CASE */ void mock_import( int mock_alloc_return_value, int mock_import_return_value, @@ -335,6 +391,7 @@ void mock_export( int mock_export_return_value, int expected_result ) memset( &key_management, 0, sizeof( key_management ) ); driver.hal_version = PSA_DRV_SE_HAL_VERSION; driver.key_management = &key_management; + driver.p_init = mock_init; key_management.p_import = mock_import; key_management.p_export = mock_export; key_management.p_destroy = mock_destroy; From c84c70a83c98e4020868be4f3c961b1cbcb18bb6 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 1 Oct 2019 15:41:42 +0200 Subject: [PATCH 4/6] SE driver: save the persistent data after calling p_init --- library/psa_crypto_se.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/psa_crypto_se.c b/library/psa_crypto_se.c index 81f0a1a8f..11604c219 100644 --- a/library/psa_crypto_se.c +++ b/library/psa_crypto_se.c @@ -289,6 +289,9 @@ psa_status_t psa_init_all_se_drivers( void ) driver->lifetime ); if( status != PSA_SUCCESS ) return( status ); + status = psa_save_se_persistent_data( driver ); + if( status != PSA_SUCCESS ) + return( status ); } } return( PSA_SUCCESS ); From d5536d8a5b9187a1e4648cbac9c1168aeba2421c Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 1 Oct 2019 16:55:29 +0200 Subject: [PATCH 5/6] SE driver: Fix loading of persistent data The persistent data was not loaded correctly (the code was loading 0 bytes instead of the correct size). --- library/psa_crypto_se.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/psa_crypto_se.c b/library/psa_crypto_se.c index 11604c219..b7fa0c5c5 100644 --- a/library/psa_crypto_se.c +++ b/library/psa_crypto_se.c @@ -341,6 +341,8 @@ psa_status_t psa_register_se_driver( driver_table[i].lifetime = lifetime; driver_table[i].methods = methods; + driver_table[i].internal.persistent_data_size = + methods->persistent_data_size; if( methods->persistent_data_size != 0 ) { @@ -358,8 +360,6 @@ psa_status_t psa_register_se_driver( if( status != PSA_SUCCESS && status != PSA_ERROR_DOES_NOT_EXIST ) goto error; } - driver_table[i].internal.persistent_data_size = - methods->persistent_data_size; return( PSA_SUCCESS ); From e1ee8f157c5f8525e4d66be1a97b56743ee099a8 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 1 Oct 2019 16:56:27 +0200 Subject: [PATCH 6/6] Test that SE driver persistent data is saved correctly Add invasive checks that peek at the stored persistent data after some successful import, generation or destruction operations and after reinitialization to ensure that the persistent data in storage has the expected content. --- ...st_suite_psa_crypto_se_driver_hal.function | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) 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 539c563c4..61fb91805 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal.function +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.function @@ -5,6 +5,13 @@ #include "psa_crypto_se.h" #include "psa_crypto_storage.h" +/* Invasive peeking: check the persistent data */ +#if defined(MBEDTLS_PSA_ITS_FILE_C) +#include "psa_crypto_its.h" +#else /* Native ITS implementation */ +#include "psa/error.h" +#include "psa/internal_trusted_storage.h" +#endif /****************************************************************/ @@ -106,6 +113,11 @@ static psa_status_t validate_slot_number_as_directed( } /* Allocate slot numbers with a monotonic counter. */ +static psa_key_slot_number_t shadow_counter; +static void counter_reset( void ) +{ + shadow_counter = 0; +} static psa_status_t counter_allocate( psa_drv_se_context_t *context, void *persistent_data, const psa_key_attributes_t *attributes, @@ -120,6 +132,7 @@ static psa_status_t counter_allocate( psa_drv_se_context_t *context, ++*p_counter; if( *p_counter == 0 ) return( PSA_ERROR_INSUFFICIENT_STORAGE ); + shadow_counter = *p_counter; *slot_number = *p_counter; return( PSA_SUCCESS ); } @@ -195,12 +208,15 @@ static ram_slot_t ram_slots[16]; * bit vector indicating which slots are in use. */ typedef uint16_t ram_slot_usage_t; +static ram_slot_usage_t ram_shadow_slot_usage; + static uint8_t ram_min_slot = 0; static void ram_slots_reset( void ) { memset( ram_slots, 0, sizeof( ram_slots ) ); ram_min_slot = 0; + ram_shadow_slot_usage = 0; } /* Common parts of key creation. @@ -344,6 +360,7 @@ static psa_status_t ram_destroy( psa_drv_se_context_t *context, 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 ); + ram_shadow_slot_usage = *slot_usage; return( PSA_SUCCESS ); } @@ -362,7 +379,10 @@ static psa_status_t ram_allocate( psa_drv_se_context_t *context, ++( *slot_number ) ) { if( ! ( *slot_usage & 1 << *slot_number ) ) + { + ram_shadow_slot_usage = *slot_usage; return( PSA_SUCCESS ); + } } return( PSA_ERROR_INSUFFICIENT_STORAGE ); } @@ -526,6 +546,37 @@ exit: return( ok ); } +/* Get the file UID corresponding to the specified lifetime. + * If this changes, the storage format version must change. + * See psa_get_se_driver_its_file_uid() in psa_crypto_se.c. + */ +psa_storage_uid_t file_uid_for_lifetime( psa_key_lifetime_t lifetime ) +{ + if( lifetime > PSA_MAX_SE_LIFETIME ) + return( 0 ); + return( 0xfffffe00 + lifetime ); +} + +/* Check that the persistent data of a driver has its expected content. */ +static int check_persistent_data( psa_key_lifetime_t lifetime, + const void *expected_data, + size_t size ) +{ + psa_storage_uid_t uid = file_uid_for_lifetime( lifetime ); + struct psa_storage_info_t info; + uint8_t *loaded = NULL; + + PSA_ASSERT( psa_its_get_info( uid, &info ) ); + ASSERT_ALLOC( loaded, info.size ); + PSA_ASSERT( psa_its_get( uid, 0, info.size, loaded, NULL ) ); + ASSERT_COMPARE( expected_data, size, loaded, info.size ); + return( 1 ); + +exit: + mbedtls_free( loaded ); + return( 0 ); +} + /* Check that a function's return status is "smoke-free", i.e. that * it's an acceptable error code when calling an API function that operates * on a key with potentially bogus parameters. */ @@ -780,6 +831,10 @@ void key_creation_import_export( int min_slot, int restart ) PSA_ASSERT( psa_import_key( &attributes, key_material, sizeof( key_material ), &handle ) ); + if( ! check_persistent_data( lifetime, + &ram_shadow_slot_usage, + sizeof( ram_shadow_slot_usage ) ) ) + goto exit; /* Maybe restart, to check that the information is saved correctly. */ if( restart ) @@ -787,6 +842,10 @@ void key_creation_import_export( int min_slot, int restart ) mbedtls_psa_crypto_free( ); PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) ); PSA_ASSERT( psa_crypto_init( ) ); + if( ! check_persistent_data( lifetime, + &ram_shadow_slot_usage, + sizeof( ram_shadow_slot_usage ) ) ) + goto exit; PSA_ASSERT( psa_open_key( id, &handle ) ); } @@ -809,6 +868,10 @@ void key_creation_import_export( int min_slot, int restart ) PSA_ASSERT( psa_destroy_key( handle ) ); handle = 0; + if( ! check_persistent_data( lifetime, + &ram_shadow_slot_usage, + sizeof( ram_shadow_slot_usage ) ) ) + goto exit; TEST_EQUAL( psa_open_key( id, &handle ), PSA_ERROR_DOES_NOT_EXIST ); @@ -864,6 +927,10 @@ void key_creation_in_chosen_slot( int slot_arg, if( status != PSA_SUCCESS ) goto exit; + if( ! check_persistent_data( lifetime, + &ram_shadow_slot_usage, + sizeof( ram_shadow_slot_usage ) ) ) + goto exit; /* Maybe restart, to check that the information is saved correctly. */ if( restart ) @@ -871,6 +938,10 @@ void key_creation_in_chosen_slot( int slot_arg, mbedtls_psa_crypto_free( ); PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) ); PSA_ASSERT( psa_crypto_init( ) ); + if( ! check_persistent_data( lifetime, + &ram_shadow_slot_usage, + sizeof( ram_shadow_slot_usage ) ) ) + goto exit; PSA_ASSERT( psa_open_key( id, &handle ) ); } @@ -883,6 +954,10 @@ void key_creation_in_chosen_slot( int slot_arg, PSA_ASSERT( psa_destroy_key( handle ) ); handle = 0; + if( ! check_persistent_data( lifetime, + &ram_shadow_slot_usage, + sizeof( ram_shadow_slot_usage ) ) ) + goto exit; TEST_EQUAL( psa_open_key( id, &handle ), PSA_ERROR_DOES_NOT_EXIST ); @@ -930,6 +1005,9 @@ void import_key_smoke( int type_arg, int alg_arg, PSA_ASSERT( psa_import_key( &attributes, key_material->x, key_material->len, &handle ) ); + if( ! check_persistent_data( lifetime, + &shadow_counter, sizeof( shadow_counter ) ) ) + goto exit; /* Do stuff with the key. */ if( ! smoke_test_key( handle ) ) @@ -939,6 +1017,9 @@ void import_key_smoke( int type_arg, int alg_arg, mbedtls_psa_crypto_free( ); PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) ); PSA_ASSERT( psa_crypto_init( ) ); + if( ! check_persistent_data( lifetime, + &shadow_counter, sizeof( shadow_counter ) ) ) + goto exit; PSA_ASSERT( psa_open_key( id, &handle ) ); if( ! smoke_test_key( handle ) ) goto exit; @@ -946,11 +1027,15 @@ void import_key_smoke( int type_arg, int alg_arg, /* We're done. */ PSA_ASSERT( psa_destroy_key( handle ) ); handle = 0; + if( ! check_persistent_data( lifetime, + &shadow_counter, sizeof( shadow_counter ) ) ) + goto exit; TEST_EQUAL( psa_open_key( id, &handle ), PSA_ERROR_DOES_NOT_EXIST ); exit: PSA_DONE( ); + counter_reset( ); psa_purge_storage( ); } /* END_CASE */ @@ -987,6 +1072,7 @@ void generate_key_not_supported( int type_arg, int bits_arg ) exit: PSA_DONE( ); + counter_reset( ); psa_purge_storage( ); } /* END_CASE */ @@ -1027,6 +1113,9 @@ void generate_key_smoke( int type_arg, int bits_arg, int alg_arg ) psa_set_key_type( &attributes, type ); psa_set_key_bits( &attributes, bits ); PSA_ASSERT( psa_generate_key( &attributes, &handle ) ); + if( ! check_persistent_data( lifetime, + &shadow_counter, sizeof( shadow_counter ) ) ) + goto exit; /* Do stuff with the key. */ if( ! smoke_test_key( handle ) ) @@ -1036,6 +1125,9 @@ void generate_key_smoke( int type_arg, int bits_arg, int alg_arg ) mbedtls_psa_crypto_free( ); PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) ); PSA_ASSERT( psa_crypto_init( ) ); + if( ! check_persistent_data( lifetime, + &shadow_counter, sizeof( shadow_counter ) ) ) + goto exit; PSA_ASSERT( psa_open_key( id, &handle ) ); if( ! smoke_test_key( handle ) ) goto exit; @@ -1043,11 +1135,15 @@ void generate_key_smoke( int type_arg, int bits_arg, int alg_arg ) /* We're done. */ PSA_ASSERT( psa_destroy_key( handle ) ); handle = 0; + if( ! check_persistent_data( lifetime, + &shadow_counter, sizeof( shadow_counter ) ) ) + goto exit; TEST_EQUAL( psa_open_key( id, &handle ), PSA_ERROR_DOES_NOT_EXIST ); exit: PSA_DONE( ); + counter_reset( ); psa_purge_storage( ); } /* END_CASE */