diff --git a/docs/architecture/mbed-crypto-storage-specification.md b/docs/architecture/mbed-crypto-storage-specification.md
index f4abd3e706..2c3119fbdc 100644
--- a/docs/architecture/mbed-crypto-storage-specification.md
+++ b/docs/architecture/mbed-crypto-storage-specification.md
@@ -193,3 +193,92 @@ The layout of a key file is:
* key material length (4 bytes)
* key material: output of `psa_export_key`
* Any trailing data is rejected on load.
+
+Mbed Crypto TBD
+---------------
+
+Tags: TBD
+
+Released in TBD 2019.
+Integrated in Mbed OS TBD.
+
+### Changes introduced in TBD
+
+* The layout of a key file now has a lifetime field before the type field.
+* Key files can store references to keys in a secure element. In such key files, the key material contains the slot number.
+
+### File namespace on a PSA platform on TBD
+
+Assumption: ITS provides a 64-bit file identifier namespace. The Crypto service can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace.
+
+Assumption: the owner identifier is a nonzero value of type `int32_t`.
+
+* Files 0 through 0xfffeffff: unused.
+* Files 0xffff0000 through 0xffffffff: reserved for internal use of the crypto library or crypto service. See [non-key files](#non-key-files-on-tbd).
+* Files 0x100000000 through 0xffffffffffff: [content](#key-file-format-for-1.0.0) of the [key whose identifier is the file identifier](#key-names-for-1.0.0). The upper 32 bits determine the owner.
+
+### File namespace on ITS as a library on TBD
+
+Assumption: ITS provides a 64-bit file identifier namespace. The entity using the crypto library can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace.
+
+This is a library integration, so there is no owner. The key file identifier is identical to the key identifier.
+
+* File 0: unused.
+* Files 1 through 0xfffeffff: [content](#key-file-format-for-1.0.0) of the [key whose identifier is the file identifier](#key-names-for-1.0.0).
+* Files 0xffff0000 through 0xffffffff: reserved for internal use of the crypto library or crypto service. See [non-key files](#non-key-files-on-tbd).
+* Files 0x100000000 through 0xffffffffffffffff: unused.
+
+### Non-key files on TBD
+
+File identifiers in the range 0xffff0000 through 0xffffffff are reserved for internal use in Mbed Crypto.
+
+* Files 0xfffffe02 through 0xfffffeff (`PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE + lifetime`): secure element driver storage. The content of the file is the secure element driver's persistent data.
+* File 0xffffff52 (`PSA_CRYPTO_ITS_RANDOM_SEED_UID`): [nonvolatile random seed](#nonvolatile-random-seed-file-format-for-1.0.0).
+* File 0xffffff54 (`PSA_CRYPTO_ITS_TRANSACTION_UID`): [transaction file](#transaction-file-format-for-tbd).
+* Other files are unused and reserved for future use.
+
+### Key file format for TBD
+
+All integers are encoded in little-endian order in 8-bit bytes except where otherwise indicated.
+
+The layout of a key file is:
+
+* magic (8 bytes): `"PSA\0KEY\0"`.
+* version (4 bytes): 0.
+* lifetime (4 bytes): `psa_key_lifetime_t` value.
+* type (4 bytes): `psa_key_type_t` value.
+* policy usage flags (4 bytes): `psa_key_usage_t` value.
+* policy usage algorithm (4 bytes): `psa_algorithm_t` value.
+* policy enrollment algorithm (4 bytes): `psa_algorithm_t` value.
+* key material length (4 bytes).
+* key material:
+ * For a transparent key: output of `psa_export_key`.
+ * For an opaque key (key in a secure element): slot number (8 bytes), in platform endianness.
+* Any trailing data is rejected on load.
+
+### Transaction file format for TBD
+
+The transaction file contains data about an ongoing action that cannot be completed atomically. It exists only if there is an ongoing transaction.
+
+All integers are encoded in platform endianness.
+
+All currently existing transactions concern a key in a secure element.
+
+The layout of a transaction file is:
+
+* type (2 bytes): the [transaction type](#transaction-types-on-tbd).
+* unused (2 bytes)
+* lifetime (4 bytes): `psa_key_lifetime_t` value that corresponds to a key in a secure element.
+* slot number (8 bytes): `psa_key_slot_number_t` value. This is the unique designation of the key for the secure element driver.
+* key identifier (4 bytes in a library integration, 8 bytes on a PSA platform): the internal representation of the key identifier. On a PSA platform, this encodes the key owner in the same way as [in file identifiers for key files](#file-namespace-on-a-psa-platform-on-tbd)).
+
+#### Transaction types on TBD
+
+* 0x0001: key creation. The following locations may or may not contain data about the key that is being created:
+ * The slot in the secure element designated by the slot number.
+ * The file containing the key metadata designated by the key identifier.
+ * The driver persistent data.
+* 0x0002: key destruction. The following locations may or may not still contain data about the key that is being destroyed:
+ * The slot in the secure element designated by the slot number.
+ * The file containing the key metadata designated by the key identifier.
+ * The driver persistent data.
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index 0e8d7550e1..bd6f7b6a03 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -1715,12 +1715,15 @@
* Enable secure element support in the Platform Security Architecture
* cryptography API.
*
+ * \warning This feature is not yet suitable for production. It is provided
+ * for API evaluation and testing purposes only.
+ *
* Module: library/psa_crypto_se.c
*
* Requires: MBEDTLS_PSA_CRYPTO_C, MBEDTLS_PSA_CRYPTO_STORAGE_C
*
*/
-#define MBEDTLS_PSA_CRYPTO_SE_C
+//#define MBEDTLS_PSA_CRYPTO_SE_C
/**
* \def MBEDTLS_PSA_CRYPTO_STORAGE_C
diff --git a/include/psa/crypto.h b/include/psa/crypto.h
index 4226587a80..2b5bb97fc2 100644
--- a/include/psa/crypto.h
+++ b/include/psa/crypto.h
@@ -93,117 +93,10 @@ psa_status_t psa_crypto_init(void);
/**@}*/
-/** \defgroup attributes Key attributes
+/** \addtogroup attributes
* @{
*/
-/** The type of a structure containing key attributes.
- *
- * This is an opaque structure that can represent the metadata of a key
- * object. Metadata that can be stored in attributes includes:
- * - The location of the key in storage, indicated by its key identifier
- * and its lifetime.
- * - The key's policy, comprising usage flags and a specification of
- * the permitted algorithm(s).
- * - Information about the key itself: the key type and its size.
- * - Implementations may define additional attributes.
- *
- * The actual key material is not considered an attribute of a key.
- * Key attributes do not contain information that is generally considered
- * highly confidential.
- *
- * An attribute structure can be a simple data structure where each function
- * `psa_set_key_xxx` sets a field and the corresponding function
- * `psa_get_key_xxx` retrieves the value of the corresponding field.
- * However, implementations may report values that are equivalent to the
- * original one, but have a different encoding. For example, an
- * implementation may use a more compact representation for types where
- * many bit-patterns are invalid or not supported, and store all values
- * that it does not support as a special marker value. In such an
- * implementation, after setting an invalid value, the corresponding
- * get function returns an invalid value which may not be the one that
- * was originally stored.
- *
- * An attribute structure may contain references to auxiliary resources,
- * for example pointers to allocated memory or indirect references to
- * pre-calculated values. In order to free such resources, the application
- * must call psa_reset_key_attributes(). As an exception, calling
- * psa_reset_key_attributes() on an attribute structure is optional if
- * the structure has only been modified by the following functions
- * since it was initialized or last reset with psa_reset_key_attributes():
- * - psa_set_key_id()
- * - psa_set_key_lifetime()
- * - psa_set_key_type()
- * - psa_set_key_bits()
- * - psa_set_key_usage_flags()
- * - psa_set_key_algorithm()
- *
- * Before calling any function on a key attribute structure, the application
- * must initialize it by any of the following means:
- * - Set the structure to all-bits-zero, for example:
- * \code
- * psa_key_attributes_t attributes;
- * memset(&attributes, 0, sizeof(attributes));
- * \endcode
- * - Initialize the structure to logical zero values, for example:
- * \code
- * psa_key_attributes_t attributes = {0};
- * \endcode
- * - Initialize the structure to the initializer #PSA_KEY_ATTRIBUTES_INIT,
- * for example:
- * \code
- * psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
- * \endcode
- * - Assign the result of the function psa_key_attributes_init()
- * to the structure, for example:
- * \code
- * psa_key_attributes_t attributes;
- * attributes = psa_key_attributes_init();
- * \endcode
- *
- * A freshly initialized attribute structure contains the following
- * values:
- *
- * - lifetime: #PSA_KEY_LIFETIME_VOLATILE.
- * - key identifier: unspecified.
- * - type: \c 0.
- * - key size: \c 0.
- * - usage flags: \c 0.
- * - algorithm: \c 0.
- *
- * A typical sequence to create a key is as follows:
- * -# Create and initialize an attribute structure.
- * -# If the key is persistent, call psa_set_key_id().
- * Also call psa_set_key_lifetime() to place the key in a non-default
- * location.
- * -# Set the key policy with psa_set_key_usage_flags() and
- * psa_set_key_algorithm().
- * -# Set the key type with psa_set_key_type().
- * Skip this step if copying an existing key with psa_copy_key().
- * -# When generating a random key with psa_generate_key() or deriving a key
- * with psa_key_derivation_output_key(), set the desired key size with
- * psa_set_key_bits().
- * -# Call a key creation function: psa_import_key(), psa_generate_key(),
- * psa_key_derivation_output_key() or psa_copy_key(). This function reads
- * the attribute structure, creates a key with these attributes, and
- * outputs a handle to the newly created key.
- * -# The attribute structure is now no longer necessary.
- * You may call psa_reset_key_attributes(), although this is optional
- * with the workflow presented here because the attributes currently
- * defined in this specification do not require any additional resources
- * beyond the structure itself.
- *
- * A typical sequence to query a key's attributes is as follows:
- * -# Call psa_get_key_attributes().
- * -# Call `psa_get_key_xxx` functions to retrieve the attribute(s) that
- * you are interested in.
- * -# Call psa_reset_key_attributes() to free any resources that may be
- * used by the attribute structure.
- *
- * Once a key has been created, it is impossible to change its attributes.
- */
-typedef struct psa_key_attributes_s psa_key_attributes_t;
-
/** \def PSA_KEY_ATTRIBUTES_INIT
*
* This macro returns a suitable initializer for a key attribute structure
diff --git a/include/psa/crypto_se_driver.h b/include/psa/crypto_se_driver.h
index 85247051e6..9aebc45c1c 100644
--- a/include/psa/crypto_se_driver.h
+++ b/include/psa/crypto_se_driver.h
@@ -40,10 +40,106 @@
extern "C" {
#endif
+/** \defgroup se_init Secure element driver initialization
+ */
+/**@{*/
+
+/** \brief Driver context structure
+ *
+ * Driver functions receive a pointer to this structure.
+ * Each registered driver has one instance of this structure.
+ *
+ * Implementations must include the fields specified here and
+ * may include other fields.
+ */
+typedef struct {
+ /** A read-only pointer to the driver's persistent data.
+ *
+ * Drivers typically use this persistent data to keep track of
+ * which slot numbers are available. This is only a guideline:
+ * drivers may use the persistent data for any purpose, keeping
+ * in mind the restrictions on when the persistent data is saved
+ * to storage: the persistent data is only saved after calling
+ * certain functions that receive a writable pointer to the
+ * persistent data.
+ *
+ * The core allocates a memory buffer for the persistent data.
+ * The pointer is guaranteed to be suitably aligned for any data type,
+ * like a pointer returned by `malloc` (but the core can use any
+ * method to allocate the buffer, not necessarily `malloc`).
+ *
+ * The size of this buffer is in the \c persistent_data_size field of
+ * this structure.
+ *
+ * Before the driver is initialized for the first time, the content of
+ * the persistent data is all-bits-zero. After a driver upgrade, if the
+ * size of the persistent data has increased, the original data is padded
+ * on the right with zeros; if the size has decreased, the original data
+ * is truncated to the new size.
+ *
+ * This pointer is to read-only data. Only a few driver functions are
+ * allowed to modify the persistent data. These functions receive a
+ * writable pointer. These functions are:
+ * - psa_drv_se_t::p_init
+ * - psa_drv_se_key_management_t::p_allocate
+ * - psa_drv_se_key_management_t::p_destroy
+ *
+ * The PSA Cryptography core saves the persistent data from one
+ * session to the next. It does this before returning from API functions
+ * that call a driver method that is allowed to modify the persistent
+ * data, specifically:
+ * - psa_crypto_init() causes a call to psa_drv_se_t::p_init, and may call
+ * psa_drv_se_key_management_t::p_destroy to complete an action
+ * that was interrupted by a power failure.
+ * - Key creation functions cause a call to
+ * psa_drv_se_key_management_t::p_allocate, and may cause a call to
+ * psa_drv_se_key_management_t::p_destroy in case an error occurs.
+ * - psa_destroy_key() causes a call to
+ * psa_drv_se_key_management_t::p_destroy.
+ */
+ const void *const persistent_data;
+
+ /** The size of \c persistent_data in bytes.
+ *
+ * This is always equal to the value of the `persistent_data_size` field
+ * of the ::psa_drv_se_t structure when the driver is registered.
+ */
+ const size_t persistent_data_size;
+
+ /** Driver transient data.
+ *
+ * The core initializes this value to 0 and does not read or modify it
+ * afterwards. The driver may store whatever it wants in this field.
+ */
+ uintptr_t transient_data;
+} psa_drv_se_context_t;
+
+/** \brief A driver initialization function.
+ *
+ * \param[in,out] drv_context The driver context structure.
+ * \param[in,out] persistent_data A pointer to the persistent data
+ * that allows writing.
+ * \param lifetime The lifetime value for which this driver
+ * is registered.
+ *
+ * \retval #PSA_SUCCESS
+ * The driver is operational.
+ * The core will update the persistent data in storage.
+ * \return
+ * Any other return value prevents the driver from being used in
+ * this session.
+ * The core will NOT update the persistent data in storage.
+ */
+typedef psa_status_t (*psa_drv_se_init_t)(psa_drv_se_context_t *drv_context,
+ void *persistent_data,
+ psa_key_lifetime_t lifetime);
+
/** 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 uint32_t psa_key_slot_number_t; // Change this to psa_key_slot_t after psa_key_slot_t is removed from Mbed crypto
+typedef uint64_t psa_key_slot_number_t;
+
+/**@}*/
/** \defgroup se_mac Secure Element Message Authentication Codes
* Generation and authentication of Message Authentication Codes (MACs) using
@@ -65,7 +161,8 @@ typedef uint32_t psa_key_slot_number_t; // Change this to psa_key_slot_t after p
/** \brief A function that starts a secure element MAC operation for a PSA
* Crypto Driver implementation
*
- * \param[in,out] p_context A structure that will contain the
+ * \param[in,out] drv_context The driver context structure.
+ * \param[in,out] op_context A structure that will contain the
* hardware-specific MAC context
* \param[in] key_slot The slot of the key to be used for the
* operation
@@ -75,28 +172,29 @@ typedef uint32_t psa_key_slot_number_t; // Change this to psa_key_slot_t after p
* \retval PSA_SUCCESS
* Success.
*/
-typedef psa_status_t (*psa_drv_se_mac_setup_t)(void *p_context,
+typedef psa_status_t (*psa_drv_se_mac_setup_t)(psa_drv_se_context_t *drv_context,
+ void *op_context,
psa_key_slot_number_t key_slot,
psa_algorithm_t algorithm);
/** \brief A function that continues a previously started secure element MAC
* operation
*
- * \param[in,out] p_context A hardware-specific structure for the
+ * \param[in,out] op_context A hardware-specific structure for the
* previously-established MAC operation to be
* updated
* \param[in] p_input A buffer containing the message to be appended
* to the MAC operation
- * \param[in] input_length The size in bytes of the input message buffer
+ * \param[in] input_length The size in bytes of the input message buffer
*/
-typedef psa_status_t (*psa_drv_se_mac_update_t)(void *p_context,
+typedef psa_status_t (*psa_drv_se_mac_update_t)(void *op_context,
const uint8_t *p_input,
size_t input_length);
/** \brief a function that completes a previously started secure element MAC
* operation by returning the resulting MAC.
*
- * \param[in,out] p_context A hardware-specific structure for the
+ * \param[in,out] op_context A hardware-specific structure for the
* previously started MAC operation to be
* finished
* \param[out] p_mac A buffer where the generated MAC will be
@@ -109,7 +207,7 @@ typedef psa_status_t (*psa_drv_se_mac_update_t)(void *p_context,
* \retval PSA_SUCCESS
* Success.
*/
-typedef psa_status_t (*psa_drv_se_mac_finish_t)(void *p_context,
+typedef psa_status_t (*psa_drv_se_mac_finish_t)(void *op_context,
uint8_t *p_mac,
size_t mac_size,
size_t *p_mac_length);
@@ -117,11 +215,11 @@ typedef psa_status_t (*psa_drv_se_mac_finish_t)(void *p_context,
/** \brief A function that completes a previously started secure element MAC
* operation by comparing the resulting MAC against a provided value
*
- * \param[in,out] p_context A hardware-specific structure for the previously
- * started MAC operation to be fiinished
- * \param[in] p_mac The MAC value against which the resulting MAC will
- * be compared against
- * \param[in] mac_length The size in bytes of the value stored in `p_mac`
+ * \param[in,out] op_context A hardware-specific structure for the previously
+ * started MAC operation to be fiinished
+ * \param[in] p_mac The MAC value against which the resulting MAC
+ * will be compared against
+ * \param[in] mac_length The size in bytes of the value stored in `p_mac`
*
* \retval PSA_SUCCESS
* The operation completed successfully and the MACs matched each
@@ -130,21 +228,22 @@ typedef psa_status_t (*psa_drv_se_mac_finish_t)(void *p_context,
* The operation completed successfully, but the calculated MAC did
* not match the provided MAC
*/
-typedef psa_status_t (*psa_drv_se_mac_finish_verify_t)(void *p_context,
+typedef psa_status_t (*psa_drv_se_mac_finish_verify_t)(void *op_context,
const uint8_t *p_mac,
size_t mac_length);
/** \brief A function that aborts a previous started secure element MAC
* operation
*
- * \param[in,out] p_context A hardware-specific structure for the previously
- * started MAC operation to be aborted
+ * \param[in,out] op_context A hardware-specific structure for the previously
+ * started MAC operation to be aborted
*/
-typedef psa_status_t (*psa_drv_se_mac_abort_t)(void *p_context);
+typedef psa_status_t (*psa_drv_se_mac_abort_t)(void *op_context);
/** \brief A function that performs a secure element MAC operation in one
* command and returns the calculated MAC
*
+ * \param[in,out] drv_context The driver context structure.
* \param[in] p_input A buffer containing the message to be MACed
* \param[in] input_length The size in bytes of `p_input`
* \param[in] key_slot The slot of the key to be used
@@ -159,7 +258,8 @@ typedef psa_status_t (*psa_drv_se_mac_abort_t)(void *p_context);
* \retval PSA_SUCCESS
* Success.
*/
-typedef psa_status_t (*psa_drv_se_mac_generate_t)(const uint8_t *p_input,
+typedef psa_status_t (*psa_drv_se_mac_generate_t)(psa_drv_se_context_t *drv_context,
+ const uint8_t *p_input,
size_t input_length,
psa_key_slot_number_t key_slot,
psa_algorithm_t alg,
@@ -170,6 +270,7 @@ typedef psa_status_t (*psa_drv_se_mac_generate_t)(const uint8_t *p_input,
/** \brief A function that performs a secure element MAC operation in one
* command and compares the resulting MAC against a provided value
*
+ * \param[in,out] drv_context The driver context structure.
* \param[in] p_input A buffer containing the message to be MACed
* \param[in] input_length The size in bytes of `input`
* \param[in] key_slot The slot of the key to be used
@@ -186,7 +287,8 @@ typedef psa_status_t (*psa_drv_se_mac_generate_t)(const uint8_t *p_input,
* The operation completed successfully, but the calculated MAC did
* not match the provided MAC
*/
-typedef psa_status_t (*psa_drv_se_mac_verify_t)(const uint8_t *p_input,
+typedef psa_status_t (*psa_drv_se_mac_verify_t)(psa_drv_se_context_t *drv_context,
+ const uint8_t *p_input,
size_t input_length,
psa_key_slot_number_t key_slot,
psa_algorithm_t alg,
@@ -263,7 +365,8 @@ typedef struct {
/** \brief A function that provides the cipher setup function for a
* secure element driver
*
- * \param[in,out] p_context A structure that will contain the
+ * \param[in,out] drv_context The driver context structure.
+ * \param[in,out] op_context A structure that will contain the
* hardware-specific cipher context.
* \param[in] key_slot The slot of the key to be used for the
* operation
@@ -275,7 +378,8 @@ typedef struct {
* \retval PSA_SUCCESS
* \retval PSA_ERROR_NOT_SUPPORTED
*/
-typedef psa_status_t (*psa_drv_se_cipher_setup_t)(void *p_context,
+typedef psa_status_t (*psa_drv_se_cipher_setup_t)(psa_drv_se_context_t *drv_context,
+ void *op_context,
psa_key_slot_number_t key_slot,
psa_algorithm_t algorithm,
psa_encrypt_or_decrypt_t direction);
@@ -288,21 +392,21 @@ typedef psa_status_t (*psa_drv_se_cipher_setup_t)(void *p_context,
* generate function is not necessary for the drivers to implement as the PSA
* Crypto implementation can do the generation using its RNG features.
*
- * \param[in,out] p_context A structure that contains the previously set up
+ * \param[in,out] op_context A structure that contains the previously set up
* hardware-specific cipher context
* \param[in] p_iv A buffer containing the initialization vector
* \param[in] iv_length The size (in bytes) of the `p_iv` buffer
*
* \retval PSA_SUCCESS
*/
-typedef psa_status_t (*psa_drv_se_cipher_set_iv_t)(void *p_context,
+typedef psa_status_t (*psa_drv_se_cipher_set_iv_t)(void *op_context,
const uint8_t *p_iv,
size_t iv_length);
/** \brief A function that continues a previously started secure element cipher
* operation
*
- * \param[in,out] p_context A hardware-specific structure for the
+ * \param[in,out] op_context A hardware-specific structure for the
* previously started cipher operation
* \param[in] p_input A buffer containing the data to be
* encrypted/decrypted
@@ -317,7 +421,7 @@ typedef psa_status_t (*psa_drv_se_cipher_set_iv_t)(void *p_context,
*
* \retval PSA_SUCCESS
*/
-typedef psa_status_t (*psa_drv_se_cipher_update_t)(void *p_context,
+typedef psa_status_t (*psa_drv_se_cipher_update_t)(void *op_context,
const uint8_t *p_input,
size_t input_size,
uint8_t *p_output,
@@ -327,7 +431,7 @@ typedef psa_status_t (*psa_drv_se_cipher_update_t)(void *p_context,
/** \brief A function that completes a previously started secure element cipher
* operation
*
- * \param[in,out] p_context A hardware-specific structure for the
+ * \param[in,out] op_context A hardware-specific structure for the
* previously started cipher operation
* \param[out] p_output The caller-allocated buffer where the output
* will be placed
@@ -338,7 +442,7 @@ typedef psa_status_t (*psa_drv_se_cipher_update_t)(void *p_context,
*
* \retval PSA_SUCCESS
*/
-typedef psa_status_t (*psa_drv_se_cipher_finish_t)(void *p_context,
+typedef psa_status_t (*psa_drv_se_cipher_finish_t)(void *op_context,
uint8_t *p_output,
size_t output_size,
size_t *p_output_length);
@@ -346,10 +450,10 @@ typedef psa_status_t (*psa_drv_se_cipher_finish_t)(void *p_context,
/** \brief A function that aborts a previously started secure element cipher
* operation
*
- * \param[in,out] p_context A hardware-specific structure for the
+ * \param[in,out] op_context A hardware-specific structure for the
* previously started cipher operation
*/
-typedef psa_status_t (*psa_drv_se_cipher_abort_t)(void *p_context);
+typedef psa_status_t (*psa_drv_se_cipher_abort_t)(void *op_context);
/** \brief A function that performs the ECB block mode for secure element
* cipher operations
@@ -357,23 +461,25 @@ typedef psa_status_t (*psa_drv_se_cipher_abort_t)(void *p_context);
* Note: this function should only be used with implementations that do not
* provide a needed higher-level operation.
*
- * \param[in] key_slot The slot of the key to be used for the operation
- * \param[in] algorithm The algorithm to be used in the cipher operation
- * \param[in] direction Indicates whether the operation is an encrypt or
- * decrypt
- * \param[in] p_input A buffer containing the data to be
- * encrypted/decrypted
- * \param[in] input_size The size in bytes of the buffer pointed to by
- * `p_input`
- * \param[out] p_output The caller-allocated buffer where the output will
- * be placed
- * \param[in] output_size The allocated size in bytes of the `p_output`
- * buffer
+ * \param[in,out] drv_context The driver context structure.
+ * \param[in] key_slot The slot of the key to be used for the operation
+ * \param[in] algorithm The algorithm to be used in the cipher operation
+ * \param[in] direction Indicates whether the operation is an encrypt or
+ * decrypt
+ * \param[in] p_input A buffer containing the data to be
+ * encrypted/decrypted
+ * \param[in] input_size The size in bytes of the buffer pointed to by
+ * `p_input`
+ * \param[out] p_output The caller-allocated buffer where the output
+ * will be placed
+ * \param[in] output_size The allocated size in bytes of the `p_output`
+ * buffer
*
* \retval PSA_SUCCESS
* \retval PSA_ERROR_NOT_SUPPORTED
*/
-typedef psa_status_t (*psa_drv_se_cipher_ecb_t)(psa_key_slot_number_t key_slot,
+typedef psa_status_t (*psa_drv_se_cipher_ecb_t)(psa_drv_se_context_t *drv_context,
+ psa_key_slot_number_t key_slot,
psa_algorithm_t algorithm,
psa_encrypt_or_decrypt_t direction,
const uint8_t *p_input,
@@ -427,6 +533,7 @@ typedef struct {
* \brief A function that signs a hash or short message with a private key in
* a secure element
*
+ * \param[in,out] drv_context The driver context structure.
* \param[in] key_slot Key slot of an asymmetric key pair
* \param[in] alg A signature algorithm that is compatible
* with the type of `key`
@@ -439,7 +546,8 @@ typedef struct {
*
* \retval PSA_SUCCESS
*/
-typedef psa_status_t (*psa_drv_se_asymmetric_sign_t)(psa_key_slot_number_t key_slot,
+typedef psa_status_t (*psa_drv_se_asymmetric_sign_t)(psa_drv_se_context_t *drv_context,
+ psa_key_slot_number_t key_slot,
psa_algorithm_t alg,
const uint8_t *p_hash,
size_t hash_length,
@@ -451,6 +559,7 @@ typedef psa_status_t (*psa_drv_se_asymmetric_sign_t)(psa_key_slot_number_t key_s
* \brief A function that verifies the signature a hash or short message using
* an asymmetric public key in a secure element
*
+ * \param[in,out] drv_context The driver context structure.
* \param[in] key_slot Key slot of a public key or an asymmetric key
* pair
* \param[in] alg A signature algorithm that is compatible with
@@ -463,7 +572,8 @@ typedef psa_status_t (*psa_drv_se_asymmetric_sign_t)(psa_key_slot_number_t key_s
* \retval PSA_SUCCESS
* The signature is valid.
*/
-typedef psa_status_t (*psa_drv_se_asymmetric_verify_t)(psa_key_slot_number_t key_slot,
+typedef psa_status_t (*psa_drv_se_asymmetric_verify_t)(psa_drv_se_context_t *drv_context,
+ psa_key_slot_number_t key_slot,
psa_algorithm_t alg,
const uint8_t *p_hash,
size_t hash_length,
@@ -474,6 +584,7 @@ typedef psa_status_t (*psa_drv_se_asymmetric_verify_t)(psa_key_slot_number_t key
* \brief A function that encrypts a short message with an asymmetric public
* key in a secure element
*
+ * \param[in,out] drv_context The driver context structure.
* \param[in] key_slot Key slot of a public key or an asymmetric key
* pair
* \param[in] alg An asymmetric encryption algorithm that is
@@ -499,7 +610,8 @@ typedef psa_status_t (*psa_drv_se_asymmetric_verify_t)(psa_key_slot_number_t key
*
* \retval PSA_SUCCESS
*/
-typedef psa_status_t (*psa_drv_se_asymmetric_encrypt_t)(psa_key_slot_number_t key_slot,
+typedef psa_status_t (*psa_drv_se_asymmetric_encrypt_t)(psa_drv_se_context_t *drv_context,
+ psa_key_slot_number_t key_slot,
psa_algorithm_t alg,
const uint8_t *p_input,
size_t input_length,
@@ -513,6 +625,7 @@ typedef psa_status_t (*psa_drv_se_asymmetric_encrypt_t)(psa_key_slot_number_t ke
* \brief A function that decrypts a short message with an asymmetric private
* key in a secure element.
*
+ * \param[in,out] drv_context The driver context structure.
* \param[in] key_slot Key slot of an asymmetric key pair
* \param[in] alg An asymmetric encryption algorithm that is
* compatible with the type of `key`
@@ -537,7 +650,8 @@ typedef psa_status_t (*psa_drv_se_asymmetric_encrypt_t)(psa_key_slot_number_t ke
*
* \retval PSA_SUCCESS
*/
-typedef psa_status_t (*psa_drv_se_asymmetric_decrypt_t)(psa_key_slot_number_t key_slot,
+typedef psa_status_t (*psa_drv_se_asymmetric_decrypt_t)(psa_drv_se_context_t *drv_context,
+ psa_key_slot_number_t key_slot,
psa_algorithm_t alg,
const uint8_t *p_input,
size_t input_length,
@@ -581,6 +695,7 @@ typedef struct {
/** \brief A function that performs a secure element authenticated encryption
* operation
*
+ * \param[in,out] drv_context The driver context structure.
* \param[in] key_slot Slot containing the key to use.
* \param[in] algorithm The AEAD algorithm to compute
* (\c PSA_ALG_XXX value such that
@@ -608,7 +723,8 @@ typedef struct {
* \retval #PSA_SUCCESS
* Success.
*/
-typedef psa_status_t (*psa_drv_se_aead_encrypt_t)(psa_key_slot_number_t key_slot,
+typedef psa_status_t (*psa_drv_se_aead_encrypt_t)(psa_drv_se_context_t *drv_context,
+ psa_key_slot_number_t key_slot,
psa_algorithm_t algorithm,
const uint8_t *p_nonce,
size_t nonce_length,
@@ -622,6 +738,7 @@ typedef psa_status_t (*psa_drv_se_aead_encrypt_t)(psa_key_slot_number_t key_slot
/** A function that peforms a secure element authenticated decryption operation
*
+ * \param[in,out] drv_context The driver context structure.
* \param[in] key_slot Slot containing the key to use
* \param[in] algorithm The AEAD algorithm to compute
* (\c PSA_ALG_XXX value such that
@@ -648,7 +765,8 @@ typedef psa_status_t (*psa_drv_se_aead_encrypt_t)(psa_key_slot_number_t key_slot
* \retval #PSA_SUCCESS
* Success.
*/
-typedef psa_status_t (*psa_drv_se_aead_decrypt_t)(psa_key_slot_number_t key_slot,
+typedef psa_status_t (*psa_drv_se_aead_decrypt_t)(psa_drv_se_context_t *drv_context,
+ psa_key_slot_number_t key_slot,
psa_algorithm_t algorithm,
const uint8_t *p_nonce,
size_t nonce_length,
@@ -685,25 +803,50 @@ typedef struct {
*/
/**@{*/
+/** \brief A function that allocates a slot for a key.
+ *
+ * \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[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.
+ *
+ * \retval #PSA_SUCCESS
+ * Success.
+ * The core will record \c *key_slot as the key slot where the key
+ * is stored and will update the persistent data in storage.
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ * \retval #PSA_ERROR_INSUFFICIENT_STORAGE
+ */
+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_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] 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,out] drv_context The driver context structure.
+ * \param[in] 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
*
* \retval #PSA_SUCCESS
* Success.
*/
-typedef psa_status_t (*psa_drv_se_import_key_t)(psa_key_slot_number_t key_slot,
+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,
@@ -721,12 +864,18 @@ typedef psa_status_t (*psa_drv_se_import_key_t)(psa_key_slot_number_t key_slot,
*
* This function returns the specified slot to its default state.
*
- * \param[in] key_slot The key slot to erase.
+ * \param[in,out] drv_context The driver context structure.
+ * \param[in,out] persistent_data A pointer to the persistent data
+ * that allows writing.
+ * \param key_slot The key slot to erase.
*
* \retval #PSA_SUCCESS
* The slot's content, if any, has been erased.
*/
-typedef psa_status_t (*psa_drv_se_destroy_key_t)(psa_key_slot_number_t key_slot);
+typedef psa_status_t (*psa_drv_se_destroy_key_t)(
+ psa_drv_se_context_t *drv_context,
+ void *persistent_data,
+ psa_key_slot_number_t key_slot);
/**
* \brief A function that exports a secure element key in binary format
@@ -743,6 +892,7 @@ typedef psa_status_t (*psa_drv_se_destroy_key_t)(psa_key_slot_number_t key_slot)
* `psa_export_key()` does. 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 whose content is to be exported. This must
* be an occupied key slot.
* \param[out] p_data Buffer where the key data is to be written.
@@ -758,7 +908,8 @@ typedef psa_status_t (*psa_drv_se_destroy_key_t)(psa_key_slot_number_t key_slot)
* \retval #PSA_ERROR_HARDWARE_FAILURE
* \retval #PSA_ERROR_CORRUPTION_DETECTED
*/
-typedef psa_status_t (*psa_drv_se_export_key_t)(psa_key_slot_number_t key,
+typedef psa_status_t (*psa_drv_se_export_key_t)(psa_drv_se_context_t *drv_context,
+ psa_key_slot_number_t key,
uint8_t *p_data,
size_t data_size,
size_t *p_data_length);
@@ -767,31 +918,34 @@ typedef psa_status_t (*psa_drv_se_export_key_t)(psa_key_slot_number_t key,
* \brief A function that generates a symmetric or asymmetric key on a secure
* element
*
- * If \p type is asymmetric (`#PSA_KEY_TYPE_IS_ASYMMETRIC(\p type) == 1`),
+ * 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.
*
- * \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,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`.
*/
-typedef psa_status_t (*psa_drv_se_generate_key_t)(psa_key_slot_number_t key_slot,
+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,
@@ -811,6 +965,8 @@ typedef psa_status_t (*psa_drv_se_generate_key_t)(psa_key_slot_number_t key_slot
* If one of the functions is not implemented, it should be set to NULL.
*/
typedef struct {
+ /** Function that allocates a slot. */
+ psa_drv_se_allocate_key_t p_allocate;
/** Function that performs a key import operation */
psa_drv_se_import_key_t p_import;
/** Function that performs a generation */
@@ -819,6 +975,8 @@ typedef struct {
psa_drv_se_destroy_key_t p_destroy;
/** Function that performs a key export operation */
psa_drv_se_export_key_t p_export;
+ /** Function that performs a public key export operation */
+ psa_drv_se_export_key_t p_export_public;
} psa_drv_se_key_management_t;
/**@}*/
@@ -875,15 +1033,17 @@ typedef struct {
/** \brief A function that Sets up a secure element key derivation operation by
* specifying the algorithm and the source key sot
*
- * \param[in,out] p_context A hardware-specific structure containing any
- * context information for the implementation
- * \param[in] kdf_alg The algorithm to be used for the key derivation
- * \param[in] source_key The key to be used as the source material for the
- * key derivation
+ * \param[in,out] drv_context The driver context structure.
+ * \param[in,out] op_context A hardware-specific structure containing any
+ * context information for the implementation
+ * \param[in] kdf_alg The algorithm to be used for the key derivation
+ * \param[in] source_key The key to be used as the source material for
+ * the key derivation
*
* \retval PSA_SUCCESS
*/
-typedef psa_status_t (*psa_drv_se_key_derivation_setup_t)(void *p_context,
+typedef psa_status_t (*psa_drv_se_key_derivation_setup_t)(psa_drv_se_context_t *drv_context,
+ void *op_context,
psa_algorithm_t kdf_alg,
psa_key_slot_number_t source_key);
@@ -894,7 +1054,7 @@ typedef psa_status_t (*psa_drv_se_key_derivation_setup_t)(void *p_context,
* expeced that this function may be called multiple times for the same
* operation, each with a different algorithm-specific `collateral_id`
*
- * \param[in,out] p_context A hardware-specific structure containing any
+ * \param[in,out] op_context A hardware-specific structure containing any
* context information for the implementation
* \param[in] collateral_id An ID for the collateral being provided
* \param[in] p_collateral A buffer containing the collateral data
@@ -902,7 +1062,7 @@ typedef psa_status_t (*psa_drv_se_key_derivation_setup_t)(void *p_context,
*
* \retval PSA_SUCCESS
*/
-typedef psa_status_t (*psa_drv_se_key_derivation_collateral_t)(void *p_context,
+typedef psa_status_t (*psa_drv_se_key_derivation_collateral_t)(void *op_context,
uint32_t collateral_id,
const uint8_t *p_collateral,
size_t collateral_size);
@@ -910,14 +1070,14 @@ typedef psa_status_t (*psa_drv_se_key_derivation_collateral_t)(void *p_context,
/** \brief A function that performs the final secure element key derivation
* step and place the generated key material in a slot
*
- * \param[in,out] p_context A hardware-specific structure containing any
+ * \param[in,out] op_context A hardware-specific structure containing any
* context information for the implementation
* \param[in] dest_key The slot where the generated key material
* should be placed
*
* \retval PSA_SUCCESS
*/
-typedef psa_status_t (*psa_drv_se_key_derivation_derive_t)(void *p_context,
+typedef psa_status_t (*psa_drv_se_key_derivation_derive_t)(void *op_context,
psa_key_slot_number_t dest_key);
/** \brief A function that performs the final step of a secure element key
@@ -931,7 +1091,7 @@ typedef psa_status_t (*psa_drv_se_key_derivation_derive_t)(void *p_context,
*
* \retval PSA_SUCCESS
*/
-typedef psa_status_t (*psa_drv_se_key_derivation_export_t)(void *p_context,
+typedef psa_status_t (*psa_drv_se_key_derivation_export_t)(void *op_context,
uint8_t *p_output,
size_t output_size,
size_t *p_output_length);
@@ -978,12 +1138,35 @@ typedef struct {
* Use #PSA_DRV_SE_HAL_VERSION.
*/
uint32_t hal_version;
- psa_drv_se_key_management_t key_management;
- psa_drv_se_mac_t mac;
- psa_drv_se_cipher_t cipher;
- psa_drv_se_aead_t aead;
- psa_drv_se_asymmetric_t asymmetric;
- psa_drv_se_key_derivation_t derivation;
+
+ /** The size of the driver's persistent data in bytes.
+ *
+ * This can be 0 if the driver does not need persistent data.
+ *
+ * See the documentation of psa_drv_se_context_t::persistent_data
+ * for more information about why and how a driver can use
+ * persistent data.
+ */
+ size_t persistent_data_size;
+
+ /** The driver initialization function.
+ *
+ * This function is called once during the initialization of the
+ * PSA Cryptography subsystem, before any other function of the
+ * driver is called. If this function returns a failure status,
+ * the driver will be unusable, at least until the next system reset.
+ *
+ * If this field is \c NULL, it is equivalent to a function that does
+ * nothing and returns #PSA_SUCCESS.
+ */
+ psa_drv_se_init_t p_init;
+
+ const psa_drv_se_key_management_t *key_management;
+ const psa_drv_se_mac_t *mac;
+ const psa_drv_se_cipher_t *cipher;
+ const psa_drv_se_aead_t *aead;
+ const psa_drv_se_asymmetric_t *asymmetric;
+ const psa_drv_se_key_derivation_t *derivation;
} psa_drv_se_t;
/** The current version of the secure element driver HAL.
diff --git a/include/psa/crypto_types.h b/include/psa/crypto_types.h
index 7f0f38cddf..1944be4b26 100644
--- a/include/psa/crypto_types.h
+++ b/include/psa/crypto_types.h
@@ -133,6 +133,119 @@ typedef uint32_t psa_key_usage_t;
/**@}*/
+/** \defgroup attributes Key attributes
+ * @{
+ */
+
+/** The type of a structure containing key attributes.
+ *
+ * This is an opaque structure that can represent the metadata of a key
+ * object. Metadata that can be stored in attributes includes:
+ * - The location of the key in storage, indicated by its key identifier
+ * and its lifetime.
+ * - The key's policy, comprising usage flags and a specification of
+ * the permitted algorithm(s).
+ * - Information about the key itself: the key type and its size.
+ * - Implementations may define additional attributes.
+ *
+ * The actual key material is not considered an attribute of a key.
+ * Key attributes do not contain information that is generally considered
+ * highly confidential.
+ *
+ * An attribute structure can be a simple data structure where each function
+ * `psa_set_key_xxx` sets a field and the corresponding function
+ * `psa_get_key_xxx` retrieves the value of the corresponding field.
+ * However, implementations may report values that are equivalent to the
+ * original one, but have a different encoding. For example, an
+ * implementation may use a more compact representation for types where
+ * many bit-patterns are invalid or not supported, and store all values
+ * that it does not support as a special marker value. In such an
+ * implementation, after setting an invalid value, the corresponding
+ * get function returns an invalid value which may not be the one that
+ * was originally stored.
+ *
+ * An attribute structure may contain references to auxiliary resources,
+ * for example pointers to allocated memory or indirect references to
+ * pre-calculated values. In order to free such resources, the application
+ * must call psa_reset_key_attributes(). As an exception, calling
+ * psa_reset_key_attributes() on an attribute structure is optional if
+ * the structure has only been modified by the following functions
+ * since it was initialized or last reset with psa_reset_key_attributes():
+ * - psa_set_key_id()
+ * - psa_set_key_lifetime()
+ * - psa_set_key_type()
+ * - psa_set_key_bits()
+ * - psa_set_key_usage_flags()
+ * - psa_set_key_algorithm()
+ *
+ * Before calling any function on a key attribute structure, the application
+ * must initialize it by any of the following means:
+ * - Set the structure to all-bits-zero, for example:
+ * \code
+ * psa_key_attributes_t attributes;
+ * memset(&attributes, 0, sizeof(attributes));
+ * \endcode
+ * - Initialize the structure to logical zero values, for example:
+ * \code
+ * psa_key_attributes_t attributes = {0};
+ * \endcode
+ * - Initialize the structure to the initializer #PSA_KEY_ATTRIBUTES_INIT,
+ * for example:
+ * \code
+ * psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ * \endcode
+ * - Assign the result of the function psa_key_attributes_init()
+ * to the structure, for example:
+ * \code
+ * psa_key_attributes_t attributes;
+ * attributes = psa_key_attributes_init();
+ * \endcode
+ *
+ * A freshly initialized attribute structure contains the following
+ * values:
+ *
+ * - lifetime: #PSA_KEY_LIFETIME_VOLATILE.
+ * - key identifier: unspecified.
+ * - type: \c 0.
+ * - key size: \c 0.
+ * - usage flags: \c 0.
+ * - algorithm: \c 0.
+ *
+ * A typical sequence to create a key is as follows:
+ * -# Create and initialize an attribute structure.
+ * -# If the key is persistent, call psa_set_key_id().
+ * Also call psa_set_key_lifetime() to place the key in a non-default
+ * location.
+ * -# Set the key policy with psa_set_key_usage_flags() and
+ * psa_set_key_algorithm().
+ * -# Set the key type with psa_set_key_type().
+ * Skip this step if copying an existing key with psa_copy_key().
+ * -# When generating a random key with psa_generate_key() or deriving a key
+ * with psa_key_derivation_output_key(), set the desired key size with
+ * psa_set_key_bits().
+ * -# Call a key creation function: psa_import_key(), psa_generate_key(),
+ * psa_key_derivation_output_key() or psa_copy_key(). This function reads
+ * the attribute structure, creates a key with these attributes, and
+ * outputs a handle to the newly created key.
+ * -# The attribute structure is now no longer necessary.
+ * You may call psa_reset_key_attributes(), although this is optional
+ * with the workflow presented here because the attributes currently
+ * defined in this specification do not require any additional resources
+ * beyond the structure itself.
+ *
+ * A typical sequence to query a key's attributes is as follows:
+ * -# Call psa_get_key_attributes().
+ * -# Call `psa_get_key_xxx` functions to retrieve the attribute(s) that
+ * you are interested in.
+ * -# Call psa_reset_key_attributes() to free any resources that may be
+ * used by the attribute structure.
+ *
+ * Once a key has been created, it is impossible to change its attributes.
+ */
+typedef struct psa_key_attributes_s psa_key_attributes_t;
+
+/**@}*/
+
/** \defgroup derivation Key derivation
* @{
*/
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 95088a0d14..0b33d764b4 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -363,6 +363,13 @@ static psa_status_t mbedtls_to_psa_error( int ret )
/* Key management */
/****************************************************************/
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+static inline int psa_key_slot_is_external( const psa_key_slot_t *slot )
+{
+ return( psa_key_lifetime_is_external( slot->lifetime ) );
+}
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+
#if defined(MBEDTLS_ECP_C)
static psa_ecc_curve_t mbedtls_ecc_group_to_psa( mbedtls_ecp_group_id grpid )
{
@@ -864,9 +871,46 @@ static psa_status_t psa_get_key_from_slot( psa_key_handle_t handle,
return( PSA_SUCCESS );
}
+/** Retrieve a slot which must contain a transparent key.
+ *
+ * A transparent key is a key for which the key material is directly
+ * available, as opposed to a key in a secure element.
+ *
+ * This is a temporary function to use instead of psa_get_key_from_slot()
+ * until secure element support is fully implemented.
+ */
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+static psa_status_t psa_get_transparent_key( psa_key_handle_t handle,
+ psa_key_slot_t **p_slot,
+ psa_key_usage_t usage,
+ psa_algorithm_t alg )
+{
+ psa_status_t status = psa_get_key_from_slot( handle, p_slot, usage, alg );
+ if( status != PSA_SUCCESS )
+ return( status );
+ if( psa_key_slot_is_external( *p_slot ) )
+ {
+ *p_slot = NULL;
+ return( PSA_ERROR_NOT_SUPPORTED );
+ }
+ return( PSA_SUCCESS );
+}
+#else /* MBEDTLS_PSA_CRYPTO_SE_C */
+/* With no secure element support, all keys are transparent. */
+#define psa_get_transparent_key( handle, p_slot, usage, alg ) \
+ psa_get_key_from_slot( handle, p_slot, usage, alg )
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+
/** Wipe key data from a slot. Preserve metadata such as the policy. */
static psa_status_t psa_remove_key_data_from_memory( psa_key_slot_t *slot )
{
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+ if( psa_key_slot_is_external( slot ) )
+ {
+ /* No key material to clean. */
+ }
+ else
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
if( slot->type == PSA_KEY_TYPE_NONE )
{
/* No key material to clean. */
@@ -925,10 +969,39 @@ 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;
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+ psa_se_drv_table_entry_t *driver;
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
status = psa_get_key_slot( handle, &slot );
if( status != PSA_SUCCESS )
return( status );
+
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+ driver = psa_get_se_driver_entry( slot->lifetime );
+ if( driver != NULL )
+ {
+ /* For a key in a secure element, we need to do three things:
+ * remove the key file in internal storage, destroy the
+ * key inside the secure element, and update the driver's
+ * persistent data. Start a transaction that will encompass these
+ * three actions. */
+ psa_crypto_prepare_transaction( PSA_CRYPTO_TRANSACTION_DESTROY_KEY );
+ psa_crypto_transaction.key.lifetime = slot->lifetime;
+ psa_crypto_transaction.key.slot = slot->data.se.slot_number;
+ psa_crypto_transaction.key.id = slot->persistent_storage_id;
+ status = psa_crypto_save_transaction( );
+ if( status != PSA_SUCCESS )
+ {
+ (void) psa_crypto_stop_transaction( );
+ /* TOnogrepDO: destroy what can be destroyed anyway */
+ return( status );
+ }
+
+ status = psa_destroy_se_key( driver, slot->data.se.slot_number );
+ }
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
if( slot->lifetime == PSA_KEY_LIFETIME_PERSISTENT )
{
@@ -936,6 +1009,23 @@ psa_status_t psa_destroy_key( psa_key_handle_t handle )
psa_destroy_persistent_key( slot->persistent_storage_id );
}
#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 )
+ {
+ /* TOnogrepDO: destroy what can be destroyed anyway */
+ return( status );
+ }
+ }
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+
status = psa_wipe_key_slot( slot );
if( status != PSA_SUCCESS )
return( status );
@@ -1050,6 +1140,22 @@ exit:
}
#endif /* MBEDTLS_RSA_C */
+/** Retrieve the readily-accessible attributes of a key in a slot.
+ *
+ * This function does not compute attributes that are not directly
+ * stored in the slot, such as the bit size of a transparent key.
+ */
+static void psa_get_key_slot_attributes( psa_key_slot_t *slot,
+ psa_key_attributes_t *attributes )
+{
+ attributes->id = slot->persistent_storage_id;
+ attributes->lifetime = slot->lifetime;
+ attributes->policy = slot->policy;
+ attributes->type = slot->type;
+}
+
+/** Retrieve all the publicly-accessible attributes of a key.
+ */
psa_status_t psa_get_key_attributes( psa_key_handle_t handle,
psa_key_attributes_t *attributes )
{
@@ -1058,14 +1164,11 @@ psa_status_t psa_get_key_attributes( psa_key_handle_t handle,
psa_reset_key_attributes( attributes );
- status = psa_get_key_slot( handle, &slot );
+ status = psa_get_transparent_key( handle, &slot, 0, 0 );
if( status != PSA_SUCCESS )
return( status );
- attributes->id = slot->persistent_storage_id;
- attributes->lifetime = slot->lifetime;
- attributes->policy = slot->policy;
- attributes->type = slot->type;
+ psa_get_key_slot_attributes( slot, attributes );
attributes->bits = psa_get_key_slot_bits( slot );
switch( slot->type )
@@ -1108,11 +1211,33 @@ static psa_status_t psa_internal_export_key( const psa_key_slot_t *slot,
size_t *data_length,
int export_public_key )
{
+#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 */
+
*data_length = 0;
if( export_public_key && ! PSA_KEY_TYPE_IS_ASYMMETRIC( slot->type ) )
return( PSA_ERROR_INVALID_ARGUMENT );
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+ if( psa_get_se_driver( slot->lifetime, &drv, &drv_context ) )
+ {
+ psa_drv_se_export_key_t method;
+ if( drv->key_management == NULL )
+ return( PSA_ERROR_NOT_SUPPORTED );
+ method = ( export_public_key ?
+ drv->key_management->p_export_public :
+ drv->key_management->p_export );
+ if( method == NULL )
+ return( PSA_ERROR_NOT_SUPPORTED );
+ return( method( drv_context,
+ slot->data.se.slot_number,
+ data, data_size, data_length ) );
+ }
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+
if( key_type_is_raw_bytes( slot->type ) )
{
if( slot->data.raw.bytes > data_size )
@@ -1291,9 +1416,11 @@ static psa_status_t psa_set_key_policy_internal(
* In case of failure at any step, stop the sequence and call
* psa_fail_key_creation().
*
- * \param attributes Key attributes for the new key.
- * \param handle On success, a handle for the allocated slot.
- * \param p_slot On success, a pointer to the prepared slot.
+ * \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.
+ * \param[out] p_drv On any return, the driver for the key, if any.
+ * NULL for a transparent key.
*
* \retval #PSA_SUCCESS
* The key slot is ready to receive key material.
@@ -1303,11 +1430,14 @@ static psa_status_t psa_set_key_policy_internal(
static psa_status_t psa_start_key_creation(
const psa_key_attributes_t *attributes,
psa_key_handle_t *handle,
- psa_key_slot_t **p_slot )
+ psa_key_slot_t **p_slot,
+ psa_se_drv_table_entry_t **p_drv )
{
psa_status_t status;
psa_key_slot_t *slot;
+ *p_drv = NULL;
+
status = psa_internal_allocate_key_slot( handle, p_slot );
if( status != PSA_SUCCESS )
return( status );
@@ -1317,16 +1447,51 @@ static psa_status_t psa_start_key_creation(
if( status != PSA_SUCCESS )
return( status );
slot->lifetime = attributes->lifetime;
+
if( attributes->lifetime != PSA_KEY_LIFETIME_VOLATILE )
{
status = psa_validate_persistent_key_parameters( attributes->lifetime,
- attributes->id, 1 );
+ attributes->id,
+ p_drv, 1 );
if( status != PSA_SUCCESS )
return( status );
slot->persistent_storage_id = attributes->id;
}
slot->type = attributes->type;
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+ /* For a key in a secure element, we need to do three things:
+ * create the key file in internal storage, create the
+ * key inside the secure element, and update the driver's
+ * persistent data. Start a transaction that will encompass these
+ * three actions. */
+ /* The first thing to do is to find a slot number for the new key.
+ * We save the slot number in persistent storage as part of the
+ * transaction data. It will be needed to recover if the power
+ * fails during the key creation process, to clean up on the secure
+ * element side after restarting. Obtaining a slot number from the
+ * 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 )
+ {
+ status = psa_find_se_slot_for_key( attributes, *p_drv,
+ &slot->data.se.slot_number );
+ if( status != PSA_SUCCESS )
+ return( status );
+ psa_crypto_prepare_transaction( PSA_CRYPTO_TRANSACTION_CREATE_KEY );
+ psa_crypto_transaction.key.lifetime = slot->lifetime;
+ psa_crypto_transaction.key.slot = slot->data.se.slot_number;
+ psa_crypto_transaction.key.id = slot->persistent_storage_id;
+ status = psa_crypto_save_transaction( );
+ if( status != PSA_SUCCESS )
+ {
+ (void) psa_crypto_stop_transaction( );
+ return( status );
+ }
+ }
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+
return( status );
}
@@ -1338,47 +1503,82 @@ static psa_status_t psa_start_key_creation(
* See the documentation of psa_start_key_creation() for the intended use
* of this function.
*
- * \param slot Pointer to the slot with key material.
+ * \param[in,out] slot Pointer to the slot with key material.
+ * \param[in] driver The secure element driver for the key,
+ * or NULL for a transparent key.
*
* \retval #PSA_SUCCESS
* The key was successfully created. The handle is now valid.
* \return If this function fails, the key slot is an invalid state.
* You must call psa_fail_key_creation() to wipe and free the slot.
*/
-static psa_status_t psa_finish_key_creation( psa_key_slot_t *slot )
+static psa_status_t psa_finish_key_creation(
+ psa_key_slot_t *slot,
+ psa_se_drv_table_entry_t *driver )
{
psa_status_t status = PSA_SUCCESS;
(void) slot;
+ (void) driver;
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
- if( slot->lifetime == PSA_KEY_LIFETIME_PERSISTENT )
+ if( slot->lifetime != PSA_KEY_LIFETIME_VOLATILE )
{
uint8_t *buffer = NULL;
size_t buffer_size = 0;
- size_t length;
+ size_t length = 0;
- buffer_size = PSA_KEY_EXPORT_MAX_SIZE( slot->type,
- psa_get_key_slot_bits( slot ) );
- buffer = mbedtls_calloc( 1, buffer_size );
- if( buffer == NULL && buffer_size != 0 )
- return( PSA_ERROR_INSUFFICIENT_MEMORY );
- status = psa_internal_export_key( slot,
- buffer, buffer_size, &length,
- 0 );
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+ if( driver != NULL )
+ {
+ buffer = (uint8_t*) &slot->data.se.slot_number;
+ length = sizeof( slot->data.se.slot_number );
+ }
+ else
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+ {
+ buffer_size = PSA_KEY_EXPORT_MAX_SIZE( slot->type,
+ psa_get_key_slot_bits( slot ) );
+ buffer = mbedtls_calloc( 1, buffer_size );
+ if( buffer == NULL && buffer_size != 0 )
+ return( PSA_ERROR_INSUFFICIENT_MEMORY );
+ status = psa_internal_export_key( slot,
+ buffer, buffer_size, &length,
+ 0 );
+ }
if( status == PSA_SUCCESS )
{
- status = psa_save_persistent_key( slot->persistent_storage_id,
- slot->type, &slot->policy,
- buffer, length );
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ psa_get_key_slot_attributes( slot, &attributes );
+ status = psa_save_persistent_key( &attributes, buffer, length );
}
- if( buffer_size != 0 )
- mbedtls_platform_zeroize( buffer, buffer_size );
- mbedtls_free( buffer );
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+ if( driver == NULL )
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+ {
+ if( buffer_size != 0 )
+ mbedtls_platform_zeroize( buffer, buffer_size );
+ mbedtls_free( buffer );
+ }
}
#endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+ if( driver != NULL )
+ {
+ status = psa_save_se_persistent_data( driver );
+ if( status != PSA_SUCCESS )
+ {
+ psa_destroy_persistent_key( slot->persistent_storage_id );
+ return( status );
+ }
+ status = psa_crypto_stop_transaction( );
+ if( status != PSA_SUCCESS )
+ return( status );
+ }
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+
return( status );
}
@@ -1390,12 +1590,30 @@ static psa_status_t psa_finish_key_creation( psa_key_slot_t *slot )
* See the documentation of psa_start_key_creation() for the intended use
* of this function.
*
- * \param slot Pointer to the slot with key material.
+ * \param[in,out] slot Pointer to the slot with key material.
+ * \param[in] driver The secure element driver for the key,
+ * or NULL for a transparent key.
*/
-static void psa_fail_key_creation( psa_key_slot_t *slot )
+static void psa_fail_key_creation( psa_key_slot_t *slot,
+ psa_se_drv_table_entry_t *driver )
{
+ (void) driver;
+
if( slot == NULL )
return;
+
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+ /* TOnogrepDO: 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. */
+
+ /* 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. */
+ (void) psa_crypto_stop_transaction( );
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+
psa_wipe_key_slot( slot );
}
@@ -1458,23 +1676,45 @@ psa_status_t psa_import_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 );
+ status = psa_start_key_creation( attributes, handle, &slot, &driver );
if( status != PSA_SUCCESS )
goto exit;
- status = psa_import_key_into_slot( slot, data, data_length );
- if( status != PSA_SUCCESS )
- goto exit;
- status = psa_check_key_slot_attributes( slot, attributes );
- if( status != PSA_SUCCESS )
- goto exit;
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+ if( driver != NULL )
+ {
+ const psa_drv_se_t *drv = psa_get_se_driver_methods( driver );
+ if( drv->key_management == NULL ||
+ drv->key_management->p_import == NULL )
+ {
+ status = PSA_ERROR_NOT_SUPPORTED;
+ goto exit;
+ }
+ status = drv->key_management->p_import(
+ psa_get_se_driver_context( driver ),
+ slot->data.se.slot_number,
+ slot->lifetime, slot->type, slot->policy.alg, slot->policy.usage,
+ data, data_length );
+ /* TOnogrepDO: psa_check_key_slot_attributes? */
+ }
+ else
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+ {
+ status = psa_import_key_into_slot( slot, data, data_length );
+ if( status != PSA_SUCCESS )
+ goto exit;
+ status = psa_check_key_slot_attributes( slot, attributes );
+ if( status != PSA_SUCCESS )
+ goto exit;
+ }
- status = psa_finish_key_creation( slot );
+ status = psa_finish_key_creation( slot, driver );
exit:
if( status != PSA_SUCCESS )
{
- psa_fail_key_creation( slot );
+ psa_fail_key_creation( slot, driver );
*handle = 0;
}
return( status );
@@ -1514,9 +1754,10 @@ psa_status_t psa_copy_key( psa_key_handle_t source_handle,
psa_key_slot_t *source_slot = NULL;
psa_key_slot_t *target_slot = NULL;
psa_key_attributes_t actual_attributes = *specified_attributes;
+ psa_se_drv_table_entry_t *driver = NULL;
- status = psa_get_key_from_slot( source_handle, &source_slot,
- PSA_KEY_USAGE_COPY, 0 );
+ status = psa_get_transparent_key( source_handle, &source_slot,
+ PSA_KEY_USAGE_COPY, 0 );
if( status != PSA_SUCCESS )
goto exit;
@@ -1530,19 +1771,28 @@ psa_status_t psa_copy_key( psa_key_handle_t source_handle,
goto exit;
status = psa_start_key_creation( &actual_attributes,
- target_handle, &target_slot );
+ target_handle, &target_slot, &driver );
if( status != PSA_SUCCESS )
goto exit;
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+ if( driver != NULL )
+ {
+ /* Copying to a secure element is not implemented yet. */
+ status = PSA_ERROR_NOT_SUPPORTED;
+ goto exit;
+ }
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+
status = psa_copy_key_material( source_slot, target_slot );
if( status != PSA_SUCCESS )
goto exit;
- status = psa_finish_key_creation( target_slot );
+ status = psa_finish_key_creation( target_slot, driver );
exit:
if( status != PSA_SUCCESS )
{
- psa_fail_key_creation( target_slot );
+ psa_fail_key_creation( target_slot, driver );
*target_handle = 0;
}
return( status );
@@ -2296,7 +2546,7 @@ static psa_status_t psa_mac_setup( psa_mac_operation_t *operation,
if( is_sign )
operation->is_sign = 1;
- status = psa_get_key_from_slot( handle, &slot, usage, alg );
+ status = psa_get_transparent_key( handle, &slot, usage, alg );
if( status != PSA_SUCCESS )
goto exit;
key_bits = psa_get_key_slot_bits( slot );
@@ -2875,7 +3125,7 @@ psa_status_t psa_asymmetric_sign( psa_key_handle_t handle,
*signature_length = signature_size;
- status = psa_get_key_from_slot( handle, &slot, PSA_KEY_USAGE_SIGN, alg );
+ status = psa_get_transparent_key( handle, &slot, PSA_KEY_USAGE_SIGN, alg );
if( status != PSA_SUCCESS )
goto exit;
if( ! PSA_KEY_TYPE_IS_KEY_PAIR( slot->type ) )
@@ -2948,7 +3198,7 @@ psa_status_t psa_asymmetric_verify( psa_key_handle_t handle,
psa_key_slot_t *slot;
psa_status_t status;
- status = psa_get_key_from_slot( handle, &slot, PSA_KEY_USAGE_VERIFY, alg );
+ status = psa_get_transparent_key( handle, &slot, PSA_KEY_USAGE_VERIFY, alg );
if( status != PSA_SUCCESS )
return( status );
@@ -3018,7 +3268,7 @@ psa_status_t psa_asymmetric_encrypt( psa_key_handle_t handle,
if( ! PSA_ALG_IS_RSA_OAEP( alg ) && salt_length != 0 )
return( PSA_ERROR_INVALID_ARGUMENT );
- status = psa_get_key_from_slot( handle, &slot, PSA_KEY_USAGE_ENCRYPT, alg );
+ status = psa_get_transparent_key( handle, &slot, PSA_KEY_USAGE_ENCRYPT, alg );
if( status != PSA_SUCCESS )
return( status );
if( ! ( PSA_KEY_TYPE_IS_PUBLIC_KEY( slot->type ) ||
@@ -3098,7 +3348,7 @@ psa_status_t psa_asymmetric_decrypt( psa_key_handle_t handle,
if( ! PSA_ALG_IS_RSA_OAEP( alg ) && salt_length != 0 )
return( PSA_ERROR_INVALID_ARGUMENT );
- status = psa_get_key_from_slot( handle, &slot, PSA_KEY_USAGE_DECRYPT, alg );
+ status = psa_get_transparent_key( handle, &slot, PSA_KEY_USAGE_DECRYPT, alg );
if( status != PSA_SUCCESS )
return( status );
if( ! PSA_KEY_TYPE_IS_KEY_PAIR( slot->type ) )
@@ -3207,7 +3457,7 @@ static psa_status_t psa_cipher_setup( psa_cipher_operation_t *operation,
if( status != PSA_SUCCESS )
return( status );
- status = psa_get_key_from_slot( handle, &slot, usage, alg);
+ status = psa_get_transparent_key( handle, &slot, usage, alg);
if( status != PSA_SUCCESS )
goto exit;
key_bits = psa_get_key_slot_bits( slot );
@@ -3544,7 +3794,7 @@ static psa_status_t psa_aead_setup( aead_operation_t *operation,
size_t key_bits;
mbedtls_cipher_id_t cipher_id;
- status = psa_get_key_from_slot( handle, &operation->slot, usage, alg );
+ status = psa_get_transparent_key( handle, &operation->slot, usage, alg );
if( status != PSA_SUCCESS )
return( status );
@@ -4437,7 +4687,15 @@ psa_status_t psa_key_derivation_output_key( const psa_key_attributes_t *attribut
{
psa_status_t status;
psa_key_slot_t *slot = NULL;
- status = psa_start_key_creation( attributes, handle, &slot );
+ psa_se_drv_table_entry_t *driver = NULL;
+ status = psa_start_key_creation( attributes, handle, &slot, &driver );
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+ if( driver != NULL )
+ {
+ /* Deriving a key in a secure element is not implemented yet. */
+ status = PSA_ERROR_NOT_SUPPORTED;
+ }
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
if( status == PSA_SUCCESS )
{
status = psa_generate_derived_key_internal( slot,
@@ -4445,10 +4703,10 @@ psa_status_t psa_key_derivation_output_key( const psa_key_attributes_t *attribut
operation );
}
if( status == PSA_SUCCESS )
- status = psa_finish_key_creation( slot );
+ status = psa_finish_key_creation( slot, driver );
if( status != PSA_SUCCESS )
{
- psa_fail_key_creation( slot );
+ psa_fail_key_creation( slot, driver );
*handle = 0;
}
return( status );
@@ -4718,7 +4976,7 @@ psa_status_t psa_key_derivation( psa_key_derivation_operation_t *operation,
if( ! PSA_ALG_IS_KEY_DERIVATION( alg ) )
return( PSA_ERROR_INVALID_ARGUMENT );
- status = psa_get_key_from_slot( handle, &slot, PSA_KEY_USAGE_DERIVE, alg );
+ status = psa_get_transparent_key( handle, &slot, PSA_KEY_USAGE_DERIVE, alg );
if( status != PSA_SUCCESS )
return( status );
@@ -5092,9 +5350,9 @@ psa_status_t psa_key_derivation_input_key(
{
psa_key_slot_t *slot;
psa_status_t status;
- status = psa_get_key_from_slot( handle, &slot,
- PSA_KEY_USAGE_DERIVE,
- operation->alg );
+ status = psa_get_transparent_key( handle, &slot,
+ PSA_KEY_USAGE_DERIVE,
+ operation->alg );
if( status != PSA_SUCCESS )
return( status );
if( slot->type != PSA_KEY_TYPE_DERIVE )
@@ -5241,8 +5499,8 @@ psa_status_t psa_key_derivation_key_agreement( psa_key_derivation_operation_t *o
psa_status_t status;
if( ! PSA_ALG_IS_KEY_AGREEMENT( operation->alg ) )
return( PSA_ERROR_INVALID_ARGUMENT );
- status = psa_get_key_from_slot( private_key, &slot,
- PSA_KEY_USAGE_DERIVE, operation->alg );
+ status = psa_get_transparent_key( private_key, &slot,
+ PSA_KEY_USAGE_DERIVE, operation->alg );
if( status != PSA_SUCCESS )
return( status );
status = psa_key_agreement_internal( operation, step,
@@ -5269,8 +5527,8 @@ psa_status_t psa_raw_key_agreement( psa_algorithm_t alg,
status = PSA_ERROR_INVALID_ARGUMENT;
goto exit;
}
- status = psa_get_key_from_slot( private_key, &slot,
- PSA_KEY_USAGE_DERIVE, alg );
+ status = psa_get_transparent_key( private_key, &slot,
+ PSA_KEY_USAGE_DERIVE, alg );
if( status != PSA_SUCCESS )
goto exit;
@@ -5467,7 +5725,15 @@ psa_status_t psa_generate_key( const psa_key_attributes_t *attributes,
{
psa_status_t status;
psa_key_slot_t *slot = NULL;
- status = psa_start_key_creation( attributes, handle, &slot );
+ psa_se_drv_table_entry_t *driver = NULL;
+ status = psa_start_key_creation( attributes, handle, &slot, &driver );
+#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;
+ }
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
if( status == PSA_SUCCESS )
{
status = psa_generate_key_internal(
@@ -5475,10 +5741,10 @@ psa_status_t psa_generate_key( const psa_key_attributes_t *attributes,
attributes->domain_parameters, attributes->domain_parameters_size );
}
if( status == PSA_SUCCESS )
- status = psa_finish_key_creation( slot );
+ status = psa_finish_key_creation( slot, driver );
if( status != PSA_SUCCESS )
{
- psa_fail_key_creation( slot );
+ psa_fail_key_creation( slot, driver );
*handle = 0;
}
return( status );
@@ -5520,6 +5786,30 @@ void mbedtls_psa_crypto_free( void )
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
}
+#if defined(PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS)
+/** Recover a transaction that was interrupted by a power failure.
+ *
+ * This function is called during initialization, before psa_crypto_init()
+ * returns. If this function returns a failure status, the initialization
+ * fails.
+ */
+static psa_status_t psa_crypto_recover_transaction(
+ const psa_crypto_transaction_t *transaction )
+{
+ switch( transaction->unknown.type )
+ {
+ case PSA_CRYPTO_TRANSACTION_CREATE_KEY:
+ case PSA_CRYPTO_TRANSACTION_DESTROY_KEY:
+ /* TOnogrepDO - fall through to the failure case until this
+ * is implemented */
+ default:
+ /* We found an unsupported transaction in the storage.
+ * We don't know what state the storage is in. Give up. */
+ return( PSA_ERROR_STORAGE_FAILURE );
+ }
+}
+#endif /* PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS */
+
psa_status_t psa_crypto_init( void )
{
psa_status_t status;
@@ -5553,6 +5843,22 @@ psa_status_t psa_crypto_init( void )
if( status != PSA_SUCCESS )
goto exit;
+#if defined(PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS)
+ status = psa_crypto_load_transaction( );
+ if( status == PSA_SUCCESS )
+ {
+ status = psa_crypto_recover_transaction( &psa_crypto_transaction );
+ if( status != PSA_SUCCESS )
+ goto exit;
+ status = psa_crypto_stop_transaction( );
+ }
+ else if( status == PSA_ERROR_DOES_NOT_EXIST )
+ {
+ /* There's no transaction to complete. It's all good. */
+ status = PSA_SUCCESS;
+ }
+#endif /* PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS */
+
/* All done. */
global_data.initialized = 1;
diff --git a/library/psa_crypto_core.h b/library/psa_crypto_core.h
index 5958972572..6096810f40 100644
--- a/library/psa_crypto_core.h
+++ b/library/psa_crypto_core.h
@@ -29,6 +29,7 @@
#endif
#include "psa/crypto.h"
+#include "psa/crypto_se_driver.h"
#include "mbedtls/ecp.h"
#include "mbedtls/rsa.h"
@@ -45,17 +46,25 @@ typedef struct
unsigned allocated : 1;
union
{
+ /* Raw-data key (key_type_is_raw_bytes() in psa_crypto.c) */
struct raw_data
{
uint8_t *data;
size_t bytes;
} raw;
#if defined(MBEDTLS_RSA_C)
+ /* RSA public key or key pair */
mbedtls_rsa_context *rsa;
#endif /* MBEDTLS_RSA_C */
#if defined(MBEDTLS_ECP_C)
+ /* EC public key or key pair */
mbedtls_ecp_keypair *ecp;
#endif /* MBEDTLS_ECP_C */
+ /* Any key type in a secure element */
+ struct se
+ {
+ psa_key_slot_number_t slot_number;
+ } se;
} data;
} psa_key_slot_t;
diff --git a/library/psa_crypto_se.c b/library/psa_crypto_se.c
index 688d4e7c8e..aece47d01c 100644
--- a/library/psa_crypto_se.c
+++ b/library/psa_crypto_se.c
@@ -28,23 +28,232 @@
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
#include
+#include
#include
+#include "psa/crypto_se_driver.h"
+
#include "psa_crypto_se.h"
+#if defined(MBEDTLS_PSA_ITS_FILE_C)
+#include "psa_crypto_its.h"
+#else /* Native ITS implementation */
+#include "psa/error.h"
+#include "psa/internal_trusted_storage.h"
+#endif
+
+#include "mbedtls/platform.h"
+#if !defined(MBEDTLS_PLATFORM_C)
+#define mbedtls_calloc calloc
+#define mbedtls_free free
+#endif
+
+
+
+/****************************************************************/
+/* Driver lookup */
+/****************************************************************/
+
+/* This structure is identical to psa_drv_se_context_t declared in
+ * `crypto_se_driver.h`, except that some parts are writable here
+ * (non-const, or pointer to non-const). */
typedef struct
+{
+ void *persistent_data;
+ size_t persistent_data_size;
+ uintptr_t transient_data;
+} psa_drv_se_internal_context_t;
+
+typedef struct psa_se_drv_table_entry_s
{
psa_key_lifetime_t lifetime;
const psa_drv_se_t *methods;
-} method_table_entry_t;
+ union
+ {
+ psa_drv_se_internal_context_t internal;
+ psa_drv_se_context_t context;
+ };
+} psa_se_drv_table_entry_t;
-static method_table_entry_t driver_table[PSA_MAX_SE_DRIVERS];
+static psa_se_drv_table_entry_t driver_table[PSA_MAX_SE_DRIVERS];
+
+psa_se_drv_table_entry_t *psa_get_se_driver_entry(
+ psa_key_lifetime_t lifetime )
+{
+ size_t i;
+ /* In the driver table, lifetime=0 means an entry that isn't used.
+ * No driver has a lifetime of 0 because it's a reserved value
+ * (which designates volatile keys). Make sure we never return
+ * a driver entry for lifetime 0. */
+ if( lifetime == 0 )
+ return( NULL );
+ for( i = 0; i < PSA_MAX_SE_DRIVERS; i++ )
+ {
+ if( driver_table[i].lifetime == lifetime )
+ return( &driver_table[i] );
+ }
+ return( NULL );
+}
+
+const psa_drv_se_t *psa_get_se_driver_methods(
+ const psa_se_drv_table_entry_t *driver )
+{
+ return( driver->methods );
+}
+
+psa_drv_se_context_t *psa_get_se_driver_context(
+ psa_se_drv_table_entry_t *driver )
+{
+ return( &driver->context );
+}
+
+int psa_get_se_driver( psa_key_lifetime_t lifetime,
+ const psa_drv_se_t **p_methods,
+ psa_drv_se_context_t **p_drv_context)
+{
+ psa_se_drv_table_entry_t *driver = psa_get_se_driver_entry( lifetime );
+ if( p_methods != NULL )
+ *p_methods = ( driver ? driver->methods : NULL );
+ if( p_drv_context != NULL )
+ *p_drv_context = ( driver ? &driver->context : NULL );
+ return( driver != NULL );
+}
+
+
+
+/****************************************************************/
+/* Persistent data management */
+/****************************************************************/
+
+static psa_status_t psa_get_se_driver_its_file_uid(
+ const psa_se_drv_table_entry_t *driver,
+ psa_storage_uid_t *uid )
+{
+ if( driver->lifetime > PSA_MAX_SE_LIFETIME )
+ return( PSA_ERROR_NOT_SUPPORTED );
+
+#if SIZE_MAX > UINT32_MAX
+ /* ITS file sizes are limited to 32 bits. */
+ if( driver->internal.persistent_data_size > UINT32_MAX )
+ return( PSA_ERROR_NOT_SUPPORTED );
+#endif
+
+ /* See the documentation of PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE. */
+ *uid = PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE + driver->lifetime;
+ return( PSA_SUCCESS );
+}
+
+psa_status_t psa_load_se_persistent_data(
+ const psa_se_drv_table_entry_t *driver )
+{
+ psa_status_t status;
+ psa_storage_uid_t uid;
+
+ status = psa_get_se_driver_its_file_uid( driver, &uid );
+ if( status != PSA_SUCCESS )
+ return( status );
+
+ /* psa_get_se_driver_its_file_uid ensures that the size_t
+ * persistent_data_size is in range, but compilers don't know that,
+ * so cast to reassure them. */
+ return( psa_its_get( uid, 0,
+ (uint32_t) driver->internal.persistent_data_size,
+ driver->internal.persistent_data ) );
+}
+
+psa_status_t psa_save_se_persistent_data(
+ const psa_se_drv_table_entry_t *driver )
+{
+ psa_status_t status;
+ psa_storage_uid_t uid;
+
+ status = psa_get_se_driver_its_file_uid( driver, &uid );
+ if( status != PSA_SUCCESS )
+ return( status );
+
+ /* psa_get_se_driver_its_file_uid ensures that the size_t
+ * persistent_data_size is in range, but compilers don't know that,
+ * so cast to reassure them. */
+ return( psa_its_set( uid,
+ (uint32_t) driver->internal.persistent_data_size,
+ driver->internal.persistent_data,
+ 0 ) );
+}
+
+psa_status_t psa_destroy_se_persistent_data( psa_key_lifetime_t lifetime )
+{
+ psa_storage_uid_t uid;
+ if( lifetime > PSA_MAX_SE_LIFETIME )
+ return( PSA_ERROR_NOT_SUPPORTED );
+ uid = PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE + lifetime;
+ return( psa_its_remove( uid ) );
+}
+
+psa_status_t psa_find_se_slot_for_key(
+ const psa_key_attributes_t *attributes,
+ 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 != attributes->lifetime )
+ return( PSA_ERROR_CORRUPTION_DETECTED );
+
+ /* 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 );
+ return( status );
+}
+
+psa_status_t psa_destroy_se_key( psa_se_drv_table_entry_t *driver,
+ psa_key_slot_number_t slot_number )
+{
+ psa_status_t status;
+ psa_status_t storage_status;
+ /* Normally a missing method would mean that the action is not
+ * supported. But psa_destroy_key() is not supposed to return
+ * PSA_ERROR_NOT_SUPPORTED: if you can create a key, you should
+ * be able to destroy it. The only use case for a driver that
+ * does not have a way to destroy keys at all is if the keys are
+ * locked in a read-only state: we can use the keys but not
+ * destroy them. Hence, if the driver doesn't support destroying
+ * keys, it's really a lack of permission. */
+ if( driver->methods->key_management == NULL ||
+ driver->methods->key_management->p_destroy == NULL )
+ return( PSA_ERROR_NOT_PERMITTED );
+ status = driver->methods->key_management->p_destroy(
+ &driver->context,
+ driver->internal.persistent_data,
+ slot_number );
+ storage_status = psa_save_se_persistent_data( driver );
+ return( status == PSA_SUCCESS ? storage_status : status );
+}
+
+
+
+/****************************************************************/
+/* Driver registration */
+/****************************************************************/
psa_status_t psa_register_se_driver(
psa_key_lifetime_t lifetime,
const psa_drv_se_t *methods)
{
size_t i;
+ psa_status_t status;
if( methods->hal_version != PSA_DRV_SE_HAL_VERSION )
return( PSA_ERROR_NOT_SUPPORTED );
@@ -59,6 +268,8 @@ psa_status_t psa_register_se_driver(
{
return( PSA_ERROR_INVALID_ARGUMENT );
}
+ if( lifetime > PSA_MAX_SE_LIFETIME )
+ return( PSA_ERROR_NOT_SUPPORTED );
for( i = 0; i < PSA_MAX_SE_DRIVERS; i++ )
{
@@ -75,12 +286,48 @@ psa_status_t psa_register_se_driver(
driver_table[i].lifetime = lifetime;
driver_table[i].methods = methods;
+
+ if( methods->persistent_data_size != 0 )
+ {
+ driver_table[i].internal.persistent_data =
+ mbedtls_calloc( 1, methods->persistent_data_size );
+ if( driver_table[i].internal.persistent_data == NULL )
+ {
+ status = PSA_ERROR_INSUFFICIENT_MEMORY;
+ goto error;
+ }
+ /* Load the driver's persistent data. On first use, the persistent
+ * data does not exist in storage, and is initialized to
+ * all-bits-zero by the calloc call just above. */
+ status = psa_load_se_persistent_data( &driver_table[i] );
+ if( status != PSA_SUCCESS && status != PSA_ERROR_DOES_NOT_EXIST )
+ goto error;
+ }
+ driver_table[i].internal.persistent_data_size =
+ methods->persistent_data_size;
+
return( PSA_SUCCESS );
+
+error:
+ memset( &driver_table[i], 0, sizeof( driver_table[i] ) );
+ return( status );
}
void psa_unregister_all_se_drivers( void )
{
+ size_t i;
+ for( i = 0; i < PSA_MAX_SE_DRIVERS; i++ )
+ {
+ if( driver_table[i].internal.persistent_data != NULL )
+ mbedtls_free( driver_table[i].internal.persistent_data );
+ }
memset( driver_table, 0, sizeof( driver_table ) );
}
+
+
+/****************************************************************/
+/* The end */
+/****************************************************************/
+
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
diff --git a/library/psa_crypto_se.h b/library/psa_crypto_se.h
index e99bd25763..08e658cddc 100644
--- a/library/psa_crypto_se.h
+++ b/library/psa_crypto_se.h
@@ -31,6 +31,30 @@
#include "psa/crypto.h"
#include "psa/crypto_se_driver.h"
+/** The maximum lifetime value that this implementation supports
+ * for a secure element.
+ *
+ * This is not a characteristic that each PSA implementation has, but a
+ * limitation of the current implementation due to the constraints imposed
+ * by storage. See #PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE.
+ *
+ * The minimum lifetime value for a secure element is 2, like on any
+ * PSA implementation (0=volatile and 1=internal-storage are taken).
+ */
+#define PSA_MAX_SE_LIFETIME 255
+
+/** The base of the range of ITS file identifiers for secure element
+ * driver persistent data.
+ *
+ * We use a slice of the implemenation reserved range 0xffff0000..0xffffffff,
+ * specifically the range 0xfffffe00..0xfffffeff. The length of this range
+ * drives the value of #PSA_MAX_SE_LIFETIME.
+ * The identifiers 0xfffffe00 and 0xfffffe01 are actually not used since
+ * they correspond to #PSA_KEY_LIFETIME_VOLATILE and
+ * #PSA_KEY_LIFETIME_PERSISTENT which don't have a driver.
+ */
+#define PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE ( (psa_key_id_t) 0xfffffe00 )
+
/** The maximum number of registered secure element driver lifetimes. */
#define PSA_MAX_SE_DRIVERS 4
@@ -42,4 +66,109 @@
*/
void psa_unregister_all_se_drivers( void );
+/** A structure that describes a registered secure element driver.
+ *
+ * A secure element driver table entry contains a pointer to the
+ * driver's method table as well as the driver context structure.
+ */
+typedef struct psa_se_drv_table_entry_s psa_se_drv_table_entry_t;
+
+/** Return the secure element driver information for a lifetime value.
+ *
+ * \param lifetime The lifetime value to query.
+ * \param[out] p_methods On output, if there is a driver,
+ * \c *methods points to its method table.
+ * Otherwise \c *methods is \c NULL.
+ * \param[out] p_drv_context On output, if there is a driver,
+ * \c *drv_context points to its context
+ * structure.
+ * Otherwise \c *drv_context is \c NULL.
+ *
+ * \retval 1
+ * \p lifetime corresponds to a registered driver.
+ * \retval 0
+ * \p lifetime does not correspond to a registered driver.
+ */
+int psa_get_se_driver( psa_key_lifetime_t lifetime,
+ const psa_drv_se_t **p_methods,
+ psa_drv_se_context_t **p_drv_context);
+
+/** Return the secure element driver table entry for a lifetime value.
+ *
+ * \param lifetime The lifetime value to query.
+ *
+ * \return The driver table entry for \p lifetime, or
+ * \p NULL if \p lifetime does not correspond to a registered driver.
+ */
+psa_se_drv_table_entry_t *psa_get_se_driver_entry(
+ psa_key_lifetime_t lifetime );
+
+/** Return the method table for a secure element driver.
+ *
+ * \param[in] driver The driver table entry to access, or \c NULL.
+ *
+ * \return The driver's method table.
+ * \c NULL if \p driver is \c NULL.
+ */
+const psa_drv_se_t *psa_get_se_driver_methods(
+ const psa_se_drv_table_entry_t *driver );
+
+/** Return the context of a secure element driver.
+ *
+ * \param[in] driver The driver table entry to access, or \c NULL.
+ *
+ * \return A pointer to the driver context.
+ * \c NULL if \p driver is \c NULL.
+ */
+psa_drv_se_context_t *psa_get_se_driver_context(
+ psa_se_drv_table_entry_t *driver );
+
+/** Find a free slot for a key that is to be created.
+ *
+ * This function calls the relevant method in the driver to find a suitable
+ * slot for a key with the given attributes.
+ *
+ * \param[in] attributes Metadata about the key that is about to be created.
+ * \param[in] driver The driver table entry to query.
+ * \param[out] slot_number On success, a slot number that is free in this
+ * secure element.
+ */
+psa_status_t psa_find_se_slot_for_key(
+ const psa_key_attributes_t *attributes,
+ psa_se_drv_table_entry_t *driver,
+ psa_key_slot_number_t *slot_number );
+
+/** Destoy a key in a secure element.
+ *
+ * This function calls the relevant driver method to destroy a key
+ * and updates the driver's persistent data.
+ */
+psa_status_t psa_destroy_se_key( psa_se_drv_table_entry_t *driver,
+ psa_key_slot_number_t slot_number );
+
+/** Load the persistent data of a secure element driver.
+ *
+ * \param driver The driver table entry containing the persistent
+ * data to load from storage.
+ */
+psa_status_t psa_load_se_persistent_data(
+ const psa_se_drv_table_entry_t *driver );
+
+/** Save the persistent data of a secure element driver.
+ *
+ * \param[in] driver The driver table entry containing the persistent
+ * data to save to storage.
+ */
+psa_status_t psa_save_se_persistent_data(
+ const psa_se_drv_table_entry_t *driver );
+
+/** Destroy the persistent data of a secure element driver.
+ *
+ * This is currently only used for testing.
+ *
+ * \param[in] lifetime The driver lifetime whose persistent data should
+ * be erased.
+ */
+psa_status_t psa_destroy_se_persistent_data( psa_key_lifetime_t lifetime );
+
#endif /* PSA_CRYPTO_SE_H */
diff --git a/library/psa_crypto_slot_management.c b/library/psa_crypto_slot_management.c
index 900aa41a5f..6b87ea0b01 100644
--- a/library/psa_crypto_slot_management.c
+++ b/library/psa_crypto_slot_management.c
@@ -124,15 +124,35 @@ static psa_status_t psa_load_persistent_key_into_slot( psa_key_slot_t *p_slot )
psa_status_t status = PSA_SUCCESS;
uint8_t *key_data = NULL;
size_t key_data_length = 0;
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
- status = psa_load_persistent_key( p_slot->persistent_storage_id,
- &( p_slot )->type,
- &( p_slot )->policy, &key_data,
- &key_data_length );
+ psa_set_key_id( &attributes, p_slot->persistent_storage_id );
+ status = psa_load_persistent_key( &attributes,
+ &key_data, &key_data_length );
if( status != PSA_SUCCESS )
goto exit;
- status = psa_import_key_into_slot( p_slot,
- key_data, key_data_length );
+ p_slot->lifetime = psa_get_key_lifetime( &attributes );
+ p_slot->type = psa_get_key_type( &attributes );
+ p_slot->policy = attributes.policy;
+
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+ if( psa_key_lifetime_is_external( p_slot->lifetime ) )
+ {
+ if( key_data_length != sizeof( p_slot->data.se.slot_number ) )
+ {
+ status = PSA_ERROR_STORAGE_FAILURE;
+ goto exit;
+ }
+ memcpy( &p_slot->data.se.slot_number, key_data,
+ sizeof( p_slot->data.se.slot_number ) );
+ }
+ else
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+ {
+ status = psa_import_key_into_slot( p_slot,
+ key_data, key_data_length );
+ }
+
exit:
psa_free_persistent_key_data( key_data, key_data_length );
return( status );
@@ -168,8 +188,20 @@ static int psa_is_key_id_valid( psa_key_file_id_t file_id,
psa_status_t psa_validate_persistent_key_parameters(
psa_key_lifetime_t lifetime,
psa_key_file_id_t id,
+ psa_se_drv_table_entry_t **p_drv,
int creating )
{
+ if( p_drv != NULL )
+ *p_drv = NULL;
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+ if( psa_key_lifetime_is_external( lifetime ) )
+ {
+ *p_drv = psa_get_se_driver_entry( lifetime );
+ if( *p_drv == NULL )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ }
+ else
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
if( lifetime != PSA_KEY_LIFETIME_PERSISTENT )
return( PSA_ERROR_INVALID_ARGUMENT );
@@ -194,7 +226,7 @@ psa_status_t psa_open_key( psa_key_file_id_t id, psa_key_handle_t *handle )
*handle = 0;
status = psa_validate_persistent_key_parameters(
- PSA_KEY_LIFETIME_PERSISTENT, id, 0 );
+ PSA_KEY_LIFETIME_PERSISTENT, id, NULL, 0 );
if( status != PSA_SUCCESS )
return( status );
diff --git a/library/psa_crypto_slot_management.h b/library/psa_crypto_slot_management.h
index 5c1bde146e..049520d4b0 100644
--- a/library/psa_crypto_slot_management.h
+++ b/library/psa_crypto_slot_management.h
@@ -22,6 +22,9 @@
#ifndef PSA_CRYPTO_SLOT_MANAGEMENT_H
#define PSA_CRYPTO_SLOT_MANAGEMENT_H
+#include "psa/crypto.h"
+#include "psa_crypto_se.h"
+
/* Number of key slots (plus one because 0 is not used).
* The value is a compile-time constant for now, for simplicity. */
#define PSA_KEY_SLOT_COUNT 32
@@ -71,6 +74,24 @@ void psa_wipe_all_key_slots( void );
psa_status_t psa_internal_allocate_key_slot( psa_key_handle_t *handle,
psa_key_slot_t **p_slot );
+/** Test whether a lifetime designates a key in an external cryptoprocessor.
+ *
+ * \param lifetime The lifetime to test.
+ *
+ * \retval 1
+ * The lifetime designates an external key. There should be a
+ * registered driver for this lifetime, otherwise the key cannot
+ * be created or manipulated.
+ * \retval 0
+ * The lifetime designates a key that is volatile or in internal
+ * storage.
+ */
+static inline int psa_key_lifetime_is_external( psa_key_lifetime_t lifetime )
+{
+ return( lifetime != PSA_KEY_LIFETIME_VOLATILE &&
+ lifetime != PSA_KEY_LIFETIME_PERSISTENT );
+}
+
/** Test whether the given parameters are acceptable for a persistent key.
*
* This function does not access the storage in any way. It only tests
@@ -78,8 +99,16 @@ psa_status_t psa_internal_allocate_key_slot( psa_key_handle_t *handle,
* It does not test whether the a file by the given id exists or could be
* created.
*
+ * If the key is in external storage, this function returns the corresponding
+ * driver.
+ *
* \param lifetime The lifetime to test.
* \param id The key id to test.
+ * \param[out] p_drv On output, if \p lifetime designates a key
+ * in an external processor, \c *p_drv is a pointer
+ * to the driver table entry fot this lifetime.
+ * If \p lifetime designates a transparent key,
+ * \c *p_drv is \c NULL.
* \param creating 0 if attempting to open an existing key.
* Nonzero if attempting to create a key.
*
@@ -93,6 +122,7 @@ psa_status_t psa_internal_allocate_key_slot( psa_key_handle_t *handle,
psa_status_t psa_validate_persistent_key_parameters(
psa_key_lifetime_t lifetime,
psa_key_file_id_t id,
+ psa_se_drv_table_entry_t **p_drv,
int creating );
diff --git a/library/psa_crypto_storage.c b/library/psa_crypto_storage.c
index cd36bb9101..b8569beb8a 100644
--- a/library/psa_crypto_storage.c
+++ b/library/psa_crypto_storage.c
@@ -50,6 +50,12 @@
#define mbedtls_free free
#endif
+
+
+/****************************************************************/
+/* Key storage */
+/****************************************************************/
+
/* Determine a file name (ITS file identifier) for the given key file
* identifier. The file name must be distinct from any file that is used
* for a purpose other than storing a key. Currently, the only such file
@@ -221,7 +227,7 @@ static psa_status_t psa_crypto_storage_get_data_length(
* 32-bit integer manipulation macros (little endian)
*/
#ifndef GET_UINT32_LE
-#define GET_UINT32_LE(n,b,i) \
+#define GET_UINT32_LE( n, b, i ) \
{ \
(n) = ( (uint32_t) (b)[(i) ] ) \
| ( (uint32_t) (b)[(i) + 1] << 8 ) \
@@ -231,7 +237,7 @@ static psa_status_t psa_crypto_storage_get_data_length(
#endif
#ifndef PUT_UINT32_LE
-#define PUT_UINT32_LE(n,b,i) \
+#define PUT_UINT32_LE( n, b, i ) \
{ \
(b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \
(b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \
@@ -249,6 +255,7 @@ static psa_status_t psa_crypto_storage_get_data_length(
typedef struct {
uint8_t magic[PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH];
uint8_t version[4];
+ uint8_t lifetime[sizeof( psa_key_lifetime_t )];
uint8_t type[sizeof( psa_key_type_t )];
uint8_t policy[sizeof( psa_key_policy_t )];
uint8_t data_len[4];
@@ -257,20 +264,20 @@ typedef struct {
void psa_format_key_data_for_storage( const uint8_t *data,
const size_t data_length,
- const psa_key_type_t type,
- const psa_key_policy_t *policy,
+ const psa_key_attributes_t *attributes,
uint8_t *storage_data )
{
psa_persistent_key_storage_format *storage_format =
(psa_persistent_key_storage_format *) storage_data;
memcpy( storage_format->magic, PSA_KEY_STORAGE_MAGIC_HEADER, PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH );
- PUT_UINT32_LE(0, storage_format->version, 0);
- PUT_UINT32_LE(type, storage_format->type, 0);
- PUT_UINT32_LE(policy->usage, storage_format->policy, 0);
- PUT_UINT32_LE(policy->alg, storage_format->policy, sizeof( uint32_t ));
- PUT_UINT32_LE(policy->alg2, storage_format->policy, 2 * sizeof( uint32_t ) );
- PUT_UINT32_LE(data_length, storage_format->data_len, 0);
+ PUT_UINT32_LE( 0, storage_format->version, 0 );
+ PUT_UINT32_LE( psa_get_key_lifetime( attributes ), storage_format->lifetime, 0 );
+ PUT_UINT32_LE( psa_get_key_type( attributes ), storage_format->type, 0 );
+ PUT_UINT32_LE( psa_get_key_usage_flags( attributes ), storage_format->policy, 0 );
+ PUT_UINT32_LE( psa_get_key_algorithm( attributes ), storage_format->policy, sizeof( uint32_t ) );
+ PUT_UINT32_LE( psa_get_key_enrollment_algorithm( attributes ), storage_format->policy, 2 * sizeof( uint32_t ) );
+ PUT_UINT32_LE( data_length, storage_format->data_len, 0 );
memcpy( storage_format->key_data, data, data_length );
}
@@ -286,8 +293,7 @@ psa_status_t psa_parse_key_data_from_storage( const uint8_t *storage_data,
size_t storage_data_length,
uint8_t **key_data,
size_t *key_data_length,
- psa_key_type_t *type,
- psa_key_policy_t *policy )
+ psa_key_attributes_t *attributes )
{
psa_status_t status;
const psa_persistent_key_storage_format *storage_format =
@@ -301,11 +307,11 @@ psa_status_t psa_parse_key_data_from_storage( const uint8_t *storage_data,
if( status != PSA_SUCCESS )
return( status );
- GET_UINT32_LE(version, storage_format->version, 0);
+ GET_UINT32_LE( version, storage_format->version, 0 );
if( version != 0 )
return( PSA_ERROR_STORAGE_FAILURE );
- GET_UINT32_LE(*key_data_length, storage_format->data_len, 0);
+ GET_UINT32_LE( *key_data_length, storage_format->data_len, 0 );
if( *key_data_length > ( storage_data_length - sizeof(*storage_format) ) ||
*key_data_length > PSA_CRYPTO_MAX_STORAGE_SIZE )
return( PSA_ERROR_STORAGE_FAILURE );
@@ -322,17 +328,16 @@ psa_status_t psa_parse_key_data_from_storage( const uint8_t *storage_data,
memcpy( *key_data, storage_format->key_data, *key_data_length );
}
- GET_UINT32_LE(*type, storage_format->type, 0);
- GET_UINT32_LE(policy->usage, storage_format->policy, 0);
- GET_UINT32_LE(policy->alg, storage_format->policy, sizeof( uint32_t ));
- GET_UINT32_LE(policy->alg2, storage_format->policy, 2 * sizeof( uint32_t ));
+ GET_UINT32_LE( attributes->lifetime, storage_format->lifetime, 0 );
+ GET_UINT32_LE( attributes->type, storage_format->type, 0 );
+ GET_UINT32_LE( attributes->policy.usage, storage_format->policy, 0 );
+ GET_UINT32_LE( attributes->policy.alg, storage_format->policy, sizeof( uint32_t ) );
+ GET_UINT32_LE( attributes->policy.alg2, storage_format->policy, 2 * sizeof( uint32_t ) );
return( PSA_SUCCESS );
}
-psa_status_t psa_save_persistent_key( const psa_key_file_id_t key,
- const psa_key_type_t type,
- const psa_key_policy_t *policy,
+psa_status_t psa_save_persistent_key( const psa_key_attributes_t *attributes,
const uint8_t *data,
const size_t data_length )
{
@@ -348,10 +353,10 @@ psa_status_t psa_save_persistent_key( const psa_key_file_id_t key,
if( storage_data == NULL )
return( PSA_ERROR_INSUFFICIENT_MEMORY );
- psa_format_key_data_for_storage( data, data_length, type, policy,
+ psa_format_key_data_for_storage( data, data_length, attributes,
storage_data );
- status = psa_crypto_storage_store( key,
+ status = psa_crypto_storage_store( psa_get_key_id( attributes ),
storage_data, storage_data_length );
mbedtls_free( storage_data );
@@ -368,15 +373,14 @@ void psa_free_persistent_key_data( uint8_t *key_data, size_t key_data_length )
mbedtls_free( key_data );
}
-psa_status_t psa_load_persistent_key( psa_key_file_id_t key,
- psa_key_type_t *type,
- psa_key_policy_t *policy,
+psa_status_t psa_load_persistent_key( psa_key_attributes_t *attributes,
uint8_t **data,
size_t *data_length )
{
psa_status_t status = PSA_SUCCESS;
uint8_t *loaded_data;
size_t storage_data_length = 0;
+ psa_key_id_t key = psa_get_key_id( attributes );
status = psa_crypto_storage_get_data_length( key, &storage_data_length );
if( status != PSA_SUCCESS )
@@ -392,13 +396,67 @@ psa_status_t psa_load_persistent_key( psa_key_file_id_t key,
goto exit;
status = psa_parse_key_data_from_storage( loaded_data, storage_data_length,
- data, data_length, type, policy );
+ data, data_length, attributes );
exit:
mbedtls_free( loaded_data );
return( status );
}
+
+
+/****************************************************************/
+/* Transactions */
+/****************************************************************/
+
+#if defined(PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS)
+
+psa_crypto_transaction_t psa_crypto_transaction;
+
+psa_status_t psa_crypto_save_transaction( void )
+{
+ struct psa_storage_info_t p_info;
+ psa_status_t status;
+ status = psa_its_get_info( PSA_CRYPTO_ITS_RANDOM_SEED_UID, &p_info );
+ if( status == PSA_SUCCESS )
+ {
+ /* This shouldn't happen: we're trying to start a transaction while
+ * there is still a transaction that hasn't been replayed. */
+ return( PSA_ERROR_CORRUPTION_DETECTED );
+ }
+ else if( status != PSA_ERROR_DOES_NOT_EXIST )
+ return( status );
+ return( psa_its_set( PSA_CRYPTO_ITS_TRANSACTION_UID,
+ sizeof( psa_crypto_transaction ),
+ &psa_crypto_transaction,
+ 0 ) );
+}
+
+psa_status_t psa_crypto_load_transaction( void )
+{
+ return( psa_its_get( PSA_CRYPTO_ITS_TRANSACTION_UID, 0,
+ sizeof( psa_crypto_transaction ),
+ &psa_crypto_transaction ) );
+}
+
+psa_status_t psa_crypto_stop_transaction( void )
+{
+ psa_status_t status = psa_its_remove( PSA_CRYPTO_ITS_TRANSACTION_UID );
+ /* Whether or not updating the storage succeeded, the transaction is
+ * finished now. It's too late to go back, so zero out the in-memory
+ * data. */
+ memset( &psa_crypto_transaction, 0, sizeof( psa_crypto_transaction ) );
+ return( status );
+}
+
+#endif /* PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS */
+
+
+
+/****************************************************************/
+/* Random generator state */
+/****************************************************************/
+
#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
psa_status_t mbedtls_psa_storage_inject_entropy( const unsigned char *seed,
size_t seed_size )
@@ -421,4 +479,10 @@ psa_status_t mbedtls_psa_storage_inject_entropy( const unsigned char *seed,
}
#endif /* MBEDTLS_PSA_INJECT_ENTROPY */
+
+
+/****************************************************************/
+/* The end */
+/****************************************************************/
+
#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
diff --git a/library/psa_crypto_storage.h b/library/psa_crypto_storage.h
index 2af624a0cf..8fe20ac320 100644
--- a/library/psa_crypto_storage.h
+++ b/library/psa_crypto_storage.h
@@ -29,16 +29,11 @@
extern "C" {
#endif
-/* Include the Mbed TLS configuration file, the way Mbed TLS does it
- * in each of its header files. */
-#if defined(MBEDTLS_CONFIG_FILE)
-#include MBEDTLS_CONFIG_FILE
-#else
-#include "mbedtls/config.h"
-#endif
-
#include "psa/crypto.h"
+#include "psa/crypto_se_driver.h"
+
#include
+#include
/* Limit the maximum key size to 30kB (just in case someone tries to
* inadvertently store an obscene amount of data) */
@@ -88,12 +83,11 @@ int psa_is_key_present_in_storage( const psa_key_file_id_t key );
* already occupied non-persistent key, as well as validating the key data.
*
*
- * \param key Persistent identifier of the key to be stored. This
- * should be an unoccupied storage location.
- * \param type Key type (a \c PSA_KEY_TYPE_XXX value).
- * \param[in] policy The key policy to save.
- * \param[in] data Buffer containing the key data.
- * \param data_length The number of bytes that make up the key data.
+ * \param[in] attributes The attributes of the key to save.
+ * The key identifier field in the attributes
+ * determines the key's location.
+ * \param[in] data Buffer containing the key data.
+ * \param data_length The number of bytes that make up the key data.
*
* \retval PSA_SUCCESS
* \retval PSA_ERROR_INSUFFICIENT_MEMORY
@@ -101,9 +95,7 @@ int psa_is_key_present_in_storage( const psa_key_file_id_t key );
* \retval PSA_ERROR_STORAGE_FAILURE
* \retval PSA_ERROR_ALREADY_EXISTS
*/
-psa_status_t psa_save_persistent_key( const psa_key_file_id_t key,
- const psa_key_type_t type,
- const psa_key_policy_t *policy,
+psa_status_t psa_save_persistent_key( const psa_key_attributes_t *attributes,
const uint8_t *data,
const size_t data_length );
@@ -119,11 +111,11 @@ psa_status_t psa_save_persistent_key( const psa_key_file_id_t key,
* this function to zeroize and free this buffer, regardless of whether this
* function succeeds or fails.
*
- * \param key Persistent identifier of the key to be loaded. This
- * should be an occupied storage location.
- * \param[out] type On success, the key type (a \c PSA_KEY_TYPE_XXX
- * value).
- * \param[out] policy On success, the key's policy.
+ * \param[in,out] attributes
+ * On input, the key identifier field identifies
+ * the key to load. Other fields are ignored.
+ * On success, the attribute structure contains
+ * the key metadata that was loaded from storage.
* \param[out] data Pointer to an allocated key data buffer on return.
* \param[out] data_length The number of bytes that make up the key data.
*
@@ -132,9 +124,7 @@ psa_status_t psa_save_persistent_key( const psa_key_file_id_t key,
* \retval PSA_ERROR_STORAGE_FAILURE
* \retval PSA_ERROR_DOES_NOT_EXIST
*/
-psa_status_t psa_load_persistent_key( psa_key_file_id_t key,
- psa_key_type_t *type,
- psa_key_policy_t *policy,
+psa_status_t psa_load_persistent_key( psa_key_attributes_t *attributes,
uint8_t **data,
size_t *data_length );
@@ -166,17 +156,15 @@ void psa_free_persistent_key_data( uint8_t *key_data, size_t key_data_length );
/**
* \brief Formats key data and metadata for persistent storage
*
- * \param[in] data Buffer for the key data.
+ * \param[in] data Buffer containing the key data.
* \param data_length Length of the key data buffer.
- * \param type Key type (a \c PSA_KEY_TYPE_XXX value).
- * \param policy The key policy.
+ * \param[in] attributes The attributes of the key.
* \param[out] storage_data Output buffer for the formatted data.
*
*/
void psa_format_key_data_for_storage( const uint8_t *data,
const size_t data_length,
- const psa_key_type_t type,
- const psa_key_policy_t *policy,
+ const psa_key_attributes_t *attributes,
uint8_t *storage_data );
/**
@@ -188,8 +176,8 @@ void psa_format_key_data_for_storage( const uint8_t *data,
* containing the key data. This must be freed
* using psa_free_persistent_key_data()
* \param[out] key_data_length Length of the key data buffer
- * \param[out] type Key type (a \c PSA_KEY_TYPE_XXX value).
- * \param[out] policy The key policy.
+ * \param[out] attributes On success, the attribute structure is filled
+ * with the loaded key metadata.
*
* \retval PSA_SUCCESS
* \retval PSA_ERROR_INSUFFICIENT_STORAGE
@@ -200,8 +188,180 @@ psa_status_t psa_parse_key_data_from_storage( const uint8_t *storage_data,
size_t storage_data_length,
uint8_t **key_data,
size_t *key_data_length,
- psa_key_type_t *type,
- psa_key_policy_t *policy );
+ psa_key_attributes_t *attributes );
+
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+/** This symbol is defined if transaction support is required. */
+#define PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS
+#endif
+
+#if defined(PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS)
+
+/** The type of transaction that is in progress.
+ */
+/* This is an integer type rather than an enum for two reasons: to support
+ * unknown values when loading a transaction file, and to ensure that the
+ * type has a known size.
+ */
+typedef uint16_t psa_crypto_transaction_type_t;
+
+/** No transaction is in progress.
+ *
+ * This has the value 0, so zero-initialization sets a transaction's type to
+ * this value.
+ */
+#define PSA_CRYPTO_TRANSACTION_NONE ( (psa_crypto_transaction_type_t) 0x0000 )
+
+/** A key creation transaction.
+ *
+ * This is only used for keys in an external cryptoprocessor (secure element).
+ * Keys in RAM or in internal storage are created atomically in storage
+ * (simple file creation), so they do not need a transaction mechanism.
+ */
+#define PSA_CRYPTO_TRANSACTION_CREATE_KEY ( (psa_crypto_transaction_type_t) 0x0001 )
+
+/** A key destruction transaction.
+ *
+ * This is only used for keys in an external cryptoprocessor (secure element).
+ * Keys in RAM or in internal storage are destroyed atomically in storage
+ * (simple file deletion), so they do not need a transaction mechanism.
+ */
+#define PSA_CRYPTO_TRANSACTION_DESTROY_KEY ( (psa_crypto_transaction_type_t) 0x0002 )
+
+/** Transaction data.
+ *
+ * This type is designed to be serialized by writing the memory representation
+ * and reading it back on the same device.
+ *
+ * \note The transaction mechanism is designed for a single active transaction
+ * at a time. The transaction object is #psa_crypto_transaction.
+ *
+ * \note If an API call starts a transaction, it must complete this transaction
+ * before returning to the application.
+ *
+ * The lifetime of a transaction is the following (note that only one
+ * transaction may be active at a time):
+ *
+ * -# Call psa_crypto_prepare_transaction() to initialize the transaction
+ * object in memory and declare the type of transaction that is starting.
+ * -# Fill in the type-specific fields of #psa_crypto_transaction.
+ * -# Call psa_crypto_save_transaction() to start the transaction. This
+ * saves the transaction data to internal storage.
+ * -# Perform the work of the transaction by modifying files, contacting
+ * external entities, or whatever needs doing. Note that the transaction
+ * may be interrupted by a power failure, so you need to have a way
+ * recover from interruptions either by undoing what has been done
+ * so far or by resuming where you left off.
+ * -# If there are intermediate stages in the transaction, update
+ * the fields of #psa_crypto_transaction and call
+ * psa_crypto_save_transaction() again when each stage is reached.
+ * -# When the transaction is over, call psa_crypto_stop_transaction() to
+ * remove the transaction data in storage and in memory.
+ *
+ * If the system crashes while a transaction is in progress, psa_crypto_init()
+ * calls psa_crypto_load_transaction() and takes care of completing or
+ * rewinding the transaction. This is done in psa_crypto_recover_transaction()
+ * in psa_crypto.c. If you add a new type of transaction, be
+ * sure to add code for it in psa_crypto_recover_transaction().
+ */
+typedef union
+{
+ /* Each element of this union must have the following properties
+ * to facilitate serialization and deserialization:
+ *
+ * - The element is a struct.
+ * - The first field of the struct is `psa_crypto_transaction_type_t type`.
+ * - Elements of the struct are arranged such a way that there is
+ * no padding.
+ */
+ struct psa_crypto_transaction_unknown_s
+ {
+ psa_crypto_transaction_type_t type;
+ uint16_t unused1;
+ uint32_t unused2;
+ uint64_t unused3;
+ uint64_t unused4;
+ } unknown;
+ /* ::type is #PSA_CRYPTO_TRANSACTION_CREATE_KEY or
+ * #PSA_CRYPTO_TRANSACTION_DESTROY_KEY. */
+ struct psa_crypto_transaction_key_s
+ {
+ psa_crypto_transaction_type_t type;
+ uint16_t unused1;
+ psa_key_lifetime_t lifetime;
+ psa_key_slot_number_t slot;
+ psa_key_id_t id;
+ } key;
+} psa_crypto_transaction_t;
+
+/** The single active transaction.
+ */
+extern psa_crypto_transaction_t psa_crypto_transaction;
+
+/** Prepare for a transaction.
+ *
+ * There must not be an ongoing transaction.
+ *
+ * \param type The type of transaction to start.
+ */
+static inline void psa_crypto_prepare_transaction(
+ psa_crypto_transaction_type_t type )
+{
+ psa_crypto_transaction.unknown.type = type;
+}
+
+/** Save the transaction data to storage.
+ *
+ * You may call this function multiple times during a transaction to
+ * atomically update the transaction state.
+ *
+ * \retval #PSA_SUCCESS
+ * \retval #PSA_ERROR_INSUFFICIENT_STORAGE
+ * \retval #PSA_ERROR_STORAGE_FAILURE
+ */
+psa_status_t psa_crypto_save_transaction( void );
+
+/** Load the transaction data from storage, if any.
+ *
+ * This function is meant to be called from psa_crypto_init() to recover
+ * in case a transaction was interrupted by a system crash.
+ *
+ * \retval #PSA_SUCCESS
+ * The data about the ongoing transaction has been loaded to
+ * #psa_crypto_transaction.
+ * \retval #PSA_ERROR_DOES_NOT_EXIST
+ * There is no ongoing transaction.
+ * \retval #PSA_ERROR_STORAGE_FAILURE
+ */
+psa_status_t psa_crypto_load_transaction( void );
+
+/** Indicate that the current transaction is finished.
+ *
+ * Call this function at the very end of transaction processing.
+ * This function does not "commit" or "abort" the transaction: the storage
+ * subsystem has no concept of "commit" and "abort", just saving and
+ * removing the transaction information in storage.
+ *
+ * This function erases the transaction data in storage (if any) and
+ * resets the transaction data in memory.
+ *
+ * \retval #PSA_SUCCESS
+ * There was transaction data in storage.
+ * \retval #PSA_ERROR_DOES_NOT_EXIST
+ * There was no transaction data in storage.
+ * \retval #PSA_ERROR_STORAGE_FAILURE
+ * It was impossible to determine whether there was transaction data
+ * in storage, or the transaction data could not be erased.
+ */
+psa_status_t psa_crypto_stop_transaction( void );
+
+/** The ITS file identifier for the transaction data.
+ *
+ * 0xffffffNN = special file; 0x74 = 't' for transaction.
+ */
+#define PSA_CRYPTO_ITS_TRANSACTION_UID ( (psa_key_id_t) 0xffffff74 )
+
+#endif /* PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS */
#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
/** Backend side of mbedtls_psa_inject_entropy().
diff --git a/scripts/config.pl b/scripts/config.pl
index 05cc52e648..6479c6d53b 100755
--- a/scripts/config.pl
+++ b/scripts/config.pl
@@ -85,6 +85,7 @@ MBEDTLS_NO_PLATFORM_ENTROPY
MBEDTLS_RSA_NO_CRT
MBEDTLS_NO_UDBL_DIVISION
MBEDTLS_NO_64BIT_MULTIPLICATION
+MBEDTLS_PSA_CRYPTO_SE_C
MBEDTLS_PSA_CRYPTO_SPM
MBEDTLS_PSA_CRYPTO_KEY_FILE_ID_ENCODES_OWNER
MBEDTLS_PSA_INJECT_ENTROPY
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index c1e1ffe24b..28225899fc 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -783,6 +783,24 @@ component_test_aes_fewer_tables_and_rom_tables () {
make test
}
+component_test_se_default () {
+ msg "build: default config + MBEDTLS_PSA_CRYPTO_SE_C"
+ scripts/config.pl set MBEDTLS_PSA_CRYPTO_SE_C
+ make CC=clang CFLAGS='-Werror -Wall -Wextra -Wno-unused-function -Os -fsanitize=address' LDFLAGS='-fsanitize=address'
+
+ msg "test: default config + MBEDTLS_PSA_CRYPTO_SE_C"
+ make test
+}
+
+component_test_se_full () {
+ msg "build: full config + MBEDTLS_PSA_CRYPTO_SE_C"
+ scripts/config.pl set MBEDTLS_PSA_CRYPTO_SE_C
+ make CC=gcc CFLAGS='-Werror -Wall -Wextra -O2 -fsanitize=address' LDFLAGS='-fsanitize=address'
+
+ msg "test: full config + MBEDTLS_PSA_CRYPTO_SE_C"
+ make test
+}
+
component_test_make_shared () {
msg "build/test: make shared" # ~ 40s
make SHARED=1 all check
diff --git a/tests/scripts/list-identifiers.sh b/tests/scripts/list-identifiers.sh
index eaf270c7ae..4828c80eb4 100755
--- a/tests/scripts/list-identifiers.sh
+++ b/tests/scripts/list-identifiers.sh
@@ -41,7 +41,7 @@ rm -f identifiers
grep '^[^ /#{]' $HEADERS | \
sed -e 's/^[^:]*://' | \
- egrep -v '^(extern "C"|(typedef )?(struct|enum)( {)?$|};?$)' \
+ egrep -v '^(extern "C"|(typedef )?(struct|union|enum)( {)?$|};?$)' \
> _decls
if true; then
diff --git a/tests/suites/test_suite_psa_crypto_persistent_key.data b/tests/suites/test_suite_psa_crypto_persistent_key.data
index dead13d010..925c0f54a9 100644
--- a/tests/suites/test_suite_psa_crypto_persistent_key.data
+++ b/tests/suites/test_suite_psa_crypto_persistent_key.data
@@ -1,20 +1,20 @@
PSA Storage format data for storage
-format_storage_data_check:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":"505341004b4559000000000000000170010000000000001200000010620200003082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION:PSA_ALG_CATEGORY_SIGN
+format_storage_data_check:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":"505341004b455900000000000100000000000170010000000000001200000010620200003082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_LIFETIME_PERSISTENT:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION:PSA_ALG_CATEGORY_SIGN
PSA Storage parse stored data
-parse_storage_data_check:"505341004b4559000000000000000170010000000000001200000010620200003082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION:PSA_ALG_CATEGORY_SIGN:PSA_SUCCESS
+parse_storage_data_check:"505341004b455900000000000100000000000170010000000000001200000010620200003082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_LIFETIME_PERSISTENT:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION:PSA_ALG_CATEGORY_SIGN:PSA_SUCCESS
PSA Storage parse stored data wrong version, should fail
-parse_storage_data_check:"505341004b455900ffffffff00000170010000000000001200000010620200003082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION:PSA_ALG_CATEGORY_SIGN:PSA_ERROR_STORAGE_FAILURE
+parse_storage_data_check:"505341004b455900ffffffff0100000000000170010000000000001200000010620200003082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_LIFETIME_PERSISTENT:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION:PSA_ALG_CATEGORY_SIGN:PSA_ERROR_STORAGE_FAILURE
PSA Storage parse too big data, should fail
-parse_storage_data_check:"505341004b4559000000000000000170010000000000001200000010ffffffff3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":"":PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION:PSA_ALG_CATEGORY_SIGN:PSA_ERROR_STORAGE_FAILURE
+parse_storage_data_check:"505341004b455900000000000100000000000170010000000000001200000010ffffffff3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":"":PSA_KEY_LIFETIME_PERSISTENT:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION:PSA_ALG_CATEGORY_SIGN:PSA_ERROR_STORAGE_FAILURE
PSA Storage parse bad magic, should fail
-parse_storage_data_check:"645341004b4559000000000000000170010000000000001200000010620200003082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION:PSA_ALG_CATEGORY_SIGN:PSA_ERROR_STORAGE_FAILURE
+parse_storage_data_check:"645341004b455900000000000100000000000170010000000000001200000010620200003082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_LIFETIME_PERSISTENT:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION:PSA_ALG_CATEGORY_SIGN:PSA_ERROR_STORAGE_FAILURE
PSA Storage parse not enough magic, should fail
-parse_storage_data_check:"505341004b4559":"":PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION:PSA_ALG_CATEGORY_SIGN:PSA_ERROR_STORAGE_FAILURE
+parse_storage_data_check:"505341004b4559":"":PSA_KEY_LIFETIME_PERSISTENT:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION:PSA_ALG_CATEGORY_SIGN:PSA_ERROR_STORAGE_FAILURE
# Not specific to files, but only run this test in an environment where the maximum size could be reached.
Save maximum size persistent raw key
diff --git a/tests/suites/test_suite_psa_crypto_persistent_key.function b/tests/suites/test_suite_psa_crypto_persistent_key.function
index fc1924897e..b76c7330ae 100644
--- a/tests/suites/test_suite_psa_crypto_persistent_key.function
+++ b/tests/suites/test_suite_psa_crypto_persistent_key.function
@@ -12,6 +12,7 @@
typedef struct {
uint8_t magic[PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH];
uint8_t version[4];
+ uint8_t lifetime[sizeof( psa_key_lifetime_t )];
uint8_t type[sizeof( psa_key_type_t )];
uint8_t policy[sizeof( psa_key_policy_t )];
uint8_t data_len[4];
@@ -28,21 +29,23 @@ typedef struct {
/* BEGIN_CASE */
void format_storage_data_check( data_t *key_data,
data_t *expected_file_data,
- int key_type,
+ int key_lifetime, int key_type,
int key_usage, int key_alg, int key_alg2 )
{
uint8_t *file_data;
size_t file_data_length;
- psa_key_policy_t key_policy;
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
- key_policy.usage = (psa_key_usage_t) key_usage;
- key_policy.alg = (psa_algorithm_t) key_alg;
- key_policy.alg2 = (psa_algorithm_t) key_alg2;
+ psa_set_key_lifetime( &attributes, key_lifetime );
+ psa_set_key_type( &attributes, key_type );
+ psa_set_key_usage_flags( &attributes, key_usage );
+ psa_set_key_algorithm( &attributes, key_alg );
+ psa_set_key_enrollment_algorithm( &attributes, key_alg2 );
file_data_length = key_data->len + sizeof( psa_persistent_key_storage_format );
file_data = mbedtls_calloc( 1, file_data_length );
psa_format_key_data_for_storage( key_data->x, key_data->len,
- (psa_key_type_t) key_type, &key_policy,
+ &attributes,
file_data );
ASSERT_COMPARE( expected_file_data->x, expected_file_data->len,
@@ -54,6 +57,7 @@ void format_storage_data_check( data_t *key_data,
/* BEGIN_CASE */
void parse_storage_data_check( data_t *file_data,
data_t *expected_key_data,
+ int expected_key_lifetime,
int expected_key_type,
int expected_key_usage,
int expected_key_alg,
@@ -62,22 +66,27 @@ void parse_storage_data_check( data_t *file_data,
{
uint8_t *key_data = NULL;
size_t key_data_length = 0;
- psa_key_type_t key_type = 0;
- psa_key_policy_t key_policy;
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_status_t status;
status = psa_parse_key_data_from_storage( file_data->x, file_data->len,
&key_data, &key_data_length,
- &key_type, &key_policy );
+ &attributes );
TEST_EQUAL( status, expected_status );
if( status != PSA_SUCCESS )
goto exit;
- TEST_EQUAL( key_type, (psa_key_type_t) expected_key_type );
- TEST_EQUAL( key_policy.usage, (uint32_t) expected_key_usage );
- TEST_EQUAL( key_policy.alg, (uint32_t) expected_key_alg );
- TEST_EQUAL( key_policy.alg2, (uint32_t) expected_key_alg2 );
+ TEST_EQUAL( psa_get_key_lifetime( &attributes ),
+ (psa_key_type_t) expected_key_lifetime );
+ TEST_EQUAL( psa_get_key_type( &attributes ),
+ (psa_key_type_t) expected_key_type );
+ TEST_EQUAL( psa_get_key_usage_flags( &attributes ),
+ (uint32_t) expected_key_usage );
+ TEST_EQUAL( psa_get_key_algorithm( &attributes ),
+ (uint32_t) expected_key_alg );
+ TEST_EQUAL( psa_get_key_enrollment_algorithm( &attributes ),
+ (uint32_t) expected_key_alg2 );
ASSERT_COMPARE( expected_key_data->x, expected_key_data->len,
key_data, key_data_length );
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 c04b70d962..6fb65f02a3 100644
--- a/tests/suites/test_suite_psa_crypto_se_driver_hal.data
+++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.data
@@ -26,3 +26,72 @@ register_twice:3
Register SE driver: maximum number of drivers
register_max:
+
+SE key import-export (p_allocate allows all slots)
+key_creation_import_export:0:0
+
+SE key import-export (p_allocate allows 1 slot)
+key_creation_import_export:ARRAY_LENGTH( ram_slots ) - 1:0
+
+SE key import-export, check after restart (slot 0)
+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 smoke test: AES-CBC
+key_creation_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CBC_NO_PADDING:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+Key creation smoke test: AES-CMAC
+key_creation_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+Key creation smoke test: AES-CCM
+key_creation_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+Key creation smoke test: AES-GCM
+key_creation_smoke:PSA_KEY_TYPE_AES:PSA_ALG_GCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+Key creation smoke test: CAMELLIA-CTR
+key_creation_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_CTR:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+Key creation smoke test: CAMELLIA-CBC
+key_creation_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_CBC_NO_PADDING:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+Key creation smoke test: CAMELLIA-CMAC
+key_creation_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_CMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+Key creation smoke test: CAMELLIA-CCM
+key_creation_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_GCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+Key creation smoke test: CAMELLIA-CCM
+key_creation_smoke:PSA_KEY_TYPE_CAMELLIA: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 creation smoke test: HKDF-SHA-256
+key_creation_smoke:PSA_KEY_TYPE_DERIVE:PSA_ALG_HKDF( PSA_ALG_SHA_256 ):"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+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 creation smoke test: RSA PKCS#1v1.5 encryption
+key_creation_smoke:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_ALG_RSA_PKCS1V15_CRYPT:"30818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001"
+
+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 creation smoke test: ECDSA secp256r1
+key_creation_smoke:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee"
+
+Key creation smoke test: ECDH secp256r1
+key_creation_smoke:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDH:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee"
+
+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"
+
+Generate key: not supported
+generate_key_not_supported:PSA_KEY_TYPE_AES:128
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 b9d0a1f0a8..e0b8d29a57 100644
--- a/tests/suites/test_suite_psa_crypto_se_driver_hal.function
+++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.function
@@ -3,10 +3,328 @@
#include "psa/crypto_se_driver.h"
#include "psa_crypto_se.h"
+#include "psa_crypto_storage.h"
-/* The minimum valid lifetime value for a secure element driver. */
+
+
+/****************************************************************/
+/* Test driver helpers */
+/****************************************************************/
+
+/** The minimum valid lifetime value for a secure element driver. */
#define MIN_DRIVER_LIFETIME 2
+/** The driver detected a condition that shouldn't happen.
+ * 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.
+ *
+ * Use this macro to assert on guarantees provided by the core.
+ */
+#define DRIVER_ASSERT( TEST ) \
+ do { \
+ if( ! (TEST) ) \
+ { \
+ test_fail( #TEST, __LINE__, __FILE__ ); \
+ return( PSA_ERROR_DETECTED_BY_DRIVER ); \
+ } \
+ } while( 0 )
+
+
+
+/****************************************************************/
+/* Miscellaneous driver methods */
+/****************************************************************/
+
+/* 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_slot_number_t *slot_number )
+{
+ psa_key_slot_number_t *p_counter = persistent_data;
+ (void) attributes;
+ if( context->persistent_data_size != sizeof( psa_key_slot_number_t ) )
+ return( PSA_ERROR_DETECTED_BY_DRIVER );
+ ++*p_counter;
+ if( *p_counter == 0 )
+ return( PSA_ERROR_INSUFFICIENT_STORAGE );
+ *slot_number = *p_counter;
+ return( PSA_SUCCESS );
+}
+
+/* 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,
+ size_t data_length )
+{
+ (void) context;
+ (void) slot_number;
+ (void) lifetime;
+ (void) type;
+ (void) algorithm;
+ (void) usage;
+ (void) p_data;
+ (void) data_length;
+ return( PSA_SUCCESS );
+}
+
+
+
+/****************************************************************/
+/* RAM-based test driver */
+/****************************************************************/
+
+#define RAM_MAX_KEY_SIZE 64
+typedef struct
+{
+ psa_key_lifetime_t lifetime;
+ psa_key_type_t type;
+ size_t bits;
+ uint8_t content[RAM_MAX_KEY_SIZE];
+} ram_slot_t;
+static ram_slot_t ram_slots[16];
+
+/* A type with at least ARRAY_LENGTH(ram_slots) bits, containing a
+ * bit vector indicating which slots are in use. */
+typedef uint16_t ram_slot_usage_t;
+
+static uint8_t ram_min_slot = 0;
+
+static void ram_slots_reset( void )
+{
+ memset( ram_slots, 0, sizeof( ram_slots ) );
+ ram_min_slot = 0;
+}
+
+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,
+ size_t data_length )
+{
+ (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 );
+ (void) algorithm;
+ (void) usage;
+ memcpy( ram_slots[slot_number].content, p_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,
+ size_t data_size,
+ size_t *p_data_length )
+{
+ size_t actual_size;
+ (void) context;
+ DRIVER_ASSERT( 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 );
+ return( PSA_SUCCESS );
+}
+
+static psa_status_t ram_destroy( psa_drv_se_context_t *context,
+ void *persistent_data,
+ 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 ) );
+ memset( &ram_slots[slot_number], 0, sizeof( ram_slots[slot_number] ) );
+ *slot_usage &= ~(ram_slot_usage_t)( 1 << slot_number );
+ return( PSA_SUCCESS );
+}
+
+static psa_status_t ram_allocate( psa_drv_se_context_t *context,
+ void *persistent_data,
+ const psa_key_attributes_t *attributes,
+ 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 ) );
+ for( *slot_number = ram_min_slot;
+ *slot_number < ARRAY_LENGTH( ram_slots );
+ ++( *slot_number ) )
+ {
+ if( ! ( *slot_usage & 1 << *slot_number ) )
+ return( PSA_SUCCESS );
+ }
+ return( PSA_ERROR_INSUFFICIENT_STORAGE );
+}
+
+
+
+/****************************************************************/
+/* Other test helper functions */
+/****************************************************************/
+
+/* Check that a function's return status is "smoke-free", i.e. that
+ * it's an acceptable error code when calling an API function that operates
+ * on a key with potentially bogus parameters. */
+static int is_status_smoke_free( psa_status_t status )
+{
+ switch( status )
+ {
+ case PSA_SUCCESS:
+ case PSA_ERROR_NOT_SUPPORTED:
+ case PSA_ERROR_NOT_PERMITTED:
+ case PSA_ERROR_BUFFER_TOO_SMALL:
+ case PSA_ERROR_INVALID_ARGUMENT:
+ case PSA_ERROR_INVALID_SIGNATURE:
+ case PSA_ERROR_INVALID_PADDING:
+ return( 1 );
+ default:
+ return( 0 );
+ }
+}
+#define SMOKE_ASSERT( expr ) \
+ TEST_ASSERT( is_status_smoke_free( expr ) )
+
+/* Smoke test a key. There are mostly no wrong answers here since we pass
+ * mostly bogus parameters: the goal is to ensure that there is no memory
+ * corruption or crash. This test function is most useful when run under
+ * an environment with sanity checks such as ASan or MSan. */
+static int smoke_test_key( psa_key_handle_t handle )
+{
+ int ok = 0;
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ psa_mac_operation_t mac_operation = PSA_MAC_OPERATION_INIT;
+ psa_cipher_operation_t cipher_operation = PSA_CIPHER_OPERATION_INIT;
+ psa_key_derivation_operation_t derivation_operation =
+ PSA_KEY_DERIVATION_OPERATION_INIT;
+ uint8_t buffer[80]; /* large enough for a public key for ECDH */
+ size_t length;
+ psa_key_handle_t handle2 = 0;
+
+ SMOKE_ASSERT( psa_get_key_attributes( handle, &attributes ) );
+
+ SMOKE_ASSERT( psa_export_key( handle,
+ buffer, sizeof( buffer ), &length ) );
+ SMOKE_ASSERT( psa_export_public_key( handle,
+ buffer, sizeof( buffer ), &length ) );
+
+ SMOKE_ASSERT( psa_copy_key( handle, &attributes, &handle2 ) );
+ if( handle2 != 0 )
+ PSA_ASSERT( psa_close_key( handle2 ) );
+
+ SMOKE_ASSERT( psa_mac_sign_setup( &mac_operation, handle, PSA_ALG_CMAC ) );
+ PSA_ASSERT( psa_mac_abort( &mac_operation ) );
+ SMOKE_ASSERT( psa_mac_verify_setup( &mac_operation, handle,
+ PSA_ALG_HMAC( PSA_ALG_SHA_256 ) ) );
+ PSA_ASSERT( psa_mac_abort( &mac_operation ) );
+
+ SMOKE_ASSERT( psa_cipher_encrypt_setup( &cipher_operation, handle,
+ PSA_ALG_CTR ) );
+ PSA_ASSERT( psa_cipher_abort( &cipher_operation ) );
+ SMOKE_ASSERT( psa_cipher_decrypt_setup( &cipher_operation, handle,
+ PSA_ALG_CTR ) );
+ PSA_ASSERT( psa_cipher_abort( &cipher_operation ) );
+
+ SMOKE_ASSERT( psa_aead_encrypt( handle, PSA_ALG_CCM,
+ buffer, sizeof( buffer ),
+ NULL, 0,
+ buffer, sizeof( buffer),
+ buffer, sizeof( buffer), &length ) );
+ SMOKE_ASSERT( psa_aead_decrypt( handle, PSA_ALG_CCM,
+ buffer, sizeof( buffer ),
+ NULL, 0,
+ buffer, sizeof( buffer),
+ buffer, sizeof( buffer), &length ) );
+
+ SMOKE_ASSERT( psa_asymmetric_sign( handle, PSA_ALG_ECDSA_ANY,
+ buffer, 32,
+ buffer, sizeof( buffer ), &length ) );
+ SMOKE_ASSERT( psa_asymmetric_verify( handle, PSA_ALG_ECDSA_ANY,
+ buffer, 32,
+ buffer, sizeof( buffer ) ) );
+
+ SMOKE_ASSERT( psa_asymmetric_encrypt( handle, PSA_ALG_RSA_PKCS1V15_CRYPT,
+ buffer, 10, NULL, 0,
+ buffer, sizeof( buffer ), &length ) );
+ SMOKE_ASSERT( psa_asymmetric_decrypt( handle, PSA_ALG_RSA_PKCS1V15_CRYPT,
+ buffer, sizeof( buffer ), NULL, 0,
+ buffer, sizeof( buffer ), &length ) );
+
+#if defined(MBEDTLS_SHA256_C)
+ /* Try the key in a plain key derivation. */
+ PSA_ASSERT( psa_key_derivation_setup( &derivation_operation,
+ PSA_ALG_HKDF( PSA_ALG_SHA_256 ) ) );
+ PSA_ASSERT( psa_key_derivation_input_bytes( &derivation_operation,
+ PSA_KEY_DERIVATION_INPUT_SALT,
+ NULL, 0 ) );
+ SMOKE_ASSERT( psa_key_derivation_input_key( &derivation_operation,
+ PSA_KEY_DERIVATION_INPUT_SECRET,
+ handle ) );
+ PSA_ASSERT( psa_key_derivation_abort( &derivation_operation ) );
+
+ /* If the key is asymmetric, try it in a key agreement, both as
+ * part of a derivation operation and standalone. */
+ if( psa_export_public_key( handle, buffer, sizeof( buffer ), &length ) ==
+ PSA_SUCCESS )
+ {
+ psa_algorithm_t alg =
+ PSA_ALG_KEY_AGREEMENT( PSA_ALG_ECDH,
+ PSA_ALG_HKDF( PSA_ALG_SHA_256 ) );
+ PSA_ASSERT( psa_key_derivation_setup( &derivation_operation, alg ) );
+ PSA_ASSERT( psa_key_derivation_input_bytes(
+ &derivation_operation, PSA_KEY_DERIVATION_INPUT_SALT,
+ NULL, 0 ) );
+ SMOKE_ASSERT( psa_key_derivation_key_agreement(
+ &derivation_operation,
+ PSA_KEY_DERIVATION_INPUT_SECRET,
+ handle, buffer, length ) );
+ PSA_ASSERT( psa_key_derivation_abort( &derivation_operation ) );
+
+ SMOKE_ASSERT( psa_raw_key_agreement(
+ alg, handle, buffer, length,
+ buffer, sizeof( buffer ), &length ) );
+ }
+#endif /* MBEDTLS_SHA256_C */
+
+ ok = 1;
+
+exit:
+ psa_reset_key_attributes( &attributes );
+ return( ok );
+}
+
+#define MAX_KEY_ID_FOR_TEST 10
+static void psa_purge_storage( void )
+{
+ psa_key_id_t id;
+ psa_key_lifetime_t lifetime;
+ /* The tests may have potentially created key ids from 1 to
+ * MAX_KEY_ID_FOR_TEST. In addition, run the destroy function on key id
+ * 0, which file-based storage uses as a temporary file. */
+ for( id = 0; id <= MAX_KEY_ID_FOR_TEST; id++ )
+ psa_destroy_persistent_key( id );
+ /* Purge the transaction file. */
+ psa_crypto_stop_transaction( );
+ /* Purge driver persistent data. */
+ for( lifetime = 0; lifetime < PSA_MAX_SE_LIFETIME; lifetime++ )
+ psa_destroy_se_persistent_data( lifetime );
+}
+
/* END_HEADER */
/* BEGIN_DEPENDENCIES
@@ -78,3 +396,164 @@ exit:
PSA_DONE( );
}
/* END_CASE */
+
+/* BEGIN_CASE */
+void key_creation_import_export( int min_slot, int restart )
+{
+ 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};
+ uint8_t exported[sizeof( key_material )];
+ size_t exported_length;
+
+ 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_allocate = ram_allocate;
+ key_management.p_import = ram_import;
+ key_management.p_destroy = ram_destroy;
+ key_management.p_export = ram_export;
+ ram_min_slot = min_slot;
+
+ 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_ASSERT( psa_import_key( &attributes,
+ key_material, sizeof( key_material ),
+ &handle ) );
+
+ /* 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_ASSERT( ram_slots[min_slot].type == PSA_KEY_TYPE_RAW_DATA );
+
+ PSA_ASSERT( psa_export_key( handle,
+ exported, sizeof( exported ),
+ &exported_length ) );
+ ASSERT_COMPARE( key_material, sizeof( key_material ),
+ exported, exported_length );
+
+ PSA_ASSERT( psa_destroy_key( handle ) );
+
+ /* Test that the key has been erased from the designated slot. */
+ TEST_ASSERT( ram_slots[min_slot].type == 0 );
+
+exit:
+ PSA_DONE( );
+ ram_slots_reset( );
+ psa_purge_storage( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void key_creation_smoke( int type_arg, int alg_arg,
+ data_t *key_material )
+{
+ psa_key_type_t type = type_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_import = null_import;
+
+ 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_ASSERT( psa_import_key( &attributes,
+ key_material->x, key_material->len,
+ &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 ) );
+
+exit:
+ PSA_DONE( );
+ ram_slots_reset( );
+ psa_purge_storage( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void generate_key_not_supported( int type_arg, int bits_arg )
+{
+ psa_key_type_t type = type_arg;
+ size_t bits = bits_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;
+
+ PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) );
+ PSA_ASSERT( psa_crypto_init( ) );
+
+ psa_set_key_id( &attributes, id );
+ psa_set_key_lifetime( &attributes, lifetime );
+ psa_set_key_type( &attributes, type );
+ psa_set_key_bits( &attributes, bits );
+ TEST_EQUAL( psa_generate_key( &attributes, &handle ),
+ PSA_ERROR_NOT_SUPPORTED );
+
+exit:
+ PSA_DONE( );
+ ram_slots_reset( );
+ psa_purge_storage( );
+}
+/* END_CASE */