diff --git a/tests/include/test/psa_test_wrappers.h b/tests/include/test/psa_test_wrappers.h index 5ef1226c8..3fd4b32cd 100644 --- a/tests/include/test/psa_test_wrappers.h +++ b/tests/include/test/psa_test_wrappers.h @@ -363,6 +363,23 @@ psa_status_t mbedtls_test_wrap_psa_generate_key_custom( #define psa_generate_key_custom(arg0_attributes, arg1_custom, arg2_custom_data, arg3_custom_data_length, arg4_key) \ mbedtls_test_wrap_psa_generate_key_custom(arg0_attributes, arg1_custom, arg2_custom_data, arg3_custom_data_length, arg4_key) +psa_status_t mbedtls_test_wrap_psa_generate_key_iop_abort( + psa_generate_key_iop_t *arg0_operation); +#define psa_generate_key_iop_abort(arg0_operation) \ + mbedtls_test_wrap_psa_generate_key_iop_abort(arg0_operation) + +psa_status_t mbedtls_test_wrap_psa_generate_key_iop_complete( + psa_generate_key_iop_t *arg0_operation, + psa_key_id_t *arg1_key); +#define psa_generate_key_iop_complete(arg0_operation, arg1_key) \ + mbedtls_test_wrap_psa_generate_key_iop_complete(arg0_operation, arg1_key) + +psa_status_t mbedtls_test_wrap_psa_generate_key_iop_setup( + psa_generate_key_iop_t *arg0_operation, + const psa_key_attributes_t *arg1_attributes); +#define psa_generate_key_iop_setup(arg0_operation, arg1_attributes) \ + mbedtls_test_wrap_psa_generate_key_iop_setup(arg0_operation, arg1_attributes) + psa_status_t mbedtls_test_wrap_psa_generate_random( uint8_t *arg0_output, size_t arg1_output_size); diff --git a/tests/src/psa_test_wrappers.c b/tests/src/psa_test_wrappers.c index 8557590d7..8484b25d2 100644 --- a/tests/src/psa_test_wrappers.c +++ b/tests/src/psa_test_wrappers.c @@ -622,6 +622,32 @@ psa_status_t mbedtls_test_wrap_psa_generate_key_custom( return status; } +/* Wrapper for psa_generate_key_iop_abort */ +psa_status_t mbedtls_test_wrap_psa_generate_key_iop_abort( + psa_generate_key_iop_t *arg0_operation) +{ + psa_status_t status = (psa_generate_key_iop_abort)(arg0_operation); + return status; +} + +/* Wrapper for psa_generate_key_iop_complete */ +psa_status_t mbedtls_test_wrap_psa_generate_key_iop_complete( + psa_generate_key_iop_t *arg0_operation, + psa_key_id_t *arg1_key) +{ + psa_status_t status = (psa_generate_key_iop_complete)(arg0_operation, arg1_key); + return status; +} + +/* Wrapper for psa_generate_key_iop_setup */ +psa_status_t mbedtls_test_wrap_psa_generate_key_iop_setup( + psa_generate_key_iop_t *arg0_operation, + const psa_key_attributes_t *arg1_attributes) +{ + psa_status_t status = (psa_generate_key_iop_setup)(arg0_operation, arg1_attributes); + return status; +} + /* Wrapper for psa_generate_random */ psa_status_t mbedtls_test_wrap_psa_generate_random( uint8_t *arg0_output, diff --git a/tf-psa-crypto/core/psa_crypto_ecp.c b/tf-psa-crypto/core/psa_crypto_ecp.c index 096bc116b..749e11be0 100644 --- a/tf-psa-crypto/core/psa_crypto_ecp.c +++ b/tf-psa-crypto/core/psa_crypto_ecp.c @@ -592,6 +592,45 @@ exit: } #endif /* MBEDTLS_PSA_BUILTIN_ALG_ECDH */ +/****************************************************************/ +/* Interruptible ECC Key Generation */ +/****************************************************************/ + +uint32_t psa_generate_key_iop_get_num_ops( + psa_generate_key_iop_t *operation) +{ + (void) operation; + return 0; +} + +psa_status_t psa_generate_key_iop_setup( + psa_generate_key_iop_t *operation, + const psa_key_attributes_t *attributes) +{ + (void) operation; + (void) attributes; + + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_generate_key_iop_complete( + psa_generate_key_iop_t *operation, + psa_key_id_t *key) +{ + (void) operation; + (void) key; + + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_generate_key_iop_abort( + psa_generate_key_iop_t *operation) +{ + (void) operation; + + return PSA_ERROR_NOT_SUPPORTED; +} + /****************************************************************/ /* Interruptible ECC Key Agreement */ /****************************************************************/ @@ -638,4 +677,5 @@ psa_status_t psa_key_agreement_iop_abort( return PSA_SUCCESS; } + #endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/tf-psa-crypto/include/psa/crypto.h b/tf-psa-crypto/include/psa/crypto.h index 6f0049bc6..77b740791 100644 --- a/tf-psa-crypto/include/psa/crypto.h +++ b/tf-psa-crypto/include/psa/crypto.h @@ -5168,6 +5168,299 @@ psa_status_t psa_key_agreement_iop_abort( /**@}*/ +/** + * \defgroup interruptible_generate_key Interruptible Key Generation + * @{ + */ + +/** + * The type of the state data structure for interruptible key generation + * operations. + * + * Before calling any function on an interruptible key generation object, the + * application must initialize it by any of the following means: + * - Set the structure to all-bits-zero, for example: + * \code + * psa_generate_key_iop_t operation; + * memset(&operation, 0, sizeof(operation)); + * \endcode + * - Initialize the structure to logical zero values, for example: + * \code + * psa_generate_key_iop_t operation = {0}; + * \endcode + * - Initialize the structure to the initializer #PSA_GENERATE_KEY_IOP_INIT, + * for example: + * - \code + * psa_generate_key_iop_t operation = PSA_GENERATE_KEY_IOP_INIT; + * \endcode + * - Assign the result of the function psa_generate_key_iop_init() to the + * structure, for example: + * \code + * psa_generate_key_iop_t operation; + * operation = psa_generate_key_iop_init(); + * \endcode + * + * This is an implementation-defined \c struct. Applications should not + * make any assumptions about the content of this structure. + * Implementation details can change in future versions without notice. + */ +typedef struct psa_generate_key_iop_s psa_generate_key_iop_t; + +/** + * \brief Get the number of ops that a key generation + * operation has taken so far. If the operation has + * completed, then this will represent the number + * of ops required for the entire operation. After + * initialization or calling \c + * psa_generate_key_iop_abort() on the operation, + * a value of 0 will be returned. + * + * \warning This is a beta API, and thus subject to change + * at any point. It is not bound by the usual + * interface stability promises. + * + * This is a helper provided to help you tune the + * value passed to \c + * psa_interruptible_set_max_ops(). + * + * \param operation The \c psa_generate_key_iop_t to use. This must + * be initialized first. + * + * \return Number of ops that the operation has taken so + * far. + */ +uint32_t psa_generate_key_iop_get_num_ops(psa_generate_key_iop_t *operation); + +/** + * \brief Start a key generation operation, in an + * interruptible manner. + * + * \see \c psa_generate_key_iop_complete() + * + * \warning This is a beta API, and thus subject to change + * at any point. It is not bound by the usual + * interface stability promises. + * + * \note This function combined with \c + * psa_generate_key_iop_complete() is equivalent + * to \c psa_generate_key() but \c + * psa_generate_key_iop_complete() can return + * early and resume according to the limit set with + * \c psa_interruptible_set_max_ops() to reduce the + * maximum time spent in a function. + * + * \note Users should call + * \c psa_generate_key_iop_complete() repeatedly + * on the same operation object after a successful + * call to this function until \c + * psa_generate_key_iop_complete() either returns + * #PSA_SUCCESS or an error. + * \c psa_generate_key_iop_complete() will return + * #PSA_OPERATION_INCOMPLETE if there is more work + * to do. Alternatively users can call + * \c psa_generate_key_iop_abort() at any point + * if they no longer want the result. + * + * \note This function clears the number of ops completed + * as part of the operation. Please ensure you copy + * this value via + * \c psa_generate_key_iop_get_num_ops() if + * required before calling. + * + * \note If this function returns an error status, the + * operation enters an error state and must be + * aborted by calling \c + * psa_generate_key_iop_abort(). + * + * \note Only asymmetric key pairs are supported. (See \p attributes.) + * + * \param[in, out] operation The \c psa_generate_key_iop_t to use. + * This must be initialized as per the + * documentation for + * \c psa_generate_key_iop_t, and be inactive. + * + * \param[in] attributes The attributes for the new key. + * The following attributes are required for all + * keys: + * * The key type. It must be an asymmetric key-pair. + * * The key size. It must be a valid size for the + * key type. + * The following attributes must be set for keys + * used in cryptographic operations: + * * The key permitted-algorithm policy. + * * The key usage flags. + * The following attributes must be set for keys + * that do not use the default volatile lifetime: + * * The key lifetime. + * * The key identifier is required for a key with + * a persistent lifetime, + * + * \note \p attributes is an input parameter, it is not + * updated with the final key attributes. The final + * attributes of the new key can be queried by + * calling `psa_get_key_attributes()` with + * the key's identifier. + * + * \retval #PSA_SUCCESS + * The operation started successfully. + * Call \c psa_generate_key_iop_complete() with the same context to + * complete the operation. + * + * \retval PSA_ERROR_ALREADY_EXISTS + * This is an attempt to create a persistent key, and there is already + * a persistent key with the given identifier + * \retval PSA_ERROR_NOT_SUPPORTED + * The key attributes, as a whole, are not supported, either in general + * or in the specified storage location. + * \retval PSA_ERROR_INVALID_ARGUMENT + * The following conditions can result in this error: + * * The key type is invalid, or is an asymmetric public key type. + * * The key size is not valid for the key type. + * * The key lifetime is invalid. + * * The key identifier is not valid for the key lifetime. + * * The key usage flags include invalid values. + * * The key's permitted-usage algorithm is invalid. + * * The key attributes, as a whole, are invalid. + * \retval PSA_ERROR_NOT_PERMITTED + * Creating a key with the specified attributes is not permitted. + * + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription + * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription + * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription + * \retval #PSA_ERROR_DATA_INVALID \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_STORAGE \emptydescription + * \retval #PSA_ERROR_BAD_STATE + * The following conditions can result in this error: + * * The library has not been previously initialized by + * \c psa_crypto_init(). + * * The operation state is not valid: it must be inactive. + */ + +psa_status_t psa_generate_key_iop_setup( + psa_generate_key_iop_t *operation, + const psa_key_attributes_t *attributes); + +/** + * \brief Continue and eventually complete the action of + * key generation, in an interruptible + * manner. + * + * \see \c psa_generate_key_iop_setup() + * + * \warning This is a beta API, and thus subject to change + * at any point. It is not bound by the usual + * interface stability promises. + * + * \note This function combined with \c + * psa_generate_key_iop_setup() is equivalent to + * \c psa_generate_key() but this + * function can return early and resume according + * to the limit set with \c + * psa_interruptible_set_max_ops() to reduce the + * maximum time spent in a function call. + * + * \note Users should call this function on the same + * operation object repeatedly whilst it returns + * #PSA_OPERATION_INCOMPLETE, stopping when it + * returns either #PSA_SUCCESS or an error. + * Alternatively users can call + * \c psa_generate_key_iop_abort() at any + * point if they no longer want the result. + * + * \note When this function returns successfully, the + * operation becomes inactive. If this function + * returns an error status, the operation enters an + * error state and must be aborted by calling + * \c psa_generate_key_iop_abort(). + * + * \param[in, out] operation The \c psa_generate_key_iop_t to use. + * This must be initialized first, and have had \c + * psa_generate_key_iop_setup() called + * with it first. + * + * \param[out] key On success, an identifier for the newly created + * key, on failure this will be set to + * #PSA_KEY_ID_NULL. + * + * \retval #PSA_SUCCESS + * The operation is complete and \p key contains the new key. + * If the key is persistent, the key material and the key's metadata + * have been saved to persistent storage. + * + * \retval #PSA_OPERATION_INCOMPLETE + * Operation was interrupted due to the setting of \c + * psa_interruptible_set_max_ops(). There is still work to be done. + * Call this function again with the same operation object. + * + * \retval #PSA_ERROR_ALREADY_EXISTS + * This is an attempt to create a persistent key, and there is already a + * persistent key with the given identifier. + * + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription + * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription + * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription + * \retval #PSA_ERROR_DATA_INVALID \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY \emptydescription + * \retval #PSA_ERROR_BAD_STATE + * The following conditions can result in this error: + * * The library has not been previously initialized by + * \c psa_crypto_init(). + * * The operation state is not valid: it must be inactive. + */ +psa_status_t psa_generate_key_iop_complete( + psa_generate_key_iop_t *operation, + psa_key_id_t *key); + +/** + * \brief Abort a key generation operation. + * + * \warning This is a beta API, and thus subject to change + * at any point. It is not bound by the usual + * interface stability promises. + * + * \note This function clears the number of ops completed + * as part of the operation. Please ensure you copy + * this value via + * \c psa_generate_key_iop_get_num_ops() if + * required before calling. + * + * \note Aborting an operation frees all + * associated resources except for the operation + * structure itself. Once aborted, the operation + * object can be reused for another operation by + * calling \c psa_generate_key_iop_setup() again. + * + * \note You may call this function any time after the + * operation object has been initialized. + * In particular, calling \c + * psa_generate_key_iop_abort() after the + * operation has already been terminated by a call + * to \c psa_generate_key_iop_abort() or + * psa_generate_key_iop_complete() is safe. + * + * \param[in,out] operation The \c psa_key_agreement_iop_t to use + * + * \retval #PSA_SUCCESS + * The operation was aborted successfully. + * + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by + * \c psa_crypto_init(). + */ +psa_status_t psa_generate_key_iop_abort( + psa_generate_key_iop_t *operation); + +/**@}*/ + #ifdef __cplusplus } #endif diff --git a/tf-psa-crypto/include/psa/crypto_struct.h b/tf-psa-crypto/include/psa/crypto_struct.h index 9685eae20..2eec94811 100644 --- a/tf-psa-crypto/include/psa/crypto_struct.h +++ b/tf-psa-crypto/include/psa/crypto_struct.h @@ -526,6 +526,40 @@ psa_key_agreement_iop_init(void) return v; } +/** + * \brief The context for PSA interruptible key agreement. + */ +struct psa_generate_key_iop_s { +#if defined(MBEDTLS_PSA_CRYPTO_CLIENT) && !defined(MBEDTLS_PSA_CRYPTO_C) + mbedtls_psa_client_handle_t handle; +#else + /** + * Unique ID indicating which driver got assigned to do the + * operation. Since driver contexts are driver-specific, swapping + * drivers halfway through the operation is not supported. + * ID values are auto-generated in psa_crypto_driver_wrappers.h + * ID value zero means the context is not valid or not assigned to + * any driver (i.e. none of the driver contexts are active). + */ + unsigned int MBEDTLS_PRIVATE(id); + +#endif +}; + +#if defined(MBEDTLS_PSA_CRYPTO_CLIENT) && !defined(MBEDTLS_PSA_CRYPTO_C) +#define PSA_GENERATE_KEY_IOP_INIT { 0 } +#else +#define PSA_GENERATE_KEY_IOP_INIT { 0 } +#endif + +static inline struct psa_generate_key_iop_s +psa_generate_key_iop_init(void) +{ + const struct psa_generate_key_iop_s v = PSA_GENERATE_KEY_IOP_INIT; + + return v; +} + #ifdef __cplusplus } #endif