Skip to content

Add hooks for generate and sign in a secure element #211

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 62 additions & 48 deletions include/psa/crypto_se_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -956,15 +956,21 @@ typedef psa_status_t (*psa_drv_se_validate_slot_number_t)(
* documentation of psa_export_key() for the format for each key type.
*
* \param[in,out] drv_context The driver context structure.
* \param[in] key_slot Slot where the key will be stored
* \param key_slot Slot where the key will be stored.
* This must be a valid slot for a key of the
* chosen type. It must be unoccupied.
* \param[in] lifetime The required lifetime of the key storage
* \param[in] type Key type (a \c PSA_KEY_TYPE_XXX value)
* \param[in] algorithm Key algorithm (a \c PSA_ALG_XXX value)
* \param[in] usage The allowed uses of the key
* \param[in] p_data Buffer containing the key data
* \param[in] data_length Size of the `data` buffer in bytes
* \param[in] attributes The key attributes, including the lifetime,
* the key type and the usage policy.
* Drivers should not access the key size stored
* in the attributes: it may not match the
* data passed in \p data.
* Drivers can call psa_get_key_lifetime(),
* psa_get_key_type(),
* psa_get_key_usage_flags() and
* psa_get_key_algorithm() to access this
* information.
* \param[in] data Buffer containing the key data.
* \param[in] data_length Size of the \p data buffer in bytes.
* \param[out] bits On success, the key size in bits. The driver
* must determine this value after parsing the
* key according to the key type.
Expand All @@ -973,15 +979,13 @@ typedef psa_status_t (*psa_drv_se_validate_slot_number_t)(
* \retval #PSA_SUCCESS
* Success.
*/
typedef psa_status_t (*psa_drv_se_import_key_t)(psa_drv_se_context_t *drv_context,
psa_key_slot_number_t key_slot,
psa_key_lifetime_t lifetime,
psa_key_type_t type,
psa_algorithm_t algorithm,
psa_key_usage_t usage,
const uint8_t *p_data,
size_t data_length,
size_t *bits);
typedef psa_status_t (*psa_drv_se_import_key_t)(
psa_drv_se_context_t *drv_context,
psa_key_slot_number_t key_slot,
const psa_key_attributes_t *attributes,
const uint8_t *data,
size_t data_length,
size_t *bits);

/**
* \brief A function that destroys a secure element key and restore the slot to
Expand Down Expand Up @@ -1048,41 +1052,51 @@ typedef psa_status_t (*psa_drv_se_export_key_t)(psa_drv_se_context_t *drv_contex
* element
*
* If \p type is asymmetric (#PSA_KEY_TYPE_IS_ASYMMETRIC(\p type) = 1),
* the public component of the generated key will be placed in `p_pubkey_out`.
* The format of the public key information will match the format specified for
* the psa_export_key() function for the key type.
* the driver may export the public key at the time of generation,
* in the format documented for psa_export_public_key() by writing it
* to the \p pubkey buffer.
* This is optional, intended for secure elements that output the
* public key at generation time and that cannot export the public key
* later. Drivers that do not need this feature should leave
* \p *pubkey_length set to 0 and should
* implement the psa_drv_key_management_t::p_export_public function.
* Some implementations do not support this feature, in which case
Copy link
Contributor

@AndrzejKurek AndrzejKurek Aug 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NULL can also be passed in a case when the user is not interested in receiving the public key, right? This information is missing.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, there's no such thing as “the user is not interested in receiving the public key”. psa_generate_key never outputs the public key. If the driver outputs the public key, the core stores it in case the user ever calls psa_export_public_key later.

* \p pubkey is \c NULL and \p pubkey_size is 0.
*
* \param[in,out] drv_context The driver context structure.
* \param[in] key_slot Slot where the generated key will be placed
* \param[in] type The type of the key to be generated
* \param[in] usage The prescribed usage of the generated key
* Note: Not all Secure Elements support the same
* restrictions that PSA Crypto does (and vice
* versa).
* Driver developers should endeavor to match the
* usages as close as possible.
* \param[in] bits The size in bits of the key to be generated.
* \param[in] extra Extra parameters for key generation. The
* interpretation of this parameter should match
* the interpretation in the `extra` parameter is
* the `psa_generate_key` function
* \param[in] extra_size The size in bytes of the \p extra buffer
* \param[out] p_pubkey_out The buffer where the public key information will
* be placed
* \param[in] pubkey_out_size The size in bytes of the `p_pubkey_out` buffer
* \param[out] p_pubkey_length Upon successful completion, will contain the
* size of the data placed in `p_pubkey_out`.
* \param key_slot Slot where the key will be stored.
* This must be a valid slot for a key of the
* chosen type. It must be unoccupied.
* \param[in] attributes The key attributes, including the lifetime,
* the key type and size, and the usage policy.
* Drivers can call psa_get_key_lifetime(),
* psa_get_key_type(), psa_get_key_bits(),
* psa_get_key_usage_flags() and
* psa_get_key_algorithm() to access this
* information.
* \param[out] pubkey A buffer where the driver can write the
* public key, when generating an asymmetric
* key pair.
* This is \c NULL when generating a symmetric
* key or if the core does not support
* exporting the public key at generation time.
* \param pubkey_size The size of the `pubkey` buffer in bytes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocker: the pubkey parameter is referenced here in an inconsistent way.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sure it isn't the only place, and it's preexisting. I'll fix it if I change something else.

* This is 0 when generating a symmetric
* key or if the core does not support
* exporting the public key at generation time.
* \param[out] pubkey_length On entry, this is always 0.
* On success, the number of bytes written to
* \p pubkey. If this is 0 or unchanged on return,
* the core will not read the \p pubkey buffer,
* and will instead call the driver's
* psa_drv_key_management_t::p_export_public
* function to export the public key when needed.
*/
typedef psa_status_t (*psa_drv_se_generate_key_t)(psa_drv_se_context_t *drv_context,
psa_key_slot_number_t key_slot,
psa_key_type_t type,
psa_key_usage_t usage,
size_t bits,
const void *extra,
size_t extra_size,
uint8_t *p_pubkey_out,
size_t pubkey_out_size,
size_t *p_pubkey_length);
typedef psa_status_t (*psa_drv_se_generate_key_t)(
psa_drv_se_context_t *drv_context,
psa_key_slot_number_t key_slot,
const psa_key_attributes_t *attributes,
uint8_t *pubkey, size_t pubkey_size, size_t *pubkey_length);

/**
* \brief A struct containing all of the function pointers needed to for secure
Expand Down
71 changes: 62 additions & 9 deletions library/psa_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -1827,10 +1827,7 @@ psa_status_t psa_import_key( const psa_key_attributes_t *attributes,
}
status = drv->key_management->p_import(
psa_get_se_driver_context( driver ),
slot->data.se.slot_number,
slot->attr.lifetime, slot->attr.type,
slot->attr.policy.alg, slot->attr.policy.usage,
data, data_length,
slot->data.se.slot_number, attributes, data, data_length,
&bits );
if( status != PSA_SUCCESS )
goto exit;
Expand Down Expand Up @@ -3334,10 +3331,14 @@ psa_status_t psa_asymmetric_sign( psa_key_handle_t handle,
{
psa_key_slot_t *slot;
psa_status_t status;
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */

*signature_length = signature_size;

status = psa_get_transparent_key( handle, &slot, PSA_KEY_USAGE_SIGN, alg );
status = psa_get_key_from_slot( handle, &slot, PSA_KEY_USAGE_SIGN, alg );
if( status != PSA_SUCCESS )
goto exit;
if( ! PSA_KEY_TYPE_IS_KEY_PAIR( slot->attr.type ) )
Expand All @@ -3346,6 +3347,24 @@ psa_status_t psa_asymmetric_sign( psa_key_handle_t handle,
goto exit;
}

#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
if( psa_get_se_driver( slot->attr.lifetime, &drv, &drv_context ) )
{
if( drv->asymmetric == NULL ||
drv->asymmetric->p_sign == NULL )
{
status = PSA_ERROR_NOT_SUPPORTED;
goto exit;
}
status = drv->asymmetric->p_sign( drv_context,
slot->data.se.slot_number,
alg,
hash, hash_length,
signature, signature_size,
signature_length );
}
else
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
#if defined(MBEDTLS_RSA_C)
if( slot->attr.type == PSA_KEY_TYPE_RSA_KEY_PAIR )
{
Expand Down Expand Up @@ -3409,11 +3428,29 @@ psa_status_t psa_asymmetric_verify( psa_key_handle_t handle,
{
psa_key_slot_t *slot;
psa_status_t status;
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */

status = psa_get_transparent_key( handle, &slot, PSA_KEY_USAGE_VERIFY, alg );
status = psa_get_key_from_slot( handle, &slot, PSA_KEY_USAGE_VERIFY, alg );
if( status != PSA_SUCCESS )
return( status );

#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
if( psa_get_se_driver( slot->attr.lifetime, &drv, &drv_context ) )
{
if( drv->asymmetric == NULL ||
drv->asymmetric->p_verify == NULL )
return( PSA_ERROR_NOT_SUPPORTED );
return( drv->asymmetric->p_verify( drv_context,
slot->data.se.slot_number,
alg,
hash, hash_length,
signature, signature_length ) );
}
else
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
#if defined(MBEDTLS_RSA_C)
if( PSA_KEY_TYPE_IS_RSA( slot->attr.type ) )
{
Expand Down Expand Up @@ -5947,21 +5984,37 @@ psa_status_t psa_generate_key( const psa_key_attributes_t *attributes,
psa_status_t status;
psa_key_slot_t *slot = NULL;
psa_se_drv_table_entry_t *driver = NULL;

status = psa_start_key_creation( PSA_KEY_CREATION_GENERATE,
attributes, handle, &slot, &driver );
if( status != PSA_SUCCESS )
goto exit;

#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
if( driver != NULL )
{
/* Generating a key in a secure element is not implemented yet. */
status = PSA_ERROR_NOT_SUPPORTED;
const psa_drv_se_t *drv = psa_get_se_driver_methods( driver );
size_t pubkey_length = 0; /* We don't support this feature yet */
if( drv->key_management == NULL ||
drv->key_management->p_generate == NULL )
{
status = PSA_ERROR_NOT_SUPPORTED;
goto exit;
}
status = drv->key_management->p_generate(
psa_get_se_driver_context( driver ),
slot->data.se.slot_number, attributes,
NULL, 0, &pubkey_length );
}
else
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
if( status == PSA_SUCCESS )
{
status = psa_generate_key_internal(
slot, attributes->core.bits,
attributes->domain_parameters, attributes->domain_parameters_size );
}

exit:
if( status == PSA_SUCCESS )
status = psa_finish_key_creation( slot, driver );
if( status != PSA_SUCCESS )
Expand Down
Loading