Skip to content

Let applications create a key in a specific secure element slot #202

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
73 changes: 73 additions & 0 deletions include/psa/crypto_extra.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,79 @@ static inline psa_algorithm_t psa_get_key_enrollment_algorithm(
return( attributes->core.policy.alg2 );
}

#if defined(MBEDTLS_PSA_CRYPTO_SE_C)

/** Retrieve the slot number where a key is stored.
*
* A slot number is only defined for keys that are stored in a secure
* element.
*
* This information is only useful if the secure element is not entirely
* managed through the PSA Cryptography API. It is up to the secure
* element driver to decide how PSA slot numbers map to any other interface
* that the secure element may have.
*
* \param[in] attributes The key attribute structure to query.
* \param[out] slot_number On success, the slot number containing the key.
*
* \retval #PSA_SUCCESS
* The key is located in a secure element, and \p *slot_number
* indicates the slot number that contains it.
* \retval #PSA_ERROR_NOT_PERMITTED
* The caller is not permitted to query the slot number.
* Mbed Crypto currently does not return this error.
* \retval #PSA_ERROR_INVALID_ARGUMENT
* The key is not located in a secure element.
*/
psa_status_t psa_get_key_slot_number(
const psa_key_attributes_t *attributes,
psa_key_slot_number_t *slot_number );

/** Choose the slot number where a key is stored.
*
* This function declares a slot number in the specified attribute
* structure.
*
* A slot number is only meaningful for keys that are stored in a secure
* element. It is up to the secure element driver to decide how PSA slot
* numbers map to any other interface that the secure element may have.
*
* \note Setting a slot number in key attributes for a key creation can
* cause the following errors when creating the key:
* - #PSA_ERROR_NOT_SUPPORTED if the selected secure element does
* not support choosing a specific slot number.
* - #PSA_ERROR_NOT_PERMITTED if the caller is not permitted to
* choose slot numbers in general or to choose this specific slot.
* - #PSA_ERROR_INVALID_ARGUMENT if the chosen slot number is not
* valid in general or not valid for this specific key.
* - #PSA_ERROR_ALREADY_EXISTS if there is already a key in the
* selected slot.
*
* \param[out] attributes The attribute structure to write to.
* \param slot_number The slot number to set.
*/
static inline void psa_set_key_slot_number(
psa_key_attributes_t *attributes,
psa_key_slot_number_t slot_number )
{
attributes->core.flags |= MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER;
attributes->slot_number = slot_number;
}

/** Remove the slot number attribute from a key attribute structure.
*
* This function undoes the action of psa_set_key_slot_number().
*
* \param[out] attributes The attribute structure to write to.
*/
static inline void psa_clear_key_slot_number(
psa_key_attributes_t *attributes )
{
attributes->core.flags &= ~MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER;
}

#endif /* MBEDTLS_PSA_CRYPTO_SE_C */

/**@}*/

/**
Expand Down
83 changes: 82 additions & 1 deletion include/psa/crypto_se_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,17 @@ typedef psa_status_t (*psa_drv_se_init_t)(psa_drv_se_context_t *drv_context,
void *persistent_data,
psa_key_lifetime_t lifetime);

#if defined(__DOXYGEN_ONLY__) || !defined(MBEDTLS_PSA_CRYPTO_SE_C)
/* Mbed Crypto with secure element support enabled defines this type in
* crypto_types.h because it is also visible to applications through an
* implementation-specific extension.
* For the PSA Cryptography specification, this type is only visible
* via crypto_se_driver.h. */
/** An internal designation of a key slot between the core part of the
* PSA Crypto implementation and the driver. The meaning of this value
* is driver-dependent. */
typedef uint64_t psa_key_slot_number_t;
#endif /* __DOXYGEN_ONLY__ || !MBEDTLS_PSA_CRYPTO_SE_C */

/**@}*/

Expand Down Expand Up @@ -804,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
Expand All @@ -826,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
Expand Down Expand Up @@ -970,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 */
Expand Down
33 changes: 32 additions & 1 deletion include/psa/crypto_struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -322,26 +322,57 @@ typedef uint16_t psa_key_bits_t;
* conditionals. */
#define PSA_MAX_KEY_BITS 0xfff8

/** A mask of flags that can be stored in key attributes.
*
* This type is also used internally to store flags in slots. Internal
* flags are defined in library/psa_crypto_core.h. Internal flags may have
* the same value as external flags if they are properly handled during
* key creation and in psa_get_key_attributes.
*/
typedef uint16_t psa_key_attributes_flag_t;

#define MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER \
( (psa_key_attributes_flag_t) 0x0001 )

/* A mask of key attribute flags used externally only.
* Only meant for internal checks inside the library. */
#define MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY ( \
MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER | \
0 )

/* A mask of key attribute flags used both internally and externally.
* Currently there aren't any. */
#define MBEDTLS_PSA_KA_MASK_DUAL_USE ( \
0 )

typedef struct
{
psa_key_type_t type;
psa_key_lifetime_t lifetime;
psa_key_id_t id;
psa_key_policy_t policy;
psa_key_bits_t bits;
uint16_t flags;
psa_key_attributes_flag_t flags;
} psa_core_key_attributes_t;

#define PSA_CORE_KEY_ATTRIBUTES_INIT {0, 0, 0, {0, 0, 0}, 0, 0}

struct psa_key_attributes_s
{
psa_core_key_attributes_t core;
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
psa_key_slot_number_t slot_number;
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
void *domain_parameters;
size_t domain_parameters_size;
};

