From 46d9439a5ec82d09b76d007f785cef74924f969c Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 5 Aug 2019 14:55:50 +0200 Subject: [PATCH] Support slot_number attribute when creating a key Allow the application to choose the slot number in a secure element, rather than always letting the driver choose. With this commit, any application may request any slot. In an implementation with isolation, it's up to the service to filter key creation requests and apply policies to limit which applications can request which slot. --- library/psa_crypto.c | 4 -- library/psa_crypto_se.c | 37 +++++++--- .../test_suite_psa_crypto_se_driver_hal.data | 9 +++ ...st_suite_psa_crypto_se_driver_hal.function | 70 +++++++++++++++++++ 4 files changed, 105 insertions(+), 15 deletions(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 5cb88de7e..856d8622d 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -1582,10 +1582,6 @@ static psa_status_t psa_start_key_creation( * we can roll back to a state where the key doesn't exist. */ if( *p_drv != NULL ) { - /* Choosing a slot number is not supported yet. */ - if( attributes->core.flags & MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER ) - return( PSA_ERROR_NOT_SUPPORTED ); - status = psa_find_se_slot_for_key( attributes, *p_drv, &slot->data.se.slot_number ); if( status != PSA_SUCCESS ) diff --git a/library/psa_crypto_se.c b/library/psa_crypto_se.c index bc7325180..ca38e2065 100644 --- a/library/psa_crypto_se.c +++ b/library/psa_crypto_se.c @@ -201,7 +201,6 @@ psa_status_t psa_find_se_slot_for_key( psa_key_slot_number_t *slot_number ) { psa_status_t status; - psa_drv_se_allocate_key_t p_allocate = NULL; /* If the lifetime is wrong, it's a bug in the library. */ if( driver->lifetime != psa_get_key_lifetime( attributes ) ) @@ -210,17 +209,33 @@ psa_status_t psa_find_se_slot_for_key( /* If the driver doesn't support key creation in any way, give up now. */ if( driver->methods->key_management == NULL ) return( PSA_ERROR_NOT_SUPPORTED ); - p_allocate = driver->methods->key_management->p_allocate; - /* If the driver doesn't tell us how to allocate a slot, that's - * not supported for the time being. */ - if( p_allocate == NULL ) - return( PSA_ERROR_NOT_SUPPORTED ); - - status = p_allocate( &driver->context, - driver->internal.persistent_data, - attributes, - slot_number ); + if( psa_get_key_slot_number( attributes, slot_number ) == PSA_SUCCESS ) + { + /* The application wants to use a specific slot. Allow it if + * the driver supports it. On a system with isolation, + * the crypto service must check that the application is + * permitted to request this slot. */ + psa_drv_se_validate_slot_number_t p_validate_slot_number = + driver->methods->key_management->p_validate_slot_number; + if( p_validate_slot_number == NULL ) + return( PSA_ERROR_NOT_SUPPORTED ); + status = p_validate_slot_number( &driver->context, attributes, + *slot_number ); + } + else + { + /* The application didn't tell us which slot to use. Let the driver + * choose. This is the normal case. */ + psa_drv_se_allocate_key_t p_allocate = + driver->methods->key_management->p_allocate; + if( p_allocate == NULL ) + return( PSA_ERROR_NOT_SUPPORTED ); + status = p_allocate( &driver->context, + driver->internal.persistent_data, + attributes, + slot_number ); + } return( status ); } 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 6fb65f02a..57aa47f76 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal.data +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.data @@ -39,6 +39,15 @@ key_creation_import_export:0:1 SE key import-export, check after restart (slot 3) key_creation_import_export:3:1 +Key creation in a specific slot (0) +key_creation_in_chosen_slot:0:PSA_SUCCESS + +Key creation in a specific slot (max) +key_creation_in_chosen_slot:ARRAY_LENGTH( ram_slots ) - 1:PSA_SUCCESS + +Key creation in a specific slot (too large) +key_creation_in_chosen_slot:ARRAY_LENGTH( ram_slots ):PSA_ERROR_INVALID_ARGUMENT + Key creation smoke test: AES-CTR key_creation_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CTR:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 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 9a5746476..8924ae1e7 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal.function +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.function @@ -177,6 +177,18 @@ static psa_status_t ram_allocate( psa_drv_se_context_t *context, return( PSA_ERROR_INSUFFICIENT_STORAGE ); } +static psa_status_t ram_validate_slot_number( + psa_drv_se_context_t *context, + const psa_key_attributes_t *attributes, + psa_key_slot_number_t slot_number ) +{ + (void) context; + (void) attributes; + if( slot_number >= ARRAY_LENGTH( ram_slots ) ) + return( PSA_ERROR_INVALID_ARGUMENT ); + return( PSA_SUCCESS ); +} + /****************************************************************/ @@ -536,6 +548,64 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void key_creation_in_chosen_slot( int slot_arg, + int expected_status_arg ) +{ + psa_key_slot_number_t wanted_slot = slot_arg; + psa_status_t expected_status = expected_status_arg; + psa_status_t status; + psa_drv_se_t driver; + psa_drv_se_key_management_t key_management; + psa_key_lifetime_t lifetime = 2; + psa_key_id_t id = 1; + psa_key_handle_t handle = 0; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + const uint8_t key_material[3] = {0xfa, 0xca, 0xde}; + + 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.persistent_data_size = sizeof( ram_slot_usage_t ); + key_management.p_validate_slot_number = ram_validate_slot_number; + key_management.p_import = ram_import; + key_management.p_destroy = ram_destroy; + key_management.p_export = ram_export; + + PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) ); + PSA_ASSERT( psa_crypto_init( ) ); + + /* Create a key. */ + psa_set_key_id( &attributes, id ); + psa_set_key_lifetime( &attributes, lifetime ); + psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_EXPORT ); + psa_set_key_type( &attributes, PSA_KEY_TYPE_RAW_DATA ); + psa_set_key_slot_number( &attributes, wanted_slot ); + status = psa_import_key( &attributes, + key_material, sizeof( key_material ), + &handle ); + TEST_EQUAL( status, expected_status ); + + if( status == PSA_SUCCESS ) + { + /* Test that the key was created in the expected slot. */ + TEST_EQUAL( ram_slots[wanted_slot].type, PSA_KEY_TYPE_RAW_DATA ); + + /* Test that the key is reported with the correct attributes, + * including the expected slot. */ + PSA_ASSERT( psa_get_key_attributes( handle, &attributes ) ); + + PSA_ASSERT( psa_destroy_key( handle ) ); + } + +exit: + PSA_DONE( ); + ram_slots_reset( ); + psa_purge_storage( ); +} +/* END_CASE */ + /* BEGIN_CASE */ void key_creation_smoke( int type_arg, int alg_arg, data_t *key_material )