diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h index 6dfaa1300..355012236 100644 --- a/include/psa/crypto_extra.h +++ b/include/psa/crypto_extra.h @@ -104,6 +104,117 @@ 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; +} + +/** Register a key that is already present in a secure element. + * + * The key must be located in a secure element designated by the + * lifetime field in \p attributes, in the slot set with + * psa_set_key_slot_number() in the attribute structure. + * This function makes the key available through the key identifier + * specified in \p attributes. + * + * \param[in] attributes The attributes of the existing key. + * + * \retval #PSA_SUCCESS + * The key was successfully registered. + * Note that depending on the design of the driver, this may or may + * not guarantee that a key actually exists in the designated slot + * and is compatible with the specified attributes. + * \retval #PSA_ERROR_ALREADY_EXISTS + * There is already a key with the identifier specified in + * \p attributes. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \p attributes specifies a lifetime which is not located + * in a secure element. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * No slot number is specified in \p attributes, + * or the specified slot number is not valid. + * \retval #PSA_ERROR_NOT_PERMITTED + * The caller is not authorized to register the specified key slot. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t mbedtls_psa_register_se_key( + const psa_key_attributes_t *attributes); + +#endif /* MBEDTLS_PSA_CRYPTO_SE_C */ + /**@}*/ /** diff --git a/include/psa/crypto_se_driver.h b/include/psa/crypto_se_driver.h index f95eaeb33..a43e0db48 100644 --- a/include/psa/crypto_se_driver.h +++ b/include/psa/crypto_se_driver.h @@ -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 */ /**@}*/ @@ -803,12 +810,90 @@ typedef struct { */ /**@{*/ +/** An enumeration indicating how a key is created. + */ +typedef enum +{ + PSA_KEY_CREATION_IMPORT, /**< During psa_import_key() */ + PSA_KEY_CREATION_GENERATE, /**< During psa_generate_key() */ + PSA_KEY_CREATION_DERIVE, /**< During psa_key_derivation_output_key() */ + PSA_KEY_CREATION_COPY, /**< During psa_copy_key() */ + +#ifndef __DOXYGEN_ONLY__ + /** A key is being registered with mbedtls_psa_register_se_key(). + * + * The core only passes this value to + * psa_drv_se_key_management_t::p_validate_slot_number, not to + * psa_drv_se_key_management_t::p_allocate. The call to + * `p_validate_slot_number` is not followed by any other call to the + * driver: the key is considered successfully registered if the call to + * `p_validate_slot_number` succeeds, or if `p_validate_slot_number` is + * null. + * + * With this creation method, the driver must return #PSA_SUCCESS if + * the given attributes are compatible with the existing key in the slot, + * and #PSA_ERROR_DOES_NOT_EXIST if the driver can determine that there + * is no key with the specified slot number. + * + * This is an Mbed Crypto extension. + */ + PSA_KEY_CREATION_REGISTER, +#endif +} psa_key_creation_method_t; + /** \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. + * In nominal conditions (that is, if no error occurs), + * the effect of a call to a key creation function in the PSA Cryptography + * API 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 a key creation function in the driver. + * + * The key creation functions in the PSA Cryptography API are: + * - psa_import_key(), which causes + * a call to `p_allocate` with \p method = #PSA_KEY_CREATION_IMPORT + * then a call to psa_drv_se_key_management_t::p_import. + * - psa_generate_key(), which causes + * a call to `p_allocate` with \p method = #PSA_KEY_CREATION_GENERATE + * then a call to psa_drv_se_key_management_t::p_import. + * - psa_key_derivation_output_key(), which causes + * a call to `p_allocate` with \p method = #PSA_KEY_CREATION_DERIVE + * then a call to psa_drv_se_key_derivation_t::p_derive. + * - psa_copy_key(), which causes + * a call to `p_allocate` with \p method = #PSA_KEY_CREATION_COPY + * then a call to psa_drv_se_key_management_t::p_export. + * + * 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 * that allows writing. * \param[in] attributes Attributes of the key. + * \param method The way in which the key is being created. * \param[out] 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. @@ -824,23 +909,68 @@ typedef psa_status_t (*psa_drv_se_allocate_key_t)( psa_drv_se_context_t *drv_context, void *persistent_data, const psa_key_attributes_t *attributes, + psa_key_creation_method_t method, 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 method The way in which the key is being created. + * \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_creation_method_t method, + 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 * 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. @@ -849,15 +979,13 @@ typedef psa_status_t (*psa_drv_se_allocate_key_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 @@ -924,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 + * \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. + * 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 @@ -970,8 +1108,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 */ diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h index 9e38e53ce..28bbc6ac8 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -12,6 +12,26 @@ * In implementations with isolation between the application and the * cryptography module, it is expected that the front-end and the back-end * would have different versions of this file. + * + *

Design notes about multipart operation structures

+ * + * Each multipart operation structure contains a `psa_algorithm_t alg` + * field which indicates which specific algorithm the structure is for. + * When the structure is not in use, `alg` is 0. Most of the structure + * consists of a union which is discriminated by `alg`. + * + * Note that when `alg` is 0, the content of other fields is undefined. + * In particular, it is not guaranteed that a freshly-initialized structure + * is all-zero: we initialize structures to something like `{0, 0}`, which + * is only guaranteed to initializes the first member of the union; + * GCC and Clang initialize the whole structure to 0 (at the time of writing), + * but MSVC and CompCert don't. + * + * In Mbed Crypto, multipart operation structures live independently from + * the key. This allows Mbed Crypto to free the key objects when destroying + * a key slot. If a multipart operation needs to remember the key after + * the setup function returns, the operation structure needs to contain a + * copy of the key. */ /* * Copyright (C) 2018, ARM Limited, All Rights Reserved @@ -322,6 +342,29 @@ 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; @@ -329,7 +372,7 @@ typedef struct 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} @@ -337,11 +380,19 @@ typedef struct 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; diff --git a/include/psa/crypto_types.h b/include/psa/crypto_types.h index 1944be4b2..9af4957df 100644 --- a/include/psa/crypto_types.h +++ b/include/psa/crypto_types.h @@ -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 diff --git a/library/psa_crypto.c b/library/psa_crypto.c index bd801441a..6ec2a1c38 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -994,18 +994,16 @@ static psa_status_t psa_remove_key_data_from_memory( psa_key_slot_t *slot ) return( PSA_SUCCESS ); } -static void psa_abort_operations_using_key( psa_key_slot_t *slot ) -{ - /*TODO how to implement this?*/ - (void) slot; -} - /** Completely wipe a slot in memory, including its policy. * Persistent storage is not affected. */ psa_status_t psa_wipe_key_slot( psa_key_slot_t *slot ) { psa_status_t status = psa_remove_key_data_from_memory( slot ); - psa_abort_operations_using_key( slot ); + /* Multipart operations may still be using the key. This is safe + * because all multipart operation objects are independent from + * the key slot: if they need to access the key after the setup + * phase, they have a copy of the key. Note that this means that + * key material can linger until all operations are completed. */ /* At this point, key material and other type-specific content has * been wiped. Clear remaining metadata. We can call memset and not * zeroize because the metadata is not particularly sensitive. */ @@ -1016,8 +1014,8 @@ psa_status_t psa_wipe_key_slot( psa_key_slot_t *slot ) psa_status_t psa_destroy_key( psa_key_handle_t handle ) { psa_key_slot_t *slot; - psa_status_t status = PSA_SUCCESS; - psa_status_t storage_status = PSA_SUCCESS; + psa_status_t status; /* status of the last operation */ + psa_status_t overall_status = PSA_SUCCESS; #if defined(MBEDTLS_PSA_CRYPTO_SE_C) psa_se_drv_table_entry_t *driver; #endif /* MBEDTLS_PSA_CRYPTO_SE_C */ @@ -1043,42 +1041,57 @@ psa_status_t psa_destroy_key( psa_key_handle_t handle ) if( status != PSA_SUCCESS ) { (void) psa_crypto_stop_transaction( ); - /* TODO: destroy what can be destroyed anyway */ - return( status ); + /* We should still try to destroy the key in the secure + * element and the key metadata in storage. This is especially + * important if the error is that the storage is full. + * But how to do it exactly without risking an inconsistent + * state after a reset? + * https://github.com/ARMmbed/mbed-crypto/issues/215 + */ + overall_status = status; + goto exit; } status = psa_destroy_se_key( driver, slot->data.se.slot_number ); + if( overall_status == PSA_SUCCESS ) + overall_status = status; } #endif /* MBEDTLS_PSA_CRYPTO_SE_C */ #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) - if( slot->attr.lifetime == PSA_KEY_LIFETIME_PERSISTENT ) + if( slot->attr.lifetime != PSA_KEY_LIFETIME_VOLATILE ) { - storage_status = - psa_destroy_persistent_key( slot->attr.id ); + status = psa_destroy_persistent_key( slot->attr.id ); + if( overall_status == PSA_SUCCESS ) + overall_status = status; + + /* TODO: other slots may have a copy of the same key. We should + * invalidate them. + * https://github.com/ARMmbed/mbed-crypto/issues/214 + */ } #endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */ #if defined(MBEDTLS_PSA_CRYPTO_SE_C) if( driver != NULL ) { - psa_status_t status2; status = psa_save_se_persistent_data( driver ); - status2 = psa_crypto_stop_transaction( ); - if( status == PSA_SUCCESS ) - status = status2; - if( status != PSA_SUCCESS ) - { - /* TODO: destroy what can be destroyed anyway */ - return( status ); - } + if( overall_status == PSA_SUCCESS ) + overall_status = status; + status = psa_crypto_stop_transaction( ); + if( overall_status == PSA_SUCCESS ) + overall_status = status; } #endif /* MBEDTLS_PSA_CRYPTO_SE_C */ +#if defined(MBEDTLS_PSA_CRYPTO_SE_C) +exit: +#endif /* MBEDTLS_PSA_CRYPTO_SE_C */ status = psa_wipe_key_slot( slot ); - if( status != PSA_SUCCESS ) - return( status ); - return( storage_status ); + /* Prioritize CORRUPTION_DETECTED from wiping over a storage error */ + if( overall_status == PSA_SUCCESS ) + overall_status = status; + return( overall_status ); } void psa_reset_key_attributes( psa_key_attributes_t *attributes ) @@ -1187,6 +1200,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 ) { @@ -1195,8 +1215,10 @@ psa_status_t psa_get_key_attributes( psa_key_handle_t handle, case PSA_KEY_TYPE_RSA_PUBLIC_KEY: #if defined(MBEDTLS_PSA_CRYPTO_SE_C) /* TODO: reporting the public exponent for opaque keys - * is not yet implemented. */ - if( psa_get_se_driver( slot->attr.lifetime, NULL, NULL ) ) + * is not yet implemented. + * https://github.com/ARMmbed/mbed-crypto/issues/216 + */ + if( psa_key_slot_is_external( slot ) ) break; #endif /* MBEDTLS_PSA_CRYPTO_SE_C */ status = psa_get_rsa_public_exponent( slot->data.rsa, attributes ); @@ -1212,6 +1234,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 ) @@ -1408,6 +1445,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 @@ -1467,6 +1513,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 ); } @@ -1484,6 +1535,7 @@ static psa_status_t psa_validate_key_attributes( * In case of failure at any step, stop the sequence and call * psa_fail_key_creation(). * + * \param method An identification of the calling function. * \param[in] attributes Key attributes for the new key. * \param[out] handle On success, a handle for the allocated slot. * \param[out] p_slot On success, a pointer to the prepared slot. @@ -1496,6 +1548,7 @@ static psa_status_t psa_validate_key_attributes( * You must call psa_fail_key_creation() to wipe and free the slot. */ static psa_status_t psa_start_key_creation( + psa_key_creation_method_t method, const psa_key_attributes_t *attributes, psa_key_handle_t *handle, psa_key_slot_t **p_slot, @@ -1504,13 +1557,14 @@ static psa_status_t psa_start_key_creation( psa_status_t status; psa_key_slot_t *slot; + (void) method; *p_drv = NULL; status = psa_validate_key_attributes( attributes, p_drv ); 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; @@ -1523,8 +1577,16 @@ 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: + /* For a key in a secure element, we need to do three things + * when creating a key (but not when registering an existing key): * create the key file in internal storage, create the * key inside the secure element, and update the driver's * persistent data. Start a transaction that will encompass these @@ -1537,9 +1599,9 @@ static psa_status_t psa_start_key_creation( * secure element driver updates its persistent state, but we do not yet * save the driver's persistent state, so that if the power fails, * we can roll back to a state where the key doesn't exist. */ - if( *p_drv != NULL ) + if( *p_drv != NULL && method != PSA_KEY_CREATION_REGISTER ) { - status = psa_find_se_slot_for_key( attributes, *p_drv, + status = psa_find_se_slot_for_key( attributes, method, *p_drv, &slot->data.se.slot_number ); if( status != PSA_SUCCESS ) return( status ); @@ -1631,7 +1693,13 @@ static psa_status_t psa_finish_key_creation( #endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */ #if defined(MBEDTLS_PSA_CRYPTO_SE_C) - if( driver != NULL ) + /* Finish the transaction for a key creation. This does not + * happen when registering an existing key. Detect this case + * by checking whether a transaction is in progress (actual + * creation of a key in a secure element requires a transaction, + * but registration doesn't use one). */ + if( driver != NULL && + psa_crypto_transaction.unknown.type == PSA_CRYPTO_TRANSACTION_CREATE_KEY ) { status = psa_save_se_persistent_data( driver ); if( status != PSA_SUCCESS ) @@ -1672,11 +1740,16 @@ static void psa_fail_key_creation( psa_key_slot_t *slot, /* TODO: If the key has already been created in the secure * element, and the failure happened later (when saving metadata * to internal storage), we need to destroy the key in the secure - * element. */ + * element. + * https://github.com/ARMmbed/mbed-crypto/issues/217 + */ - /* Abort the ongoing transaction if any. We already did what it - * takes to undo any partial creation. All that's left is to update - * the transaction data itself. */ + /* Abort the ongoing transaction if any (there may not be one if + * the creation process failed before starting one, or if the + * key creation is a registration of a key in a secure element). + * Earlier functions must already have done what it takes to undo any + * partial creation. All that's left is to update the transaction data + * itself. */ (void) psa_crypto_stop_transaction( ); #endif /* MBEDTLS_PSA_CRYPTO_SE_C */ @@ -1753,7 +1826,8 @@ psa_status_t psa_import_key( const psa_key_attributes_t *attributes, psa_key_slot_t *slot = NULL; psa_se_drv_table_entry_t *driver = NULL; - status = psa_start_key_creation( attributes, handle, &slot, &driver ); + status = psa_start_key_creation( PSA_KEY_CREATION_IMPORT, attributes, + handle, &slot, &driver ); if( status != PSA_SUCCESS ) goto exit; @@ -1770,10 +1844,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; @@ -1805,6 +1876,74 @@ exit: return( status ); } +#if defined(MBEDTLS_PSA_CRYPTO_SE_C) +psa_status_t mbedtls_psa_register_se_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; + const psa_drv_se_t *drv; + psa_key_handle_t handle = 0; + + /* Leaving attributes unspecified is not currently supported. + * It could make sense to query the key type and size from the + * secure element, but not all secure elements support this + * and the driver HAL doesn't currently support it. */ + if( psa_get_key_type( attributes ) == PSA_KEY_TYPE_NONE ) + return( PSA_ERROR_NOT_SUPPORTED ); + if( psa_get_key_bits( attributes ) == 0 ) + return( PSA_ERROR_NOT_SUPPORTED ); + + status = psa_start_key_creation( PSA_KEY_CREATION_REGISTER, attributes, + &handle, &slot, &driver ); + if( status != PSA_SUCCESS ) + goto exit; + + if( driver == NULL ) + { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + drv = psa_get_se_driver_methods( driver ); + + if ( psa_get_key_slot_number( attributes, + &slot->data.se.slot_number ) != PSA_SUCCESS ) + { + /* The application didn't specify a slot number. This doesn't + * make sense when registering a slot. */ + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + /* If the driver has a slot number validation method, call it. + * If it doesn't, it means the secure element is unable to validate + * anything and so we have to trust the application. */ + if( drv->key_management != NULL && + drv->key_management->p_validate_slot_number != NULL ) + { + status = drv->key_management->p_validate_slot_number( + psa_get_se_driver_context( driver ), + attributes, + PSA_KEY_CREATION_REGISTER, + slot->data.se.slot_number ); + if( status != PSA_SUCCESS ) + goto exit; + } + + status = psa_finish_key_creation( slot, driver ); + +exit: + if( status != PSA_SUCCESS ) + { + psa_fail_key_creation( slot, driver ); + } + /* Registration doesn't keep the key in RAM. */ + psa_close_key( handle ); + return( status ); +} +#endif /* MBEDTLS_PSA_CRYPTO_SE_C */ + static psa_status_t psa_copy_key_material( const psa_key_slot_t *source, psa_key_slot_t *target ) { @@ -1856,7 +1995,8 @@ psa_status_t psa_copy_key( psa_key_handle_t source_handle, if( status != PSA_SUCCESS ) goto exit; - status = psa_start_key_creation( &actual_attributes, + status = psa_start_key_creation( PSA_KEY_CREATION_COPY, + &actual_attributes, target_handle, &target_slot, &driver ); if( status != PSA_SUCCESS ) goto exit; @@ -3208,10 +3348,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 ) ) @@ -3220,6 +3364,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 ) { @@ -3283,11 +3445,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 ) ) { @@ -4774,7 +4954,8 @@ psa_status_t psa_key_derivation_output_key( const psa_key_attributes_t *attribut psa_status_t status; psa_key_slot_t *slot = NULL; psa_se_drv_table_entry_t *driver = NULL; - status = psa_start_key_creation( attributes, handle, &slot, &driver ); + status = psa_start_key_creation( PSA_KEY_CREATION_DERIVE, + attributes, handle, &slot, &driver ); #if defined(MBEDTLS_PSA_CRYPTO_SE_C) if( driver != NULL ) { @@ -5820,20 +6001,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( attributes, handle, &slot, &driver ); + + 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 ) @@ -5895,7 +6093,9 @@ static psa_status_t psa_crypto_recover_transaction( case PSA_CRYPTO_TRANSACTION_CREATE_KEY: case PSA_CRYPTO_TRANSACTION_DESTROY_KEY: /* TODO - fall through to the failure case until this - * is implemented */ + * is implemented. + * https://github.com/ARMmbed/mbed-crypto/issues/218 + */ default: /* We found an unsupported transaction in the storage. * We don't know what state the storage is in. Give up. */ diff --git a/library/psa_crypto_core.h b/library/psa_crypto_core.h index fbfb6daef..edf3ab603 100644 --- a/library/psa_crypto_core.h +++ b/library/psa_crypto_core.h @@ -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 diff --git a/library/psa_crypto_se.c b/library/psa_crypto_se.c index bc7325180..523c62105 100644 --- a/library/psa_crypto_se.c +++ b/library/psa_crypto_se.c @@ -197,11 +197,11 @@ psa_status_t psa_destroy_se_persistent_data( psa_key_lifetime_t lifetime ) psa_status_t psa_find_se_slot_for_key( const psa_key_attributes_t *attributes, + psa_key_creation_method_t method, psa_se_drv_table_entry_t *driver, 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 +210,34 @@ 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, method, + *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, method, + slot_number ); + } return( status ); } diff --git a/library/psa_crypto_se.h b/library/psa_crypto_se.h index 378c78ffe..900a72bd3 100644 --- a/library/psa_crypto_se.h +++ b/library/psa_crypto_se.h @@ -135,6 +135,7 @@ psa_drv_se_context_t *psa_get_se_driver_context( */ psa_status_t psa_find_se_slot_for_key( const psa_key_attributes_t *attributes, + psa_key_creation_method_t method, psa_se_drv_table_entry_t *driver, psa_key_slot_number_t *slot_number ); diff --git a/library/psa_crypto_slot_management.c b/library/psa_crypto_slot_management.c index 073400988..fe9214831 100644 --- a/library/psa_crypto_slot_management.c +++ b/library/psa_crypto_slot_management.c @@ -102,7 +102,7 @@ void psa_wipe_all_key_slots( void ) global_data.key_slots_initialized = 0; } -psa_status_t psa_internal_allocate_key_slot( psa_key_handle_t *handle, +psa_status_t psa_get_empty_key_slot( psa_key_handle_t *handle, psa_key_slot_t **p_slot ) { if( ! global_data.key_slots_initialized ) @@ -228,7 +228,7 @@ psa_status_t psa_open_key( psa_key_file_id_t id, psa_key_handle_t *handle ) if( status != PSA_SUCCESS ) return( status ); - status = psa_internal_allocate_key_slot( handle, &slot ); + status = psa_get_empty_key_slot( handle, &slot ); if( status != PSA_SUCCESS ) return( status ); diff --git a/library/psa_crypto_slot_management.h b/library/psa_crypto_slot_management.h index cde590fc5..472253dd9 100644 --- a/library/psa_crypto_slot_management.h +++ b/library/psa_crypto_slot_management.h @@ -71,8 +71,8 @@ void psa_wipe_all_key_slots( void ); * \retval #PSA_ERROR_INSUFFICIENT_MEMORY * \retval #PSA_ERROR_BAD_STATE */ -psa_status_t psa_internal_allocate_key_slot( psa_key_handle_t *handle, - psa_key_slot_t **p_slot ); +psa_status_t psa_get_empty_key_slot( psa_key_handle_t *handle, + psa_key_slot_t **p_slot ); /** Test whether a lifetime designates a key in an external cryptoprocessor. * diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index b04984024..21e3c5200 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -19,6 +19,9 @@ persistence_attributes:0x1234:3:-1:0x1234:3 PSA key attributes: lifetime then id persistence_attributes:0x1234:3:0x1235:0x1235:3 +PSA key attributes: slot number +slot_number_attribute: + PSA import/export raw: 0 bytes import_export:"":PSA_KEY_TYPE_RAW_DATA:PSA_KEY_USAGE_EXPORT:0:0:0:PSA_SUCCESS:1 @@ -353,6 +356,14 @@ PSA key policy: MAC, wrong algorithm depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C mac_key_policy:PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY:PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_224) +PSA key policy: MAC, alg=0 in policy +depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C +mac_key_policy:PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY:0:PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_256) + +PSA key policy: MAC, ANY_HASH in policy is not meaningful +depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C +mac_key_policy:PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY:PSA_ALG_HMAC(PSA_ALG_ANY_HASH):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_256) + PSA key policy: MAC, sign but not verify depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C mac_key_policy:PSA_KEY_USAGE_SIGN:PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_256) @@ -385,6 +396,10 @@ PSA key policy: cipher, neither encrypt nor decrypt depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR cipher_key_policy:0:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_CTR +PSA key policy: cipher, alg=0 in policy +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_key_policy:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:0:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_CTR + PSA key policy: AEAD, encrypt | decrypt depends_on:MBEDTLS_AES_C:MBEDTLS_CCM_C aead_key_policy:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_CCM:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":13:16:PSA_ALG_CCM @@ -393,6 +408,10 @@ PSA key policy: AEAD, wrong algorithm depends_on:MBEDTLS_AES_C:MBEDTLS_CCM_C:MBEDTLS_GCM_C aead_key_policy:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_CCM:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":16:16:PSA_ALG_GCM +PSA key policy: AEAD, alg=0 in policy +depends_on:MBEDTLS_AES_C:MBEDTLS_CCM_C +aead_key_policy:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:0:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":16:16:PSA_ALG_CCM + PSA key policy: AEAD, encrypt but not decrypt depends_on:MBEDTLS_AES_C:MBEDTLS_CCM_C aead_key_policy:PSA_KEY_USAGE_ENCRYPT:PSA_ALG_CCM:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":13:16:PSA_ALG_CCM @@ -417,6 +436,10 @@ PSA key policy: asymmetric encryption, wrong algorithm (OAEP with different hash depends_on:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V21:MBEDTLS_SHA256_C asymmetric_encryption_key_policy:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_RSA_OAEP(PSA_ALG_SHA_224):PSA_KEY_TYPE_RSA_KEY_PAIR:"3082013b020100024100ee2b131d6b1818a94ca8e91c42387eb15a7c271f57b89e7336b144d4535b16c83097ecdefbbb92d1b5313b5a37214d0e8f25922dca778b424b25295fc8a1a7070203010001024100978ac8eadb0dc6035347d6aba8671215ff21283385396f7897c04baf5e2a835f3b53ef80a82ed36ae687a925380b55a0c73eb85656e989dcf0ed7fb4887024e1022100fdad8e1c6853563f8b921d2d112462ae7d6b176082d2ba43e87e1a37fc1a8b33022100f0592cf4c55ba44307b18981bcdbda376c51e590ffa5345ba866f6962dca94dd02201995f1a967d44ff4a4cd1de837bc65bf97a2bf7eda730a9a62cea53254591105022027f96cf4b8ee68ff8d04062ec1ce7f18c0b74e4b3379b29f9bfea3fc8e592731022100cefa6d220496b43feb83194255d8fb930afcf46f36606e3aa0eb7a93ad88c10c":PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256) +PSA key policy: asymmetric encryption, alg=0 in policy +depends_on:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15 +asymmetric_encryption_key_policy:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:0:PSA_KEY_TYPE_RSA_KEY_PAIR:"3082013b020100024100ee2b131d6b1818a94ca8e91c42387eb15a7c271f57b89e7336b144d4535b16c83097ecdefbbb92d1b5313b5a37214d0e8f25922dca778b424b25295fc8a1a7070203010001024100978ac8eadb0dc6035347d6aba8671215ff21283385396f7897c04baf5e2a835f3b53ef80a82ed36ae687a925380b55a0c73eb85656e989dcf0ed7fb4887024e1022100fdad8e1c6853563f8b921d2d112462ae7d6b176082d2ba43e87e1a37fc1a8b33022100f0592cf4c55ba44307b18981bcdbda376c51e590ffa5345ba866f6962dca94dd02201995f1a967d44ff4a4cd1de837bc65bf97a2bf7eda730a9a62cea53254591105022027f96cf4b8ee68ff8d04062ec1ce7f18c0b74e4b3379b29f9bfea3fc8e592731022100cefa6d220496b43feb83194255d8fb930afcf46f36606e3aa0eb7a93ad88c10c":PSA_ALG_RSA_PKCS1V15_CRYPT + PSA key policy: asymmetric encryption, ANY_HASH in policy is not meaningful depends_on:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V21:MBEDTLS_SHA256_C asymmetric_encryption_key_policy:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_RSA_OAEP(PSA_ALG_ANY_HASH):PSA_KEY_TYPE_RSA_KEY_PAIR:"3082013b020100024100ee2b131d6b1818a94ca8e91c42387eb15a7c271f57b89e7336b144d4535b16c83097ecdefbbb92d1b5313b5a37214d0e8f25922dca778b424b25295fc8a1a7070203010001024100978ac8eadb0dc6035347d6aba8671215ff21283385396f7897c04baf5e2a835f3b53ef80a82ed36ae687a925380b55a0c73eb85656e989dcf0ed7fb4887024e1022100fdad8e1c6853563f8b921d2d112462ae7d6b176082d2ba43e87e1a37fc1a8b33022100f0592cf4c55ba44307b18981bcdbda376c51e590ffa5345ba866f6962dca94dd02201995f1a967d44ff4a4cd1de837bc65bf97a2bf7eda730a9a62cea53254591105022027f96cf4b8ee68ff8d04062ec1ce7f18c0b74e4b3379b29f9bfea3fc8e592731022100cefa6d220496b43feb83194255d8fb930afcf46f36606e3aa0eb7a93ad88c10c":PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256) @@ -461,6 +484,10 @@ PSA key policy: asymmetric signature, wrong hash algorithm depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA256_C asymmetric_signature_key_policy:PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY:PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256):PSA_KEY_TYPE_RSA_KEY_PAIR:"3082013b020100024100ee2b131d6b1818a94ca8e91c42387eb15a7c271f57b89e7336b144d4535b16c83097ecdefbbb92d1b5313b5a37214d0e8f25922dca778b424b25295fc8a1a7070203010001024100978ac8eadb0dc6035347d6aba8671215ff21283385396f7897c04baf5e2a835f3b53ef80a82ed36ae687a925380b55a0c73eb85656e989dcf0ed7fb4887024e1022100fdad8e1c6853563f8b921d2d112462ae7d6b176082d2ba43e87e1a37fc1a8b33022100f0592cf4c55ba44307b18981bcdbda376c51e590ffa5345ba866f6962dca94dd02201995f1a967d44ff4a4cd1de837bc65bf97a2bf7eda730a9a62cea53254591105022027f96cf4b8ee68ff8d04062ec1ce7f18c0b74e4b3379b29f9bfea3fc8e592731022100cefa6d220496b43feb83194255d8fb930afcf46f36606e3aa0eb7a93ad88c10c":PSA_ALG_RSA_PKCS1V15_SIGN_RAW:0 +PSA key policy: asymmetric signature, alg=0 in policy +depends_on:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15 +asymmetric_signature_key_policy:PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY:0:PSA_KEY_TYPE_RSA_KEY_PAIR:"3082013b020100024100ee2b131d6b1818a94ca8e91c42387eb15a7c271f57b89e7336b144d4535b16c83097ecdefbbb92d1b5313b5a37214d0e8f25922dca778b424b25295fc8a1a7070203010001024100978ac8eadb0dc6035347d6aba8671215ff21283385396f7897c04baf5e2a835f3b53ef80a82ed36ae687a925380b55a0c73eb85656e989dcf0ed7fb4887024e1022100fdad8e1c6853563f8b921d2d112462ae7d6b176082d2ba43e87e1a37fc1a8b33022100f0592cf4c55ba44307b18981bcdbda376c51e590ffa5345ba866f6962dca94dd02201995f1a967d44ff4a4cd1de837bc65bf97a2bf7eda730a9a62cea53254591105022027f96cf4b8ee68ff8d04062ec1ce7f18c0b74e4b3379b29f9bfea3fc8e592731022100cefa6d220496b43feb83194255d8fb930afcf46f36606e3aa0eb7a93ad88c10c":PSA_ALG_RSA_PKCS1V15_SIGN_RAW:0 + PSA key policy: asymmetric signature, sign but not verify depends_on:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15 asymmetric_signature_key_policy:PSA_KEY_USAGE_SIGN:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_TYPE_RSA_KEY_PAIR:"3082013b020100024100ee2b131d6b1818a94ca8e91c42387eb15a7c271f57b89e7336b144d4535b16c83097ecdefbbb92d1b5313b5a37214d0e8f25922dca778b424b25295fc8a1a7070203010001024100978ac8eadb0dc6035347d6aba8671215ff21283385396f7897c04baf5e2a835f3b53ef80a82ed36ae687a925380b55a0c73eb85656e989dcf0ed7fb4887024e1022100fdad8e1c6853563f8b921d2d112462ae7d6b176082d2ba43e87e1a37fc1a8b33022100f0592cf4c55ba44307b18981bcdbda376c51e590ffa5345ba866f6962dca94dd02201995f1a967d44ff4a4cd1de837bc65bf97a2bf7eda730a9a62cea53254591105022027f96cf4b8ee68ff8d04062ec1ce7f18c0b74e4b3379b29f9bfea3fc8e592731022100cefa6d220496b43feb83194255d8fb930afcf46f36606e3aa0eb7a93ad88c10c":PSA_ALG_RSA_PKCS1V15_SIGN_RAW:1 diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 0eb6172a4..3225bef34 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -1113,6 +1113,23 @@ exit: return( ok ); } +/* Assert that a key isn't reported as having a slot number. */ +#if defined(MBEDTLS_PSA_CRYPTO_SE_C) +#define ASSERT_NO_SLOT_NUMBER( attributes ) \ + do \ + { \ + psa_key_slot_number_t ASSERT_NO_SLOT_NUMBER_slot_number; \ + TEST_EQUAL( psa_get_key_slot_number( \ + attributes, \ + &ASSERT_NO_SLOT_NUMBER_slot_number ), \ + PSA_ERROR_INVALID_ARGUMENT ); \ + } \ + while( 0 ) +#else /* MBEDTLS_PSA_CRYPTO_SE_C */ +#define ASSERT_NO_SLOT_NUMBER( attributes ) \ + ( (void) 0 ) +#endif /* MBEDTLS_PSA_CRYPTO_SE_C */ + /* An overapproximation of the amount of storage needed for a key of the * given type and with the given content. The API doesn't make it easy * to find a good value for the size. The current implementation doesn't @@ -1214,6 +1231,46 @@ void persistence_attributes( int id1_arg, int lifetime_arg, int id2_arg, } /* END_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_SE_C */ +void slot_number_attribute( ) +{ + psa_key_slot_number_t slot_number = 0xdeadbeef; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + + /* Initially, there is no slot number. */ + TEST_EQUAL( psa_get_key_slot_number( &attributes, &slot_number ), + PSA_ERROR_INVALID_ARGUMENT ); + + /* Test setting a slot number. */ + psa_set_key_slot_number( &attributes, 0 ); + PSA_ASSERT( psa_get_key_slot_number( &attributes, &slot_number ) ); + TEST_EQUAL( slot_number, 0 ); + + /* Test changing the slot number. */ + psa_set_key_slot_number( &attributes, 42 ); + PSA_ASSERT( psa_get_key_slot_number( &attributes, &slot_number ) ); + TEST_EQUAL( slot_number, 42 ); + + /* Test clearing the slot number. */ + psa_clear_key_slot_number( &attributes ); + TEST_EQUAL( psa_get_key_slot_number( &attributes, &slot_number ), + PSA_ERROR_INVALID_ARGUMENT ); + + /* Clearing again should have no effect. */ + psa_clear_key_slot_number( &attributes ); + TEST_EQUAL( psa_get_key_slot_number( &attributes, &slot_number ), + PSA_ERROR_INVALID_ARGUMENT ); + + /* Test that reset clears the slot number. */ + psa_set_key_slot_number( &attributes, 42 ); + PSA_ASSERT( psa_get_key_slot_number( &attributes, &slot_number ) ); + TEST_EQUAL( slot_number, 42 ); + psa_reset_key_attributes( &attributes ); + TEST_EQUAL( psa_get_key_slot_number( &attributes, &slot_number ), + PSA_ERROR_INVALID_ARGUMENT ); +} +/* END_CASE */ + /* BEGIN_CASE */ void import_with_policy( int type_arg, int usage_arg, int alg_arg, @@ -1246,6 +1303,7 @@ void import_with_policy( int type_arg, TEST_EQUAL( psa_get_key_type( &got_attributes ), type ); TEST_EQUAL( psa_get_key_usage_flags( &got_attributes ), usage ); TEST_EQUAL( psa_get_key_algorithm( &got_attributes ), alg ); + ASSERT_NO_SLOT_NUMBER( &got_attributes ); PSA_ASSERT( psa_destroy_key( handle ) ); test_operations_on_invalid_handle( handle ); @@ -1284,6 +1342,7 @@ void import_with_data( data_t *data, int type_arg, TEST_EQUAL( psa_get_key_type( &got_attributes ), type ); if( attr_bits != 0 ) TEST_EQUAL( attr_bits, psa_get_key_bits( &got_attributes ) ); + ASSERT_NO_SLOT_NUMBER( &got_attributes ); PSA_ASSERT( psa_destroy_key( handle ) ); test_operations_on_invalid_handle( handle ); @@ -1328,6 +1387,7 @@ void import_large_key( int type_arg, int byte_size_arg, TEST_EQUAL( psa_get_key_type( &attributes ), type ); TEST_EQUAL( psa_get_key_bits( &attributes ), PSA_BYTES_TO_BITS( byte_size ) ); + ASSERT_NO_SLOT_NUMBER( &attributes ); memset( buffer, 0, byte_size + 1 ); PSA_ASSERT( psa_export_key( handle, buffer, byte_size, &n ) ); for( n = 0; n < byte_size; n++ ) @@ -1420,6 +1480,7 @@ void import_export( data_t *data, PSA_ASSERT( psa_get_key_attributes( handle, &got_attributes ) ); TEST_EQUAL( psa_get_key_type( &got_attributes ), type ); TEST_EQUAL( psa_get_key_bits( &got_attributes ), (size_t) expected_bits ); + ASSERT_NO_SLOT_NUMBER( &got_attributes ); /* Export the key */ status = psa_export_key( handle, 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..5819f785b 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal.data +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.data @@ -39,59 +39,125 @@ key_creation_import_export:0:1 SE key import-export, check after restart (slot 3) key_creation_import_export:3:1 -Key creation smoke test: AES-CTR -key_creation_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CTR:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key creation in a specific slot (0) +key_creation_in_chosen_slot:0:0:PSA_SUCCESS -Key creation smoke test: AES-CBC -key_creation_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CBC_NO_PADDING:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key creation in a specific slot (max) +key_creation_in_chosen_slot:ARRAY_LENGTH( ram_slots ) - 1:0:PSA_SUCCESS -Key creation smoke test: AES-CMAC -key_creation_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key creation in a specific slot (0, restart) +key_creation_in_chosen_slot:0:1:PSA_SUCCESS -Key creation smoke test: AES-CCM -key_creation_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key creation in a specific slot (max, restart) +key_creation_in_chosen_slot:ARRAY_LENGTH( ram_slots ) - 1:1:PSA_SUCCESS -Key creation smoke test: AES-GCM -key_creation_smoke:PSA_KEY_TYPE_AES:PSA_ALG_GCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +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: CAMELLIA-CTR -key_creation_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_CTR:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: AES-CTR +import_key_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CTR:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: CAMELLIA-CBC -key_creation_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_CBC_NO_PADDING:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: AES-CBC +import_key_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CBC_NO_PADDING:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: CAMELLIA-CMAC -key_creation_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_CMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: AES-CMAC +import_key_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: CAMELLIA-CCM -key_creation_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_GCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: AES-CCM +import_key_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: CAMELLIA-CCM -key_creation_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_GCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: AES-GCM +import_key_smoke:PSA_KEY_TYPE_AES:PSA_ALG_GCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: HMAC-SHA-256 -key_creation_smoke:PSA_KEY_TYPE_HMAC:PSA_ALG_HMAC( PSA_ALG_SHA_256 ):"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: CAMELLIA-CTR +import_key_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_CTR:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: HKDF-SHA-256 -key_creation_smoke:PSA_KEY_TYPE_DERIVE:PSA_ALG_HKDF( PSA_ALG_SHA_256 ):"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: CAMELLIA-CBC +import_key_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_CBC_NO_PADDING:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: RSA PKCS#1v1.5 signature -key_creation_smoke:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:"30818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001" +Key import smoke test: CAMELLIA-CMAC +import_key_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_CMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: RSA PKCS#1v1.5 encryption -key_creation_smoke:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_ALG_RSA_PKCS1V15_CRYPT:"30818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001" +Key import smoke test: CAMELLIA-CCM +import_key_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_GCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: RSA OAEP encryption -key_creation_smoke:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_ALG_RSA_OAEP( PSA_ALG_SHA_256 ):"30818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001" +Key import smoke test: CAMELLIA-CCM +import_key_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_GCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: ECDSA secp256r1 -key_creation_smoke:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee" +Key import smoke test: HMAC-SHA-256 +import_key_smoke:PSA_KEY_TYPE_HMAC:PSA_ALG_HMAC( PSA_ALG_SHA_256 ):"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: ECDH secp256r1 -key_creation_smoke:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDH:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee" +Key import smoke test: HKDF-SHA-256 +import_key_smoke:PSA_KEY_TYPE_DERIVE:PSA_ALG_HKDF( PSA_ALG_SHA_256 ):"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: ECDH secp256r1 with HKDF -key_creation_smoke:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_KEY_AGREEMENT( PSA_ALG_ECDH, PSA_ALG_HKDF( PSA_ALG_SHA_256 ) ):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee" +Key import smoke test: RSA PKCS#1v1.5 signature +import_key_smoke:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:"30818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001" + +Key import smoke test: RSA PKCS#1v1.5 encryption +import_key_smoke:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_ALG_RSA_PKCS1V15_CRYPT:"30818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001" + +Key import smoke test: RSA OAEP encryption +import_key_smoke:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_ALG_RSA_OAEP( PSA_ALG_SHA_256 ):"30818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001" + +Key import smoke test: ECDSA secp256r1 +import_key_smoke:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee" + +Key import smoke test: ECDH secp256r1 +import_key_smoke:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDH:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee" + +Key import smoke test: ECDH secp256r1 with HKDF +import_key_smoke:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_KEY_AGREEMENT( PSA_ALG_ECDH, PSA_ALG_HKDF( PSA_ALG_SHA_256 ) ):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee" Generate key: not supported generate_key_not_supported:PSA_KEY_TYPE_AES:128 + +Key generation smoke test: AES-128-CTR +generate_key_smoke:PSA_KEY_TYPE_AES:128:PSA_ALG_CTR + +Key generation smoke test: AES-256-CTR +generate_key_smoke:PSA_KEY_TYPE_AES:128:PSA_ALG_CTR + +Key generation smoke test: HMAC-SHA-256 +generate_key_smoke:PSA_KEY_TYPE_HMAC:256:PSA_ALG_HMAC( PSA_ALG_SHA_256 ) + +Key registration: smoke test +register_key_smoke_test:MIN_DRIVER_LIFETIME:-1:PSA_SUCCESS + +Key registration: invalid lifetime (volatile) +register_key_smoke_test:PSA_KEY_LIFETIME_VOLATILE:-1:PSA_ERROR_INVALID_ARGUMENT + +Key registration: invalid lifetime (internal storage) +register_key_smoke_test:PSA_KEY_LIFETIME_PERSISTENT:-1:PSA_ERROR_INVALID_ARGUMENT + +Key registration: invalid lifetime (no registered driver) +register_key_smoke_test:MIN_DRIVER_LIFETIME + 1:-1:PSA_ERROR_INVALID_ARGUMENT + +Key registration: with driver validation (accepted) +register_key_smoke_test:MIN_DRIVER_LIFETIME:1:PSA_SUCCESS + +Key registration: with driver validation (rejected) +register_key_smoke_test:MIN_DRIVER_LIFETIME:0:PSA_ERROR_NOT_PERMITTED + +Import-sign-verify: sign in driver, ECDSA +depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED +sign_verify:SIGN_IN_DRIVER_AND_PARALLEL_CREATION:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:0:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" + +Import-sign-verify: sign in driver then export_public, ECDSA +depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED +sign_verify:SIGN_IN_DRIVER_THEN_EXPORT_PUBLIC:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:0:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" + +Import-sign-verify: sign in software, ECDSA +depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED +sign_verify:SIGN_IN_SOFTWARE_AND_PARALLEL_CREATION:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:0:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" + +Generate-sign-verify: sign in driver, ECDSA +depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED +sign_verify:SIGN_IN_DRIVER_AND_PARALLEL_CREATION:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:256:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" + +Generate-sign-verify: sign in driver then export_public, ECDSA +depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED +sign_verify:SIGN_IN_DRIVER_THEN_EXPORT_PUBLIC:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:256:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" + +Generate-sign-verify: sign in software, ECDSA +depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED +sign_verify:SIGN_IN_SOFTWARE_AND_PARALLEL_CREATION:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:256:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" 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 6ac19a60e..fc6f66816 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal.function +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.function @@ -18,11 +18,13 @@ * This is probably a bug in the library. */ #define PSA_ERROR_DETECTED_BY_DRIVER ((psa_status_t)( -500 )) -/** Like #TEST_ASSERT for use in a driver method. +/** Like #TEST_ASSERT for use in a driver method, with no cleanup. + * + * If an error happens, this macro returns from the calling function. * * Use this macro to assert on guarantees provided by the core. */ -#define DRIVER_ASSERT( TEST ) \ +#define DRIVER_ASSERT_RETURN( TEST ) \ do { \ if( ! (TEST) ) \ { \ @@ -31,20 +33,86 @@ } \ } while( 0 ) +/** Like #TEST_ASSERT for use in a driver method, with cleanup. + * + * In case of error, this macro sets `status` and jumps to the + * label `exit`. + * + * Use this macro to assert on guarantees provided by the core. + */ +#define DRIVER_ASSERT( TEST ) \ + do { \ + if( ! (TEST) ) \ + { \ + test_fail( #TEST, __LINE__, __FILE__ ); \ + status = PSA_ERROR_DETECTED_BY_DRIVER; \ + goto exit; \ + } \ + } while( 0 ) + +/** Like #PSA_ASSERT for a PSA API call that calls a driver underneath. + * + * Run the code \p expr. If this returns \p expected_status, + * do nothing. If this returns #PSA_ERROR_DETECTED_BY_DRIVER, + * jump directly to the `exit` label. If this returns any other + * status, call test_fail() then jump to `exit`. + * + * The special case for #PSA_ERROR_DETECTED_BY_DRIVER is because in this + * case, the test driver code is expected to have called test_fail() + * already, so we make sure not to overwrite the failure information. + */ +#define PSA_ASSERT_VIA_DRIVER( expr, expected_status ) \ + do { \ + psa_status_t PSA_ASSERT_VIA_DRIVER_status = ( expr ); \ + if( PSA_ASSERT_VIA_DRIVER_status == PSA_ERROR_DETECTED_BY_DRIVER ) \ + goto exit; \ + if( PSA_ASSERT_VIA_DRIVER_status != ( expected_status ) ) \ + { \ + test_fail( #expr, __LINE__, __FILE__ ); \ + goto exit; \ + } \ + } while( 0 ) + /****************************************************************/ /* Miscellaneous driver methods */ /****************************************************************/ +typedef struct +{ + psa_key_slot_number_t slot_number; + psa_key_creation_method_t method; + psa_status_t status; +} validate_slot_number_directions_t; +static validate_slot_number_directions_t validate_slot_number_directions; + +/* Validate a choice of slot number as directed. */ +static psa_status_t validate_slot_number_as_directed( + psa_drv_se_context_t *context, + const psa_key_attributes_t *attributes, + psa_key_creation_method_t method, + psa_key_slot_number_t slot_number ) +{ + (void) context; + (void) attributes; + DRIVER_ASSERT_RETURN( slot_number == + validate_slot_number_directions.slot_number ); + DRIVER_ASSERT_RETURN( method == + validate_slot_number_directions.method ); + return( validate_slot_number_directions.status ); +} + /* Allocate slot numbers with a monotonic counter. */ static psa_status_t counter_allocate( psa_drv_se_context_t *context, void *persistent_data, const psa_key_attributes_t *attributes, + psa_key_creation_method_t method, psa_key_slot_number_t *slot_number ) { psa_key_slot_number_t *p_counter = persistent_data; (void) attributes; + (void) method; if( context->persistent_data_size != sizeof( psa_key_slot_number_t ) ) return( PSA_ERROR_DETECTED_BY_DRIVER ); ++*p_counter; @@ -57,27 +125,54 @@ static psa_status_t counter_allocate( psa_drv_se_context_t *context, /* Null import: do nothing, but pretend it worked. */ static psa_status_t null_import( psa_drv_se_context_t *context, psa_key_slot_number_t slot_number, - psa_key_lifetime_t lifetime, - psa_key_type_t type, - psa_algorithm_t algorithm, - psa_key_usage_t usage, - const uint8_t *p_data, + const psa_key_attributes_t *attributes, + const uint8_t *data, size_t data_length, size_t *bits ) { (void) context; (void) slot_number; - (void) lifetime; - (void) type; - (void) algorithm; - (void) usage; - (void) p_data; + (void) attributes; + (void) data; /* We're supposed to return a key size. Return one that's correct for * plain data keys. */ *bits = PSA_BYTES_TO_BITS( data_length ); return( PSA_SUCCESS ); } +/* Null generate: do nothing, but pretend it worked. */ +static psa_status_t null_generate( psa_drv_se_context_t *context, + psa_key_slot_number_t slot_number, + const psa_key_attributes_t *attributes, + uint8_t *pubkey, + size_t pubkey_size, + size_t *pubkey_length ) +{ + (void) context; + (void) slot_number; + (void) attributes; + + DRIVER_ASSERT_RETURN( *pubkey_length == 0 ); + if( ! PSA_KEY_TYPE_IS_KEY_PAIR( psa_get_key_type( attributes ) ) ) + { + DRIVER_ASSERT_RETURN( pubkey == NULL ); + DRIVER_ASSERT_RETURN( pubkey_size == 0 ); + } + + return( PSA_SUCCESS ); +} + +/* Null destroy: do nothing, but pretend it worked. */ +static psa_status_t null_destroy( psa_drv_se_context_t *context, + void *persistent_data, + psa_key_slot_number_t slot_number ) +{ + (void) context; + (void) persistent_data; + (void) slot_number; + return( PSA_SUCCESS ); +} + /****************************************************************/ @@ -106,44 +201,135 @@ static void ram_slots_reset( void ) ram_min_slot = 0; } +/* Common parts of key creation. + * + * In case of error, zero out ram_slots[slot_number]. But don't + * do that if the error is PSA_ERROR_DETECTED_BY_DRIVER: in this case + * you don't need to clean up (ram_slot_reset() will take care of it + * in the test case function's cleanup code) and it might be wrong + * (if slot_number is invalid). + */ +static psa_status_t ram_create_common( psa_drv_se_context_t *context, + psa_key_slot_number_t slot_number, + const psa_key_attributes_t *attributes, + size_t required_storage ) +{ + (void) context; + DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) ); + + ram_slots[slot_number].lifetime = psa_get_key_lifetime( attributes ); + ram_slots[slot_number].type = psa_get_key_type( attributes ); + ram_slots[slot_number].bits = psa_get_key_bits( attributes ); + + if( required_storage > sizeof( ram_slots[slot_number].content ) ) + { + memset( &ram_slots[slot_number], 0, sizeof( ram_slots[slot_number] ) ); + return( PSA_ERROR_INSUFFICIENT_STORAGE ); + } + + return( PSA_SUCCESS ); +} + +/* This function does everything except actually generating key material. + * After calling it, you must copy the desired key material to + * ram_slots[slot_number].content. */ +static psa_status_t ram_fake_generate( psa_drv_se_context_t *context, + psa_key_slot_number_t slot_number, + const psa_key_attributes_t *attributes, + uint8_t *pubkey, + size_t pubkey_size, + size_t *pubkey_length ) +{ + psa_status_t status; + size_t required_storage = + PSA_KEY_EXPORT_MAX_SIZE( psa_get_key_type( attributes ), + psa_get_key_bits( attributes ) ); + + DRIVER_ASSERT_RETURN( *pubkey_length == 0 ); + if( ! PSA_KEY_TYPE_IS_KEY_PAIR( psa_get_key_type( attributes ) ) ) + { + DRIVER_ASSERT_RETURN( pubkey == NULL ); + DRIVER_ASSERT_RETURN( pubkey_size == 0 ); + } + + status = ram_create_common( context, slot_number, attributes, + required_storage ); + return( status ); +} + static psa_status_t ram_import( psa_drv_se_context_t *context, psa_key_slot_number_t slot_number, - psa_key_lifetime_t lifetime, - psa_key_type_t type, - psa_algorithm_t algorithm, - psa_key_usage_t usage, - const uint8_t *p_data, + const psa_key_attributes_t *attributes, + const uint8_t *data, size_t data_length, size_t *bits ) { - (void) context; - DRIVER_ASSERT( slot_number < ARRAY_LENGTH( ram_slots ) ); - if( data_length > sizeof( ram_slots[slot_number].content ) ) - return( PSA_ERROR_INSUFFICIENT_STORAGE ); - ram_slots[slot_number].lifetime = lifetime; - ram_slots[slot_number].type = type; - ram_slots[slot_number].bits = PSA_BYTES_TO_BITS( data_length ); - *bits = PSA_BYTES_TO_BITS( data_length ); - (void) algorithm; - (void) usage; - memcpy( ram_slots[slot_number].content, p_data, data_length ); + psa_key_type_t type = psa_get_key_type( attributes ); + psa_status_t status = ram_create_common( context, slot_number, attributes, + data_length ); + if( status != PSA_SUCCESS ) + return( status ); + + /* The RAM driver only works for certain key types: raw keys, + * and ECC key pairs. This is true in particular of the bit-size + * calculation here. */ + if( PSA_KEY_TYPE_IS_UNSTRUCTURED( type ) ) + *bits = PSA_BYTES_TO_BITS( data_length ); + else if ( PSA_KEY_TYPE_IS_ECC_KEY_PAIR( type ) ) + *bits = PSA_ECC_CURVE_BITS( PSA_KEY_TYPE_GET_CURVE( type ) ); + else + { + memset( &ram_slots[slot_number], 0, sizeof( ram_slots[slot_number] ) ); + return( PSA_ERROR_NOT_SUPPORTED ); + } + + ram_slots[slot_number].bits = *bits; + memcpy( ram_slots[slot_number].content, data, data_length ); + return( PSA_SUCCESS ); } static psa_status_t ram_export( psa_drv_se_context_t *context, psa_key_slot_number_t slot_number, - uint8_t *p_data, + uint8_t *data, size_t data_size, - size_t *p_data_length ) + size_t *data_length ) { size_t actual_size; (void) context; - DRIVER_ASSERT( slot_number < ARRAY_LENGTH( ram_slots ) ); + DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) ); actual_size = PSA_BITS_TO_BYTES( ram_slots[slot_number].bits ); if( actual_size > data_size ) return( PSA_ERROR_BUFFER_TOO_SMALL ); - *p_data_length = actual_size; - memcpy( p_data, ram_slots[slot_number].content, actual_size ); + *data_length = actual_size; + memcpy( data, ram_slots[slot_number].content, actual_size ); + return( PSA_SUCCESS ); +} + +static psa_status_t ram_export_public( psa_drv_se_context_t *context, + psa_key_slot_number_t slot_number, + uint8_t *data, + size_t data_size, + size_t *data_length ) +{ + psa_status_t status; + psa_key_handle_t handle; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + + (void) context; + DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) ); + DRIVER_ASSERT_RETURN( + PSA_KEY_TYPE_IS_KEY_PAIR( ram_slots[slot_number].type ) ); + + psa_set_key_type( &attributes, ram_slots[slot_number].type ); + status = psa_import_key( &attributes, + ram_slots[slot_number].content, + PSA_BITS_TO_BYTES( ram_slots[slot_number].bits ), + &handle ); + if( status != PSA_SUCCESS ) + return( status ); + status = psa_export_public_key( handle, data, data_size, data_length ); + psa_destroy_key( handle ); return( PSA_SUCCESS ); } @@ -152,8 +338,8 @@ static psa_status_t ram_destroy( psa_drv_se_context_t *context, psa_key_slot_number_t slot_number ) { ram_slot_usage_t *slot_usage = persistent_data; - DRIVER_ASSERT( context->persistent_data_size == sizeof( ram_slot_usage_t ) ); - DRIVER_ASSERT( slot_number < ARRAY_LENGTH( ram_slots ) ); + DRIVER_ASSERT_RETURN( context->persistent_data_size == sizeof( ram_slot_usage_t ) ); + DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) ); memset( &ram_slots[slot_number], 0, sizeof( ram_slots[slot_number] ) ); *slot_usage &= ~(ram_slot_usage_t)( 1 << slot_number ); return( PSA_SUCCESS ); @@ -162,11 +348,13 @@ static psa_status_t ram_destroy( psa_drv_se_context_t *context, static psa_status_t ram_allocate( psa_drv_se_context_t *context, void *persistent_data, const psa_key_attributes_t *attributes, + psa_key_creation_method_t method, psa_key_slot_number_t *slot_number ) { ram_slot_usage_t *slot_usage = persistent_data; (void) attributes; - DRIVER_ASSERT( context->persistent_data_size == sizeof( ram_slot_usage_t ) ); + (void) method; + DRIVER_ASSERT_RETURN( context->persistent_data_size == sizeof( ram_slot_usage_t ) ); for( *slot_number = ram_min_slot; *slot_number < ARRAY_LENGTH( ram_slots ); ++( *slot_number ) ) @@ -177,12 +365,103 @@ 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_creation_method_t method, + psa_key_slot_number_t slot_number ) +{ + (void) context; + (void) attributes; + (void) method; + if( slot_number >= ARRAY_LENGTH( ram_slots ) ) + return( PSA_ERROR_INVALID_ARGUMENT ); + return( PSA_SUCCESS ); +} + +static psa_status_t ram_sign( psa_drv_se_context_t *context, + psa_key_slot_number_t slot_number, + psa_algorithm_t alg, + const uint8_t *hash, + size_t hash_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length ) +{ + ram_slot_t *slot; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_handle_t handle = 0; + psa_status_t status = PSA_ERROR_GENERIC_ERROR; + + (void) context; + DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) ); + slot = &ram_slots[slot_number]; + + psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN ); + psa_set_key_algorithm( &attributes, alg ); + psa_set_key_type( &attributes, slot->type ); + DRIVER_ASSERT( psa_import_key( &attributes, + slot->content, + PSA_BITS_TO_BYTES( slot->bits ), + &handle ) == PSA_SUCCESS ); + status = psa_asymmetric_sign( handle, alg, + hash, hash_length, + signature, signature_size, + signature_length ); + +exit: + psa_destroy_key( handle ); + return( status ); +} + +static psa_status_t ram_verify( psa_drv_se_context_t *context, + psa_key_slot_number_t slot_number, + psa_algorithm_t alg, + const uint8_t *hash, + size_t hash_length, + const uint8_t *signature, + size_t signature_length ) +{ + ram_slot_t *slot; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_handle_t handle = 0; + psa_status_t status = PSA_ERROR_GENERIC_ERROR; + + (void) context; + DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) ); + slot = &ram_slots[slot_number]; + + psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_VERIFY ); + psa_set_key_algorithm( &attributes, alg ); + psa_set_key_type( &attributes, slot->type ); + DRIVER_ASSERT( psa_import_key( &attributes, + slot->content, + PSA_BITS_TO_BYTES( slot->bits ), + &handle ) == + PSA_SUCCESS ); + status = psa_asymmetric_verify( handle, alg, + hash, hash_length, + signature, signature_length ); + +exit: + psa_destroy_key( handle ); + return( status ); +} + + /****************************************************************/ /* Other test helper functions */ /****************************************************************/ +typedef enum +{ + SIGN_IN_SOFTWARE_AND_PARALLEL_CREATION, + SIGN_IN_DRIVER_AND_PARALLEL_CREATION, + SIGN_IN_DRIVER_THEN_EXPORT_PUBLIC, +} sign_verify_method_t; + /* Check that the attributes of a key reported by psa_get_key_attributes() * are consistent with the attributes used when creating the key. */ static int check_key_attributes( @@ -212,6 +491,31 @@ static int check_key_attributes( psa_get_key_bits( reference_attributes ) ); } + { + psa_key_slot_number_t actual_slot_number = 0xdeadbeef; + psa_key_slot_number_t desired_slot_number = 0xb90cc011; + psa_key_lifetime_t lifetime = + psa_get_key_lifetime( &actual_attributes ); + psa_status_t status = psa_get_key_slot_number( &actual_attributes, + &actual_slot_number ); + if( lifetime < MIN_DRIVER_LIFETIME ) + { + /* The key is not in a secure element. */ + TEST_EQUAL( status, PSA_ERROR_INVALID_ARGUMENT ); + } + else + { + /* The key is in a secure element. If it had been created + * in a specific slot, check that it is reported there. */ + PSA_ASSERT( status ); + status = psa_get_key_slot_number( reference_attributes, + &desired_slot_number ); + if( status == PSA_SUCCESS ) + { + TEST_EQUAL( desired_slot_number, actual_slot_number ); + } + } + } ok = 1; exit: @@ -485,11 +789,14 @@ void key_creation_import_export( int min_slot, int restart ) /* Test that the key was created in the expected slot. */ TEST_ASSERT( ram_slots[min_slot].type == PSA_KEY_TYPE_RAW_DATA ); - /* Test the key attributes and the key data. */ + /* Test the key attributes, including the reported slot number. */ psa_set_key_bits( &attributes, PSA_BYTES_TO_BITS( sizeof( key_material ) ) ); + psa_set_key_slot_number( &attributes, min_slot ); if( ! check_key_attributes( handle, &attributes ) ) goto exit; + + /* Test the key data. */ PSA_ASSERT( psa_export_key( handle, exported, sizeof( exported ), &exported_length ) ); @@ -497,6 +804,9 @@ void key_creation_import_export( int min_slot, int restart ) exported, exported_length ); PSA_ASSERT( psa_destroy_key( handle ) ); + handle = 0; + TEST_EQUAL( psa_open_key( id, &handle ), + PSA_ERROR_DOES_NOT_EXIST ); /* Test that the key has been erased from the designated slot. */ TEST_ASSERT( ram_slots[min_slot].type == 0 ); @@ -509,8 +819,79 @@ exit: /* END_CASE */ /* BEGIN_CASE */ -void key_creation_smoke( int type_arg, int alg_arg, - data_t *key_material ) +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 ) ); + handle = 0; + TEST_EQUAL( psa_open_key( id, &handle ), + PSA_ERROR_DOES_NOT_EXIST ); + +exit: + PSA_DONE( ); + ram_slots_reset( ); + psa_purge_storage( ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void import_key_smoke( int type_arg, int alg_arg, + data_t *key_material ) { psa_key_type_t type = type_arg; psa_algorithm_t alg = alg_arg; @@ -528,6 +909,7 @@ void key_creation_smoke( int type_arg, int alg_arg, driver.persistent_data_size = sizeof( psa_key_slot_number_t ); key_management.p_allocate = counter_allocate; key_management.p_import = null_import; + key_management.p_destroy = null_destroy; PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) ); PSA_ASSERT( psa_crypto_init( ) ); @@ -559,10 +941,12 @@ void key_creation_smoke( int type_arg, int alg_arg, /* We're done. */ PSA_ASSERT( psa_destroy_key( handle ) ); + handle = 0; + TEST_EQUAL( psa_open_key( id, &handle ), + PSA_ERROR_DOES_NOT_EXIST ); exit: PSA_DONE( ); - ram_slots_reset( ); psa_purge_storage( ); } /* END_CASE */ @@ -585,6 +969,7 @@ void generate_key_not_supported( int type_arg, int bits_arg ) driver.key_management = &key_management; driver.persistent_data_size = sizeof( psa_key_slot_number_t ); key_management.p_allocate = counter_allocate; + /* No p_generate method */ PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) ); PSA_ASSERT( psa_crypto_init( ) ); @@ -597,8 +982,310 @@ void generate_key_not_supported( int type_arg, int bits_arg ) PSA_ERROR_NOT_SUPPORTED ); exit: + PSA_DONE( ); + psa_purge_storage( ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void generate_key_smoke( int type_arg, int bits_arg, int alg_arg ) +{ + psa_key_type_t type = type_arg; + psa_key_bits_t bits = bits_arg; + psa_algorithm_t alg = alg_arg; + 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; + + 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( psa_key_slot_number_t ); + key_management.p_allocate = counter_allocate; + key_management.p_generate = null_generate; + key_management.p_destroy = null_destroy; + + 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_SIGN | PSA_KEY_USAGE_VERIFY | + PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT | + PSA_KEY_USAGE_EXPORT ); + psa_set_key_algorithm( &attributes, alg ); + psa_set_key_type( &attributes, type ); + psa_set_key_bits( &attributes, bits ); + PSA_ASSERT( psa_generate_key( &attributes, &handle ) ); + + /* Do stuff with the key. */ + if( ! smoke_test_key( handle ) ) + goto exit; + + /* Restart and try again. */ + mbedtls_psa_crypto_free( ); + PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) ); + PSA_ASSERT( psa_crypto_init( ) ); + PSA_ASSERT( psa_open_key( id, &handle ) ); + if( ! smoke_test_key( handle ) ) + goto exit; + + /* We're done. */ + PSA_ASSERT( psa_destroy_key( handle ) ); + handle = 0; + TEST_EQUAL( psa_open_key( id, &handle ), + PSA_ERROR_DOES_NOT_EXIST ); + +exit: + PSA_DONE( ); + psa_purge_storage( ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void sign_verify( int flow, + int type_arg, int alg_arg, + int bits_arg, data_t *key_material, + data_t *input ) +{ + psa_key_type_t type = type_arg; + psa_algorithm_t alg = alg_arg; + size_t bits = bits_arg; + /* Pass bits=0 to import, bits>0 to fake-generate */ + int generating = ( bits != 0 ); + + psa_drv_se_t driver; + psa_drv_se_key_management_t key_management; + psa_drv_se_asymmetric_t asymmetric; + + psa_key_lifetime_t lifetime = 2; + psa_key_id_t id = 1; + psa_key_handle_t drv_handle = 0; /* key managed by the driver */ + psa_key_handle_t sw_handle = 0; /* transparent key */ + psa_key_attributes_t sw_attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_attributes_t drv_attributes; + uint8_t signature[PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE]; + size_t signature_length; + + memset( &driver, 0, sizeof( driver ) ); + memset( &key_management, 0, sizeof( key_management ) ); + memset( &asymmetric, 0, sizeof( asymmetric ) ); + driver.hal_version = PSA_DRV_SE_HAL_VERSION; + driver.key_management = &key_management; + driver.asymmetric = &asymmetric; + driver.persistent_data_size = sizeof( ram_slot_usage_t ); + key_management.p_allocate = ram_allocate; + key_management.p_destroy = ram_destroy; + if( generating ) + key_management.p_generate = ram_fake_generate; + else + key_management.p_import = ram_import; + switch( flow ) + { + case SIGN_IN_SOFTWARE_AND_PARALLEL_CREATION: + break; + case SIGN_IN_DRIVER_AND_PARALLEL_CREATION: + asymmetric.p_sign = ram_sign; + break; + case SIGN_IN_DRIVER_THEN_EXPORT_PUBLIC: + asymmetric.p_sign = ram_sign; + key_management.p_export_public = ram_export_public; + break; + default: + TEST_ASSERT( ! "unsupported flow (should be SIGN_IN_xxx)" ); + break; + } + asymmetric.p_verify = ram_verify; + + PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) ); + PSA_ASSERT( psa_crypto_init( ) ); + + /* Prepare to create two keys with the same key material: a transparent + * key, and one that goes through the driver. */ + psa_set_key_usage_flags( &sw_attributes, + PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY ); + psa_set_key_algorithm( &sw_attributes, alg ); + psa_set_key_type( &sw_attributes, type ); + drv_attributes = sw_attributes; + psa_set_key_id( &drv_attributes, id ); + psa_set_key_lifetime( &drv_attributes, lifetime ); + + /* Create the key in the driver. */ + if( generating ) + { + psa_set_key_bits( &drv_attributes, bits ); + PSA_ASSERT( psa_generate_key( &drv_attributes, &drv_handle ) ); + /* Since we called a generate method that does not actually + * generate material, store the desired result of generation in + * the mock secure element storage. */ + PSA_ASSERT( psa_get_key_attributes( drv_handle, &drv_attributes ) ); + TEST_ASSERT( key_material->len == PSA_BITS_TO_BYTES( bits ) ); + memcpy( ram_slots[ram_min_slot].content, key_material->x, + key_material->len ); + } + else + { + PSA_ASSERT( psa_import_key( &drv_attributes, + key_material->x, key_material->len, + &drv_handle ) ); + } + + /* Either import the same key in software, or export the driver's + * public key and import that. */ + switch( flow ) + { + case SIGN_IN_SOFTWARE_AND_PARALLEL_CREATION: + case SIGN_IN_DRIVER_AND_PARALLEL_CREATION: + PSA_ASSERT( psa_import_key( &sw_attributes, + key_material->x, key_material->len, + &sw_handle ) ); + break; + case SIGN_IN_DRIVER_THEN_EXPORT_PUBLIC: + { + uint8_t public_key[PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE( PSA_VENDOR_ECC_MAX_CURVE_BITS )]; + size_t public_key_length; + PSA_ASSERT( psa_export_public_key( drv_handle, + public_key, sizeof( public_key ), + &public_key_length ) ); + psa_set_key_type( &sw_attributes, + PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR( type ) ); + PSA_ASSERT( psa_import_key( &sw_attributes, + public_key, public_key_length, + &sw_handle ) ); + break; + } + } + + /* Sign with the chosen key. */ + switch( flow ) + { + case SIGN_IN_DRIVER_AND_PARALLEL_CREATION: + case SIGN_IN_DRIVER_THEN_EXPORT_PUBLIC: + PSA_ASSERT_VIA_DRIVER( + psa_asymmetric_sign( drv_handle, + alg, + input->x, input->len, + signature, sizeof( signature ), + &signature_length ), + PSA_SUCCESS ); + break; + case SIGN_IN_SOFTWARE_AND_PARALLEL_CREATION: + PSA_ASSERT( psa_asymmetric_sign( sw_handle, + alg, + input->x, input->len, + signature, sizeof( signature ), + &signature_length ) ); + break; + } + + /* Verify with both keys. */ + PSA_ASSERT( psa_asymmetric_verify( sw_handle, alg, + input->x, input->len, + signature, signature_length ) ); + PSA_ASSERT_VIA_DRIVER( + psa_asymmetric_verify( drv_handle, alg, + input->x, input->len, + signature, signature_length ), + PSA_SUCCESS ); + + /* Change the signature and verify again. */ + signature[0] ^= 1; + TEST_EQUAL( psa_asymmetric_verify( sw_handle, alg, + input->x, input->len, + signature, signature_length ), + PSA_ERROR_INVALID_SIGNATURE ); + PSA_ASSERT_VIA_DRIVER( + psa_asymmetric_verify( drv_handle, alg, + input->x, input->len, + signature, signature_length ), + PSA_ERROR_INVALID_SIGNATURE ); + +exit: + psa_destroy_key( drv_handle ); + psa_destroy_key( sw_handle ); PSA_DONE( ); ram_slots_reset( ); psa_purge_storage( ); } /* END_CASE */ + +/* BEGIN_CASE */ +void register_key_smoke_test( int lifetime_arg, + int validate, + int expected_status_arg ) +{ + psa_key_lifetime_t lifetime = lifetime_arg; + psa_status_t expected_status = expected_status_arg; + psa_drv_se_t driver; + psa_drv_se_key_management_t key_management; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t id = 1; + size_t bit_size = 48; + psa_key_slot_number_t wanted_slot = 0x123456789; + psa_key_handle_t handle = 0; + psa_status_t status; + + memset( &driver, 0, sizeof( driver ) ); + driver.hal_version = PSA_DRV_SE_HAL_VERSION; + memset( &key_management, 0, sizeof( key_management ) ); + driver.key_management = &key_management; + key_management.p_destroy = null_destroy; + if( validate >= 0 ) + { + key_management.p_validate_slot_number = validate_slot_number_as_directed; + validate_slot_number_directions.slot_number = wanted_slot; + validate_slot_number_directions.method = PSA_KEY_CREATION_REGISTER; + validate_slot_number_directions.status = + ( validate > 0 ? PSA_SUCCESS : PSA_ERROR_NOT_PERMITTED ); + } + + PSA_ASSERT( psa_register_se_driver( MIN_DRIVER_LIFETIME, &driver ) ); + PSA_ASSERT( psa_crypto_init( ) ); + + 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_bits( &attributes, bit_size ); + psa_set_key_slot_number( &attributes, wanted_slot ); + + status = mbedtls_psa_register_se_key( &attributes ); + TEST_EQUAL( status, expected_status ); + + if( status != PSA_SUCCESS ) + goto exit; + + /* Test that the key exists and has the expected attributes. */ + PSA_ASSERT( psa_open_key( id, &handle ) ); + if( ! check_key_attributes( handle, &attributes ) ) + goto exit; + PSA_ASSERT( psa_close_key( handle ) ); + + /* Restart and try again. */ + PSA_DONE( ); + PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) ); + PSA_ASSERT( psa_crypto_init( ) ); + PSA_ASSERT( psa_open_key( id, &handle ) ); + if( ! check_key_attributes( handle, &attributes ) ) + goto exit; + /* This time, destroy the key. */ + PSA_ASSERT( psa_destroy_key( handle ) ); + handle = 0; + TEST_EQUAL( psa_open_key( id, &handle ), + PSA_ERROR_DOES_NOT_EXIST ); + +exit: + psa_reset_key_attributes( &attributes ); + psa_destroy_key( handle ); + PSA_DONE( ); + psa_purge_storage( ); + memset( &validate_slot_number_directions, 0, + sizeof( validate_slot_number_directions ) ); +} +/* END_CASE */