#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
#define PSA_KEY_ATTRIBUTES_INIT {PSA_CORE_KEY_ATTRIBUTES_INIT, 0, NULL, 0}
#else
#define PSA_KEY_ATTRIBUTES_INIT {PSA_CORE_KEY_ATTRIBUTES_INIT, NULL, 0}
#endif

static inline struct psa_key_attributes_s psa_key_attributes_init( void )
{
const struct psa_key_attributes_s v = PSA_KEY_ATTRIBUTES_INIT;
Expand Down
11 changes: 11 additions & 0 deletions include/psa/crypto_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,17 @@ typedef uint32_t psa_key_usage_t;
*/
typedef struct psa_key_attributes_s psa_key_attributes_t;


#ifndef __DOXYGEN_ONLY__
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
/* Mbed Crypto defines this type in crypto_types.h because it is also
* visible to applications through an implementation-specific extension.
* For the PSA Cryptography specification, this type is only visible
* via crypto_se_driver.h. */
typedef uint64_t psa_key_slot_number_t;
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
#endif /* !__DOXYGEN_ONLY__ */

/**@}*/

/** \defgroup derivation Key derivation
Expand Down
47 changes: 45 additions & 2 deletions library/psa_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -1187,6 +1187,13 @@ psa_status_t psa_get_key_attributes( psa_key_handle_t handle,
return( status );

attributes->core = slot->attr;
attributes->core.flags &= ( MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY |
MBEDTLS_PSA_KA_MASK_DUAL_USE );

#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
if( psa_key_slot_is_external( slot ) )
psa_set_key_slot_number( attributes, slot->data.se.slot_number );
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */

switch( slot->attr.type )
{
Expand All @@ -1196,7 +1203,7 @@ psa_status_t psa_get_key_attributes( psa_key_handle_t handle,
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
/* TOnogrepDO: reporting the public exponent for opaque keys
* is not yet implemented. */
if( psa_get_se_driver( slot->attr.lifetime, NULL, NULL ) )
if( psa_key_slot_is_external( slot ) )
break;
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
status = psa_get_rsa_public_exponent( slot->data.rsa, attributes );
Expand All @@ -1212,6 +1219,21 @@ psa_status_t psa_get_key_attributes( psa_key_handle_t handle,
return( status );
}

#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
psa_status_t psa_get_key_slot_number(
const psa_key_attributes_t *attributes,
psa_key_slot_number_t *slot_number )
{
if( attributes->core.flags & MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER )
{
*slot_number = attributes->slot_number;
return( PSA_SUCCESS );
}
else
return( PSA_ERROR_INVALID_ARGUMENT );
}
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */

#if defined(MBEDTLS_RSA_C) || defined(MBEDTLS_ECP_C)
static int pk_write_pubkey_simple( mbedtls_pk_context *key,
unsigned char *buf, size_t size )
Expand Down Expand Up @@ -1408,6 +1430,15 @@ psa_status_t psa_export_public_key( psa_key_handle_t handle,
data_length, 1 ) );
}

#if defined(static_assert)
static_assert( ( MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY & MBEDTLS_PSA_KA_MASK_DUAL_USE ) == 0,
"One or more key attribute flag is listed as both external-only and dual-use" );
static_assert( ( PSA_KA_MASK_INTERNAL_ONLY & MBEDTLS_PSA_KA_MASK_DUAL_USE ) == 0,
"One or more key attribute flag is listed as both internal-only and dual-use" );
static_assert( ( PSA_KA_MASK_INTERNAL_ONLY & MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY ) == 0,
"One or more key attribute flag is listed as both internal-only and external-only" );
#endif

/** Validate that a key policy is internally well-formed.
*
* This function only rejects invalid policies. It does not validate the
Expand Down Expand Up @@ -1467,6 +1498,11 @@ static psa_status_t psa_validate_key_attributes(
if( psa_get_key_bits( attributes ) > PSA_MAX_KEY_BITS )
return( PSA_ERROR_NOT_SUPPORTED );

/* Reject invalid flags. These should not be reachable through the API. */
if( attributes->core.flags & ~ ( MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY |
MBEDTLS_PSA_KA_MASK_DUAL_USE ) )
return( PSA_ERROR_INVALID_ARGUMENT );

return( PSA_SUCCESS );
}

Expand Down Expand Up @@ -1510,7 +1546,7 @@ static psa_status_t psa_start_key_creation(
if( status != PSA_SUCCESS )
return( status );

status = psa_internal_allocate_key_slot( handle, p_slot );
status = psa_get_empty_key_slot( handle, p_slot );
if( status != PSA_SUCCESS )
return( status );
slot = *p_slot;
Expand All @@ -1523,6 +1559,13 @@ static psa_status_t psa_start_key_creation(

slot->attr = attributes->core;

/* Erase external-only flags from the internal copy. To access
* external-only flags, query `attributes`. Thanks to the check
* in psa_validate_key_attributes(), this leaves the dual-use
* flags and any internal flag that psa_get_empty_key_slot()
* may have set. */
slot->attr.flags &= ~MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY;

#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
/* For a key in a secure element, we need to do three things:
* create the key file in internal storage, create the
Expand Down
7 changes: 7 additions & 0 deletions library/psa_crypto_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,21 @@ typedef struct
/* EC public key or key pair */
mbedtls_ecp_keypair *ecp;
#endif /* MBEDTLS_ECP_C */
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
/* Any key type in a secure element */
struct se
{
psa_key_slot_number_t slot_number;
} se;
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
} data;
} psa_key_slot_t;

/* A mask of key attribute flags used only internally.
* Currently there aren't any. */
#define PSA_KA_MASK_INTERNAL_ONLY ( \
0 )

/** Test whether a key slot is occupied.
*
* A key slot is occupied iff the key type is nonzero. This works because
Expand Down
Loading