Skip to content

Commit b231d99

Browse files
Merge pull request #202 from gilles-peskine-arm/psa-se_driver-choose_key_slot_number
Let applications create a key in a specific secure element slot
2 parents fdbc544 + 9d75202 commit b231d99

File tree

5 files changed

+196
-16
lines changed

5 files changed

+196
-16
lines changed

include/psa/crypto_se_driver.h

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,42 @@ typedef struct {
811811
/**@{*/
812812

813813
/** \brief A function that allocates a slot for a key.
814+
*
815+
* To create a key in a specific slot in a secure element, the core
816+
* first calls this function to determine a valid slot number,
817+
* then calls a function to create the key material in that slot.
818+
* For example, in nominal conditions (that is, if no error occurs),
819+
* the effect of a call to psa_import_key() with a lifetime that places
820+
* the key in a secure element is the following:
821+
* -# The core calls psa_drv_se_key_management_t::p_allocate
822+
* (or in some implementations
823+
* psa_drv_se_key_management_t::p_validate_slot_number). The driver
824+
* selects (or validates) a suitable slot number given the key attributes
825+
* and the state of the secure element.
826+
* -# The core calls psa_drv_se_key_management_t::p_import to import
827+
* the key material in the selected slot.
828+
*
829+
* Other key creation methods lead to similar sequences. For example, the
830+
* sequence for psa_generate_key() is the same except that the second step
831+
* is a call to psa_drv_se_key_management_t::p_generate.
832+
*
833+
* In case of errors, other behaviors are possible.
834+
* - If the PSA Cryptography subsystem dies after the first step,
835+
* for example because the device has lost power abruptly,
836+
* the second step may never happen, or may happen after a reset
837+
* and re-initialization. Alternatively, after a reset and
838+
* re-initialization, the core may call
839+
* psa_drv_se_key_management_t::p_destroy on the slot number that
840+
* was allocated (or validated) instead of calling a key creation function.
841+
* - If an error occurs, the core may call
842+
* psa_drv_se_key_management_t::p_destroy on the slot number that
843+
* was allocated (or validated) instead of calling a key creation function.
844+
*
845+
* Errors and system resets also have an impact on the driver's persistent
846+
* data. If a reset happens before the overall key creation process is
847+
* completed (before or after the second step above), it is unspecified
848+
* whether the persistent data after the reset is identical to what it
849+
* was before or after the call to `p_allocate` (or `p_validate_slot_number`).
814850
*
815851
* \param[in,out] drv_context The driver context structure.
816852
* \param[in,out] persistent_data A pointer to the persistent data
@@ -833,6 +869,42 @@ typedef psa_status_t (*psa_drv_se_allocate_key_t)(
833869
const psa_key_attributes_t *attributes,
834870
psa_key_slot_number_t *key_slot);
835871

872+
/** \brief A function that determines whether a slot number is valid
873+
* for a key.
874+
*
875+
* To create a key in a specific slot in a secure element, the core
876+
* first calls this function to validate the choice of slot number,
877+
* then calls a function to create the key material in that slot.
878+
* See the documentation of #psa_drv_se_allocate_key_t for more details.
879+
*
880+
* As of the PSA Cryptography API specification version 1.0, there is no way
881+
* for applications to trigger a call to this function. However some
882+
* implementations offer the capability to create or declare a key in
883+
* a specific slot via implementation-specific means, generally for the
884+
* sake of initial device provisioning or onboarding. Such a mechanism may
885+
* be added to a future version of the PSA Cryptography API specification.
886+
*
887+
* \param[in,out] drv_context The driver context structure.
888+
* \param[in] attributes Attributes of the key.
889+
* \param[in] key_slot Slot where the key is to be stored.
890+
*
891+
* \retval #PSA_SUCCESS
892+
* The given slot number is valid for a key with the given
893+
* attributes.
894+
* \retval #PSA_ERROR_INVALID_ARGUMENT
895+
* The given slot number is not valid for a key with the
896+
* given attributes. This includes the case where the slot
897+
* number is not valid at all.
898+
* \retval #PSA_ERROR_ALREADY_EXISTS
899+
* There is already a key with the specified slot number.
900+
* Drivers may choose to return this error from the key
901+
* creation function instead.
902+
*/
903+
typedef psa_status_t (*psa_drv_se_validate_slot_number_t)(
904+
psa_drv_se_context_t *drv_context,
905+
const psa_key_attributes_t *attributes,
906+
psa_key_slot_number_t key_slot);
907+
836908
/** \brief A function that imports a key into a secure element in binary format
837909
*
838910
* This function can support any output from psa_export_key(). Refer to the
@@ -977,8 +1049,10 @@ typedef psa_status_t (*psa_drv_se_generate_key_t)(psa_drv_se_context_t *drv_cont
9771049
* If one of the functions is not implemented, it should be set to NULL.
9781050
*/
9791051
typedef struct {
980-
/** Function that allocates a slot. */
1052+
/** Function that allocates a slot for a key. */
9811053
psa_drv_se_allocate_key_t p_allocate;
1054+
/** Function that checks the validity of a slot for a key. */
1055+
psa_drv_se_validate_slot_number_t p_validate_slot_number;
9821056
/** Function that performs a key import operation */
9831057
psa_drv_se_import_key_t p_import;
9841058
/** Function that performs a generation */

library/psa_crypto.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,10 +1582,6 @@ static psa_status_t psa_start_key_creation(
15821582
* we can roll back to a state where the key doesn't exist. */
15831583
if( *p_drv != NULL )
15841584
{
1585-
/* Choosing a slot number is not supported yet. */
1586-
if( attributes->core.flags & MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER )
1587-
return( PSA_ERROR_NOT_SUPPORTED );
1588-
15891585
status = psa_find_se_slot_for_key( attributes, *p_drv,
15901586
&slot->data.se.slot_number );
15911587
if( status != PSA_SUCCESS )

library/psa_crypto_se.c

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,6 @@ psa_status_t psa_find_se_slot_for_key(
201201
psa_key_slot_number_t *slot_number )
202202
{
203203
psa_status_t status;
204-
psa_drv_se_allocate_key_t p_allocate = NULL;
205204

206205
/* If the lifetime is wrong, it's a bug in the library. */
207206
if( driver->lifetime != psa_get_key_lifetime( attributes ) )
@@ -210,17 +209,33 @@ psa_status_t psa_find_se_slot_for_key(
210209
/* If the driver doesn't support key creation in any way, give up now. */
211210
if( driver->methods->key_management == NULL )
212211
return( PSA_ERROR_NOT_SUPPORTED );
213-
p_allocate = driver->methods->key_management->p_allocate;
214212

215-
/* If the driver doesn't tell us how to allocate a slot, that's
216-
* not supported for the time being. */
217-
if( p_allocate == NULL )
218-
return( PSA_ERROR_NOT_SUPPORTED );
219-
220-
status = p_allocate( &driver->context,
221-
driver->internal.persistent_data,
222-
attributes,
223-
slot_number );
213+
if( psa_get_key_slot_number( attributes, slot_number ) == PSA_SUCCESS )
214+
{
215+
/* The application wants to use a specific slot. Allow it if
216+
* the driver supports it. On a system with isolation,
217+
* the crypto service must check that the application is
218+
* permitted to request this slot. */
219+
psa_drv_se_validate_slot_number_t p_validate_slot_number =
220+
driver->methods->key_management->p_validate_slot_number;
221+
if( p_validate_slot_number == NULL )
222+
return( PSA_ERROR_NOT_SUPPORTED );
223+
status = p_validate_slot_number( &driver->context, attributes,
224+
*slot_number );
225+
}
226+
else
227+
{
228+
/* The application didn't tell us which slot to use. Let the driver
229+
* choose. This is the normal case. */
230+
psa_drv_se_allocate_key_t p_allocate =
231+
driver->methods->key_management->p_allocate;
232+
if( p_allocate == NULL )
233+
return( PSA_ERROR_NOT_SUPPORTED );
234+
status = p_allocate( &driver->context,
235+
driver->internal.persistent_data,
236+
attributes,
237+
slot_number );
238+
}
224239
return( status );
225240
}
226241

tests/suites/test_suite_psa_crypto_se_driver_hal.data

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,21 @@ key_creation_import_export:0:1
3939
SE key import-export, check after restart (slot 3)
4040
key_creation_import_export:3:1
4141

42+
Key creation in a specific slot (0)
43+
key_creation_in_chosen_slot:0:0:PSA_SUCCESS
44+
45+
Key creation in a specific slot (max)
46+
key_creation_in_chosen_slot:ARRAY_LENGTH( ram_slots ) - 1:0:PSA_SUCCESS
47+
48+
Key creation in a specific slot (0, restart)
49+
key_creation_in_chosen_slot:0:1:PSA_SUCCESS
50+
51+
Key creation in a specific slot (max, restart)
52+
key_creation_in_chosen_slot:ARRAY_LENGTH( ram_slots ) - 1:1:PSA_SUCCESS
53+
54+
Key creation in a specific slot (too large)
55+
key_creation_in_chosen_slot:ARRAY_LENGTH( ram_slots ):0:PSA_ERROR_INVALID_ARGUMENT
56+
4257
Key creation smoke test: AES-CTR
4358
key_creation_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CTR:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4459

tests/suites/test_suite_psa_crypto_se_driver_hal.function

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,18 @@ static psa_status_t ram_allocate( psa_drv_se_context_t *context,
177177
return( PSA_ERROR_INSUFFICIENT_STORAGE );
178178
}
179179

180+
static psa_status_t ram_validate_slot_number(
181+
psa_drv_se_context_t *context,
182+
const psa_key_attributes_t *attributes,
183+
psa_key_slot_number_t slot_number )
184+
{
185+
(void) context;
186+
(void) attributes;
187+
if( slot_number >= ARRAY_LENGTH( ram_slots ) )
188+
return( PSA_ERROR_INVALID_ARGUMENT );
189+
return( PSA_SUCCESS );
190+
}
191+
180192

181193

182194
/****************************************************************/
@@ -536,6 +548,74 @@ exit:
536548
}
537549
/* END_CASE */
538550

551+
/* BEGIN_CASE */
552+
void key_creation_in_chosen_slot( int slot_arg,
553+
int restart,
554+
int expected_status_arg )
555+
{
556+
psa_key_slot_number_t wanted_slot = slot_arg;
557+
psa_status_t expected_status = expected_status_arg;
558+
psa_status_t status;
559+
psa_drv_se_t driver;
560+
psa_drv_se_key_management_t key_management;
561+
psa_key_lifetime_t lifetime = 2;
562+
psa_key_id_t id = 1;
563+
psa_key_handle_t handle = 0;
564+
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
565+
const uint8_t key_material[3] = {0xfa, 0xca, 0xde};
566+
567+
memset( &driver, 0, sizeof( driver ) );
568+
memset( &key_management, 0, sizeof( key_management ) );
569+
driver.hal_version = PSA_DRV_SE_HAL_VERSION;
570+
driver.key_management = &key_management;
571+
driver.persistent_data_size = sizeof( ram_slot_usage_t );
572+
key_management.p_validate_slot_number = ram_validate_slot_number;
573+
key_management.p_import = ram_import;
574+
key_management.p_destroy = ram_destroy;
575+
key_management.p_export = ram_export;
576+
577+
PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) );
578+
PSA_ASSERT( psa_crypto_init( ) );
579+
580+
/* Create a key. */
581+
psa_set_key_id( &attributes, id );
582+
psa_set_key_lifetime( &attributes, lifetime );
583+
psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_EXPORT );
584+
psa_set_key_type( &attributes, PSA_KEY_TYPE_RAW_DATA );
585+
psa_set_key_slot_number( &attributes, wanted_slot );
586+
status = psa_import_key( &attributes,
587+
key_material, sizeof( key_material ),
588+
&handle );
589+
TEST_EQUAL( status, expected_status );
590+
591+
if( status != PSA_SUCCESS )
592+
goto exit;
593+
594+
/* Maybe restart, to check that the information is saved correctly. */
595+
if( restart )
596+
{
597+
mbedtls_psa_crypto_free( );
598+
PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) );
599+
PSA_ASSERT( psa_crypto_init( ) );
600+
PSA_ASSERT( psa_open_key( id, &handle ) );
601+
}
602+
603+
/* Test that the key was created in the expected slot. */
604+
TEST_EQUAL( ram_slots[wanted_slot].type, PSA_KEY_TYPE_RAW_DATA );
605+
606+
/* Test that the key is reported with the correct attributes,
607+
* including the expected slot. */
608+
PSA_ASSERT( psa_get_key_attributes( handle, &attributes ) );
609+
610+
PSA_ASSERT( psa_destroy_key( handle ) );
611+
612+
exit:
613+
PSA_DONE( );
614+
ram_slots_reset( );
615+
psa_purge_storage( );
616+
}
617+
/* END_CASE */
618+
539619
/* BEGIN_CASE */
540620
void key_creation_smoke( int type_arg, int alg_arg,
541621
data_t *key_material )

0 commit comments

Comments
 (0)