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
This commit is contained in:
Gilles Peskine 2019-08-09 14:29:54 +02:00 committed by GitHub
commit b231d996a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 196 additions and 16 deletions

View File

@ -811,6 +811,42 @@ typedef struct {
/**@{*/
/** \brief A function that allocates a slot for a key.
*
* To create a key in a specific slot in a secure element, the core
* first calls this function to determine a valid slot number,
* then calls a function to create the key material in that slot.
* For example, in nominal conditions (that is, if no error occurs),
* the effect of a call to psa_import_key() with a lifetime that places
* the key in a secure element is the following:
* -# The core calls psa_drv_se_key_management_t::p_allocate
* (or in some implementations
* psa_drv_se_key_management_t::p_validate_slot_number). The driver
* selects (or validates) a suitable slot number given the key attributes
* and the state of the secure element.
* -# The core calls psa_drv_se_key_management_t::p_import to import
* the key material in the selected slot.
*
* Other key creation methods lead to similar sequences. For example, the
* sequence for psa_generate_key() is the same except that the second step
* is a call to psa_drv_se_key_management_t::p_generate.
*
* In case of errors, other behaviors are possible.
* - If the PSA Cryptography subsystem dies after the first step,
* for example because the device has lost power abruptly,
* the second step may never happen, or may happen after a reset
* and re-initialization. Alternatively, after a reset and
* re-initialization, the core may call
* psa_drv_se_key_management_t::p_destroy on the slot number that
* was allocated (or validated) instead of calling a key creation function.
* - If an error occurs, the core may call
* psa_drv_se_key_management_t::p_destroy on the slot number that
* was allocated (or validated) instead of calling a key creation function.
*
* Errors and system resets also have an impact on the driver's persistent
* data. If a reset happens before the overall key creation process is
* completed (before or after the second step above), it is unspecified
* whether the persistent data after the reset is identical to what it
* was before or after the call to `p_allocate` (or `p_validate_slot_number`).
*
* \param[in,out] drv_context The driver context structure.
* \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)(
const psa_key_attributes_t *attributes,
psa_key_slot_number_t *key_slot);
/** \brief A function that determines whether a slot number is valid
* for a key.
*
* To create a key in a specific slot in a secure element, the core
* first calls this function to validate the choice of slot number,
* then calls a function to create the key material in that slot.
* See the documentation of #psa_drv_se_allocate_key_t for more details.
*
* As of the PSA Cryptography API specification version 1.0, there is no way
* for applications to trigger a call to this function. However some
* implementations offer the capability to create or declare a key in
* a specific slot via implementation-specific means, generally for the
* sake of initial device provisioning or onboarding. Such a mechanism may
* be added to a future version of the PSA Cryptography API specification.
*
* \param[in,out] drv_context The driver context structure.
* \param[in] attributes Attributes of the key.
* \param[in] key_slot Slot where the key is to be stored.
*
* \retval #PSA_SUCCESS
* The given slot number is valid for a key with the given
* attributes.
* \retval #PSA_ERROR_INVALID_ARGUMENT
* The given slot number is not valid for a key with the
* given attributes. This includes the case where the slot
* number is not valid at all.
* \retval #PSA_ERROR_ALREADY_EXISTS
* There is already a key with the specified slot number.
* Drivers may choose to return this error from the key
* creation function instead.
*/
typedef psa_status_t (*psa_drv_se_validate_slot_number_t)(
psa_drv_se_context_t *drv_context,
const psa_key_attributes_t *attributes,
psa_key_slot_number_t key_slot);
/** \brief A function that imports a key into a secure element in binary format
*
* 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
* If one of the functions is not implemented, it should be set to NULL.
*/
typedef struct {
/** Function that allocates a slot. */
/** Function that allocates a slot for a key. */
psa_drv_se_allocate_key_t p_allocate;
/** Function that checks the validity of a slot for a key. */
psa_drv_se_validate_slot_number_t p_validate_slot_number;
/** Function that performs a key import operation */
psa_drv_se_import_key_t p_import;
/** Function that performs a generation */

View File

@ -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 )

View File

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

View File

@ -39,6 +39,21 @@ 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:0:PSA_SUCCESS
Key creation in a specific slot (max)
key_creation_in_chosen_slot:ARRAY_LENGTH( ram_slots ) - 1:0:PSA_SUCCESS
Key creation in a specific slot (0, restart)
key_creation_in_chosen_slot:0:1:PSA_SUCCESS
Key creation in a specific slot (max, restart)
key_creation_in_chosen_slot:ARRAY_LENGTH( ram_slots ) - 1:1:PSA_SUCCESS
Key creation in a specific slot (too large)
key_creation_in_chosen_slot:ARRAY_LENGTH( ram_slots ):0:PSA_ERROR_INVALID_ARGUMENT
Key creation smoke test: AES-CTR
key_creation_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CTR:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

View File

@ -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,74 @@ exit:
}
/* END_CASE */
/* BEGIN_CASE */
void key_creation_in_chosen_slot( int slot_arg,
int restart,
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 )
goto exit;
/* Maybe restart, to check that the information is saved correctly. */
if( restart )
{
mbedtls_psa_crypto_free( );
PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) );
PSA_ASSERT( psa_crypto_init( ) );
PSA_ASSERT( psa_open_key( id, &handle ) );
}
/* 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 )