diff --git a/doc/doxygen/src/riot-psa-structure.svg b/doc/doxygen/src/riot-psa-structure.svg new file mode 100644 index 0000000000..ef2b814cd3 --- /dev/null +++ b/doc/doxygen/src/riot-psa-structure.svg @@ -0,0 +1,851 @@ + + + + RIOT's GNRC Network Stack + + + + image/svg+xml + + RIOT's GNRC Network Stack + + + + Cenk Gündoğan + + + Martine Lenders + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PSA Crypto + + + + Key Management and Location Dispatch + + + + Algorithm Dispatch + + + + Spec. Algorithm API + + + + SE Dispatch + + + + SE API + + + + SE API + + + + SE API + + + SE1 Drv + + SE2 Drv + + SE3 Drv + + HW Drv + + SW Library + + diff --git a/makefiles/dependency_resolution.inc.mk b/makefiles/dependency_resolution.inc.mk index ecea9e1086..274c96c1a2 100644 --- a/makefiles/dependency_resolution.inc.mk +++ b/makefiles/dependency_resolution.inc.mk @@ -93,4 +93,12 @@ else "don't run this on public networks!$(COLOR_RESET)" 1>&2) endif endif + + # Warn about PSA Crypto + ifneq (,$(filter psa_crypto,$(USEMODULE))) + $(shell $(COLOR_ECHO) "$(COLOR_YELLOW) You are going to use the PSA Crypto module,"\ + "which is only partly implemented and not yet thouroughly tested.\n"\ + "Please do not use this module in production, as it may introduce"\ + "security issues!$(COLOR_RESET)" 1>&2) + endif endif diff --git a/sys/Kconfig b/sys/Kconfig index fc11536036..97ed70068a 100644 --- a/sys/Kconfig +++ b/sys/Kconfig @@ -93,6 +93,7 @@ rsource "posix/Kconfig" rsource "preprocessor/Kconfig" rsource "progress_bar/Kconfig" rsource "ps/Kconfig" +rsource "psa_crypto/Kconfig" rsource "random/Kconfig" rsource "rtc_utils/Kconfig" rsource "rust_riotmodules/Kconfig" diff --git a/sys/Makefile b/sys/Makefile index de159e8680..835383e8b9 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -173,6 +173,9 @@ endif ifneq (,$(filter posix_sleep,$(USEMODULE))) DIRS += posix/sleep endif +ifneq (,$(filter psa_crypto,$(USEMODULE))) + DIRS += psa_crypto +endif ifneq (,$(filter pthread,$(USEMODULE))) DIRS += posix/pthread endif diff --git a/sys/Makefile.dep b/sys/Makefile.dep index 783df5777e..8a7771accc 100644 --- a/sys/Makefile.dep +++ b/sys/Makefile.dep @@ -686,6 +686,14 @@ ifneq (,$(filter fido2_ctap%,$(USEMODULE))) USEMODULE += fido2 endif +ifneq (,$(filter psa_crypto,$(USEMODULE))) + include $(RIOTBASE)/sys/psa_crypto/Makefile.dep +endif + +ifneq (,$(filter psa_riot_cipher_aes_%,$(USEMODULE))) + USEMODULE += psa_riot_cipher_aes_common +endif + ifneq (,$(filter rust_riotmodules,$(USEMODULE))) include $(RIOTBASE)/sys/rust_riotmodules/Makefile.dep endif diff --git a/sys/Makefile.include b/sys/Makefile.include index b2d5ac2c27..450b3fe401 100644 --- a/sys/Makefile.include +++ b/sys/Makefile.include @@ -163,6 +163,10 @@ ifneq (,$(filter prng,$(USEMODULE))) include $(RIOTBASE)/sys/random/Makefile.include endif +ifneq (,$(filter psa_crypto,$(USEMODULE))) + include $(RIOTBASE)/sys/psa_crypto/Makefile.include +endif + ifneq (,$(filter test_utils_netdev_eth_minimal,$(USEMODULE))) CFLAGS += -DCONFIG_NETDEV_REGISTER_SIGNAL endif diff --git a/sys/include/psa_crypto/psa/crypto.h b/sys/include/psa_crypto/psa/crypto.h new file mode 100644 index 0000000000..19f8fe718e --- /dev/null +++ b/sys/include/psa_crypto/psa/crypto.h @@ -0,0 +1,4053 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @{ + * + * @file crypto.h + * @brief Function declarations for PSA Crypto + * + * @author Lena Boeckmann + * + * @see https://armmbed.github.io/mbed-crypto/html/index.html + * + */ + +#ifndef PSA_CRYPTO_PSA_CRYPTO_H +#define PSA_CRYPTO_PSA_CRYPTO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "kernel_defines.h" + +#if IS_USED(MODULE_PSA_SECURE_ELEMENT_CONFIG) +#include "psa/crypto_se_config.h" +#endif + +#include "crypto_sizes.h" +#include "crypto_struct.h" +#include "crypto_values.h" +#include "crypto_types.h" + +/** + * @brief The major version of this implementation of the PSA Crypto API + */ +#define PSA_CRYPTO_API_VERSION_MAJOR 1 + +/** + * @brief The minor version of this implementation of the PSA Crypto API + */ +#define PSA_CRYPTO_API_VERSION_MINOR 1 + +/** + * @brief Helper function to convert PSA status values humanly readable. + * + * @param status PSA status value + * @return Pointer to string + */ +const char *psa_status_to_humanly_readable(psa_status_t status); + +/** + * @brief Library initialization. + * + * @details Applications must call this function before calling any other function in this module. + * Applications are permitted to call this function more than once. Once a call succeeds, + * subsequent calls are guaranteed to succeed. + * + * If the application calls other functions before calling @ref psa_crypto_init(), + * the behavior is undefined. In this situation: + * - Implementations are encouraged to either perform the operation as if the library + * had been initialized or to return @ref PSA_ERROR_BAD_STATE or some other applicable + * error. + * - Implementations must not return a success status if the lack of initialization might + * have security implications, for example due to improper seeding of the random number + * generator. + * + * @return @ref PSA_SUCCESS + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_INSUFFICIENT_ENTROPY + */ +psa_status_t psa_crypto_init(void); + +/** + * @brief Process an authenticated encryption operation. + * + * @param key Identifier of the key to use for the operation. It must allow + * the usage @ref PSA_KEY_USAGE_ENCRYPT. + * @param alg The AEAD algorithm to compute (@c PSA_ALG_XXX value such that + * @ref PSA_ALG_IS_AEAD(@p alg) is true). + * @param nonce Nonce or IV to use. + * @param nonce_length Size of the nonce buffer in bytes. This must be appropriate + * for the selected algorithm. The default nonce size is + * @ref PSA_AEAD_NONCE_LENGTH(@p key_type, @p alg) where + * @c key_type is the type of key. + * @param additional_data Additional data that will be authenticated but not encrypted. + * @param additional_data_length Size of additional_data in bytes. + * @param plaintext Data that will be authenticated and encrypted. + * @param plaintext_length Size of plaintext in bytes. + * @param ciphertext Output buffer for the authenticated and encrypted data. The + * additional data is not part of this output. For algorithms + * where the encrypted data and the authentication tag are defined + * as separate outputs, the authentication tag is appended to the + * encrypted data. + * @param ciphertext_size Size of the ciphertext buffer in bytes. This must be + * appropriate for the selected algorithm and key: + * - A sufficient output size is + * @ref PSA_AEAD_ENCRYPT_OUTPUT_SIZE(@p key_type, @p alg, + * @p plaintext_length) where key_type is the type of key. + * - @ref PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE(@p plaintext_length) + * evaluates to the maximum ciphertext size of any supported + * AEAD encryption. + * @param ciphertext_length On success, the size of the output in the ciphertext buffer. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_INVALID_HANDLE + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the + * @ref PSA_KEY_USAGE_ENCRYPT flag, or it does not + * permit the requested algorithm. + * @return @ref PSA_ERROR_INVALID_ARGUMENT @c key is not compatible with @c alg. + * @return @ref PSA_ERROR_NOT_SUPPORTED @c alg is not supported or is not an AEAD + * algorithm. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL @c ciphertext_size is too small. + * @ref PSA_AEAD_ENCRYPT_OUTPUT_SIZE() or + * @ref PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE() can be + * used to determine the required buffer size. + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized + * by @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_aead_encrypt(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *nonce, + size_t nonce_length, + const uint8_t *additional_data, + size_t additional_data_length, + const uint8_t *plaintext, + size_t plaintext_length, + uint8_t *ciphertext, + size_t ciphertext_size, + size_t *ciphertext_length); + +/** + * @brief Process an authenticated decryption operation. + * + * @param key Identifier of the key to use for the operation. It must allow + * the usage @ref PSA_KEY_USAGE_DECRYPT. + * @param alg The AEAD algorithm to compute (@c PSA_ALG_XXX value such that + * @ref PSA_ALG_IS_AEAD(@p alg) is true). + * @param nonce Nonce or IV to use. + * @param nonce_length Size of the nonce buffer in bytes. This must be appropriate + * for the selected algorithm. The default nonce size is + * @ref PSA_AEAD_NONCE_LENGTH(@p key_type, @p alg) where + * @c key_type is the type of @c key. + * @param additional_data Additional data that will be authenticated but not encrypted. + * @param additional_data_length Size of @c additional_data in bytes. + * @param ciphertext Data that has been authenticated and encrypted. For algorithms + * where the encrypted data and the authentication tag are defined + * as separate inputs, the buffer must contain the encrypted data + * followed by the authentication tag. + * @param ciphertext_length Size of @c ciphertext in bytes. + * @param plaintext Output buffer for the decrypted data. + * @param plaintext_size Size of the plaintext buffer in bytes. This must be + * appropriate for the selected algorithm and key: + * - A sufficient output size is + * @ref PSA_AEAD_DECRYPT_OUTPUT_SIZE(@p key_type, @p alg, + * @p ciphertext_length) where @c key_type is the type of key. + * - @ref PSA_AEAD_DECRYPT_OUTPUT_MAX_SIZE(@p ciphertext_length) + * evaluates to the maximum ciphertext size of any supported + * AEAD decryption. + * @param plaintext_length On success, the size of the output in the plaintext buffer. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_INVALID_HANDLE + * @return @ref PSA_ERROR_INVALID_SIGNATURE The ciphertext is not authentic. + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref + * PSA_KEY_USAGE_DECRYPT flag, or it does not + * permit the requested algorithm. + * @return @ref PSA_ERROR_INVALID_ARGUMENT @c key is not compatible with @c alg. + * @return @ref PSA_ERROR_NOT_SUPPORTED @c alg is not supported or is not an AEAD + * algorithm. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL @c plaintext_size is too small. + * @ref PSA_AEAD_DECRYPT_OUTPUT_SIZE() or + * @ref PSA_AEAD_DECRYPT_OUTPUT_MAX_SIZE() can be + * used to determine the required buffer size. + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized + * by @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_aead_decrypt(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *nonce, + size_t nonce_length, + const uint8_t *additional_data, + size_t additional_data_length, + const uint8_t *ciphertext, + size_t ciphertext_length, + uint8_t *plaintext, + size_t plaintext_size, + size_t *plaintext_length); + +/** + * @brief Set the key for a multi-part authenticated encryption operation. + * + * @details The sequence of operations to encrypt a message with authentication is as follows: + * -# Allocate an operation object which will be passed to all the functions listed here + * -# Initialize the operation object with one of the methods described in the + * documentation for @ref psa_aead_operation_t, e.g. @ref PSA_AEAD_OPERATION_INIT. + * -# Call @ref psa_aead_encrypt_setup() to specify the algorithm and key. + * -# If needed, call @ref psa_aead_set_lengths() to specify the length of the inputs to + * the subsequent calls to @ref psa_aead_update_ad() and @ref psa_aead_update(). See + * the documentation of @ref psa_aead_set_lengths() for details. + * -# Call either @ref psa_aead_generate_nonce() or @ref psa_aead_set_nonce() to generate + * or set the nonce. It is recommended to use @ref psa_aead_generate_nonce() unless + * the protocol being implemented requires a specific nonce value. + * -# Call @ref psa_aead_update_ad() zero, one or more times, passing a fragment of the + * non-encrypted additional authenticated data each time. + * -# Call @ref psa_aead_update() zero, one or more times, passing a fragment of the + * message to encrypt each time. + * -# Call @ref psa_aead_finish(). + * + * If an error occurs at any step after a call to @ref psa_aead_encrypt_setup(), + * the operation will need to be reset by a call to @ref psa_aead_abort(). The application + * can call @ref psa_aead_abort() at any time after the operation has been initialized. + * + * After a successful call to @ref psa_aead_encrypt_setup(), the application must + * eventually terminate the operation. The following events terminate an operation: + * - A successful call to @ref psa_aead_finish(). + * - A call to @ref psa_aead_abort(). + * + * @param operation The operation object to set up. It must have been initialized as per the + * documentation for @ref psa_aead_operation_t and not yet in use. + * @param key Identifier of the key to use for the operation. It must remain valid until + * the operation terminates. + * It must allow the usage @ref PSA_KEY_USAGE_ENCRYPT. + * @param alg The AEAD algorithm to compute (@c PSA_ALG_XXX value such that + * @ref PSA_ALG_IS_AEAD(@p alg) is true). + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: it must be + * inactive. + * @return @ref PSA_ERROR_INVALID_HANDLE + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref PSA_KEY_USAGE_ENCRYPT + * flag, or it does not permit the requested algorithm. + * @return @ref PSA_ERROR_INVALID_ARGUMENT @c key is not compatible with @c alg. + * @return @ref PSA_ERROR_NOT_SUPPORTED @c alg is not supported or is not an AEAD algorithm. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized by + * @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_aead_encrypt_setup(psa_aead_operation_t *operation, + psa_key_id_t key, + psa_algorithm_t alg); + +/** + * @brief Set the key for a multi-part authenticated decryption operation. + * + * @details The sequence of operations to decrypt a message with authentication is as follows: + * -# Allocate an operation object which will be passed to all the functions listed here + * -# Initialize the operation object with one of the methods described in the + * documentation for @ref psa_aead_operation_t, e.g. @ref PSA_AEAD_OPERATION_INIT. + * -# Call @ref psa_aead_decrypt_setup() to specify the algorithm and key. + * -# If needed, call @ref psa_aead_set_lengths() to specify the length of the inputs to + * the subsequent calls to @ref psa_aead_update_ad() and @ref psa_aead_update(). See + * the documentation of @ref psa_aead_set_lengths() for details. + * -# Call @ref psa_aead_set_nonce() with the nonce for the decryption. + * -# Call @ref psa_aead_update_ad() zero, one or more times, passing a fragment of the + * non-encrypted additional authenticated data each time. + * -# Call @ref psa_aead_update() zero, one or more times, passing a fragment of the + * message to encrypt each time. + * -# Call @ref psa_aead_verify(). + * + * If an error occurs at any step after a call to @ref psa_aead_decrypt_setup(), + * the operation will need to be reset by a call to @ref psa_aead_abort(). The application + * can call @ref psa_aead_abort() at any time after the operation has been initialized. + * + * After a successful call to @ref psa_aead_decrypt_setup(), the application must + * eventually terminate the operation. The following events terminate an operation: + * - A successful call to @ref psa_aead_verify(). + * - A call to @ref psa_aead_abort(). + * + * @param operation The operation object to set up. It must have been initialized as per the + * documentation for @ref psa_aead_operation_t and not yet in use. + * @param key Identifier of the key to use for the operation. It must remain valid + * until the operation terminates. It must allow the usage @ref + * PSA_KEY_USAGE_DECRYPT. + * @param alg The AEAD algorithm to compute (@c PSA_ALG_XXX value such that + * @ref PSA_ALG_IS_AEAD(@p alg) is true). + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: it must be + * inactive. + * @return @ref PSA_ERROR_INVALID_HANDLE + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref + * PSA_KEY_USAGE_DECRYPT flag, or it does not + * permit the requested algorithm. + * @return @ref PSA_ERROR_INVALID_ARGUMENT @c key is not compatible with @c alg. + * @return @ref PSA_ERROR_NOT_SUPPORTED @c alg is not supported or is not an AEAD + * algorithm. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized + * by @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_aead_decrypt_setup(psa_aead_operation_t *operation, + psa_key_id_t key, + psa_algorithm_t alg); + +/** + * @brief Declare the lengths of the message and additional data for AEAD. + * + * @details The application must call this function before calling @ref psa_aead_set_nonce() + * or @ref psa_aead_generate_nonce(), if the algorithm for the operation requires it. + * If the algorithm does not require it, calling this function is optional, but if + * this function is called then the implementation must enforce the lengths. + * - For @ref PSA_ALG_CCM, calling this function is required. + * - For the other AEAD algorithms defined in this specification, + * calling this function is not required. + * - For vendor-defined algorithm, refer to the vendor documentation. + * + * If this function returns an error status, the operation enters an error state and + * must be aborted by calling @ref psa_aead_abort(). + * + * @param operation Active AEAD operation. + * @param ad_length Size of the non-encrypted additional authenticated data in bytes. + * @param plaintext_length Size of the plaintext to encrypt in bytes. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: it must be + * active, and @ref psa_aead_set_nonce() and + * @ref psa_aead_generate_nonce() must not have + * been called yet. + * @return @ref PSA_ERROR_INVALID_ARGUMENT At least one of the lengths is not acceptable + * for the chosen algorithm. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized + * by @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_aead_set_lengths(psa_aead_operation_t *operation, + size_t ad_length, + size_t plaintext_length); + +/** + * @brief Generate a random nonce for an authenticated encryption operation. + * + * @details This function generates a random nonce for the authenticated encryption operation + * with an appropriate size for the chosen algorithm, key type and key size. + * + * The application must call @ref psa_aead_encrypt_setup() before calling this function. + * If applicable for the algorithm, the application must call @ref psa_aead_set_lengths() + * before calling this function. + * + * If this function returns an error status, the operation enters an error state and must + * be aborted by calling @ref psa_aead_abort(). + * + * @param operation Active AEAD operation. + * @param nonce Buffer where the generated nonce is to be written. + * @param nonce_size Size of the nonce buffer in bytes. This must be at least + * @ref PSA_AEAD_NONCE_LENGTH(@p key_type, @p alg) where @p key_type + * and @p alg are type of key and the algorithm respectively that + * were used to set up the AEAD operation. + * @param nonce_length On success, the number of bytes of the generated nonce. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: it must be + * an active AEAD encryption operation, with no + * nonce set. + * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: this is an + * algorithm which requires @ref + * psa_aead_set_lengths() to be called before + * setting the nonce. + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the nonce buffer is too small. + * @ref PSA_AEAD_NONCE_LENGTH() or @ref + * PSA_AEAD_NONCE_MAX_SIZE can be used to + * determine the required buffer size. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized + * by @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_aead_generate_nonce(psa_aead_operation_t *operation, + uint8_t *nonce, + size_t nonce_size, + size_t *nonce_length); + +/** + * @brief Set the nonce for an authenticated encryption or decryption operation. + * + * @details This function sets the nonce for the authenticated encryption or decryption operation. + * The application must call @ref psa_aead_encrypt_setup() or @ref + * psa_aead_decrypt_setup() before calling this function. If applicable for the algorithm, + * the application must call @ref psa_aead_set_lengths() before calling this function. + * + * If this function returns an error status, the operation enters an error state and must + * be aborted by calling @ref psa_aead_abort(). + * + * @note When encrypting, @ref psa_aead_generate_nonce() is recommended instead of using this + * function, unless implementing a protocol that requires a non-random IV. + * + * @param operation Active AEAD operation. + * @param nonce Buffer containing the nonce to use. + * @param nonce_length Size of the nonce in bytes. This must be a valid nonce size for the + * chosen algorithm. The default nonce size is @ref PSA_AEAD_NONCE_LENGTH + * (@p key_type, @p alg) where @c key_type and @c alg are type of key and + * the algorithm respectively that were used to set up the AEAD operation. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: it must be + * an active AEAD encryption operation, with no + * nonce set. + * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: this is an + * algorithm which requires @ref + * psa_aead_set_lengths() to be called before + * setting the nonce. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The size of nonce is not acceptable for the + * chosen algorithm. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized + * by @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_aead_set_nonce(psa_aead_operation_t *operation, + const uint8_t *nonce, + size_t nonce_length); + +/** + * @brief Pass additional data to an active AEAD operation. + * + * @details Additional data is authenticated, but not encrypted. + * This function can be called multiple times to pass successive fragments of the + * additional data. This function must not be called after passing data to encrypt + * or decrypt with @ref psa_aead_update(). + * + * The following must occur before calling this function: + * -# Call either @ref psa_aead_encrypt_setup() or @ref psa_aead_decrypt_setup(). + * -# Set the nonce with @ref psa_aead_generate_nonce() or @ref psa_aead_set_nonce(). + * + * If this function returns an error status, the operation enters an error state and + * must be aborted by calling @ref psa_aead_abort(). + * + * @warning When decrypting, do not trust the input until @ref psa_aead_verify() succeeds. + * See the detailed warning. + * + * @param operation Active AEAD operation. + * @param input Buffer containing the fragment of additional data. + * @param input_length Size of the input buffer in bytes. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: it must be + * active, have a nonce set, have lengths set if + * required by the algorithm, and @ref + * psa_aead_update() must not have been called yet. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The total input length overflows the additional + * data length that was previously specified with + * @ref psa_aead_set_lengths(). + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized + * by @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_aead_update_ad(psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length); + +/** + * @brief Encrypt or decrypt a message fragment in an active AEAD operation. + * + * @details The following must occur before calling this function: + * -# Call either @ref psa_aead_encrypt_setup() or @ref psa_aead_decrypt_setup(). + * The choice of setup function determines whether this function encrypts or decrypts + * its input. + * -# Set the nonce with @ref psa_aead_generate_nonce() or @ref psa_aead_set_nonce(). + * -# Call @ref psa_aead_update_ad() to pass all the additional data. + * + * If this function returns an error status, the operation enters an error state and must + * be aborted by calling @ref psa_aead_abort(). + * + * This function does not require the input to be aligned to any particular block + * boundary. If the implementation can only process a whole block at a time, it must + * consume all the input provided, but it might delay the end of the corresponding output + * until a subsequent call to @ref psa_aead_update(), @ref psa_aead_finish() or @ref + * psa_aead_verify() provides sufficient input. + * The amount of data that can be delayed in this way is bounded by @ref + * PSA_AEAD_UPDATE_OUTPUT_SIZE(). + * + * @warning When decrypting, do not trust the input until @ref psa_aead_verify() succeeds. + * See the detailed warning. + * + * @param operation Active AEAD operation. + * @param input Buffer containing the message fragment to encrypt or decrypt. + * @param input_length Size of the input buffer in bytes. + * @param output Buffer where the output is to be written. + * @param output_size Size of the output buffer in bytes. This must be appropriate for the + * selected algorithm and key: + * - A sufficient output size is @ref PSA_AEAD_UPDATE_OUTPUT_SIZE( + * @p key_type, @p alg, @p input_length) where @c key_type is the + * type of key and @c alg is the algorithm that were used to set up + * the operation. + * - @ref PSA_AEAD_UPDATE_OUTPUT_MAX_SIZE(@p input_length) evaluates to + * the maximum output size of any supported AEAD algorithm. + * @param output_length On success, the number of bytes that make up the returned output. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: it must be + * active, have a nonce set, and have lengths set + * if required by the algorithm. + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the output buffer is too small. + * @ref PSA_AEAD_UPDATE_OUTPUT_SIZE() or + * @ref PSA_AEAD_UPDATE_OUTPUT_MAX_SIZE() can be + * used to determine the required buffer size. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The total length of input to @ref + * psa_aead_update_ad() so far is less than the + * additional data length that was previously + * specified with @ref psa_aead_set_lengths() + * @return @ref PSA_ERROR_INVALID_ARGUMENT The total input length overflows the plaintext + * length that was previously specified with + * @ref psa_aead_set_lengths(). + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized + * by @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_aead_update(psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Finish encrypting a message in an AEAD operation. + * + * @details The operation must have been set up with @ref psa_aead_encrypt_setup(). + * This function finishes the authentication of the additional data formed + * by concatenating the inputs passed to preceding calls to @ref psa_aead_update_ad() + * with the plaintext formed by concatenating the inputs passed to preceding calls to + * @ref psa_aead_update(). This function has two output buffers: + * - @p ciphertext contains trailing ciphertext that was buffered from preceding calls to + * @ref psa_aead_update(). + * - @p tag contains the authentication tag. + * + * 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 @ref psa_aead_abort(). + * + * @param operation Active AEAD operation. + * @param ciphertext Buffer where the last part of the ciphertext is to be written. + * @param ciphertext_size Size of the ciphertext buffer in bytes. This must be appropriate + * for the selected algorithm and key: + * - A sufficient output size is @ref PSA_AEAD_FINISH_OUTPUT_SIZE( + * @p key_type, @p alg) where @p key_type is the type of key and + * @p alg is the algorithm that were used to set up the operation + * - @ref PSA_AEAD_FINISH_OUTPUT_MAX_SIZE evaluates to the maximum + * output size of any supported AEAD algorithm. + * @param ciphertext_length On success, the number of bytes of returned ciphertext. + * @param tag Buffer where the authentication tag is to be written. + * @param tag_size Size of the tag buffer in bytes. This must be appropriate for the + * selected algorithm and key: + * - The exact tag size is @ref PSA_AEAD_TAG_LENGTH(@p key_type, + * @p key_bits, @p alg) where @c key_type and @c key_bits are + * the type and bit-size of the key, and @c alg is the algorithm + * that were used in the call to @ref psa_aead_encrypt_setup(). + * - @ref PSA_AEAD_TAG_MAX_SIZE evaluates to the maximum tag size + * of any supported AEAD algorithm. + * @param tag_length On success, the number of bytes that make up the returned tag. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: it must be an + * active encryption operation with a nonce set. + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the ciphertext or tag buffer is too + * small. @ref PSA_AEAD_FINISH_OUTPUT_SIZE() or + * @ref PSA_AEAD_FINISH_OUTPUT_MAX_SIZE can be + * used to determine the required ciphertext + * buffer size. @ref PSA_AEAD_TAG_LENGTH() or + * @ref PSA_AEAD_TAG_MAX_SIZE can be used to + * determine the required tag buffer size. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The total length of input to @ref + * psa_aead_update_ad() so far is less than the + * additional data length that was previously + * specified with @ref psa_aead_set_lengths() + * @return @ref PSA_ERROR_INVALID_ARGUMENT The total length of input to @ref + * psa_aead_update() so far is less than the + * plaintext length that was previously specified + * with @ref psa_aead_set_lengths(). + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized + * by @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_aead_finish(psa_aead_operation_t *operation, + uint8_t *ciphertext, + size_t ciphertext_size, + size_t *ciphertext_length, + uint8_t *tag, + size_t tag_size, + size_t *tag_length); + +/** + * @brief Finish authenticating and decrypting a message in an AEAD operation. + * + * @details The operation must have been set up with @ref psa_aead_decrypt_setup(). + * This function finishes the authenticated decryption of the message components: + * - The additional data consisting of the concatenation of the inputs passed to + * preceding calls to @ref psa_aead_update_ad(). + * - The ciphertext consisting of the concatenation of the inputs passed to + * preceding calls to @ref psa_aead_update(). + * - The tag passed to this function call. + * + * If the authentication tag is correct, this function outputs any remaining plaintext + * and reports success. If the authentication tag is not correct, this function returns + * @ref PSA_ERROR_INVALID_SIGNATURE. + * + * 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 @ref psa_aead_abort(). + * + * @note Implementations must make the best effort to ensure that the comparison between + * the actual tag and the expected tag is performed in constant time. + * + * @param operation Active AEAD operation. + * @param plaintext Buffer where the last part of the plaintext is to be written. This + * is the remaining data from previous calls to @ref psa_aead_update() + * that could not be processed until the end of the input. + * @param plaintext_size Size of the plaintext buffer in bytes. This must be appropriate + * for the selected algorithm and key: + * - A sufficient output size is @ref PSA_AEAD_FINISH_OUTPUT_SIZE( + * @p key_type, @p alg) where @c key_type is the type of key and + * @c alg is the algorithm that were used to set up the operation + * - @ref PSA_AEAD_FINISH_OUTPUT_MAX_SIZE evaluates to the maximum + * output size of any supported AEAD algorithm. + * @param plaintext_length On success, the number of bytes of returned plaintext. + * @param tag Buffer containing the authentication tag. + * @param tag_length Size of the tag buffer in bytes. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_INVALID_SIGNATURE The calculations were successful, but the + * authentication tag is not correct. + * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: it must be an + * active encryption operation with a nonce set. + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the plaintext buffer is too small. + * @ref PSA_AEAD_VERIFY_OUTPUT_SIZE() or + * @ref PSA_AEAD_VERIFY_OUTPUT_MAX_SIZE can be + * used to determine the required buffer size. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The total length of input to @ref + * psa_aead_update_ad() so far is less than the + * additional data length that was previously + * specified with @ref psa_aead_set_lengths() + * @return @ref PSA_ERROR_INVALID_ARGUMENT The total length of input to @ref + * psa_aead_update() so far is less than the + * plaintext length that was previously specified + * with @ref psa_aead_set_lengths(). + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized + * by @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_aead_verify(psa_aead_operation_t *operation, + uint8_t *plaintext, + size_t plaintext_size, + size_t *plaintext_length, + const uint8_t *tag, + size_t tag_length); + +/** + * @brief Abort an AEAD operation. + * + * @details Aborting an operation frees all associated resources except for the operation object + * itself. Once aborted, the operation object can be reused for another operation by + * calling @ref psa_aead_encrypt_setup() or @ref psa_aead_decrypt_setup() again. + * + * This function can be called any time after the operation object has been initialized as + * described in @ref psa_aead_operation_t. + * + * In particular, calling @ref psa_aead_abort() after the operation has been terminated + * by a call to @ref psa_aead_abort(), @ref psa_aead_finish() or @ref psa_aead_verify() + * is safe and has no effect. + * + * @param operation Initialized AEAD operation. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized + * by @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_aead_abort(psa_aead_operation_t *operation); + +/** + * @brief Encrypt a short message with a public key. + * + * @details For @ref PSA_ALG_RSA_PKCS1V15_CRYPT, no salt is supported. + * + * @param key Identifier of the key to use for the operation. It must be a + * public key or an asymmetric key pair. It must allow the usage + * @ref PSA_KEY_USAGE_ENCRYPT. + * @param alg An asymmetric encryption algorithm that is compatible with + * the type of key. + * @param input The message to encrypt. + * @param input_length Size of the input buffer in bytes. + * @param salt A salt or label, if supported by the encryption algorithm. If the + * algorithm does not support a salt, pass @c NULL. If the algorithm + * supports an optional salt, pass @c NULL to indicate that there is + * no salt. + * @param salt_length Size of the salt buffer in bytes. If salt is @c NULL, pass 0. + * @param output Buffer where the encrypted message is to be written. + * @param output_size Size of the output buffer in bytes. This must be appropriate for the + * selected algorithm and key: + * - The required output size is @ref PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE + * (@p key_type, @p key_bits, @p alg) where @p key_type and + * @p key_bits are the type and bit-size respectively of key + * - @ref PSA_ASYMMETRIC_ENCRYPT_OUTPUT_MAX_SIZE evaluates to the maximum + * output size of any supported asymmetric encryption. + * @param output_length On success, the number of bytes that make up the returned output. + * + * @return @ref PSA_SUCCESS + * @return @ref PSA_ERROR_INVALID_HANDLE + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref + * PSA_KEY_USAGE_ENCRYPT flag, or it does not + * permit the requested algorithm. + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the output buffer is too small. + * @ref PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE() or + * @ref PSA_ASYMMETRIC_ENCRYPT_OUTPUT_MAX_SIZE can + * be used to determine the required buffer size. + * @return @ref PSA_ERROR_NOT_SUPPORTED + * @return @ref PSA_ERROR_INVALID_ARGUMENT + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + * @return @ref PSA_ERROR_INSUFFICIENT_ENTROPY + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized + * by @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_asymmetric_encrypt(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *salt, + size_t salt_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Decrypt a short message with a private key. + * + * @details For @ref PSA_ALG_RSA_PKCS1V15_CRYPT, no salt is supported. + * + * @param key Identifier of the key to use for the operation. It must be an asymmetric + * key pair. It must allow the usage @ref PSA_KEY_USAGE_DECRYPT. + * @param alg An asymmetric encryption algorithm that is compatible with + * the type of key. + * @param input The message to decrypt. + * @param input_length Size of the input buffer in bytes. + * @param salt A salt or label, if supported by the encryption algorithm. If the + * algorithm does not support a salt, pass @c NULL. If the algorithm + * supports an optional salt, pass @c NULL to indicate that there is + * no salt. + * @param salt_length Size of the salt buffer in bytes. If salt is @c NULL, pass 0. + * @param output Buffer where the decrypted message is to be written. + * @param output_size Size of the output buffer in bytes. This must be appropriate for the + * selected algorithm and key: + * - The required output size is @ref PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE + * (@p key_type, @p key_bits, @p alg) where @p key_type and + * @p key_bits are the type and bit-size respectively of key. + * - @ref PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE evaluates to the maximum + * output size of any supported asymmetric decryption. + * @param output_length On success, the number of bytes that make up the returned output. + * + * @return @ref PSA_SUCCESS + * @return @ref PSA_ERROR_INVALID_HANDLE + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref + * PSA_KEY_USAGE_DECRYPT flag, or it does not + * permit the requested algorithm. + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the output buffer is too small. + * @ref PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE() or + * @ref PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE + * can be used to determine the required buffer + * size. + * @return @ref PSA_ERROR_NOT_SUPPORTED + * @return @ref PSA_ERROR_INVALID_ARGUMENT + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + * @return @ref PSA_ERROR_INSUFFICIENT_ENTROPY + * @return @ref PSA_ERROR_INVALID_PADDING + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized + * by @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_asymmetric_decrypt(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *salt, + size_t salt_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Abort a cipher operation. + * + * @details Aborting an operation frees all associated resources except for the operation object + * itself. Once aborted, the operation object can be reused for another operation by + * calling @ref psa_cipher_encrypt_setup() or @ref psa_cipher_decrypt_setup() again. + * + * This function can be called any time after the operation object has been initialized + * as described in @ref psa_cipher_operation_t. + * + * In particular, calling @ref psa_cipher_abort() after the operation has been terminated + * by a call to @ref psa_cipher_abort() or @ref psa_cipher_finish() is safe and has no + * effect. + * + * @param operation Initialized cipher operation. + * + * @return @ref PSA_SUCCESS Success. The operation object can now be + * discarded or reused. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call + * to @ref psa_crypto_init(). + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + */ +psa_status_t psa_cipher_abort(psa_cipher_operation_t *operation); + +/** + * @brief Decrypt a message using a symmetric cipher. + * + * @details This function decrypts a message encrypted with a symmetric cipher. * + * The input to this function must contain the IV followed by the ciphertext, as output + * by @ref psa_cipher_encrypt(). The IV must be @ref PSA_CIPHER_IV_LENGTH(@p key_type, + * @p alg) bytes in length, where @c key_type is the type of key. + * + * Use the multi-part operation interface with a @ref psa_cipher_operation_t object to + * decrypt data which is not in the expected input format. + * + * @param key Identifier of the key to use for the operation. It must remain + * valid until the operation terminates. It must allow the usage + * @ref PSA_KEY_USAGE_DECRYPT. + * @param alg The cipher algorithm to compute: a value of type @ref psa_algorithm_t + * such that @ref PSA_ALG_IS_CIPHER(@p alg) is true. + * @param input Buffer containing the message to decrypt. This consists of the IV + * followed by the ciphertext proper. + * @param input_length Size of the input buffer in bytes. + * @param output Buffer where the plaintext is to be written. + * @param output_size Size of the output buffer in bytes. + * This must be appropriate for the selected algorithm and key: + * - A sufficient output size is @ref PSA_CIPHER_DECRYPT_OUTPUT_SIZE( + * @p key_type, @p alg, @p input_length) where @c key_type is the + * type of key. + * - @ref PSA_CIPHER_DECRYPT_OUTPUT_MAX_SIZE(@p input_length) evaluates + * to the maximum output size of any supported cipher decryption. + * @param output_length On success, the number of bytes that make up the output. + * + * @return @ref PSA_SUCCESS Success. The first @p (*output_length) bytes of + * @p output contain the plaintext. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier. + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref PSA_KEY_USAGE_DECRYPT + * flag, or it does not permit the requested algorithm. + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the output buffer is too small. + * @ref PSA_CIPHER_DECRYPT_OUTPUT_SIZE() or + * @ref PSA_CIPHER_DECRYPT_OUTPUT_MAX_SIZE() can be + * used to determine a sufficient buffer size. + * @return @ref PSA_ERROR_INVALID_PADDING The algorithm uses padding, and the input does not + * contain valid padding. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - @c alg is not a cipher algorithm. + * - @c key is not compatible with alg. + * - The input_length is not valid for the algorithm + * and key type. + * For example, the algorithm is a based on block + * cipher and requires a whole number of blocks, + * but the total input size is not a multiple + * of the block size. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - @c alg is not supported or is not a cipher + * algorithm. + * - @c key is not supported for use with alg. + * - @c input_length is too large for the implementation. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_cipher_decrypt(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Set the key for a multi-part symmetric decryption operation. + * + * @details The sequence of operations to decrypt a message with a symmetric cipher is as follows: + * -# Allocate an operation object which will be passed to all the functions listed here. + * -# Initialize the operation object with one of the methods described in the + * documentation for @ref psa_cipher_operation_t, e.g. @ref PSA_CIPHER_OPERATION_INIT. + * -# Call @ref psa_cipher_decrypt_setup() to specify the algorithm and key. + * -# Call @ref psa_cipher_set_iv() with the initialization vector (IV) for the + * decryption, if the algorithm requires one. This must match the IV used for the + * encryption. + * -# Call @ref psa_cipher_update() zero, one or more times, passing a fragment of the + * message each time. + * -# Call @ref psa_cipher_finish(). + * + * If an error occurs at any step after a call to @ref psa_cipher_decrypt_setup(), + * the operation will need to be reset by a call to @ref psa_cipher_abort(). + * The application can call @ref psa_cipher_abort() at any time after the operation + * has been initialized. + * + * After a successful call to @ref psa_cipher_decrypt_setup(), the application must + * eventually terminate the operation. The following events terminate an operation: + * - A successful call to @ref psa_cipher_finish(). + * - A call to @ref psa_cipher_abort(). + * + * @param operation The operation object to set up. It must have been initialized as per + * the documentation for @ref psa_cipher_operation_t and not yet in use. + * @param key Identifier of the key to use for the operation. It must remain valid + * until the operation terminates. It must allow the usage @ref + * PSA_KEY_USAGE_DECRYPT. + * @param alg The cipher algorithm to compute: a value of type @ref psa_algorithm_t + * such that @ref PSA_ALG_IS_CIPHER(@p alg) is true. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be + * inactive. + * - The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @p key is not a valid key identifier. + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref PSA_KEY_USAGE_DECRYPT + * flag, or it does not permit the requested algorithm. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - @c alg is not a cipher algorithm. + * - @c key is not compatible with alg. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - @c alg is not supported or is not a cipher algorithm. + * - @c key is not supported for use with alg. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_cipher_decrypt_setup(psa_cipher_operation_t *operation, + psa_key_id_t key, + psa_algorithm_t alg); + +/** + * @brief Encrypt a message using a symmetric cipher. + * + * @details This function encrypts a message with a random initialization vector (IV). + * The length of the IV is @ref PSA_CIPHER_IV_LENGTH(@p key_type, @p alg) where + * @p key_type is the type of key. The output of @ref psa_cipher_encrypt() is + * the IV followed by the ciphertext. + * + * Use the multi-part operation interface with a @ref psa_cipher_operation_t object + * to provide other forms of IV or to manage the IV and ciphertext independently. + * + * @param key Identifier of the key to use for the operation. It must allow the usage + * @ref PSA_KEY_USAGE_ENCRYPT. + * @param alg The cipher algorithm to compute (@c PSA_ALG_XXX value such that + * @ref PSA_ALG_IS_CIPHER(@p alg) is true). + * @param input Buffer containing the message to encrypt. + * @param input_length Size of the input buffer in bytes. + * @param output Buffer where the output is to be written. The output contains the IV + * followed by the ciphertext proper. + * @param output_size Size of the output buffer in bytes. This must be appropriate for the + * selected algorithm and key: + * - A sufficient output size is @ref PSA_CIPHER_ENCRYPT_OUTPUT_SIZE( + * @p key_type, @p alg, @p input_length) where @c key_type is the + * type of key + * - @ref PSA_CIPHER_ENCRYPT_OUTPUT_MAX_SIZE(@p input_length) evaluates + * to the maximum output size of any supported cipher encryption. + * @param output_length On success, the number of bytes that make up the output. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_INVALID_HANDLE + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref + * PSA_KEY_USAGE_ENCRYPT flag, or it does not permit + * the requested algorithm. + * @return @ref PSA_ERROR_INVALID_ARGUMENT @c key is not compatible with alg. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The @c input_length is not valid for the algorithm + * and key type. For example, the algorithm is a based + * on block cipher and requires a whole number of + * blocks, but the total input size is not a multiple + * of the block size. + * @return @ref PSA_ERROR_NOT_SUPPORTED @c alg is not supported or is not a cipher + * algorithm. + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL @c output_size is too small. + * @ref PSA_CIPHER_ENCRYPT_OUTPUT_SIZE() or + * @ref PSA_CIPHER_ENCRYPT_OUTPUT_MAX_SIZE() + * can be used to determine the required buffer size. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized + * by @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_cipher_encrypt(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Set the key for a multi-part symmetric encryption operation. + * + * @details The sequence of operations to encrypt a message with a symmetric cipher is as follows: + * -# Allocate an operation object which will be passed to all the functions listed here. + * -# Initialize the operation object with one of the methods described in the + * documentation for @ref psa_cipher_operation_t, e.g. @ref PSA_CIPHER_OPERATION_INIT. + * -# Call @ref psa_cipher_encrypt_setup() to specify the algorithm and key. + * -# Call either @ref psa_cipher_generate_iv() or @ref psa_cipher_set_iv() to generate + * or set the initialization vector (IV), if the algorithm requires one. It is + * recommended to use @ref psa_cipher_generate_iv() unless the protocol being + * implemented requires a specific IV value. + * -# Call @ref psa_cipher_update() zero, one or more times, passing a fragment of + * the message each time. + * -# Call @ref psa_cipher_finish(). + * + * If an error occurs at any step after a call to @ref psa_cipher_encrypt_setup(), + * the operation will need to be reset by a call to @ref psa_cipher_abort(). The + * application can call @ref psa_cipher_abort() at any time after the operation has + * been initialized. + * + * After a successful call to @ref psa_cipher_encrypt_setup(), the application must + * eventually terminate the operation. The following events terminate an operation: + * - A successful call to @ref psa_cipher_finish(). + * - A call to @ref psa_cipher_abort(). + * + * @param operation The operation object to set up. It must have been initialized as per the + * documentation for @ref psa_cipher_operation_t and not yet in use. + * @param key Identifier of the key to use for the operation. It must remain valid + * until the operation terminates. It must allow the usage @ref + * PSA_KEY_USAGE_ENCRYPT. + * @param alg The cipher algorithm to compute: a value of type @ref psa_algorithm_t + * such that @ref PSA_ALG_IS_CIPHER(@p alg) is true. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be + * inactive. + * - The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier. + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref + * PSA_KEY_USAGE_ENCRYPT flag, or it does not permit + * the requested algorithm. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - @c alg is not a cipher algorithm. + * - @c key is not compatible with alg. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - @c alg is not supported or is not a cipher algorithm. + * - @c key is not supported for use with @c alg. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_cipher_encrypt_setup(psa_cipher_operation_t *operation, + psa_key_id_t key, + psa_algorithm_t alg); + +/** + * @brief Finish encrypting or decrypting a message in a cipher operation. + * + * @details The application must call @ref psa_cipher_encrypt_setup() or @ref + * psa_cipher_decrypt_setup() before calling this function. The choice of setup function + * determines whether this function encrypts or decrypts its input. + * + * This function finishes the encryption or decryption of the message formed by + * concatenating the inputs passed to preceding calls to @ref psa_cipher_update(). + * + * 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 @ref psa_cipher_abort(). + * + * @param operation Active cipher operation. + * @param output Buffer where the output is to be written. + * @param output_size Size of the output buffer in bytes. This must be appropriate for the + * selected algorithm and key: + * - A sufficient output size is @ref PSA_CIPHER_FINISH_OUTPUT_SIZE( + * @p key_type, @p alg) where @c key_type is the type of key and + * @c alg is the algorithm that were used to set up the operation. + * - @ref PSA_CIPHER_FINISH_OUTPUT_MAX_SIZE evaluates to the maximum + * output size of any supported cipher algorithm. + * @param output_length On success, the number of bytes that make up the returned output. + * + * @return @ref PSA_SUCCESS Success. The first @c (*output_length) bytes of + * @c output contain the final output. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be + * active, with an IV set if required for the + * algorithm. + * - The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the output buffer is too small. + * @ref PSA_CIPHER_FINISH_OUTPUT_SIZE() or + * @ref PSA_CIPHER_FINISH_OUTPUT_MAX_SIZE can be used + * to determine a sufficient buffer size. + * @return @ref PSA_ERROR_INVALID_PADDING This is a decryption operation for an algorithm that + * includes padding, and the ciphertext does not contain + * valid padding. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The total input size passed to this operation is not + * valid for this particular algorithm. For example, the + * algorithm is a based on block cipher and requires a + * whole number of blocks, but the total input size + * is not a multiple of the block size. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_cipher_finish(psa_cipher_operation_t *operation, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Generate an initialization vector (IV) for a symmetric encryption operation. + * + * @details This function generates a random IV, nonce or initial counter value for the encryption + * operation as appropriate for the chosen algorithm, key type and key size. + * + * The generated IV is always the default length for the key and algorithm: + * @ref PSA_CIPHER_IV_LENGTH(@p key_type, @p alg), where @p key_type is the type of key + * and @p alg is the algorithm that were used to set up the operation. To generate + * different lengths of IV, use @ref psa_generate_random() and @ref psa_cipher_set_iv(). + * + * If the cipher algorithm does not use an IV, calling this function returns a + * @ref PSA_ERROR_BAD_STATE error. For these algorithms, @ref PSA_CIPHER_IV_LENGTH( + * @p key_type, @p alg) will be zero. + * + * The application must call @ref psa_cipher_encrypt_setup() before calling this function. + * + * If this function returns an error status, the operation enters an error state and must + * be aborted by calling @ref psa_cipher_abort(). + * + * @param operation Active cipher operation. + * @param iv Buffer where the generated IV is to be written. + * @param iv_size Size of the iv buffer in bytes. This must be at least + * @ref PSA_CIPHER_IV_LENGTH(@p key_type, @p alg) where @p key_type and + * @p alg are type of key and the algorithm respectively that + * were used to set up the cipher operation. + * @param iv_length On success, the number of bytes of the generated IV. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE Either: + * - The cipher algorithm does not use an IV. + * - The operation state is not valid: it must be + * active, with no IV set. + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the iv buffer is too small. + * @ref PSA_CIPHER_IV_LENGTH() or + * @ref PSA_CIPHER_IV_MAX_SIZE can be used to + * determine the required buffer size. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized + * by @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_cipher_generate_iv(psa_cipher_operation_t *operation, + uint8_t *iv, + size_t iv_size, + size_t *iv_length); + +/** + * @brief Set the initialization vector (IV) for a symmetric encryption or decryption operation. + * + * @details This function sets the IV, nonce or initial counter value for the encryption or + * decryption operation. + * + * If the cipher algorithm does not use an IV, calling this function returns a + * @ref PSA_ERROR_BAD_STATE error. + * For these algorithms, @ref PSA_CIPHER_IV_LENGTH(key_type, alg) will be zero. + * + * The application must call @ref psa_cipher_encrypt_setup() or @ref + * psa_cipher_decrypt_setup() before calling this function. + * + * If this function returns an error status, the operation enters an error state and must + * be aborted by calling @ref psa_cipher_abort(). + * + * @note When encrypting, @ref psa_cipher_generate_iv() is recommended instead of using this + * function, unless implementing a protocol that requires a non-random IV. + * + * @param operation Active cipher operation. + * @param iv Buffer containing the IV to use. + * @param iv_length Size of the IV in bytes. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The cipher algorithm does not use an IV. + * - The operation state is not valid: it must be an + * active cipher encrypt operation, with no IV set. + * - The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - The chosen algorithm does not use an IV. + * - @c iv_length is not valid for the chosen algorithm. + * @return @ref PSA_ERROR_NOT_SUPPORTED @c iv_length is not supported for use with the + * operation’s algorithm and key. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_cipher_set_iv(psa_cipher_operation_t *operation, + const uint8_t *iv, + size_t iv_length); + +/** + * @brief Encrypt or decrypt a message fragment in an active cipher operation. + * + * @details The following must occur before calling this function: + * -# Call either @ref psa_cipher_encrypt_setup() or @ref psa_cipher_decrypt_setup(). + * The choice of setup function determines whether this function encrypts or decrypts + * its input. + * -# If the algorithm requires an IV, call @ref psa_cipher_generate_iv() or @ref + * psa_cipher_set_iv(). @ref psa_cipher_generate_iv() is recommended when encrypting. + * + * If this function returns an error status, the operation enters an error state and must + * be aborted by calling @ref psa_cipher_abort(). + * + * @param operation Active cipher operation. + * @param input Buffer containing the message fragment to encrypt or decrypt. + * @param input_length Size of the @c input buffer in bytes. + * @param output Buffer where the output is to be written. + * @param output_size Size of the output buffer in bytes. This must be appropriate for the + * selected algorithm and key: + * - A sufficient output size is @ref PSA_CIPHER_UPDATE_OUTPUT_SIZE( + * @p key_type, @p alg, @p input_length) where @c key_type is the type + * of key and @c alg is the algorithm that were used to set up the + * operation. + * - @ref PSA_CIPHER_UPDATE_OUTPUT_MAX_SIZE(@p input_length) evaluates + * to the maximum output size of any supported cipher algorithm. + * @param output_length On success, the number of bytes that make up the returned output. + * + * @return @ref PSA_SUCCESS Success. The first @p (*output_length) bytes of + * @p output contain the output data. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be + * active, with an IV set if required for the + * algorithm. + * - The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the output buffer is too small. + * @ref PSA_CIPHER_UPDATE_OUTPUT_SIZE() or + * @ref PSA_CIPHER_UPDATE_OUTPUT_MAX_SIZE() can be + * used to determine a sufficient buffer size. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The total input size passed to this operation is + * too large for this particular algorithm. + * @return @ref PSA_ERROR_NOT_SUPPORTED The total input size passed to this operation is + * too large for the implementation. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_cipher_update(psa_cipher_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Make a copy of a key. + * + * @details Copy key material from one location to another. * + * This function is primarily useful to copy a key from one location to another, as it + * populates a key using the material from another key which can have a different lifetime. + * + * This function can be used to share a key with a different party, subject to + * implementation-defined restrictions on key sharing. + * + * The policy on the source key must have the usage flag @ref PSA_KEY_USAGE_COPY set. + * This flag is sufficient to permit the copy if the key has the lifetime @ref + * PSA_KEY_LIFETIME_VOLATILE or @ref PSA_KEY_LIFETIME_PERSISTENT. Some secure elements + * do not provide a way to copy a key without making it extractable from the secure + * element. If a key is located in such a secure element, then the key must have + * both usage flags @ref PSA_KEY_USAGE_COPY and @ref PSA_KEY_USAGE_EXPORT in order to make + * a copy of the key outside the secure element. + * + * The resulting key can only be used in a way that conforms to both the policy of the + * original key and the policy specified in the attributes parameter: + * - The usage flags on the resulting key are the bitwise-and of the usage flags on the + * source policy and the usage flags in attributes. + * - If both permit the same algorithm or wildcard-based algorithm, the resulting key + * has the same permitted algorithm. + * - If either of the policies permits an algorithm and the other policy allows a + * wildcard-based permitted algorithm that includes this algorithm, the resulting key + * uses this permitted algorithm. + * - If the policies do not permit any algorithm in common, this function fails with the + * status @ref PSA_ERROR_INVALID_ARGUMENT. + * + * The effect of this function on implementation-defined attributes is + * implementation-defined. + * + * @param source_key The key to copy. It must allow the usage @ref PSA_KEY_USAGE_COPY. If a + * private or secret key is being copied outside of a secure element it must + * also allow @ref PSA_KEY_USAGE_EXPORT. + * @param attributes The attributes for the new key. This function uses the attributes as + * follows: + * - The key type and size can be 0. If either is nonzero, it must match the + * corresponding attribute of the source key. + * - The key location (the lifetime and, for persistent keys, the key + * identifier) is used directly. + * - The key policy (usage flags and permitted algorithm) are combined from + * the source key and attributes so that both sets of restrictions apply, + * as described in the documentation of this function. + * @note This 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 @ref psa_get_key_attributes() with the key’s identifier. + * @param target_key On success, an identifier for the newly created key. @ref PSA_KEY_ID_NULL + * on failure. + * + * @return @ref PSA_SUCCESS Success. If the new key is persistent, the key material + * and the key’s metadata have been saved to persistent + * storage. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @p source_key is not a valid key identifier. + * @return @ref PSA_ERROR_NOT_PERMITTED The following conditions can result in this error: + * - @p source_key does not have the @ref + * PSA_KEY_USAGE_COPY usage flag. + * - @p source_key does not have the @ref + * PSA_KEY_USAGE_EXPORT usage flag, and its storage + * location does not allow copying it to the target + * key’s storage location. + * - @p The implementation does not permit creating + * a key with the specified attributes due to some + * implementation-specific policy. + * @return @ref PSA_ERROR_ALREADY_EXISTS This is an attempt to create a persistent key, + * and there is already a persistent key with the given + * identifier. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - @p attributes specifies a key type or + * key size which does not match the attributes + * of @p source_key. + * - The lifetime or identifier in @p attributes + * are invalid. + * - The key policies from @p source_key and those + * specified in @p attributes are incompatible. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - The @p source_key storage location does not support + * copying to the target key’s storage location. + * - The key attributes, as a whole, are not supported + * in the target key’s storage location. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_INSUFFICIENT_STORAGE + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_copy_key(psa_key_id_t source_key, + const psa_key_attributes_t *attributes, + psa_key_id_t *target_key); + +/** + * @brief Destroy a key. + * + * @details This function destroys a key from both volatile memory and, if applicable, non-volatile + * storage. Implementations must make a best effort to ensure that that the key material + * cannot be recovered. + * + * This function also erases any metadata such as policies and frees resources associated + * with the key. Destroying the key makes the key identifier invalid, and the key + * identifier must not be used again by the application. + * + * If a key is currently in use in a multi-part operation, then destroying the key will + * cause the multi-part operation to fail. + * + * @param key Identifier of the key to erase. If this is @ref PSA_KEY_ID_NULL, do nothing and + * return @ref PSA_SUCCESS. + * + * @return @ref PSA_SUCCESS Success. If @p key was a valid key identifier, + * then the key material that it referred to has + * been erased. Alternatively, @p key was + * @ref PSA_KEY_ID_NULL. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @p key is neither a valid key identifier, + * nor @ref PSA_KEY_ID_NULL. + * @return @ref PSA_ERROR_NOT_PERMITTED The key cannot be erased because it is + * read-only, either due to a policy or due to + * physical restrictions. + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE There was an failure in communication with + * the cryptoprocessor. + * The key material might still be present in + * the cryptoprocessor. + * @return @ref PSA_ERROR_CORRUPTION_DETECTED An unexpected condition which is not a storage + * corruption or a communication failure occurred. + * The cryptoprocessor might have been compromised. + * @return @ref PSA_ERROR_STORAGE_FAILURE The storage operation failed. Implementations + * must make a best effort to erase key material + * even in this situation, however, it might be + * impossible to guarantee that the key material + * is not recoverable in such cases. + * @return @ref PSA_ERROR_DATA_CORRUPT The storage is corrupted. Implementations must + * make a best effort to erase key material even + * in this situation, however, it might be + * impossible to guarantee that the key material + * is not recoverable in such cases. + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_destroy_key(psa_key_id_t key); + +/** + * @brief Export a key in binary format. + * + * @details The output of this function can be passed to @ref psa_import_key() to create an + * equivalent object. + * + * If the implementation of @ref psa_import_key() supports other formats beyond the + * format specified here, the output from @ref psa_export_key() must use the + * representation specified here, not the original representation. + * + * For standard key types, the output format is as follows: + * - For symmetric keys, excluding HMAC keys, the format is the raw bytes of the key. + * - For HMAC keys that are shorter than, or equal in size to, the underlying hash + * algorithm block size, the format is the raw bytes of the key. + * - For HMAC keys that are longer than the underlying hash algorithm block size, + * the format is an implementation defined choice between the following formats: + * - The raw bytes of the key. + * - The raw bytes of the hash of the key, using the underlying hash algorithm. + * See also @ref PSA_KEY_TYPE_HMAC. + * - For DES, the key data consists of 8 bytes. The parity bits must be correct. + * - For Triple-DES, the format is the concatenation of the two or three DES keys. + * - For RSA key pairs, with key type @ref PSA_KEY_TYPE_RSA_KEY_PAIR, the format is + * the non-encrypted DER encoding of the representation defined by in PKCS #1: RSA + * Cryptography Specifications Version 2.2 [RFC8017] as RSAPrivateKey, version 0. + * @code + * RSAPrivateKey ::= SEQUENCE { + * version INTEGER, -- must be 0 + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * privateExponent INTEGER, -- d + * prime1 INTEGER, -- p + * prime2 INTEGER, -- q + * exponent1 INTEGER, -- d mod (p-1) + * exponent2 INTEGER, -- d mod (q-1) + * coefficient INTEGER, -- (inverse of q) mod p + * } + * @endcode + * @note Although it is possible to define an RSA key pair or private key using a + * subset of these elements, the output from @ref psa_export_key() for an RSA + * key pair must include all of these elements. + * - For elliptic curve key pairs, with key types for which PSA_KEY_TYPE_IS_ECC_KEY_PAIR + * () is true, the format is a representation of the private value. + * - For Weierstrass curve families @c PSA_ECC_FAMILY_SECT_XX, + * @c PSA_ECC_FAMILY_SECP_XX, @ref PSA_ECC_FAMILY_FRP and + * @ref PSA_ECC_FAMILY_BRAINPOOL_P_R1, the content of the @c privateKey field of + * the @c ECPrivateKey format defined by Elliptic Curve Private Key Structure + * [RFC5915]. This is a @c ceiling(m/8)-byte string in big-endian order where @c m + * is the key size in bits. + * - For curve family @ref PSA_ECC_FAMILY_MONTGOMERY, the scalar value of the + * ‘private key’ in little-endian order as defined by Elliptic Curves for Security + * [RFC7748] §6. The value must have the forced bits set to zero or one as + * specified by @c decodeScalar25519() and @c decodeScalar448() in [RFC7748] §5. + * This is a @c ceiling(m/8)-byte string where @c m is the key size in bits. This + * is 32 bytes for Curve25519, and 56 bytes for Curve448. + * - For the Twisted Edwards curve family @ref PSA_ECC_FAMILY_TWISTED_EDWARDS, + * the private key is defined by Edwards-Curve Digital Signature Algorithm (EdDSA) + * [RFC8032]. This is a 32-byte string for Edwards25519, and a 57-byte string + * for Edwards448. + * - For Diffie-Hellman key exchange key pairs, with key types for which @ref + * PSA_KEY_TYPE_IS_DH_KEY_PAIR() is true, the format is the representation of the + * private key x as a big-endian byte string. The length of the byte string is the + * private key size in bytes, and leading zeroes are not stripped. + * - For public keys, with key types for which @ref PSA_KEY_TYPE_IS_PUBLIC_KEY() is + * true, the format is the same as for @ref psa_export_public_key(). + * + * The policy on the key must have the usage flag @ref PSA_KEY_USAGE_EXPORT set. + * + * @param key Identifier of the key to export. It must allow the usage @ref + * PSA_KEY_USAGE_EXPORT, unless it is a public key. + * @param data Buffer where the key data is to be written. + * @param data_size Size of the data buffer in bytes. This must be appropriate for the key: + * - The required output size is @ref PSA_EXPORT_KEY_OUTPUT_SIZE(@p type, + * @p bits) where @c type is the key type and @c bits is the key size in + * bits. + * - @ref PSA_EXPORT_KEY_PAIR_MAX_SIZE evaluates to the maximum output size + * of any supported key pair. + * - @ref PSA_EXPORT_PUBLIC_KEY_MAX_SIZE evaluates to the maximum output + * size of any supported public key. + * - This API defines no maximum size for symmetric keys. Arbitrarily large + * data items can be stored in the key store, for example certificates + * that correspond to a stored private key or input material for key + * derivation. + * @param data_length On success, the number of bytes that make up the key data. + * + * @return @ref PSA_SUCCESS Success. The first @p (*data_length) bytes of data + * contain the exported key + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @p key is not a valid key identifier. + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref PSA_KEY_USAGE_EXPORT + * flag. + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the data buffer is too small. + * @ref PSA_EXPORT_KEY_OUTPUT_SIZE() or @ref + * PSA_EXPORT_KEY_PAIR_MAX_SIZE can be used to determine + * a sufficient buffer size. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - The key’s storage location does not support export + * of the key + * - The implementation does not support export of keys + * with this key type. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_export_key(psa_key_id_t key, + uint8_t *data, + size_t data_size, + size_t *data_length); + +/** + * @brief Export a public key or the public part of a key pair in binary format. + * + * @details The output of this function can be passed to @ref psa_import_key() to create an object + * that is equivalent to the public key. + * + * If the implementation of @ref psa_import_key() supports other formats beyond the + * format specified here, the output from @ref psa_export_public_key() must use the + * representation specified here, not the original representation. + * + * For standard key types, the output format is as follows: + * - For RSA public keys, with key type @ref PSA_KEY_TYPE_RSA_PUBLIC_KEY, the DER + * encoding of the representation defined by Algorithms and Identifiers for the + * Internet X.509 Public Key Infrastructure + * Certificate and Certificate Revocation List (CRL) Profile [RFC3279] §2.3.1 as + * @c RSAPublicKey. + * @code + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER } -- e + * @endcode + * - For elliptic curve key pairs, with key types for which + * @ref PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY() is true, the format depends on the key family: + * - For Weierstrass curve families @c PSA_ECC_FAMILY_SECT_XX, + * @c PSA_ECC_FAMILY_SECP_XX, @ref PSA_ECC_FAMILY_FRP and @ref + * PSA_ECC_FAMILY_BRAINPOOL_P_R1, the uncompressed representation of an elliptic + * curve point as an octet string defined in SEC 1: Elliptic Curve Cryptography + * [SEC1] §2.3.3. If @c m is the bit size associated with the curve, i.e. the bit + * size of @c q for a curve over @c F_q. The representation consists of: + * - The byte @c 0x04; + * - @c x_P as a @c ceiling(m/8)-byte string, big-endian; + * - @c y_P as a @c ceiling(m/8)-byte string, big-endian. + * - For curve family @ref PSA_ECC_FAMILY_MONTGOMERY, the scalar value of the + * ‘public key’ in little-endian order as defined by Elliptic Curves for Security + * [RFC7748] §6. This is a @c ceiling(m/8)-byte string where @c m is the key size + * in bits. + * - This is 32 bytes for Curve25519, computed as @c X25519(private_key, 9). + * - This is 56 bytes for Curve448, computed as @c X448(private_key, 5). + * - For curve family @ref PSA_ECC_FAMILY_TWISTED_EDWARDS, the public key is defined + * by Edwards-Curve Digital Signature Algorithm (EdDSA) [RFC8032]. + * This is a 32-byte string for Edwards25519, and a 57-byte string for Edwards448. + * - For Diffie-Hellman key exchange public keys, with key types for which + * @ref PSA_KEY_TYPE_IS_DH_PUBLIC_KEY is true, the format is the representation of the + * public key `y = g^x mod p` as a big-endian byte string. The + * length of the byte string is the length of the base prime p in bytes. + * Exporting a public key object or the public part of a key pair is always permitted, + * regardless of the key’s usage flags. + * + * @param key Identifier of the key to export. + * @param data Buffer where the key data is to be written. + * @param data_size Size of the @c data buffer in bytes. This must be appropriate for the key: + * - The required output size is @ref PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE( + * @p type, @p bits) where @c type is the key type and @c bits is the key + * size in bits. + * - @ref PSA_EXPORT_PUBLIC_KEY_MAX_SIZE evaluates to the maximum output + * size of any supported public key or public part of a key pair. + * @param data_length On success, the number of bytes that make up the key data. + * + * @return @ref PSA_SUCCESS Success. The first @p (*data_length) bytes of @p data + * contain the exported public key. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier. + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the data buffer is too small. + * @ref PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE() or + * @ref PSA_EXPORT_PUBLIC_KEY_MAX_SIZE can be used to + * determine a sufficient buffer size. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The key is neither a public key nor a key pair. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - The key’s storage location does not support export + * of the key. + * - The implementation does not support export of keys + * with this key type. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_export_public_key(psa_key_id_t key, + uint8_t *data, + size_t data_size, + size_t *data_length); + +/** + * @brief Built-in key generation function. + * + * @details This function generates a random symmetric key. As of yet it does not implement + * asymmetric key generation. + * + * @param attributes + * @param key_buffer + * @param key_buffer_size + * @param key_buffer_length + * @return psa_status_t + */ +psa_status_t psa_builtin_generate_key(const psa_key_attributes_t *attributes, uint8_t *key_buffer, + size_t key_buffer_size, size_t *key_buffer_length); + +/** + * @brief Generate a key or key pair. + * + * @details The key is generated randomly. Its location, policy, type and size are taken from + * @c attributes. + * + * Implementations must reject an attempt to generate a key of size 0. + * + * The following type-specific considerations apply: + * - For RSA keys (@ref PSA_KEY_TYPE_RSA_KEY_PAIR), the public exponent is 65537. + * The modulus is a product of two probabilistic primes between 2^{n-1} and 2^n where n + * is the bit size specified in the attributes. + * + * @param attributes The attributes for the new key. This function uses the attributes as + * follows: + * - The key type is required. It cannot be an asymmetric public key. + * - The key size is required. It must be a valid size for the key type. + * - The key permitted-algorithm policy is required for keys that will be + * used for a cryptographic operation, see Permitted algorithms. + * - The key usage flags define what operations are permitted with the key, + * see Key usage flags. + * - The key lifetime and identifier are required for a persistent key. + * @note This 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 @ref psa_get_key_attributes() with the key’s + * identifier. + * @param key On success, an identifier for the newly created key. @ref PSA_KEY_ID_NULL + * on failure. + * + * @return @ref PSA_SUCCESS Success. If the key is persistent, the key material + * and the key’s metadata have been saved to persistent + * storage. + * @return @ref PSA_ERROR_ALREADY_EXISTS This is an attempt to create a persistent key, and + * there is already a persistent key with the given + * identifier. + * @return @ref PSA_ERROR_NOT_SUPPORTED The key type or key size is not supported, either by + * the implementation in general or in this particular + * persistent location. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The key attributes, as a whole, are invalid. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The key type is an asymmetric public key type. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The key size is not a valid size for the key type. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_INSUFFICIENT_ENTROPY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_INSUFFICIENT_STORAGE + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized + * by @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_generate_key(const psa_key_attributes_t *attributes, + psa_key_id_t *key); + +/** + * @brief Built-in function for random number generation. + * + * @details This function is being used to generate a random number if no other driver for random + * number generation is present. It uses the RIOT RNG module as a default backend. + * + * @param output Output buffer of the size of the random number to be generated. + * @param output_size Size of @c output in bytes + * + * @return @ref PSA_SUCCESS + * @return @ref PSA_ERROR_INVALID_ARGUMENT @c output is NULL + */ +psa_status_t psa_builtin_generate_random( uint8_t *output, + size_t output_size); + +/** + * @brief Generate random bytes. + * + * @warning This function can fail! Callers MUST check the return status and MUST NOT use the + * content of the output buffer if the return status is not @ref PSA_SUCCESS. + * + * @note To generate a key, use @ref psa_generate_key() instead. + * + * @param output Output buffer for the generated data. + * @param output_size Number of bytes to generate and output. + * + * @return @ref PSA_SUCCESS Success. @c output contains @c output_size bytes + * of generated random data. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_ARGUMENT @c output is NULL + * @return @ref PSA_ERROR_NOT_SUPPORTED + * @return @ref PSA_ERROR_INSUFFICIENT_ENTROPY + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + */ +psa_status_t psa_generate_random(uint8_t *output, + size_t output_size); + +/** + * @brief Declare the permitted algorithm policy for a key. + * + * @details The permitted algorithm policy of a key encodes which algorithm or algorithms + * are permitted to be used with this key. + * This function overwrites any permitted algorithm policy previously set in attributes. + * + * @param attributes The attribute object to write to. + * @param alg The permitted algorithm to write. + */ +static inline void psa_set_key_algorithm(psa_key_attributes_t *attributes, + psa_algorithm_t alg) +{ + attributes->policy.alg = alg; +} + +/** + * @brief Retrieve the permitted algorithm policy from key attributes. + * + * @param attributes The key attribute object to query. + * + * @return @ref psa_algorithm_t The algorithm stored in the attribute object. + */ +static inline psa_algorithm_t psa_get_key_algorithm(const psa_key_attributes_t *attributes) +{ + return attributes->policy.alg; +} + +/** + * @brief Declare the size of a key. + * + * @details This function overwrites any key size previously set in attributes. + * + * @param attributes The attribute object to write to. + * @param bits The key size in bits. If this is 0, + * the key size in attributes becomes + * unspecified. Keys of size 0 are not supported. + */ +static inline void psa_set_key_bits(psa_key_attributes_t *attributes, + size_t bits) +{ + attributes->bits = bits; +} + +/** + * @brief Retrieve the key size from key attributes. + * + * @param attributes The key attribute object to query. + * + * @return size_t The key size stored in the attribute object, in bits. + */ +static inline size_t psa_get_key_bits(const psa_key_attributes_t *attributes) +{ + return attributes->bits; +} + +/** + * @brief Declare a key as persistent and set its key identifier. + * + * @details The application must choose a value for id between @ref PSA_KEY_ID_USER_MIN and + * @ref PSA_KEY_ID_USER_MAX. If the attribute object currently declares the key as + * volatile, which is the default lifetime of an attribute object, this function sets + * the lifetime attribute to @ref PSA_KEY_LIFETIME_PERSISTENT. + * + * This function does not access storage, it merely stores the given value in the + * attribute object. The persistent key will be written to storage when the attribute + * object is passed to a key creation function such as @ref psa_import_key(), + * @ref psa_generate_key(), @ref psa_key_derivation_output_key() or @ref psa_copy_key(). + * + * @param attributes The attribute object to write to. + * @param id The persistent identifier for the key. + */ +static inline void psa_set_key_id(psa_key_attributes_t *attributes, psa_key_id_t id) +{ + attributes->id = id; +} + +/** + * @brief Retrieve the key identifier from key attributes. + * + * @param attributes The key attribute object to query. + * + * @return @ref psa_key_id_t The persistent identifier stored in the attribute object. + * This value is unspecified if the attribute object declares + * the key as volatile. + */ +static inline psa_key_id_t psa_get_key_id(const psa_key_attributes_t *attributes) +{ + return attributes->id; +} + +/** + * @brief Set the location of a persistent key. + * + * @details To make a key persistent, give it a persistent key identifier by using + * @ref psa_set_key_id(). By default, a key that has a persistent identifier is stored in + * the default storage area identifier by @ref PSA_KEY_LIFETIME_PERSISTENT. Call this + * function to choose a storage area, or to explicitly declare the key as volatile. + * + * This function does not access storage, it merely stores the given value in the + * attribute object. The persistent key will be written to storage when the attribute + * object is passed to a key creation function such as @ref psa_import_key(), + * @ref psa_generate_key(), @ref psa_key_derivation_output_key() or @ref psa_copy_key(). + * + * @param attributes The attribute object to write to. + * @param lifetime The lifetime for the key. If this is @ref PSA_KEY_LIFETIME_VOLATILE, + * the key will be volatile, and the key identifier attribute is reset + * to @ref PSA_KEY_ID_NULL. + */ +static inline void psa_set_key_lifetime(psa_key_attributes_t *attributes, + psa_key_lifetime_t lifetime) +{ + attributes->lifetime = lifetime; +} + +/** + * @brief Retrieve the lifetime from key attributes. + * + * @param attributes The key attribute object to query. + * + * @return @ref psa_key_lifetime_t The lifetime value stored in the attribute object. + */ +static inline psa_key_lifetime_t psa_get_key_lifetime(const psa_key_attributes_t *attributes) +{ + return attributes->lifetime; +} + +/** + * @brief Declare the type of a key. + * + * @details This function overwrites any key type previously set in @c attributes. + * + * @param attributes The attribute object to write to. + * @param type The key type to write. If this is @ref PSA_KEY_TYPE_NONE, + * the key type in attributes becomes unspecified. + */ +static inline void psa_set_key_type(psa_key_attributes_t *attributes, + psa_key_type_t type) +{ + attributes->type = type; +} + +/** + * @brief Retrieve the key type from key attributes. + * + * @param attributes The key attribute object to query. + * + * @return @ref psa_key_type_t The key type stored in the attribute object. + */ +static inline psa_key_type_t psa_get_key_type(const psa_key_attributes_t *attributes) +{ + return attributes->type; +} + +/** + * @brief Declare usage flags for a key. + * + * @details Usage flags are part of a key’s policy. They encode what kind of operations are + * permitted on the key. For more details, see Key policies. + * + * This function overwrites any usage flags previously set in attributes. + * + * @param attributes The attribute object to write to. + * @param usage_flags The usage flags to write. + */ +static inline void psa_set_key_usage_flags(psa_key_attributes_t *attributes, + psa_key_usage_t usage_flags) +{ + attributes->policy.usage = usage_flags; +} + +/** + * @brief Retrieve the usage flags from key attributes. + * + * @param attributes The key attribute object to query. + * + * @return @ref psa_key_usage_t The usage flags stored in the attribute object. + */ +static inline psa_key_usage_t psa_get_key_usage_flags(const psa_key_attributes_t *attributes) +{ + return attributes->policy.usage; +} + +/** + * @brief Reset a key attribute object to a freshly initialized state. + * + * @details The attribute object must be initialized as described in the documentation of the type + * @ref psa_key_attributes_t before calling this function. Once the object has been + * initialized, this function can be called at any time. + * + * This function frees any auxiliary resources that the object might contain. + * + * @param attributes The attribute object to reset. + */ +static inline void psa_reset_key_attributes(psa_key_attributes_t *attributes) +{ + *attributes = psa_key_attributes_init(); +} + +/** + * @brief Retrieve the attributes of a key. + * + * @details This function first resets the attribute object as with @ref psa_reset_key_attributes(). + * It then copies the attributes of the given key into the given attribute object. + * + * @note This function clears any previous content from the attribute object and therefore + * expects it to be in a valid state. In particular, if this function is called on a newly + * allocated attribute object, the attribute object must be initialized before calling + * this function. + * + * @param key Identifier of the key to query. + * @param attributes On entry, @c *attributes must be in a valid state. On successful return, + * it contains the attributes of the key. On failure, it is equivalent + * to a freshly-initialized attribute object. + * + * @return @ref PSA_SUCCESS + * @return @ref PSA_ERROR_INVALID_HANDLE + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized + * by @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_get_key_attributes(psa_key_id_t key, + psa_key_attributes_t *attributes); + +/** + * @brief Abort a hash operation. + * + * @details Aborting an operation frees all associated resources except for the @p operation + * structure itself. Once aborted, the operation object can be reused for another operation + * by calling @ref psa_hash_setup() again. + * + * You may call this function any time after the operation object has + * been initialized by one of the methods described in @ref psa_hash_operation_t. + * + * In particular, calling @ref psa_hash_abort() after the operation has been + * terminated by a call to @ref psa_hash_abort(), @ref psa_hash_finish() or + * @ref psa_hash_verify() is safe and has no effect. + * + * @param operation Initialized hash operation. + * + * @return @ref PSA_SUCCESS + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_HARDWARE_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized + * by @ref psa_crypto_init(). It is + * implementation-dependent whether a failure to + * initialize results in this error code. + */ +psa_status_t psa_hash_abort(psa_hash_operation_t *operation); + +/** + * @brief Clone a hash operation. + * + * @details This function copies the state of an ongoing hash operation to a new operation object. + * In other words, this function is equivalent to calling @ref psa_hash_setup() on + * @p target_operation with the same algorithm that @p source_operation was set up for, + * then @ref psa_hash_update() on @p target_operation with the same input that that was + * passed to @p source_operation. After this function returns, the two objects are + * independent, i.e. subsequent calls involving one of the objects do not affect the other + * object. + * + * @param source_operation The active hash operation to clone. + * @param target_operation The operation object to set up. + * It must be initialized but not active. + * + * @return @ref PSA_SUCCESS + *@return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The @p source_operation state is not valid: + * it must be active. + * - The @p target_operation state is not valid: + * it must be inactive. + * - The library requires initializing by a call + * to @ref psa_crypto_init(). + *@return @ref PSA_ERROR_COMMUNICATION_FAILURE + *@return @ref PSA_ERROR_HARDWARE_FAILURE + *@return @ref PSA_ERROR_CORRUPTION_DETECTED + *@return @ref PSA_ERROR_INSUFFICIENT_MEMORY + */ +psa_status_t psa_hash_clone(const psa_hash_operation_t *source_operation, + psa_hash_operation_t *target_operation); + +/** + * @brief Calculate the hash (digest) of a message and compare it with a reference value. + * + * @param alg The hash algorithm to compute: a value of type @ref psa_algorithm_t such + * that @ref PSA_ALG_IS_HASH(@p alg) is true. + * @param input Buffer containing the message to hash. + * @param input_length Size of the input buffer in bytes. + * @param hash Buffer containing the expected hash value. + * @param hash_length Size of the hash buffer in bytes. + * + * @return @ref PSA_SUCCESS Success. The expected hash is identical to the + * actual hash of the input. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_SIGNATURE The calculated hash of the message does not match + * the value in hash. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - @p alg is not a hash algorithm. + * - @p input_length is too large for alg. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - @p alg is not supported or is not a hash + * algorithm. + * - @p input_length is too large for the + * implementation. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + */ +psa_status_t psa_hash_compare(psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *hash, + size_t hash_length); + +/** + * @brief Calculate the hash (digest) of a message. + * + * @note To verify the hash of a message against an expected value, + * use @ref psa_hash_compare() instead. + * + * @param alg The hash algorithm to compute: a value of type @ref psa_algorithm_t + * such that @ref PSA_ALG_IS_HASH(@p alg) is true. + * @param input Buffer containing the message to hash. + * @param input_length Size of the @p input buffer in bytes. + * @param hash Buffer where the hash is to be written. + * @param hash_size Size of the @p hash buffer in bytes. + * This must be at least @ref PSA_HASH_LENGTH(@p alg). + * @param hash_length On success, the number of bytes that make up the hash value. + * This is always @ref PSA_HASH_LENGTH(@p alg). + * + * @return @ref PSA_SUCCESS Success. The first @p (*hash_length) bytes of + * @p hash contain the hash value. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the hash buffer is too small. + * @ref PSA_HASH_LENGTH() can be used to determine + * a sufficient buffer size. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - @p alg is not a hash algorithm + * - @p input_length is too large for alg. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - @c alg is not supported or is not a hash algorithm. + * - @c input_length is too large for the implementation. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + */ +psa_status_t psa_hash_compute(psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *hash, + size_t hash_size, + size_t *hash_length); + +/** + * @brief Finish the calculation of the hash of a message. + * + * @details The application must call @ref psa_hash_setup() before calling this function. + * This function calculates the hash of the message formed by concatenating + * the inputs passed to preceding calls to @ref psa_hash_update(). + * + * 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 @ref psa_hash_abort(). + * + * @warning Applications should not call this function if they expect + * a specific value for the hash. Call @ref psa_hash_verify() instead. + * Beware that comparing integrity or authenticity data such as + * hash values with a function such as @c memcmp is risky + * because the time taken by the comparison may leak information + * about the hashed data which could allow an attacker to guess + * a valid hash and thereby bypass security controls. + * + * @param operation Active hash operation. + * @param hash Buffer where the hash is to be written. + * @param hash_size Size of the @p hash buffer in bytes. This must be at least + * @ref PSA_HASH_LENGTH(@p alg) where @p alg is the algorithm that + * the operation performs. + * @param hash_length On success, the number of bytes that make up the hash value. This is always + * @ref PSA_HASH_LENGTH(@p alg) where @p alg is the hash algorithm that is + * calculated. + * + * @return @ref PSA_SUCCESS Success. The first @p (*hash_length) bytes of @p hash + * contain the hash value. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be active. + * - The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the hash buffer is too small. + * @ref PSA_HASH_LENGTH() can be used to determine + * a sufficient buffer size. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + */ +psa_status_t psa_hash_finish(psa_hash_operation_t *operation, + uint8_t *hash, + size_t hash_size, + size_t *hash_length); + +/** + * @brief Set up a multi-part hash operation using the hash suspend state from a previously + * suspended hash operation. + * + * @details See @ref psa_hash_suspend() for an example of how to use this function to suspend + * and resume a hash operation. + * + * After a successful call to @ref psa_hash_resume(), the application must eventually + * terminate the operation. The following events terminate an operation: + * - A successful call to @ref psa_hash_finish(), @ref psa_hash_verify() or + * @ref psa_hash_suspend(). + * - A call to @ref psa_hash_abort(). + * + * @param operation The operation object to set up. It must have been initialized + * as per the documentation for @ref psa_hash_operation_t and not + * yet in use. + * @param hash_state A buffer containing the suspended hash state which is to be + * resumed. This must be in the format output by @ref + * psa_hash_suspend(). + * @param hash_state_length Length of hash_state in bytes. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be + * inactive. + * - The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_ARGUMENT @p hash_state does not correspond to a valid hash + * suspend state. See Hash suspend state format for + * the definition. + * @return @ref PSA_ERROR_NOT_SUPPORTED The provided hash suspend state is for an algorithm + * that is not supported. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + */ +psa_status_t psa_hash_resume(psa_hash_operation_t *operation, + const uint8_t *hash_state, + size_t hash_state_length); + +/** + * @brief Set up a multipart hash operation. + * + * @details The sequence of operations to calculate a hash (message digest) + * is as follows: + * -# Allocate an operation object which will be passed to all the functions listed here. + * -# Initialize the operation object with one of the methods described in the + * documentation for @ref psa_hash_operation_t, e.g. @ref PSA_HASH_OPERATION_INIT. + * -# Call @ref psa_hash_setup() to specify the algorithm. + * -# Call @ref psa_hash_update() zero, one or more times, passing a fragment of the + * message each time. The hash that is calculated is the hash of the concatenation + * of these messages in order. + * -# To calculate the hash, call @ref psa_hash_finish(). To compare the hash with an + * expected value, call @ref psa_hash_verify(). + * + * If an error occurs at any step after a call to @ref psa_hash_setup(), the operation + * will need to be reset by a call to @ref psa_hash_abort(). The application may call + * @ref psa_hash_abort() at any time after the operation has been initialized. + * + * After a successful call to @ref psa_hash_setup(), the application must eventually + * terminate the operation. The following events terminate an operation: + * - A successful call to @ref psa_hash_finish() or @ref psa_hash_verify(). + * - A call to @ref psa_hash_abort(). + * + * @param operation The operation object to set up. It must have been initialized as per the + * documentation for @ref psa_hash_operation_t and not yet in use. + * @param alg The hash algorithm to compute: a value of type @ref psa_algorithm_t such + * that @ref PSA_ALG_IS_HASH(@p alg) is true. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be + * inactive. + * - The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_ARGUMENT @p alg is not a hash algorithm. + * @return @ref PSA_ERROR_NOT_SUPPORTED @p alg is not supported or is not a hash algorithm. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + */ +psa_status_t psa_hash_setup(psa_hash_operation_t *operation, + psa_algorithm_t alg); + +/** + * @brief Halt the hash operation and extract the intermediate state of the hash computation. + * + * @details The application must call @ref psa_hash_setup() or @ref psa_hash_resume() before + * calling this function. This function extracts an intermediate state of the hash + * computation of the message formed by concatenating the inputs passed to preceding + * calls to @ref psa_hash_update(). + * + * This function can be used to halt a hash operation, and then resume the hash operation + * at a later time, or in another application, by transferring the extracted hash suspend + * state to a call to @ref psa_hash_resume(). + * + * 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 @ref psa_hash_abort(). + * + * Hash suspend and resume is not defined for the SHA3 family of hash algorithms. + * Hash suspend state defines the format of the output from @ref psa_hash_suspend(). + * + * @warning Applications must not use any of the hash suspend state as if it was a hash output. + * Instead, the suspend state must only be used to resume a hash operation, and + * @ref psa_hash_finish() or @ref psa_hash_verify() can then calculate or verify the + * final hash value. + * + * ## Usage + * The sequence of operations to suspend and resume a hash operation is as follows: + * -# Compute the first part of the hash. + * -# Allocate an operation object and initialize it as described in the + * documentation for @ref psa_hash_operation_t. + * -# Call @ref psa_hash_setup() to specify the algorithm. + * -# Call @ref psa_hash_update() zero, one or more times, passing a fragment + * of the message each time. + * -# Call @ref psa_hash_suspend() to extract the hash suspend state into a buffer. + * -# Pass the hash state buffer to the application which will resume the operation. + * -# Compute the rest of the hash. + * -# Allocate an operation object and initialize it as described in the + * documentation for @ref psa_hash_operation_t. + * -# Call @ref psa_hash_resume() with the extracted hash state. + * -# Call @ref psa_hash_update() zero, one or more times, passing a fragment + * of the message each time. + * -# To calculate the hash, call @ref psa_hash_finish(). To compare the hash + * with an expected value, call @ref psa_hash_verify(). + * + * If an error occurs at any step after a call to @ref psa_hash_setup() or + * @ref psa_hash_resume(), the operation will need to be reset by a call to + * @ref psa_hash_abort(). The application can call @ref psa_hash_abort() at + * any time after the operation has been initialized. + * + * @param operation Active hash operation. + * @param hash_state Buffer where the hash suspend state is to be written. + * @param hash_state_size Size of the hash_state buffer in bytes. This must be + * appropriate for the selected algorithm: + * - A sufficient output size is @ref + * PSA_HASH_SUSPEND_OUTPUT_SIZE(@p alg) where alg is + * the algorithm that was used to set up the operation. + * - @ref PSA_HASH_SUSPEND_OUTPUT_MAX_SIZE evaluates to + * the maximum output size of any supported hash algorithm. + * @param hash_state_length On success, the number of bytes that make up the hash suspend state. + * + * @return @ref PSA_SUCCESS Success. The first @p (*hash_state_length) bytes of + * @p hash_state contain the intermediate hash state. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be active. + * - The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the hash_state buffer is too small. + * @ref PSA_HASH_SUSPEND_OUTPUT_SIZE() or + * @ref PSA_HASH_SUSPEND_OUTPUT_MAX_SIZE can be used + * to determine a sufficient buffer size. + * @return @ref PSA_ERROR_NOT_SUPPORTED The hash algorithm being computed does not support + * suspend and resume. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + */ +psa_status_t psa_hash_suspend(psa_hash_operation_t *operation, + uint8_t *hash_state, + size_t hash_state_size, + size_t *hash_state_length); + +/** + * @brief Add a message fragment to a multi-part hash operation. + * + * @details The application must call @ref psa_hash_setup() before calling this function. + * If this function returns an error status, the operation enters an error + * state and must be aborted by calling @ref psa_hash_abort(). + * + * @param operation Active hash operation. + * @param input Buffer containing the message fragment to hash. + * @param input_length Size of the @p input buffer in bytes. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be active. + * - The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_ARGUMENT The total input for the operation is too large for the + * hash algorithm. + * @return @ref PSA_ERROR_NOT_SUPPORTED The total input for the operation is too large for the + * implementation. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + */ +psa_status_t psa_hash_update(psa_hash_operation_t *operation, + const uint8_t *input, + size_t input_length); + +/** + * @brief Finish the calculation of the hash of a message and compare it with an expected value. + * + * @details The application must call @ref psa_hash_setup() before calling this function. This + * function calculates the hash of the message formed by concatenating the inputs passed + * to preceding calls to @ref psa_hash_update(). It then compares the calculated hash with + * the expected hash passed as a parameter to this function. + * + * 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 @ref psa_hash_abort(). + * + * @note Implementations shall make the best effort to ensure that the comparison between the + * actual hash and the expected hash is performed in constant time. + * + * @param operation Active hash operation. + * @param hash Buffer containing the expected hash value. + * @param hash_length Size of the @p hash buffer in bytes. + * + * @return @ref PSA_SUCCESS Success. The expected hash is identical to the + * actual hash of the message. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be + * active. + * - The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_SIGNATURE The calculated hash of the message does not match + * the value in hash. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + */ +psa_status_t psa_hash_verify(psa_hash_operation_t *operation, + const uint8_t *hash, + size_t hash_length); + +/** + * @brief Built-in key import function. + * + * @details Copies a plain key into local memory. This function is used by the implementation, + * when an imported key is stored only in local memory. + * + * @param attributes The attributes for the new key. + * This function uses the attributes as follows: + * - The key type is required, and determines how the data buffer is + * interpreted. + * - The key size is always determined from the data buffer. If the + * key size in attributes is nonzero, it must be equal to the size + * determined from data. + * - The key permitted-algorithm policy is required for keys that will + * be used for a cryptographic operation, see Permitted algorithms. + * - The key usage flags define what operations are permitted with the + * key, see Key usage flags. + * - The key lifetime and identifier are required for a persistent key. + * @note This 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 @ref psa_get_key_attributes() + * with the key’s identifier. + * @param data Buffer containing the key data. The content of this buffer is + * interpreted according to the type declared in attributes. All + * implementations must support at least the format described in + * the documentation of @ref psa_export_key() or @ref + * psa_export_public_key() for the chosen type. + * Implementations can support other formats, but be conservative in + * interpreting the key data: it is recommended that implementations + * reject content if it might be erroneous, for example, if it is the + * wrong type or is truncated. + * @param data_length Size of the data buffer in bytes. + * @param key_buffer Pointer to buffer containing the plain text key material + * @param key_buffer_size Size of @p key_buffer in bytes + * @param key_buffer_length Size of the key buffer + * @param bits Size of the key in bits + * + * @return @ref PSA_SUCCESS Success. If the key is persistent, the key material + * and the key’s metadata have been saved to persistent + * storage. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - The key size is nonzero, and is incompatible with + * the key data in @p data. + * @return @ref PSA_ERROR_NOT_SUPPORTED The key attributes, as a whole, are not supported, + * either by the implementation in general or in the + * specified storage location. + */ +psa_status_t psa_builtin_import_key(const psa_key_attributes_t *attributes, + const uint8_t *data, size_t data_length, + uint8_t *key_buffer, size_t key_buffer_size, + size_t *key_buffer_length, size_t *bits); + +/** + * @brief Import a key in binary format. + * + * @details This function supports any output from @ref psa_export_key(). Refer to the + * documentation of @ref psa_export_public_key() for the format of public keys + * and to the documentation of @ref psa_export_key() for the format for other key types. + * + * The key data determines the key size. The attributes can optionally specify a key size; + * in this case it must match the size determined from the key data. A key size of 0 in + * attributes indicates that the key size is solely determined by the key data. + * + * Implementations must reject an attempt to import a key of size 0. + * + * This specification defines a single format for each key type. Implementations can + * optionally support other formats in addition to the standard format. It is recommended + * that implementations that support other formats ensure that the formats are clearly + * unambiguous, to minimize the risk that an invalid input is accidentally interpreted + * according to a different format. + * + * @note The PSA Crypto API does not support asymmetric private key objects outside of a key + * pair. To import a private key, the attributes must specify the corresponding key pair + * type. Depending on the key type, either the import format contains the public key data + * or the implementation will reconstruct the public key from the private key as needed. + * + * @param attributes The attributes for the new key. + * This function uses the attributes as follows: + * - The key type is required, and determines how the data buffer is + * interpreted. + * - The key size is always determined from the data buffer. If the key + * size in attributes is nonzero, it must be equal to the size + * determined from data. + * - The key permitted-algorithm policy is required for keys that will be + * used for a cryptographic operation, see Permitted algorithms. + * - The key usage flags define what operations are permitted with the key, + * see Key usage flags. + * - The key lifetime and identifier are required for a persistent key. + * @note This 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 @ref psa_get_key_attributes() with the key’s identifier. + * + * @param data Buffer containing the key data. The content of this buffer is interpreted + * according to the type declared in attributes. All implementations must + * support at least the format described in the documentation of + * @ref psa_export_key() or @ref psa_export_public_key() for the chosen type. + * Implementations can support other formats, but be conservative in + * interpreting the key data: it is recommended that implementations reject + * content if it might be erroneous, for example, if it is the wrong type or + * is truncated. + * @param data_length Size of the data buffer in bytes. + * @param key On success, an identifier for the newly created key. + * @ref PSA_KEY_ID_NULL on failure. + * + * @return @ref PSA_SUCCESS Success. If the key is persistent, the key material + * and the key’s metadata have been saved to persistent + * storage. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_NOT_PERMITTED The implementation does not permit creating a + * key with the specified attributes due to some + * implementation-specific policy. + * @return @ref PSA_ERROR_ALREADY_EXISTS This is an attempt to create a persistent key, + * and there is already a persistent key with the given + * identifier. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - The key type is invalid. + * - The key size is nonzero, and is incompatible with + * the key data in @p data. + * - 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. + * - The key data is not correctly formatted for the key + * type. + * @return @ref PSA_ERROR_NOT_SUPPORTED The key attributes, as a whole, are not supported, + * either by the implementation in general or in the + * specified storage location. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_INSUFFICIENT_STORAGE + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_import_key(const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length, + psa_key_id_t *key); + +/** + * @brief Abort a key derivation operation. + * + * @details Aborting an operation frees all associated resources except for the operation object + * itself. Once aborted, the operation object can be reused for another operation by + * calling @ref psa_key_derivation_setup() again. + * + * This function can be called at any time after the operation object has been initialized + * as described in @ref psa_key_derivation_operation_t. + * + * In particular, it is valid to call @ref psa_key_derivation_abort() twice, or to call + * @ref psa_key_derivation_abort() on an operation that has not been set up. + * + * @param operation The operation to abort. + * + * @return @ref PSA_SUCCESS Success. The operation object can now be discarded or + * reused. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + */ +psa_status_t psa_key_derivation_abort(psa_key_derivation_operation_t *operation); + +/** + * @brief Retrieve the current capacity of a key derivation operation. + * + * @details The capacity of a key derivation is the maximum number of bytes that it can return. + * Reading N bytes of output from a key derivation operation reduces its capacity by at + * least N. The capacity can be reduced by more than N in the following situations: + * - Calling @ref psa_key_derivation_output_key() can reduce the capacity by more than + * the key size, depending on the type of key being generated. See @ref + * psa_key_derivation_output_key() for details of the key derivation process. + * - When the @ref psa_key_derivation_operation_t object is operating as a deterministic + * random bit generator (DBRG), which reduces capacity in whole blocks, even when less + * than a block is read. + * + * @param operation The operation to query. + * @param capacity On success, the capacity of the operation. + * + * @return @ref PSA_SUCCESS Success. The maximum number of bytes that this key + * derivation can return is (@c *capacity). + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be active. + * - The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + */ +psa_status_t psa_key_derivation_get_capacity(const psa_key_derivation_operation_t *operation, + size_t *capacity); + +/** + * @brief Provide an input for key derivation or key agreement. + * + * @details Which inputs are required and in what order depends on the algorithm. Refer to the + * documentation of each key derivation or key agreement algorithm for information. + * + * This function passes direct inputs, which is usually correct for non-secret inputs. + * To pass a secret input, which is normally in a key object, call @ref + * psa_key_derivation_input_key() instead of this function. Refer to the documentation + * of individual step types (@c PSA_KEY_DERIVATION_INPUT_xxx values of type @ref + * psa_key_derivation_step_t) for more information. + * + * If this function returns an error status, the operation enters an error state and must + * be aborted by calling @ref psa_key_derivation_abort(). + * + * @param operation The key derivation operation object to use. It must have been set up with + * @ref psa_key_derivation_setup() and must not have produced any output yet. + * @param step Which step the input data is for. + * @param data Input data to use. + * @param data_length Size of the data buffer in bytes. + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid for this input step. + * This can happen if the application provides a step + * out of order or repeats a step that may not be + * repeated. + * - The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - @c step is not compatible with the operation’s + * algorithm. + * - @c step does not allow direct inputs. + * - @c data_length is too small or too large for step in + * this particular algorithm. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - @c step is not supported with the operation’s + * algorithm. + * - @c data_length is is not supported for step in this + * particular algorithm. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_key_derivation_input_bytes(psa_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + const uint8_t *data, + size_t data_length); + +/** + * @brief Provide a numeric input for key derivation or key agreement. + * + * @details Which inputs are required and in what order depends on the algorithm. However, when an + * algorithm requires a particular order, numeric inputs usually come first as they tend + * to be configuration parameters. Refer to the documentation of each key derivation or + * key agreement algorithm for information. + * + * This function is used for inputs which are fixed-size non-negative integers. + * + * If this function returns an error status, the operation enters an error state and must + * be aborted by calling @ref psa_key_derivation_abort(). + * + * @param operation The key derivation operation object to use. It must have been set up with + * @ref psa_key_derivation_setup() and must not have produced any output yet. + * @param step Which step the input data is for. + * @param value The value of the numeric input. + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid for this input step. + * This can happen if the application provides a step + * out of order or repeats a step that may not be + * repeated. + * - The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - @c step is not compatible with the operation’s + * algorithm. + * - @c step does not allow numerical inputs. + * - @c value is not valid for step in the operation’s + * algorithm. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - @c step is not supported with the operation’s + * algorithm. + * - @c value is not supported for step in the operation’s + * algorithm. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_key_derivation_input_integer( psa_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + uint64_t value); + +/** + * @brief Provide an input for key derivation in the form of a key. + * + * @details Which inputs are required and in what order depends on the algorithm. Refer to the + * documentation of each key derivation or key agreement algorithm for information. + * + * This function obtains input from a key object, which is usually correct for secret + * inputs or for non-secret personalization strings kept in the key store. To pass a + * non-secret parameter which is not in the key store, call @ref + * psa_key_derivation_input_bytes() instead of this function. Refer to the documentation + * of individual step types (@c PSA_KEY_DERIVATION_INPUT_xxx values of type @ref + * psa_key_derivation_step_t) for more information. + * + * @note Once all inputs steps are completed, the following operations are permitted: + * - @ref psa_key_derivation_output_bytes() — if each input was either a direct + * input or a key with usage flag @ref PSA_KEY_USAGE_DERIVE. + * - @ref psa_key_derivation_output_key() — if the input for step @ref + * PSA_KEY_DERIVATION_INPUT_SECRET or @ref PSA_KEY_DERIVATION_INPUT_PASSWORD was + * a key with usage flag @ref PSA_KEY_USAGE_DERIVE, and every other input was + * either a direct input or a key with usage flag @ref PSA_KEY_USAGE_DERIVE. + * - @ref psa_key_derivation_verify_bytes() — if each input was either a direct + * input or a key with usage flag @ref PSA_KEY_USAGE_VERIFY_DERIVATION. + * - @ref psa_key_derivation_verify_key() — under the same conditions as @ref + * psa_key_derivation_verify_bytes(). + * + * If this function returns an error status, the operation enters an error state and must + * be aborted by calling @ref psa_key_derivation_abort(). + * + * @param operation The key derivation operation object to use. It must have been set up with + * @ref psa_key_derivation_setup() and must not have produced any output yet. + * @param step Which step the input data is for. + * @param key Identifier of the key. The key must have an appropriate type for step, it + * must allow the usage @ref PSA_KEY_USAGE_DERIVE or @ref + * PSA_KEY_USAGE_VERIFY_DERIVATION (see note), and it must permit the + * algorithm used by the operation. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid for this input step. + * This can happen if the application provides a step + * out of order or repeats a step that may not be + * repeated. + * - The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier. + * @return @ref PSA_ERROR_NOT_PERMITTED The key has neither the @ref PSA_KEY_USAGE_DERIVE nor + * the @ref PSA_KEY_USAGE_VERIFY_DERIVATION usage flag, + * or it does not permit the operation’s algorithm. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - @c step is not compatible with the operation’s + * algorithm. + * - @c step does not allow key inputs of the given type, + * or does not allow key inputs at all. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - @c step is not supported with the operation’s + * algorithm. + * - @c Key inputs of the given type are not supported for + * step in the operation’s algorithm. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_key_derivation_input_key(psa_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + psa_key_id_t key); + +/** + * @brief Perform a key agreement and use the shared secret as input to a key derivation. + * + * @details A key agreement algorithm takes two inputs: a private key @c private_key, and a public + * key @c peer_key. The result of this function is passed as input to the key derivation + * operation. The output of this key derivation can be extracted by reading from the + * resulting operation to produce keys and other cryptographic material. + * + * If this function returns an error status, the operation enters an error state and must + * be aborted by calling @ref psa_key_derivation_abort(). + * + * @param operation The key derivation operation object to use. It must have been set + * up with @ref psa_key_derivation_setup() with a key agreement and + * derivation algorithm alg: a value of type @ref psa_algorithm_t such + * that @ref PSA_ALG_IS_KEY_AGREEMENT(@p alg) is true and @ref + * PSA_ALG_IS_RAW_KEY_AGREEMENT(@p alg) is false. + * The operation must be ready for an input of the type given by step. + * @param step Which step the input data is for. + * @param private_key Identifier of the private key to use. It must allow the usage @ref + * PSA_KEY_USAGE_DERIVE. + * @param peer_key Public key of the peer. The peer key must be in the same format that + * @ref psa_import_key() accepts for the public key type corresponding to + * the type of @c private_key. That is, this function performs the + * equivalent of @ref psa_import_key(..., @p peer_key, @p + * peer_key_length), with key attributes indicating the public key type + * corresponding to the type of @c private_key. For example, for ECC keys, + * this means that @c peer_key is interpreted as a point on the curve that + * the private key is on. The standard formats for public keys are + * documented in the documentation of @ref psa_export_public_key(). + * @param peer_key_length Size of @c peer_key in bytes. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid for this key + * agreement step. + * - The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @c private_key is not a valid key identifier. + * @return @ref PSA_ERROR_NOT_PERMITTED @c private_key does not have the @ref + * PSA_KEY_USAGE_DERIVE flag, or it does not permit the + * operation’s algorithm. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - The operation’s algorithm is not a key agreement + * algorithm. + * - @c step does not allow an input resulting from a key + * agreement. + * - @c private_key is not compatible with the operation’s + * algorithm. + * - @c peer_key is not a valid public key corresponding + * to @c private_key. + * @return @ref PSA_ERROR_NOT_SUPPORTED @c private_key is not supported for use with the + * operation’s algorithm. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_key_derivation_key_agreement(psa_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + psa_key_id_t private_key, + const uint8_t *peer_key, + size_t peer_key_length); + +/** + * @brief Read some data from a key derivation operation. + * + * @details This function calculates output bytes from a key derivation algorithm and returns those + * bytes. If the key derivation’s output is viewed as a stream of bytes, this function + * consumes the requested number of bytes from the stream and returns them to the caller. + * The operation’s capacity decreases by the number of bytes read. + * + * If this function returns an error status other than @ref PSA_ERROR_INSUFFICIENT_DATA, + * the operation enters an error state and must be aborted by calling @ref + * psa_key_derivation_abort(). + * + * @param operation The key derivation operation object to read from. + * @param output Buffer where the output will be written. + * @param output_length Number of bytes to output. + * + * @return @ref PSA_SUCCESS Success. The first output_length bytes of output + * contain the derived data. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be + * active, with all required input steps complete. + * - The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_NOT_PERMITTED One of the inputs was a key whose policy did not + * allow @ref PSA_KEY_USAGE_DERIVE. + * @return @ref PSA_ERROR_INSUFFICIENT_DATA The operation’s capacity was less than + * @c output_length bytes. In this case, the following + * occurs: + * - No output is written to the output buffer. + * - The operation’s capacity is set to zero — + * subsequent calls to this function will not + * succeed, even with a smaller output buffer. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_key_derivation_output_bytes(psa_key_derivation_operation_t *operation, + uint8_t *output, + size_t output_length); + +/** + * @brief Derive a key from an ongoing key derivation operation. + * + * @details This function calculates output bytes from a key derivation algorithm and uses those + * bytes to generate a key deterministically. The key’s location, policy, type and size + * are taken from attributes. + * + * If the key derivation’s output is viewed as a stream of bytes, this function consumes + * the required number of bytes from the stream. The operation’s capacity decreases by the + * number of bytes used to derive the key. + * + * If this function returns an error status other than @ref PSA_ERROR_INSUFFICIENT_DATA, + * the operation enters an error state and must be aborted by calling @ref + * psa_key_derivation_abort(). + * + * How much output is produced and consumed from the operation, and how the key is + * derived, depends on the key type. + * + * - For key types for which the key is an arbitrary sequence of bytes of a given size, + * this function is functionally equivalent to calling @ref + * psa_key_derivation_output_bytes() and passing the resulting output to @ref + * psa_import_key(). However, this function has a security benefit: if the + * implementation provides an isolation boundary then the key material is not exposed + * outside the isolation boundary. As a consequence, for these key types, this function + * always consumes exactly @c (bits/8) bytes from the operation. + * The following key types defined in this specification follow this scheme: + * - @ref PSA_KEY_TYPE_AES + * - @ref PSA_KEY_TYPE_ARC4 + * - @ref PSA_KEY_TYPE_ARIA + * - @ref PSA_KEY_TYPE_CAMELLIA + * - @ref PSA_KEY_TYPE_CHACHA20 + * - @ref PSA_KEY_TYPE_SM4 + * - @ref PSA_KEY_TYPE_DERIVE + * - @ref PSA_KEY_TYPE_HMAC + * - @ref PSA_KEY_TYPE_PASSWORD_HASH + * - @ref PSA_KEY_TYPE_DES, 64 bits + * This function generates a key using the following process: + * -# Draw an 8-byte string. + * -# Set/clear the parity bits in each byte. + * -# If the result is a forbidden weak key, discard the result and return to step 1. + * -# Output the string. + * - @ref PSA_KEY_TYPE_DES, 192 bits + * - @ref PSA_KEY_TYPE_DES, 128 bits + * The two or three keys are generated by repeated application of the process used to + * generate a DES key. + * For example, for 3-key 3DES, if the first 8 bytes specify a weak key and the next 8 + * bytes do not, discard the first 8 bytes, use the next 8 bytes as the first key, and + * continue reading output from the operation to derive the other two keys. + * - For Finite-field Diffie-Hellman keys @ref PSA_KEY_TYPE_DH_KEY_PAIR(@p dh_family) + * where @c dh_family designates any Diffie-Hellman family. + * - ECC keys on a Weierstrass elliptic curve (@ref PSA_KEY_TYPE_ECC_KEY_PAIR( + * @p ecc_family) where @c ecc_family designates a Weierstrass curve family.) require + * the generation of a private key which is an integer in the range [1, N - 1], where N + * is the boundary of the private key domain: N is the prime p for Diffie-Hellman, or + * the order of the curve’s base point for ECC. + * Let m be the bit size of N, such that 2^m > N >= 2^(m-1). This function generates the + * private key using the following process: + * -# Draw a byte string of length ceiling(m/8) bytes. + * -# If m is not a multiple of 8, set the most significant (8 * ceiling(m/8) - m) bits + * of the first byte in the string to zero. + * -# Convert the string to integer k by decoding it as a big-endian byte string. + * -# If k > N - 2, discard the result and return to step 1. + * -# Output k + 1 as the private key. + * This method allows compliance to NIST standards, specifically the methods titled + * Key-Pair Generation by Testing Candidates in the following publications: + * - NIST Special Publication 800-56A: Recommendation for Pair-Wise Key-Establishment + * Schemes Using Discrete Logarithm Cryptography SP800-56A §5.6.1.1.4 for + * Diffie-Hellman keys. + * - SP800-56A §5.6.1.2.2 or FIPS Publication 186-4: Digital Signature Standard (DSS) + * FIPS186-4 §B.4.2 for elliptic curve keys. + * - For ECC keys on a Montgomery elliptic curve (where @ref PSA_KEY_TYPE_ECC_KEY_PAIR + * (@ref PSA_ECC_FAMILY_MONTGOMERY)) this function always draws a byte string whose + * length is determined by the curve, and sets the mandatory bits accordingly. That is: + * - Curve25519 (@ref PSA_ECC_FAMILY_MONTGOMERY, 255 bits): draw a 32-byte string and + * process it as specified in Elliptic Curves for Security RFC7748 §5. + * - Curve448 (@ref PSA_ECC_FAMILY_MONTGOMERY, 448 bits): draw a 56-byte string and + * process it as specified in RFC7748 §5. + * + * In all cases, the data that is read is discarded from the operation. The operation’s + * capacity is decreased by the number of bytes read. + * + * For algorithms that take an input step @ref PSA_KEY_DERIVATION_INPUT_SECRET, the input + * to that step must be provided with @ref psa_key_derivation_input_key(). Future versions + * of this specification might include additional restrictions on the derived key based on + * the attributes and strength of the secret key. + * + * @param attributes The attributes for the new key. This function uses the attributes as + * follows: + * - The key type is required. It cannot be an asymmetric public key. + * - The key size is required. It must be a valid size for the key type. + * - The key permitted-algorithm policy is required for keys that will be + * used for a cryptographic operation. + * - If the key type to be created is @ref PSA_KEY_TYPE_PASSWORD_HASH, + * then the permitted-algorithm policy must be the same as the current + * operation’s algorithm. + * - The key usage flags define what operations are permitted with the + * key. + * - The key lifetime and identifier are required for a persistent key. + * @note This 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 @ref psa_get_key_attributes() with the key’s + * identifier. + * @param operation The key derivation operation object to read from. + * @param key On success, an identifier for the newly created key. + * @ref PSA_KEY_ID_NULL on failure. + * @return @ref PSA_SUCCESS Success. If the key is persistent, the key material + * and the key’s metadata have been saved to persistent + * storage. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be active, + * with all required input steps complete. + * - The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_NOT_PERMITTED The following conditions can result in this error: + * - The @ref PSA_KEY_DERIVATION_INPUT_SECRET input step + * was neither provided through a key, nor the result of + * a key agreement. + * - One of the inputs was a key whose policy did not + * allow @ref PSA_KEY_USAGE_DERIVE. + * - The implementation does not permit creating a key + * with the specified attributes due to some + * implementation-specific policy. + * @return @ref PSA_ERROR_ALREADY_EXISTS This is an attempt to create a persistent key, and + * there is already a persistent key with the given + * identifier. + * @return @ref PSA_ERROR_INSUFFICIENT_DATA There was not enough data to create the desired + * key. In this case, the following occurs: + * - No key is generated. + * - The operation’s capacity is set to zero — + * subsequent calls to this function will not + * succeed, even if they require less data. + * @return @ref 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 type is @ref PSA_KEY_TYPE_PASSWORD_HASH, and + * the permitted-algorithm policy is not the same as the + * current operation’s algorithm. + * - 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. + * @return @ref PSA_ERROR_NOT_SUPPORTED The key attributes, as a whole, are not supported, + * either by the implementation in general or in the + * specified storage location. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_INSUFFICIENT_STORAGE + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_key_derivation_output_key(const psa_key_attributes_t *attributes, + psa_key_derivation_operation_t *operation, + psa_key_id_t *key); + +/** + * @brief Set the maximum capacity of a key derivation operation. + * + * @details The capacity of a key derivation operation is the maximum number of bytes that the key + * derivation operation can return from this point onwards. + * + * @param operation The key derivation operation object to modify. + * @param capacity The new capacity of the operation. It must be less or equal to the + * operation’s current capacity. + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be active. + * - The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_ARGUMENT @c capacity is larger than the operation’s current + * capacity. In this case, the operation object remains + * valid and its capacity remains unchanged. + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + */ +psa_status_t psa_key_derivation_set_capacity(psa_key_derivation_operation_t *operation, + size_t capacity); + +/** + * @brief Set up a key derivation operation. + * + * @details A key derivation algorithm takes some inputs and uses them to generate a byte stream in + * a deterministic way. This byte stream can be used to produce keys and other + * cryptographic material. + * + * A key agreement and derivation algorithm uses a key agreement protocol to provide a + * shared secret which is used for the key derivation. See @ref + * psa_key_derivation_key_agreement(). + * + * To derive a key: + * -# Start with an initialized object of type @ref psa_key_derivation_operation_t. + * -# Call @ref psa_key_derivation_setup() to select the algorithm. + * -# Provide the inputs for the key derivation by calling @ref + * psa_key_derivation_input_bytes() or @ref psa_key_derivation_input_key() as + * appropriate. Which inputs are needed, in what order, whether keys are permitted, + * and what type of keys depends on the algorithm. + * -# Optionally set the operation’s maximum capacity with @ref + * psa_key_derivation_set_capacity(). This can be done before, in the middle of, or + * after providing inputs. For some algorithms, this step is mandatory because the + * output depends on the maximum capacity. + * -# To derive a key, call @ref psa_key_derivation_output_key(). To derive a byte string + * for a different purpose, call @ref psa_key_derivation_output_bytes(). Successive + * calls to these functions use successive output bytes calculated by the key + * derivation algorithm. + * -# Clean up the key derivation operation object with @ref psa_key_derivation_abort(). + * + * If this function returns an error, the key derivation operation object is not changed. + * + * If an error occurs at any step after a call to @ref psa_key_derivation_setup(), the + * operation will need to be reset by a call to @ref psa_key_derivation_abort(). + * + * Implementations must reject an attempt to derive a key of size 0. + * + * @param operation The key derivation operation object to set up. It must have been + * initialized but not set up yet. + * @param alg The algorithm to compute. This must be one of the following: + * - A key derivation algorithm: a value of type @ref psa_algorithm_t + * such that @ref PSA_ALG_IS_KEY_DERIVATION(@p alg) is true. + * - A key agreement and derivation algorithm: a value of type @ref + * psa_algorithm_t such that @ref PSA_ALG_IS_KEY_AGREEMENT(@p alg) is + * true and @ref PSA_ALG_IS_RAW_KEY_AGREEMENT(@p alg) is false. + * + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be inactive. + * - The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_ARGUMENT @c alg is neither a key derivation algorithm, nor a key + * agreement and derivation algorithm. + * @return @ref PSA_ERROR_NOT_SUPPORTED @c alg is not supported or is not a key derivation + * algorithm, or a key agreement and derivation algorithm. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + */ +psa_status_t psa_key_derivation_setup(psa_key_derivation_operation_t *operation, + psa_algorithm_t alg); + +/** + * @brief Compare output data from a key derivation operation to an expected value. + * + * @details This function calculates output bytes from a key derivation algorithm and compares + * those bytes to an expected value. If the key derivation’s output is viewed as a stream + * of bytes, this function destructively reads @c output_length bytes from the stream + * before comparing them with @c expected_output. The operation’s capacity decreases by + * the number of bytes read. + * + * This is functionally equivalent to the following code: + * @code + * uint8_t tmp[output_length]; + * psa_key_derivation_output_bytes(operation, tmp, output_length); + * if (memcmp(expected_output, tmp, output_length) != 0) + * return PSA_ERROR_INVALID_SIGNATURE; + * @endcode + * + * However, calling @ref psa_key_derivation_verify_bytes() works even if the key’s policy + * does not allow output of the bytes. + * + * If this function returns an error status other than @ref PSA_ERROR_INSUFFICIENT_DATA or + * @ref PSA_ERROR_INVALID_SIGNATURE, the operation enters an error state and must be + * aborted by calling @ref psa_key_derivation_abort(). + * + * @note Implementations must make the best effort to ensure that the comparison between + * the actual key derivation output and the expected output is performed in + * constant time. + * + * @param operation The key derivation operation object to read from. + * @param expected_output Buffer containing the expected derivation output. + * @param output_length Length ot the expected output. This is also the number of bytes that + * will be read. + * + * @return @ref PSA_SUCCESS Success. The output of the key derivation operation + * matches expected_output. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be + * active, with all required input steps complete. + * - The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_NOT_PERMITTED One of the inputs is a key whose policy does not + * permit @ref PSA_KEY_USAGE_VERIFY_DERIVATION. + * @return @ref PSA_ERROR_INVALID_SIGNATURE The output of the key derivation operation does + * not match the value in expected_output. + * @return @ref PSA_ERROR_INSUFFICIENT_DATA The operation’s capacity was less than + * @c output_length bytes. In this case, the + * operation’s capacity is set to zero — subsequent + * calls to this function will not succeed, even with + * a smaller expected output length. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_key_derivation_verify_bytes(psa_key_derivation_operation_t *operation, + const uint8_t *expected_output, + size_t output_length); + +/** + * @brief Compare output data from a key derivation operation to an expected value stored in a + * key. + * + * @details This function calculates output bytes from a key derivation algorithm and compares + * those bytes to an expected value, provided as key of type @ref + * PSA_KEY_TYPE_PASSWORD_HASH. If the key derivation’s output is viewed as a stream of + * bytes, this function destructively reads the number of bytes corresponding to the + * length of the expected key from the stream before comparing them with the key value. + * The operation’s capacity decreases by the number of bytes read. + * + * This is functionally equivalent to exporting the expected key and calling @ref + * psa_key_derivation_verify_bytes() on the result, except that it works when the key + * cannot be exported. + * + * If this function returns an error status other than @ref PSA_ERROR_INSUFFICIENT_DATA or + * @ref PSA_ERROR_INVALID_SIGNATURE, the operation enters an error state and must be + * aborted by calling @ref psa_key_derivation_abort(). + * + * @note Implementations must make the best effort to ensure that the comparison between + * the actual key derivation output and the expected output is performed in + * constant time. + * + * @param operation The key derivation operation object to read from. + * @param expected A key of type @ref PSA_KEY_TYPE_PASSWORD_HASH containing the expected + * output. The key must allow the usage @ref PSA_KEY_USAGE_VERIFY_DERIVATION, + * and the permitted algorithm must match the operation’s algorithm. + * The value of this key is typically computed by a previous call to @ref + * psa_key_derivation_output_key(). + + * @return @ref PSA_SUCCESS Success. The output of the key derivation operation + * matches the expected key value. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be + * active, with all required input steps complete. + * - The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @c expected is not a valid key identifier. + * @return @ref PSA_ERROR_NOT_PERMITTED The following conditions can result in this error: + * - The key does not have the @ref + * PSA_KEY_USAGE_VERIFY_DERIVATION flag, or it does + * not permit the requested algorithm. + * - One of the inputs is a key whose policy does not + * permit @ref PSA_KEY_USAGE_VERIFY_DERIVATION. + * @return @ref PSA_ERROR_INVALID_SIGNATURE The output of the key derivation operation does not + * match the value of the expected key. + * @return @ref PSA_ERROR_INSUFFICIENT_DATA The operation’s capacity was less than the length + * of the @c expected key. In this case, the + * operation’s capacity is set to zero — subsequent + * calls to this function will not succeed, even with + * a smaller expected key length. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The key type is not @ref PSA_KEY_TYPE_PASSWORD_HASH. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_key_derivation_verify_key(psa_key_derivation_operation_t *operation, + psa_key_id_t expected); + +/** + * @brief Abort a MAC operation. + * + * @details Aborting an operation frees all associated resources except for the operation object + * itself. Once aborted, the operation object can be reused for another operation by + * calling @ref psa_mac_sign_setup() or @ref psa_mac_verify_setup() again. + * + * This function can be called any time after the operation object has been initialized by + * one of the methods described in @ref psa_mac_operation_t. + * + * In particular, calling @ref psa_mac_abort() after the operation has been terminated + * by a call to @ref psa_mac_abort(), @ref psa_mac_sign_finish() or @ref + * psa_mac_verify_finish() is safe and has no effect. + * + * @param operation Initialized MAC operation. + * @return @ref PSA_SUCCESS Success. The operation object can now be discarded or + * reused. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + */ +psa_status_t psa_mac_abort(psa_mac_operation_t *operation); + +/** + * @brief Calculate the message authentication code (MAC) of a message. + * + * @note To verify the MAC of a message against an expected value, use @ref psa_mac_verify() + * instead. Beware that comparing integrity or authenticity data such as MAC values with a + * function such as @c memcmp() is risky because the time taken by the comparison might + * leak information about the MAC value which could allow an attacker to guess a valid MAC + * and thereby bypass security controls. + * + * @param key Identifier of the key to use for the operation. It must allow the usage + * @ref PSA_KEY_USAGE_SIGN_MESSAGE. + * @param alg The MAC algorithm to compute (PSA_ALG_XXX value such that @ref + * PSA_ALG_IS_MAC(@p alg) is true). + * @param input Buffer containing the input message. + * @param input_length Size of the input buffer in bytes. + * @param mac Buffer where the MAC value is to be written. + * @param mac_size Size of the mac buffer in bytes. This must be appropriate for the + * selected algorithm and key: + * - The exact MAC size is @ref PSA_MAC_LENGTH(@p key_type, @p key_bits, + * @p alg) where @c key_type and @c key_bits are attributes of the key + * used to compute the MAC. + * - @ref PSA_MAC_MAX_SIZE evaluates to the maximum MAC size of any + * supported MAC algorithm. + * @param mac_length On success, the number of bytes that make up the MAC value. + * + * @return @ref PSA_SUCCESS Success. The first @c (*mac_length) bytes of @c mac contain + * the MAC value. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier. + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref + * PSA_KEY_USAGE_SIGN_MESSAGE flag, or it does not permit + * the requested algorithm. + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the mac buffer is too small. @ref + * PSA_MAC_LENGTH() or @ref PSA_MAC_MAX_SIZE can be used + * to determine a sufficient buffer size. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - @c alg is not a MAC algorithm. + * - @c key is not compatible with @c alg. + * - @c input_length is too large for @c alg. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - @c alg is not supported or is not a MAC algorithm. + * - @c key is not supported for use with @c alg. + * - @c input_length is too large for the implementation. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_mac_compute(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *mac, + size_t mac_size, + size_t *mac_length); + +/** + * @brief Finish the calculation of the MAC of a message. + * + * @details The application must call @ref psa_mac_sign_setup() before calling this function. This + * function calculates the MAC of the message formed by concatenating the inputs passed to + * preceding calls to @ref psa_mac_update(). + * + * 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 @ref psa_mac_abort(). + * + * @warning It is not recommended to use this function when a specific value is expected for the + * MAC. Call @ref psa_mac_verify_finish() instead with the expected MAC value. + * Comparing integrity or authenticity data such as MAC values with a function such as + * @c memcmp() is risky because the time taken by the comparison might leak information + * about the hashed data which could allow an attacker to guess a valid MAC and thereby + * bypass security controls. + * + * @param operation Active MAC operation. + * @param mac Buffer where the MAC value is to be written. + * @param mac_size Size of the mac buffer in bytes. This must be appropriate for the selected + * algorithm and key: + * - The exact MAC size is @ref PSA_MAC_LENGTH(@p key_type, @p key_bits, + * @p alg) where @c key_type and @c key_bits are attributes of the key, + * and @c alg is the algorithm used to compute the MAC. + * - @ref PSA_MAC_MAX_SIZE evaluates to the maximum MAC size of any supported + * MAC algorithm. + * @param mac_length On success, the number of bytes that make up the MAC value. This is always + * @ref PSA_MAC_LENGTH(@p key_type, @p key_bits, @p alg) where @c key_type and + * @c key_bits are attributes of the key, and @c alg is the algorithm used to + * compute the MAC. + * @return @ref PSA_SUCCESS Success. The first @c (*mac_length) bytes of mac + * contain the MAC value. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be an + * active mac sign operation. + * - The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the mac buffer is too small. @ref + * PSA_MAC_LENGTH() or @ref PSA_MAC_MAX_SIZE can be used + * to determine a sufficient buffer size. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_mac_sign_finish(psa_mac_operation_t *operation, + uint8_t *mac, + size_t mac_size, + size_t *mac_length); + +/** + * @brief Set up a multi-part MAC calculation operation. + * + * @details This function sets up the calculation of the message authentication code (MAC) + * of a byte string. To verify the MAC of a message against an expected value, + * use @ref psa_mac_verify_setup() instead. + * + * The sequence of operations to calculate a MAC is as follows: + * -# Allocate an operation object which will be passed to all the functions listed here. + * -# Initialize the operation object with one of the methods described in the + * documentation for @ref psa_mac_operation_t, e.g. @ref PSA_MAC_OPERATION_INIT. + * -# Call @ref psa_mac_sign_setup() to specify the algorithm and key. + * -# Call @ref psa_mac_update() zero, one or more times, passing a fragment of the + * message each time. The MAC that is calculated is the MAC of the concatenation of + * these messages in order. + * -# At the end of the message, call @ref psa_mac_sign_finish() to finish calculating the + * MAC value and retrieve it. + * + * If an error occurs at any step after a call to @ref psa_mac_sign_setup(), the operation + * will need to be reset by a call to @ref psa_mac_abort(). The application can call @ref + * psa_mac_abort() at any time after the operation has been initialized. + * + * After a successful call to @ref psa_mac_sign_setup(), the application must eventually + * terminate the operation through one of the following methods: + * - A successful call to @ref psa_mac_sign_finish(). + * - A call to @ref psa_mac_abort(). + * + * @param operation The operation object to set up. It must have been initialized as per the + * documentation for @ref psa_mac_operation_t and not yet in use. + * @param key Identifier of the key to use for the operation. It must remain valid until + * the operation terminates. It must allow the usage @ref + * PSA_KEY_USAGE_SIGN_MESSAGE. + * @param alg The MAC algorithm to compute: a value of type @ref psa_algorithm_t such + * that @ref PSA_ALG_IS_MAC(@p alg) is true. + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be inactive. + * - The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier. + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref + * PSA_KEY_USAGE_SIGN_MESSAGE flag, or it does not permit + * the requested algorithm. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - @c alg is not a MAC algorithm. + * - @c key is not compatible with @c alg. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - @c alg is not supported or is not a MAC algorithm. + * - @c key is not supported for use with @c alg. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_mac_sign_setup(psa_mac_operation_t *operation, + psa_key_id_t key, + psa_algorithm_t alg); + +/** + * @brief Add a message fragment to a multi-part MAC operation. + * + * @details The application must call @ref psa_mac_sign_setup() or @ref psa_mac_verify_setup() + * before calling this function. + * + * If this function returns an error status, the operation enters an error state and must + * be aborted by calling @ref psa_mac_abort(). + * + * @param operation Active MAC operation. + * @param input Buffer containing the message fragment to add to the MAC calculation. + * @param input_length Size of the @c input buffer in bytes. + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be active. + * - The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_ARGUMENT The total input for the operation is too large for the + * MAC algorithm. + * @return @ref PSA_ERROR_NOT_SUPPORTED The total input for the operation is too large for the + * implementation. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_mac_update(psa_mac_operation_t *operation, + const uint8_t *input, + size_t input_length); + +/** + * @brief Calculate the MAC of a message and compare it with a reference value. + * + * @param key Identifier of the key to use for the operation. It must allow the usage + * @ref PSA_KEY_USAGE_VERIFY_MESSAGE. + * @param alg The MAC algorithm to compute: a value of type @ref psa_algorithm_t such + * that @ref PSA_ALG_IS_MAC(@p alg) is true. + * @param input Buffer containing the input message. + * @param input_length Size of the @c input buffer in bytes. + * @param mac Buffer containing the expected MAC value. + * @param mac_length Size of the @c mac buffer in bytes. + * @return @ref PSA_SUCCESS Success. The expected MAC is identical to the + * actual MAC of the input. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier. + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref + * PSA_KEY_USAGE_VERIFY_MESSAGE flag, or it does not + * permit the requested algorithm. + * @return @ref PSA_ERROR_INVALID_SIGNATURE The calculated MAC of the message does not match + * the value in @c mac. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - @c alg is not a MAC algorithm. + * - @c key is not compatible with @c alg. + * - @c input_length is too large for @c alg. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - @c alg is not supported or is not a MAC algorithm. + * - @c key is not supported for use with @c alg. + * - @c input_length is too large for the + * implementation. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_mac_verify(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *mac, + size_t mac_length); + +/** + * @brief Finish the calculation of the MAC of a message and compare it with an expected value. + * + * @details The application must call @ref psa_mac_verify_setup() before calling this function. + * This function calculates the MAC of the message formed by concatenating the inputs + * passed to preceding calls to @ref psa_mac_update(). It then compares the calculated MAC + * with the expected MAC passed as a parameter to this function. + * + * 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 @ref psa_mac_abort(). + * + * @note Implementations must make the best effort to ensure that the comparison between the + * actual MAC and the expected MAC is performed in constant time. + * + * @param operation Active MAC operation. + * @param mac Buffer containing the expected MAC value. + * @param mac_length Size of the @c mac buffer in bytes. + * + * @return @ref PSA_SUCCESS Success. The expected MAC is identical to the + * actual MAC of the message. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be an + * active mac verify operation. + * - The library requires initializing by a call to + * @ref psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_SIGNATURE The calculated MAC of the message does not match + * the value in mac. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_mac_verify_finish(psa_mac_operation_t *operation, + const uint8_t *mac, + size_t mac_length); + +/** + * @brief Set up a multi-part MAC verification operation. + * + * @details This function sets up the verification of the message authentication code (MAC) of a + * byte string against an expected value. + * + * The sequence of operations to verify a MAC is as follows: + * -# Allocate an operation object which will be passed to all the functions listed here. + * -# Initialize the operation object with one of the methods described in the + * documentation for @ref psa_mac_operation_t, e.g. @ref PSA_MAC_OPERATION_INIT. + * -# Call @ref psa_mac_verify_setup() to specify the algorithm and key. + * -# Call @ref psa_mac_update() zero, one or more times, passing a fragment of the + * message each time. The MAC that is calculated is the MAC of the concatenation of + * these messages in order. + * -# At the end of the message, call @ref psa_mac_verify_finish() to finish calculating + * the actual MAC of the message and verify it against the expected value. + * + * If an error occurs at any step after a call to @ref psa_mac_verify_setup(), the + * operation will need to be reset by a call to @ref psa_mac_abort(). The application can + * call @ref psa_mac_abort() at any time after the operation has been initialized. + * + * After a successful call to @ref psa_mac_verify_setup(), the application must eventually + * terminate the operation through one of the following methods: + * - A successful call to @ref psa_mac_verify_finish(). + * - A call to @ref psa_mac_abort(). + + * @param operation The operation object to set up. It must have been initialized as per the + * documentation for @ref psa_mac_operation_t and not yet in use. + * @param key Identifier of the key to use for the operation. It must remain valid until + * the operation terminates. It must allow the usage @ref + * PSA_KEY_USAGE_VERIFY_MESSAGE. + * @param alg The MAC algorithm to compute: a value of type @ref psa_algorithm_t such + * that @ref PSA_ALG_IS_MAC(@p alg) is true. + * @return @ref PSA_SUCCESS Success. + * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error: + * - The operation state is not valid: it must be inactive. + * - The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier. + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref + * PSA_KEY_USAGE_VERIFY_MESSAGE flag, or it does not + * permit the requested algorithm. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - @c alg is not a MAC algorithm. + * - @c key is not compatible with @c alg. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - @c alg is not supported or is not a MAC algorithm. + * - @c key is not supported for use with @c alg. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_mac_verify_setup(psa_mac_operation_t *operation, + psa_key_id_t key, + psa_algorithm_t alg); + +/** + * @brief Remove non-essential copies of key material from memory. + * + * @details For keys that have been created with the @ref PSA_KEY_USAGE_CACHE usage flag, an + * implementation is permitted to make additional copies of the key material that are + * not in storage and not for the purpose of ongoing operations. + * + * This function will remove these extra copies of the key material from memory. + * + * This function is not required to remove key material from memory in any of the + * following situations: + * - The key is currently in use in a cryptographic operation. + * - The key is volatile. + + * @param key Identifier of the key to purge. + * @return @ref PSA_SUCCESS Success. The key material has been removed from memory, + * if the key material is not currently required. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier. + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_purge_key(psa_key_id_t key); + +/** + * @brief Perform a key agreement and return the raw shared secret. + * + * @warning The raw result of a key agreement algorithm such as finite-field Diffie-Hellman or + * elliptic curve Diffie-Hellman has biases, and is not suitable for use as key material. + * Instead it is recommended that the result is used as input to a key derivation + * algorithm. To chain a key agreement with a key derivation, use @ref + * psa_key_derivation_key_agreement() and other functions from the key derivation + * interface. + * + * @param alg The key agreement algorithm to compute: a value of type @ref + * psa_algorithm_t such that @ref PSA_ALG_IS_RAW_KEY_AGREEMENT(@c alg) + * is true. + * @param private_key Identifier of the private key to use. It must allow the usage @ref + * PSA_KEY_USAGE_DERIVE. + * @param peer_key Public key of the peer. The peer key must be in the same format that + * @ref psa_import_key() accepts for the public key type corresponding to + * the type of private_key. That is, this function performs the equivalent + * of @ref psa_import_key(..., @p peer_key, @p peer_key_length), with key + * attributes indicating the public key type corresponding to the type of + * @c private_key. For example, for ECC keys, this means that @c peer_key + * is interpreted as a point on the curve that the private key is on. The + * standard formats for public keys are documented in the documentation of + * @ref psa_export_public_key(). + * @param peer_key_length Size of peer_key in bytes. + * @param output Buffer where the raw shared secret is to be written. + * @param output_size Size of the output buffer in bytes. This must be appropriate for the + * keys: + * - The required output size is @ref PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE + * (@p type, @p bits) where type is the type of @c private_key and @c + * bits is the bit-size of either @c private_key or the @c peer_key. + * - @ref PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE evaluates to the maximum + * output size of any supported raw key agreement algorithm. + * @param output_length On success, the number of bytes that make up the returned output. + * + * @return @ref PSA_SUCCESS Success. The first (*output_length) bytes of output + * contain the raw shared secret. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @c private_key is not a valid key identifier. + * @return @ref PSA_ERROR_NOT_PERMITTED @c private_key does not have the @ref + * PSA_KEY_USAGE_DERIVE flag, or it does not permit + * the requested algorithm. + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the output buffer is too small. + * @ref PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE() or @ref + * PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE can be used to + * determine a sufficient buffer size. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - @c alg is not a key agreement algorithm. + * - @c private_key is not compatible with @c alg. + * - @c peer_key is not a valid public key corresponding + * to @c private_key. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - @c alg is not supported or is not a key agreement + * algorithm. + * - @c private_key is not supported for use with @c alg. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_raw_key_agreement(psa_algorithm_t alg, + psa_key_id_t private_key, + const uint8_t *peer_key, + size_t peer_key_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Sign an already-calculated hash with a private key. + * + * @details With most signature mechanisms that follow the hash-and-sign paradigm, the hash input + * to this function is the hash of the message to sign. The hash algorithm is encoded in + * the signature algorithm. + * + * Some hash-and-sign mechanisms apply a padding or encoding to the hash. In such cases, + * the encoded hash must be passed to this function. The current version of this + * specification defines one such signature algorithm: @ref PSA_ALG_RSA_PKCS1V15_SIGN_RAW. + * + * @note To perform a hash-and-sign signature algorithm, the hash must be calculated before + * passing it to this function. This can be done by calling @ref psa_hash_compute() or + * with a multi-part hash operation. The correct hash algorithm to use can be determined + * using @ref PSA_ALG_GET_HASH(). + * + * Alternatively, to hash and sign a message in a single call, use @ref psa_sign_message(). + * + * @param key Identifier of the key to use for the operation. It must be an + * asymmetric key pair. The key must allow the usage @ref + * PSA_KEY_USAGE_SIGN_HASH. + * @param alg An asymmetric signature algorithm that separates the hash and sign + * operations: a value of type @ref psa_algorithm_t such that @ref + * PSA_ALG_IS_SIGN_HASH(@p alg) is true. + * @param hash The input to sign. This is usually the hash of a message. See the + * detailed description of this function and the description of + * individual signature algorithms for a detailed description of + * acceptable inputs. + * @param hash_length Size of the hash buffer in bytes. + * @param signature Buffer where the signature is to be written. + * @param signature_size Size of the signature buffer in bytes. This must be appropriate for + * the selected algorithm and key: + * - The required signature size is @ref PSA_SIGN_OUTPUT_SIZE(@p + * key_type, @p key_bits, @p alg) where @c key_type and @c key_bits + * are the type and bit-size respectively of @c key. + * - @ref PSA_SIGNATURE_MAX_SIZE evaluates to the maximum signature + * size of any supported signature algorithm. + * @param signature_length On success, the number of bytes that make up the returned signature + * value. + * @return @ref PSA_SUCCESS Success. The first @c (*signature_length) bytes of + * @c signature contain the signature value. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier. + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref PSA_KEY_USAGE_SIGN_HASH + * flag, or it does not permit the requested algorithm. + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the signature buffer is too small. + * @ref PSA_SIGN_OUTPUT_SIZE() or @ref + * PSA_SIGNATURE_MAX_SIZE can be used to determine a + * sufficient buffer size. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - @c alg is not an asymmetric signature algorithm. + * - @c key is not an asymmetric key pair, that is + * compatible with @c alg. + * - @c hash_length is not valid for the algorithm and key + * type. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - @c alg is not supported or is not an asymmetric + * signature algorithm. + * - @c key is not supported for use with alg. + * @return @ref PSA_ERROR_INSUFFICIENT_ENTROPY + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_sign_hash(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *hash, + size_t hash_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length); + +/** + * @brief Sign a message with a private key. For hash-and-sign algorithms, this includes the + * hashing step. + * + * @note To perform a multi-part hash-and-sign signature algorithm, first use a multi-part hash + * operation and then pass the resulting hash to @ref psa_sign_hash(). + * @ref PSA_ALG_GET_HASH(@p alg) can be used to determine the hash algorithm to use. + * + * @param key Identifier of the key to use for the operation. It must be an + * asymmetric key pair. The key must allow the usage @ref + * PSA_KEY_USAGE_SIGN_MESSAGE. + * @param alg An asymmetric signature algorithm: a value of type @ref + * psa_algorithm_t such that @ref PSA_ALG_IS_SIGN_MESSAGE(@p alg) is + * true. + * @param input The input message to sign. + * @param input_length Size of the input buffer in bytes. + * @param signature Buffer where the signature is to be written. + * @param signature_size Size of the signature buffer in bytes. This must be appropriate for + * the selected algorithm and key: + * - The required signature size is @ref PSA_SIGN_OUTPUT_SIZE + * (@p key_type, @p key_bits, @p alg) where @c key_type and + * @c key_bits are the type and bit-size respectively of @c key. + * - @ref PSA_SIGNATURE_MAX_SIZE evaluates to the maximum signature + * size of any supported signature algorithm. + * @param signature_length On success, the number of bytes that make up the returned signature + * value. + * @return @ref PSA_SUCCESS Success. The first @c (*signature_length) bytes of + * @c signature contain the signature value. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier. + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref + * PSA_KEY_USAGE_SIGN_MESSAGE flag, or it does not permit + * the requested algorithm. + * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the signature buffer is too small. + * @ref PSA_SIGN_OUTPUT_SIZE() or @ref + * PSA_SIGNATURE_MAX_SIZE can be used to determine a + * sufficient buffer size. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - @c alg is not an asymmetric signature algorithm. + * - @c key is not an asymmetric key pair, that is + * compatible with @c alg. + * - @c input_length is too large for the algorithm and + * key type. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - @c alg is not supported or is not an asymmetric + * signature algorithm. + * - @c key is not supported for use with @c alg. + * - @c input_length is too large for the implementation. + * @return @ref PSA_ERROR_INSUFFICIENT_ENTROPY + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_sign_message(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length); + +/** + * @brief Verify the signature of a hash or short message using a public key. + * + * @details With most signature mechanisms that follow the hash-and-sign paradigm, the hash input + * to this function is the hash of the message to sign. The hash algorithm is encoded in + * the signature algorithm. + * + * Some hash-and-sign mechanisms apply a padding or encoding to the hash. In such cases, + * the encoded hash must be passed to this function. The current version of this + * specification defines one such signature algorithm: @ref PSA_ALG_RSA_PKCS1V15_SIGN_RAW. + * + * @note To perform a hash-and-sign verification algorithm, the hash must be calculated before + * passing it to this function. This can be done by calling @ref psa_hash_compute() or + * with a multi-part hash operation. Alternatively, to hash and verify a message signature + * in a single call, use @ref psa_verify_message(). + * + * @note When using secure elements as backends in this implementation, the key type can only be + * of type @ref PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve) and must be stored on a secure element. + * To use the public key of a previously generated key pair, please export the public key + * first and then import it as a separate key with its own attributes and identifier. + * + * @param key Identifier of the key to use for the operation. It must be a public key + * or an asymmetric key pair. The key must allow the usage @ref + * PSA_KEY_USAGE_VERIFY_HASH. + * @param alg An asymmetric signature algorithm that separates the hash and sign + * operations (PSA_ALG_XXX value such that @ref PSA_ALG_IS_SIGN_HASH(@p + * alg) is true), that is compatible with the type of key. + * @param hash The input whose signature is to be verified. This is usually the hash + * of a message. See the detailed description of this function and the + * description of individual signature algorithms for a detailed + * description of acceptable inputs. + * @param hash_length Size of the hash buffer in bytes. + * @param signature Buffer containing the signature to verify. + * @param signature_length Size of the signature buffer in bytes. + * + * @return @ref PSA_SUCCESS Success. The signature is valid. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier. + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref + * PSA_KEY_USAGE_VERIFY_HASH flag, or it does not + * permit the requested algorithm. + * @return @ref PSA_ERROR_INVALID_SIGNATURE @c signature is not the result of signing hash with + * algorithm @c alg using the private key + * corresponding to @c key. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - @c alg is not an asymmetric signature algorithm. + * - @c key is not a public key or an asymmetric key + * pair, that is compatible with @c alg. + * - @c hash_length is not valid for the algorithm and + * key type. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - @c alg is not supported or is not an asymmetric + * signature algorithm. + * - @c key is not supported for use with @c alg. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_verify_hash(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *hash, + size_t hash_length, + const uint8_t *signature, + size_t signature_length); + +/** + * @brief Verify the signature of a message with a public key. For hash-and-sign algorithms, + * this includes the hashing step. + * + * @note To perform a multi-part hash-and-sign signature verification algorithm, first use a + * multi-part hash operation to hash the message and then pass the resulting hash to @ref + * psa_verify_hash(). @ref PSA_ALG_GET_HASH(@p alg) can be used to determine the hash + * algorithm to use. + * + * @param key Identifier of the key to use for the operation. It must be a public + * key or an asymmetric key pair. The key must allow the usage @ref + * PSA_KEY_USAGE_VERIFY_MESSAGE. + * @param alg An asymmetric signature algorithm: a value of type @ref + * psa_algorithm_t such that @ref PSA_ALG_IS_SIGN_MESSAGE(@p alg) + * is true. + * @param input The message whose signature is to be verified. + * @param input_length Size of the @c input buffer in bytes. + * @param signature Buffer containing the signature to verify. + * @param signature_length Size of the @c signature buffer in bytes. + * + * @return @ref PSA_SUCCESS Success. The signature is valid. + * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref + * psa_crypto_init(). + * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier. + * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref + * PSA_KEY_USAGE_VERIFY_MESSAGE flag, or it does not + * permit the requested algorithm. + * @return @ref PSA_ERROR_INVALID_SIGNATURE @c signature is not the result of signing the input + * message with algorithm @c alg using the private key + * corresponding to @c key. + * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error: + * - @c alg is not an asymmetric signature algorithm. + * - @c key is not a public key or an asymmetric key + * pair, that is compatible with @c alg. + * - @c input_length is too large for the algorithm + * and key type. + * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error: + * - @c alg is not supported or is not an asymmetric + * signature algorithm. + * - @c key is not supported for use with @c alg. + * - @c input_length is too large for the + * implementation. + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_COMMUNICATION_FAILURE + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_STORAGE_FAILURE + * @return @ref PSA_ERROR_DATA_CORRUPT + * @return @ref PSA_ERROR_DATA_INVALID + */ +psa_status_t psa_verify_message(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *signature, + size_t signature_length); + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTO_PSA_CRYPTO_H */ +/** @} */ diff --git a/sys/include/psa_crypto/psa/crypto_contexts.h b/sys/include/psa_crypto/psa/crypto_contexts.h new file mode 100644 index 0000000000..246116316a --- /dev/null +++ b/sys/include/psa_crypto/psa/crypto_contexts.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @{ + * + * @file crypto_contexts.h + * @brief Context definitions for PSA Crypto + * + * @author Lena Boeckmann + * + */ + +#ifndef PSA_CRYPTO_PSA_CRYPTO_CONTEXTS_H +#define PSA_CRYPTO_PSA_CRYPTO_CONTEXTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "kernel_defines.h" + +#include "psa/crypto_includes.h" + + +#if IS_USED(MODULE_PSA_HASH) +/** + * @brief Structure containing the hash contexts needed by the application. + */ +typedef union { +#if IS_USED(MODULE_PSA_HASH_MD5) || defined(DOXYGEN) + psa_hashes_md5_ctx_t md5; /**< MD5 context */ +#endif +#if IS_USED(MODULE_PSA_HASH_SHA_1) || defined(DOXYGEN) + psa_hashes_sha1_ctx_t sha1; /**< SHA-1 context */ +#endif +#if IS_USED(MODULE_PSA_HASH_SHA_224) || defined(DOXYGEN) + psa_hashes_sha224_ctx_t sha224; /**< SHA-224 context */ +#endif +#if IS_USED(MODULE_PSA_HASH_SHA_256) || defined(DOXYGEN) + psa_hashes_sha256_ctx_t sha256; /**< SHA-256 context */ +#endif +#if IS_USED(MODULE_PSA_HASH_SHA_512) || defined(DOXYGEN) + psa_hashes_sha512_ctx_t sha512; /**< SHA-512 context */ +#endif +} psa_hash_context_t; +#endif + +#if IS_USED(MODULE_PSA_CIPHER) +/** + * @brief Structure containing the cipher contexts needed by the application. + */ +typedef union { +#if IS_USED(MODULE_PSA_CIPHER_AES_128_ECB) ||\ + IS_USED(MODULE_PSA_CIPHER_AES_128_CBC) ||\ + defined(DOXYGEN) + psa_cipher_aes_128_ctx_t aes_128; /**< AES 128 context*/ +#endif +#if IS_USED(MODULE_PSA_CIPHER_AES_192_CBC) || defined(DOXYGEN) + psa_cipher_aes_192_ctx_t aes_192; /**< AES 192 context*/ +#endif +#if IS_USED(MODULE_PSA_CIPHER_AES_256_CBC) || defined(DOXYGEN) + psa_cipher_aes_256_ctx_t aes_256; /**< AES 256 context*/ +#endif +} psa_cipher_context_t; +#endif + +#if IS_USED(MODULE_PSA_SECURE_ELEMENT) +/** + * @brief Structure containing the secure element specific cipher contexts needed by the + * application. + */ +typedef struct { + psa_encrypt_or_decrypt_t direction; /**< Direction of this cipher operation */ + /** Structure containing a driver specific cipher context */ + union driver_context { + unsigned dummy; /**< Make the union non-empty even with no supported algorithms. */ + #if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) || defined(DOXYGEN) + atca_aes_cbc_ctx_t atca_aes_cbc; /**< ATCA AES CBC context*/ + #endif + } drv_ctx; /**< SE specific cipher operation context */ +} psa_se_cipher_context_t; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTO_PSA_CRYPTO_CONTEXTS_H */ +/** @} */ diff --git a/sys/include/psa_crypto/psa/crypto_includes.h b/sys/include/psa_crypto/psa/crypto_includes.h new file mode 100644 index 0000000000..128602ea4c --- /dev/null +++ b/sys/include/psa_crypto/psa/crypto_includes.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @{ + * + * @brief Files to include in the build of PSA Crypto + * + * @author Lena Boeckmann + * + */ + +#ifndef PSA_CRYPTO_PSA_CRYPTO_INCLUDES_H +#define PSA_CRYPTO_PSA_CRYPTO_INCLUDES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "kernel_defines.h" + +#if IS_USED(MODULE_CRYPTO) +#include "crypto/psa/riot_ciphers.h" +#endif + +#if IS_USED(MODULE_PSA_RIOT_HASHES_HMAC_SHA256) || IS_USED(MODULE_PSA_RIOT_HASHES_MD5) || \ + IS_USED(MODULE_PSA_RIOT_HASHES_SHA_1) || IS_USED(MODULE_PSA_RIOT_HASHES_SHA_224) || \ + IS_USED(MODULE_PSA_RIOT_HASHES_SHA_256) +#include "hashes/psa/riot_hashes.h" +#endif + +#if IS_USED(MODULE_PERIPH_CIPHER_AES_128_CBC) +#include "psa_periph_aes_ctx.h" +#endif + +#if IS_USED(MODULE_PERIPH_HASH_SHA_1) || IS_USED(MODULE_PERIPH_HASH_SHA_224) || \ + IS_USED(MODULE_PERIPH_HASH_SHA_256) || IS_USED(MODULE_PERIPH_HASH_SHA_512) +#include "psa_periph_hashes_ctx.h" +#endif + +#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) +#include "atca_params.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTO_PSA_CRYPTO_INCLUDES_H */ +/** @} */ diff --git a/sys/include/psa_crypto/psa/crypto_se_config.h b/sys/include/psa_crypto/psa/crypto_se_config.h new file mode 100644 index 0000000000..a8df8bbceb --- /dev/null +++ b/sys/include/psa_crypto/psa/crypto_se_config.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2023 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @{ + * + * @file + * @brief Define structures für SE slot configurations + * + * @author Lena Boeckmann + * + */ + +#ifndef PSA_CRYPTO_PSA_CRYPTO_SE_CONFIG_H +#define PSA_CRYPTO_PSA_CRYPTO_SE_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) +#include "atca.h" +#endif + +/** + * @brief Structure containing device specific configuration data. + * + * This will be stored in the driver's persistent data to + * manage the device. + */ +typedef union { + #if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) + psa_atca_slot_config_t slots[16]; + #endif +} psa_se_config_t; + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTO_PSA_CRYPTO_SE_CONFIG_H */ +/** @} */ diff --git a/sys/include/psa_crypto/psa/crypto_sizes.h b/sys/include/psa_crypto/psa/crypto_sizes.h new file mode 100644 index 0000000000..701aec16f2 --- /dev/null +++ b/sys/include/psa_crypto/psa/crypto_sizes.h @@ -0,0 +1,1004 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @{ + * + * @file crypto_sizes.h + * @brief Size definitions for PSA Crypto + * + * @author Lena Boeckmann + * + * @note Some of the macros in this file have already been copied here from + * the PSA API specification, but are not implemented, yet. + * They are marked by comments that either say "specification-defined" + * or "implementation-defined". + * These macros will be implemented successively in the future. + */ + +#ifndef PSA_CRYPTO_PSA_CRYPTO_SIZES_H +#define PSA_CRYPTO_PSA_CRYPTO_SIZES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "kernel_defines.h" +#include "crypto_values.h" + +/** + * @brief Functions to convert bits to bytes + * + * @param bits + * + * @return Number of bytes contained in bits + */ +#define PSA_BITS_TO_BYTES(bits) (size_t)(((bits) + 7) / 8) + +/** + * @brief Functions to convert bytes to bits + * + * @param bytes + * + * @return Number of bits contained in bytes + */ +#define PSA_BYTES_TO_BITS(bytes) ((bytes) * 8) + +/** + * @brief Maximum key size determined by the build system. + * + * @details The maximum key size is set automatically, depending on + * the features chosen at compile-time. They should not be + * changed manually. + */ +#ifndef CONFIG_PSA_MAX_KEY_SIZE +#if (IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P256R1) || \ + IS_USED(MODULE_PSA_CIPHER_AES_256_CBC) || \ + IS_USED(MODULE_PSA_MAC_HMAC_SHA_256) || \ + IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A_ECC_P256)) +#define CONFIG_PSA_MAX_KEY_SIZE 32 +#elif (IS_USED(MODULE_PSA_CIPHER_AES_192_CBC) || \ + IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P192R1)) +#define CONFIG_PSA_MAX_KEY_SIZE 24 +#elif (IS_USED(MODULE_PSA_CIPHER_AES_128_CBC)) || \ + (IS_USED(MODULE_PSA_CIPHER_AES_128_ECB)) +#define CONFIG_PSA_MAX_KEY_SIZE 16 +#else +#define CONFIG_PSA_MAX_KEY_SIZE 0 +#endif +#endif + +/** + * @brief Number of required allocated asymmetric key pair slots. + * + * @details These should be defined by the developer to + * fit their requirements. The default number is 5. + */ +#ifndef CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT +#if (IS_USED(MODULE_PSA_ASYMMETRIC)) +#define CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT 5 +#else +#define CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT 0 +#endif +#endif + +/** + * @brief Number of required allocated single key slots. + * + * @details These should be defined by the developer to + * fit their requirements. The default number is 5. + */ +#ifndef CONFIG_PSA_SINGLE_KEY_COUNT +#if (IS_USED(MODULE_PSA_KEY_SLOT_MGMT)) +#define CONFIG_PSA_SINGLE_KEY_COUNT 5 +#else +#define CONFIG_PSA_SINGLE_KEY_COUNT 0 +#endif +#endif + +/** + * @brief Number of required allocated protected key slots. + * + * @details These should be defined by the developer to + * fit their requirements. The default number is 5. + */ +#ifndef CONFIG_PSA_PROTECTED_KEY_COUNT +#if (IS_USED(MODULE_PSA_SE_MGMT)) +#define CONFIG_PSA_PROTECTED_KEY_COUNT 5 +#else +#define CONFIG_PSA_PROTECTED_KEY_COUNT 0 +#endif +#endif + +/** + * @brief A sufficient plaintext buffer size for @ref psa_aead_decrypt(), + * for any of the supported key types and AEAD algorithms. + * + * @details If the size of the plaintext buffer is at least this large, + * it is guaranteed that @ref psa_aead_decrypt() will not fail due + * to an insufficient buffer size. + * + * See also @ref PSA_AEAD_DECRYPT_OUTPUT_SIZE(). + * + * @param ciphertext_length Size of the ciphertext in bytes. + */ +#define PSA_AEAD_DECRYPT_OUTPUT_MAX_SIZE(ciphertext_length) \ +/* implementation-defined value */ + +/** + * @brief A sufficient plaintext buffer size for @ref psa_aead_decrypt(), in bytes. + * + * @details If the size of the plaintext buffer is at least this large, it is guaranteed that + * @ref psa_aead_decrypt() will not fail due to an insufficient buffer size. Depending on + * the algorithm, the actual size of the plaintext might be smaller. + * + * See also @ref PSA_AEAD_DECRYPT_OUTPUT_MAX_SIZE. + * + * @param key_type A symmetric key type that is compatible with algorithm alg. + * @param alg An AEAD algorithm: a value of type @ref psa_algorithm_t + * such that @ref PSA_ALG_IS_AEAD(@p alg) is true. + * @param ciphertext_length Size of the ciphertext in bytes. + * + * @return The AEAD plaintext size for the specified key type and algorithm. + * 0 if the key type or AEAD algorithm is not recognized, not supported or the parameters + * are incompatible. + */ +#define PSA_AEAD_DECRYPT_OUTPUT_SIZE(key_type, alg, ciphertext_length) \ +/* implementation-defined value */ + +/** + * @brief A sufficient ciphertext buffer size for @ref psa_aead_encrypt(), + * for any of the supported key types and AEAD algorithms. + * + * @details If the size of the ciphertext buffer is at least this large, + * it is guaranteed that @ref psa_aead_encrypt() will not fail due to an insufficient + * buffer size. + * + * See also @ref PSA_AEAD_ENCRYPT_OUTPUT_SIZE(). + * + * @param plaintext_length Size of the plaintext in bytes. + */ +#define PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE(plaintext_length) \ +/* implementation-defined value */ + +/** + * @brief A sufficient ciphertext buffer size for @ref psa_aead_encrypt(), in bytes. + * + * @details If the size of the ciphertext buffer is at least this large, it is guaranteed that + * @ref psa_aead_encrypt() will not fail due to an insufficient buffer size. Depending on + * the algorithm, the actual size of the ciphertext might be smaller. + * + * See also @ref PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE. + * + * @param key_type A symmetric key type that is compatible with algorithm alg. + * @param alg An AEAD algorithm: a value of type @ref psa_algorithm_t such + * that @ref PSA_ALG_IS_AEAD(alg) is true. + * @param plaintext_length Size of the plaintext in bytes. + * + * @return The AEAD ciphertext size for the specified key type and algorithm. + * 0 if the key type or AEAD algorithm is not recognized, not supported or the parameters + * are incompatible. + */ +#define PSA_AEAD_ENCRYPT_OUTPUT_SIZE(key_type, alg, plaintext_length) \ +/* implementation-defined value */ + +/** + * @brief A sufficient ciphertext buffer size for @ref psa_aead_finish(), + * for any of the supported key types and AEAD algorithms. + * + * @details If the size of the ciphertext buffer is at least this large, it is guaranteed that + * @ref psa_aead_finish() will not fail due to an insufficient ciphertext buffer size. + * + * See also @ref PSA_AEAD_FINISH_OUTPUT_SIZE(). + */ +#define PSA_AEAD_FINISH_OUTPUT_MAX_SIZE /* implementation-defined value */ + +/** + * @brief A sufficient ciphertext buffer size for @ref psa_aead_finish(). + * + * @details If the size of the ciphertext buffer is at least this large, it is guaranteed that + * @ref psa_aead_finish() will not fail due to an insufficient ciphertext buffer size. The + * actual size of the output might be smaller in any given call. + * + * See also @ref PSA_AEAD_FINISH_OUTPUT_MAX_SIZE. + * + * @param key_type A symmetric key type that is compatible with algorithm alg. + * @param alg An AEAD algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_AEAD(@p alg) is true. + * + * @return A sufficient ciphertext buffer size for the specified key type and algorithm. + * If the key type or AEAD algorithm is not recognized, or the parameters are incompatible, + * return 0. An implementation can return either 0 or a correct size for a key type and + * AEAD algorithm that it recognizes, but does not support. + */ +#define PSA_AEAD_FINISH_OUTPUT_SIZE(key_type, alg) \ +/* implementation-defined value */ + +/** + * @brief The default nonce size for an AEAD algorithm, in bytes. + * + * @details If the size of the nonce buffer is at least this large, it is guaranteed that + * @ref psa_aead_generate_nonce() will not fail due to an insufficient buffer size. + * + * For most AEAD algorithms, @ref PSA_AEAD_NONCE_LENGTH() evaluates to the exact size of + * the nonce generated by @ref psa_aead_generate_nonce(). + * + * See also @ref PSA_AEAD_NONCE_MAX_SIZE. + * + * @param key_type A symmetric key type that is compatible with algorithm alg. + * @param alg An AEAD algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_AEAD(@p alg) is true. + * + * @return The default nonce size for the specified key type and algorithm. + * 0 if the key type or AEAD algorithm is not recognized, not supported or the parameters + * are incompatible. + */ +#define PSA_AEAD_NONCE_LENGTH(key_type, alg) /* implementation-defined value */ + +/** + * @brief A sufficient buffer size for storing the nonce generated by + * @ref psa_aead_generate_nonce(), for any of the supported key types and AEAD algorithms. + * + * @details If the size of the nonce buffer is at least this large, it is guaranteed that + * @ref psa_aead_generate_nonce() will not fail due to an insufficient buffer size. + * + * See also @ref PSA_AEAD_NONCE_LENGTH(). + */ +#define PSA_AEAD_NONCE_MAX_SIZE /* implementation-defined value */ + +/** + * @brief The length of a tag for an AEAD algorithm, in bytes. + * + * @details This is the size of the tag output from @ref psa_aead_finish(). + * If the size of the tag buffer is at least this large, it is guaranteed that + * @ref psa_aead_finish() will not fail due to an insufficient tag buffer size. + * + * See also @ref PSA_AEAD_TAG_MAX_SIZE. + * + * @param key_type The type of the AEAD key. + * @param key_bits The size of the AEAD key in bits. + * @param alg An AEAD algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_AEAD(@p alg) is true. + * + * @return The tag length for the specified algorithm and key. + * 0 if the AEAD algorithm does not have an identified tag that can be distinguished from + * the rest of the ciphertext. + * 0 if the AEAD algorithm is not recognized or not supported. + */ +#define PSA_AEAD_TAG_LENGTH(key_type, key_bits, alg) \ +/* implementation-defined value */ + +/** + * @brief A sufficient buffer size for storing the tag output by @ref psa_aead_finish(), + * for any of the supported key types and AEAD algorithms. + * + * @details If the size of the tag buffer is at least this large, it is guaranteed that + * @ref psa_aead_finish() will not fail due to an insufficient buffer size. + * + * See also @ref PSA_AEAD_TAG_LENGTH(). + */ +#define PSA_AEAD_TAG_MAX_SIZE /* implementation-defined value */ + +/** + * @brief A sufficient output buffer size for @ref psa_aead_update(), for any of the supported key + * types and AEAD algorithms. + * + * @details If the size of the output buffer is at least this large, it is guaranteed that + * @ref psa_aead_update() will not fail due to an insufficient buffer size. + * + * See also @ref PSA_AEAD_UPDATE_OUTPUT_SIZE(). + * + * @param input_length Size of the input in bytes. + */ +#define PSA_AEAD_UPDATE_OUTPUT_MAX_SIZE(input_length) \ +/* implementation-defined value */ + +/** + * @brief A sufficient output buffer size for @ref psa_aead_update(). + * + * @details If the size of the output buffer is at least this large, it is guaranteed that + * @ref psa_aead_update() will not fail due to an insufficient buffer size. The actual + * size of the output might be smaller in any given call. + * + * See also @ref PSA_AEAD_UPDATE_OUTPUT_MAX_SIZE. + * + * @param key_type A symmetric key type that is compatible with algorithm alg. + * @param alg An AEAD algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_AEAD(@p alg) is true. + * @param input_length Size of the input in bytes. + * + * @return A sufficient output buffer size for the specified key type and algorithm. + * 0 if the key type or AEAD algorithm is not recognized, not supported or the parameters + * are incompatible. + */ +#define PSA_AEAD_UPDATE_OUTPUT_SIZE(key_type, alg, input_length) \ +/* implementation-defined value */ + +/** + * @brief A sufficient output buffer size for @ref psa_aead_update(), for any of the supported key + * types and AEAD algorithms. + * + * @details If the size of the output buffer is at least this large, it is guaranteed that + * @ref psa_aead_update() will not fail due to an insufficient buffer size. + * + * See also @ref PSA_AEAD_UPDATE_OUTPUT_SIZE(). + * + * @param input_length Size of the input in bytes. + */ +#define PSA_AEAD_VERIFY_OUTPUT_MAX_SIZE /* implementation-defined value */ + +/** + * @brief A sufficient plaintext buffer size for @ref psa_aead_verify(), in bytes. + * + * @details If the size of the plaintext buffer is at least this large, it is guaranteed that + * @ref psa_aead_verify() will not fail due to an insufficient plaintext buffer size. The + * actual size of the output might be smaller in any given call. + * + * See also @ref PSA_AEAD_VERIFY_OUTPUT_MAX_SIZE. + * + * @param key_type A symmetric key type that is compatible with algorithm alg. + * @param alg An AEAD algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_AEAD(@p alg) is true. + * + * @return A sufficient plaintext buffer size for the specified key type and algorithm. + * 0 if the key type or AEAD algorithm is not recognized, not supported or the parameters + * are incompatible. + */ +#define PSA_AEAD_VERIFY_OUTPUT_SIZE(key_type, alg) \ +/* implementation-defined value */ + +/** + * @brief Maximum size of a hash supported by this implementation, in bytes. + * + * See also @ref PSA_HASH_LENGTH(). + */ +#define PSA_HASH_MAX_SIZE (64) + +/** + * @brief The input block size of a hash algorithm, in bytes. + * + * @details Hash algorithms process their input data in blocks. Hash operations will retain any + * partial blocks until they have enough input to fill the block or until the operation + * is finished. + * + * This affects the output from @ref psa_hash_suspend(). + * + * @param alg A hash algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_HASH(@p alg) is true. + * + * @return The block size in bytes for the specified hash algorithm. If the hash algorithm is not + * recognized, return 0. An implementation can return either 0 or the correct size for a + * hash algorithm that it recognizes, but does not support. + */ +#define PSA_HASH_BLOCK_LENGTH(alg) /* implementation-defined value */ + +/** + * @brief The size of the output of @ref psa_hash_compute() and @ref psa_hash_finish(), in bytes. + * + * @details This is also the hash length that @ref psa_hash_compare() and @ref psa_hash_verify() + * expect. + * + * See also @ref PSA_HASH_MAX_SIZE. + * + * @param alg A hash algorithm or an HMAC algorithm: a value of type @ref psa_algorithm_t such + * that (@ref PSA_ALG_IS_HASH(@p alg) || @ref PSA_ALG_IS_HMAC(@p alg)) is true. + * + * @return The hash length for the specified hash algorithm. + * 0 if the hash algorithm is not recognized or not supported. + */ +#define PSA_HASH_LENGTH(alg) \ + ( \ + PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_MD2 ? 16 : \ + PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_MD4 ? 16 : \ + PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_MD5 ? 16 : \ + PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_RIPEMD160 ? 20 : \ + PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_1 ? 20 : \ + PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_224 ? 28 : \ + PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_256 ? 32 : \ + PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_384 ? 48 : \ + PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_512 ? 64 : \ + PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_512_224 ? 28 : \ + PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_512_256 ? 32 : \ + PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA3_224 ? 28 : \ + PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA3_256 ? 32 : \ + PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA3_384 ? 48 : \ + PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA3_512 ? 64 : \ + 0) + +/** + * @brief The size of the output of @ref psa_mac_compute() and @ref psa_mac_sign_finish(), + * in bytes. + * + * @details If the size of the MAC buffer is at least this large, it is guaranteed that + * @ref psa_mac_compute() and @ref psa_mac_sign_finish() will not fail due to an + * insufficient buffer size. + * + * This is also the MAC length that @ref psa_mac_verify() and @ref psa_mac_verify_finish() + * expect. + * + * See also @ref PSA_MAC_MAX_SIZE. + * + * @param key_type The type of the MAC key. + * @param key_bits The size of the MAC key in bits. + * @param alg A MAC algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_MAC(@p alg) is true. + * + * @return The MAC length for the specified algorithm with the specified key parameters. + * 0 if the MAC algorithm is not recognized or not supported. + * Unspecified if the key parameters are not consistent with the algorithm. + */ +#define PSA_MAC_LENGTH(key_type, key_bits, alg) \ + ((PSA_ALG_IS_HMAC(alg)) ? PSA_HASH_LENGTH(PSA_ALG_HMAC_GET_HASH(alg)) : \ + PSA_ALG_IS_BLOCK_CIPHER_MAC(alg) ? PSA_BLOCK_CIPHER_BLOCK_LENGTH(key_type) : \ + ((void)(key_type), (void)(key_bits), 0)) + +/** + * @brief A sufficient buffer size for storing the MAC output by @ref psa_mac_verify() and + * @ref psa_mac_verify_finish(), for any of the supported key types and MAC algorithms. + * + * @details If the size of the MAC buffer is at least this large, it is guaranteed that + * @ref psa_mac_verify() and @ref psa_mac_verify_finish() will not fail due to an + * insufficient buffer size. + * + * See also @ref PSA_MAC_LENGTH(). + */ +#define PSA_MAC_MAX_SIZE (PSA_HASH_MAX_SIZE) + +/** + * @brief The block size of a block cipher. + * + * @note It is possible to build stream cipher algorithms on top of a block cipher, + * for example CTR mode (@ref PSA_ALG_CTR). This macro only takes the key type + * into account, so it cannot be used to determine the size of the data that + * @ref psa_cipher_update() might buffer for future processing in general. + * + * @param type A cipher key type (value of type @ref psa_key_type_t). + * + * @return The block size for a block cipher, or 1 for a stream cipher. + */ +#define PSA_BLOCK_CIPHER_BLOCK_LENGTH(type) \ + (1u << (((type) >> 8) & 7)) + +/** + * @brief The maximum block size of a block cipher supported by the implementation. + * + * @details See also @ref PSA_BLOCK_CIPHER_BLOCK_LENGTH(). + */ +#define PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE /* implementation-defined value */ + +/** + * @brief A sufficient output buffer size for @ref psa_cipher_decrypt(), for any of the supported + * key types and cipher algorithms. + * + * @details If the size of the output buffer is at least this large, it is guaranteed that + * @ref psa_cipher_decrypt() will not fail due to an insufficient buffer size. + * + * See also @ref PSA_CIPHER_DECRYPT_OUTPUT_SIZE(). + * + * @param input_length Size of the input in bytes. + */ +#define PSA_CIPHER_DECRYPT_OUTPUT_MAX_SIZE(input_length) \ + (input_length) + +/** + * @brief The maximum size of the output of @ref psa_cipher_decrypt(), in bytes. + * + * @details If the size of the output buffer is at least this large, it is guaranteed + * that @ref psa_cipher_decrypt() will not fail due to an insufficient buffer size. + * Depending on the algorithm, the actual size of the output might be smaller. + * + * See also @ref PSA_CIPHER_DECRYPT_OUTPUT_MAX_SIZE. + * + * @param key_type A symmetric key type that is compatible with algorithm alg. + * @param alg A cipher algorithm (PSA_ALG_XXX value such that + * @ref PSA_ALG_IS_CIPHER(@p alg) is true). + * @param input_length Size of the input in bytes. + * + * @return A sufficient output size for the specified key type and algorithm. + * 0 if the key type or cipher algorithm is not recognized, or the parameters + * are incompatible. + */ +#define PSA_CIPHER_DECRYPT_OUTPUT_SIZE(key_type, alg, input_length) \ + (input_length - PSA_CIPHER_IV_LENGTH(key_type, alg)) + +/** + * @brief A sufficient output buffer size for @ref psa_cipher_encrypt(), for any of the supported + * key types and cipher algorithms. + * + * @details If the size of the output buffer is at least this large, it is guaranteed that + * @ref psa_cipher_encrypt() will not fail due to an insufficient buffer size. + * + * See also @ref PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(). + * + * @param input_length Size of the input in bytes. + */ +#define PSA_CIPHER_ENCRYPT_OUTPUT_MAX_SIZE(input_length) \ + (PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES, PSA_ALG_CBC_NO_PADDING, input_length)) + +/** + * @brief The maximum size of the output of @ref psa_cipher_encrypt(), in bytes. + * + * @details If the size of the output buffer is at least this large, it is guaranteed + * that @ref psa_cipher_encrypt() will not fail due to an insufficient buffer size. + * Depending on the algorithm, the actual size of the output might be smaller. + * + * See also @ref PSA_CIPHER_ENCRYPT_OUTPUT_MAX_SIZE. + * + * @param key_type A symmetric key type that is compatible with algorithm alg. + * @param alg A cipher algorithm (PSA_ALG_XXX value such that + * @ref PSA_ALG_IS_CIPHER(@p alg) is true). + * @param input_length Size of the input in bytes. + * + * @return A sufficient output size for the specified key type and algorithm. + * 0 if the key type or cipher algorithm is not recognized, not supported or the + * parameters are incompatible. + */ +#define PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(key_type, alg, input_length) \ + (input_length + PSA_CIPHER_IV_LENGTH(key_type, alg)) + +/** + * @brief A sufficient output buffer size for @ref psa_cipher_finish(), for any of the supported + * key types and cipher algorithms. + * + * @details If the size of the output buffer is at least this large, it is guaranteed that + * @ref psa_cipher_finish() will not fail due to an insufficient buffer size. + * + * See also @ref PSA_CIPHER_FINISH_OUTPUT_SIZE(). + */ +#define PSA_CIPHER_FINISH_OUTPUT_MAX_SIZE /* implementation-defined value */ + +/** + * @brief A sufficient output buffer size for @ref psa_cipher_finish(). + * + * @details If the size of the output buffer is at least this large, it is guaranteed that + * @ref psa_cipher_finish() will not fail due to an insufficient buffer size. + * The actual size of the output might be smaller in any given call. + * + * See also @ref PSA_CIPHER_FINISH_OUTPUT_MAX_SIZE. + * + * @param key_type A symmetric key type that is compatible with algorithm alg. + * @param alg A cipher algorithm: a value of type psa_algorithm_t such that + * @ref PSA_ALG_IS_CIPHER(@p alg) is true. + * + * @return A sufficient output size for the specified key type and algorithm. + * 0 if the key type or cipher algorithm is not recognized, not supported or the + * parameters are incompatible. + */ +#define PSA_CIPHER_FINISH_OUTPUT_SIZE(key_type, alg) \ +/* implementation-defined value */ + +/** + * @brief The default IV size for a cipher algorithm, in bytes. + * + * @details The IV that is generated as part of a call to @ref psa_cipher_encrypt() is always + * the default IV length for the algorithm. + * + * This macro can be used to allocate a buffer of sufficient size to + * store the IV output from @ref psa_cipher_generate_iv() when using + * a multi-part cipher operation. + * + * See also @ref PSA_CIPHER_IV_MAX_SIZE. + * + * @warning This macro may evaluate its arguments multiple times or + * zero times, so you should not pass arguments that contain + * side effects. + * + * @param key_type A symmetric key type that is compatible with algorithm alg. + * + * @param alg A cipher algorithm (PSA_ALG_XXX value such that + * @ref PSA_ALG_IS_CIPHER(@p alg) is true) + * + * @return The default IV size for the specified key type and algorithm. + * 0, if the algorithm does not use an IV, if key type or cipher + * algorithm are not recognized or if the parameters are not compatible. + * + */ +#define PSA_CIPHER_IV_LENGTH(key_type, alg) \ + (PSA_BLOCK_CIPHER_BLOCK_LENGTH(key_type) > 1 && \ + ((alg) == PSA_ALG_CBC_NO_PADDING) ? 16 : 0) + +/** + * @brief A sufficient buffer size for storing the IV generated by @ref psa_cipher_generate_iv(), + * for any of the supported key types and cipher algorithms. + * + * @details If the size of the IV buffer is at least this large, it is guaranteed that + * @ref psa_cipher_generate_iv() will not fail due to an insufficient buffer size. + * + * See also @ref PSA_CIPHER_IV_LENGTH(). + */ +#define PSA_CIPHER_IV_MAX_SIZE /* implementation-defined value */ + +/** + * @brief A sufficient output buffer size for @ref psa_cipher_update(), + * for any of the supported key types and cipher algorithms. + * + * @details If the size of the output buffer is at least this large, + * it is guaranteed that @ref psa_cipher_update() will not fail + * due to an insufficient buffer size. + * + * See also @ref PSA_CIPHER_UPDATE_OUTPUT_SIZE(). + * + * @param input_length Size of the input in bytes. + */ +#define PSA_CIPHER_UPDATE_OUTPUT_MAX_SIZE(input_length) \ +/* implementation-defined value */ + +/** + * @brief A sufficient output buffer size for @ref psa_cipher_update(). + * + * @details If the size of the output buffer is at least this large, + * it is guaranteed that @ref psa_cipher_update() will not fail + * due to an insufficient buffer size. The actual size of the + * output might be smaller in any given call. + * + * See also @ref PSA_CIPHER_UPDATE_OUTPUT_MAX_SIZE. + * + * @param key_type A symmetric key type that is compatible with algorithm alg. + * @param alg A cipher algorithm (PSA_ALG_XXX value such that + * @ref PSA_ALG_IS_CIPHER(alg) is true). + * @param input_length Size of the input in bytes. + * + * @return A sufficient output size for the specified key type and algorithm. + * 0 if the key type or cipher algorithm is not recognized, not supported or the parameters + * are incompatible. + */ +#define PSA_CIPHER_UPDATE_OUTPUT_SIZE(key_type, alg, input_length) \ +/* implementation-defined value */ + +/** + * @brief The size of the algorithm field that is part of the output of @ref psa_hash_suspend(), + * in bytes. + * + * @details Applications can use this value to unpack the hash suspend state that is output by + * @ref psa_hash_suspend(). + */ +#define PSA_HASH_SUSPEND_ALGORITHM_FIELD_LENGTH ((size_t)4) + +/** + * @brief The size of the hash-state field that is part of the output of @ref psa_hash_suspend(), + * in bytes. + * + * @details Applications can use this value to unpack the hash suspend state that is output by + * @ref psa_hash_suspend(). + * + * @param alg A hash algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_HASH(@p alg) is true. + * + * @return The size, in bytes, of the hash-state field of the hash suspend state for the specified + * hash algorithm. + * 0 if the hash algorithm is not recognized or not supported. + */ +#define PSA_HASH_SUSPEND_HASH_STATE_FIELD_LENGTH(alg) \ +/* specification-defined value */ + +/** + * @brief The size of the input-length field that is part of the output of + * @ref psa_hash_suspend(), in bytes. + * + * @details Applications can use this value to unpack the hash suspend state that is output + * by @ref psa_hash_suspend(). + * + * @param alg A hash algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_HASH(@p alg) is true. + * + * @return The size, in bytes, of the input-length field of the hash suspend state for the + * specified hash algorithm. + * 0 i f the hash algorithm is not recognized or not supported. + */ +#define PSA_HASH_SUSPEND_INPUT_LENGTH_FIELD_LENGTH(alg) \ +/* specification-defined value */ + +/** + * @brief A sufficient hash suspend state buffer size for @ref psa_hash_suspend(), + * for any supported hash algorithms. + * + * @details If the size of the hash state buffer is at least this large, it is guaranteed that + * @ref psa_hash_suspend() will not fail due to an insufficient buffer size. + * + * See also @ref PSA_HASH_SUSPEND_OUTPUT_SIZE(). + */ +#define PSA_HASH_SUSPEND_OUTPUT_MAX_SIZE /* implementation-defined value */ + +/** + * @brief A sufficient hash suspend state buffer size for @ref psa_hash_suspend(), in bytes. + * + * @details If the size of the hash state buffer is at least this large, it is guaranteed that + * @ref psa_hash_suspend() will not fail due to an insufficient buffer size. The actual + * size of the output might be smaller in any given call. + * + * See also @ref PSA_HASH_SUSPEND_OUTPUT_MAX_SIZE. + * + * @param alg A hash algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_HASH(alg) is true. + * + * @return A sufficient output size for the algorithm. + * 0 if the hash algorithm is not recognized, or is not supported by + * @ref psa_hash_suspend(). + * + * For a supported hash algorithm alg, the following expression is true: + * @code + * PSA_HASH_SUSPEND_OUTPUT_SIZE(alg) == PSA_HASH_SUSPEND_ALGORITHM_FIELD_LENGTH + + * PSA_HASH_SUSPEND_INPUT_LENGTH_FIELD_LENGTH(alg) + + * PSA_HASH_SUSPEND_HASH_STATE_FIELD_LENGTH(alg) + + * PSA_HASH_BLOCK_LENGTH(alg) - 1 + * @endcode + */ +#define PSA_HASH_SUSPEND_OUTPUT_SIZE(alg) /* specification-defined value */ + +/** + * @brief A sufficient output buffer size for @ref psa_asymmetric_decrypt(), + * for any of the supported key types and asymmetric encryption algorithms. + * + * @details If the size of the output buffer is at least this large, it is guaranteed that + * @ref psa_asymmetric_decrypt() will not fail due to an insufficient buffer size. + * + * See also @ref PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(). + */ +#define PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE \ +/* implementation-defined value */ + +/** + * @brief Sufficient output buffer size for @ref psa_asymmetric_decrypt(). + * + * @details If the size of the output buffer is at least this large, it is guaranteed that + * @ref psa_asymmetric_decrypt() will not fail due to an insufficient buffer size. + * The actual size of the output might be smaller in any given call. + * + * See also @ref PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE. + * + * @param key_type An asymmetric key type, either a key pair or a public key. + * @param key_bits The size of the key in bits. + * @param alg An asymmetric encryption algorithm: a value of type psa_algorithm_t such + * that @ref PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(@p alg) is true. + * + * @return A sufficient output buffer size for the specified asymmetric encryption algorithm + * and key parameters. + * 0 if the asymmetric encryption algorithm and key parameters are not supported. + * Unspecified if the parameters are not valid. + */ +#define PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(key_type, key_bits, alg) \ +/* implementation-defined value */ + +/** + * @brief A sufficient output buffer size for @ref psa_asymmetric_encrypt(), + * for any of the supported key types and asymmetric encryption algorithms. + * + * @details If the size of the output buffer is at least this large, it is guaranteed that + * @ref psa_asymmetric_encrypt() will not fail due to an insufficient buffer size. + * + * See also @ref PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(). + */ +#define PSA_ASYMMETRIC_ENCRYPT_OUTPUT_MAX_SIZE /* implementation-defined value */ + +/** + * @brief Sufficient output buffer size for @ref psa_asymmetric_encrypt(). + * + * @details If the size of the output buffer is at least this large, it is guaranteed that + * @ref psa_asymmetric_encrypt() will not fail due to an insufficient buffer size. + * The actual size of the output might be smaller in any given call. + * + * See also @ref PSA_ASYMMETRIC_ENCRYPT_OUTPUT_MAX_SIZE. + * + * @param key_type An asymmetric key type, either a key pair or a public key. + * @param key_bits The size of the key in bits. + * @param alg An asymmetric encryption algorithm: a value of type psa_algorithm_t + * such that @ref PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(@p alg) is true. + * + * @return A sufficient output buffer size for the specified asymmetric encryption algorithm + * and key parameters. + * 0 if the asymmetric encryption algorithm and key parameters are not supported. + * Unspecified if the parameters are not valid. + */ +#define PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(key_type, key_bits, alg) \ +/* implementation-defined value */ + +/** + * @brief Sufficient output buffer size for @ref psa_export_key(). + * + * @details The following code illustrates how to allocate enough memory to export a key by + * querying the key type and size at runtime. + * + * @code + * @ref psa_key_attributes_t attributes = @ref PSA_KEY_ATTRIBUTES_INIT; + * @ref psa_status_t status; + * status = @ref psa_get_key_attributes(key, &attributes); + * if (status != @ref PSA_SUCCESS) + * handle_error(...); + * @ref psa_key_type_t key_type = @ref psa_get_key_type(&attributes); + * size_t key_bits = @ref psa_get_key_bits(&attributes); + * size_t buffer_size = @ref PSA_EXPORT_KEY_OUTPUT_SIZE(key_type, key_bits); + * @ref psa_reset_key_attributes(&attributes); + * uint8_t *buffer = malloc(buffer_size); + * if (buffer == NULL) + * handle_error(...); + * size_t buffer_length; + * status = @ref psa_export_key(key, buffer, buffer_size, &buffer_length); + * if (status != @ref PSA_SUCCESS) + * handle_error(...); + * @endcode + * + * See also @ref PSA_EXPORT_KEY_PAIR_MAX_SIZE and @ref PSA_EXPORT_PUBLIC_KEY_MAX_SIZE. + * + * @param key_type A supported key type. + * @param key_bits The size of the key in bits. + * + * @return If the parameters are valid and supported, return a buffer size in bytes that + * guarantees that @ref psa_export_key() or @ref psa_export_public_key() will not fail + * with @ref PSA_ERROR_BUFFER_TOO_SMALL. + * 0 if the parameters are a valid combination that is not supported by the implementation. + * Unspecified if the parameters are not valid. + */ +#define PSA_EXPORT_KEY_OUTPUT_SIZE(key_type, key_bits) \ + /* implementation-defined value */ + +/** + * @brief Check whether the key size is a valid ECC size. + * + * @param bits Key size of type @ref psa_key_bits_t + */ +#define PSA_ECC_KEY_SIZE_IS_VALID(bits) \ + (bits == 128 || \ + bits == 192 || \ + bits == 224 || \ + bits == 256 || \ + bits == 384) + +/** + * @brief The maximum size of an asymmetric private key. + */ +#define PSA_MAX_PRIV_KEY_SIZE (PSA_BYTES_TO_BITS(CONFIG_PSA_MAX_KEY_SIZE)) + +/** + * @brief Sufficient buffer size for exporting any asymmetric key pair. + * + * @details This value must be a sufficient buffer size when calling @ref psa_export_key() to + * export any asymmetric key pair that is supported by the implementation, regardless of + * the exact key type and key size. + * + * See also @ref PSA_EXPORT_KEY_OUTPUT_SIZE(). + */ +#define PSA_EXPORT_KEY_PAIR_MAX_SIZE /* implementation-defined value */ + +/** + * @brief Maximum size of the export encoding of an ECC public key. + * + * @details The representation of an ECC public key is: + * - The byte 0x04; + * - `x_P` as a `ceiling(m/8)`-byte string, big-endian; + * - `y_P` as a `ceiling(m/8)`-byte string, big-endian; + * - where m is the bit size associated with the curve. + * - 1 byte + 2 * point size. + */ +#define PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits) \ + ((size_t)(2 * PSA_BITS_TO_BYTES(key_bits) + 1)) + +/** + * @brief Sufficient output buffer size for @ref psa_export_public_key(). + * + * @details This macro returns a compile-time constant if its arguments are + * compile-time constants. + * + * @warning This macro may evaluate its arguments multiple times or + * zero times, so you should not pass arguments that contain + * side effects. + * + * The following code illustrates how to allocate enough memory to export + * a public key by querying the key type and size at runtime. + * + * @code + * @ref psa_key_attributes_t attributes = @ref PSA_KEY_ATTRIBUTES_INIT; + * @ref psa_status_t status; + * status = @ref psa_get_key_attributes(key, &attributes); + * if (status != @ref PSA_SUCCESS) handle_error(...); + * @ref psa_key_type_t key_type = @ref psa_get_key_type(&attributes); + * size_t key_bits = @ref psa_get_key_bits(&attributes); + * size_t buffer_size = @ref PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(key_type, key_bits); + * @ref psa_reset_key_attributes(&attributes); + * uint8_t *buffer = malloc(buffer_size); + * if (buffer == NULL) handle_error(...); + * size_t buffer_length; + * status = @ref psa_export_public_key(key, buffer, buffer_size, &buffer_length); + * if (status != @ref PSA_SUCCESS) handle_error(...); + * @endcode + * + * @param key_type A public key or key pair key type. + * @param key_bits The size of the key in bits. + * + * @return A buffer size in bytes that guarantees that @ref psa_export_public_key() will not fail + * with @ref PSA_ERROR_BUFFER_TOO_SMALL. + * 0 if the parameters are a valid combination that is not supported. + * Unspecified if the parameters are not valid, the return value is unspecified. + * If the parameters are valid and supported, return the same result as + * @ref PSA_EXPORT_KEY_OUTPUT_SIZE( + * @ref PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(@p key_type), @p key_bits). + */ +#define PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(key_type, key_bits) \ + (PSA_KEY_TYPE_IS_ECC(key_type) ? PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits) : \ + 0) + +/** + * @brief Sufficient buffer size for exporting any asymmetric public key. + * + * @details This macro expands to a compile-time constant integer. This value is + * a sufficient buffer size when calling @ref psa_export_key() or + * @ref psa_export_public_key() to export any asymmetric public key, + * regardless of the exact key type and key size. + * + * See also @ref PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(@p key_type, @p key_bits). + */ +#define PSA_EXPORT_PUBLIC_KEY_MAX_SIZE \ + (PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_MAX_PRIV_KEY_SIZE)) + +/** + * @brief The maximum size of an asymmetric private key buffer. If only a secure element driver is + * present, the private key will always be stored in a key slot and PSA Crypto will only + * allocate memory for an 8 Byte key slot number. + */ +#define PSA_MAX_PRIV_KEY_BUFFER_SIZE (PSA_BITS_TO_BYTES(PSA_MAX_PRIV_KEY_SIZE)) + +/** + * @brief The maximum size of an asymmetric private key pair. + */ +#define PSA_MAX_ASYMMETRIC_KEYPAIR_SIZE (PSA_BITS_TO_BYTES(PSA_MAX_PRIV_KEY_SIZE) + \ + PSA_EXPORT_PUBLIC_KEY_MAX_SIZE) + +/** + * @brief The maximum size of the used key data. + */ +#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC) || IS_USED(MODULE_PSA_ASYMMETRIC) +#define PSA_MAX_KEY_DATA_SIZE (PSA_EXPORT_PUBLIC_KEY_MAX_SIZE) +#else +#define PSA_MAX_KEY_DATA_SIZE (CONFIG_PSA_MAX_KEY_SIZE) +#endif + +/** + * @brief The maximum size of an unstructured key. + */ +#define PSA_MAX_UNSTRUCTURED_KEY_SIZE (CONFIG_PSA_MAX_KEY_SIZE) + +/** + * @brief ECDSA signature size for a given curve bit size + * + * @note This macro returns a compile-time constant if its argument is one. + * + * @param curve_bits Curve size in bits. + * + * @return Signature size in bytes. + */ +#define PSA_ECDSA_SIGNATURE_SIZE(curve_bits) \ + ((size_t)(PSA_BITS_TO_BYTES(curve_bits) * 2)) + +/** + * @brief Sufficient signature buffer size for @ref psa_sign_message() and @ref psa_sign_hash(). + * + * @details If the size of the signature buffer is at least this large, it is guaranteed that + * @ref psa_sign_message() and @ref psa_sign_hash() will not fail due to an insufficient + * buffer size. The actual size of the output might be smaller in any given call. + * + * See also @ref PSA_SIGNATURE_MAX_SIZE. + * + * @param key_type An asymmetric key type. This can be a key pair type or a public key type. + * @param key_bits The size of the key in bits. + * @param alg The signature algorithm. + * + * @return A sufficient signature buffer size for the specified asymmetric signature algorithm and + * key parameters. + * 0 if algorithm and key parameters are not supported. + * If the parameters are not valid, the return value is unspecified. + */ +#define PSA_SIGN_OUTPUT_SIZE(key_type, key_bits, alg) \ + (PSA_KEY_TYPE_IS_ECC(key_type) ? PSA_ECDSA_SIGNATURE_SIZE(key_bits) : \ + ((void)alg, 0)) + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTO_PSA_CRYPTO_SIZES_H */ +/** @} */ diff --git a/sys/include/psa_crypto/psa/crypto_struct.h b/sys/include/psa_crypto/psa/crypto_struct.h new file mode 100644 index 0000000000..830c9722b0 --- /dev/null +++ b/sys/include/psa_crypto/psa/crypto_struct.h @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @{ + * + * @file crypto_struct.h + * @brief Structure definitions for PSA Crypto + * + * @author Lena Boeckmann + * + */ + +#ifndef PSA_CRYPTO_PSA_CRYPTO_STRUCT_H +#define PSA_CRYPTO_PSA_CRYPTO_STRUCT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "crypto_types.h" +#include "crypto_sizes.h" +#include "crypto_contexts.h" + +/** + * @brief Structure containing a hash context and algorithm + */ +struct psa_hash_operation_s { + psa_algorithm_t alg; /**< Operation algorithm */ +#if IS_USED(MODULE_PSA_HASH) + psa_hash_context_t ctx; /**< Operation hash context */ +#endif +}; + +/** + * @brief This macro returns a suitable initializer for a hash operation object of type + * @ref psa_hash_operation_t. + */ +#define PSA_HASH_OPERATION_INIT { 0 } + +/** + * @brief Return an initial value for a hash operation object. + * + * @return struct psa_hash_operation_s + */ +static inline struct psa_hash_operation_s psa_hash_operation_init(void) +{ + const struct psa_hash_operation_s v = PSA_HASH_OPERATION_INIT; + + return v; +} + +/** + * @brief Structure storing the key usage policies + */ +struct psa_key_policy_s { + psa_key_usage_t usage; /**< Key usage policy */ + psa_algorithm_t alg; /**< Algorithm for key usage */ +}; + +/** + * @brief Type for key usage policies. + */ +typedef struct psa_key_policy_s psa_key_policy_t; + +/** + * @brief Structure storing key attributes + */ +struct psa_key_attributes_s { + psa_key_type_t type; /**< Type of key */ + psa_key_bits_t bits; /**< Size of key in bits */ + psa_key_lifetime_t lifetime; /**< Lifetime of key */ + psa_key_id_t id; /**< Key identifier */ + psa_key_policy_t policy; /**< Key usage policy */ +}; + +/** + * @brief This macro returns a suitable initializer for a key attribute object of + * type @ref psa_key_attributes_t. + */ +#define PSA_KEY_ATTRIBUTES_INIT { 0 } + +/** + * @brief Return an initial value for a key attribute object. + * + * @return struct psa_key_attributes_s + */ +static inline struct psa_key_attributes_s psa_key_attributes_init(void) +{ + const struct psa_key_attributes_s v = PSA_KEY_ATTRIBUTES_INIT; + + return v; +} + +/** + * @brief Structure storing an AEAD operation context + * + * @note Not implemented, yet + */ +struct psa_aead_operation_s { + int dummy; /**< Not implemented, yet */ +}; + +/** + * @brief This macro returns a suitable initializer for an AEAD operation object of type + * @ref psa_aead_operation_t. + */ +#define PSA_AEAD_OPERATION_INIT { 0 } + +/** + * @brief Return an initial value for an AEAD operation object. + * + * @return psa_aead_operation_s + */ +static inline struct psa_aead_operation_s psa_aead_operation_init(void) +{ + const struct psa_aead_operation_s v = PSA_AEAD_OPERATION_INIT; + + return v; +} + +/** + * @brief Structure storing a cipher operation context + */ +struct psa_cipher_operation_s { + uint8_t iv_required : 1; /**< True if algorithm requires IV */ + uint8_t iv_set : 1; /**< True if IV was already set */ + uint8_t default_iv_length; /**< Default IV length for algorithm */ + psa_algorithm_t alg; /**< Operation algorithm*/ + /** Union containing cipher contexts for the executing backend */ + union cipher_context { +#if IS_USED(MODULE_PSA_CIPHER) + psa_cipher_context_t cipher_ctx; /**< Cipher context */ +#endif +#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) || defined(DOXYGEN) + psa_se_cipher_context_t se_ctx; /**< SE Cipher context */ +#endif + } backend_ctx; /**< Backend specific cipher context */ +}; + +/** + * @brief This macro returns a suitable initializer for a cipher operation + * object of type @ref psa_cipher_operation_t. + */ +#define PSA_CIPHER_OPERATION_INIT { 0 } + +/** + * @brief Return an initial value for a cipher operation object. + * + * @return psa_cipher_operation_s + */ +static inline struct psa_cipher_operation_s psa_cipher_operation_init(void) +{ + const struct psa_cipher_operation_s v = PSA_CIPHER_OPERATION_INIT; + + return v; +} + +/** + * @brief This macro returns a suitable initializer for a key derivation operation object of + * type @ref psa_key_derivation_operation_t. + */ +#define PSA_KEY_DERIVATION_OPERATION_INIT { 0 } + +/** + * @brief Structure storing a key derivation context + * + * @note Not yet implemented + */ +struct psa_key_derivation_operation_s { + int dummy; /**< Not implemented yet */ +}; + +/** + * @brief Return an initial value for a key derivation operation object. + * + * @return psa_key_derivation_operation_s + */ +static inline struct psa_key_derivation_operation_s psa_key_derivation_operation_init(void) +{ + const struct psa_key_derivation_operation_s v = PSA_KEY_DERIVATION_OPERATION_INIT; + + return v; +} + +/** + * @brief This macro returns a suitable initializer for a MAC operation object of type + * @ref psa_mac_operation_t. + */ +#define PSA_MAC_OPERATION_INIT { 0 } + +/** + * @brief Structure storing a MAC operation context + * + * @note Not yet implemented + */ +struct psa_mac_operation_s { + int dummy; /**< Not yet implemented */ +}; + +/** + * @brief Return an initial value for a MAC operation object. + * + * @return psa_mac_operation_s + */ +static inline struct psa_mac_operation_s psa_mac_operation_init(void) +{ + const struct psa_mac_operation_s v = PSA_MAC_OPERATION_INIT; + + return v; +} + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTO_PSA_CRYPTO_STRUCT_H */ +/** @} */ diff --git a/sys/include/psa_crypto/psa/crypto_types.h b/sys/include/psa_crypto/psa/crypto_types.h new file mode 100644 index 0000000000..fa343e7a5d --- /dev/null +++ b/sys/include/psa_crypto/psa/crypto_types.h @@ -0,0 +1,503 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @{ + * + * @file crypto_types.h + * @brief Type definitions for PSA Crypto + * + * @author Lena Boeckmann + * + */ + +#ifndef PSA_CRYPTO_PSA_CRYPTO_TYPES_H +#define PSA_CRYPTO_PSA_CRYPTO_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * @brief For encrypt-decrypt functions, whether the operation is an encryption + * or a decryption. + */ +typedef enum { + PSA_CRYPTO_DRIVER_DECRYPT, + PSA_CRYPTO_DRIVER_ENCRYPT +} psa_encrypt_or_decrypt_t; + +/** + * @brief Encoding of a cryptographic algorithm. + * + * @details For algorithms that can be applied to multiple key types, this identifier does not + * encode the key type. For example, for symmetric ciphers based on a block cipher, + * @ref psa_algorithm_t encodes the block cipher mode and the padding mode while the + * block cipher itself is encoded via @ref psa_key_type_t. + */ +typedef uint32_t psa_algorithm_t; + +/** + * @brief The type of PSA finite-field Diffie-Hellman group family identifiers. + * + * @details The group family identifier is required to create a finite-field Diffie-Hellman + * key using the @ref PSA_KEY_TYPE_DH_KEY_PAIR() or @ref PSA_KEY_TYPE_DH_PUBLIC_KEY() + * macros. + * + * The specific Diffie-Hellman group within a family is identified by the @c key_bits + * attribute of the key. + */ +typedef uint8_t psa_dh_family_t; + +/** + * @brief The type of PSA elliptic curve family identifiers. + * + * @details The curve identifier is required to create an ECC key using the + * @ref PSA_KEY_TYPE_ECC_KEY_PAIR() or @ref PSA_KEY_TYPE_ECC_PUBLIC_KEY() + * macros. + * + * The specific ECC curve within a family is identified by the @c key_bits + * attribute of the key. + */ +typedef uint8_t psa_ecc_family_t; + +/** + * @brief The type of the state object for key derivation operations. + * + * @details Before calling any function on a key derivation operation object, the application must + * initialize it by any of the following means: + * - Set the object to all-bits-zero, for example: + * @code + * @ref psa_key_derivation_operation_t operation; + * memset(&operation, 0, sizeof(operation)); + * @endcode + * - Initialize the object to logical zero values by declaring the object as static or + * global without an explicit initializer, for example: + * @code + * static @ref psa_key_derivation_operation_t operation; + * @endcode + * - Initialize the object to the initializer @ref PSA_KEY_DERIVATION_OPERATION_INIT, + * for example: + * @code + * @ref psa_key_derivation_operation_t operation = + * @ref PSA_KEY_DERIVATION_OPERATION_INIT; + * @endcode + * - Assign the result of the function @ref psa_key_derivation_operation_init() to + * the object, for example: + * @code + * @ref psa_key_derivation_operation_t operation; + * operation = @ref psa_key_derivation_operation_init(); + * @endcode + * This is an implementation-defined type. Applications that make assumptions about the + * content of this object will result in in implementation-specific behavior, and are + * non-portable. + */ +typedef struct psa_key_derivation_operation_s psa_key_derivation_operation_t; + +/** + * @brief Encoding of the step of a key derivation. + */ +typedef uint16_t psa_key_derivation_step_t; + +/** + * @brief Key identifier. + * + * @details A key identifier can be a permanent name for a persistent key, or a transient reference + * to volatile key. + */ +typedef uint32_t psa_key_id_t; + +/** + * @brief Encoding of key lifetimes. + * + * @details The lifetime of a key indicates where it is stored and which application and system + * actions will create and destroy it. + * + * Lifetime values have the following structure: + * - Bits[7:0]: Persistence level + * This value indicates what device management actions can cause it to be destroyed. + * In particular, it indicates whether the key is volatile or persistent. + * See @ref psa_key_persistence_t for more information. + * @ref PSA_KEY_LIFETIME_GET_PERSISTENCE(@p lifetime) returns the persistence level for + * a key lifetime value. + * - Bits[31:8]: Location indicator + * This value indicates where the key material is stored (or at least where it is + * accessible in cleartext) and where operations on the key are performed. See + * @ref psa_key_location_t for more information. + * @ref PSA_KEY_LIFETIME_GET_LOCATION(@p lifetime) returns the location indicator for a + * key lifetime value. + * + * Volatile keys are automatically destroyed when the application instance terminates or + * on a power reset of the device. Persistent keys are preserved until the application + * explicitly destroys them or until an implementation-specific device management event + * occurs, for example, a factor reset. + * + * Persistent keys have a key identifier of type @ref psa_key_id_t. This identifier + * remains valid throughout the lifetime of the key, even if the application instance + * that created the key terminates. + * + * This specification defines two basic lifetime values: + * - Keys with the lifetime @ref PSA_KEY_LIFETIME_VOLATILE are volatile. All + * implementations should support this lifetime. + * - Keys with the lifetime @ref PSA_KEY_LIFETIME_PERSISTENT are persistent. All + * implementations that have access to persistent storage with appropriate security + * guarantees should support this lifetime. + */ +typedef uint32_t psa_key_lifetime_t; + +/** + * @brief Encoding of key location indicators. + * + * @details If an implementation of this API can make calls to external cryptoprocessors such as + * secure elements, the location of a key indicates which secure element performs the + * operations on the key. If the key material is not stored persistently inside the secure + * element, it must be stored in a wrapped form such that only the secure element can + * access the key material in cleartext. + * + * @note Key location indicators are 24-bit values. Key management interfaces operate on + * lifetimes (type @ref psa_key_lifetime_t), and encode the location as the upper 24 bits + * of a 32-bit value. + * + * Values for location indicators defined by this specification are shown below: + * - @c 0: Primary local storage. + * All implementations should support this value. The primary local storage is + * typically the same storage area that contains the key metadata. + * - @c 1: Primary secure element. + * @note As of now, this value is not supported by this implementation. + * Use the vendor-defined location values. + * + * Implementations should support this value if there is a secure element + * attached to the operating environment. As a guideline, secure elements may + * provide higher resistance against side channel and physical attacks than the + * primary local storage, but may have restrictions on supported key types, + * sizes, policies and operations and may have different performance + * characteristics. + * - @c 2–0x7fffff: Other locations defined by a PSA specification. + * The PSA Cryptography API does not currently assign any meaning to + * these locations, but future versions of this specification or other + * PSA specifications may do so. + * - @c 0x800000–0xffffff: Vendor-defined locations. No PSA specification will assign a + * meaning to locations in this range. + */ +typedef uint32_t psa_key_location_t; + +/** + * @brief Encoding of key persistence levels. + * + * @details What distinguishes different persistence levels is which device management events can + * cause keys to be destroyed. For example, power reset, transfer of device ownership, + * or a factory reset are device management events that can affect keys at different + * persistence levels. The specific management events which affect persistent keys at + * different levels is outside the scope of the PSA Cryptography specification. + * + * @note Key persistence levels are 8-bit values. Key management interfaces operate on lifetimes + * (type @ref psa_key_lifetime_t), and encode the persistence value as the lower 8 bits of + * a 32-bit value. + * + * Values for persistence levels defined by this specification are shown below: + * - @c 0 = @ref PSA_KEY_PERSISTENCE_VOLATILE : Volatile key. + * A volatile key is automatically destroyed by the implementation when the + * application instance terminates. In particular, a volatile key is + * automatically destroyed on a power reset of the device. + * - @c 1 = @ref PSA_KEY_PERSISTENCE_DEFAULT : Persistent key with a default lifetime. + * Implementations should support this value if they support persistent keys + * at all. Applications should use this value if they have no specific needs + * that are only met by implementation-specific features. + * - @c 2–127: Persistent key with a PSA-specified lifetime. The PSA Cryptography + * specification does not define the meaning of these values, but other PSA + * specifications may do so. + * - @c 128–254: Persistent key with a vendor-specified lifetime. No PSA specification + * will define the meaning of these values, so implementations may choose + * the meaning freely. As a guideline, higher persistence levels should + * cause a key to survive more management events than lower levels. + * - @c 255 = @ref PSA_KEY_PERSISTENCE_READ_ONLY : Read-only or write-once key. + * A key with this persistence level cannot be destroyed. Implementations that + * support such keys may either allow their creation through the PSA + * Cryptography API, preferably only to applications with the appropriate + * privilege, or only expose keys created through implementation-specific + * means such as a factory ROM engraving process. + * @note Keys that are read-only due to policy restrictions rather than + * due to physical limitations should not have this persistence level. + */ +typedef uint8_t psa_key_persistence_t; + +/** + * @brief Encoding of a key type. + * + * @details This is a structured bitfield that identifies the category and type of key. The range + * of key type values is divided as follows: + * - @ref PSA_KEY_TYPE_NONE == @c 0: + * Reserved as an invalid key type. + * - @c 0x0001–0x7fff: + * Specification-defined key types. Key types defined by this standard always have bit + * 15 clear. Unallocated key type values in this range are reserved for future use. + * - @c 0x8000–0xffff: + * Implementation-defined key types. Implementations that define additional key types + * must use an encoding with bit 15 set. + */ +typedef uint16_t psa_key_type_t; + +/** + * @brief Encoding of permitted usage on a key. + */ +typedef uint32_t psa_key_usage_t; + +/** + * @brief Public interfaces use @c size_t, but internally we use a smaller type. + */ +typedef uint16_t psa_key_bits_t; + +/* These are all temporarily defined as some numeric type to prevent errors at compile time.*/ +/** + * @brief The type of the state object for multi-part AEAD operations. + * + * @details Before calling any function on an AEAD operation object, the application must + * initialize it by any of the following means: + * - Set the object to all-bits-zero, for example: + * @code + * @ref psa_aead_operation_t operation; + * memset(&operation, 0, sizeof(operation)); + * @endcode + * - Initialize the object to logical zero values by declaring the object as static + * or global without an explicit initializer, for example: + * @code + * static @ref psa_aead_operation_t operation; + * @endcode + * - Initialize the object to the initializer @ref PSA_AEAD_OPERATION_INIT, for example: + * @code + * @ref psa_aead_operation_t operation = @ref PSA_AEAD_OPERATION_INIT; + * @endcode + * - Assign the result of the function @ref psa_aead_operation_init() to the object, + * for example: + * @code + * @ref psa_aead_operation_t operation; + * operation = @ref psa_aead_operation_init(); + * @endcode + * + * This is an implementation-defined type. Applications that make assumptions about the + * content of this object will result in in implementation-specific behavior, and are + * non-portable. + */ +typedef struct psa_aead_operation_s psa_aead_operation_t; + +/** + * @brief The type of the state object for multi-part MAC operations. + * + * @details Before calling any function on a MAC operation object, the application must initialize + * it by any of the following means: + * - Set the object to all-bits-zero, for example: + * @code + * @ref psa_mac_operation_t operation; + * memset(&operation, 0, sizeof(operation)); + * @endcode + * - Initialize the object to logical zero values by declaring the object as static or + * global without an explicit initializer, for example: + * @code + * static @ref psa_mac_operation_t operation; + * @endcode + * - Initialize the object to the initializer @ref PSA_MAC_OPERATION_INIT, for example: + * @code + * @ref psa_mac_operation_t operation = @ref PSA_MAC_OPERATION_INIT; + * @endcode + * - Assign the result of the function @ref psa_mac_operation_init() to the object, + * for example: + * @code + * @ref psa_mac_operation_t operation; + * operation = @ref psa_mac_operation_init(); + * @endcode + * This is an implementation-defined type. Applications that make assumptions about the + * content of this object will result in in implementation-specific behavior, and are + * non-portable. + */ +typedef struct psa_mac_operation_s psa_mac_operation_t; + +/** + * @brief Function return status. + * + * @details This is either @ref PSA_SUCCESS, which is zero, indicating success; or a small + * negative value indicating that an error occurred. Errors are encoded as one of + * the @c PSA_ERROR_xxx values defined here. + */ +typedef int32_t psa_status_t; + +/** + * @brief The type of the state data structure for multipart hash operations. + * + * @details Before calling any function on a hash operation object, the application must + * initialize it by any of the following means: + * - Set the structure to all-bits-zero, for example: + * @code + * @ref psa_hash_operation_t operation; + * memset(&operation, 0, sizeof(operation)); + * @endcode + * - Initialize the structure to logical zero values, for example: + * @code + * @ref psa_hash_operation_t operation = {0}; + * @endcode + * - Initialize the structure to the initializer @ref PSA_HASH_OPERATION_INIT, + * for example: + * @code + * @ref psa_hash_operation_t operation = @ref PSA_HASH_OPERATION_INIT; + * @endcode + * - Assign the result of the function @ref psa_hash_operation_init() + * to the structure, for example: + * @code + * @ref psa_hash_operation_t operation; + * operation = @ref psa_hash_operation_init(); + * @endcode + * + * This is an implementation-defined struct. Applications should not + * make any assumptions about the content of this structure except + * as directed by the documentation of a specific implementation. + */ +typedef struct psa_hash_operation_s psa_hash_operation_t; + +/** + * @brief The type of an object containing key attributes. + * + * @details This is the object that represents 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 can 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. + * + * @note Implementations are recommended to define the attribute object as a simple data + * structure, with fields corresponding to the individual key attributes. In such an + * implementation, each function @c psa_set_key_xxx() sets a field and the corresponding + * function @c psa_get_key_xxx() retrieves the value of the field. + * An implementation can report attribute values that are equivalent to the original one, + * but have a different encoding. For example, an implementation can 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 might not be the one that was originally stored. + * + * This is an implementation-defined type. Applications that make assumptions about the + * content of this object will result in in implementation-specific behavior, and are + * non-portable. + * + * An attribute object can 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 @ref psa_reset_key_attributes(). As an + * exception, calling @ref psa_reset_key_attributes() on an attribute object is optional + * if the object has only been modified by the following functions since it was + * initialized or last reset with @ref psa_reset_key_attributes(): + * - @ref psa_set_key_id() + * - @ref psa_set_key_lifetime() + * - @ref psa_set_key_type() + * - @ref psa_set_key_bits() + * - @ref psa_set_key_usage_flags() + * - @ref psa_set_key_algorithm() + * Before calling any function on a key attribute object, the application must initialize + * it by any of the following means: + * - Set the object to all-bits-zero, for example: + * @code + * @ref psa_key_attributes_t attributes; + * memset(&attributes, 0, sizeof(attributes)); + * @endcode + * - Initialize the object to logical zero values by declaring the object as static or + * global without an explicit initializer, for example: + * @code + * static @ref psa_key_attributes_t attributes; + * @endcode + * - Initialize the object to the initializer @ref PSA_KEY_ATTRIBUTES_INIT, for example: + * @code + * @ref psa_key_attributes_t attributes = @ref PSA_KEY_ATTRIBUTES_INIT; + * @endcode + * - Assign the result of the function @ref psa_key_attributes_init() to the object, + * for example: + * @code + * @ref psa_key_attributes_t attributes; + * attributes = @ref psa_key_attributes_init(); + * @endcode + * + * A freshly initialized attribute object contains the following values: + * - lifetime: @ref PSA_KEY_LIFETIME_VOLATILE. + * - key identifier: @ref PSA_KEY_ID_NULL — which is not a valid key identifier. + * - type: @ref PSA_KEY_TYPE_NONE — meaning that the type is unspecified. + * - key size: @c 0 — meaning that the size is unspecified. + * - usage flags: @c 0 — which allows no usage except exporting a public key. + * - algorithm: @ref PSA_ALG_NONE — which does not allow cryptographic usage, + * but allows exporting. + * + * ## Usage + * A typical sequence to create a key is as follows: + * -# Create and initialize an attribute object. + * -# If the key is persistent, call @ref psa_set_key_id(). Also call @ref + * psa_set_key_lifetime() to place the key in a non-default location. + * -# Set the key policy with @ref psa_set_key_usage_flags() and @ref + * psa_set_key_algorithm(). + * -# Set the key type with @ref psa_set_key_type(). Skip this step if copying an existing + * key with @ref psa_copy_key(). + * -# When generating a random key with @ref psa_generate_key() or deriving a key with + * @ref psa_key_derivation_output_key(), set the desired key size with @ref + * psa_set_key_bits(). + * -# Call a key creation function: @ref psa_import_key(), @ref psa_generate_key(), + * @ref psa_key_derivation_output_key() or @ref psa_copy_key(). This function reads the + * attribute object, creates a key with these attributes, and outputs an identifier for + * the newly created key. + * -# Optionally call @ref psa_reset_key_attributes(), now that the attribute object is no + * longer needed. Currently this call is not required as the attributes defined in this + * specification do not require additional resources beyond the object itself. + * + * A typical sequence to query a key’s attributes is as follows: + * -# Call @ref psa_get_key_attributes(). + * -# Call @c psa_get_key_xxx() functions to retrieve the required attribute(s). + * -# Call @ref psa_reset_key_attributes() to free any resources that can be used by the + * attribute object. + * + * Once a key has been created, it is impossible to change its attributes. + */ +typedef struct psa_key_attributes_s psa_key_attributes_t; + +/** + * @brief The type of the state object for multi-part cipher operations. + * + * @details Before calling any function on a cipher operation object, the application must + * initialize it by any of the following means: + * - Set the object to all-bits-zero, for example: + * @code + * @ref psa_cipher_operation_t operation; + * memset(&operation, 0, sizeof(operation)); + * @endcode + * - Initialize the object to logical zero values by declaring the object as static or + * global without an explicit initializer, for example: + * @code + * static @ref psa_cipher_operation_t operation; + * @endcode + * - Initialize the object to the initializer @ref PSA_CIPHER_OPERATION_INIT, for example: + * @code + * @ref psa_cipher_operation_t operation = @ref PSA_CIPHER_OPERATION_INIT; + * @endcode + * - Assign the result of the function @ref psa_cipher_operation_init() to the object, + * for example: + * @code + * @ref psa_cipher_operation_t operation; + * operation = @ref psa_cipher_operation_init(); + * @endcode + * + * This is an implementation-defined type. Applications that make assumptions about the + * content of this object will result in in implementation-specific behavior, and are + * non-portable. + */ +typedef struct psa_cipher_operation_s psa_cipher_operation_t; + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTO_PSA_CRYPTO_TYPES_H */ +/** @} */ diff --git a/sys/include/psa_crypto/psa/crypto_values.h b/sys/include/psa_crypto/psa/crypto_values.h new file mode 100644 index 0000000000..8a35b8a9d7 --- /dev/null +++ b/sys/include/psa_crypto/psa/crypto_values.h @@ -0,0 +1,3486 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @{ + * + * @file crypto_values.h + * @brief Value definitions for PSA Crypto. + * + * @author Lena Boeckmann + * + * @note Some of the macros in this file have already been copied here from + * the PSA API specification, but are not implemented, yet. + * They are marked by comments that either say "specification-defined" + * or "implementation-defined". + * These macros will be implemented successively in the future. + */ + +#ifndef PSA_CRYPTO_PSA_CRYPTO_VALUES_H +#define PSA_CRYPTO_PSA_CRYPTO_VALUES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "crypto_types.h" + +/** + * @brief PSA algorithm category mask + */ +#define PSA_ALG_CATEGORY_MASK ((psa_algorithm_t)0x7f000000) + +/** + * @brief Category for hash algorithms + */ +#define PSA_ALG_CATEGORY_HASH ((psa_algorithm_t)0x02000000) +/** + * @brief Category for MAC algorithms + */ +#define PSA_ALG_CATEGORY_MAC ((psa_algorithm_t)0x03000000) +/** + * @brief Category for cipher algorithms + */ +#define PSA_ALG_CATEGORY_CIPHER ((psa_algorithm_t)0x04000000) +/** + * @brief Category for AEAD algorithms + */ +#define PSA_ALG_CATEGORY_AEAD ((psa_algorithm_t)0x05000000) +/** + * @brief Category for signature algorithms + */ +#define PSA_ALG_CATEGORY_SIGN ((psa_algorithm_t)0x06000000) +/** + * @brief Category for asymmetric encryption algorithms + */ +#define PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION ((psa_algorithm_t)0x07000000) +/** + * @brief Category for key derivation algorithms + */ +#define PSA_ALG_CATEGORY_KEY_DERIVATION ((psa_algorithm_t)0x08000000) +/** + * @brief Category for key agreement algorithms + */ +#define PSA_ALG_CATEGORY_KEY_AGREEMENT ((psa_algorithm_t)0x09000000) + +/** + * @brief Macro to build an AEAD minimum-tag-length wildcard algorithm. + * + * @details A key with a minimum-tag-length AEAD wildcard algorithm as permitted algorithm policy + * can be used with all AEAD algorithms sharing the same base algorithm, and where the tag + * length of the specific algorithm is equal to or larger then the minimum tag length + * specified by the wildcard algorithm. + * + * @note When setting the minimum required tag length to less than the smallest tag length + * allowed by the base algorithm, this effectively becomes an ‘any-tag-length-allowed’ + * policy for that base algorithm. + * + * The AEAD algorithm with a default length tag can be recovered using + * @ref PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(). + * + * @param aead_alg An AEAD algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_AEAD(@p aead_alg) is true. + * @param min_tag_length Desired minimum length of the authentication tag in bytes. This must be + * at least 1 and at most the largest allowed tag length of the algorithm. + * + * @return The corresponding AEAD wildcard algorithm with the specified minimum tag length + * Unspecified if @c aead_alg is not a supported AEAD algorithm or if @c min_tag_length is + * less than 1 or too large for the specified AEAD algorithm. + */ +#define PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(aead_alg, min_tag_length) \ + /* specification-defined value */ + +/** + * @brief An AEAD algorithm with the default tag length. + * + * @details This macro can be used to construct the AEAD algorithm with default tag length from an + * AEAD algorithm with a shortened tag. See also @ref PSA_ALG_AEAD_WITH_SHORTENED_TAG(). + * + * @b Compatible @b key @b types: + * The resulting AEAD algorithm is compatible with the same key types as the + * AEAD algorithm used to construct it. + */ +#define PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(aead_alg) \ + ((((aead_alg) & ~0x003f0000) == 0x05400100) ? PSA_ALG_CCM : \ + (((aead_alg) & ~0x003f0000) == 0x05400200) ? PSA_ALG_GCM : \ + (((aead_alg) & ~0x003f0000) == 0x05000500) ? PSA_ALG_CHACHA20_POLY1305 : \ + PSA_ALG_NONE) + +/** + * @brief Macro to build a AEAD algorithm with a shortened tag. + * + * @details An AEAD algorithm with a shortened tag is similar to the corresponding AEAD algorithm, + * but has an authentication tag that consists of fewer bytes. Depending on the algorithm, + * the tag length might affect the calculation of the ciphertext. + * + * The AEAD algorithm with a default length tag can be recovered using + * @ref PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(). + * + * @b Compatible @b key @b types: + * The resulting AEAD algorithm is compatible with the same key types as the AEAD + * algorithm used to construct it. + * + * @param aead_alg An AEAD algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_AEAD(@p aead_alg) is true. + * @param tag_length Desired length of the authentication tag in bytes. + * + * @return The corresponding AEAD algorithm with the specified tag length. + * Unspecified if @c aead_alg is not a supported AEAD algorithm or if @c tag_length is not + * valid for the specified AEAD algorithm. + */ +#define PSA_ALG_AEAD_WITH_SHORTENED_TAG(aead_alg, tag_length) \ + ((psa_algorithm_t)(((aead_alg) & ~0x003f0000) | (((tag_length) & 0x3f) << 16))) + +/** + * @brief When setting a hash-and-sign algorithm in a key policy, permit any hash algorithm. + * + * @details This value can be used to form the permitted algorithm attribute of a key policy for a + * signature algorithm that is parametrized by a hash. A key with this policy can then be + * used to perform operations using the same signature algorithm parametrized with any + * supported hash. A signature algorithm created using this macro is a wildcard algorithm, + * and @ref PSA_ALG_IS_WILDCARD() will return true. + * + * This value must not be used to build other algorithms that are parametrized over a + * hash. For any valid use of this macro to build an algorithm alg, + * @ref PSA_ALG_IS_HASH_AND_SIGN(alg) is true. This value must not be used to build an + * algorithm specification to perform an operation. It is only valid for setting the + * permitted algorithm in a key policy. + * + * @b Usage: + * For example, suppose that @c PSA_xxx_SIGNATURE is one of the following macros: + * - @ref PSA_ALG_RSA_PKCS1V15_SIGN + * - @ref PSA_ALG_RSA_PSS + * - @ref PSA_ALG_RSA_PSS_ANY_SALT + * - @ref PSA_ALG_ECDSA + * - @ref PSA_ALG_DETERMINISTIC_ECDSA + * + * The following sequence of operations shows how @ref PSA_ALG_ANY_HASH can be used in a + * key policy: + * -# Set the key usage flags using @ref PSA_ALG_ANY_HASH, for example: + * @code + * @ref psa_set_key_usage_flags(@p &attributes, @ref PSA_KEY_USAGE_SIGN_MESSAGE); + * // or VERIFY_MESSAGE + * @ref psa_set_key_algorithm(@p &attributes, + * PSA_xxx_SIGNATURE(@ref PSA_ALG_ANY_HASH)); + * @endcode + * -# Import or generate key material. + * -# Call @ref psa_sign_message() or @ref psa_verify_message(), passing an algorithm + * built from PSA_xxx_SIGNATURE and a specific hash. Each call to sign or verify a + * message can use a different hash algorithm. + * @code + * @ref psa_sign_message(@p key, PSA_xxx_SIGNATURE(@ref PSA_ALG_SHA_256), ...); + * @ref psa_sign_message(@p key, PSA_xxx_SIGNATURE(@ref PSA_ALG_SHA_512), ...); + * @ref psa_sign_message(@p key, PSA_xxx_SIGNATURE(@ref PSA_ALG_SHA3_256), ...); + * @endcode + */ +#define PSA_ALG_ANY_HASH ((psa_algorithm_t)0x020000ff) + +/** + * @brief Macro to build a MAC minimum-MAC-length wildcard algorithm. + * + * @details A key with a minimum-MAC-length MAC wildcard algorithm as permitted algorithm policy + * can be used with all MAC algorithms sharing the same base algorithm, and where the + * (potentially truncated) MAC length of the specific algorithm is equal to or larger then + * the wildcard algorithm’s minimum MAC length. + * + * @note When setting the minimum required MAC length to less than the smallest MAC length + * allowed by the base algorithm, this effectively becomes an ‘any-MAC-length-allowed’ + * policy for that base algorithm. + * + * The untruncated MAC algorithm can be recovered using @ref PSA_ALG_FULL_LENGTH_MAC(). + * + * @b Compatible @b key @b types + * The resulting wildcard MAC algorithm is compatible with the same key types as the MAC + * algorithm used to construct it. + * + * @param mac_alg A MAC algorithm: a value of type psa_algorithm_t such that + * @ref PSA_ALG_IS_MAC(alg) is true. + * This can be a truncated or untruncated MAC algorithm. + * @param min_mac_length Desired minimum length of the message authentication code in bytes. + * This must be at most the untruncated length of the MAC and must be at + * least 1. + * @return The corresponding MAC wildcard algorithm with the specified minimum MAC length. + * Unspecified if mac_alg is not a supported MAC algorithm or if min_mac_length is less + * than 1 or too large for the specified MAC algorithm. + */ +#define PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(mac_alg, min_mac_length) \ + /* specification-defined value */ + +/** + * @brief Deterministic ECDSA signature scheme, with hashing. + * + * @details This algorithm can be used with both the message and hash signature functions. + * + * This is the deterministic ECDSA signature scheme defined by Deterministic Usage of the + * Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm + * (ECDSA) [RFC6979]. + * + * The representation of a signature is the same as with @ref PSA_ALG_ECDSA(). + * + * @note When based on the same hash algorithm, the verification operations for + * @ref PSA_ALG_ECDSA and @ref PSA_ALG_DETERMINISTIC_ECDSA are identical. A signature + * created using @ref PSA_ALG_ECDSA can be verified with the same key using either + * @ref PSA_ALG_ECDSA or @ref PSA_ALG_DETERMINISTIC_ECDSA. Similarly, a signature created + * using @ref PSA_ALG_DETERMINISTIC_ECDSA can be verified with the same key using + * either @ref PSA_ALG_ECDSA or @ref PSA_ALG_DETERMINISTIC_ECDSA. + * + * In particular, it is impossible to determine whether a signature was produced with + * deterministic ECDSA or with randomized ECDSA: it is only possible to verify that a + * signature was made with ECDSA with the private key corresponding to the public key used + * for the verification. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_ECC_KEY_PAIR(@p family) + * - @ref PSA_KEY_TYPE_ECC_PUBLIC_KEY(@p family) (signature verification only) + * + * where family is a Weierstrass Elliptic curve family. + * That is, one of the following values: + * - PSA_ECC_FAMILY_SECT_XX + * - PSA_ECC_FAMILY_SECP_XX + * - @ref PSA_ECC_FAMILY_FRP + * - @ref PSA_ECC_FAMILY_BRAINPOOL_P_R1 + * + * @param hash_alg A hash algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_HASH(@p hash_alg) is true. This includes + * @ref PSA_ALG_ANY_HASH when specifying the algorithm in a key policy. + * + * @return The corresponding deterministic ECDSA signature algorithm. + * Unspecified if @c hash_alg is not a supported hash algorithm. + */ +#define PSA_ALG_DETERMINISTIC_ECDSA(hash_alg) \ + ((psa_algorithm_t)(0x06000700 | ((hash_alg) & 0x000000ff))) + +/** + * @brief Macro to construct the MAC algorithm with a full length MAC, from a truncated MAC + * algorithm. + * + * @details @b Compatible @b key @b types + * The resulting untruncated MAC algorithm is compatible with the same key types as the MAC + * algorithm used to construct it. + * + * @param mac_alg A MAC algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_MAC(@p mac_alg) is true. + * This can be a truncated or untruncated MAC algorithm. + * + * @return The corresponding MAC algorithm with a full length MAC. + * Unspecified if @c mac_alg is not a supported MAC algorithm. * + */ +#define PSA_ALG_FULL_LENGTH_MAC(mac_alg) \ + ((psa_algorithm_t)((mac_alg) & ~0x003f0000)) + +/** + * @brief Macro to build an HKDF algorithm. + * + * @details This is the HMAC-based Extract-and-Expand Key Derivation Function (HKDF) specified by + * HMAC-based Extract-and-Expand Key Derivation Function (HKDF) [RFC5869]. + * + * This key derivation algorithm uses the following inputs: + * - @ref PSA_KEY_DERIVATION_INPUT_SALT is the salt used in the “extract” step. It is + * optional; if omitted, the derivation uses an empty salt. + * - @ref PSA_KEY_DERIVATION_INPUT_INFO is the info string used in the “expand” step. + * - @ref PSA_KEY_DERIVATION_INPUT_SECRET is the secret key used in the “extract” step. + * + * If @ref PSA_KEY_DERIVATION_INPUT_SALT is provided, it must be before + * @ref PSA_KEY_DERIVATION_INPUT_SECRET. @ref PSA_KEY_DERIVATION_INPUT_INFO can be + * provided at any time after setup and before starting to generate output. + * + * Each input may only be passed once. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_DERIVE (for the secret key) + * - @ref PSA_KEY_TYPE_RAW_DATA (for the other inputs) + * + * @param hash_alg A hash algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_HASH(@p hash_alg) is true. + * + * @return The corresponding HKDF algorithm. For example, @ref PSA_ALG_HKDF(@ref PSA_ALG_SHA_256) + * is HKDF using HMAC-SHA-256. + * Unspecified if @c hash_alg is not a supported hash algorithm. + */ +#define PSA_ALG_HKDF(hash_alg) \ + ((psa_algorithm_t)(0x08000100 | ((hash_alg) & 0x000000ff))) + +/** + * @brief Get the hash used by a composite algorithm. + * + * The following composite algorithms require a hash algorithm: + * - @ref PSA_ALG_ECDSA() + * - @ref PSA_ALG_HKDF() + * - @ref PSA_ALG_HMAC() + * - @ref PSA_ALG_RSA_OAEP() + * - @ref PSA_ALG_IS_RSA_PKCS1V15_SIGN() + * - @ref PSA_ALG_RSA_PSS() + * - @ref PSA_ALG_RSA_PSS_ANY_SALT() + * - @ref PSA_ALG_TLS12_PRF() + * - @ref PSA_ALG_TLS12_PSK_TO_MS() + * - @ref PSA_ALG_PBKDF2_HMAC() + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return The underlying hash algorithm if alg is a composite algorithm that uses a hash algorithm + * @ref PSA_ALG_NONE if alg is not a composite algorithm that uses a hash. + */ +#define PSA_ALG_GET_HASH(alg) \ + (((alg) & PSA_ALG_HASH_MASK) == \ + 0 ? ((psa_algorithm_t)0) : PSA_ALG_CATEGORY_HASH | ((alg) & PSA_ALG_HASH_MASK)) + +/** + * @brief HMAC Base + */ +#define PSA_ALG_HMAC_BASE (0x03800000) + +/** + * @brief Macro to build an HMAC message-authentication-code algorithm from an underlying hash + * algorithm. + * + * @details For example, @ref PSA_ALG_HMAC(@ref PSA_ALG_SHA_256) is HMAC-SHA-256. + * The HMAC construction is defined in HMAC: Keyed-Hashing for Message Authentication + * [RFC2104]. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_HMAC + * + * @param hash_alg A hash algorithm (PSA_ALG_XXX value such that + * @ref PSA_ALG_IS_HASH(@p hash_alg) is true). + * + * @return The corresponding HMAC algorithm. + * Unspecified if @c hash_alg is not a supported hash algorithm. + */ +#define PSA_ALG_HMAC(hash_alg) \ + ((psa_algorithm_t)(PSA_ALG_HMAC_BASE | ((hash_alg) & PSA_ALG_HASH_MASK))) + +/** + * @brief Whether the specified algorithm is a symmetric cipher algorithm. + * + * @param alg An algorithm identifier (value of type @ref psa_algorithm_t). + * + * @return 1 if alg is a symmetric cipher algorithm, + * 0 if algorithm is not recognized or not supported + */ +#define PSA_ALG_IS_CIPHER(alg) \ + (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_CIPHER) + +/** + * @brief Whether the specified algorithm is an authenticated encryption with + * associated data (AEAD) algorithm. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is an AEAD algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_AEAD(alg) \ + (((alg) & PSA_ALG_CATEGORY_MASK) == 0x05000000) + +/** + * @brief Whether the specified algorithm is an AEAD mode on a block cipher. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is an AEAD algorithm which is an AEAD mode based on a block cipher + * 0 otherwise. + */ +#define PSA_ALG_IS_AEAD_ON_BLOCK_CIPHER(alg) \ + (((alg) & 0x7f400000) == 0x05400000) + +/** + * @brief Whether the specified algorithm is an asymmetric encryption algorithm, also known as + * public-key encryption algorithm. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is an asymmetric encryption algorithm, + * 0 otherwise. + */ +#define PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg) \ + (((alg) & PSA_ALG_CATEGORY_MASK) == 0x07000000) + +/** + * @brief Whether the specified algorithm is a MAC algorithm based on a block cipher. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a MAC algorithm based on a block cipher + * 0 otherwise + */ +#define PSA_ALG_IS_BLOCK_CIPHER_MAC(alg) \ + (((alg) & 0x7fc00000) == 0x03c00000) + +/** + * @brief Whether the specified algorithm is deterministic ECDSA. + * + * See also @ref PSA_ALG_IS_ECDSA() and @ref PSA_ALG_IS_RANDOMIZED_ECDSA(). + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a deterministic ECDSA algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_DETERMINISTIC_ECDSA(alg) \ + (((alg) & ~0x000000ff) == 0x06000700) + +/** + * @brief Whether the specified algorithm is an elliptic curve Diffie-Hellman algorithm. + * + * @details This includes the raw elliptic curve Diffie-Hellman algorithm as well as elliptic curve + * Diffie-Hellman followed by any supporter key derivation algorithm. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is an elliptic curve Diffie-Hellman algorithm + * 0 otherwise. + */ +#define PSA_ALG_IS_ECDH(alg) \ + (((alg) & 0x7fff0000) == 0x09020000) + +/** + * @brief Whether the specified algorithm is a finite field Diffie-Hellman algorithm. + * + * @details This includes the raw finite field Diffie-Hellman algorithm as well as finite-field + * Diffie-Hellman followed by any supported key derivation algorithm. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a finite field Diffie-Hellman algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_FFDH(alg) \ + (((alg) & 0x7fff0000) == 0x09010000) + +/** + * @brief Whether the specified algorithm is ECDSA. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is an ECDSA algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_ECDSA(alg) \ + (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_SIGN) + +/** + * @brief Whether the specified algorithm is a hash algorithm. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a hash algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_HASH(alg) \ + (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_HASH) + +/** + * @brief Get the hash operation of a hmac algorithm + * + * @param hmac_alg HMAC algorithm + */ +#define PSA_ALG_HMAC_GET_HASH(hmac_alg) \ + (PSA_ALG_CATEGORY_HASH | ((hmac_alg) & PSA_ALG_HASH_MASK)) + +/** + * @brief Whether the specified algorithm is HashEdDSA. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a HashEdDSA algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_HASH_EDDSA(alg) \ + (((alg) & ~0x000000ff) == 0x06000900) + +/** + * @brief Whether the specified algorithm is a hash-and-sign algorithm that signs exactly the hash + * value. + * + * @details This macro identifies algorithms that can be used with @ref psa_sign_hash() that use + * the exact message hash value as an input the signature operation. + * For example, if @ref PSA_ALG_IS_HASH_AND_SIGN(@p alg) is true, the following call + * sequence is equivalent to + * @ref psa_sign_message(@p key, @p alg, @p msg, @p msg_len, ...): + * + * @code + * @ref psa_hash_operation_t op = {0}; + * uint8_t hash[@ref PSA_HASH_MAX_SIZE]; + * size_t hash_len; + * @ref psa_hash_setup(&op, @ref PSA_ALG_GET_HASH(alg)); + * @ref psa_hash_update(&op, msg, msg_len); + * @ref psa_hash_finish(&op, hash, sizeof(hash), &hash_len); + * @ref psa_sign_hash(key, alg, hash, hash_len, ...); + * @endcode + * + * This excludes hash-and-sign algorithms that require a encoded or modified hash for the + * signature step in the algorithm, such as @ref PSA_ALG_RSA_PKCS1V15_SIGN_RAW. For such + * algorithms, @ref PSA_ALG_IS_SIGN_HASH() is true but @ref PSA_ALG_IS_HASH_AND_SIGN() is + * false. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a hash-and-sign algorithm that signs exactly the hash value + * 0 otherwise + * A wildcard signature algorithm policy, using @ref PSA_ALG_ANY_HASH, returns the same + * value as the signature algorithm parameterised with a valid hash algorithm. + */ +#define PSA_ALG_IS_HASH_AND_SIGN(alg) \ + (PSA_ALG_IS_RSA_PSS(alg) || PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) || \ + PSA_ALG_IS_ECDSA(alg) || PSA_ALG_IS_HASH_EDDSA(alg)) + +/** + * @brief Whether the specified algorithm is an HKDF algorithm. + * + * @details HKDF is a family of key derivation algorithms that are based on a hash function and the + * HMAC construction. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is an HKDF algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_HKDF(alg) \ + (((alg) & ~0x000000ff) == 0x08000100) + +/** + * @brief Whether the specified algorithm is an HMAC algorithm. + * + * @details HMAC is a family of MAC algorithms that are based on a hash function. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is an HMAC algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_HMAC(alg) \ + (((alg) & 0x7fc0ff00) == 0x03800000) + +/** + * @brief Whether the specified algorithm is a key agreement algorithm. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a key agreement algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_KEY_AGREEMENT(alg) \ + (((alg) & 0x7f000000) == 0x09000000) + +/** + * @brief Whether the specified algorithm is a key derivation algorithm. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a key derivation algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_KEY_DERIVATION(alg) \ + (((alg) & 0x7f000000) == 0x08000000) + +/** + * @brief Whether the specified algorithm is a key-stretching or password-hashing algorithm. + * + * @details A key-stretching or password-hashing algorithm is a key derivation algorithm that is + * suitable for use with a low-entropy secret such as a password. Equivalently, it’s a key + * derivation algorithm that uses a @ref PSA_KEY_DERIVATION_INPUT_PASSWORD input step. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a key-stretching or password-hashing algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_KEY_DERIVATION_STRETCHING(alg) \ + (((alg) & 0x7f800000) == 0x08800000) + +/** + * @brief Whether the specified algorithm is a MAC algorithm. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a MAC algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_MAC(alg) \ + (((alg) & 0x7f000000) == 0x03000000) + +/** + * @brief Whether the specified algorithm is a PBKDF2-HMAC algorithm. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a PBKDF2-HMAC algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_PBKDF2_HMAC(alg) \ + (((alg) & ~0x000000ff) == 0x08800100) + +/** + * @brief Whether the specified algorithm is randomized ECDSA. + * + * @details See also @ref PSA_ALG_IS_ECDSA() and @ref PSA_ALG_IS_DETERMINISTIC_ECDSA(). + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is arandomized ECDSA algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_RANDOMIZED_ECDSA(alg) \ + (((alg) & ~0x000000ff) == 0x06000600) + +/** + * @brief Whether the specified algorithm is a raw key agreement algorithm. + * + * @details A raw key agreement algorithm is one that does not specify a key derivation function. + * Usually, raw key agreement algorithms are constructed directly with a + * PSA_ALG_xxx macro while non-raw key agreement algorithms are constructed with + * @ref PSA_ALG_KEY_AGREEMENT(). + * + * The raw key agreement algorithm can be extracted from a full key agreement algorithm + * identifier using @ref PSA_ALG_KEY_AGREEMENT_GET_BASE(). + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a raw key agreement algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_RAW_KEY_AGREEMENT(alg) \ + (((alg) & 0x7f00ffff) == 0x09000000) + +/** + * @brief Whether the specified algorithm is an RSA OAEP encryption algorithm. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a RSA OAEP algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_RSA_OAEP(alg) \ + (((alg) & ~0x000000ff) == 0x07000300) + +/** + * @brief Whether the specified algorithm is an RSA PKCS#1 v1.5 signature algorithm. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a RSA PKCS#1 v1.5 signature algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) \ + (((alg) & ~0x000000ff) == 0x06000200) + +/** + * @brief Whether the specified algorithm is a RSA PSS signature algorithm. + * + * @details This macro returns 1 for algorithms constructed using either @ref PSA_ALG_RSA_PSS() or + * @ref PSA_ALG_RSA_PSS_ANY_SALT(). + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a RSA PSS signature algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_RSA_PSS(alg) \ + (((alg) & ~0x000000ff) == 0x06000300) + +/** + * @brief Whether the specified algorithm is an RSA PSS signature algorithm that permits any salt + * length. + * + * @details An RSA PSS signature algorithm that permits any salt length is constructed using + * @ref PSA_ALG_RSA_PSS_ANY_SALT(). + * + * See also @ref PSA_ALG_IS_RSA_PSS() and @ref PSA_ALG_IS_RSA_PSS_STANDARD_SALT(). + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a RSA PSS signature algorithm that permits any salt length + * 0 otherwise + */ +#define PSA_ALG_IS_RSA_PSS_ANY_SALT(alg) \ + (((alg) & ~0x000000ff) == 0x06001300) + +/** + * @brief Whether the specified algorithm is an RSA PSS signature algorithm that requires the + * standard salt length. + * + * @details An RSA PSS signature algorithm that requires the standard salt length is constructed + * using @ref PSA_ALG_RSA_PSS(). + * + * See also @ref PSA_ALG_IS_RSA_PSS() and @ref PSA_ALG_IS_RSA_PSS_ANY_SALT(). + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is an RSA PSS signature algorithm that requires the standard salt length + * 0 otherwise + */ +#define PSA_ALG_IS_RSA_PSS_STANDARD_SALT(alg) \ + (((alg) & ~0x000000ff) == 0x06000300) + +/** + * @brief Whether the specified algorithm is an asymmetric signature algorithm, also known as + * public-key signature algorithm. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is an asymmetric signature algorithm algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_SIGN(alg) \ + (((alg) & 0x7f000000) == 0x06000000) + +/** + * @brief Whether the specified algorithm is a signature algorithm that can be used with + * @ref psa_sign_hash() and @ref psa_verify_hash(). + * + * @details This includes all algorithms such that @ref PSA_ALG_IS_HASH_AND_SIGN() is true, + * as well as signature algorithms for which the input to @ref psa_sign_hash() or + * @ref psa_verify_hash() is not directly a hash, such as + * @ref PSA_ALG_IS_RSA_PKCS1V15_SIGN. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a signature algorithm that can be used to sign a hash. + * 0 if alg is a signature algorithm that can only be used to sign a message. + * 0 if alg is not a signature algorithm + */ +#define PSA_ALG_IS_SIGN_HASH(alg) \ + PSA_ALG_IS_SIGN(alg) + +/** + * @brief Whether the specified algorithm is a signature algorithm that can be used with + * @ref psa_sign_message() and @ref psa_verify_message(). + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a signature algorithm that can be used to sign a message. + * 0 if alg is a signature algorithm that can only be used to sign an already-calculated + * hash. + * 0 if alg is not a signature algorithm. + */ +#define PSA_ALG_IS_SIGN_MESSAGE(alg) \ + (PSA_ALG_IS_SIGN(alg) && \ + (alg) != PSA_ALG_ECDSA_ANY && (alg) != PSA_ALG_RSA_PKCS1V15_SIGN_RAW) + +/** + * @brief Whether the specified algorithm is a stream cipher. + * + * @details A stream cipher is a symmetric cipher that encrypts or decrypts messages by applying a + * bitwise-xor with a stream of bytes that is generated from a key. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a stream cipher + * 0 otherwise + */ +#define PSA_ALG_IS_STREAM_CIPHER(alg) \ + (((alg) & 0x7f800000) == 0x04800000) + +/** + * @brief Whether the specified algorithm is a TLS-1.2 PRF algorithm. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a TLS-1.2 PRF algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_TLS12_PRF(alg) \ + (((alg) & ~0x000000ff) == 0x08000200) + +/** + * @brief Whether the specified algorithm is a TLS-1.2 PSK to MS algorithm. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a TLS-1.2 PSK to MS algorithm + * 0 otherwise + */ +#define PSA_ALG_IS_TLS12_PSK_TO_MS(alg) \ + (((alg) & ~0x000000ff) == 0x08000300) + +/** + * @brief Whether the specified algorithm encoding is a wildcard. + * + * @details Wildcard algorithm values can only be used to set the permitted algorithm field in a + * key policy, wildcard values cannot be used to perform an operation. + * + * See @ref PSA_ALG_ANY_HASH for example of how a wildcard algorithm can be used in a key + * policy. + * + * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t. + * + * @return 1 if alg is a wildcard algorithm encoding. + * 0 if alg is a non-wildcard algorithm encoding that is suitable for an operation. + */ +#define PSA_ALG_IS_WILDCARD(alg) \ + (PSA_ALG_GET_HASH(alg) == PSA_ALG_HASH_ANY) + +/** + * @brief Macro to build a combined algorithm that chains a key agreement with a key derivation. + * + * @details A combined key agreement algorithm is used with a multi-part key derivation operation, + * using a call to @ref psa_key_derivation_key_agreement(). + * + * The component parts of a key agreement algorithm can be extracted using + * @ref PSA_ALG_KEY_AGREEMENT_GET_BASE() and @ref PSA_ALG_KEY_AGREEMENT_GET_KDF(). + * + * @b Compatible @b key @b types + * The resulting combined key agreement algorithm is compatible with the same key types as + * the raw key agreement algorithm used to construct it. + * + * @param ka_alg A key agreement algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_KEY_AGREEMENT(@p ka_alg) is true. + * @param kdf_alg A key derivation algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_KEY_DERIVATION(@p kdf_alg) is true. + * + * @return The corresponding key agreement and derivation algorithm. + * Unspecified if ka_alg is not a supported key agreement algorithm or kdf_alg is not a + * supported key derivation algorithm. + */ +#define PSA_ALG_KEY_AGREEMENT(ka_alg, kdf_alg) \ + ((ka_alg) | (kdf_alg)) + +/** + * @brief Get the raw key agreement algorithm from a full key agreement algorithm. + * + * @details See also @ref PSA_ALG_KEY_AGREEMENT() and @ref PSA_ALG_KEY_AGREEMENT_GET_KDF(). + * + * @param alg A key agreement algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_KEY_AGREEMENT(@p alg) is true. + * + * @return The underlying raw key agreement algorithm if @c alg is a key agreement algorithm. + * Unspecified if alg is not a key agreement algorithm or if it is not supported by the + * implementation. + */ +#define PSA_ALG_KEY_AGREEMENT_GET_BASE(alg) \ + ((psa_algorithm_t)((alg) & 0xffff0000)) + +/** + * @brief Get the key derivation algorithm used in a full key agreement algorithm. + * + * @details See also @ref PSA_ALG_KEY_AGREEMENT() and @ref PSA_ALG_KEY_AGREEMENT_GET_BASE(). + * + * @param alg A key agreement algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_KEY_AGREEMENT(@p alg) is true. + * + * @return The underlying key derivation algorithm if @c alg is a key agreement algorithm. + * Unspecified if alg is not a key agreement algorithm or if it is not supported by the + * implementation. + */ +#define PSA_ALG_KEY_AGREEMENT_GET_KDF(alg) \ + ((psa_algorithm_t)((alg) & 0xfe00ffff)) + +/** + * @brief An invalid algorithm identifier value. + * + * @details Zero is not the encoding of any algorithm. + */ +#define PSA_ALG_NONE ((psa_algorithm_t)0) + +/** + * @brief Hash algorithm mask + */ +#define PSA_ALG_HASH_MASK ((psa_algorithm_t)0x000000ff) + +/** + * @brief The MD2 message-digest algorithm. + * + * @warning The MD2 hash is weak and deprecated and is only recommended + * for use in legacy protocols. + * + * @details MD2 is defined in *The MD2 Message-Digest Algorithm + * [RFC1319](https://tools.ietf.org/html/rfc1319.html)*. + */ +#define PSA_ALG_MD2 ((psa_algorithm_t)0x02000001) + +/** + * @brief The MD4 message-digest algorithm. + * + * @warning The MD4 hash is weak and deprecated and is only recommended + * for use in legacy protocols. + * + * @details MD4 is defined in *The MD4 Message-Digest Algorithm + * [RFC1320](https://tools.ietf.org/html/rfc1320.html)*. + */ +#define PSA_ALG_MD4 ((psa_algorithm_t)0x02000002) + +/** + * @brief The MD5 message-digest algorithm. + * + * @warning The MD5 hash is weak and deprecated and is only recommended + * for use in legacy protocols. + * + * @details MD5 is defined in *The MD5 Message-Digest Algorithm + * [RFC1321](https://tools.ietf.org/html/rfc1321.html)*. + */ +#define PSA_ALG_MD5 ((psa_algorithm_t)0x02000003) + +/** + * @brief The RIPEMD-160 message-digest algorithm. + * + * @details RIPEMD-160 is defined in *RIPEMD-160: A Strengthened Version of RIPEMD*, + * and also in *ISO/IEC 10118-3:2018 IT Security techniques — Hash-functions — Part 3: + * Dedicated hash-functions [ISO10118](https://www.iso.org/standard/67116.html)*. + */ +#define PSA_ALG_RIPEMD160 ((psa_algorithm_t)0x02000004) + +/** + * @brief The SHA-1 message-digest algorithm. + * + * @warning The SHA-1 hash is weak and deprecated and is only recommended + * for use in legacy protocols. + * + * @details SHA-1 is defined in FIPS Publication 180-4: Secure Hash Standard (SHS) + * [FIPS180-4](https://doi.org/10.6028/NIST.FIPS.180-4). + */ +#define PSA_ALG_SHA_1 ((psa_algorithm_t)0x02000005) + +/** + * @brief The SHA-224 message-digest algorithm. + * + * @details SHA-224 is defined in FIPS Publication 180-4: Secure Hash Standard (SHS) + * [FIPS180-4](https://doi.org/10.6028/NIST.FIPS.180-4). + */ +#define PSA_ALG_SHA_224 ((psa_algorithm_t)0x02000008) /** SHA-224 */ + +/** + * @brief The SHA-256 message-digest algorithm. + * + * @details SHA-256 is defined in FIPS Publication 180-4: Secure Hash Standard (SHS) + * [FIPS180-4](https://doi.org/10.6028/NIST.FIPS.180-4). + */ +#define PSA_ALG_SHA_256 ((psa_algorithm_t)0x02000009) /** SHA-256 */ + +/** + * @brief The SHA-384 message-digest algorithm. + * + * @details SHA-384 is defined in FIPS Publication 180-4: Secure Hash Standard (SHS) + * [FIPS180-4](https://doi.org/10.6028/NIST.FIPS.180-4). + */ +#define PSA_ALG_SHA_384 ((psa_algorithm_t)0x0200000a) /** SHA-384 */ + +/** + * @brief The SHA-512 message-digest algorithm. + * + * @details SHA-512 is defined in FIPS Publication 180-4: Secure Hash Standard (SHS) + * [FIPS180-4](https://doi.org/10.6028/NIST.FIPS.180-4). + */ +#define PSA_ALG_SHA_512 ((psa_algorithm_t)0x0200000b) /** SHA-512 */ + +/** + * @brief The SHA-512/224 message-digest algorithm. + * + * @details SHA-512-224 is defined in FIPS Publication 180-4: Secure Hash Standard (SHS) + * [FIPS180-4](https://doi.org/10.6028/NIST.FIPS.180-4). + */ +#define PSA_ALG_SHA_512_224 ((psa_algorithm_t)0x0200000c) /** SHA-512/224 */ + +/** + * @brief The SHA-512/256 message-digest algorithm. + * + * @details SHA-512-256 is defined in FIPS Publication 180-4: Secure Hash Standard (SHS) + * [FIPS180-4](https://doi.org/10.6028/NIST.FIPS.180-4). + */ +#define PSA_ALG_SHA_512_256 ((psa_algorithm_t)0x0200000d) /** SHA-512/256 */ + +/** + * @brief The SHA3-224 message-digest algorithm. + * + * @details SHA3-224 is defined in FIPS Publication 202: *SHA-3 Standard: Permutation-Based + * Hash and Extendable-Output Functions [FIPS202](https://doi.org/10.6028/NIST.FIPS.202)*. + */ +#define PSA_ALG_SHA3_224 ((psa_algorithm_t)0x02000010) /** SHA-3-224 */ + +/** + * @brief The SHA3-256 message-digest algorithm. + * + * @details SHA3-256 is defined in [FIPS202](https://doi.org/10.6028/NIST.FIPS.202). + */ +#define PSA_ALG_SHA3_256 ((psa_algorithm_t)0x02000011) /** SHA-3-256 */ + +/** + * @brief The SHA3-384 message-digest algorithm. + * + * @details SHA3-384 is defined in [FIPS202](https://doi.org/10.6028/NIST.FIPS.202). + */ +#define PSA_ALG_SHA3_384 ((psa_algorithm_t)0x02000012) /** SHA-3-384 */ + +/** + * @brief The SHA3-512 message-digest algorithm. + * + * @details SHA3-512 is defined in [FIPS202](https://doi.org/10.6028/NIST.FIPS.202). + */ +#define PSA_ALG_SHA3_512 ((psa_algorithm_t)0x02000013) /** SHA-3-512 */ + +/** + * @brief The SM3 message-digest algorithm. + * + * @details SM3 is defined in *ISO/IEC 10118-3:2018 IT Security techniques — Hash-functions — + * Part 3: Dedicated hash-functions [ISO10118](https://www.iso.org/standard/67116.html)*, + * and also in *GM/T 0004-2012: SM3 cryptographic hash algorithm + * [CSTC0004](http://www.gmbz.org.cn/main/viewfile/20180108023812835219.html) + * (English version + * [CSTC0004/E](http://www.gmbz.org.cn/main/postDetail.html?id=20180724105928))*. + */ +#define PSA_ALG_SM3 ((psa_algorithm_t)0x02000014) /** SM3 */ + +/** + * @brief The first 512 bits (64 bytes) of the SHAKE256 output. + * + * @details This is the prehashing for Ed448ph (see @ref PSA_ALG_ED448PH). + * + * SHAKE256 is defined in [FIPS202](https://doi.org/10.6028/NIST.FIPS.202). + * + * @note For other scenarios where a hash function based on SHA3 or SHAKE is required, SHA3-512 + * is recommended. SHA3-512 has the same output size, and a theoretically higher security + * strength. + */ +#define PSA_ALG_SHAKE256_512 ((psa_algorithm_t)0x02000015) + +/** + * @brief The CBC-MAC message-authentication-code algorithm, constructed over a block cipher. + * + * @warning CBC-MAC is insecure in many cases. A more secure mode, such as @ref PSA_ALG_CMAC, + * is recommended. + * + * @details The CBC-MAC algorithm must be used with a key for a block cipher. + * For example, one of @ref PSA_KEY_TYPE_AES. + * + * CBC-MAC is defined as MAC Algorithm 1 in ISO/IEC 9797-1:2011 Information technology — + * Security techniques — Message Authentication Codes (MACs) — Part 1: Mechanisms using a + * block cipher + * [ISO9797](https://www.iso.org/standard/50375.html). + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_AES + * - @ref PSA_KEY_TYPE_ARIA + * - @ref PSA_KEY_TYPE_DES + * - @ref PSA_KEY_TYPE_CAMELLIA + * - @ref PSA_KEY_TYPE_SM4 + */ +#define PSA_ALG_CBC_MAC ((psa_algorithm_t)0x03c00100) + +/** + * @brief The CMAC message-authentication-code algorithm, constructed over a block cipher. + * + * @details The CMAC algorithm must be used with a key for a block cipher. For example, when used + * with a key with type @ref PSA_KEY_TYPE_AES, the resulting operation is AES-CMAC. + * + * CMAC is defined in NIST Special Publication 800-38B: Recommendation for Block Cipher + * Modes of Operation: the CMAC Mode for Authentication + * [SP800-38B](https://doi.org/10.6028/NIST.SP.800-38B). + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_AES + * - @ref PSA_KEY_TYPE_ARIA + * - @ref PSA_KEY_TYPE_DES + * - @ref PSA_KEY_TYPE_CAMELLIA + * - @ref PSA_KEY_TYPE_SM4 + */ +#define PSA_ALG_CMAC ((psa_algorithm_t)0x03c00200) + +/** + * @brief The Cipher Block Chaining (CBC) mode of a block cipher, with no padding. + * + * @details The underlying block cipher is determined by the key type. This symmetric cipher mode + * can only be used with messages whose lengths are a multiple of the block size of the + * chosen block cipher. + * + * CBC mode requires an initialization vector (IV) that is the same size as the cipher + * block length. + * + * @note The cipher block length can be determined using @ref PSA_BLOCK_CIPHER_BLOCK_LENGTH(). + * + * The CBC block cipher mode is defined in NIST Special Publication 800-38A: + * Recommendation for Block Cipher Modes of Operation: Methods and Techniques + * [SP800-38A](https://doi.org/10.6028/NIST.SP.800-38B). + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_AES + * - @ref PSA_KEY_TYPE_ARIA + * - @ref PSA_KEY_TYPE_DES + * - @ref PSA_KEY_TYPE_CAMELLIA + * - @ref PSA_KEY_TYPE_SM4 + */ +#define PSA_ALG_CBC_NO_PADDING ((psa_algorithm_t)0x04404000) + +/** + * @brief The Cipher Block Chaining (CBC) mode of a block cipher, with PKCS#7 padding. + * + * @details The underlying block cipher is determined by the key type. + * + * CBC mode requires an initialization vector (IV) that is the same size as the cipher + * block length. + * + * @note The cipher block length can be determined using @ref PSA_BLOCK_CIPHER_BLOCK_LENGTH(). + * + * The CBC block cipher mode is defined in NIST Special Publication 800-38A: + * Recommendation for Block Cipher Modes of Operation: Methods and Techniques + * [SP800-38A](https://doi.org/10.6028/NIST.SP.800-38B). + * The padding operation is defined by PKCS #7: Cryptographic Message Syntax Version 1.5 + * [RFC2315](https://tools.ietf.org/html/rfc2315.html) §10.3. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_AES + * - @ref PSA_KEY_TYPE_ARIA + * - @ref PSA_KEY_TYPE_DES + * - @ref PSA_KEY_TYPE_CAMELLIA + * - @ref PSA_KEY_TYPE_SM4 + */ +#define PSA_ALG_CBC_PKCS7 ((psa_algorithm_t)0x04404100) + +/** + * @brief The Electronic Codebook (ECB) mode of a block cipher, with no padding. + * + * @warning ECB mode does not protect the confidentiality of the encrypted data except in extremely + * narrow circumstances. It is recommended that applications only use ECB if they need to + * construct an operating mode that the implementation does not provide. Implementations + * are encouraged to provide the modes that applications need in preference to supporting + * direct access to ECB. + * + * @details The underlying block cipher is determined by the key type. + * + * This symmetric cipher mode can only be used with messages whose lengths are a multiple + * of the block size of the chosen block cipher. + * + * ECB mode does not accept an initialization vector (IV). When using a multi-part cipher + * operation with this algorithm, @ref psa_cipher_generate_iv() and + * @ref psa_cipher_set_iv() must not be called. + * + * @note The cipher block length can be determined using @ref PSA_BLOCK_CIPHER_BLOCK_LENGTH(). + * + * The ECB block cipher mode is defined in NIST Special Publication 800-38A: + * Recommendation for Block Cipher Modes of Operation: Methods and Techniques + * [SP800-38A](https://doi.org/10.6028/NIST.SP.800-38A). + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_AES + * - @ref PSA_KEY_TYPE_ARIA + * - @ref PSA_KEY_TYPE_DES + * - @ref PSA_KEY_TYPE_CAMELLIA + * - @ref PSA_KEY_TYPE_SM4 + */ +#define PSA_ALG_ECB_NO_PADDING ((psa_algorithm_t)0x04404400) + +/** + * @brief The XEX with Ciphertext Stealing (XTS) cipher mode of a block cipher. + * + * @details XTS is a cipher mode which is built from a block cipher, designed for use in disk + * encryption. It requires at least one full cipher block length of input, but beyond this + * minimum the input does not need to be a whole number of blocks. + * + * XTS mode uses two keys for the underlying block cipher. These are provided by using a + * key that is twice the normal key size for the cipher. For example, to use AES-256-XTS + * the application must create a key with type @ref PSA_KEY_TYPE_AES and bit size 512. + * + * XTS mode requires an initialization vector (IV) that is the same size as the cipher + * block length. The IV for XTS is typically defined to be the sector number of the disk + * block being encrypted or decrypted. + * + * The XTS block cipher mode is defined in 1619-2018 --- IEEE Standard for Cryptographic + * Protection of Data on Block-Oriented Storage Devices + * [IEEE-XTS](https://ieeexplore.ieee.org/servlet/opac?punumber=8637986). + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_AES + * - @ref PSA_KEY_TYPE_ARIA + * - @ref PSA_KEY_TYPE_DES + * - @ref PSA_KEY_TYPE_CAMELLIA + * - @ref PSA_KEY_TYPE_SM4 + */ +#define PSA_ALG_XTS ((psa_algorithm_t)0x0440ff00) + +/** + * @brief A stream cipher built using the Counter (CTR) mode of a block cipher. + * + * @details CTR is a stream cipher which is built from a block cipher. The underlying block cipher + * is determined by the key type. For example, to use AES-128-CTR, use this algorithm with + * a key of type @ref PSA_KEY_TYPE_AES and a size of 128 bits (16 bytes). + * + * The CTR block cipher mode is defined in NIST Special Publication 800-38A: + * Recommendation for Block Cipher Modes of Operation: Methods and Techniques [SP800-38A]. + * + * CTR mode requires a counter block which is the same size as the cipher block length. + * The counter block is updated for each block (or a partial final block) that is + * encrypted or decrypted. + * + * A counter block value must only be used once across all messages encrypted using the + * same key value. This is typically achieved by splitting the counter block into a nonce, + * which is unique among all message encrypted with the key, and a counter which is + * incremented for each block of a message. + * + * For example, when using AES-CTR encryption, which uses a 16-byte block, the application + * can provide a 12-byte nonce when setting the IV. This leaves 4 bytes for the counter, + * allowing up to 2^32 blocks (64GB) of message data to be encrypted in each message. + * + * The first counter block is constructed from the initialization vector (IV). The initial + * counter block is is constructed in the following ways: + * - A call to @ref psa_cipher_encrypt() will generate a random counter block value. + * This is the first block of output. + * - A call to @ref psa_cipher_decrypt() will use first block of the input buffer as the + * initial counter block value. + * - A call to @ref psa_cipher_generate_iv() on a multi-part cipher operation will + * generate and return a random counter block value. + * - A call to @ref psa_cipher_set_iv() on a multi-part cipher operation requires an IV + * that is between 1 and n bytes in length, where n is the cipher block length. The + * counter block is initialized using the IV, and padded with zero bytes up to the + * block length. + * + * During the counter block update operation, the counter block is treated as a single + * big-endian encoded integer and the update operation increments this integer by 1. + * + * This scheme meets the recommendations in Appendix B of + * [SP800-38A](https://doi.org/10.6028/NIST.SP.800-38A). + * + * @note The cipher block length can be determined using @ref PSA_BLOCK_CIPHER_BLOCK_LENGTH(). + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_AES + * - @ref PSA_KEY_TYPE_ARIA + * - @ref PSA_KEY_TYPE_DES + * - @ref PSA_KEY_TYPE_CAMELLIA + * - @ref PSA_KEY_TYPE_SM4 + */ +#define PSA_ALG_CTR ((psa_algorithm_t)0x04c01000) + +/** + * @brief A stream cipher built using the Cipher Feedback (CFB) mode of a block cipher. + * + * @details The underlying block cipher is determined by the key type. This is the variant of CFB + * where each iteration encrypts or decrypts a segment of the input that is the same + * length as the cipher block size. For example, using @ref PSA_ALG_CFB with a key of type + * @ref PSA_KEY_TYPE_AES will result in the AES-CFB-128 cipher. + * + * CFB mode requires an initialization vector (IV) that is the same size as the cipher + * block length. + * + * @note The cipher block length can be determined using @ref PSA_BLOCK_CIPHER_BLOCK_LENGTH(). + * + * The CFB block cipher mode is defined in NIST Special Publication 800-38A: + * Recommendation for Block Cipher Modes of Operation: Methods and Techniques + * [SP800-38A](https://doi.org/10.6028/NIST.SP.800-38A), using a segment size s equal + * to the block size b. The definition in + * [SP800-38A](https://doi.org/10.6028/NIST.SP.800-38A) is + * extended to allow an incomplete final block of input, in which case the algorithm + * discards the final bytes of the key stream when encrypting or decrypting the final + * partial block. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_AES + * - @ref PSA_KEY_TYPE_ARIA + * - @ref PSA_KEY_TYPE_DES + * - @ref PSA_KEY_TYPE_CAMELLIA + * - @ref PSA_KEY_TYPE_SM4 + */ +#define PSA_ALG_CFB ((psa_algorithm_t)0x04c01100) + +/** + * @brief A stream cipher built using the Output Feedback (OFB) mode of a block cipher. + * + * @details The underlying block cipher is determined by the key type. + * + * OFB mode requires an initialization vector (IV) that is the same size as the cipher + * block length. OFB mode requires that the IV is a nonce, and must be unique for each use + * of the mode with the same key. + * + * @note The cipher block length can be determined using @ref PSA_BLOCK_CIPHER_BLOCK_LENGTH(). + * + * The OFB block cipher mode is defined in NIST Special Publication 800-38A: + * Recommendation for Block Cipher Modes of Operation: Methods and Techniques + * [SP800-38A](https://doi.org/10.6028/NIST.SP.800-38A). + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_AES + * - @ref PSA_KEY_TYPE_ARIA + * - @ref PSA_KEY_TYPE_DES + * - @ref PSA_KEY_TYPE_CAMELLIA + * - @ref PSA_KEY_TYPE_SM4 + */ +#define PSA_ALG_OFB ((psa_algorithm_t)0x04c01200) + +/** + * @brief The stream cipher mode of a stream cipher algorithm. + * + * @details The underlying stream cipher is determined by the key type. The ARC4 and ChaCha20 + * ciphers use this algorithm identifier. + * + * @b ARC4 + * To use ARC4, use a key type of @ref PSA_KEY_TYPE_ARC4 and algorithm id + * @ref PSA_ALG_STREAM_CIPHER. + * + * @warning The ARC4 cipher is weak and deprecated and is only recommended for use in legacy + * protocols. + * + * The ARC4 cipher does not use an initialization vector (IV). When using a multi-part + * cipher operation with the @ref PSA_ALG_STREAM_CIPHER algorithm and an ARC4 key, + * @ref psa_cipher_generate_iv() and @ref psa_cipher_set_iv() must not be called. + * + * @b ChaCha20 + * To use ChaCha20, use a key type of @ref PSA_KEY_TYPE_CHACHA20 and algorithm id + * @ref PSA_ALG_STREAM_CIPHER. + * + * Implementations must support the variant that is defined in ChaCha20 and Poly1305 for + * IETF Protocols [RFC7539](https://tools.ietf.org/html/rfc7539.html) §2.4, which has a + * 96-bit nonce and a 32-bit counter. + * Implementations can optionally also support the original variant, as defined in ChaCha, + * a variant of Salsa20 [CHACHA20](http://cr.yp.to/chacha/chacha-20080128.pdf), + * which has a 64-bit nonce and a 64-bit counter. Except where noted, the + * [RFC7539](https://tools.ietf.org/html/rfc7539.html) variant must be used. + * + * ChaCha20 defines a nonce and an initial counter to be provided to the encryption and + * decryption operations. When using a ChaCha20 key with the @ref PSA_ALG_STREAM_CIPHER + * algorithm, these values are provided using the initialization vector (IV) functions in + * the following ways: + * - A call to @ref psa_cipher_encrypt() will generate a random 12-byte nonce, and set + * the counter value to zero. The random nonce is output as a 12-byte IV value in the + * output. + * - A call to @ref psa_cipher_decrypt() will use first 12 bytes of the input buffer as + * the nonce and set the counter value to zero. + * - A call to @ref psa_cipher_generate_iv() on a multi-part cipher operation will + * generate and return a random 12-byte nonce and set the counter value to zero. + * - A call to @ref psa_cipher_set_iv() on a multi-part cipher operation can support + * the following IV sizes: + * - 12 bytes: the provided IV is used as the nonce, and the counter value is + * set to zero. + * - 16 bytes: the first four bytes of the IV are used as the counter value (encoded + * as little-endian), and the remaining 12 bytes is used as the nonce. + * - 8 bytes: the cipher operation uses the original + * [CHACHA20](http://cr.yp.to/chacha/chacha-20080128.pdf) definition of + * ChaCha20: the provided IV is used as the 64-bit nonce, and the 64-bit counter + * value is set to zero. + * - It is recommended that implementations do not support other sizes of IV. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_ARC4 + * - @ref PSA_KEY_TYPE_CHACHA20 + */ +#define PSA_ALG_STREAM_CIPHER ((psa_algorithm_t)0x04800100) + +/** + * @brief The ChaCha20-Poly1305 AEAD algorithm. + * + * @details There are two defined variants of ChaCha20-Poly1305: + * - An implementation that supports ChaCha20-Poly1305 must support the variant defined + * by ChaCha20 and Poly1305 for IETF Protocols + * [RFC7539](https://tools.ietf.org/html/rfc7539.html), which has a 96-bit nonce and + * 32-bit counter. + * - An implementation can optionally also support the original variant defined by + * ChaCha, a variant of Salsa20 + * [CHACHA20](http://cr.yp.to/chacha/chacha-20080128.pdf), which has a 64-bit nonce + * and 64-bit counter. + * + * The variant used for the AEAD encryption or decryption operation, depends on the nonce + * provided for an AEAD operation using @ref PSA_ALG_CHACHA20_POLY1305 : + * - A nonce provided in a call to @ref psa_aead_encrypt(), @ref psa_aead_decrypt() or + * @ref psa_aead_set_nonce() must be 8 or 12 bytes. The size of nonce will select the + * appropriate variant of the algorithm. + * - A nonce generated by a call to @ref psa_aead_generate_nonce() will be 12 bytes, and + * will use the [RFC7539](https://tools.ietf.org/html/rfc7539.html) variant. + * + * Implementations must support 16-byte tags. It is recommended that truncated tag sizes + * are rejected. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_CHACHA20 + */ +#define PSA_ALG_CHACHA20_POLY1305 ((psa_algorithm_t)0x05100500) + +/** + * @brief The Counter with CBC-MAC (CCM) authenticated encryption algorithm. + * + * @details CCM is defined for block ciphers that have a 128-bit block size. The underlying block + * cipher is determined by the key type. + * + * To use @ref PSA_ALG_CCM with a multi-part AEAD operation, the application must call + * @ref psa_aead_set_lengths() before providing the nonce, the additional data and + * plaintext to the operation. + * + * CCM requires a nonce of between 7 and 13 bytes in length. The length of the nonce + * affects the `m` maximum length of the plaintext than can be encrypted or decrypted. If + * the nonce has length `N`, then the plaintext length `pLen` is encoded in `L = 15 - N` + * octets, this requires that `pLen < 28L`. + * + * The value for L that is used with PSA_ALG_CCM depends on the function used to provide + * the nonce: + * - A call to @ref psa_aead_encrypt(), @ref psa_aead_decrypt(), or @ref + * psa_aead_set_nonce() will set `L` to 15 - nonce_length. If the plaintext length + * cannot be encoded in `L` octets, then a @ref PSA_ERROR_INVALID_ARGUMENT error is + * returned. + * - A call to @ref psa_aead_generate_nonce() on a multi-part cipher operation will + * select `L` as the smallest integer `>= 2` where `pLen < 28L`, with `pLen` being the + * plaintext_length provided to @ref psa_aead_set_lengths(). The call to @ref + * psa_aead_generate_nonce() will generate and return a random nonce of length + * `15 - L` bytes. + * + * CCM supports authentication tag sizes of 4, 6, 8, 10, 12, 14, and 16 bytes. The default + * tag length is 16. Shortened tag lengths can be requested using + * @ref PSA_ALG_AEAD_WITH_SHORTENED_TAG(@ref PSA_ALG_CCM, @p tag_length), + * where @c tag_length is a valid CCM tag length. + * + * The CCM block cipher mode is defined in Counter with CBC-MAC (CCM) + * [RFC3610](https://tools.ietf.org/html/rfc3610). + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_AES + * - @ref PSA_KEY_TYPE_ARIA + * - @ref PSA_KEY_TYPE_CAMELLIA + * - @ref PSA_KEY_TYPE_SM4 + */ +#define PSA_ALG_CCM ((psa_algorithm_t)0x05500100) + +/** + * @brief The Galois/Counter Mode (GCM) authenticated encryption algorithm. + * + * @details GCM is defined for block ciphers that have a 128-bit block size. The underlying block + * cipher is determined by the key type. + * + * GCM requires a nonce of at least 1 byte in length. The maximum supported nonce size is + * implementation defined. Calling @ref psa_aead_generate_nonce() will generate a random + * 12-byte nonce. + * + * GCM supports authentication tag sizes of 4, 8, 12, 13, 14, 15, and 16 bytes. The + * default tag length is 16. Shortened tag lengths can be requested using + * @ref PSA_ALG_AEAD_WITH_SHORTENED_TAG(@ref PSA_ALG_GCM, @p tag_length), where + * @c tag_length is a valid GCM tag length. + * + * The GCM block cipher mode is defined in NIST Special Publication 800-38D: + * Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC + * [SP800-38D](https://doi.org/10.6028/NIST.SP.800-38D). + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_AES + * - @ref PSA_KEY_TYPE_ARIA + * - @ref PSA_KEY_TYPE_CAMELLIA + * - @ref PSA_KEY_TYPE_SM4 + */ +#define PSA_ALG_GCM ((psa_algorithm_t)0x05500200) + +/** + * @brief The PBKDF2-AES-CMAC-PRF-128 password-hashing or key-stretching algorithm. + * + * @details PBKDF2 is specified by PKCS #5: Password-Based Cryptography Specification Version 2.1 + * [RFC8018](https://tools.ietf.org/html/rfc8018.html) §5.2. This algorithm specifies the + * PBKDF2 algorithm using the AES-CMAC-PRF-128 pseudo-random function specified by + * [RFC4615](https://tools.ietf.org/html/rfc4615.html). + * + * This key derivation algorithm uses the same inputs as @ref PSA_ALG_PBKDF2_HMAC() with + * the same constraints. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_DERIVE (for password input) + * - @ref PSA_KEY_TYPE_PASSWORD (for password input) + * - @ref PSA_KEY_TYPE_PEPPER (for salt input) + * - @ref PSA_KEY_TYPE_RAW_DATA (for salt input) + * - @ref PSA_KEY_TYPE_PASSWORD_HASH (for key verification) + */ +#define PSA_ALG_PBKDF2_AES_CMAC_PRF_128 ((psa_algorithm_t)0x08800200) + +/** + * @brief Macro to build a PBKDF2-HMAC password-hashing or key-stretching algorithm. + * + * @details PBKDF2 is specified by PKCS #5: Password-Based Cryptography Specification Version 2.1 + * [RFC8018](https://tools.ietf.org/html/rfc8018.html) §5.2. This macro constructs a + * PBKDF2 algorithm that uses a pseudo-random function based on HMAC with the specified + * hash. + * + * This key derivation algorithm uses the following inputs, which must be provided in the + * following order: + * - @ref PSA_KEY_DERIVATION_INPUT_COST is the iteration count. This input step must be + * used exactly once. + * - @ref PSA_KEY_DERIVATION_INPUT_SALT is the salt. This input step must be used one or + * more times; if used several times, the inputs will be concatenated. This can be + * used to build the final salt from multiple sources, both public and secret (also + * known as pepper). + * - @ref PSA_KEY_DERIVATION_INPUT_PASSWORD is the password to be hashed. This input + * step must be used exactly once. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_DERIVE (for password input) + * - @ref PSA_KEY_TYPE_PASSWORD (for password input) + * - @ref PSA_KEY_TYPE_PEPPER (for salt input) + * - @ref PSA_KEY_TYPE_RAW_DATA (for salt input) + * - @ref PSA_KEY_TYPE_PASSWORD_HASH (for key verification) + * + * @param hash_alg A hash algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_HASH(@p hash_alg) is true. + * + * @return The corresponding `PBKDF2-HMAC-XXX` algorithm. For example, + * @ref PSA_ALG_PBKDF2_HMAC(@ref PSA_ALG_SHA_256) is the algorithm identifier for + * `PBKDF2-HMAC-SHA-256`. + * Unspecified if @c hash_alg is not a supported hash algorithm. + */ +#define PSA_ALG_PBKDF2_HMAC(hash_alg) \ + ((psa_algorithm_t)(0x08800100 | ((hash_alg) & 0x000000ff))) + +/** + * @brief The raw RSA PKCS#1 v1.5 signature algorithm, without hashing. + * + * @details This algorithm can be only used with the @ref psa_sign_hash() and @ref psa_verify_hash() + * functions. + * This signature scheme is defined by PKCS #1: RSA Cryptography Specifications Version 2.2 + * [RFC8017](https://tools.ietf.org/html/rfc8017.html) §8.2 under the name + * RSASSA-PKCS1-v1_5. + * + * The hash parameter to @ref psa_sign_hash() or @ref psa_verify_hash() is used as `T` + * from step 3 onwards in the message encoding algorithm EMSA-PKCS1-V1_5-ENCODE() in + * [RFC8017](https://tools.ietf.org/html/rfc8017.html) §9.2.0 `T` is the DER encoding of + * the DigestInfo structure normally produced by step 2 in the message encoding algorithm. + * + * The wildcard key policy @ref PSA_ALG_RSA_PKCS1V15_SIGN(@ref PSA_ALG_ANY_HASH) also + * permits a key to be used with the @ref PSA_ALG_RSA_PKCS1V15_SIGN_RAW signature + * algorithm. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_RSA_KEY_PAIR + * - @ref PSA_KEY_TYPE_RSA_PUBLIC_KEY (signature verification only) + */ +#define PSA_ALG_RSA_PKCS1V15_SIGN_RAW ((psa_algorithm_t)0x06000200) + +/** + * @brief Base of ECDSA algorithms + */ +#define PSA_ALG_ECDSA_BASE ((psa_algorithm_t)0x06000600) + +/** + * @brief Edwards-curve digital signature algorithm without prehashing (PureEdDSA), + * using standard parameters. + * + * @details This algorithm can be only used with the @ref psa_sign_message() and + * @ref psa_verify_message() functions. + * + * This is the PureEdDSA digital signature algorithm defined by Edwards-Curve Digital + * Signature Algorithm (EdDSA) [RFC8032](https://tools.ietf.org/html/rfc8032.html), + * using standard parameters. + * + * PureEdDSA requires an elliptic curve key on a twisted Edwards curve. The following + * curves are supported: + * - Edwards25519: the Ed25519 algorithm is computed. The output signature is a 64-byte + * string: the concatenation of R and S as defined by + * [RFC8032](https://tools.ietf.org/html/rfc8032.html) §5.1.6. + * - Edwards448: the Ed448 algorithm is computed with an empty string as the context. + * The output signature is a 114-byte string: the concatenation of R and S as defined + * by [RFC8032](https://tools.ietf.org/html/rfc8032.html) §5.2.6. + * + * @note Contexts are not supported in the current version of this specification because there + * is no suitable signature interface that can take the context as a parameter. A future + * version of this specification may add suitable functions and extend this algorithm to + * support contexts. + * + * @note To sign or verify the pre-computed hash of a message using EdDSA, the HashEdDSA + * algorithms (@ref PSA_ALG_ED25519PH and @ref PSA_ALG_ED448PH) can be used with + * @ref psa_sign_hash() and @ref psa_verify_hash(). + * The signature produced by HashEdDSA is distinct from that produced by PureEdDSA. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS) + * - @ref PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_TWISTED_EDWARDS) (signature + * verification only) + */ +#define PSA_ALG_PURE_EDDSA ((psa_algorithm_t)0x06000800) + +/** + * @brief The randomized ECDSA signature scheme, with hashing. + * + * @details This algorithm can be used with both the message and hash signature functions. + * + * This algorithm is randomized: each invocation returns a different, equally valid + * signature. + * + * @note When based on the same hash algorithm, the verification operations for + * @ref PSA_ALG_ECDSA and @ref PSA_ALG_DETERMINISTIC_ECDSA are identical. + * A signature created using @ref PSA_ALG_ECDSA can be verified with the same key using + * either @ref PSA_ALG_ECDSA or @ref PSA_ALG_DETERMINISTIC_ECDSA. + * Similarly, a signature created using @ref PSA_ALG_DETERMINISTIC_ECDSA can be verified + * with the same key using either @ref PSA_ALG_ECDSA or @ref PSA_ALG_DETERMINISTIC_ECDSA. + * + * In particular, it is impossible to determine whether a signature was produced with + * deterministic ECDSA or with randomized ECDSA: it is only possible to verify that a + * signature was made with ECDSA with the private key corresponding to the public key used + * for the verification. + * + * This signature scheme is defined by SEC 1: Elliptic Curve Cryptography + * [SEC1](https://www.secg.org/sec1-v2.pdf), and also by Public Key Cryptography For The + * Financial Services Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA) + * [X9-62])(https://standards.globalspec.com/std/1955141/ANSI%20X9.62), with a random + * per-message secret number `k`. + * + * The representation of the signature as a byte string consists of the concatenation of + * the signature values `r` and `s`. Each of `r` and `s` is encoded as an `N`-octet + * string, where `N` is the length of the base point of the curve in octets. Each value is + * represented in big-endian order, with the most significant octet first. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_ECC_KEY_PAIR(family) + * - @ref PSA_KEY_TYPE_ECC_PUBLIC_KEY(family) (signature verification only) + * + * where family is a Weierstrass Elliptic curve family. That is, one of the following + * values: + * - @c PSA_ECC_FAMILY_SECT_XX + * - @c PSA_ECC_FAMILY_SECP_XX + * - @ref PSA_ECC_FAMILY_FRP + * - @ref PSA_ECC_FAMILY_BRAINPOOL_P_R1 + * + * @param hash_alg A hash algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_HASH(@p hash_alg) is true. This includes + * @ref PSA_ALG_ANY_HASH when specifying the algorithm in a key policy. + * + * @return The corresponding randomized ECDSA signature algorithm. + * Unspecified if @c hash_alg is not a supported hash algorithm. + */ +#define PSA_ALG_ECDSA(hash_alg) \ + (PSA_ALG_ECDSA_BASE | ((hash_alg) & PSA_ALG_HASH_MASK)) + +/** + * @brief The randomized ECDSA signature scheme, without hashing. + * + * @details This algorithm can be only used with the @ref psa_sign_hash() and @ref psa_verify_hash() + * functions. + * + * This algorithm is randomized: each invocation returns a different, equally valid + * signature. + * + * This is the same signature scheme as @ref PSA_ALG_ECDSA(), but without specifying a hash + * algorithm, and skipping the message hashing operation. + * + * This algorithm is only recommended to sign or verify a sequence of bytes that are an + * already-calculated hash. Note that the input is padded with zeros on the left or + * truncated on the right as required to fit the curve size. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_ECC_KEY_PAIR(@p family) + * - @ref PSA_KEY_TYPE_ECC_PUBLIC_KEY(@p family) (signature verification only) + * + * where @c family is a Weierstrass Elliptic curve family. That is, one of the following + * values: + * - @c PSA_ECC_FAMILY_SECT_XX + * - @c PSA_ECC_FAMILY_SECP_XX + * - @ref PSA_ECC_FAMILY_FRP + * - @ref PSA_ECC_FAMILY_BRAINPOOL_P_R1 + */ +#define PSA_ALG_ECDSA_ANY PSA_ALG_ECDSA_BASE + +/** + * @brief Edwards-curve digital signature algorithm with prehashing (HashEdDSA), using the + * Edwards25519 curve. + * + * @details This algorithm can be used with both the message and hash signature functions. + * + * This computes the Ed25519ph algorithm as specified in Edwards-Curve Digital Signature + * Algorithm (EdDSA) [RFC8032](https://tools.ietf.org/html/rfc8032.html) §5.1, and + * requires an Edwards25519 curve key. An empty string is used as the context. The prehash + * function is SHA-512. + * + * @b Usage + * This is a hash-and-sign algorithm. To calculate a signature, use one of the following + * approaches: + * - Call @ref psa_sign_message() with the message. + * - Calculate the SHA-512 hash of the message with @ref psa_hash_compute(), or with a + * multi-part hash operation, using the hash algorithm @ref PSA_ALG_SHA_512. Then sign + * the calculated hash with @ref psa_sign_hash(). + * + * Verifying a signature is similar, using @ref psa_verify_message() or + * @ref psa_verify_hash() instead of the signature function. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_ECC_KEY_PAIR(@ref PSA_ECC_FAMILY_TWISTED_EDWARDS) + * - @ref PSA_KEY_TYPE_ECC_PUBLIC_KEY(@ref PSA_ECC_FAMILY_TWISTED_EDWARDS) (signature + * verification only) + */ +#define PSA_ALG_ED25519PH ((psa_algorithm_t)0x0600090B) + +/** + * @brief Edwards-curve digital signature algorithm with prehashing (HashEdDSA), using the + * Edwards448 curve. + * + * @details This algorithm can be used with both the message and hash signature functions. + * + * This computes the Ed448ph algorithm as specified in Edwards-Curve Digital Signature + * Algorithm (EdDSA) [RFC8032](https://tools.ietf.org/html/rfc8032.html) §5.2, and + * requires an Edwards448 curve key. An empty string is used as the context. The prehash + * function is the first 64 bytes of the output from SHAKE256. + * + * @b Usage + * This is a hash-and-sign algorithm. To calculate a signature, use one of the following + * approaches: + * - Call @ref psa_sign_message() with the message. + * - Calculate the first 64 bytes of the SHAKE256 output of the message with + * @ref psa_hash_compute(), or with a multi-part hash operation, using the hash + * algorithm @ref PSA_ALG_SHAKE256_512. Then sign the calculated hash with + * @ref psa_sign_hash(). + * + * Verifying a signature is similar, using @ref psa_verify_message() or + * @ref psa_verify_hash() instead of the signature function. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_ECC_KEY_PAIR(@ref PSA_ECC_FAMILY_TWISTED_EDWARDS) + * - @ref PSA_KEY_TYPE_ECC_PUBLIC_KEY(@ref PSA_ECC_FAMILY_TWISTED_EDWARDS) (signature + * verification only) + */ +#define PSA_ALG_ED448PH ((psa_algorithm_t)0x06000915) + +/** + * @brief The RSA PKCS#1 v1.5 asymmetric encryption algorithm. + * + * @details This encryption scheme is defined by PKCS #1: RSA Cryptography Specifications + * Version 2.2 [RFC8017](https://tools.ietf.org/html/rfc8017.html) §7.2 under the + * name RSAES-PKCS-v1_5. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_RSA_KEY_PAIR + * - @ref PSA_KEY_TYPE_RSA_PUBLIC_KEY (asymmetric encryption only) + */ +#define PSA_ALG_RSA_PKCS1V15_CRYPT ((psa_algorithm_t)0x07000200) + +/** + * @brief The finite-field Diffie-Hellman (DH) key agreement algorithm. + * + * @details This algorithm can be used directly in a call to @ref psa_raw_key_agreement(), + * or combined with a key derivation operation using @ref PSA_ALG_KEY_AGREEMENT() for use + * with @ref psa_key_derivation_key_agreement(). + * + * When used as a key’s permitted algorithm policy, the following uses are permitted: + * - In a call to @ref psa_raw_key_agreement(), with algorithm @ref PSA_ALG_FFDH. + * - In a call to @ref psa_key_derivation_key_agreement(), with any combined key + * agreement and key derivation algorithm constructed with @ref PSA_ALG_FFDH. + * + * When used as part of a multi-part key derivation operation, this implements a + * Diffie-Hellman key agreement scheme using a single Diffie-Hellman key-pair for each + * participant. This includes the `dhEphem`, `dhOneFlow`, and `dhStatic` schemes. + * The input step @ref PSA_KEY_DERIVATION_INPUT_SECRET is used when providing the secret + * and peer keys to the operation. + * + * The shared secret produced by this key agreement algorithm is `g^{ab}` in big-endian + * format. It is `ceiling(m / 8)` bytes long where `m` is the size of the prime `p` in + * bits. + * + * This key agreement scheme is defined by NIST Special Publication 800-56A: + * Recommendation for Pair-Wise Key-Establishment Schemes Using Discrete Logarithm + * Cryptography [SP800-56A](https://doi.org/10.6028/NIST.SP.800-56Ar3) §5.7.1.1 + * under the name FFC DH. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_DH_KEY_PAIR() + */ +#define PSA_ALG_FFDH ((psa_algorithm_t)0x09010000) + +/** + * @brief The elliptic curve Diffie-Hellman (ECDH) key agreement algorithm. + * + * @details This algorithm can be used directly in a call to @ref psa_raw_key_agreement(), or + * combined with a key derivation operation using @ref PSA_ALG_KEY_AGREEMENT() for use + * with @ref psa_key_derivation_key_agreement(). + * + * When used as a key’s permitted algorithm policy, the following uses are permitted: + * - In a call to @ref psa_raw_key_agreement(), with algorithm @ref PSA_ALG_ECDH. + * - In a call to @ref psa_key_derivation_key_agreement(), with any combined key + * agreement and key derivation algorithm constructed with @ref PSA_ALG_ECDH. + * + * When used as part of a multi-part key derivation operation, this implements a + * Diffie-Hellman key agreement scheme using a single elliptic curve key-pair for each + * participant. This includes the Ephemeral unified model, the Static unified model, and + * the One-pass Diffie-Hellman schemes. The input step + * @ref PSA_KEY_DERIVATION_INPUT_SECRET is used when providing the secret and peer keys + * to the operation. + * + * The shared secret produced by key agreement is the x-coordinate of the shared secret + * point. It is always `ceiling(m / 8)` bytes long where `m` is the bit size associated + * with the curve, i.e. the bit size of the order of the curve’s coordinate field. When + * `m` is not a multiple of 8, the byte containing the most significant bit of the shared + * secret is padded with zero bits. The byte order is either little-endian or big-endian + * depending on the curve type. + * + * - For Montgomery curves (curve family @ref PSA_ECC_FAMILY_MONTGOMERY), the shared + * secret is the x-coordinate of `Z = d_A Q_B = d_B Q_A` in little-endian byte order. + * - For Curve25519, this is the X25519 function defined in Curve25519: new + * Diffie-Hellman speed records + * [Curve25519](https://www.iacr.org/archive/pkc2006/39580209/39580209.pdf). + * The bit size `m` is 255. + * - For Curve448, this is the X448 function defined in Ed448-Goldilocks, a new + * elliptic curve [Curve448](https://eprint.iacr.org/2015/625.pdf). + * The bit size `m` is 448. + * - For Weierstrass curves (curve families @c PSA_ECC_FAMILY_SECP_XX, + * @c PSA_ECC_FAMILY_SECT_XX, @ref PSA_ECC_FAMILY_BRAINPOOL_P_R1 and + * @ref PSA_ECC_FAMILY_FRP) the shared secret is the x-coordinate of + * `Z = h d_A Q_B = h d_B Q_A` in big-endian byte order. This is the Elliptic Curve + * Cryptography Cofactor Diffie-Hellman primitive defined by SEC 1: Elliptic Curve + * Cryptography [SEC1](https://www.secg.org/sec1-v2.pdf) §3.3.2 as, and also as ECC + * CDH by NIST Special Publication 800-56A: Recommendation for Pair-Wise + * Key-Establishment Schemes Using Discrete Logarithm Cryptography + * [SP800-56A](https://doi.org/10.6028/NIST.SP.800-56Ar3) §5.7.1.2. + * - Over prime fields (curve families @c PSA_ECC_FAMILY_SECP_XX, + * @ref PSA_ECC_FAMILY_BRAINPOOL_P_R1 and @ref PSA_ECC_FAMILY_FRP), + * the bit size is `m = ceiling(log_2(p))` for the field `F_p`. + * - Over binary fields (curve families @c PSA_ECC_FAMILY_SECT_XX), the bit size + * is `m` for the field `F_{2^m}`. + * + * @note The cofactor Diffie-Hellman primitive is equivalent to the standard elliptic curve + * Diffie-Hellman calculation `Z = d_A Q_B = d_B Q_A` + * ([SEC1](https://www.secg.org/sec1-v2.pdf) §3.3.1) for curves where the cofactor `h` + * is 1. This is true for all curves in the @c PSA_ECC_FAMILY_SECP_XX, + * @ref PSA_ECC_FAMILY_BRAINPOOL_P_R1, and @ref PSA_ECC_FAMILY_FRP families. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_ECC_KEY_PAIR(@p family) + * + * where @p family is a Weierstrass or Montgomery Elliptic curve family. That is, one of + * the following values: + * - @c PSA_ECC_FAMILY_SECT_XX + * - @c PSA_ECC_FAMILY_SECP_XX + * - @ref PSA_ECC_FAMILY_FRP + * - @ref PSA_ECC_FAMILY_BRAINPOOL_P_R1 + * - @ref PSA_ECC_FAMILY_MONTGOMERY + */ +#define PSA_ALG_ECDH ((psa_algorithm_t)0x09020000) + +/** + * @brief The RSA OAEP asymmetric encryption algorithm. + * + * @details This encryption scheme is defined by + * [RFC8017](https://tools.ietf.org/html/rfc8017.html) §7.1 under the name RSAES-OAEP, + * with the following options: + * - The mask generation function MGF1 defined in + * [RFC8017](https://tools.ietf.org/html/rfc8017.html) Appendix B.2.1. + * - The specified hash algorithm is used to hash the label, and for the mask generation + * function. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_RSA_KEY_PAIR + * - @ref PSA_KEY_TYPE_RSA_PUBLIC_KEY (asymmetric encryption only) + * + * @param hash_alg A hash algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_HASH(@p hash_alg) is true. The hash algorithm is used for + * MGF1. + * + * @return The corresponding RSA OAEP encryption algorithm. + * Unspecified if @c hash_alg is not a supported hash algorithm. + */ +#define PSA_ALG_RSA_OAEP(hash_alg) \ + ((psa_algorithm_t)(0x07000300 | ((hash_alg) & 0x000000ff))) + +/** + * @brief The RSA PKCS#1 v1.5 message signature scheme, with hashing. + * + * @details This algorithm can be used with both the message and hash signature functions. + * + * This signature scheme is defined by PKCS #1: RSA Cryptography Specifications Version 2.2 + * [RFC8017](https://tools.ietf.org/html/rfc8017.html) §8.2 under the name + * RSASSA-PKCS1-v1_5. + * + * When used with @ref psa_sign_hash() or @ref psa_verify_hash(), the provided hash + * parameter is used as `H` from step 2 onwards in the message encoding algorithm + * EMSA-PKCS1-V1_5-ENCODE() in [RFC8017](https://tools.ietf.org/html/rfc8017.html) §9.2. + * `H` is usually the message digest, using the @c hash_alg hash algorithm. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_RSA_KEY_PAIR + * - @ref PSA_KEY_TYPE_RSA_PUBLIC_KEY (signature verification only) + * + * @param hash_alg A hash algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_HASH(@p hash_alg) is true. This includes + * @ref PSA_ALG_ANY_HASH when specifying the algorithm in a key policy. + * + * @return The corresponding RSA PKCS#1 v1.5 signature algorithm. + * Unspecified if @c hash_alg is not a supported hash algorithm. + */ +#define PSA_ALG_RSA_PKCS1V15_SIGN(hash_alg) \ + ((psa_algorithm_t)(0x06000200 | ((hash_alg) & 0x000000ff))) + +/** + * @brief The RSA PSS message signature scheme, with hashing. + * + * @details This algorithm can be used with both the message and hash signature functions. + * + * This algorithm is randomized: each invocation returns a different, equally valid + * signature. + * + * This is the signature scheme defined by + * [RFC8017](https://tools.ietf.org/html/rfc8017.html) §8.1 under the name RSASSA-PSS, + * with the following options: + * - The mask generation function is MGF1 defined by + * [RFC8017](https://tools.ietf.org/html/rfc8017.html) Appendix B. + * - When creating a signature, the salt length is equal to the length of the hash, or + * the largest possible salt length for the algorithm and key size if that is smaller + * than the hash length. + * - When verifying a signature, the salt length must be equal to the length of the + * hash, or the largest possible salt length for the algorithm and key size if that is + * smaller than the hash length. + * - The specified hash algorithm is used to hash the input message, to create the + * salted hash, and for the mask generation. + * + * @note The @ref PSA_ALG_RSA_PSS_ANY_SALT() algorithm is equivalent to @ref PSA_ALG_RSA_PSS() + * when creating a signature, but permits any salt length when verifying a signature. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_RSA_KEY_PAIR + * - @ref PSA_KEY_TYPE_RSA_PUBLIC_KEY (signature verification only) + */ +#define PSA_ALG_RSA_PSS(hash_alg) \ + ((psa_algorithm_t)(0x06000300 | ((hash_alg) & 0x000000ff))) + +/** + * @brief The RSA PSS message signature scheme, with hashing. This variant permits any salt length + * for signature verification. + * + * @details This algorithm can be used with both the message and hash signature functions. + * + * This algorithm is randomized: each invocation returns a different, equally valid + * signature. + * + * This is the signature scheme defined by + * [RFC8017](https://tools.ietf.org/html/rfc8017.html) §8.1 under the name RSASSA-PSS, + * with the following options: + * - The mask generation function is MGF1 defined by + * [RFC8017](https://tools.ietf.org/html/rfc8017.html) Appendix B. + * - When creating a signature, the salt length is equal to the length of the hash, or + * the largest possible salt length for the algorithm and key size if that is smaller + * than the hash length. + * - When verifying a signature, any salt length permitted by the RSASSA-PSS signature + * algorithm is accepted. + * - The specified hash algorithm is used to hash the input message, to create the + * salted hash, and for the mask generation. + * + * @note The @ref PSA_ALG_RSA_PSS() algorithm is equivalent to @ref PSA_ALG_RSA_PSS_ANY_SALT() + * when creating a signature, but is strict about the permitted salt length when verifying + * a signature. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_RSA_KEY_PAIR + * - @ref PSA_KEY_TYPE_RSA_PUBLIC_KEY (signature verification only) + */ +#define PSA_ALG_RSA_PSS_ANY_SALT(hash_alg) \ + ((psa_algorithm_t)(0x06001300 | ((hash_alg) & 0x000000ff))) + +/** + * @brief Macro to build a TLS-1.2 PRF algorithm. + * + * @details TLS 1.2 uses a custom pseudorandom function (PRF) for key schedule, specified in + * The Transport Layer Security (TLS) Protocol Version 1.2 + * [RFC5246](https://tools.ietf.org/html/rfc5246.html) §5. It is based on + * HMAC and can be used with either SHA-256 or SHA-384. + * + * This key derivation algorithm uses the following inputs, which must be passed in the + * order given here: + * - @ref PSA_KEY_DERIVATION_INPUT_SEED is the seed. + * - @ref PSA_KEY_DERIVATION_INPUT_SECRET is the secret key. + * - @ref PSA_KEY_DERIVATION_INPUT_LABEL is the label. + * + * Each input may only be passed once. + * + * For the application to TLS-1.2 key expansion: + * - The seed is the concatenation of @c ServerHello.Random + @c ClientHello.Random. + * - The label is `key expansion`. + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_DERIVE (for the secret key) + * - @ref PSA_KEY_TYPE_RAW_DATA (for the other inputs) + * + * @param hash_alg A hash algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_HASH(@p hash_alg) is true. + * + * @return The corresponding TLS-1.2 PRF algorithm. For example, + * @ref PSA_ALG_TLS12_PRF(@p PSA_ALG_SHA_256) represents the TLS 1.2 PRF using + * HMAC-SHA-256. + * Unspecified if @c hash_alg is not a supported hash algorithm. + */ +#define PSA_ALG_TLS12_PRF(hash_alg) \ + ((psa_algorithm_t)(0x08000200 | ((hash_alg) & 0x000000ff))) + +/** + * @brief Macro to build a TLS-1.2 PSK-to-MasterSecret algorithm. + * + * @details In a pure-PSK handshake in TLS 1.2, the master secret (MS) is derived from the + * pre-shared key (PSK) through the application of padding (Pre-Shared Key Ciphersuites + * for Transport Layer Security (TLS) [RFC4279](https://tools.ietf.org/html/rfc4279.html) + * §2) and the TLS-1.2 PRF (The Transport Layer Security (TLS) Protocol Version 1.2 + * [RFC5246](https://tools.ietf.org/html/rfc5246.html) §5). The latter is based on HMAC + * and can be used with either SHA-256 or SHA-384. + * + * This key derivation algorithm uses the following inputs, which must be passed in the + * order given here: + * - @ref PSA_KEY_DERIVATION_INPUT_SEED is the seed. + * - @ref PSA_KEY_DERIVATION_INPUT_SECRET is the PSK. The PSK must not be larger than + * @ref PSA_TLS12_PSK_TO_MS_PSK_MAX_SIZE. + * - @ref PSA_KEY_DERIVATION_INPUT_LABEL is the label. + * + * Each input may only be passed once. + * + * For the application to TLS-1.2: + * - The seed, which is forwarded to the TLS-1.2 PRF, is the concatenation of the + * @c ClientHello.Random + @c ServerHello.Random. + * - The label is "master secret" or "extended master secret". + * + * @b Compatible @b key @b types + * - @ref PSA_KEY_TYPE_DERIVE (for the PSK) + * - @ref PSA_KEY_TYPE_RAW_DATA (for the other inputs) + */ +#define PSA_ALG_TLS12_PSK_TO_MS(hash_alg) \ + ((psa_algorithm_t)(0x08000300 | ((hash_alg) & 0x000000ff))) + +/** + * @brief Macro to build a truncated MAC algorithm. + * + * @details A truncated MAC algorithm is identical to the corresponding MAC algorithm except that + * the MAC value for the truncated algorithm consists of only the first mac_length bytes + * of the MAC value for the untruncated algorithm. + * + * @note This macro might allow constructing algorithm identifiers that are not valid, either + * because the specified length is larger than the untruncated MAC or because the + * specified length is smaller than permitted by the implementation. + * + * @note It is implementation-defined whether a truncated MAC that is truncated to the same + * length as the MAC of the untruncated algorithm is considered identical to the + * untruncated algorithm for policy comparison purposes. + * + * The untruncated MAC algorithm can be recovered using @ref PSA_ALG_FULL_LENGTH_MAC(). + * + * @b Compatible @b key @b types + * The resulting truncated MAC algorithm is compatible with the same key types as the MAC + * algorithm used to construct it. + * + * @param mac_alg A MAC algorithm: a value of type @ref psa_algorithm_t such that + * @ref PSA_ALG_IS_MAC(@p mac_alg) is true. This can be a truncated or + * untruncated MAC algorithm. + * @param mac_length Desired length of the truncated MAC in bytes. This must be at most the + * untruncated length of the MAC and must be at least an + * implementation-specified minimum. The implementation-specified minimum must + * not be zero. + * + * @return The corresponding MAC algorithm with the specified length. + * Unspecified if @c mac_alg is not a supported MAC algorithm or if @c mac_length is too + * small or too large for the specified MAC algorithm. + */ +#define PSA_ALG_TRUNCATED_MAC(mac_alg, mac_length) \ + ((psa_algorithm_t)(((mac_alg) & ~0x003f0000) | (((mac_length) & 0x3f) << 16))) + +/** + * @brief Finite-field Diffie-Hellman groups defined for TLS in RFC 7919. + * + * @details This family includes groups with the following key sizes (in bits): 2048, 3072, 4096, + * 6144, 8192. An implementation can support all of these sizes or only a subset. + * + * Keys is this group can only be used with the @ref PSA_ALG_FFDH key agreement algorithm. + * + * These groups are defined by Negotiated Finite Field Diffie-Hellman Ephemeral Parameters + * for Transport Layer Security (TLS) [RFC7919](https://tools.ietf.org/html/rfc7919.html) + * Appendix A. + */ +#define PSA_DH_FAMILY_RFC7919 ((psa_dh_family_t)0x03) + +/** + * @brief Brainpool `P` random curves. + * + * @details This family comprises the following curves: + * - `brainpoolP160r1` : @c key_bits = 160 (Deprecated) + * - `brainpoolP192r1` : @c key_bits = 192 + * - `brainpoolP224r1` : @c key_bits = 224 + * - `brainpoolP256r1` : @c key_bits = 256 + * - `brainpoolP320r1` : @c key_bits = 320 + * - `brainpoolP384r1` : @c key_bits = 384 + * - `brainpoolP512r1` : @c key_bits = 512 + * + * They are defined in Elliptic Curve Cryptography (ECC) Brainpool Standard Curves and + * Curve Generation [RFC5639](https://tools.ietf.org/html/rfc5639.html). + * + * @warning The 160-bit curve `brainpoolP160r1` is weak and deprecated and is only recommended for + * use in legacy protocols. + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_DETERMINISTIC_ECDSA + * - @ref PSA_ALG_ECDSA + * - @ref PSA_ALG_ECDSA_ANY + * - @ref PSA_ALG_ECDH (key pair only) + */ +#define PSA_ECC_FAMILY_BRAINPOOL_P_R1 ((psa_ecc_family_t)0x30) + +/** + * @brief Curve used primarily in France and elsewhere in Europe. + * + * @details This family comprises one 256-bit curve: + * - `FRP256v1` : @c key_bits = 256 + * + * This is defined by Publication d'un paramétrage de courbe elliptique visant des + * applications de passeport électronique et de l'administration électronique française + * [FRP](https://www.ssi.gouv.fr/agence/rayonnement-scientifique/ + * publications-scientifiques/articles-ouvrages-actes). + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_DETERMINISTIC_ECDSA + * - @ref PSA_ALG_ECDSA + * - @ref PSA_ALG_ECDSA_ANY + * - @ref PSA_ALG_ECDH (key pair only) + */ +#define PSA_ECC_FAMILY_FRP ((psa_ecc_family_t)0x33) + +/** + * @brief Montgomery curves. + * + * @details This family comprises the following Montgomery curves: + * - `Curve25519` : @c key_bits = 255 + * - `Curve448` : @c key_bits = 448 + * + * `Curve25519` is defined in Curve25519: new Diffie-Hellman speed records + * [Curve25519](https://www.iacr.org/archive/pkc2006/39580209/39580209.pdf). + * `Curve448` is defined in Ed448-Goldilocks, a new elliptic curve + * [Curve448](https://eprint.iacr.org/2015/625.pdf). + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_ECDH (key pair only) + */ +#define PSA_ECC_FAMILY_MONTGOMERY ((psa_ecc_family_t)0x41) + +/** + * @brief SEC Koblitz curves over prime fields. + * + * @details This family comprises the following curves: + * - `secp192k1` : @c key_bits = 192 + * - `secp224k1` : @c key_bits = 225 + * - `secp256k1` : @c key_bits = 256 + * + * They are defined in SEC 2: Recommended Elliptic Curve Domain Parameters + * [SEC2](https://www.secg.org/sec2-v2.pdf). + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_DETERMINISTIC_ECDSA + * - @ref PSA_ALG_ECDSA + * - @ref PSA_ALG_ECDSA_ANY + * - @ref PSA_ALG_ECDH (key pair only) + */ +#define PSA_ECC_FAMILY_SECP_K1 ((psa_ecc_family_t)0x17) + +/** + * @brief SEC random curves over prime fields. + * + * @details This family comprises the following curves: + * - `secp192r1` : @c key_bits = 192 + * - `secp224r1` : @c key_bits = 224 + * - `secp256r1` : @c key_bits = 256 + * - `secp384r1` : @c key_bits = 384 + * - `secp521r1` : @c key_bits = 521 + * + * They are defined in [SEC2](https://www.secg.org/sec2-v2.pdf). + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_DETERMINISTIC_ECDSA + * - @ref PSA_ALG_ECDSA + * - @ref PSA_ALG_ECDSA_ANY + * - @ref PSA_ALG_ECDH (key pair only) + */ +#define PSA_ECC_FAMILY_SECP_R1 ((psa_ecc_family_t)0x12) + +/** + * @warning This family of curves is weak and deprecated. + * + * @details This family comprises the following curves: + * - `secp160r2` : @c key_bits = 160 (Deprecated) + * + * It is defined in the superseded SEC 2: Recommended Elliptic Curve Domain Parameters, + * Version 1.0 [SEC2v1](https://www.secg.org/SEC2-Ver-1.0.pdf). + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_DETERMINISTIC_ECDSA + * - @ref PSA_ALG_ECDSA + * - @ref PSA_ALG_ECDSA_ANY + * - @ref PSA_ALG_ECDH (key pair only) + */ +#define PSA_ECC_FAMILY_SECP_R2 ((psa_ecc_family_t)0x1b) + +/** + * @brief SEC Koblitz curves over binary fields. + * + * @details This family comprises the following curves: + * - `sect163k1` : @c key_bits = 163 (Deprecated) + * - `sect233k1` : @c key_bits = 233 + * - `sect239k1` : @c key_bits = 239 + * - `sect283k1` : @c key_bits = 283 + * - `sect409k1` : @c key_bits = 409 + * - `sect571k1` : @c key_bits = 571 + * + * They are defined in [SEC2](https://www.secg.org/sec2-v2.pdf). + * + * @warning The 163-bit curve `sect163k1` is weak and deprecated and is only recommended for use in + * legacy protocols. + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_DETERMINISTIC_ECDSA + * - @ref PSA_ALG_ECDSA + * - @ref PSA_ALG_ECDSA_ANY + * - @ref PSA_ALG_ECDH (key pair only) + */ +#define PSA_ECC_FAMILY_SECT_K1 ((psa_ecc_family_t)0x27) + +/** + * @brief SEC random curves over binary fields. + * + * @details This family comprises the following curves: + * - `sect163r1` : @c key_bits = 163 (Deprecated) + * - `sect233r1` : @c key_bits = 233 + * - `sect283r1` : @c key_bits = 283 + * - `sect409r1` : @c key_bits = 409 + * - `sect571r1` : @c key_bits = 571 + * + * They are defined in [SEC2](https://www.secg.org/sec2-v2.pdf). + * + * @warning The 163-bit curve `sect163r1` is weak and deprecated and is only recommended for use in + * legacy protocols. + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_DETERMINISTIC_ECDSA + * - @ref PSA_ALG_ECDSA + * - @ref PSA_ALG_ECDSA_ANY + * - @ref PSA_ALG_ECDH (key pair only) + */ +#define PSA_ECC_FAMILY_SECT_R1 ((psa_ecc_family_t)0x22) + +/** + * @brief SEC additional random curves over binary fields. + * + * @details This family comprises the following curves: + * - `sect163r2` : @c key_bits = 163 (Deprecated) + * + * It is defined in [SEC2](https://www.secg.org/sec2-v2.pdf). + * + * @warning The 163-bit curve `sect163r2` is weak and deprecated and is only recommended for use in + * legacy protocols. + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_DETERMINISTIC_ECDSA + * - @ref PSA_ALG_ECDSA + * - @ref PSA_ALG_ECDSA_ANY + * - @ref PSA_ALG_ECDH (key pair only) + */ +#define PSA_ECC_FAMILY_SECT_R2 ((psa_ecc_family_t)0x2b) + +/** + * @brief Twisted Edwards curves. + * + * @details This family comprises the following twisted Edwards curves: + * - `Edwards25519` : @c key_bits = 255. This curve is birationally equivalent to + * `Curve25519`. + * - `Edwards448` : @c key_bits = 448. This curve is birationally equivalent to `Curve448`. + * + * Edwards25519 is defined in Twisted Edwards curves + * [Ed25519](https://eprint.iacr.org/2008/013.pdf). Edwards448 is defined in + * Ed448-Goldilocks, a new elliptic curve [Curve448](https://eprint.iacr.org/2015/625.pdf). + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_PURE_EDDSA + * - @ref PSA_ALG_ED25519PH (Edwards25519 only) + * - @ref PSA_ALG_ED448PH (Edwards448 only) + */ +#define PSA_ECC_FAMILY_TWISTED_EDWARDS ((psa_ecc_family_t)0x42) + +/** + * @brief A context for key derivation. + * + * @details This is typically a direct input. It can also be a key of type + * @ref PSA_KEY_TYPE_RAW_DATA. + */ +#define PSA_KEY_DERIVATION_INPUT_CONTEXT /* implementation-defined value */ + +/** + * @brief A cost parameter for password hashing or key stretching. + * + * @details This must be a direct input, passed to @ref psa_key_derivation_input_integer(). + */ +#define PSA_KEY_DERIVATION_INPUT_COST /* implementation-defined value */ + +/** + * @brief An information string for key derivation. + * + * @details This is typically a direct input. It can also be a key of type + * @ref PSA_KEY_TYPE_RAW_DATA. + */ +#define PSA_KEY_DERIVATION_INPUT_INFO /* implementation-defined value */ + +/** + * @brief A label for key derivation. + * + * @details This is typically a direct input. It can also be a key of type + * @ref PSA_KEY_TYPE_RAW_DATA. + */ +#define PSA_KEY_DERIVATION_INPUT_LABEL /* implementation-defined value */ + +/** + * @brief A low-entropy secret input for password hashing or key stretching. + * + * @details This is usually a key of type @ref PSA_KEY_TYPE_PASSWORD passed to + * @ref psa_key_derivation_input_key() or a direct input passed to + * @ref psa_key_derivation_input_bytes() that is a password or passphrase. It can also be + * high-entropy secret, for example, a key of type @ref PSA_KEY_TYPE_DERIVE, or the shared + * secret resulting from a key agreement. + * + * If the secret is a direct input, the derivation operation cannot be used to derive + * keys: the operation will not allow a call to @ref psa_key_derivation_output_key(). + */ +#define PSA_KEY_DERIVATION_INPUT_PASSWORD /* implementation-defined value */ + +/** + * @brief A salt for key derivation. + * + * @details This is typically a direct input. It can also be a key of type + * @ref PSA_KEY_TYPE_RAW_DATA or @ref PSA_KEY_TYPE_PEPPER. + */ +#define PSA_KEY_DERIVATION_INPUT_SALT /* implementation-defined value */ + +/** + * @brief A high-entropy secret input for key derivation. + * + * @details This is typically a key of type @ref PSA_KEY_TYPE_DERIVE passed to + * @ref psa_key_derivation_input_key(), or the shared secret resulting from a key + * agreement obtained via @ref psa_key_derivation_key_agreement(). + * + * The secret can also be a direct input passed to @ref psa_key_derivation_input_bytes(). + * In this case, the derivation operation cannot be used to derive keys: the operation + * will not allow a call to @ref psa_key_derivation_output_key(). + */ +#define PSA_KEY_DERIVATION_INPUT_SECRET /* implementation-defined value */ + +/** + * @brief A seed for key derivation. + * + * @details This is typically a direct input. It can also be a key of type + * @ref PSA_KEY_TYPE_RAW_DATA. + */ +#define PSA_KEY_DERIVATION_INPUT_SEED /* implementation-defined value */ + +/** + * @brief Use the maximum possible capacity for a key derivation operation. + * + * @details Use this value as the capacity argument when setting up a key derivation to specify + * that the operation will use the maximum possible capacity. The value of the maximum + * possible capacity depends on the key derivation algorithm. + */ +#define PSA_KEY_DERIVATION_UNLIMITED_CAPACITY \ +/* implementation-defined value */ + +/** + * @brief The null key identifier. + * + * @details The null key identifier is always invalid, except when used without in a call to + * @ref psa_destroy_key() which will return @ref PSA_SUCCESS. + */ +#define PSA_KEY_ID_NULL ((psa_key_id_t)0) + +/** + * @brief The maximum value for a key identifier chosen by the application. + */ +#define PSA_KEY_ID_USER_MAX ((psa_key_id_t)0x3fffffff) + +/** + * @brief The minimum value for a key identifier chosen by the application. + */ +#define PSA_KEY_ID_USER_MIN ((psa_key_id_t)0x00000001) + +/** + * @brief The maximum value for a key identifier chosen by the implementation. + */ +#define PSA_KEY_ID_VENDOR_MAX ((psa_key_id_t)0x7fffffff) + +/** + * @brief The minimum value for a key identifier chosen by the implementation. + */ +#define PSA_KEY_ID_VENDOR_MIN ((psa_key_id_t)0x40000000) + +/** + * @brief Construct a lifetime from a persistence level and a location. + * + * @param persistence The persistence level: a value of type @ref psa_key_persistence_t. + * @param location The location indicator: a value of type @ref psa_key_location_t. + * + * @return The constructed lifetime value. + */ +#define PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(persistence, location) \ + ((location) << 8 | (persistence)) + +/** + * @brief Extract the location indicator from a key lifetime. + * + * @param lifetime The lifetime value to query: a value of type @ref psa_key_lifetime_t. + */ +#define PSA_KEY_LIFETIME_GET_LOCATION(lifetime) \ + ((psa_key_location_t)((lifetime) >> 8)) + +/** + * @brief Extract the persistence level from a key lifetime. + * + * @param lifetime The lifetime value to query: a value of type @ref psa_key_lifetime_t. + */ +#define PSA_KEY_LIFETIME_GET_PERSISTENCE(lifetime) \ + ((psa_key_persistence_t)((lifetime) & 0x000000ff)) + +/** + * @brief Whether a key lifetime indicates that the key is volatile. + * + * A volatile key is automatically destroyed by the implementation when the application + * instance terminates. In particular, a volatile key is automatically destroyed on a + * power reset of the device. + * + * A key that is not volatile is persistent. Persistent keys are preserved until the + * application explicitly destroys them or until an implementation-specific device + * management event occurs, for example, a factory reset. + * + * @param lifetime The lifetime value to query: a value of type @ref psa_key_lifetime_t. + * + * @return 1 if the key is volatile, otherwise 0. + */ +#define PSA_KEY_LIFETIME_IS_VOLATILE(lifetime) \ + (PSA_KEY_LIFETIME_GET_PERSISTENCE(lifetime) == PSA_KEY_PERSISTENCE_VOLATILE) + +/** + * @brief The default lifetime for persistent keys. + * + * @details A persistent key remains in storage until it is explicitly destroyed or until the + * corresponding storage area is wiped. This specification does not define any mechanism + * to wipe a storage area. Implementations are permitted to provide their own mechanism, + * for example, to perform a factory reset, to prepare for device refurbishment, or to + * uninstall an application. + * + * This lifetime value is the default storage area for the calling application. + * Implementations can offer other storage areas designated by other lifetime values as + * implementation-specific extensions. + */ +#define PSA_KEY_LIFETIME_PERSISTENT ((psa_key_lifetime_t)0x00000001) + +/** + * @brief The default lifetime for volatile keys. + * + * @details A volatile key only exists as long as its identifier is not destroyed. The key material + * is guaranteed to be erased on a power reset. + * + * A key with this lifetime is typically stored in the RAM area of the PSA Crypto + * subsystem. However this is an implementation choice. If an implementation stores data + * about the key in a non-volatile memory, it must release all the resources associated + * with the key and erase the key material if the calling application terminates. + */ +#define PSA_KEY_LIFETIME_VOLATILE ((psa_key_lifetime_t)0x00000000) + +/** + * @brief The local storage area for persistent keys. + * + * @details This storage area is available on all systems that can store persistent keys without + * delegating the storage to a third-party cryptoprocessor. + * + * See @ref psa_key_location_t for more information. + */ +#define PSA_KEY_LOCATION_LOCAL_STORAGE ((psa_key_location_t)0x000000) + +/** + * @brief The default secure element storage area for persistent keys. + * + * @details This storage location is available on systems that have one or more secure elements + * that are able to store keys. + * + * Vendor-defined locations must be provided by the system for storing keys in additional + * secure elements. + * + * See @ref psa_key_location_t for more information. + */ +#define PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT ((psa_key_location_t)0x000001) + +/** + * @brief Mark vendor defined key locations + */ +#define PSA_KEY_LOCATION_VENDOR_FLAG ((psa_key_location_t)0x800000) + +/** + * @brief Minimum location value for secure elements + */ +#define PSA_KEY_LOCATION_SE_MIN (PSA_KEY_LOCATION_VENDOR_FLAG) + +/** + * @brief Maximum location value for secure elements + */ +#define PSA_KEY_LOCATION_SE_MAX ((psa_key_location_t)0x8000ff) + +/** + * @brief The default persistence level for persistent keys. + * + * @details See @ref psa_key_persistence_t for more information. + */ +#define PSA_KEY_PERSISTENCE_DEFAULT ((psa_key_persistence_t)0x01) + +/** + * @brief A persistence level indicating that a key is never destroyed. + * + * @details See @ref psa_key_persistence_t for more information. + */ +#define PSA_KEY_PERSISTENCE_READ_ONLY ((psa_key_persistence_t)0xff) + +/** + * @brief The persistence level of volatile keys. + * + * @details See @ref psa_key_persistence_t for more information. + */ +#define PSA_KEY_PERSISTENCE_VOLATILE ((psa_key_persistence_t)0x00) + +/** + * @brief Vendor-defined key type flag. + * + * @details Key types defined by this standard will never have the + * @ref PSA_KEY_TYPE_VENDOR_FLAG bit set. Vendors who define additional key types + * must use an encoding with the @ref PSA_KEY_TYPE_VENDOR_FLAG bit set and should + * respect the bitwise structure used by standard encodings whenever practical. + */ +#define PSA_KEY_TYPE_VENDOR_FLAG ((psa_key_type_t)0x8000) + +/** + * @brief Mask for key type categories + */ +#define PSA_KEY_TYPE_CATEGORY_MASK ((psa_key_type_t)0x7000) + +/** + * @brief Raw key data type + */ +#define PSA_KEY_TYPE_CATEGORY_RAW ((psa_key_type_t)0x1000) + +/** + * @brief Symmetric key type + */ +#define PSA_KEY_TYPE_CATEGORY_SYMMETRIC ((psa_key_type_t)0x2000) + +/** + * @brief Asymmetric public key type + */ +#define PSA_KEY_TYPE_CATEGORY_PUBLIC_KEY ((psa_key_type_t)0x4000) + +/** + * @brief Asymmetric key pair type + */ +#define PSA_KEY_TYPE_CATEGORY_KEY_PAIR ((psa_key_type_t)0x7000) + +/** + * @brief Asymmetric key pair flag + */ +#define PSA_KEY_TYPE_CATEGORY_FLAG_PAIR ((psa_key_type_t)0x3000) + +/** + * @brief Key for a cipher, AEAD or MAC algorithm based on the AES block cipher. + * + * @details The size of the key is related to the AES algorithm variant. For algorithms except the + * XTS block cipher mode, the following key sizes are used: + * - AES-128 uses a 16-byte key : @c key_bits = 128 + * - AES-192 uses a 24-byte key : @c key_bits = 192 + * - AES-256 uses a 32-byte key : @c key_bits = 256 + * + * For the XTS block cipher mode (@ref PSA_ALG_XTS), the following key sizes are used: + * - AES-128-XTS uses two 16-byte keys : @c key_bits = 256 + * - AES-192-XTS uses two 24-byte keys : @c key_bits = 384 + * - AES-256-XTS uses two 32-byte keys : @c key_bits = 512 + * + * The AES block cipher is defined in FIPS Publication 197: Advanced Encryption Standard + * (AES) [FIPS197](https://doi.org/10.6028/NIST.FIPS.197). + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_CBC_MAC + * - @ref PSA_ALG_CMAC + * - @ref PSA_ALG_CTR + * - @ref PSA_ALG_CFB + * - @ref PSA_ALG_OFB + * - @ref PSA_ALG_XTS + * - @ref PSA_ALG_CBC_NO_PADDING + * - @ref PSA_ALG_CBC_PKCS7 + * - @ref PSA_ALG_ECB_NO_PADDING + * - @ref PSA_ALG_CCM + * - @ref PSA_ALG_GCM + */ +#define PSA_KEY_TYPE_AES ((psa_key_type_t)0x2400) + +/** + * @brief Key for the ARC4 stream cipher. + * + * @warning The ARC4 cipher is weak and deprecated and is only recommended for use in legacy + * protocols. + * + * @details The ARC4 cipher supports key sizes between 40 and 2048 bits, that are multiples of 8. + * (5 to 256 bytes) + * + * Use algorithm @ref PSA_ALG_STREAM_CIPHER to use this key with the ARC4 cipher. + */ +#define PSA_KEY_TYPE_ARC4 ((psa_key_type_t)0x2002) + +/** + * @brief Key for a cipher, AEAD or MAC algorithm based on the ARIA block cipher. + * + * The size of the key is related to the ARIA algorithm variant. For algorithms except the + * XTS block cipher mode, the following key sizes are used: + * - ARIA-128 uses a 16-byte key : @c key_bits = 128 + * - ARIA-192 uses a 24-byte key : @c key_bits = 192 + * - ARIA-256 uses a 32-byte key : @c key_bits = 256 + * + * For the XTS block cipher mode (@ref PSA_ALG_XTS), the following key sizes are used: + * - ARIA-128-XTS uses two 16-byte keys : @c key_bits = 256 + * - ARIA-192-XTS uses two 24-byte keys : @c key_bits = 384 + * - ARIA-256-XTS uses two 32-byte keys : @c key_bits = 512 + * + * The ARIA block cipher is defined in A Description of the ARIA Encryption Algorithm + * [RFC5794](https://datatracker.ietf.org/doc/html/rfc5794). + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_CBC_MAC + * - @ref PSA_ALG_CMAC + * - @ref PSA_ALG_CTR + * - @ref PSA_ALG_CFB + * - @ref PSA_ALG_OFB + * - @ref PSA_ALG_XTS + * - @ref PSA_ALG_CBC_NO_PADDING + * - @ref PSA_ALG_CBC_PKCS7 + * - @ref PSA_ALG_ECB_NO_PADDING + * - @ref PSA_ALG_CCM + * - @ref PSA_ALG_GCM + */ +#define PSA_KEY_TYPE_ARIA ((psa_key_type_t)0x2406) + +/** + * @brief Key for a cipher, AEAD or MAC algorithm based on the Camellia block cipher. + * + * @details The size of the key is related to the Camellia algorithm variant. For algorithms except + * the XTS block cipher mode, the following key sizes are used: + * - Camellia-128 uses a 16-byte key : @c key_bits = 128 + * - Camellia-192 uses a 24-byte key : @c key_bits = 192 + * - Camellia-256 uses a 32-byte key : @c key_bits = 256 + * + * For the XTS block cipher mode (@ref PSA_ALG_XTS), the following key sizes are used: + * - Camellia-128-XTS uses two 16-byte keys : @c key_bits = 256 + * - Camellia-192-XTS uses two 24-byte keys : @c key_bits = 384 + * - Camellia-256-XTS uses two 32-byte keys : @c key_bits = 512 + * + * The Camellia block cipher is defined in Specification of Camellia — a 128-bit Block + * Cipher [NTT-CAM](https://info.isl.ntt.co.jp/crypt/eng/camellia/specifications) and + * also described in A Description of the Camellia Encryption + * Algorithm [RFC3713](https://tools.ietf.org/html/rfc3713). + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_CBC_MAC + * - @ref PSA_ALG_CMAC + * - @ref PSA_ALG_CTR + * - @ref PSA_ALG_CFB + * - @ref PSA_ALG_OFB + * - @ref PSA_ALG_XTS + * - @ref PSA_ALG_CBC_NO_PADDING + * - @ref PSA_ALG_CBC_PKCS7 + * - @ref PSA_ALG_ECB_NO_PADDING + * - @ref PSA_ALG_CCM + * - @ref PSA_ALG_GCM + */ +#define PSA_KEY_TYPE_CAMELLIA ((psa_key_type_t)0x2403) + +/** + * @brief Key for the ChaCha20 stream cipher or the ChaCha20-Poly1305 AEAD algorithm. + * + * @details The ChaCha20 key size is 256 bits (32 bytes). + * - Use algorithm @ref PSA_ALG_STREAM_CIPHER to use this key with the ChaCha20 cipher for + * unauthenticated encryption. See @ref PSA_ALG_STREAM_CIPHER for details of this + * algorithm. + * - Use algorithm @ref PSA_ALG_CHACHA20_POLY1305 to use this key with the ChaCha20 cipher + * and Poly1305 authenticator for AEAD. See @ref PSA_ALG_CHACHA20_POLY1305 for details + * of this algorithm. + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_STREAM_CIPHER + * - @ref PSA_ALG_CHACHA20_POLY1305 + */ +#define PSA_KEY_TYPE_CHACHA20 ((psa_key_type_t)0x2004) + +/** + * @brief A secret for key derivation. + * + * @details This key type is for high-entropy secrets only. For low-entropy secrets, + * @ref PSA_KEY_TYPE_PASSWORD should be used instead. + * + * These keys can be used in the @ref PSA_KEY_DERIVATION_INPUT_SECRET or + * @ref PSA_KEY_DERIVATION_INPUT_PASSWORD input step of key derivation algorithms. + * + * The key policy determines which key derivation algorithm the key can be used for. + * + * The bit size of a secret for key derivation must be a non-zero multiple of 8. The + * maximum size of a secret for key derivation is implementation defined. + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_HKDF (secret input) + * - @ref PSA_ALG_TLS12_PRF (secret input) + * - @ref PSA_ALG_TLS12_PSK_TO_MS (secret input) + */ +#define PSA_KEY_TYPE_DERIVE ((psa_key_type_t)0x1200) + +/** + * @brief Key for a cipher or MAC algorithm based on DES or 3DES (Triple-DES). + * + * @details The size of the key determines which DES algorithm is used: + * - Single DES uses an 8-byte key : @c key_bits = 64 + * - 2-key 3DES uses a 16-byte key : @c key_bits = 128 + * - 3-key 3DES uses a 24-byte key : @c key_bits = 192 + * + * @warning Single DES and 2-key 3DES are weak and strongly deprecated and are only recommended for + * decrypting legacy data. + * 3-key 3DES is weak and deprecated and is only recommended for use in legacy protocols. + * + * The DES and 3DES block ciphers are defined in NIST Special Publication 800-67: + * Recommendation for the Triple Data Encryption Algorithm (TDEA) Block Cipher + * [SP800-67](https://doi.org/10.6028/NIST.SP.800-67r2). + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_CBC_MAC + * - @ref PSA_ALG_CMAC + * - @ref PSA_ALG_CTR + * - @ref PSA_ALG_CFB + * - @ref PSA_ALG_OFB + * - @ref PSA_ALG_XTS + * - @ref PSA_ALG_CBC_NO_PADDING + * - @ref PSA_ALG_CBC_PKCS7 + * - @ref PSA_ALG_ECB_NO_PADDING + */ +#define PSA_KEY_TYPE_DES ((psa_key_type_t)0x2301) + +/** + * @brief Extract the group family from a Diffie-Hellman key type. + * + * @param type A Diffie-Hellman key type: a value of type @ref psa_key_type_t such that + * @ref PSA_KEY_TYPE_IS_DH(@p type) is true. + * + * @return The Diffie-Hellman group family id, if type is a supported Diffie-Hellman key. + * Unspecified if type is not a supported Diffie-Hellman key. + */ +#define PSA_KEY_TYPE_DH_GET_FAMILY(type) \ + ((psa_dh_family_t)((type) & 0x00ff)) + +/** + * @brief Finite-field Diffie-Hellman key pair: both the private key and public key. + * + * @details @b Compatible @b algorithms + * - @ref PSA_ALG_FFDH + * + * @param group A value of type @ref psa_dh_family_t that identifies the Diffie-Hellman group + * family to be used. + */ +#define PSA_KEY_TYPE_DH_KEY_PAIR(group) \ + ((psa_key_type_t)(0x7200 | (group))) + +/** + * @brief Finite-field Diffie-Hellman public key. + * + * @details @b Compatible @b algorithms + * None. Finite-field Diffie-Hellman public keys are exported to use in a key agreement + * algorithm, and the peer key is provided to the @ref PSA_ALG_FFDH key agreement + * algorithm as a buffer of key data. + * + * @param group A value of type @ref psa_dh_family_t that identifies the Diffie-Hellman group + * family to be used. + */ +#define PSA_KEY_TYPE_DH_PUBLIC_KEY(group) \ + ((psa_key_type_t)(0x4200 | (group))) + +/** + * @brief Extract the curve family from an elliptic curve key type. + * + * @param type An elliptic curve key type: a value of type @ref psa_key_type_t such that + * @ref PSA_KEY_TYPE_IS_ECC(@p type) is true. + * + * @return The elliptic curve family id, if type is a supported elliptic curve key. + * Unspecified if type is not a supported elliptic curve key. + */ +#define PSA_KEY_TYPE_ECC_GET_FAMILY(type) \ + ((psa_ecc_family_t)((type) & 0x00ff)) + +/** + * @brief Base value for ECC public keys + */ +#define PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE ((psa_key_type_t)0x4100) + +/** + * @brief Base value for ECC key pairs + */ +#define PSA_KEY_TYPE_ECC_KEY_PAIR_BASE ((psa_key_type_t)0x7100) + +/** + * @brief Mask for ECC curves + */ +#define PSA_KEY_TYPE_ECC_CURVE_MASK ((psa_key_type_t)0x00ff) + +/** + * @brief Elliptic curve key pair: both the private and public key. + * + * @details The size of an elliptic curve key is the bit size associated with the curve, that is, + * the bit size of q for a curve over a field Fq. See the documentation of each Elliptic + * curve family for details. + * + * @b Compatible @b algorithms + * - Elliptic curve key pairs can be used in Asymmetric signature and Key agreement + * algorithms. + * - The set of compatible algorithms depends on the Elliptic curve key family. See the + * Elliptic curve family for details. + * + * @param curve A value of type @ref psa_ecc_family_t that identifies the ECC curve to be used. + */ +#define PSA_KEY_TYPE_ECC_KEY_PAIR(curve) \ + (PSA_KEY_TYPE_ECC_KEY_PAIR_BASE | (curve)) + +/** + * @brief Extract group family of an elliptic curve key pair + * + * @param type A an ECC key pair type: a value of type @ref psa_key_type_t such that + * @ref PSA_KEY_TYPE_IS_ECC(@p type) is true. + * + * @return The elliptic curve family id, if type is a supported elliptic curve key. + * Unspecified if type is not a supported elliptic curve key. + */ +#define PSA_KEY_TYPE_ECC_GET_CURVE(type) \ + (type & ~PSA_KEY_TYPE_ECC_KEY_PAIR_BASE) + +/** + * @brief Elliptic curve public key. + * + * @details The size of an elliptic curve public key is the same as the corresponding private key. + * See @ref PSA_KEY_TYPE_ECC_KEY_PAIR() and the documentation of each Elliptic curve + * family for details. + * + * @b Compatible @b algorithms + * Elliptic curve public keys can be used for verification in asymmetric signature + * algorithms. + * The set of compatible algorithms depends on the elliptic curve key family. See each + * elliptic curve family for details. + * + * @param curve A value of type @ref psa_ecc_family_t that identifies the ECC curve to be used. + */ +#define PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve) \ + (PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE | (curve)) + +/** + * @brief Elliptic curve public key. + */ +#define PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve) \ + (PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE | (curve)) + +/** + * @brief Whether a key type is an elliptic curve key, either a key pair or a public key. + * + * @param type A key type: a value of type @ref psa_key_type_t. + */ +#define PSA_KEY_TYPE_IS_ECC(type) \ + ((PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type) & 0xff00) == 0x4100) + +/** + * @brief Whether a key type is an elliptic curve key pair. + * + * @param type A key type: a value of type @ref psa_key_type_t. + */ +#define PSA_KEY_TYPE_IS_ECC_KEY_PAIR(type) \ + (((type) & 0xff00) == 0x7100) + +/** + * @brief Whether a key type is an elliptic curve public key. + * + * @param type A key type: a value of type @ref psa_key_type_t. + */ +#define PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(type) \ + (((type) & 0xff00) == 0x4100) + +/** + * @brief The public key type corresponding to a key pair type. + * You may also pass a key pair type as type, it will be left unchanged. + * + * @param type A public key type or key pair type. + * + * @return The corresponding public key type. + * If type is not a public key or a key pair, the return value is undefined. + */ +#define PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type) \ + ((psa_key_type_t)((type) & ~0x3000)) + +/** + * @brief HMAC key. + * + * @details The key policy determines which underlying hash algorithm the key can be used for. + * + * The bit size of an HMAC key must be a non-zero multiple of 8. An HMAC key is typically + * the same size as the output of the underlying hash algorithm. An HMAC key that is + * longer than the block size of the underlying hash algorithm will be hashed before use. + * + * When an HMAC key is created that is longer than the block size, it is implementation + * defined whether the implementation stores the original HMAC key, or the hash of the + * HMAC key. If the hash of the key is stored, the key size reported by + * @ref psa_get_key_attributes() will be the size of the hashed key. + * + * @note @ref PSA_HASH_LENGTH(@p alg) provides the output size of hash algorithm @c alg, + * in bytes. + * @ref PSA_HASH_BLOCK_LENGTH(@p alg) provides the block size of hash algorithm + * @c alg, in bytes. + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_HMAC + */ +#define PSA_KEY_TYPE_HMAC ((psa_key_type_t)0x1100) + +/** + * @brief Whether a key type is asymmetric: either a key pair or a public key. + * + * @param type A key type: a value of type @ref psa_key_type_t. + */ +#define PSA_KEY_TYPE_IS_ASYMMETRIC(type) \ + (((type) & 0x4000) == 0x4000) + +/** + * @brief Whether a key type is a Diffie-Hellman key, either a key pair or a public key. + * + * @param type A key type: a value of type @ref psa_key_type_t. + */ +#define PSA_KEY_TYPE_IS_DH(type) \ + ((PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type) & 0xff00) == 0x4200) + +/** + * @brief Whether a key type is a Diffie-Hellman key pair. + * + * @param type A key type: a value of type @ref psa_key_type_t. + */ +#define PSA_KEY_TYPE_IS_DH_KEY_PAIR(type) \ + (((type) & 0xff00) == 0x7200) + +/** + * @brief Whether a key type is a Diffie-Hellman public key. + * + * @param type A key type: a value of type @ref psa_key_type_t. + */ +#define PSA_KEY_TYPE_IS_DH_PUBLIC_KEY(type) \ + (((type) & 0xff00) == 0x4200) + +/** + * @brief Whether a key type is a key pair containing a private part and a public part. + * + * @param type A key type: a value of type @ref psa_key_type_t. + */ +#define PSA_KEY_TYPE_IS_KEY_PAIR(type) \ + (((type) & 0x7000) == 0x7000) + +/** + * @brief Whether a key type is the public part of a key pair. + * + * @param type A key type: a value of type @ref psa_key_type_t. + */ + +#define PSA_KEY_TYPE_IS_PUBLIC_KEY(type) \ + (((type) & 0x7000) == 0x4000) + +/** + * @brief Whether a key type is an RSA key. This includes both key pairs and public keys. + * + * @param type A key type: a value of type @ref psa_key_type_t. + */ +#define PSA_KEY_TYPE_IS_RSA(type) \ + (PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type) == 0x4001) + +/** + * @brief Whether a key type is an unstructured array of bytes. + * This encompasses both symmetric keys and non-key data. + * + * @param type A key type: a value of type @ref psa_key_type_t. + */ +#define PSA_KEY_TYPE_IS_UNSTRUCTURED(type) \ + (((type) & 0x7000) == 0x1000 || ((type) & 0x7000) == 0x2000) + +/** + * @brief The key pair type corresponding to a public key type. + * + * @details If type is a key pair type, it will be left unchanged. + * + * @param type A public key type or key pair type. + * + * @return The corresponding key pair type. If type is not a public key or a key pair, the return + * value is undefined. + */ +#define PSA_KEY_TYPE_KEY_PAIR_OF_PUBLIC_KEY(type) \ + ((psa_key_type_t)((type) | 0x3000)) + +/** + * @brief An invalid key type value. + * + * @details Zero is not the encoding of any key type. + */ +#define PSA_KEY_TYPE_NONE ((psa_key_type_t)0x0000) + +/** + * @brief A low-entropy secret for password hashing or key derivation. + * + * @details This key type is suitable for passwords and passphrases which are typically intended to + * be memorizable by humans, and have a low entropy relative to their size. It can be used + * for randomly generated or derived keys with maximum or near-maximum entropy, but + * @ref PSA_KEY_TYPE_DERIVE is more suitable for such keys. It is not suitable for + * passwords with extremely low entropy, such as numerical PINs. + * + * These keys can be used in the @ref PSA_KEY_DERIVATION_INPUT_PASSWORD input step of key + * derivation algorithms. Algorithms that accept such an input were designed to accept + * low-entropy secret and are known as password hashing or key stretching algorithms. + * + * These keys cannot be used in the @ref PSA_KEY_DERIVATION_INPUT_SECRET input step of key + * derivation algorithms, as the algorithms expect such an input to have high entropy. + * + * The key policy determines which key derivation algorithm the key can be used for, among + * the permissible subset defined above. + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_PBKDF2_HMAC() (password input) + * - @ref PSA_ALG_PBKDF2_AES_CMAC_PRF_128 (password input) + */ +#define PSA_KEY_TYPE_PASSWORD ((psa_key_type_t)0x1203) + +/** + * @brief A secret value that can be used to verify a password hash. + * + * @details The key policy determines which key derivation algorithm the key can be used for, among + * the same permissible subset as for @ref PSA_KEY_TYPE_PASSWORD. + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_PBKDF2_HMAC() (key output and verification) + * - @ref PSA_ALG_PBKDF2_AES_CMAC_PRF_128 (key output and verification) + */ +#define PSA_KEY_TYPE_PASSWORD_HASH ((psa_key_type_t)0x1205) + +/** + * @brief A secret value that can be used when computing a password hash. + * + * @details The key policy determines which key derivation algorithm the key can be used for, among + * the subset of algorithms that can use pepper. + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_PBKDF2_HMAC() (salt input) + * - @ref PSA_ALG_PBKDF2_AES_CMAC_PRF_128 (salt input) + */ +#define PSA_KEY_TYPE_PEPPER ((psa_key_type_t)0x1206) + +/** + * @brief Raw data. + * + * @details A “key” of this type cannot be used for any cryptographic operation. Applications can + * use this type to store arbitrary data in the keystore. + * + * The bit size of a raw key must be a non-zero multiple of 8. The maximum size of a raw + * key is implementation defined. + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_HKDF (non-secret inputs) + * - @ref PSA_ALG_TLS12_PRF (non-secret inputs) + * - @ref PSA_ALG_TLS12_PSK_TO_MS (non-secret inputs) + */ +#define PSA_KEY_TYPE_RAW_DATA ((psa_key_type_t)0x1001) + +/** + * @brief RSA key pair: both the private and public key. + * + * @details The size of an RSA key is the bit size of the modulus. + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_RSA_OAEP + * - @ref PSA_ALG_RSA_PKCS1V15_CRYPT + * - @ref PSA_ALG_RSA_PKCS1V15_SIGN + * - @ref PSA_ALG_RSA_PKCS1V15_SIGN_RAW + * - @ref PSA_ALG_RSA_PSS + * - @ref PSA_ALG_RSA_PSS_ANY_SALT + */ +#define PSA_KEY_TYPE_RSA_KEY_PAIR ((psa_key_type_t)0x7001) + +/** + * @brief RSA public key. + * + * @details The size of an RSA key is the bit size of the modulus. + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_RSA_OAEP (encryption only) + * - @ref PSA_ALG_RSA_PKCS1V15_CRYPT (encryption only) + * - @ref PSA_ALG_RSA_PKCS1V15_SIGN (signature verification only) + * - @ref PSA_ALG_RSA_PKCS1V15_SIGN_RAW (signature verification only) + * - @ref PSA_ALG_RSA_PSS (signature verification only) + * - @ref PSA_ALG_RSA_PSS_ANY_SALT (signature verification only) + */ +#define PSA_KEY_TYPE_RSA_PUBLIC_KEY ((psa_key_type_t)0x4001) + +/** + * @brief Key for a cipher, AEAD or MAC algorithm based on the SM4 block cipher. + * + * @details For algorithms except the XTS block cipher mode, the SM4 key size is 128 bits + * (16 bytes). + * + * For the XTS block cipher mode (@ref PSA_ALG_XTS), the SM4 key size is 256 bits + * (two 16-byte keys). + * + * The SM4 block cipher is defined in GM/T 0002-2012: SM4 block cipher algorithm + * [CSTC0002](http://www.gmbz.org.cn/main/viewfile/20180108015408199368.html) + * (English version [CSTC0002/E](http://www.gmbz.org.cn/main/postDetail.html? + * id=20180404044052)). + * + * @b Compatible @b algorithms + * - @ref PSA_ALG_CBC_MAC + * - @ref PSA_ALG_CMAC + * - @ref PSA_ALG_CTR + * - @ref PSA_ALG_CFB + * - @ref PSA_ALG_OFB + * - @ref PSA_ALG_XTS + * - @ref PSA_ALG_CBC_NO_PADDING + * - @ref PSA_ALG_CBC_PKCS7 + * - @ref PSA_ALG_ECB_NO_PADDING + * - @ref PSA_ALG_CCM + * - @ref PSA_ALG_GCM + */ +#define PSA_KEY_TYPE_SM4 ((psa_key_type_t)0x2405) + +/** + * @brief Permission for the implementation to cache the key. + * + * @details This flag allows the implementation to make additional copies of the key material that + * are not in storage and not for the purpose of an ongoing operation. Applications can + * use it as a hint to keep the key around for repeated access. + * + * An application can request that cached key material is removed from memory by calling + * @ref psa_purge_key(). + * + * The presence of this usage flag when creating a key is a hint: + * - An implementation is not required to cache keys that have this usage flag. + * - An implementation must not report an error if it does not cache keys. + * + * If this usage flag is not present, the implementation must ensure key material is + * removed from memory as soon as it is not required for an operation or for maintenance + * of a volatile key. + * + * This flag must be preserved when reading back the attributes for all keys, regardless + * of key type or implementation behavior. + */ +#define PSA_KEY_USAGE_CACHE ((psa_key_usage_t)0x00000004) + +/** + * @brief Permission to copy the key. + * + * @details This flag allows the use of @ref psa_copy_key() to make a copy of the key with the same + * policy or a more restrictive policy. + * + * For lifetimes for which the key is located in a secure element which enforce the + * non-exportability of keys, copying a key outside the secure element also requires the + * usage flag @ref PSA_KEY_USAGE_EXPORT. Copying the key inside the secure element is + * permitted with just @ref PSA_KEY_USAGE_COPY if the secure element supports it. For keys + * with the lifetime @ref PSA_KEY_LIFETIME_VOLATILE or @ref PSA_KEY_LIFETIME_PERSISTENT, + * the usage flag @ref PSA_KEY_USAGE_COPY is sufficient to permit the copy. + */ +#define PSA_KEY_USAGE_COPY ((psa_key_usage_t)0x00000002) + +/** + * @brief Permission to decrypt a message with the key. + * + * @details This flag allows the key to be used for a symmetric decryption operation, for an AEAD + * decryption-and-verification operation, or for an asymmetric decryption operation, if + * otherwise permitted by the key’s type and policy. The flag must be present on keys used + * with the following APIs: + * - @ref psa_cipher_decrypt() + * - @ref psa_cipher_decrypt_setup() + * - @ref psa_aead_decrypt() + * - @ref psa_aead_decrypt_setup() + * - @ref psa_asymmetric_decrypt() + * + * For a key pair, this concerns the private key. + */ +#define PSA_KEY_USAGE_DECRYPT ((psa_key_usage_t)0x00000200) + +/** + * @brief Permission to derive other keys or produce a password hash from this key. + * + * @details This flag allows the key to be used for a key derivation operation or for a key + * agreement operation, if otherwise permitted by the key’s type and policy. + * + * This flag must be present on keys used with the following APIs: + * - @ref psa_key_derivation_key_agreement() + * - @ref psa_raw_key_agreement() + * + * If this flag is present on all keys used in calls to + * @ref psa_key_derivation_input_key() for a key derivation operation, then it permits + * calling @ref psa_key_derivation_output_bytes() or @ref psa_key_derivation_output_key() + * at the end of the operation. + */ +#define PSA_KEY_USAGE_DERIVE ((psa_key_usage_t)0x00004000) + +/** + * @brief Permission to encrypt a message with the key. + * + * @details This flag allows the key to be used for a symmetric encryption operation, for an AEAD + * encryption-and-authentication operation, or for an asymmetric encryption operation, if + * otherwise permitted by the key’s type and policy. The flag must be present on keys used + * with the following APIs: + * - @ref psa_cipher_encrypt() + * - @ref psa_cipher_encrypt_setup() + * - @ref psa_aead_encrypt() + * - @ref psa_aead_encrypt_setup() + * - @ref psa_asymmetric_encrypt() + * + * For a key pair, this concerns the public key. + */ +#define PSA_KEY_USAGE_ENCRYPT ((psa_key_usage_t)0x00000100) + +/** + * @brief Permission to export the key. + * + * @details This flag allows the use of @ref psa_export_key() to export a key from the + * cryptoprocessor. A public key or the public part of a key pair can always be exported + * regardless of the value of this permission flag. + * + * This flag can also be required to copy a key using @ref psa_copy_key() outside of a + * secure element. See also @ref PSA_KEY_USAGE_COPY. + * + * If a key does not have export permission, implementations must not allow the key to be + * exported in plain form from the cryptoprocessor, whether through @ref psa_export_key() + * or through a proprietary interface. The key might still be exportable in a wrapped + * form, i.e. in a form where it is encrypted by another key. + */ +#define PSA_KEY_USAGE_EXPORT ((psa_key_usage_t)0x00000001) + +/** + * @brief Permission to sign a message hash with the key. + * + * @details This flag allows the key to be used to sign a message hash as part of an asymmetric + * signature operation, if otherwise permitted by the key’s type and policy. The flag must + * be present on keys used when calling @ref psa_sign_hash(). + * + * This flag automatically sets @ref PSA_KEY_USAGE_SIGN_MESSAGE : if an application sets + * the flag @ref PSA_KEY_USAGE_SIGN_HASH when creating a key, then the key always has the + * permissions conveyed by @ref PSA_KEY_USAGE_SIGN_MESSAGE, and the flag + * @ref PSA_KEY_USAGE_SIGN_MESSAGE will also be present when the application queries the + * usage flags of the key. + * + * For a key pair, this concerns the private key. + */ +#define PSA_KEY_USAGE_SIGN_HASH ((psa_key_usage_t)0x00001000) + +/** + * @brief Permission to sign a message with the key. + * + * @details This flag allows the key to be used for a MAC calculation operation or for an + * asymmetric message signature operation, if otherwise permitted by the key’s type and + * policy. The flag must be present on keys used with the following APIs: + * - @ref psa_mac_compute() + * - @ref psa_mac_sign_setup() + * - @ref psa_sign_message() + * + * For a key pair, this concerns the private key. + */ +#define PSA_KEY_USAGE_SIGN_MESSAGE ((psa_key_usage_t)0x00000400) + +/** + * @brief Permission to verify the result of a key derivation, including password hashing. + * + * @details This flag allows the key to be used in a key derivation operation, if otherwise + * permitted by the key’s type and policy. + * + * This flag must be present on keys used with @ref psa_key_derivation_verify_key(). + * + * If this flag is present on all keys used in calls to + * @ref psa_key_derivation_input_key() for a key derivation operation, then it permits + * calling @ref psa_key_derivation_verify_bytes() or @ref psa_key_derivation_verify_key() + * at the end of the operation. + */ +#define PSA_KEY_USAGE_VERIFY_DERIVATION ((psa_key_usage_t)0x00008000) + +/** + * @brief Permission to verify a message hash with the key. + * + * @details This flag allows the key to be used to verify a message hash as part of an asymmetric + * signature verification operation, if otherwise permitted by the key’s type and policy. + * The flag must be present on keys used when calling @ref psa_verify_hash(). + * + * This flag automatically sets @ref PSA_KEY_USAGE_VERIFY_MESSAGE : if an application sets + * the flag @ref PSA_KEY_USAGE_VERIFY_HASH when creating a key, then the key always has + * the permissions conveyed by @ref PSA_KEY_USAGE_VERIFY_MESSAGE, and the flag + * @ref PSA_KEY_USAGE_VERIFY_MESSAGE will also be present when the application queries the + * usage flags of the key. + * + * For a key pair, this concerns the public key. + */ +#define PSA_KEY_USAGE_VERIFY_HASH ((psa_key_usage_t)0x00002000) + +/** + * @brief Permission to verify a message signature with the key. + * + * @details This flag allows the key to be used for a MAC verification operation or for an + * asymmetric message signature verification operation, if otherwise permitted by the + * key’s type and policy. The flag must be present on keys used with the following APIs: + * - @ref psa_mac_verify() + * - @ref psa_mac_verify_setup() + * - @ref psa_verify_message() + * + * For a key pair, this concerns the public key. + */ +#define PSA_KEY_USAGE_VERIFY_MESSAGE ((psa_key_usage_t)0x00000800) + +/** + * @brief Sufficient output buffer size for @ref psa_raw_key_agreement(), for any of the + * supported key types and key agreement algorithms. + * + * @details If the size of the output buffer is at least this large, it is guaranteed that + * @ref psa_raw_key_agreement() will not fail due to an insufficient buffer size. + * + * See also @ref PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(). + */ +#define PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE \ +/* implementation-defined value */ + +/** + * @brief Sufficient output buffer size for @ref psa_raw_key_agreement(). + * + * @details If the size of the output buffer is at least this large, it is guaranteed that + * @ref psa_raw_key_agreement() will not fail due to an insufficient buffer size. + * The actual size of the output might be smaller in any given call. + * + * See also @ref PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE. + * + * @param key_type A supported key type. + * @param key_bits The size of the key in bits. + * + * @return A sufficient output buffer size for the specified key type and size. + * 0 if key type is not supported. + * If the parameters are not valid, the return value is unspecified. + */ +#define PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(key_type, key_bits) \ +/* implementation-defined value */ + +/** + * @brief A sufficient signature buffer size for @ref psa_sign_message() and + * @ref psa_sign_hash(), for any of the supported key types and asymmetric signature + * algorithms. + * + * @details If the size of the signature buffer is at least this large, it is guaranteed that + * @ref psa_sign_message() and @ref psa_sign_hash() will not fail due to an insufficient + * buffer size. + * + * See also @ref PSA_SIGN_OUTPUT_SIZE(). + */ +#define PSA_SIGNATURE_MAX_SIZE /* implementation-defined value */ + +/** + * @brief This macro returns the maximum supported length of the PSK for the TLS-1.2 PSK-to-MS + * key derivation. + * + * @details This implementation-defined value specifies the maximum length for the PSK input used + * with a @ref PSA_ALG_TLS12_PSK_TO_MS() key agreement algorithm. + * + * Quoting Pre-Shared Key Ciphersuites for Transport Layer Security (TLS) + * [RFC4279](https://tools.ietf.org/html/rfc4279.html) §5.3: + * TLS implementations supporting these cipher suites MUST support arbitrary PSK + * identities up to 128 octets in length, and arbitrary PSKs up to 64 octets in length. + * Supporting longer identities and keys is RECOMMENDED. + * + * Therefore, it is recommended that implementations define + * @ref PSA_TLS12_PSK_TO_MS_PSK_MAX_SIZE with a value greater than or equal to 64. + */ +#define PSA_TLS12_PSK_TO_MS_PSK_MAX_SIZE /* implementation-defined value */ + +/** + * @brief The action was completed successfully. + */ +#define PSA_SUCCESS ((psa_status_t)0) + +/** + * @brief An error occurred that does not correspond to any defined failure cause. + */ +#define PSA_ERROR_GENERIC_ERROR ((psa_status_t)-132) + +/** + * @brief The requested operation or a parameter is not supported by this implementation. + */ +#define PSA_ERROR_NOT_SUPPORTED ((psa_status_t)-134) + +/** + * @brief The requested action is denied by a policy. + */ +#define PSA_ERROR_NOT_PERMITTED ((psa_status_t)-133) + +/** + * @brief An output buffer is too small. + */ +#define PSA_ERROR_BUFFER_TOO_SMALL ((psa_status_t)-138) + +/** + * @brief Asking for an item that already exists. + */ +#define PSA_ERROR_ALREADY_EXISTS ((psa_status_t)-139) + +/** + * @brief Asking for an item that doesn’t exist. + */ +#define PSA_ERROR_DOES_NOT_EXIST ((psa_status_t)-140) + +/** + * @brief The requested action cannot be performed in the current state. + */ +#define PSA_ERROR_BAD_STATE ((psa_status_t)-137) + +/** + * @brief The parameters passed to the function are invalid. + */ +#define PSA_ERROR_INVALID_ARGUMENT ((psa_status_t)-135) + +/** + * @brief There is not enough runtime memory. + */ +#define PSA_ERROR_INSUFFICIENT_MEMORY ((psa_status_t)-141) + +/** + * @brief There is not enough persistent storage. + */ +#define PSA_ERROR_INSUFFICIENT_STORAGE ((psa_status_t)-142) + +/** + * @brief There was a communication failure inside the implementation. + */ +#define PSA_ERROR_COMMUNICATION_FAILURE ((psa_status_t)-145) + +/** + * @brief There was a storage failure that might have led to data loss. + */ +#define PSA_ERROR_STORAGE_FAILURE ((psa_status_t)-146) + +/** + * @brief Stored data has been corrupted. + */ +#define PSA_ERROR_DATA_CORRUPT ((psa_status_t)-152) + +/** + * @brief Data read from storage is not valid for the implementation. + */ +#define PSA_ERROR_DATA_INVALID ((psa_status_t)-153) + +/** + * @brief A hardware failure was detected. + */ +#define PSA_ERROR_HARDWARE_FAILURE ((psa_status_t)-147) + +/** + * @brief A tampering attempt was detected. + */ +#define PSA_ERROR_CORRUPTION_DETECTED ((psa_status_t)-151) + +/** + * @brief There is not enough entropy to generate random data needed + * for the requested action. + */ +#define PSA_ERROR_INSUFFICIENT_ENTROPY ((psa_status_t)-148) + +/** + * @brief The signature, MAC or hash is incorrect. + */ +#define PSA_ERROR_INVALID_SIGNATURE ((psa_status_t)-149) + +/** + * @brief The decrypted padding is incorrect. + */ +#define PSA_ERROR_INVALID_PADDING ((psa_status_t)-150) + +/** + * @brief Return this error when there’s insufficient data when + * attempting to read from a resource. + */ +#define PSA_ERROR_INSUFFICIENT_DATA ((psa_status_t)-143) + +/** + * @brief The key identifier is not valid. + */ +#define PSA_ERROR_INVALID_HANDLE ((psa_status_t)-136) + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTO_PSA_CRYPTO_VALUES_H */ +/** @} */ diff --git a/sys/psa_crypto/Kconfig b/sys/psa_crypto/Kconfig new file mode 100644 index 0000000000..4bdda0b10e --- /dev/null +++ b/sys/psa_crypto/Kconfig @@ -0,0 +1,24 @@ +# Copyright (c) 2021 HAW Hamburg +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. +# + +menuconfig MODULE_PSA_CRYPTO + bool "PSA Crypto" + depends on TEST_KCONFIG + select MODULE_RANDOM + +if MODULE_PSA_CRYPTO + +rsource "Kconfig.asymmetric" +rsource "Kconfig.ciphers" +rsource "Kconfig.hashes" +rsource "Kconfig.mac" +rsource "Kconfig.keys" + +rsource "psa_se_mgmt/Kconfig" +rsource "psa_key_slot_mgmt/Kconfig" + +endif # MODULE_PSA_CRYPTO diff --git a/sys/psa_crypto/Kconfig.asymmetric b/sys/psa_crypto/Kconfig.asymmetric new file mode 100644 index 0000000000..6361041e23 --- /dev/null +++ b/sys/psa_crypto/Kconfig.asymmetric @@ -0,0 +1,61 @@ +# Copyright (c) 2021 HAW Hamburg +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. +# + +menuconfig MODULE_PSA_ASYMMETRIC + bool "PSA Asymmetric Crypto" + select PSA_KEY_CONFIG + select MODULE_PSA_KEY_SLOT_MGMT + +if MODULE_PSA_ASYMMETRIC + +menuconfig MODULE_PSA_ASYMMETRIC_ECC_P192R1 + bool "ECC NIST-P192R1" + select PSA_KEY_SIZE_192 + +if MODULE_PSA_ASYMMETRIC_ECC_P192R1 + +choice PSA_ASYMMETRIC_ECC_P192R1_BACKEND + bool "ECC NIST-P192R1 Implementation" + +config MODULE_PSA_ASYMMETRIC_ECC_P192R1_BACKEND_PERIPH + bool "Hardware accelerated with peripheral" + depends on HAS_PERIPH_ECC_P192R1 + select MODULE_PERIPH_ECC_P192R1 + +config MODULE_PSA_ASYMMETRIC_ECC_P192R1_BACKEND_MICROECC + bool "Micro-ECC Package" + select PACKAGE_MICRO-ECC + select MODULE_PSA_UECC_P192 + +endchoice + +endif # MODULE_PSA_ASYMMETRIC_ECC_P192R1 + +menuconfig MODULE_PSA_ASYMMETRIC_ECC_P256R1 + bool "ECC NIST-P256R1" + select PSA_KEY_SIZE_256 + +if MODULE_PSA_ASYMMETRIC_ECC_P256R1 + +choice PSA_ASYMMETRIC_ECC_P256R1_BACKEND + bool "ECC NIST-P256R1 Implementation" + +config MODULE_PSA_ASYMMETRIC_ECC_P256R1_BACKEND_PERIPH + bool "Hardware Accelerated" + depends on HAS_PERIPH_ECC_P256R1 + select MODULE_PERIPH_ECC_P256R1 + +config MODULE_PSA_ASYMMETRIC_ECC_P256R1_BACKEND_MICROECC + bool "Micro-ECC Package" + select PACKAGE_MICRO-ECC + select MODULE_PSA_UECC_P256 + +endchoice + +endif # MODULE_PSA_ASYMMETRIC_ECC_P256R1 + +endif # MODULE_PSA_ASYMMETRIC diff --git a/sys/psa_crypto/Kconfig.ciphers b/sys/psa_crypto/Kconfig.ciphers new file mode 100644 index 0000000000..e7d5303a9b --- /dev/null +++ b/sys/psa_crypto/Kconfig.ciphers @@ -0,0 +1,92 @@ +# Copyright (c) 2021 HAW Hamburg +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. +# + +menuconfig MODULE_PSA_CIPHER + bool "PSA Ciphers" + select PSA_KEY_CONFIG + select MODULE_PSA_KEY_SLOT_MGMT + +if MODULE_PSA_CIPHER + +menuconfig MODULE_PSA_CIPHER_AES_128_ECB + bool "AES-128 ECB" + select PSA_KEY_SIZE_128 + +if MODULE_PSA_CIPHER_AES_128_ECB + +choice PSA_CIPHER_AES_128_ECB_BACKEND + bool "AES-128 Implementation" + +config MODULE_PSA_CIPHER_AES_128_ECB_BACKEND_RIOT + bool "RIOT cipher" + select MODULE_CRYPTO + select MODULE_PSA_RIOT_CIPHER_AES_ECB + +endchoice + +endif # MODULE_PSA_CIPHER_AES_128_ECB + +menuconfig MODULE_PSA_CIPHER_AES_128_CBC + bool "AES-128 CBC" + select PSA_KEY_SIZE_128 + +if MODULE_PSA_CIPHER_AES_128_CBC + +choice PSA_CIPHER_AES_128_CBC_BACKEND + bool "AES-128 CBC Implementation" + +config MODULE_PSA_CIPHER_AES_128_CBC_BACKEND_PERIPH + bool "Hardware Accelerated" + depends on HAS_PERIPH_CIPHER_AES_128_CBC + select MODULE_PERIPH_CIPHER_AES_128_CBC + +config MODULE_PSA_CIPHER_AES_128_CBC_BACKEND_RIOT + bool "RIOT cipher" + select MODULE_CRYPTO + select MODULE_PSA_RIOT_CIPHER_AES_128_CBC + +endchoice + +endif # MODULE_PSA_CIPHER_AES_128_CBC + +menuconfig MODULE_PSA_CIPHER_AES_192_CBC + bool "AES-192 CBC" + select PSA_KEY_SIZE_192 + +if MODULE_PSA_CIPHER_AES_192_CBC + +choice PSA_CIPHER_AES_192_CBC_BACKEND + bool "AES-192 Implementation" + +config MODULE_PSA_CIPHER_AES_192_CBC_BACKEND_RIOT + bool "RIOT cipher" + select MODULE_CRYPTO + select MODULE_PSA_RIOT_CIPHER_AES_CBC + +endchoice + +endif # MODULE_PSA_CIPHER_AES_192_CBC + +menuconfig MODULE_PSA_CIPHER_AES_256_CBC + bool "AES-256 CBC" + select PSA_KEY_SIZE_256 + +if MODULE_PSA_CIPHER_AES_256_CBC + +choice CIPHER_AES_256_CBC_BACKEND + bool "AES-256 Implementation" + +config MODULE_PSA_CIPHER_AES_256_CBC_BACKEND_RIOT + bool "RIOT Cipher Module" + select MODULE_CRYPTO + select MODULE_PSA_RIOT_CIPHER_AES_CBC + +endchoice + +endif # MODULE_PSA_CIPHER_AES_256_CBC + +endif # MODULE_PSA_CIPHER diff --git a/sys/psa_crypto/Kconfig.hashes b/sys/psa_crypto/Kconfig.hashes new file mode 100644 index 0000000000..6abf34ad9f --- /dev/null +++ b/sys/psa_crypto/Kconfig.hashes @@ -0,0 +1,111 @@ +# Copyright (c) 2021 HAW Hamburg +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. +# + +menuconfig MODULE_PSA_HASH + bool "PSA Hashes" + select PSA_KEY_CONFIG + +if MODULE_PSA_HASH + +menuconfig MODULE_PSA_HASH_MD5 + bool "MD5" + +if MODULE_PSA_HASH_MD5 + +choice PSA_HASH_MD5_BACKEND + bool "MD5 implementation" + +config MODULE_PSA_HASH_MD5_BACKEND_RIOT + bool "RIOT hash" + select MODULE_PSA_RIOT_HASHES_MD5 + +endchoice + +endif # MODULE_PSA_HASH_MD5 + +menuconfig MODULE_PSA_HASH_SHA_1 + bool "SHA-1" + +if MODULE_PSA_HASH_SHA_1 + +choice PSA_HASH_SHA_1_BACKEND + bool "SHA-1 implementation" + +config MODULE_PSA_HASH_SHA_1_BACKEND_PERIPH + bool "Hardware accelerated" + depends on HAS_PERIPH_HASH_SHA_1 + select MODULE_PERIPH_HASH_SHA_1 + +config MODULE_PSA_HASH_SHA_1_BACKEND_RIOT + bool "RIOT hash" + select MODULE_PSA_RIOT_HASHES_SHA_1 + +endchoice + +endif # MODULE_PSA_HASH_SHA_1 + +menuconfig MODULE_PSA_HASH_SHA_224 + bool "SHA-224" + +if MODULE_PSA_HASH_SHA_224 + +choice PSA_HASH_SHA_224_BACKEND + bool "SHA-224 implementation" + +config MODULE_PSA_HASH_SHA_224_BACKEND_PERIPH + bool "Hardware accelerated" + depends on HAS_PERIPH_HASH_SHA_224 + select MODULE_PERIPH_HASH_SHA_224 + +config MODULE_PSA_HASH_SHA_224_BACKEND_RIOT + bool "RIOT Hash Module" + select MODULE_PSA_RIOT_HASHES_SHA_224 + +endchoice + +endif # MODULE_PSA_HASH_SHA_224 + +menuconfig MODULE_PSA_HASH_SHA_256 + bool "SHA-256" + +if MODULE_PSA_HASH_SHA_256 + +choice PSA_HASH_SHA_256_BACKEND + bool "SHA-256 implementation" + +config MODULE_PSA_HASH_SHA_256_BACKEND_PERIPH + bool "Hardware accelerated" + depends on HAS_PERIPH_HASH_SHA_256 + select MODULE_PERIPH_HASH_SHA_256 + +config MODULE_PSA_HASH_SHA_256_BACKEND_RIOT + bool "RIOT hash" + select MODULE_PSA_RIOT_HASHES_SHA_256 + +endchoice + +endif # MODULE_PSA_HASH_SHA_256 + +menuconfig MODULE_PSA_HASH_SHA_512 + bool "SHA-512" + depends on HAS_PERIPH_HASH_SHA_512 # no software implementation so far... + +if MODULE_PSA_HASH_SHA_512 + +choice PSA_HASH_SHA_512_BACKEND + bool "SHA-512 implementation" + +config MODULE_PSA_HASH_SHA_512_BACKEND_PERIPH + bool "Hardware accelerated" + depends on HAS_PERIPH_HASH_SHA_512 + select MODULE_PERIPH_HASH_SHA_512 + +endchoice + +endif # MODULE_PSA_HASH_SHA_512 + +endif # MODULE_PSA_HASH diff --git a/sys/psa_crypto/Kconfig.keys b/sys/psa_crypto/Kconfig.keys new file mode 100644 index 0000000000..21cff30403 --- /dev/null +++ b/sys/psa_crypto/Kconfig.keys @@ -0,0 +1,55 @@ +# Copyright (c) 2021 HAW Hamburg +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. +# + +menu "PSA Key Management Configuration" + +config PSA_KEY_SIZE_128 + bool "Application uses key of size 128 Bits" + help + Indicates that the maximum PSA key size should be at least 128 bits. + +config PSA_KEY_SIZE_192 + bool + help + Indicates that the maximum PSA key size should be at least 192 bits. + +config PSA_KEY_SIZE_256 + bool + help + Indicates that the maximum PSA key size should be at least 256 bits. + +config PSA_KEY_SIZE_512 + bool + help + Indicates that the maximum PSA key size should be at least 512 bits. + +config PSA_MAX_KEY_SIZE + int + default 64 if PSA_KEY_SIZE_512 + default 32 if PSA_KEY_SIZE_256 + default 24 if PSA_KEY_SIZE_192 + default 16 if PSA_KEY_SIZE_128 + default 0 + help + Indicates the maximum PSA key size in bytes. + +config PSA_PROTECTED_KEY_COUNT + int "Specifies number of allocated protected key slots" + default 5 if MODULE_PSA_SECURE_ELEMENT + default 0 + +config PSA_ASYMMETRIC_KEYPAIR_COUNT + int "Specifies number of allocated key pair slots" + default 5 if MODULE_PSA_ASYMMETRIC + default 0 + +config PSA_SINGLE_KEY_COUNT + int "Specifies number of allocated single key slots" + default 5 if PSA_MAX_KEY_SIZE != 0 + default 0 + +endmenu # PSA Key Management Configuration diff --git a/sys/psa_crypto/Kconfig.mac b/sys/psa_crypto/Kconfig.mac new file mode 100644 index 0000000000..fcca459f10 --- /dev/null +++ b/sys/psa_crypto/Kconfig.mac @@ -0,0 +1,37 @@ +# Copyright (c) 2022 HAW Hamburg +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. +# + +menuconfig MODULE_PSA_MAC + bool "PSA Message Authenticated Ciphers" + select PSA_KEY_CONFIG + select MODULE_PSA_KEY_SLOT_MGMT + +if MODULE_PSA_MAC + +menuconfig MODULE_PSA_MAC_HMAC_SHA_256 + bool "HMAC SHA-256" + select PSA_KEY_SIZE_256 + +if MODULE_PSA_MAC_HMAC_SHA_256 + +choice PSA_MAC_HMAC_SHA_256_BACKEND + bool "HMAC SHA256 Implementation" + +config MODULE_PSA_MAC_HMAC_SHA_256_BACKEND_PERIPH + bool "Hardware Accelerated" + depends on HAS_PERIPH_HMAC_SHA_256 + select MODULE_PERIPH_HMAC_SHA_256 + +config MODULE_PSA_MAC_HMAC_SHA_256_BACKEND_RIOT + bool "RIOT HMAC SHA-256" + select MODULE_PSA_RIOT_HASHES_HMAC_SHA256 + +endchoice # PSA_MAC_HMAC_SHA_256_BACKEND + +endif # MODULE_PSA_MAC_HMAC_SHA_256 + +endif # MODULE_PSA_MAC diff --git a/sys/psa_crypto/Makefile b/sys/psa_crypto/Makefile new file mode 100644 index 0000000000..6d61a2db19 --- /dev/null +++ b/sys/psa_crypto/Makefile @@ -0,0 +1,15 @@ +# PSA Crypto casts like hell, so this needs to shut the f up +CFLAGS += -Wno-cast-align + +# include the PSA headers +INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include + +ifneq (,$(filter psa_key_slot_mgmt,$(USEMODULE))) + DIRS += psa_key_slot_mgmt +endif + +ifneq (,$(filter psa_se_mgmt,$(USEMODULE))) + DIRS += psa_se_mgmt +endif + +include $(RIOTBASE)/Makefile.base diff --git a/sys/psa_crypto/Makefile.dep b/sys/psa_crypto/Makefile.dep new file mode 100644 index 0000000000..14e3f34ad4 --- /dev/null +++ b/sys/psa_crypto/Makefile.dep @@ -0,0 +1,241 @@ +ifneq (,$(filter psa_crypto,$(USEMODULE))) + USEMODULE += random + USEMODULE += prng_musl_lcg +endif + +# Asymmetric +ifneq (,$(filter psa_asymmetric,$(USEMODULE))) + USEMODULE += psa_key_slot_mgmt +endif + +## ECC_P192R1 backend +ifneq (,$(filter psa_asymmetric_ecc_p192r1,$(USEMODULE))) + ifeq (,$(filter psa_asymmetric_ecc_p192r1_custom_backend,$(USEMODULE))) + FEATURES_OPTIONAL += periph_ecc_p192r1 + include $(RIOTMAKE)/features_check.inc.mk + # HACK: Due to kconfig migration, may cause problems + ifneq (,$(filter periph_ecc_p192r1,$(FEATURES_USED))) + USEMODULE += psa_asymmetric_ecc_p192r1_backend_periph + else + USEMODULE += psa_asymmetric_ecc_p192r1_backend_microecc + endif + endif +endif + +ifneq (,$(filter psa_asymmetric_ecc_p192r1_backend_microecc, $(USEMODULE))) + USEPKG += micro-ecc + USEMODULE += psa_uecc + USEMODULE += psa_uecc_p192 +endif + +ifneq (,$(filter psa_asymmetric_ecc_p192r1_backend_periph,$(USEMODULE))) + FEATURES_REQUIRED += periph_ecc_p192r1 +endif + +## ECC_P256R1 backend +ifneq (,$(filter psa_asymmetric_ecc_p256r1,$(USEMODULE))) + ifeq (,$(filter psa_asymmetric_ecc_p256r1_custom_backend,$(USEMODULE))) + FEATURES_OPTIONAL += periph_ecc_p256r1 + include $(RIOTMAKE)/features_check.inc.mk + # HACK: Due to kconfig migration, may cause problems + ifneq (,$(filter periph_ecc_p256r1,$(FEATURES_USED))) + USEMODULE += psa_asymmetric_ecc_p256r1_backend_periph + else + USEMODULE += psa_asymmetric_ecc_p256r1_backend_microecc + endif + endif +endif + +ifneq (,$(filter psa_asymmetric_ecc_p256r1_backend_microecc,$(USEMODULE))) + USEPKG += micro-ecc + USEMODULE += psa_uecc + USEMODULE += psa_uecc_p256 +endif + +ifneq (,$(filter psa_asymmetric_ecc_p256r1_backend_periph,$(USEMODULE))) + FEATURES_REQUIRED += periph_ecc_p256r1 +endif + +# Cipher +ifneq (,$(filter psa_cipher,$(USEMODULE))) + USEMODULE += psa_key_slot_mgmt +endif + +## AES-128-ECB backend +ifneq (,$(filter psa_cipher_aes_128_ecb,$(USEMODULE))) + USEMODULE += psa_cipher_aes_128_ecb_backend_riot +endif + +ifneq (,$(filter psa_cipher_aes_128_ecb_backend_riot,$(USEMODULE))) + USEMODULE += crypto + USEMODULE += cipher_modes + USEMODULE += psa_riot_cipher + USEMODULE += psa_riot_cipher_aes_ecb +endif + +## AES-128-CBC +ifneq (,$(filter psa_cipher_aes_128_cbc,$(USEMODULE))) + ifeq (,$(filter psa_cipher_aes_128_cbc_custom_backend,$(USEMODULE))) + FEATURES_OPTIONAL += periph_cipher_aes_128_cbc + include $(RIOTMAKE)/features_check.inc.mk + # HACK: Due to kconfig migration, may cause problems + ifneq (,$(filter periph_cipher_aes_128_cbc,$(FEATURES_USED))) + USEMODULE += psa_cipher_aes_128_cbc_backend_periph + else + USEMODULE += psa_cipher_aes_128_cbc_backend_riot + endif + endif +endif + +ifneq (,$(filter psa_cipher_aes_128_cbc_backend_periph,$(USEMODULE))) + FEATURES_REQUIRED += periph_cipher_aes_128_cbc +endif + +ifneq (,$(filter psa_cipher_aes_128_cbc_backend_riot,$(USEMODULE))) + USEMODULE += crypto + USEMODULE += cipher_modes + USEMODULE += psa_riot_cipher + USEMODULE += psa_riot_cipher_aes_128_cbc +endif + +## AES-192-CBC +ifneq (,$(filter psa_cipher_aes_192_cbc,$(USEMODULE))) + USEMODULE += psa_cipher_aes_192_cbc_backend_riot +endif + +ifneq (,$(filter psa_cipher_aes_192_cbc_backend_riot,$(USEMODULE))) + USEMODULE += crypto + USEMODULE += cipher_modes + USEMODULE += psa_riot_cipher + USEMODULE += psa_riot_cipher_aes_192_cbc +endif + +# Hash + +## MD5 +ifneq (,$(filter psa_hash_md5,$(USEMODULE))) + USEMODULE += psa_hash_md5_backend_riot +endif + +ifneq (,$(filter psa_hash_md5_backend_riot,$(USEMODULE))) + USEMODULE += hashes + USEMODULE += psa_riot_hashes + USEMODULE += psa_riot_hashes_md5 +endif + +## SHA-1 +ifneq (,$(filter psa_hash_sha_1,$(USEMODULE))) + ifeq (,$(filter psa_hash_sha_1_custom_backend,$(USEMODULE))) + FEATURES_OPTIONAL += periph_hash_sha_1 + include $(RIOTMAKE)/features_check.inc.mk + # HACK: Due to kconfig migration, may cause problems + ifneq (,$(filter periph_hash_sha_1,$(FEATURES_USED))) + USEMODULE += psa_hash_sha_1_backend_periph + else + USEMODULE += psa_hash_sha_1_backend_riot + endif + endif +endif + +ifneq (,$(filter psa_hash_sha_1_backend_periph,$(USEMODULE))) + FEATURES_REQUIRED += periph_hash_sha_1 +endif + +ifneq (,$(filter psa_hash_sha_1_backend_riot,$(USEMODULE))) + USEMODULE += hashes + USEMODULE += psa_riot_hashes + USEMODULE += psa_riot_hashes_sha_1 +endif + +## SHA-224 +ifneq (,$(filter psa_hash_sha_224,$(USEMODULE))) + ifeq (,$(filter psa_hash_sha_224_custom_backend,$(USEMODULE))) + FEATURES_OPTIONAL += periph_hash_sha_224 + include $(RIOTMAKE)/features_check.inc.mk + # HACK: Due to kconfig migration, may cause problems + ifneq (,$(filter periph_hash_sha_224,$(FEATURES_USED))) + USEMODULE += psa_hash_sha_224_backend_periph + else + USEMODULE += psa_hash_sha_224_backend_riot + endif + endif +endif + +ifneq (,$(filter psa_hash_sha_224_backend_periph,$(USEMODULE))) + FEATURES_REQUIRED += periph_hash_sha_224 +endif + +ifneq (,$(filter psa_hash_sha_224_backend_riot,$(USEMODULE))) + USEMODULE += hashes + USEMODULE += psa_riot_hashes + USEMODULE += psa_riot_hashes_sha_224 +endif + +## SHA-256 +ifneq (,$(filter psa_hash_sha_256,$(USEMODULE))) + ifeq (,$(filter psa_hash_sha_256_custom_backend,$(USEMODULE))) + FEATURES_OPTIONAL += periph_hash_sha_256 + include $(RIOTMAKE)/features_check.inc.mk + # HACK: Due to kconfig migration, may cause problems + ifneq (,$(filter periph_hash_sha_256,$(FEATURES_USED))) + USEMODULE += psa_hash_sha_256_backend_periph + else + USEMODULE += psa_hash_sha_256_backend_riot + endif + endif +endif + +ifneq (,$(filter psa_hash_sha_256_backend_periph,$(USEMODULE))) + FEATURES_REQUIRED += periph_hash_sha_256 +endif + +ifneq (,$(filter psa_hash_sha_256_backend_riot,$(USEMODULE))) + USEMODULE += hashes + USEMODULE += psa_riot_hashes + USEMODULE += psa_riot_hashes_sha_256 +endif + +## SHA-512 +ifneq (,$(filter psa_hash_sha_512,$(USEMODULE))) + USEMODULE += psa_hash_sha_512_backend_periph +endif + +ifneq (,$(filter psa_hash_sha_512_backend_periph,$(USEMODULE))) + FEATURES_REQUIRED += periph_hash_sha_512 +endif + +# MAC +## HMAC SHA-256 +ifneq (,$(filter psa_mac_hmac_sha_256,$(USEMODULE))) + ifeq (,$(filter psa_mac_hmac_sha_256_custom_backend,$(USEMODULE))) + FEATURES_OPTIONAL += periph_hmac_sha_256 + include $(RIOTMAKE)/features_check.inc.mk + # HACK: Due to kconfig migration, may cause problems + ifneq (,$(filter periph_hmac_sha_256,$(FEATURES_USED))) + USEMODULE += psa_mac_hmac_sha_256_backend_periph + else + USEMODULE += psa_mac_hmac_sha_256_backend_riot + endif + endif +endif + +ifneq (,$(filter psa_mac_hmac_sha_256_backend_periph,$(USEMODULE))) + FEATURES_REQUIRED += periph_hmac_sha_256 +endif + +ifneq (,$(filter psa_mac_hmac_sha_256_backend_riot,$(USEMODULE))) + USEMODULE += hashes + USEMODULE += psa_riot_hashes + USEMODULE += psa_riot_hashes_hmac_sha256 +endif + +# Secure Elements +ifneq (,$(filter psa_secure_element,$(USEMODULE))) + USEMODULE += psa_se_mgmt + USEMODULE += psa_key_slot_mgmt +endif + +ifneq (,$(filter psa_secure_element_ateccx08a, $(USEMODULE))) + USEPKG += cryptoauthlib + USEMODULE += psa_secure_element_config +endif diff --git a/sys/psa_crypto/Makefile.include b/sys/psa_crypto/Makefile.include new file mode 100644 index 0000000000..2d23d8665c --- /dev/null +++ b/sys/psa_crypto/Makefile.include @@ -0,0 +1,154 @@ +# include the PSA headers +INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include + +# Workaround for mbedtls namespacing issue +# sys/include will include the conflicting header files in psa but requires a psa/*.h structure. +INCLUDES += -I$(RIOTBASE)/sys/include/psa_crypto + +backends = $(words $(filter $1_backend_%,$(USEMODULE))) + +# Pseudomodules +## Asymmetric +PSEUDOMODULES += psa_asymmetric +PSEUDOMODULES += psa_asymmetric_ecc_p192r1 +PSEUDOMODULES += psa_asymmetric_ecc_p192r1_backend_microecc +PSEUDOMODULES += psa_asymmetric_ecc_p192r1_backend_periph +PSEUDOMODULES += psa_asymmetric_ecc_p192r1_custom_backend + +# check that one and only one backend has been selected +ifneq (,$(filter psa_asymmetric_ecc_p192r1,$(USEMODULE))) + ifneq (1,$(call backends, psa_asymmetric_ecc_p192r1)) + $(error "One (and only one) backend should be selected for psa_asymmetric_ecc_p192r1") + endif +endif + +PSEUDOMODULES += psa_asymmetric_ecc_p256r1 +PSEUDOMODULES += psa_asymmetric_ecc_p256r1_backend_microecc +PSEUDOMODULES += psa_asymmetric_ecc_p256r1_backend_periph +PSEUDOMODULES += psa_asymmetric_ecc_p256r1_custom_backend + +# check that one and only one backend has been selected +ifneq (,$(filter psa_asymmetric_ecc_p256r1,$(USEMODULE))) + ifneq (1,$(call backends,psa_asymmetric_ecc_p256r1)) + $(error "One (and only one) backend should be selected for psa_asymmetric_ecc_p256r1") + endif +endif + +## Cipher +PSEUDOMODULES += psa_cipher +PSEUDOMODULES += psa_cipher_aes_128_ecb +PSEUDOMODULES += psa_cipher_aes_128_ecb_backend_riot + +PSEUDOMODULES += psa_cipher_aes_128_cbc +PSEUDOMODULES += psa_cipher_aes_128_cbc_backend_periph +PSEUDOMODULES += psa_cipher_aes_128_cbc_backend_riot +PSEUDOMODULES += psa_cipher_aes_128_cbc_custom_backend + +# check that one and only one backend has been selected +ifneq (,$(filter psa_cipher_aes_128_cbc,$(USEMODULE))) + ifneq (1,$(call backends,psa_cipher_aes_128_cbc)) + $(error "One (and only one) backend should be selected for psa_cipher_aes_128_cbc") + endif +endif + +PSEUDOMODULES += psa_cipher_aes_192_cbc +PSEUDOMODULES += psa_cipher_aes_192_cbc_backend_riot +PSEUDOMODULES += psa_cipher_aes_192_cbc_custom_backend + +# check that one and only one backend has been selected +ifneq (,$(filter psa_cipher_aes_192_cbc,$(USEMODULE))) + ifneq (1,$(call backends,psa_cipher_aes_192_cbc)) + $(error "One (and only one) backend should be selected for psa_cipher_aes_192_cbc") + endif +endif + +PSEUDOMODULES += psa_cipher_aes_256_cbc +PSEUDOMODULES += psa_cipher_aes_256_cbc_backend_riot +PSEUDOMODULES += psa_cipher_aes_256_cbc_custom_backend + +# check that one and only one backend has been selected +ifneq (,$(filter psa_cipher_aes_256_cbc,$(USEMODULE))) + ifneq (1,$(call backends,psa_cipher_aes_256_cbc)) + $(error "One (and only one) backend should be selected for psa_cipher_aes_256_cbc") + endif +endif + +## Hash +PSEUDOMODULES += psa_hash +PSEUDOMODULES += psa_hash_md5 +PSEUDOMODULES += psa_hash_md5_backend_riot +PSEUDOMODULES += psa_hash_md5_custom_backend + +# check that one and only one backend has been selected +ifneq (,$(filter psa_hash_md5,$(USEMODULE))) + ifneq (1,$(call backends,psa_hash_md5)) + $(error "One (and only one) backend should be selected for psa_hash_md5") + endif +endif + +PSEUDOMODULES += psa_hash_sha_1 +PSEUDOMODULES += psa_hash_sha_1_backend_periph +PSEUDOMODULES += psa_hash_sha_1_backend_riot +PSEUDOMODULES += psa_hash_sha_1_custom_backend + +# check that one and only one backend has been selected +ifneq (,$(filter psa_hash_sha_1,$(USEMODULE))) + ifneq (1,$(call backends,psa_hash_sha_1)) + $(error "One (and only one) backend should be selected for psa_hash_sha_1") + endif +endif + +PSEUDOMODULES += psa_hash_sha_224 +PSEUDOMODULES += psa_hash_sha_224_backend_periph +PSEUDOMODULES += psa_hash_sha_224_backend_riot +PSEUDOMODULES += psa_hash_sha_224_custom_backend + +# check that one and only one backend has been selected +ifneq (,$(filter psa_hash_sha_224,$(USEMODULE))) + ifneq (1,$(call backends,psa_hash_sha_224)) + $(error "One (and only one) backend should be selected for psa_hash_sha_224") + endif +endif + +PSEUDOMODULES += psa_hash_sha_256 +PSEUDOMODULES += psa_hash_sha_256_backend_periph +PSEUDOMODULES += psa_hash_sha_256_backend_riot +PSEUDOMODULES += psa_hash_sha_256_custom_backend + +# check that one and only one backend has been selected +ifneq (,$(filter psa_hash_sha_256,$(USEMODULE))) + ifneq (1,$(call backends,psa_hash_sha_256)) + $(error "One (and only one) backend should be selected for psa_hash_sha_256") + endif +endif + +PSEUDOMODULES += psa_hash_sha_512 +PSEUDOMODULES += psa_hash_sha_512_backend_periph +PSEUDOMODULES += psa_hash_sha_512_custom_backend + +# check that one and only one backend has been selected +ifneq (,$(filter psa_hash_sha_512,$(USEMODULE))) + ifneq (1,$(call backends,psa_hash_sha_512)) + $(error "One (and only one) backend should be selected for psa_hash_sha_512") + endif +endif + +## MAC +PSEUDOMODULES += psa_mac +PSEUDOMODULES += psa_mac_hmac_sha_256 +PSEUDOMODULES += psa_mac_hmac_sha_256_backend_periph +PSEUDOMODULES += psa_mac_hmac_sha_256_backend_riot +PSEUDOMODULES += psa_mac_hmac_sha_256_custom_backend + +# check that one and only one backend has been selected +ifneq (,$(filter psa_mac_hmac_sha_256,$(USEMODULE))) + ifneq (1,$(call backends,psa_mac_hmac_sha_256)) + $(error "One (and only one) backend should be selected for psa_mac_hmac_sha_256") + endif +endif + +## Secure Elements +PSEUDOMODULES += psa_secure_element +PSEUDOMODULES += psa_secure_element_asymmetric +PSEUDOMODULES += psa_secure_element_config +PSEUDOMODULES += psa_secure_element_multiple diff --git a/sys/psa_crypto/doc.txt b/sys/psa_crypto/doc.txt new file mode 100644 index 0000000000..64ce3b4ab4 --- /dev/null +++ b/sys/psa_crypto/doc.txt @@ -0,0 +1,996 @@ +/** + * @defgroup sys_psa_crypto PSA Cryptographic API + * @ingroup sys + * @brief Implements the PSA Crypto API specification. + * @see https://armmbed.github.io/mbed-crypto/html/ + * + * @warning This implementation is not complete and not yet thoroughly tested. + * Please do not use this module in production, as it may introduce security issues. + * + * @note This implementation is not complete and will be successively expanded. + * + * About {#About} + * ===== + * This module implements the PSA Cryptography API Version 1.1 as specified + * [here](https://armmbed.github.io/mbed-crypto/html/). + * It provides an OS level access to cryptographic operations and supports software and hardware + * backends as well as the use of secure elements. + * The API automatically builds a hardware backend for an operation, if there's one available, + * otherwise it falls back to software. Specific backends can be configured, if needed. + * For configuration options see [Configuration](#configuration). + * + * PSA Crypto has an integrated key management module, which stores keys internally + * without exposing them to applications. To learn how to use keys with PSA, + * read [Using Keys](#using-keys). + * + * A basic usage and configuration example can be found in `examples/psa_crypto`. + * For more usage instructions, please read the documentation. + * + * If you want to add your own crypto backend, see [Porting Guide](#porting-guide). + * + * Basic Usage + * === + * To use PSA Crypto, add `psa/crypto.h` to your includes. This will make all + * operations and macros available. + * + * Call `psa_crypto_init()` before calling any other operation. + * + * ## Structure Initialization + * Whenever you declare a PSA Crypto structure (e.g. operation contexts or key attributes), + * it needs to be initialized with zeroes. A structure that is not initialized will be interpreted + * by PSA as *active* and can not be used for a new operation. + * The example function and macro shown below result in the same thing: A new, inactive structure. + * + * @code {.c} + * // Choose one of these options + * psa_hash_operation_t hash_op = psa_hash_operation_init(); + * psa_hash_operation_t hash_op = PSA_HASH_OPERATION_INIT; + * @endcode + * + * An already active operation can be set to zero by reinitializing it. It then becomes *inactive* + * again and can be used for a new operation. + * + * When errors occur during execution, PSA resets the operation contexts and makes them + * *inactive*, to prevent unauthorized access to an operation's state. + * Users can also call `psa__abort()` anytime in between function calls to do the same. + * + * Using Keys {#using-keys} + * === + * PSA can only operate on keys, that are registered with and stored within the internal + * key storage module. This means you need to either generate keys with PSA or + * import an existing key. + * For this purpose there are a number of + * [key management functions](https://armmbed.github.io/mbed-crypto/html/api/keys/management.html) + * (external link). + * + * ## Key Attributes + * When creating a key for PSA, the implementation needs to know what kind of key it is + * dealing with, what it can be used for, where it's supposed to be stored, etc. + * That information needs to be specified in a set of + * [Key Attributes](https://armmbed.github.io/mbed-crypto/html/api/keys/attributes.html) + * (external link). + * + * The example below defines attributes for an AES-128 key, which can be used for CBC encryption + * and decryption and will be stored in local volatile memory. + * @code + * // Initializes empty attributes structure + * psa_key_attributes_t attributes = psa_key_attributes_init(); + * + * // Set all necessary attributes + * psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE); + * psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + * psa_set_key_bits(&attributes, 128); + * psa_set_key_algorithm(&attributes, PSA_ALG_CBC_NO_PADDING); + * psa_set_key_usage_flags(&attributes, (PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT)); + * @endcode + * + * After setting the attributes, an exiting key can be imported: + * @code + * uint8_t aes_key[] = { ... }; + * psa_key_id_t key_id = 0; // Will be set by PSA Crypto + * psa_status_t status = psa_import_key(&attributes, aes_key, sizeof(aes_key), &key_id); + * @endcode + * The PSA Crypto implementation will assign an identifier to the key and return it + * via the `key_id` parameter. This identifier can then be used for operations with this + * specific key. + * @code + * uint8_t PLAINTEXT[] = { ... }; + * // Buffer sizes can be calculated with macros + * size_t output_buf_size = PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES, PSA_ALG_CBC_NO_PADDING,sizeof(PLAINTEXT)); + * uint8_t output_buffer[output_buf_size]; + * + * status = psa_cipher_encrypt(key_id, PSA_ALG_CBC_NO_PADDING, PLAINTEXT, sizeof(PLAINTEXT),output_buffer, sizeof(output_buffer), &output_length)); + * @endcode + * + * All the supported key types, algorithms and usage flags can be found in the documentation. + * + * ### Key Lifetime {#key-lifetime} + * #### Volatile vs. Persistent + * The PSA API specifies two ways of storing keys: volatile and persistent. Volatile + * keys will be stored only in RAM, which means they will be destroyed after application + * termination or a device reset. + * Persistent keys will also be written into flash memory for later access. To destroy + * them they must be explicitly deleted with the `psa_destroy_key()` function. + * + * @note So far this implementation only supports volatile storage. Persistent storage + * will be added in the future. + * + * #### Lifetime Encoding + * When creating a key, the user needs to specify a lifetime value, which actually consists + * of two values: persistence and location. The location defines the actual memory location + * of the key (e.g. whether the key will be stored in RAM, in a hardware protected memory slot + * or on an external device like a secure element). + * + * The persistence value defines whether the key will be stored in RAM (volatile) + * in flash (persistent). + * Some default values that exist are: + * - @ref PSA_KEY_LIFETIME_VOLATILE (stored in local, volatile memory) + * - @ref PSA_KEY_LIFETIME_PERSISTENT (stored in local, persistent memory) + * + * Other lifetime values can be constructed with the macro + * `PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(persistence, location)`. + * All supported `PSA_KEY_PERSISTENCE_*` and `PSA_KEY_LOCATION_*` values can be combined. + * + * In addition to the location values defined by the specification, this implementation also + * supports values for [Secure Elements](#secure-elements). + * + * Configuration {#configuration} + * === + * Currently there are two ways to configure PSA Crypto: Kconfig and Makefiles. An example for both + * can be found in `RIOT/examples/psa_crypto`. + * + * ## Kconfig + * We recommend using Kconfig and choosing your features in `menuconfig`. + * You can access the GUI by calling + * + * @code + * TEST_KCONFIG=1 BOARD= make menuconfig + * @endcode + * + * from your application directory. + * There you can find the available PSA features and options under `System->PSA Crypto`. + * If you only select the operations you want to use (e.g. `PSA Ciphers->AES-128 CBC`), Kconfig + * will automatically select the best backend for you depending on the board (e.g. a hardware + * accelerator if it is available). Optionally you can force a custom backend. + * + * Further you can specify the exact number of keys you need to store (section `PSA Key Management + * Configuration` in `menuconfig`), or choose your [Secure Element](#secure-elements) + * configurations. + * + * Alternatively you can create an `app.config.test` file in your application folder + * and choose your symbols there (see `examples/psa_crypto`). + * + * In the `app.config.test` file, modules can be chosen with the following syntax: + * `CONFIG_MODULE_=y`, as shown below. + * @code + * CONFIG_MODULE_PSA_CRYPTO=y + * CONFIG_MODULE_PSA_CIPHER=y + * CONFIG_MODULE_PSA_CIPHER_AES_128_CBC=y + * @endcode + * + * ## Makefiles + * If you don't want to use Kconfig, you can use the traditional way in RIOT of selecting + * modules in your application Makefile. + * + * Here you need to set the base module and individual modules for each operation you need. + * The example below also chooses a default backend depending on your board. + * @code + * // Base module: this is required! + * USEMODULE += psa_crypto + * + * USEMODULE += psa_cipher + * USEMODULE += psa_cipher_aes_128_cbc + * @endcode + * + * If desired, you can choose a specific backend at compile time. For this you need to specify + * that you want to set a custom backend and then explicitly choose the one you want (see below). + * @code + * USEMODULE += psa_cipher_aes_128_cbc_custom_backend + * USEMODULE += psa_cipher_aes_128_cbc_backend_riot + * @endcode + * + * The currently available modules, are listed [below](#available-modules). + * + * ## Key Slot Types {#configuration-keys} + * The key management of PSA keeps track of keys by storing them in virtual key slot + * representations, along with their attributes. Since keys can come in various sizes, + * it would be inefficient to allocate the same amount of memory for all keys. + * To reduce the amount of memory used for key storage, PSA internally differentiates between + * three types of key slots (see below). Depending on the operations your application uses, PSA will + * automatically detect the key sizes needed and will allocate the required memory. + * The number of key slots allocated of each type is set to five per default, but can be changed by + * the user depending on their requirements. + * + * | Single Key Slot | Asymmetric Key Slot | Protected Key Slot | + * |----------------|---------------------|--------------------| + * | Single keys or unstructured data,
e.g. AES keys or asymmetric
public keys in local memory | Asymmetric key pairs
(private and public parts)
in local memory | Any keys stored on a secure
element or on-chip in
hardware protected memory | + * + * If you want to change the default number of allocated key slots you can do so by + * updating the number in `menuconfig`, or adding them to the `app.config.test` file like so: + * @code + * CONFIG_PSA_SINGLE_KEY_COUNT=3 + * CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1 + * CONFIG_PSA_PROTECTED_KEY_COUNT=2 + * @endcode + * + * When using Makefiles, you can pass CFLAGS as shown below. + * @code + * CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=3 + * CFLAGS += -DCONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1 + * CFLAGS += -DCONFIG_PSA_PROTECTED_KEY_COUNT=2 + * @endcode + * + * ## Available Modules {#available-modules} + * Below are the currently available modules. + * No matter which operation you need, you always have to choose the base module. + * If you want to specify a backend other than the default, you need to select + * `psa__custom_backend` in addition to the actual backend module. + * + * The names listed are are the version used in makefiles with the + * `USEMODULE += ` syntax. + * In Kconfig you don't need to know the exact names, you can simply choose the features in + * `menuconfig`. + * When using `app.config.test` files in your application directory, you need to write the + * names in uppercase and add the prefix `CONFIG_MODULE_` to all of them. + * + * ### Asymmetric Crypto + * - Base: psa_asymmetric + * + * #### NIST ECC P192 + * - psa_asymmetric_ecc_p192r1 + * - psa_asymmetric_ecc_p192r1_backend_periph + * - psa_asymmetric_ecc_p192r1_custom_backend + * - psa_asymmetric_ecc_p192r1_backend_microecc + * + * #### NIST ECC P192 + * - psa_asymmetric_ecc_p256r1 + * - psa_asymmetric_ecc_p256r1_backend_periph + * - psa_asymmetric_ecc_p256r1_custom_backend + * - psa_asymmetric_ecc_p256r1_backend_microecc + * + * ### Ciphers + * - Base: psa_cipher + * + * #### AES ECB + * - psa_cipher_aes_128_ecb + * - psa_cipher_aes_128_ecb_backend_riot + * + * #### AES CBC + * - psa_cipher_aes_128_cbc + * - psa_cipher_aes_128_cbc_backend_periph + * - psa_cipher_aes_128_cbc_custom_backend + * - psa_cipher_aes_128_cbc_backend_riot + * - psa_cipher_aes_192_cbc + * - psa_cipher_aes_192_cbc_custom_backend + * - psa_cipher_aes_192_cbc_backend_riot + * - psa_cipher_aes_256_cbc + * - psa_cipher_aes_256_cbc_custom_backend + * - psa_cipher_aes_256_cbc_backend_riot + * + * ### Hashes + * - Base: psa_hash + * + * #### MD5 + * - psa_hash_md5 + * - psa_hash_md5_custom_backend + * - psa_hash_md5_backend_riot + * + * #### SHA 1 + * - psa_hash_sha_1 + * - psa_hash_sha_1_backend_periph + * - psa_hash_sha_1_custom_backend + * - psa_hash_sha_1_backend_riot + * + * #### SHA 224 + * - psa_hash_sha_224 + * - psa_hash_sha_224_backend_periph + * - psa_hash_sha_224_custom_backend + * - psa_hash_sha_224_backend_riot + * + * #### SHA 256 + * - psa_hash_sha_256 + * - psa_hash_sha_256_backend_periph + * - psa_hash_sha_256_custom_backend + * - psa_hash_sha_256_backend_riot + * + * #### SHA 512 + * - psa_hash_sha_512 + * - psa_hash_sha_512_backend_periph + * - psa_hash_sha_512_custom_backend + * + * ### MAC + * - Base: psa_mac + * + * #### HMAC SHA 256 + * - psa_mac_hmac_sha_256 + * - psa_mac_hmac_sha_256_backend_periph + * - psa_mac_hmac_sha_256_custom_backend + * - psa_mac_hmac_sha_256_backend_riot + * + * ### Secure Elements + * Base: + * + * - psa_secure_element + * - psa_secure_element_multiple + * + * #### SE Types + * - psa_secure_element_ateccx08a + * - psa_secure_element_ateccx08a_ecc_p256 + * + * Random Number Generation {#rng} + * === + * Currently uses the [RIOT Random Module](#sys_random) as a backend. + * See the documentation for configuration options. + * + * Secure Elements {#secure-elements} + * === + * + * An example showing the use of SEs can be found in `examples/psa_crypto`. + * + * To use secure elements, you first need to assign a static location value to each device, + * so PSA can find it. If you only use one device, you can use + * `PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT`. For additional devices this value must be within + * the range of `PSA_KEY_LOCATION_SE_MIN` and `PSA_KEY_LOCATION_SE_MAX`. + * When booting the system, the `auto_init` module in RIOT will automatically register the device + * with the location with PSA Crypto. + * + * You can now import or create keys on the secure element by constructing a key lifetime containing + * a device's location value. + * + * @code {.c} + * psa_key_lifetime_t lifetime = + * PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION (PSA_KEY_LIFETIME_VOLATILE, + PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT); + * @endcode + * + * Some secure elements come with their own key management and device configurations. In this case + * the configuration parameters must be passed to PSA Crypto during the registration. For this, you + * need to define a `psa_se_config_t` structure containing the configuration. + * PSA Crypto will use this structure to keep track of what types of keys are allowed on the device + * and how much storage is available. + * Where this structure should be placed, how it looks and what parameters are required depends + * on the type of your device. + * + * A good place to define that structure and the location values is a drivers `_params.h` + * file, but this may vary depending on how your device is integrated in RIOT. + * + * For detailed, device specific information, please check the device driver documentation or + * the example. + * + * ## Available Devices and Drivers + * - ATECCX08A: [Microchip Cryptoauthlib as a PSA backend](#psa-cryptoauthlib) + * + * ## Main SE Configuration + * To use SEs, the appropriate modules must be chosen in Kconfig: + * @code + * CONFIG_PSA_SECURE_ELEMENT=y + * CONFIG_PSA_SECURE_ELEMENT_ATECCX08A=y // device example + * CONFIG_PSA_SECURE_ELEMENT_ATECCX08A_ECC=y + * @endcode + * + * or added to the the Makefile: + * @code + * USEMODULE += psa_secure_element + * USEMODULE += psa_secure_element_ateccx08a // device example + * USEMODULE += psa_secure_element_ateccx08a_ecc_p256 + * @endcode + * + * This implementation supports the use of one or more secure elements (SE) as backends. In this + * case the number of used secure elements must be specified (must be at least 2 and at most 255). + * When using more than one SE, add + * @code + * CONFIG_PSA_SECURE_ELEMENT_MULTIPLE=y + * CONFIG_PSA_MAX_SE_COUNT=2 // or any other number between 2 and 255 + * @endcode + * + * or, respectively, + * + * @code + * USEMODULE += psa_secure_element_multiple + * CFLAGS += -DCONFIG_PSA_MAX_SE_COUNT=2 // or any other number between 2 and 255 + * @endcode + * + * Porting Guide {#porting-guide} + * === + * This porting guide focuses on how to add your software library or hardware driver + * as a backend to PSA Crypto without actually touching the PSA implementation. + * We will provide some [general information](#porting-general) and then some case + * examples for different kinds of backends: + * - [Software Libraries](#porting-software) + * - [Hardware Drivers](#porting-hardware) + * - [Secure Elements](#porting-secure-elements) + * + * Some examples to look at are: + * - [RIOT hash module](#sys_hashes) + * - [RIOT cipher module](#sys_crypto) + * - [Micro-ECC](#pkg_micro_ecc) + * - [CryptoCell 310 driver](#pkg_driver_cryptocell_310). + * + * An example integrating a secure element can be found in the + * [Cryptoauthlib Package](#pkg_cryptoauthlib). + * + * ## General Information {#porting-general} + * ### Error Values + * You should always check the status of your function calls and translate your library's or + * driver's errors to PSA error values (please be as thorough as possible). + * The PSA Crypto specification describes exactly what kind of error values should be returned + * by which function. Please read the API documentation and comply with the instructions. + * We recommend writing a`_to_psa_error()` function right in the beginning (see for + * example `CRYS_to_psa_error()` in + * `pkg/driver_cryptocell_310/psa_cryptocell_310/error_conversion.c`). + * + * ### The Build System + * As mentioned before, there are two ways of selecting build time configurations in RIOT: Kconfig + * and Makefiles. + * Kconfig dependency resolution is currently an experimental feature and will at some point + * replace Makefiles. Until then, our implementation needs to support both, which means we need + * to define features and symbols in multiple places. + * Luckily, the modules have the exact same names in both systems, which makes the transfer easier. + * The examples below show both ways. + * + * ### Modules {#module-names} + * In RIOT, module names are generated from path names, so if you create a directory for + * your sourcefiles, the module name will be the same as the directory name. It is possible + * to change that by declaring a new module name in the Makefile by adding the line + * your_module_name`. + * + * If you leave it like this, all sourcefiles in the path corresponding to the module name will be + * built (e.g. if you choose to module `hashes`, all files in `sys/hashes` will be included). + * For better configurability it is possible to add submodules (see + * `sys/hashes/psa_riot_hashes` for example). + * In that case the base module name will be the directory name and each file inside the directory + * becomes its own submodule that must be explicitly chosen. The module name will then be the + * directory name with the file name as a postfix. + * For example: + * @code + * USEMODULE += hashes + * USEMODULE += psa_riot_hashes + * USEMODULE += psa_riot_hashes_sha_256 + * + * will build the file at `sys/hashes/psa_riot_hashes/sha_256.c`, but none of the other files in + * the directory). + * + * To enable submodules for your implementation add the following to the directory makefile: + * @code + * BASE_MODULE := psa_ + * SUBMODULES := 1 + * @endcode + * + * We also need to create so-called pseudomodules for each available submodule. + * Those must follow the scheme `psa__`. + * Where they are declared depends on where your module is located. Pseudomodules in `RIOT/sys` must + * be added in `pseudomodules.inc.mk`. + * When integrating packages or drivers, the pseudomodules can be added in the `Makefile.include` + * file of the individual module's directory (see `pkg/micro-ecc/Makefile.include`). + * + * When adding backends to PSA Crypto, please name your modules in ways that fit within the + * current naming scheme: `psa__`. Also, when adding software libraries and + * hardware drivers, use the submodule approach. That makes PSA Crypto more configurable. + * + * The drawback of the submodule approach is, that if one of our sourcefiles depends on + * another sourcefile in the same folder, we need to select it explicitly. For example, in + * `pkg/driver_cryptocell_310/psa_cryptocell_310` you can see that there are some common source + * files that all the others use (e.g. for hashes there is a `hashes_common.c` file). + * + * If that is the case for your driver, you need to make sure the modules are selected in + * the Kconfig file as well as the `Makefile.dep` file (see `psa_cryptocell_310/Makefile.dep` or + * `psa_cryptocell_310/Kconfig`). + * + * ### Adding Glue Code {#glue-code} + * We define a number of wrapper APIs, which are called by PSA to invoke crypto backends. + * Software libraries and hardware drivers use the same methods, secure elements are handled + * in a different way (see [Case Example – Secure Elements](#porting-secure-elements) for details). + * + * The names, parameters and return values for wrapper methods are defined in header files in + * `sys/psa_crypto/include/psa_.h`. + * The functions declared in those files are the ones that are currently supported by this + * PSA implementation. They will be extended in the future. + * + * You need to implement those functions with glue code calling your library or driver code + * and converting types and error values between PSA and your backend. + * Below is an example of how this might look (it's very reduced, your library may need + * much more glue code). + * @code {.c} + * psa_status_t psa_ecc_p256r1_sign_hash(const psa_key_attributes_t *attributes, + * psa_algorithm_t alg, const uint8_t *key_buffer, + * size_t key_buffer_size, const uint8_t *hash, + * size_t hash_length, uint8_t *signature, + * size_t signature_size, size_t *signature_length) + * { + * int status = _(key_buffer, hash, hash_length, + * signature, signature_length, curve); + * + * if (status != SUCCESS) { + * return _status_to_psa_error(status); + * } + * + * (void)alg; + * (void)attributes; + * (void)key_buffer_size; + * return PSA_SUCCESS; + * } + * @endcode + * + * ### Operation Contexts + * Some cryptographic operations use driver specific context to store the operation state in + * between function calls. These must be defined somewhere. Examples can be found in + * `pkg/driver_cryptocell_310/include/psa_periph_hashes_ctx.h` and + * `sys/include/hashes/psa/riot_hashes.h`. + * + * When defining the contexts for a hardware driver, all you need to do is add a file called + * `psa_periph__ctx.h` to your driver's include folder and define the available types + * (see supported [types](#supported-types) below). + * Those files are automatically included in `crypto_includes.h` and it is important that they + * always have the same name for each algorithm. + * + * When defining the contexts for a software library, the headerfile should be called + * `_.h` (e.g. `riot_hashes.h`) and must be added to `crypto_includes.h` as + * shown below: + * @code + * #if IS_USED(MODULE_PSA__) + * #include "/_.h" + * #endif + * @endcode + * + * When defining the context types, those must always depend on the specific algorithm module, + * for example + * @code + * #if IS_USED(MODULE_PSA__HASHES_SHA_256) + * #include "path/to/headerfile_containing_the_driver_context_definition" + * + * typedef psa_hashes_sha256_ctx_t; + * #endif + * @endcode + * + * #### Hashes {#supported-types} + * - `psa_hashes_md5_ctx_t` + * - `psa_hashes_sha1_ctx_t` + * - `psa_hashes_sha224_ctx_t` + * - `psa_hashes_sha256_ctx_t` + * - `psa_hashes_sha512_ctx_t` + * + * #### Ciphers + * - `psa_cipher_aes_128_ctx_t` + * - `psa_cipher_aes_192_ctx_t` + * - `psa_cipher_aes_256_ctx_t` + * + * Secure Elements need their own contexts. For this, + * see [Case Example – Secure Elements](#porting-secure-elements). + * + * ## Adding a Backend + * The integration of hardware drivers, software libraries and secure element drivers + * differs a bit. Below we describe the necessary steps for each of them. + * + * ### Case Example – A Software Library {#porting-software} + * Software libraries are the easiest backends, because they are not platform or hardware + * specific. They can generally run on all platforms in RIOT and we can + * combine different software backends for different operations (we could, for example, + * use the Micro-ECC package for ECC NIST curves and the C25519 package for operations with + * the Curve25519). + * + * Let's say we have an imaginary software library called `FancyCrypt` and want to use + * it as a backend of PSA. We've already added it to RIOT as a third party package in + * `pkg/fancycrypt`. + * Our library provides hashes and elliptic curve operations and to make it accessible to + * PSA Crypto we need to write wrappers for our API calls. + * + * First we create a folder called `psa_fancycrypt` in the package directory. Inside we create + * a file with the name of each operation you want to integrate, e.g. `p256.c` and + * `hashes_sha_224.c` (when adding operations, remember that the path of the files will also + * be the [module name](#module-names), so please comply with the current naming scheme). + * + * In these files we need to implement the methods that are called by PSA as described + * [above](#glue-code). + * + * #### Adding Makefiles + * We add a Makefile to the `psa_fancycrypt` folder with the following content: + * @code {.c} + * BASE_MODULE := psa_fancycrypt + * SUBMODULES := 1 + * + * include $(RIOTBASE)/Makefile.base + * @endcode + * + * This tells RIOT that the `psa_fancycrypt` module has submodules, which can be selected + * individually. + * + * In `pkg/fancycrypt` we now need to declare explicit pseudomodules in `Makefile.include` and add + * the `psa_fancycrypt` folder to the source files and the `sys/psa_crypto/include` folder to the + * includes. + * These should be dependent on the PSA Crypto module as shown below. + * + * @code + * ifneq (,$(filter psa_fancycrypt_%, $(USEMODULE))) + * PSEUDOMODULES += psa_fancycrypt_hashes_sha_256 + * PSEUDOMODULES += psa_fancycrypt_p256 + * DIRS += $(RIOTPKG)/fancycrypt/psa_fancycrypt + * INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include + * endif + * @endcode + * + * If the implementation has any dependencies, they need to be added in `Makefile.dep`, for example: + * @code + * USEMODULE += psa_fancycrypt + * USEMODULE += psa_fancycrypt_error_conversion + * + * ifneq (,$(filter psa_fancycrypt_hashes_sha1,$(USEMODULE))) + * USEMODULE += psa_fancycrypt_hashes_common + * endif + * @endcode + * + * #### Adding a Kconfig file + * We add a file called `Kconfig` to the `psa_fancycrypt` folder. Here we declare + * the modules for Kconfig like so: + * @code + * config MODULE_PSA_FANCYCRYPT_HASHES_SHA_256 + * bool + * depends on MODULE_PSA_CRYPTO + * select MODULE_PSA_FANCYCRYPT + * + * config MODULE_PSA_FANCYCRYPT_P256 + * bool + * depends on MODULE_PSA_CRYPTO + * select MODULE_PSA_FANCYCRYPT + * + * config MODULE_PSA_FANCYCRYPT + * bool + * @endcode + * + * If the implementation has any dependencies, we can select them in this Kconfig file: + * @code + * config MODULE_PSA_FANCYCRYPT_HASHES_SHA_256 + * bool + * depends on MODULE_PSA_CRYPTO + * select MODULE_PSA_FANCYCRYPT + * select MODULE_PSA_FANCYCRYPT_HASHES_COMMON + * select MODULE_PSA_FANCYCRYPT_ERROR_CONVERSION + * @endcode + * + * In `pkg/fancycrypt/Kconfig` we need to add the line + * @code + * rsource "psa_fancycrypt/Kconfig" + * @endcode + * at the bottom. + * + * #### Telling PSA Crypto about it + * To be able to choose `fancycrypt` as a PSA backend, we need to add the option to the Kconfig + * and Makefiles of the PSA Crypto Module. + * + * In `sys/psa_crypto/` we need to modify `Kconfig.asymmetric`, `sys/psa_crypto/Kconfig.hashes`, + * `Makefile.dep` and `Makefile.include`. + * + * To `Kconfig.asymmetric` we need to add + * @code + * config MODULE_PSA_ASYMMETRIC_ECC_P256R1_BACKEND_FANCYCRYPT + * bool "FancyCrypt Package" + * select PACKAGE_FANCYCRYPT + * select MODULE_PSA_FANCYCRYPT_P256 + * @endcode + * This will expose FancyCrypt as a backend option in PSA and then enable all the necessary + * features, when users select it. + * You need to do the same thing for the hash operation in `Kconfig.hashes`. + * + * To achieve the same thing with Makefiles we need to do this in two places: + * In `Makefile.include` there are some existing pseudomodules for asymmetric crypto and hashes. + * There we need to create the backend modules for FancyCrypt by adding + * + * @code + * PSEUDOMODULES += psa_asymmetric_ecc_p256r1_backend_fancycrypt + * @endcode + * + * and + * + * @code + * PSEUDOMODULES += psa_hash_sha_256_backend_fancycrypt + * @endcode + * + * The automatic module selection happens in `Makefile.dep`. To the place where exiting P256 curves + * and hashes are selected we add cases for our backend modules: + * + * @code + * ifneq (,$(filter psa_asymmetric_ecc_p256r1_backend_fancycrypt,$(USEMODULE))) + * USEPKG += fancycrypt + * USEMODULE += psa_fancycrypt + * USEMODULE += psa_fancycrypt_p256 + * endif + * @endcode + * + * Now you should be able to select your package as a backend for PSA Crypto and use it to perform + * operations. + * + * ### Case Example – A Hardware Driver {#porting-hardware} + * The first steps of porting a hardware driver are the same as for the software library. + * Only we skip the last part where we add the modules to the PSA Crypto Kconfig and Makefiles + * and do something else instead. + * + * Hardware drivers are treated a little differently, mostly because they are tied to a specific + * platform and users can not just choose a different driver for their accelerator. + * Therefore we just want PSA Crypto to automatically use this driver whenever it runs on the + * corresponding platform, which means that we have to add some additional options and features, + * not only to the driver but also to the CPU it belongs to. + * A good example for this is the [CryptoCell 310 driver](#pkg_driver_cryptocell_310) for the + * accelerator on the [nRF52840 CPU](#cpu_nrf52). + * + * Now, let's say we have a CPU called `myCPU` with an on-chip accelerator called + * `speedycrypt`. Let's say that `speedycrypt` provides hashes and ECC curves. + * The vendor provides a driver, which we already have included in RIOT as a package. + * Also we've followed the steps in the [glue code section](#glue-code) and provide a folder called + * `pkg/driver_speedycrypt/psa_speedycrypt` with the required wrapper files. + * We have also added the module names in a Kconfig file and in the Makefiles. + * + * #### Telling PSA Crypto about it + * This is where we diverge from the software library example. If you take a look at the available + * backends in PSA, you'll notice one with the postfix `*_BACKEND_PERIPH` for each available + * algorithm. **Periph** here is short for *peripheral hardware accelerator*. + * The `*_BACKEND_PERIPH` modules depend on the presence of such an accelerator. They are a generic + * module for all crypto hardware accelerators and will automatically resolve to the driver that is + * associated with the available accelerator. + * + * Before we're able to use it we need to tell RIOT that those hardware features exist for + * our `myCPU` (see `cpu/nrf52/Kconfig` and `cpu/nrf52/Makefile.features` as an example). + * In `cpu/myCPU` we add all the provided features as shown below. + * + * Files we need to touch: + * - `cpu/myCPU/Makefile.features` + * - `cpu/myCPU/Kconfig` + * - `cpu/myCPU/periph/Makefile.dep` + * - `cpu/myCPU/periph/Kconfig` + * - When defining new features: `RIOT/kconfigs/Kconfig.features` + * + * **cpu/myCPU/Makefile.features:** + * @code + * FEATURES_PROVIDED += periph_speedycrypt // General feature for the acclerator + * FEATURES_PROVIDED += periph_hash_sha_256 + * FEATURES_PROVIDED += periph_ecc_p256r1 + * @endcode + * + * **cpu/myCPU/Kconfig:** + * @code + * config CPU_FAM_MYCPU + * bool + * select CPU_SOME_FEATURES + * ... + * select HAS_PERIPH_HASH_SHA_256 + * select HAS_PERIPH_ECC_P256R1 + * select HAS_PERIPH_SPEEDYCRYPT + * @endcode + * The `HAS_PERIPH_*` symbols are defined in ``. If your device + * provides capabilities that are not yet defined, you can add them to that file. + * + * Next we need to define selectable modules for this in the `cpu/myCPU/periph` folder, which + * then automatically enable the driver. An example for this is `cpu/nrf52/periph`. + * We add the following to the `cpu/myCPU/periph/Kconfig` file and `cpu/myCPU/periph/Makefile.dep`: + * + * **cpu/myCPU/periph/Makefile.dep:** + * @code + * ifneq (,$(filter periph_hash_sha_256,$(USEMODULE))) + * USEPKG += driver_speedycrypt + * USEMODULE += psa_speedycrypt_hashes_sha256 + * endif + * @endcode + * + * **cpu/myCPU/periph/Kconfig:** + * @code + * config MODULE_PERIPH_FANCYCRYPT + * bool + * depends on HAS_PERIPH_FANCYCRYPT + * select PACKAGE_DRIVER_FANCYCRYPT + * + * config MODULE_PERIPH_HASH_SHA_256 + * bool + * depends on HAS_PERIPH_HASH_SHA_256 + * select MODULE_PERIPH_SPEEDYCRYPT + * select MODULE_PSA_SPEEDYCRYPT_HASHES_SHA256 + * @endcode + * + * Here we basically say "If the user chooses the `periph_hash_sha_256 module`, also select the + * `periph_speedycrypt` feature, which will then enable the speedycrypt driver". Of course you need + * to do this for all your available features. + * + * Now, if you build PSA Crypto with default configurations, it should automatically detect that + * your board has a hardware accelerator for hashes and ECC operations and build the hardware + * driver as a backend. + * + * ### Case Example – A Secure Element Driver {#porting-secure-elements} + * Secure elements (SEs) are handled almost completely separate from the other backends. When we use + * software libraries or hardware drivers, we only build one implementation per algorithm. + * When it comes to secure elements we want to be able to build them in addition to the other + * backends and we may want to connect and use more than one of them at the same time. + * Another difference is that when using software libraries and hardware drivers, PSA handles the + * storage of key material. When using SEs, keys are stored on the SE, which means, we need + * additional functionality for the key management. + * + * An existing example in RIOT is the Microchip ATECCX08A device family, whose driver can be found + * in `pkg/cryptoauthlib`. + * + * PSA Crypto has an integrated SE driver registry, which stores all registered drivers in a list. + * When an application calls a cryptographic operation that's supposed to be performed by a secure + * element, the registry will find the correct driver in the list and PSA will invoke the operation. + * Each driver is stored with a context that contains persistent as well as transient driver data. + * Transient driver data can be anything the driver needs to function. Persistent data is supposed + * to be used to keep track of how many keys are stored on the device and if there is still some + * free space available. + * + * @note Currently PSA does not support persistent storage, so the persistent driver data + * is not really persistent, yet. Once persistent storage is implemented, this data + * will be stored, so the implementation can find already existing keys again after + * a reboot. + * + * For this example we integrate an imaginary SE called `superSE`, which comes with a driver called + * `superSE_lib`. Again, we assume that we have already added the driver as a package in RIOT and it + * can be found at `pkg/superse_lib`. + * + * #### Adding the Glue Code + * Secure element drivers need to implement a different API than the other backends. It is defined + * [here](#sys_psa_crypto_se_driver). + * In our package folder we now create a new folder called `psa_superse_driver` and add a source + * file called `psa_superse_lib_driver.c`. Here we now implement glue code for all the cryptographic + * operations our SE supports. + * + * You will notice that the SE interface also provides some key management functions. This is + * because keys are stored on the device and PSA can not access the memory and key data itself, + * but needs to tell the driver to do it. + * + * ### Operation Contexts + * Some operations need driver specific contexts. For secure elements these are wrapped in types + * defined in `crypto_contexts.h` (currently only `psa_se_cipher_context_t` is supported). + * In this header file add operation contexts that belong to your driver to the available SE + * context unions as shown in the example below: + * + * @code + * typedef struct { + * union driver_context { + * unsigned dummy; + * #if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) || defined(DOXYGEN) + * atca_aes_cbc_ctx_t atca_aes_cbc; + * #endif + * #if IS_USED(MODULE_PSA_SECURE_ELEMENT_SUPERSE) || defined(DOXYGEN) + * superse_cipher_ctx_t superse_aes_cbc; + * #endif + * } drv_ctx; + * } psa_se_cipher_context_t; + * @endcode + * + * #### Allocation + * The first thing PSA will do, when an application creates a key on an SE, is ask the driver to + * find a free key slot on the device. This is what the `allocate` function is for. How exactly + * the slot is allocated, depends on the driver. + * It may be possible to query that information directly from the device. If that is not possible, + * we can use the persistent data stored in the driver context. An example for this can be + * found in `pkg/cryptoauthlib/psa_atca_driver/psa_atca_se_driver.c`. + * This example requires the user to provide information about the configurations for each key slot, + * which is then stored in the persistent driver data and used for key management (for a better + * description read [Using Cryptoauthlib as a backend for PSA Crypto](#psa-cryptoauthlib)). + * At this point you can decide what the best approach for your device is. + * + * The `allocate` function should then return some reference to the slot it has allocated + * for the key (possibly a pointer or a slot number). Next PSA Crypto will invoke the `import` + * or `generate` function to store a key. + * + * #### Using Persistent Data + * When you want to use persistent data to keep track of keys, you should utilize the + * `psa_se_config_t` structure, which is declared in `crypto_se_config.h`. + * You can define a structure that can hold your device configuration and make sure it is available + * then your SE is used. + * + * #### Making the Methods Available + * At the bottom of the wrapper code, define structures with pointers to the available methods. + * For example if you have implemented a `superse_allocate` and `superse_generate_key` function, + * you need to add a `psa_drv_se_key_management_t` structure as shown below. Fill the unimplemented + * methods with `NULL` pointers. + * The last structure should be a `psa_drv_se_t` struct containing pointers to the other structures. + * That one will be stored during driver registration to get access to all the implemented + * functions. + * + * @code {.c} + * static psa_drv_se_key_management_t superse_key_management = { + * .p_allocate = superse_allocate, + * .p_validate_slot_number = NULL, + * .p_import = NULL, + * .p_generate = superse_generate_key, + * .p_destroy = NULL, + * .p_export = NULL, + * .p_export_public = NULL + * }; + * + * psa_drv_se_t superse_methods = { + * .hal_version = PSA_DRV_SE_HAL_VERSION, + * .persistent_data_size = 0, + * .p_init = NULL, + * .key_management = &superse_key_management, + * .mac = NULL, + * .cipher = NULL, + * .aead = NULL, + * .asymmetric = NULL, + * .derivation = NULL + * }; + * @endcode + * + * You should do this for all available functions. The structures for the functions are + * declared in `sys/psa_crypto/include/psa_crypto_se_driver.h`. + * + * #### Driver Registration + * At start-up all secure element drivers need to be registered with the PSA SE management module. + * This happens by calling `psa_register_secure_element()` during the automatic driver + * initialization in RIOT. + * When you added support for our device to RIOT, you should have implemented an + * `auto_init_` function, which initializes the connected devices. + * In this function, after initializing a device, you should call `psa_register_secure_element()` + * and pass the device's location value, and pointers to the `psa_drv_se_t` structure, + * the persistent data and some device specific context. + * An example implementation of this can be seen in `sys/auto_init/security/auto_init_atca.c`. + * + * #### Telling PSA Crypto about it + * To be able to choose our `superSE` during configuration, we need to define the corresponding + * modules in the Kconfig files and Makefiles. + * + * To `pkg/super_se_lib/Kconfig` we add something like + * @code + * config MODULE_PSA_SUPERSE_DRIVER + * bool + * depends on PACKAGE_SUPERSE_LIB + * default y if MODULE_PSA_CRYPTO + * select PSA_KEY_MANAGEMENT + * @endcode + * This tells the build system that whenever this driver and PSA Crypto are used at the same time, + * the wrapper and the PSA key management module are needed, too. + * + * To `sys/psa_crypto/psa_se_mgmt/Kconfig` we add a menu for the SE like so: + * @code + * menuconfig MODULE_PSA_SECURE_ELEMENT_SUPERSE + * bool "Our Vendor's SuperSE" + * select PACKAGE_SUPERSE_LIB + * depends on + * help + * + * @endcode + * This makes our driver selectable whenever an application configuration selects the PSA secure + * element module. + * + * As described in the [Configuration Section](#configuration-keys), references to keys on secure + * elements are stored by PSA in a different type of key slot than other keys. + * The slot for protected keys usually only contains a slot number or address and not the actual + * key, which requires a lot less memory space. + * + * **BUT:** If your secure element supports asymmetric cryptography and exports a public key part + * during key generation, that key part must be stored somewhere. This is why there needs to be + * an option to tell PSA Crypto that an application is going to perform asymmetric operations. + * Only if that option is selected, the protected key slots will have the space to store a public + * key. + * + * For this we need to add the following to the `superSE` menu: + * @code + * config MODULE_PSA_SECURE_ELEMENT_SUPERSE_ECC_P256 + * bool "Our Vendor's Elliptic Curve P256" + * select PSA_KEY_SIZE_256 + * select MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC + * depends on MODULE_PSA_SECURE_ELEMENT_SUPERSE + * @endcode + * This tells us, what size a key slot should have to store the public key. If your SE supports + * other curves, you need to modify this accordingly or add more of them. + * + * Now we need to add the same to the Makefiles. In `Makefile.include` we add the source file path + * and the PSA include folders and define the new available pseudomodules: + * @code + * ifneq (,$(filter psa_crypto,$(USEMODULE))) + * DIRS += $(RIOTPKG)/superse_lib/psa_superse_driver + * INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include + * PSEUDOMODULES += psa_secure_element_superse + * PSEUDOMODULES += psa_secure_element_superse_ecc_p256 + * endif + * @endcode + * + * In `Makefile.dep` we automatically add required modules when PSA Crypto and the ECC curve + * module are chosen: + * @code + * ifneq (,$(filter psa_crypto,$(USEMODULE))) + * USEMODULE += psa_superse_driver + * endif + * + * ifneq (,$(filter psa_secure_element_superse_ecc_p256, $(USEMODULE))) + * USEMODULE += psa_secure_element_asymmetric + * endif + * + * Now the secure element should be available for use with PSA Crypto. + * @endcode + */ diff --git a/sys/psa_crypto/include/psa_ciphers.h b/sys/psa_crypto/include/psa_ciphers.h new file mode 100644 index 0000000000..65c5601b92 --- /dev/null +++ b/sys/psa_crypto/include/psa_ciphers.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @defgroup sys_psa_crypto_cipher PSA Wrapper Functions: Cipher + * @{ + * + * @file psa_ciphers.h + * @brief Function declarations for low level wrapper functions for cipher operations. + * + * @author Lena Boeckmann + * + */ + +#ifndef PSA_CIPHERS_H +#define PSA_CIPHERS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "psa/crypto.h" +#include "psa/crypto_contexts.h" + +/** + * @brief Low level wrapper function to call a driver for an AES 128 CBC encryption. + * See @ref psa_cipher_encrypt() + * + * @param attributes + * @param key_buffer + * @param key_buffer_size + * @param alg + * @param input + * @param input_length + * @param output + * @param output_size + * @param output_length + * @return @ref psa_status_t + */ +psa_status_t psa_cipher_cbc_aes_128_encrypt(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Low level wrapper function to call a driver for an AES 128 CBC decryption. + * See @ref psa_cipher_decrypt() + * + * @param attributes + * @param key_buffer + * @param key_buffer_size + * @param alg + * @param input + * @param input_length + * @param output + * @param output_size + * @param output_length + * @return @ref psa_status_t + */ +psa_status_t psa_cipher_cbc_aes_128_decrypt(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Low level wrapper function to call a driver for an AES 192 CBC encryption. + * See @ref psa_cipher_encrypt() + * + * @param attributes + * @param key_buffer + * @param key_buffer_size + * @param alg + * @param input + * @param input_length + * @param output + * @param output_size + * @param output_length + * @return @ref psa_status_t + */ +psa_status_t psa_cipher_cbc_aes_192_encrypt(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Low level wrapper function to call a driver for an AES 256 CBC encryption. + * See @ref psa_cipher_encrypt() + * + * @param attributes + * @param key_buffer + * @param key_buffer_size + * @param alg + * @param input + * @param input_length + * @param output + * @param output_size + * @param output_length + * @return psa_status_t + */ +psa_status_t psa_cipher_cbc_aes_256_encrypt(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CIPHERS_H */ +/** @} */ diff --git a/sys/psa_crypto/include/psa_crypto_algorithm_dispatch.h b/sys/psa_crypto/include/psa_crypto_algorithm_dispatch.h new file mode 100644 index 0000000000..3e70dd5335 --- /dev/null +++ b/sys/psa_crypto/include/psa_crypto_algorithm_dispatch.h @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @defgroup sys_psa_crypto_alg_disp PSA Crypto Algorithm Dispatcher + * @{ + * + * @file psa_crypto_algorithm_dispatch.h + * @brief Function declarations for PSA Crypto algorithm dispatcher + * + * @author Lena Boeckmann + * + */ + +#ifndef PSA_CRYPTO_ALGORITHM_DISPATCH_H +#define PSA_CRYPTO_ALGORITHM_DISPATCH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "kernel_defines.h" +#include "psa/crypto.h" +#include "psa_crypto_slot_management.h" + +/** + * @brief Dispatch a hash setup function to a specific backend. + * See @ref psa_hash_setup() + * + * @param operation + * @param alg + * @return @ref psa_status_t + */ +psa_status_t psa_algorithm_dispatch_hash_setup(psa_hash_operation_t *operation, + psa_algorithm_t alg); + +/** + * @brief Dispatch a hash update function to a specific backend. + * See @ref psa_hash_update() + * + * @param operation + * @param input + * @param input_length + * @return @ref psa_status_t + */ +psa_status_t psa_algorithm_dispatch_hash_update(psa_hash_operation_t *operation, + const uint8_t *input, + size_t input_length); + +/** + * @brief Dispatch a hash finish function to a specific backend. + * See @ref psa_hash_finish() + * + * @param operation + * @param hash + * @param hash_size + * @param hash_length + * @return @ref psa_status_t + */ +psa_status_t psa_algorithm_dispatch_hash_finish(psa_hash_operation_t *operation, + uint8_t *hash, + size_t hash_size, + size_t *hash_length); + +/** + * @brief Dispatch a hash signature function to a specific backend. + * See @ref psa_sign_hash() + * + * @param attributes + * @param alg + * @param slot + * @param hash + * @param hash_length + * @param signature + * @param signature_size + * @param signature_length + * @return @ref psa_status_t + */ +psa_status_t psa_algorithm_dispatch_sign_hash( const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *hash, + size_t hash_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length); + +/** + * @brief Dispatch a hash verification function to a specific backend. + * See @ref psa_verify_hash() + * + * @param attributes + * @param alg + * @param slot + * @param hash + * @param hash_length + * @param signature + * @param signature_length + * @return @ref psa_status_t + */ +psa_status_t psa_algorithm_dispatch_verify_hash( const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *hash, + size_t hash_length, + const uint8_t *signature, + size_t signature_length); + +/** + * @brief Dispatch the key generation function to a specific backend. + * See @ref psa_generate_key() + * + * @param attributes + * @param slot + * @return @ref psa_status_t + */ +psa_status_t psa_algorithm_dispatch_generate_key( const psa_key_attributes_t *attributes, + psa_key_slot_t *slot); + +/** + * @brief Dispatch a cipher encrypt function to a specific backend. + * See @ref psa_cipher_encrypt() + * + * @param attributes + * @param alg + * @param slot + * @param input + * @param input_length + * @param output + * @param output_size + * @param output_length + * @return @ref psa_status_t + */ +psa_status_t psa_algorithm_dispatch_cipher_encrypt( const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Dispatch a cipher decrypt function to a specific backend. + * See @ref psa_cipher_decrypt() + * + * @param attributes + * @param alg + * @param slot + * @param input + * @param input_length + * @param output + * @param output_size + * @param output_length + * @return @ref psa_status_t + */ +psa_status_t psa_algorithm_dispatch_cipher_decrypt( const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Dispatch a mac computation function to a specific backend. + * See @ref psa_mac_compute() + * + * @param attributes + * @param alg + * @param slot + * @param input + * @param input_length + * @param mac + * @param mac_size + * @param mac_length + * @return @ref psa_status_t + */ +psa_status_t psa_algorithm_dispatch_mac_compute(const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *input, + size_t input_length, + uint8_t *mac, + size_t mac_size, + size_t *mac_length); + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTO_ALGORITHM_DISPATCH_H */ +/** @} */ diff --git a/sys/psa_crypto/include/psa_crypto_location_dispatch.h b/sys/psa_crypto/include/psa_crypto_location_dispatch.h new file mode 100644 index 0000000000..a6ff3c7099 --- /dev/null +++ b/sys/psa_crypto/include/psa_crypto_location_dispatch.h @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @defgroup sys_psa_crypto_loc_disp PSA Crypto Location Dispatcher + * @{ + * + * @file psa_crypto_location_dispatch.h + * @brief Function declarations for the PSA Crypto location dispatcher. + * + * @author Lena Boeckmann + * + */ + +#ifndef PSA_CRYPTO_LOCATION_DISPATCH_H +#define PSA_CRYPTO_LOCATION_DISPATCH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "kernel_defines.h" +#include "psa/crypto.h" + +/** + * @brief Dispatch call of a hash signature function to a location specific backend. + * See psa_sign_hash() + * + * @param attributes + * @param alg + * @param slot + * @param hash + * @param hash_length + * @param signature + * @param signature_size + * @param signature_length + * @return psa_status_t + */ +psa_status_t psa_location_dispatch_sign_hash( const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *hash, + size_t hash_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length); + +/** + * @brief Dispatch call of a hash verification function to a location specific backend. + * See psa_verify_hash() + * + * @param attributes + * @param alg + * @param slot + * @param hash + * @param hash_length + * @param signature + * @param signature_length + * @return psa_status_t + */ +psa_status_t psa_location_dispatch_verify_hash( const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *hash, + size_t hash_length, + const uint8_t *signature, + size_t signature_length); + +/** + * @brief Dispatch call of a mac computation function to a location specific backend. + * See psa_mac_compute() + * + * @param attributes + * @param alg + * @param slot + * @param input + * @param input_length + * @param mac + * @param mac_size + * @param mac_length + * @return psa_status_t + */ +psa_status_t psa_location_dispatch_mac_compute(const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *input, + size_t input_length, + uint8_t *mac, + size_t mac_size, + size_t *mac_length); + +/** + * @brief Dispatch call of the key generation function to a location specific backend. + * See psa_generate_key() + * + * @param attributes + * @param slot + * @return psa_status_t + */ +psa_status_t psa_location_dispatch_generate_key(const psa_key_attributes_t *attributes, + psa_key_slot_t *slot); + +/** + * @brief Dispatch call of the key import function to a location specific backend. + * See psa_import_key() + * + * @param attributes + * @param data + * @param data_length + * @param slot + * @param bits + * @return psa_status_t + */ +psa_status_t psa_location_dispatch_import_key( const psa_key_attributes_t *attributes, + const uint8_t *data, size_t data_length, + psa_key_slot_t *slot, size_t *bits); + +/** + * @brief Dispatch call of a cipher encrypt setup function to a location specific backend. + * See psa_cipher_setup() + * + * @param operation + * @param attributes + * @param slot + * @param alg + * @return psa_status_t + */ +psa_status_t psa_location_dispatch_cipher_encrypt_setup( psa_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const psa_key_slot_t *slot, + psa_algorithm_t alg); + +/** + * @brief Dispatch call of a cipher decrypt setup function to a location specific backend. + * See psa_cipher_setup() + * + * @param operation + * @param attributes + * @param slot + * @param alg + * @return psa_status_t + */ +psa_status_t psa_location_dispatch_cipher_decrypt_setup(psa_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const psa_key_slot_t *slot, + psa_algorithm_t alg); + +/** + * @brief Dispatch call of a function to set a cipher IV to a location specific backend. + * See psa_cipher_set_iv() + * + * @param operation + * @param iv + * @param iv_length + * @return psa_status_t + */ +psa_status_t psa_location_dispatch_cipher_set_iv( psa_cipher_operation_t *operation, + const uint8_t *iv, + size_t iv_length); + +/** + * @brief Dispatch call of a cipher encrypt function to a location specific backend. + * See psa_cipher_encrypt() + * + * @param attributes + * @param alg + * @param slot + * @param input + * @param input_length + * @param output + * @param output_size + * @param output_length + * @return psa_status_t + */ +psa_status_t psa_location_dispatch_cipher_encrypt( const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Dispatch call of a cipher decrypt function to a location specific backend. + * See psa_cipher_decrypt() + * + * @param attributes + * @param alg + * @param slot + * @param input + * @param input_length + * @param output + * @param output_size + * @param output_length + * @return psa_status_t + */ +psa_status_t psa_location_dispatch_cipher_decrypt( const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Dispatch call of a random number generator to a specific backend. + * See psa_generate_random() + * + * @param output + * @param output_size + * @return psa_status_t + */ +psa_status_t psa_location_dispatch_generate_random(uint8_t *output, + size_t output_size); + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTO_LOCATION_DISPATCH_H */ +/** @} */ diff --git a/sys/psa_crypto/include/psa_crypto_operation_encoder.h b/sys/psa_crypto/include/psa_crypto_operation_encoder.h new file mode 100644 index 0000000000..bcac6c80fa --- /dev/null +++ b/sys/psa_crypto/include/psa_crypto_operation_encoder.h @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2022 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @{ + * + * @file psa_crypto_operation_encoder.h + * @brief Macros used to map PSA akgorithms, key types and key sizes to specific key types + * and operations to call the corresponding driver functions. + * + * @note Currently this only supports a small number of operations. It should be expanded as + * needed as this implementation increases support for more operations. + * + * @author Lena Boeckmann + * + */ + +#ifndef PSA_CRYPTO_OPERATION_ENCODER_H +#define PSA_CRYPTO_OPERATION_ENCODER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "psa/crypto.h" +#include "psa_crypto_slot_management.h" + +/** + * @brief Unknown or invalid operation + */ +#define PSA_INVALID_OPERATION (0xFF) + +/** + * @brief Enum encoding available cipher operations. + * + * @details To be expanded with the development of this implementation. + */ +typedef enum { + PSA_CBC_NO_PAD_AES_128, + PSA_CBC_NO_PAD_AES_192, + PSA_CBC_NO_PAD_AES_256, + PSA_CBC_PKCS7_AES_256 +} psa_cipher_op_t; + +/** + * @brief Enum encoding available asymmetric key types and sizes. + * + * @details To be expanded with the development of this implementation. + */ +typedef enum { + PSA_ECC_P160_K1, + PSA_ECC_P160_R1, + PSA_ECC_P160_R2, + PSA_ECC_P192_K1, + PSA_ECC_P192_R1, + PSA_ECC_P224_K1, + PSA_ECC_P224_R1, + PSA_ECC_P256_K1, + PSA_ECC_P256_R1, + PSA_ECC_P384_R1, + PSA_ECC_P521_R1, + PSA_ECC_FRP, + PSA_ECMONT_255, + PSA_ECMONT_448 +} psa_asym_key_t; + +/** + * @brief Combine an ECC 192 key type with a given curve. + * + * @param curve Must be a curve of type @ref psa_ecc_family_t + * + * @return @ref psa_asym_key_t + * @return @ref PSA_INVALID_OPERATION @c curve is not compatible with key size + */ +#define GET_ECC_KEY_TYPE_192(curve) \ + ((curve == PSA_ECC_FAMILY_SECP_R1) ? PSA_ECC_P192_R1 : \ + PSA_INVALID_OPERATION) + +/** + * @brief Combine an ECC 265 key type with a given curve. + * + * @param curve Must be a curve of type @ref psa_ecc_family_t + * + * @return @ref psa_asym_key_t + * @return @ref PSA_INVALID_OPERATION @c curve is not compatible with key size + */ +#define GET_ECC_KEY_TYPE_256(curve) \ + ((curve == PSA_ECC_FAMILY_SECP_R1) ? PSA_ECC_P256_R1 : \ + PSA_INVALID_OPERATION) + +/** + * @brief Map an ECC 192 key to a given curve according to its type and size. + * + * @param bits Key size of type @ref psa_key_bits_t + * @param curve Must be a curve of type @ref psa_ecc_family_t + * + * @return @ref psa_asym_key_t + * @return @ref PSA_INVALID_OPERATION @c curve and @c bits are incompatible + */ +#define PSA_ENCODE_ECC_KEY_TYPE(bits, curve) \ + ((bits == 256) || (bits == 520) ? GET_ECC_KEY_TYPE_256(curve) : \ + (bits == 192) || (bits == 392) ? GET_ECC_KEY_TYPE_192(curve) : \ + PSA_INVALID_OPERATION) + +/** + * @brief Combine algorithm, and key type with a key size of 128 bits. + * + * @param alg Algorithm of type @ref psa_algorithm_t. + * @param type Key type of type @ref psa_key_type_t + * + * @return @ref psa_cipher_op_t + * @return @ref PSA_INVALID_OPERATION @c alg, and @c type are incompatible with the key size + */ +#define GET_CIPHER_OPERATION_128(alg, type) \ + (((alg == PSA_ALG_CBC_NO_PADDING) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_NO_PAD_AES_128 : \ + PSA_INVALID_OPERATION) + +/** + * @brief Combine algorithm, and key type with a key size of 192 bits. + * + * @param alg Algorithm of type @ref psa_algorithm_t. + * @param type Key type of type @ref psa_key_type_t + * + * @return @ref psa_cipher_op_t + * @return @ref PSA_INVALID_OPERATION @c alg, and @c type are incompatible with the key size + */ +#define GET_CIPHER_OPERATION_192(alg, type) \ + (((alg == PSA_ALG_CBC_NO_PADDING) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_NO_PAD_AES_192 : \ + PSA_INVALID_OPERATION) + +/** + * @brief Combine algorithm, and key type with a key size of 256 bits. + * + * @param alg Algorithm of type @ref psa_algorithm_t. + * @param type Key type of type @ref psa_key_type_t + * + * @return @ref psa_cipher_op_t + * @return @ref PSA_INVALID_OPERATION @c alg, and @c type are incompatible with the key size + */ +#define GET_CIPHER_OPERATION_256(alg, type) \ + (((alg == PSA_ALG_CBC_NO_PADDING) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_NO_PAD_AES_256 : \ + ((alg == PSA_ALG_CBC_PKCS7) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_PKCS7_AES_256 : \ + PSA_INVALID_OPERATION) + +/** + * @brief Map algorithm, key size and type to a specific operation. + * + * @param alg Algorithm of type @ref psa_algorithm_t. + * @param bits Size of the used key of type @ref psa_key_bits_t + * @param type Key type of type @ref psa_key_type_t + * + * @return @ref psa_cipher_op_t + * @return @ref PSA_INVALID_OPERATION @c alg, @c bits and @c type are not compatible + */ +#define PSA_ENCODE_CIPHER_OPERATION(alg, bits, type) \ + ((bits == 128) ? GET_CIPHER_OPERATION_128(alg, type) : \ + (bits == 192) ? GET_CIPHER_OPERATION_192(alg, type) : \ + (bits == 256) ? GET_CIPHER_OPERATION_256(alg, type) : \ + PSA_INVALID_OPERATION) + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTO_OPERATION_ENCODER_H */ +/** @} */ diff --git a/sys/psa_crypto/include/psa_crypto_se_driver.h b/sys/psa_crypto/include/psa_crypto_se_driver.h new file mode 100644 index 0000000000..cb856e4d8d --- /dev/null +++ b/sys/psa_crypto/include/psa_crypto_se_driver.h @@ -0,0 +1,1314 @@ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @ingroup sys_psa_crypto + * @defgroup sys_psa_crypto_se_driver PSA Crypto Secure Element Wrapper + * @{ + * + * @file psa_crypto_se_driver.h + * @brief PSA external cryptoprocessor driver module + * + * @details This header declares types and function signatures for cryptography + * drivers that access key material via opaque references. + * This is meant for cryptoprocessors that have a separate key storage from the + * space in which the PSA Crypto implementation runs, typically secure + * elements (SEs). + * + * This file is part of the PSA Crypto Driver HAL (hardware abstraction layer), + * containing functions for driver developers to implement to enable hardware + * to be called in a standardized way by a PSA Cryptography API + * implementation. The functions comprising the driver HAL, which driver + * authors implement, are not intended to be called by application developers. + */ + +#ifndef PSA_CRYPTO_SE_DRIVER_H +#define PSA_CRYPTO_SE_DRIVER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "psa/crypto_values.h" +#include "psa/crypto_types.h" + +/** + * @brief Maximum size of persistent driver data in bytes + */ +#define PSA_MAX_PERSISTENT_DATA_SIZE (16) + +/** + * @defgroup se_init Secure Element Driver Initialization + */ +/**@{*/ + +/** + * @brief Driver context structure + * + * @details 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 @c malloc (but the core can use any + * method to allocate the buffer, not necessarily @c 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: + * - @ref psa_drv_se_t::p_init + * - @ref psa_drv_se_key_management_t::p_allocate + * - @ref 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: + * - @ref psa_crypto_init() causes a call to @ref psa_drv_se_t::p_init, and may call + * @ref 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 @ref psa_drv_se_key_management_t::p_allocate, + * and may cause a call to @ref psa_drv_se_key_management_t::p_destroy in case an error + * occurs. + * - @ref psa_destroy_key() causes a call to @ref psa_drv_se_key_management_t::p_destroy. + */ + const void * persistent_data; + + /** + * The size of @c persistent_data in bytes. + * + * This is always equal to the value of the @c persistent_data_size field + * of the @ref 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 drv_context The driver context structure. + * @param persistent_data A pointer to the persistent data + * that allows writing. + * @param location The location value for which this driver + * is registered. The driver will be invoked + * for all keys whose lifetime is in this + * location. + * + * @return @ref PSA_SUCCESS The driver is operational. + * The core will update the persistent data in storage. + * 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_location_t location); + +/** + * @brief Encoding of a key slot number on a secure element. + */ +typedef uint64_t psa_key_slot_number_t; +/**@}*/ + +/** + * @defgroup se_mac Secure Element Message Authentication Codes + * + * @details Generation and authentication of Message Authentication Codes (MACs) + * using a secure element can be done either as a single function call + * (via the `psa_drv_se_mac_generate_t` or `psa_drv_se_mac_verify_t` functions), + * or in parts using the following sequence: + * - `psa_drv_se_mac_setup_t` + * - `psa_drv_se_mac_update_t` + * - `psa_drv_se_mac_update_t` + * - ... + * - `psa_drv_se_mac_finish_t` or `psa_drv_se_mac_finish_verify_t` + * + * If a previously started secure element MAC operation needs to be terminated, + * it should be done so by the `psa_drv_se_mac_abort_t`. Failure to do so may + * result in allocated resources not being freed or in other undefined + * behavior. + * @{ + */ + +/** + * @brief A function that starts a secure element MAC operation for a PSA + * Crypto Driver implementation + * + * @param drv_context The driver context structure. + * @param op_context A structure that will contain the + * hardware-specific MAC context + * @param key_slot The slot of the key to be used for the + * operation + * @param algorithm The algorithm to be used to underly the MAC + * operation + * + * @return @ref PSA_SUCCESS Success. + * + */ +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 op_context A hardware-specific structure for the + * previously-established MAC operation to be + * updated + * @param p_input A buffer containing the message to be appended + * to the MAC operation + * @param input_length The size in bytes of the input message buffer + */ +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 op_context A hardware-specific structure for the + * previously started MAC operation to be + * finished + * @param p_mac A buffer where the generated MAC will be + * placed + * @param mac_size The size in bytes of the buffer that has been + * allocated for the @c output buffer + * @param p_mac_length After completion, will contain the number of + * bytes placed in the @c p_mac buffer + * + * @return @ref PSA_SUCCESS Success. + */ +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); + +/** + * @brief A function that completes a previously started secure element MAC + * operation by comparing the resulting MAC against a provided value + * + * @param op_context A hardware-specific structure for the previously + * started MAC operation to be fiinished + * @param p_mac The MAC value against which the resulting MAC + * will be compared against + * @param mac_length The size in bytes of the value stored in @c p_mac + * + * @return @ref PSA_SUCCESS The operation completed successfully and the MACs + * matched each other + * @ref PSA_ERROR_INVALID_SIGNATURE 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 *op_context, + const uint8_t *p_mac, + size_t mac_length); + +/** @brief A function that aborts a previous started secure element MAC + * operation + * + * @param 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 *op_context); + +/** + * @brief A function that performs a secure element MAC operation in one + * command and returns the calculated MAC + * + * @param drv_context The driver context structure. + * @param p_input A buffer containing the message to be MACed + * @param input_length The size in bytes of @c p_input + * @param key_slot The slot of the key to be used + * @param alg The algorithm to be used to underlie the MAC + * operation + * @param p_mac A buffer where the generated MAC will be + * placed + * @param mac_size The size in bytes of the @c p_mac buffer + * @param p_mac_length After completion, will contain the number of + * bytes placed in the @c output buffer + * + * @return @ref PSA_SUCCESS Success. + */ +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, + uint8_t *p_mac, + size_t mac_size, + size_t *p_mac_length); + +/** + * @brief A function that performs a secure element MAC operation in one + * command and compares the resulting MAC against a provided value + * + * @param drv_context The driver context structure. + * @param p_input A buffer containing the message to be MACed + * @param input_length The size in bytes of @c input + * @param key_slot The slot of the key to be used + * @param alg The algorithm to be used to underlie the MAC + * operation + * @param p_mac The MAC value against which the resulting MAC will + * be compared against + * @param mac_length The size in bytes of @c p_mac + * + * @return @ref PSA_SUCCESS The operation completed successfully and the MACs + * matched each other + * @ref PSA_ERROR_INVALID_SIGNATURE The operation completed successfully, but the + * calculated MAC did not match the provided MAC + */ +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, + const uint8_t *p_mac, + size_t mac_length); + +/** + * @brief A struct containing all of the function pointers needed to + * perform secure element MAC operations + * + * @details PSA Crypto API implementations should populate the table as appropriate + * upon startup. + * + * If one of the functions is not implemented (such as + * @ref psa_drv_se_mac_generate_t), it should be set to NULL. + * + * Driver implementers should ensure that they implement all of the functions + * that make sense for their hardware, and that they provide a full solution + * (for example, if they support @c p_setup, they should also support + * @c p_update and at least one of @c p_finish or @c p_finish_verify ). + * + */ +typedef struct { + /** The size in bytes of the hardware-specific secure element MAC context structure */ + size_t context_size; + /** Function that performs a MAC setup operation */ + psa_drv_se_mac_setup_t p_setup; + /** Function that performs a MAC update operation */ + psa_drv_se_mac_update_t p_update; + /** Function that completes a MAC operation */ + psa_drv_se_mac_finish_t p_finish; + /** Function that completes a MAC operation with a verify check */ + psa_drv_se_mac_finish_verify_t p_finish_verify; + /** Function that aborts a previoustly started MAC operation */ + psa_drv_se_mac_abort_t p_abort; + /** Function that performs a MAC operation in one call */ + psa_drv_se_mac_generate_t p_mac; + /** Function that performs a MAC and verify operation in one call */ + psa_drv_se_mac_verify_t p_mac_verify; +} psa_drv_se_mac_t; +/**@}*/ + +/** + * @defgroup se_cipher Secure Element Symmetric Ciphers + * + * @details Encryption and Decryption using secure element keys in block modes other + * than ECB must be done in multiple parts, using the following flow: + * - @ref psa_drv_se_cipher_setup_t + * - @ref psa_drv_se_cipher_set_iv_t (optional depending upon block mode) + * - @ref psa_drv_se_cipher_update_t + * - @ref psa_drv_se_cipher_update_t + * - ... + * - @ref psa_drv_se_cipher_finish_t + * + * If a previously started secure element Cipher operation needs to be + * terminated, it should be done so by the @ref psa_drv_se_cipher_abort_t. Failure + * to do so may result in allocated resources not being freed or in other + * undefined behavior. + * + * In situations where a PSA Cryptographic API implementation is using a block + * mode not-supported by the underlying hardware or driver, it can construct + * the block mode itself, while calling the @ref psa_drv_se_cipher_ecb_t function + * for the cipher operations. + * @{ + */ + +/** + * @brief A function that provides the cipher setup function for a + * secure element driver + * + * @param drv_context The driver context structure. + * @param op_context A structure that will contain the + * hardware-specific cipher context. + * @param key_slot The slot of the key to be used for the + * operation + * @param algorithm The algorithm to be used in the cipher + * operation + * @param direction Indicates whether the operation is an encrypt + * or decrypt + * + * @return @ref PSA_SUCCESS + * @ref PSA_ERROR_NOT_SUPPORTED + */ +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); + +/** + * @brief A function that sets the initialization vector (if necessary) for an secure element + * cipher operation + * + * @details Rationale: The @c psa_se_cipher_* operation in the PSA Cryptographic API has + * two IV functions: one to set the IV, and one to generate it internally. The + * generate function is not necessary for the drivers to implement as the PSA + * Crypto implementation can do the generation using its RNG features. + * + * @param op_context A structure that contains the previously set up + * hardware-specific cipher context + * @param p_iv A buffer containing the initialization vector + * @param iv_length The size (in bytes) of the @c p_iv buffer + * + * @return @ref PSA_SUCCESS + */ +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 op_context A hardware-specific structure for the + * previously started cipher operation + * @param p_input A buffer containing the data to be + * encrypted/decrypted + * @param input_size The size in bytes of the buffer pointed to + * by @c p_input + * @param p_output The caller-allocated buffer where the + * output will be placed + * @param output_size The allocated size in bytes of the + * @c p_output buffer + * @param p_output_length After completion, will contain the number + * of bytes placed in the @c p_output buffer + * + * @return @ref PSA_SUCCESS + */ +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, + size_t output_size, + size_t *p_output_length); + +/** + * @brief A function that completes a previously started secure element cipher + * operation + * + * @param op_context A hardware-specific structure for the + * previously started cipher operation + * @param p_output The caller-allocated buffer where the output + * will be placed + * @param output_size The allocated size in bytes of the @c p_output + * buffer + * @param p_output_length After completion, will contain the number of + * bytes placed in the @c p_output buffer + * + * @return @ref PSA_SUCCESS + */ +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); + +/** + * @brief A function that aborts a previously started secure element cipher + * operation + * + * @param op_context A hardware-specific structure for the + * previously started cipher operation + */ +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 + * + * @note This function should only be used with implementations that do not + * provide a needed higher-level operation. + * + * @param drv_context The driver context structure. + * @param key_slot The slot of the key to be used for the operation + * @param algorithm The algorithm to be used in the cipher operation + * @param direction Indicates whether the operation is an encrypt or + * decrypt + * @param p_input A buffer containing the data to be + * encrypted/decrypted + * @param input_size The size in bytes of the buffer pointed to by + * @c input + * @param p_output The caller-allocated buffer where the output + * will be placed + * @param output_size The allocated size in bytes of the @c output + * buffer + * + * @return @ref PSA_SUCCESS + * @ref PSA_ERROR_NOT_SUPPORTED + */ +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, + size_t input_size, + uint8_t *p_output, + size_t output_size); + +/** + * @brief A struct containing all of the function pointers needed to implement + * cipher operations using secure elements. + * + * @details PSA Crypto API implementations should populate instances of the table as + * appropriate upon startup or at build time. + * + * If one of the functions is not implemented (such as + * @c psa_drv_se_cipher_ecb_t ), it should be set to NULL. + */ +typedef struct { + /** The size in bytes of the hardware-specific secure element cipher context structure */ + size_t context_size; + /** Function that performs a cipher setup operation */ + psa_drv_se_cipher_setup_t p_setup; + /** Function that sets a cipher IV (if necessary) */ + psa_drv_se_cipher_set_iv_t p_set_iv; + /** Function that performs a cipher update operation */ + psa_drv_se_cipher_update_t p_update; + /** Function that completes a cipher operation */ + psa_drv_se_cipher_finish_t p_finish; + /** Function that aborts a cipher operation */ + psa_drv_se_cipher_abort_t p_abort; + /** + * Function that performs ECB mode for a cipher operation + * @warning ECB mode should not be used directly by clients of the PSA + * Crypto Client API) + */ + psa_drv_se_cipher_ecb_t p_ecb; +} psa_drv_se_cipher_t; + +/**@}*/ + +/** + * @defgroup se_asymmetric Secure Element Asymmetric Cryptography + * + * @details Since the amount of data that can (or should) be encrypted or signed using + * asymmetric keys is limited by the key size, asymmetric key operations using + * keys in a secure element must be done in single function calls. + * @{ + */ + +/** + * @brief A function that signs a hash or short message with a private key in + * a secure element + * + * @param drv_context The driver context structure. + * @param key_slot Key slot of an asymmetric key pair + * @param alg A signature algorithm that is compatible + * with the type of @c key + * @param p_hash The hash to sign + * @param hash_length Size of the @c p_hash buffer in bytes + * @param p_signature Buffer where the signature is to be written + * @param signature_size Size of the @c p_signature buffer in bytes + * @param p_signature_length On success, the number of bytes + * that make up the returned signature value + * + * @return @ref PSA_SUCCESS + */ +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, + uint8_t *p_signature, + size_t signature_size, + size_t *p_signature_length); + +/** + * @brief A function that verifies the signature a hash or short message using + * an asymmetric public key in a secure element + * + * @param drv_context The driver context structure. + * @param key_slot Key slot of a public key or an asymmetric key + * pair + * @param alg A signature algorithm that is compatible with + * the type of @c key + * @param p_hash The hash whose signature is to be verified + * @param hash_length Size of the @c p_hash buffer in bytes + * @param p_signature Buffer containing the signature to verify + * @param signature_length Size of the @c p_signature buffer in bytes + * + * @return @ref PSA_SUCCESS The signature is valid. + */ +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, + const uint8_t *p_signature, + size_t signature_length); + +/** + * @brief A function that encrypts a short message with an asymmetric public + * key in a secure element + * + * @param drv_context The driver context structure. + * @param key_slot Key slot of a public key or an asymmetric key pair + * @param alg An asymmetric encryption algorithm that is compatible + * with the type of @c key + * @param p_input The message to encrypt + * @param input_length Size of the @c p_input buffer in bytes + * @param p_salt A salt or label, if supported by the + * encryption algorithm + * If the algorithm does not support a + * salt, pass @c NULL. + * If the algorithm supports an optional + * salt and you do not want to pass a salt, + * pass @c NULL. + * For @ref PSA_ALG_RSA_PKCS1V15_CRYPT, no salt is + * supported. + * @param salt_length Size of the @c p_salt buffer in bytes + * If @c p_salt is @c NULL, pass 0. + * @param p_output Buffer where the encrypted message is to + * be written + * @param output_size Size of the @c p_output buffer in bytes + * @param p_output_length On success, the number of bytes that make up + * the returned output + * + * @return @ref PSA_SUCCESS + */ +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, + const uint8_t *p_salt, + size_t salt_length, + uint8_t *p_output, + size_t output_size, + size_t *p_output_length); + +/** + * @brief A function that decrypts a short message with an asymmetric private + * key in a secure element. + * + * @param drv_context The driver context structure. + * @param key_slot Key slot of an asymmetric key pair + * @param alg An asymmetric encryption algorithm that is + * compatible with the type of @c key + * @param p_input The message to decrypt + * @param input_length Size of the @c p_input buffer in bytes + * @param p_salt A salt or label, if supported by the + * encryption algorithm + * If the algorithm does not support a + * salt, pass @c NULL. + * If the algorithm supports an optional + * salt and you do not want to pass a salt, + * pass @c NULL. + * For #PSA_ALG_RSA_PKCS1V15_CRYPT, no salt is + * supported. + * @param salt_length Size of the @c p_salt buffer in bytes + * If @c p_salt is @c NULL, pass 0. + * @param p_output Buffer where the decrypted message is to + * be written + * @param output_size Size of the @c p_output buffer in bytes + * @param p_output_length On success, the number of bytes + * that make up the returned output + * + * @return @ref PSA_SUCCESS + */ +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, + const uint8_t *p_salt, + size_t salt_length, + uint8_t *p_output, + size_t output_size, + size_t *p_output_length); + +/** + * @brief A struct containing all of the function pointers needed to implement + * asymmetric cryptographic operations using secure elements. + * + * @details PSA Crypto API implementations should populate instances of the table as + * appropriate upon startup or at build time. + * + * If one of the functions is not implemented, it should be set to @c NULL. + */ +typedef struct { + /** Function that performs an asymmetric sign operation */ + psa_drv_se_asymmetric_sign_t p_sign; + /** Function that performs an asymmetric verify operation */ + psa_drv_se_asymmetric_verify_t p_verify; + /** Function that performs an asymmetric encrypt operation */ + psa_drv_se_asymmetric_encrypt_t p_encrypt; + /** Function that performs an asymmetric decrypt operation */ + psa_drv_se_asymmetric_decrypt_t p_decrypt; +} psa_drv_se_asymmetric_t; + +/**@}*/ + +/** + * @defgroup se_aead Secure Element Authenticated Encryption with Additional Data + * + * @details Authenticated Encryption with Additional Data (AEAD) operations with secure + * elements must be done in one function call. While this creates a burden for + * implementers as there must be sufficient space in memory for the entire + * message, it prevents decrypted data from being made available before the + * authentication operation is complete and the data is known to be authentic. + * @{ + */ + +/** + * @brief A function that performs a secure element authenticated encryption operation + * + * @param drv_context The driver context structure. + * @param key_slot Slot containing the key to use. + * @param algorithm The AEAD algorithm to compute + * (@c PSA_ALG_XXX value such that + * @ref PSA_ALG_IS_AEAD(@p alg) is true) + * @param p_nonce Nonce or IV to use + * @param nonce_length Size of the @c p_nonce buffer in bytes + * @param p_additional_data Additional data that will be + * authenticated but not encrypted + * @param additional_data_length Size of @c p_additional_data in bytes + * @param p_plaintext Data that will be authenticated and + * encrypted + * @param plaintext_length Size of @c p_plaintext in bytes + * @param p_ciphertext Output buffer for the authenticated and + * encrypted data. The additional data is + * not part of this output. For algorithms + * where the encrypted data and the + * authentication tag are defined as + * separate outputs, the authentication + * tag is appended to the encrypted data. + * @param ciphertext_size Size of the @c p_ciphertext buffer in + * bytes + * @param p_ciphertext_length On success, the size of the output in + * the @c p_ciphertext buffer + * + * @return @ref PSA_SUCCESS Success. + */ +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, + const uint8_t *p_additional_data, + size_t additional_data_length, + const uint8_t *p_plaintext, + size_t plaintext_length, + uint8_t *p_ciphertext, + size_t ciphertext_size, + size_t *p_ciphertext_length); + +/** + * @brief A function that peforms a secure element authenticated decryption operation + * + * @param drv_context The driver context structure. + * @param key_slot Slot containing the key to use + * @param algorithm The AEAD algorithm to compute + * (@c PSA_ALG_XXX value such that + * @ref PSA_ALG_IS_AEAD(@p alg) is true) + * @param p_nonce Nonce or IV to use + * @param nonce_length Size of the @c p_nonce buffer in bytes + * @param p_additional_data Additional data that has been + * authenticated but not encrypted + * @param additional_data_length Size of @c p_additional_data in bytes + * @param p_ciphertext Data that has been authenticated and + * encrypted. + * For algorithms where the encrypted data + * and the authentication tag are defined + * as separate inputs, the buffer must + * contain the encrypted data followed by + * the authentication tag. + * @param ciphertext_length Size of @c p_ciphertext in bytes + * @param p_plaintext Output buffer for the decrypted data + * @param plaintext_size Size of the @c p_plaintext buffer in + * bytes + * @param p_plaintext_length On success, the size of the output in + * the @c p_plaintext buffer + * + * @return @ref PSA_SUCCESS Success. + */ +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, + const uint8_t *p_additional_data, + size_t additional_data_length, + const uint8_t *p_ciphertext, + size_t ciphertext_length, + uint8_t *p_plaintext, + size_t plaintext_size, + size_t *p_plaintext_length); + +/** + * @brief A struct containing all of the function pointers needed to implement + * secure element Authenticated Encryption with Additional Data operations + * + * @details PSA Crypto API implementations should populate instances of the table as + * appropriate upon startup. + * + * If one of the functions is not implemented, it should be set to NULL. + */ +typedef struct { + /** Function that performs the AEAD encrypt operation */ + psa_drv_se_aead_encrypt_t p_encrypt; + /** Function that performs the AEAD decrypt operation */ + psa_drv_se_aead_decrypt_t p_decrypt; +} psa_drv_se_aead_t; +/**@}*/ + +/** + * @defgroup se_key_management Secure Element Key Management + * + * @details Currently, key management is limited to importing keys in the clear, + * destroying keys, and exporting keys in the clear. + * Whether a key may be exported is determined by the key policies in place + * on the key slot. + * + * @{ + */ + +/** + * An enumeration indicating how a key is created. + */ +typedef enum { + PSA_KEY_CREATION_IMPORT, /**< During @ref psa_import_key() */ + PSA_KEY_CREATION_GENERATE, /**< During @ref psa_generate_key() */ + PSA_KEY_CREATION_DERIVE, /**< During @ref psa_key_derivation_output_key() */ + PSA_KEY_CREATION_COPY, /**< During @ref psa_copy_key() */ +} psa_key_creation_method_t; + +/** + * @brief A function that allocates a slot for a key. + * + * @details To create a key in a specific slot in a secure element, the core first calls this + * function to determine a valid slot number, then calls a function to create the key + * material in that slot. In nominal conditions (that is, if no error occurs), the effect + * of a call to a key creation function in the PSA Cryptography API with a lifetime that + * places the key in a secure element is the following: + * -# The core calls @ref psa_drv_se_key_management_t::p_allocate + * (or in some implementations @ref + * psa_drv_se_key_management_t::p_validate_slot_number). The driver selects (or + * validates) a suitable slot number given the key attributes and the state of the + * secure element. + * -# The core calls a key creation function in the driver. + * + * The key creation functions in the PSA Cryptography API are: + * - @ref psa_import_key(), which causes a call to @c p_allocate with + * @c method = @ref PSA_KEY_CREATION_IMPORT then a call to + * @ref psa_drv_se_key_management_t::p_import. + * - @ref psa_generate_key(), which causes a call to @c p_allocate with + * @c method = @ref PSA_KEY_CREATION_GENERATE then a call to + * @ref psa_drv_se_key_management_t::p_import. + * - @ref psa_key_derivation_output_key(), which causes a call to @c p_allocate with + * @p method = @ref PSA_KEY_CREATION_DERIVE then a call to + * @ref psa_drv_se_key_derivation_t::p_derive. + * - @ref psa_copy_key(), which causes a call to @c p_allocate with + * @p method = @ref PSA_KEY_CREATION_COPY then a call to + * @ref psa_drv_se_key_management_t::p_export. + * + * In case of errors, other behaviors are possible. + * - If the PSA Cryptography subsystem dies after the first step, for example because the + * device has lost power abruptly, the second step may never happen, or may happen after + * a reset and re-initialization. Alternatively, after a reset and re-initialization, + * the core may call @ref psa_drv_se_key_management_t::p_destroy on the slot number that + * was allocated (or validated) instead of calling a key creation function. + * - If an error occurs, the core may call @ref psa_drv_se_key_management_t::p_destroy on + * the slot number that was allocated (or validated) instead of calling a key creation + * function. + * + * Errors and system resets also have an impact on the driver's persistent + * data. If a reset happens before the overall key creation process is + * completed (before or after the second step above), it is unspecified + * whether the persistent data after the reset is identical to what it + * was before or after the call to @c p_allocate (or @c p_validate_slot_number). + * + * @param drv_context The driver context structure. + * @param persistent_data A pointer to the persistent data + * that allows writing. + * @param attributes Attributes of the key. + * @param method The way in which the key is being created. + * @param key_slot Slot where the key will be stored. + * This must be a valid slot for a key of the + * chosen type. It must be unoccupied. + * + * @return @ref 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. + * @ref PSA_ERROR_NOT_SUPPORTED + * @ref 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_creation_method_t method, + psa_key_slot_number_t *key_slot); + +/** + * @brief A function that determines whether a slot number is valid for a key. + * + * @details To create a key in a specific slot in a secure element, the core + * first calls this function to validate the choice of slot number, + * then calls a function to create the key material in that slot. + * See the documentation of @ref psa_drv_se_allocate_key_t for more details. + * + * As of the PSA Cryptography API specification version 1.0, there is no way + * for applications to trigger a call to this function. However some + * implementations offer the capability to create or declare a key in + * a specific slot via implementation-specific means, generally for the + * sake of initial device provisioning or onboarding. Such a mechanism may + * be added to a future version of the PSA Cryptography API specification. + * + * This function may update the driver's persistent data through + * @c persistent_data. The core will save the updated persistent data at the + * end of the key creation process. See the description of + * @ref psa_drv_se_allocate_key_t for more information. + * + * @param drv_context The driver context structure. + * @param persistent_data A pointer to the persistent data + * that allows writing. + * @param attributes Attributes of the key. + * @param method The way in which the key is being created. + * @param key_slot Slot where the key is to be stored. + * + * @return @ref PSA_SUCCESS The given slot number is valid for a key with the given + * attributes. + * @ref PSA_ERROR_INVALID_ARGUMENT The given slot number is not valid for a key with the + * given attributes. This includes the case where the slot + * number is not valid at all. + * @ref PSA_ERROR_ALREADY_EXISTS There is already a key with the specified slot number. + * Drivers may choose to return this error from the key + * creation function instead. + */ +typedef psa_status_t (*psa_drv_se_validate_slot_number_t)( psa_drv_se_context_t *drv_context, + void *persistent_data, + const psa_key_attributes_t *attributes, + psa_key_creation_method_t method, + psa_key_slot_number_t key_slot); + +/** + * @brief A function that imports a key into a secure element in binary format + * + * @details This function can support any output from @ref psa_export_key(). Refer to the + * documentation of @ref psa_export_key() for the format for each key type. + * + * @param drv_context The driver context structure. + * @param key_slot Slot where the key will be stored. + * This must be a valid slot for a key of the + * chosen type. It must be unoccupied. + * @param attributes The key attributes, including the lifetime, + * the key type and the usage policy. + * Drivers should not access the key size stored + * in the attributes: it may not match the + * data passed in @c data. + * Drivers can call @ref psa_get_key_lifetime(), + * @ref psa_get_key_type(), @ref psa_get_key_usage_flags() + * and @ref psa_get_key_algorithm() to access this + * information. + * @param data Buffer containing the key data. + * @param data_length Size of the @c data buffer in bytes. + * @param bits On success, the key size in bits. The driver + * must determine this value after parsing the + * key according to the key type. + * This value is not used if the function fails. + * + * @return @ref PSA_SUCCESS Success. + */ +typedef psa_status_t (*psa_drv_se_import_key_t)(psa_drv_se_context_t *drv_context, + psa_key_slot_number_t key_slot, + const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length, + size_t *bits); + +/** + * @brief A function that destroys a secure element key and restore the slot to + * its default state + * + * @details This function destroys the content of the key from a secure element. + * Implementations shall make a best effort to ensure that any previous content + * of the slot is unrecoverable. + * + * This function returns the specified slot to its default state. + * + * @param drv_context The driver context structure. + * @param persistent_data A pointer to the persistent data + * that allows writing. + * @param key_slot The key slot to erase. + * + * @return @ref PSA_SUCCESS The slot's content, if any, has been erased. + */ +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 + * + * @details The output of this function can be passed to @ref psa_import_key() to + * create an equivalent object. + * + * If a key is created with @ref psa_import_key() and then exported with + * this function, it is not guaranteed that the resulting data is + * identical: the implementation may choose a different representation + * of the same key if the format permits it. + * + * This function should generate output in the same format that @ref psa_export_key() + * does. Refer to the documentation of @ref psa_export_key() for the format for each key + * type. + * + * @param drv_context The driver context structure. + * @param key_slot Slot whose content is to be exported. This must be an occupied key slot. + * @param p_data Buffer where the key data is to be written. + * @param data_size Size of the @c p_data buffer in bytes. + * @param p_data_length On success, the number of bytes that make up the key data. + * + * @return @ref PSA_SUCCESS + * @ref PSA_ERROR_DOES_NOT_EXIST + * @ref PSA_ERROR_NOT_PERMITTED + * @ref PSA_ERROR_NOT_SUPPORTED + * @ref PSA_ERROR_COMMUNICATION_FAILURE + * @ref PSA_ERROR_HARDWARE_FAILURE + * @ref PSA_ERROR_CORRUPTION_DETECTED + */ +typedef psa_status_t (*psa_drv_se_export_key_t)(psa_drv_se_context_t *drv_context, + psa_key_slot_number_t key_slot, + uint8_t *p_data, + size_t data_size, + size_t *p_data_length); + +/** + * @brief A function that generates a symmetric or asymmetric key on a secure element + * + * @details If the key type @c type recorded in @c attributes is asymmetric (@ref + * PSA_KEY_TYPE_IS_ASYMMETRIC(@c type) = 1), the driver may export the public key at the + * time of generation, in the format documented for @ref psa_export_public_key() by + * writing it to the @c pubkey buffer. + * This is optional, intended for secure elements that output the public key at generation + * time and that cannot export the public key later. Drivers that do not need this feature + * should leave @c *pubkey_length set to 0 and should implement the + * @c p_export_public function. Some implementations do not + * support this feature, in which case @c pubkey is @c NULL and @c pubkey_size is 0. + * + * @param drv_context The driver context structure. + * @param key_slot Slot where the key will be stored. This must be a valid slot for a key + * of the chosen type. It must be unoccupied. + * @param attributes The key attributes, including the lifetime, the key type and size, and + * the usage policy. Drivers can call @ref psa_get_key_lifetime(), + * @ref psa_get_key_type(), @ref psa_get_key_bits(), + * @ref psa_get_key_usage_flags() and @ref psa_get_key_algorithm() to + * access this information. + * @param pubkey A buffer where the driver can write the public key, when generating an + * asymmetric key pair. This is @c NULL when generating a symmetric key or + * if the core does not support exporting the public key at generation + * time. + * @param pubkey_size The size of the @c pubkey buffer in bytes. This is 0 when generating a + * symmetric key or if the core does not support exporting the public key + * at generation time. + * @param pubkey_length On entry, this is always 0. On success, the number of bytes written to + * @c pubkey. If this is 0 or unchanged on return, the core will not read + * the @c pubkey buffer, and will instead call the driver's + * @c p_export_public function to export the + * public key when needed. + */ +typedef psa_status_t (*psa_drv_se_generate_key_t)( psa_drv_se_context_t *drv_context, + psa_key_slot_number_t key_slot, + const psa_key_attributes_t *attributes, + uint8_t *pubkey, size_t pubkey_size, + size_t *pubkey_length); + +/** + * @brief A struct containing all of the function pointers needed to for secure element key + * management + * + * @details PSA Crypto API implementations should populate instances of the table as + * appropriate upon startup or at build time. + * + * If one of the functions is not implemented, it should be set to @c NULL. + */ +typedef struct { + /** Function that allocates a slot for a key. */ + psa_drv_se_allocate_key_t p_allocate; + /** Function that checks the validity of a slot for a key. */ + psa_drv_se_validate_slot_number_t p_validate_slot_number; + /** Function that performs a key import operation */ + psa_drv_se_import_key_t p_import; + /** Function that performs a generation */ + psa_drv_se_generate_key_t p_generate; + /** Function that performs a key destroy operation */ + 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; + +/**@}*/ + +/** + * @defgroup driver_derivation Secure Element Key Derivation and Agreement + * + * @details Key derivation is the process of generating new key material using an + * existing key and additional parameters, iterating through a basic + * cryptographic function, such as a hash. + * Key agreement is a part of cryptographic protocols that allows two parties + * to agree on the same key value, but starting from different original key + * material. + * The flows are similar, and the PSA Crypto Driver Model uses the same functions + * for both of the flows. + * + * There are two different final functions for the flows, + * @c psa_drv_se_key_derivation_derive and @c psa_drv_se_key_derivation_export. + * @c psa_drv_se_key_derivation_derive is used when the key material should be + * placed in a slot on the hardware and not exposed to the caller. + * @c psa_drv_se_key_derivation_export is used when the key material should be + * returned to the PSA Cryptographic API implementation. + * + * Different key derivation algorithms require a different number of inputs. + * Instead of having an API that takes as input variable length arrays, which + * can be problemmatic to manage on embedded platforms, the inputs are passed + * to the driver via a function, @c psa_drv_se_key_derivation_collateral, that + * is called multiple times with different @c collateral_ids. Thus, for a key + * derivation algorithm that required 3 parameter inputs, the flow would look + * something like: + * + * @code + * psa_drv_se_key_derivation_setup(kdf_algorithm, source_key, + * dest_key_size_bytes); + * psa_drv_se_key_derivation_collateral(kdf_algorithm_collateral_id_0, +* p_collateral_0, +* collateral_0_size); + * psa_drv_se_key_derivation_collateral(kdf_algorithm_collateral_id_1, + * p_collateral_1, + * collateral_1_size); + * psa_drv_se_key_derivation_collateral(kdf_algorithm_collateral_id_2, + * p_collateral_2, + * collateral_2_size); + * psa_drv_se_key_derivation_derive(); + * @endcode + * + * key agreement example: + * @code + * psa_drv_se_key_derivation_setup(alg, source_key. dest_key_size_bytes); + * psa_drv_se_key_derivation_collateral(DHE_PUBKEY, p_pubkey, pubkey_size); + * psa_drv_se_key_derivation_export(p_session_key, + * session_key_size, + * &session_key_length); + * @endcode + * @{ + */ + +/** + * @brief A function that Sets up a secure element key derivation operation by specifying the + * algorithm and the source key sot + * + * @param drv_context The driver context structure. + * @param op_context A hardware-specific structure containing any + * context information for the implementation + * @param kdf_alg The algorithm to be used for the key derivation + * @param source_key The key to be used as the source material for + * the key derivation + * + * @return @ref PSA_SUCCESS + */ +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); + +/** + * @brief A function that provides collateral (parameters) needed for a secure + * element key derivation or key agreement operation + * + * @details Since many key derivation algorithms require multiple parameters, it is + * expected that this function may be called multiple times for the same + * operation, each with a different algorithm-specific `collateral_id` + * + * @param op_context A hardware-specific structure containing any + * context information for the implementation + * @param collateral_id An ID for the collateral being provided + * @param p_collateral A buffer containing the collateral data + * @param collateral_size The size in bytes of the collateral + * + * @return @ref PSA_SUCCESS + */ +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); + +/** + * @brief A function that performs the final secure element key derivation + * step and place the generated key material in a slot + * + * @param op_context A hardware-specific structure containing any + * context information for the implementation + * @param dest_key The slot where the generated key material should be placed + * + * @return @ref PSA_SUCCESS + */ +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 + * agreement and place the generated key material in a buffer + * + * @param op_context A hardware-specific structure containing any + * context information for the implementation + * @param p_output Buffer in which to place the generated key material + * @param output_size The size in bytes of @c p_output + * @param p_output_length Upon success, contains the number of bytes of key + * material placed in @c p_output + * + * @return @ref PSA_SUCCESS + */ +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); + +/** + * @brief A struct containing all of the function pointers needed to for secure + * element key derivation and agreement + * + * @details PSA Crypto API implementations should populate instances of the table as + * appropriate upon startup. + * + * If one of the functions is not implemented, it should be set to @c NULL. + */ +typedef struct { + /** The driver-specific size of the key derivation context */ + size_t context_size; + /** Function that performs a key derivation setup */ + psa_drv_se_key_derivation_setup_t p_setup; + /** Function that sets key derivation collateral */ + psa_drv_se_key_derivation_collateral_t p_collateral; + /** Function that performs a final key derivation step */ + psa_drv_se_key_derivation_derive_t p_derive; + /** Function that perforsm a final key derivation or agreement and exports the key */ + psa_drv_se_key_derivation_export_t p_export; +} psa_drv_se_key_derivation_t; + +/**@}*/ + +/** + * @defgroup se_registration Secure Element Driver Registration + * @{ + */ + +/** + * @brief A structure containing pointers to all the entry points of a secure element driver. + * + * @details Future versions of this specification may add extra substructures at the end of this + * structure. + */ +typedef struct { + /** + * The version of the driver HAL that this driver implements. + * This is a protection against loading driver binaries built against + * a different version of this specification. + * Use @ref PSA_DRV_SE_HAL_VERSION. + */ + uint32_t hal_version; + + /** + * 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 @ref 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 @ref PSA_SUCCESS. + */ + psa_drv_se_init_t p_init; + + const psa_drv_se_key_management_t *key_management; /**< Key management methods */ + const psa_drv_se_mac_t *mac; /**< MAC operation methods */ + const psa_drv_se_cipher_t *cipher; /**< Cipher operation methods */ + const psa_drv_se_aead_t *aead; /**< AEAD operation methods */ + const psa_drv_se_asymmetric_t *asymmetric; /**< Asymmetric operation methods */ + const psa_drv_se_key_derivation_t *derivation; /**< Key derivation methods */ +} psa_drv_se_t; +/**@}*/ + +/** + * The current version of the secure element driver HAL. + */ +#define PSA_DRV_SE_HAL_VERSION 0x00000005 + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTO_SE_DRIVER_H */ +/** @} */ diff --git a/sys/psa_crypto/include/psa_crypto_se_management.h b/sys/psa_crypto/include/psa_crypto_se_management.h new file mode 100644 index 0000000000..dc342a28a7 --- /dev/null +++ b/sys/psa_crypto/include/psa_crypto_se_management.h @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @defgroup psa_crypto_se_mgmt PSA Crypto SE Management + * @{ + * + * @file psa_crypto_se_management.h + * @brief PSA Secure Element management function declarations + * + * @author Lena Boeckmann + * + */ + +#ifndef PSA_CRYPTO_SE_MANAGEMENT_H +#define PSA_CRYPTO_SE_MANAGEMENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "psa/crypto.h" +#include "psa_crypto_se_driver.h" + +/** + * @brief Maximum number of available secure elements. + */ +#ifndef CONFIG_PSA_MAX_SE_COUNT +#define CONFIG_PSA_MAX_SE_COUNT (1) +#endif /* CONFIG_PSA_MAX_SE_COUNT */ + +/** + * @brief Maximum supported number of secure elements + */ +#define PSA_MAX_SE_COUNT (CONFIG_PSA_MAX_SE_COUNT) + +/** + * @brief Internal secure element driver context. + * + * @details This is the same structure as @ref psa_drv_se_context_t, with the difference that it is + * also writeable for the implementation. + * + * This structure is not to be used by applications, only by the PSA Crypto implementation. + */ +typedef struct { + void * persistent_data; /**< Driver specific persistent data */ + size_t persistent_data_size; /**< Size of persistent data in bytes */ + uintptr_t transient_data; /**< Driver specific transient data */ +} psa_drv_se_internal_context_t; + +/** + * @brief Structure containing secure element driver data and contexts. + */ +struct psa_se_drv_data_s { + psa_key_location_t location; /**< Location value assigned to driver */ + const psa_drv_se_t *methods; /**< Methods implemented by driver */ + union { + psa_drv_se_internal_context_t internal; /**< Internally writable SE driver context */ + psa_drv_se_context_t context; /**< SE driver context, read only */ + } ctx; /**< SE driver context */ +}; + +/** + * @brief Encodes the secure element driver data + */ +typedef struct psa_se_drv_data_s psa_se_drv_data_t; + +/** + * @brief Register a secure element driver with the SE management. + * + * @details This function is called by the @c auto_init module during boot. + * + * @param location Location the driver should be registered with, + * of type @ref psa_key_location_t + * @param methods Structure of available driver entry points of the driver + * @param psa_se_configuration Pointer to a secure element configuration structure + * @param drv_transient_data Transient driver data to be used by the driver + * + * @return @ref PSA_SUCCESS + * @return @ref PSA_ERROR_INVALID_ARGUMENT The location value is invalid + * @return @ref PSA_ERROR_NOT_SUPPORTED + * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY + * @return @ref PSA_ERROR_ALREADY_EXISTS * + */ +psa_status_t psa_register_secure_element(psa_key_location_t location, + const psa_drv_se_t *methods, + void *psa_se_configuration, + const void *drv_transient_data); + +/** + * @brief Get the driver data of a specified driver + * + * @param lifetime Lifetime value of type @ref psa_key_lifetime_t of the key to be used + * + * @return @ref psa_se_drv_data_t* Pointer to the driver data + * @return @c NULL if no driver exists with this location + */ +psa_se_drv_data_t *psa_get_se_driver_data(psa_key_lifetime_t lifetime); + +/** + * @brief Get the driver entry points and context of a specified driver + * + * @param lifetime Lifetime value of type @ref psa_key_lifetime_t of the key to be used + * @param p_methods Pointer that will reference the driver methods + * @param p_drv_context Pointer that will reference the driver context + * + * @return 1 if a driver was found + * @return 0 if no driver exists with this location + */ +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); + +/** + * @brief Get the driver entry points of a specified driver + * + * @param driver Driver data of type @ref psa_se_drv_data_t containing the entry points + * + * @return const psa_drv_se_t* + */ +const psa_drv_se_t *psa_get_se_driver_methods(const psa_se_drv_data_t *driver); + +/** + * @brief Get the driver context of a specified driver + * + * @param driver Driver data of type @ref psa_se_drv_data_t containing the context + * + * @return @ref psa_drv_se_context_t* + */ +psa_drv_se_context_t *psa_get_se_drv_context(psa_se_drv_data_t *driver); + +/** + * @brief Find an empty key slot on a secure element appropriate to the key attributes + * + * @param attributes @ref psa_key_attributes_t containing the attributes of the key to be created + * @param method The method used to create the key (see @ref psa_key_creation_method_t) + * @param driver Pointer to the driver for the SE the key should be created on + * @param slot_number Pointer that will contain the slot number of the free SE slot + * + * @return @ref PSA_SUCCESS + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + * @return @ref PSA_ERROR_NOT_SUPPORTED + */ +psa_status_t psa_find_free_se_slot( const psa_key_attributes_t *attributes, + psa_key_creation_method_t method, + psa_se_drv_data_t *driver, + psa_key_slot_number_t *slot_number); + +/** + * @brief Destroy the key on a secure element + * + * @note Some secure elements may not support this operation. + * + * @param driver Driver of the SE containing the key to be destroyed + * @param slot_number Slot number of the key that is to be destroyed + * + * @return @ref PSA_SUCCESS + * @return @ref PSA_ERROR_NOT_PERMITTED + */ +psa_status_t psa_destroy_se_key(psa_se_drv_data_t *driver, + psa_key_slot_number_t slot_number); + +/** + * @brief Load SE data from persistent memory + * + * @note This operation is not yet supported by this implementation + * + * @param driver Pointer to the driver data the loaded data should be stored in + * + * @return @ref PSA_ERROR_NOT_SUPPORTED + */ +psa_status_t psa_load_se_persistent_data(const psa_se_drv_data_t *driver); + +/** + * @brief Save SE data to persistent memory + * + * @note This operation is not yet supported by this implementation + * + * @param driver Pointer to the driver data containing the data to be saved + * + * @return @ref PSA_ERROR_NOT_SUPPORTED + */ +psa_status_t psa_save_se_persistent_data(const psa_se_drv_data_t *driver); + +/** + * @brief Destroy SE data in persistent memory + * + * @note This operation is not yet supported by this implementation + * + * @param location Location of the data that should be destroyed + * + * @return @ref PSA_ERROR_NOT_SUPPORTED + */ +psa_status_t psa_destroy_se_persistent_data(psa_key_location_t location); + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTO_SE_MANAGEMENT_H */ +/**@}*/ diff --git a/sys/psa_crypto/include/psa_crypto_slot_management.h b/sys/psa_crypto/include/psa_crypto_slot_management.h new file mode 100644 index 0000000000..27febefcfb --- /dev/null +++ b/sys/psa_crypto/include/psa_crypto_slot_management.h @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @defgroup sys_psa_crypto_slot_mgmt PSA Crypto Key Slot Management + * @{ + * + * @file psa_crypto_slot_management.h + * @brief PSA key slot management function declarations + * + * @author Lena Boeckmann + * + */ + +#ifndef PSA_CRYPTO_SLOT_MANAGEMENT_H +#define PSA_CRYPTO_SLOT_MANAGEMENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "clist.h" +#include "psa/crypto.h" +#include "psa_crypto_se_management.h" + +/** + * @brief Number of allocated slots for keys in protected memory or secure elements. + */ +#define PSA_PROTECTED_KEY_COUNT (CONFIG_PSA_PROTECTED_KEY_COUNT) + +/** + * @brief Number of allocated slots for asymmetric key pairs. + */ +#define PSA_ASYMMETRIC_KEYPAIR_COUNT (CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT) + +/** + * @brief Number of allocated slots for single keys in local memory. + */ +#define PSA_SINGLE_KEY_COUNT (CONFIG_PSA_SINGLE_KEY_COUNT) + +/** + * @brief Complete number of available key slots + */ +#define PSA_KEY_SLOT_COUNT (PSA_PROTECTED_KEY_COUNT + \ + PSA_ASYMMETRIC_KEYPAIR_COUNT + \ + PSA_SINGLE_KEY_COUNT) + +/** + * @brief Minimum key id for volatile keys. + * + * @details This is used to assign volatile identifiers to created keys. + */ +#define PSA_KEY_ID_VOLATILE_MIN (PSA_KEY_ID_VENDOR_MIN) + +/** + * @brief Maximum key id for volatile keys. + * + * @details This is the maximum volatile identifiers that can be assigned to created keys. + */ +#define PSA_KEY_ID_VOLATILE_MAX (PSA_KEY_ID_VENDOR_MAX) + +/** + * @brief Structure of a virtual key slot in local memory. + * + * @details A slot contains key attributes, a lock count and the @c key_data structure. + * @c key_data consists of the size of the stored key in bytes and a @c uint8_t data array + * large enough to store the largest key used in the current build. This type of key slot + * contains symmetric keys, asymmetric public keys or unstructured data. + */ +typedef struct { + clist_node_t node; /**< List node to link slot in global list */ + size_t lock_count; /**< Number of entities accessing the slot */ + psa_key_attributes_t attr; /**< Attributes associated with the stored key */ + /** Structure containing key data */ + struct key_data { + uint8_t data[PSA_MAX_KEY_DATA_SIZE]; /**< Key data buffer */ + size_t data_len; /**< Size of actual key data in bytes */ + } key; /**< Key data structure */ +} psa_key_slot_t; + +/** + * @brief Initializes the allocated key slots and prepares the internal key slot lists. + */ +void psa_init_key_slots(void); + +/** + * @brief Check whether a key identifier is a volatile key identifier. + * + * @param key_id Key identifier to test. + * + * @return 1 The key identifier is a volatile key identifier. + * @return 0 The key identifier is not a volatile key identifier. + */ +static inline int psa_key_id_is_volatile(psa_key_id_t key_id) +{ + return ((key_id >= PSA_KEY_ID_VOLATILE_MIN) && + (key_id <= PSA_KEY_ID_VOLATILE_MAX)); +} + +/** + * @brief Check whether a key slot is locked + * + * @param slot Pointer to the slot to be checked + * + * @return 1 if slot is locked, otherwise 0 + */ +static inline int psa_is_key_slot_locked(psa_key_slot_t *slot) +{ + return (slot->lock_count > 0); +} + +/** + * @brief Get slot number in protected memory + * + * @param slot Pointer to the slot containing the protected slot number + * @return @ref psa_key_slot_number_t Key slot number stored in the input slot + */ +psa_key_slot_number_t * psa_key_slot_get_slot_number(const psa_key_slot_t *slot); + +/** + * @brief Check whether a key is stored on an external device + * + * @param lifetime Lifetime value of the key that's supposed to be checked + * + * @return int + * @return 1 if key is stored on external device, otherwise 0 + */ +static inline int psa_key_lifetime_is_external(psa_key_lifetime_t lifetime) +{ + return (PSA_KEY_LIFETIME_GET_LOCATION(lifetime) != PSA_KEY_LOCATION_LOCAL_STORAGE); +} + +/** + * @brief Wipe volatile key slot and its contents. Wiped key slots can be reused. + * + * @param slot Pointer to the key slot to be wiped + * + * @return @ref PSA_SUCCESS + * @return @ref PSA_ERROR_DOES_NOT_EXIST + */ +psa_status_t psa_wipe_key_slot(psa_key_slot_t *slot); + +/** + * @brief Wipe all existing volatile key slots. + */ +void psa_wipe_all_key_slots(void); + +/** + * @brief Find a key slot in local memory and lock it. + * + * @param id ID of the key to be used + * @param slot Pointer to the slot the key is stored in + * + * @return @ref PSA_SUCCESS + * @return @ref PSA_ERROR_DOES_NOT_EXIST + * @return @ref PSA_ERROR_NOT_SUPPORTED + */ +psa_status_t psa_get_and_lock_key_slot(psa_key_id_t id, psa_key_slot_t **slot); + +/** + * @brief Find a currently empty key slot that is appropriate for the key. + * + * @param id Key ID of the newly generated or imported key + * @param attr Attributes of the key that is supposed to be stored in the slot + * @param p_slot Pointer to the empty slot in memory + * + * @return @ref PSA_SUCCESS + * @return @ref PSA_ERROR_INSUFFICIENT_STORAGE + */ +psa_status_t psa_allocate_empty_key_slot( psa_key_id_t *id, + const psa_key_attributes_t *attr, + psa_key_slot_t **p_slot); + +/** + * @brief Increase lock count + * + * @param slot Slot to be locked + * + * @return @ref PSA_SUCCESS + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + */ +psa_status_t psa_lock_key_slot(psa_key_slot_t *slot); + +/** + * @brief Decrease lock count + * + * @param slot Slot to be unlocked + * + * @return @ref PSA_SUCCESS + * @return @ref PSA_ERROR_CORRUPTION_DETECTED + */ +psa_status_t psa_unlock_key_slot(psa_key_slot_t *slot); + +/** + * @brief Check if key location exists + * + * @param lifetime Lifetime value of the key to be validated + * @param driver Pointer to driver assigned to the existing key location, if it exists + * + * @return @ref PSA_SUCCESS + * @return @ref PSA_ERROR_INVALID_ARGUMENT + */ +psa_status_t psa_validate_key_location( psa_key_lifetime_t lifetime, + psa_se_drv_data_t **driver); + +/** + * @brief Validate key persistence. Currently only volatile keys are supported. + * + * @param lifetime Lifetime of key to be validated + * + * @return @ref PSA_SUCCESS + * @return @ref PSA_ERROR_NOT_SUPPORTED + */ +psa_status_t psa_validate_key_persistence(psa_key_lifetime_t lifetime); + +/** + * @brief Check if provided key ID is either a valid user ID or vendor ID + * + * @param id ID of key to be validated + * @param vendor If ID is supposed to be user or vendor ID + * + * @return 1 if valid + * @return 0 if invalid + */ +int psa_is_valid_key_id(psa_key_id_t id, int vendor); + +/** + * @brief Get key data and key size from key slot + * + * @param slot Slot the desired key is stored in + * @param key_data Pointer to key data + * @param key_bytes Pointer to key data size in bytes + * + * @return Size of @p key_data in bytes. + */ +size_t psa_get_key_data_from_key_slot(const psa_key_slot_t *slot, + uint8_t **key_data, + size_t **key_bytes); + +/** + * @brief Get public key data and size from key slot + * + * @param slot Slot the desired key is stored in + * @param pubkey_data Pointer to key data + * @param pubkey_data_len Pointer to key data size in bytes + */ +void psa_get_public_key_data_from_key_slot( const psa_key_slot_t *slot, + uint8_t **pubkey_data, + size_t **pubkey_data_len); + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTO_SLOT_MANAGEMENT_H */ +/**@}*/ diff --git a/sys/psa_crypto/include/psa_ecc.h b/sys/psa_crypto/include/psa_ecc.h new file mode 100644 index 0000000000..d995b821cb --- /dev/null +++ b/sys/psa_crypto/include/psa_ecc.h @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @defgroup sys_psa_crypto_ecc PSA Wrapper Functions: ECC + * @{ + * + * @file psa_ecc.h + * @brief Function declarations for low level wrapper functions for ECC operations. + * + * @author Lena Boeckmann + * + */ + +#ifndef PSA_ECC_H +#define PSA_ECC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "psa/crypto.h" +#include "kernel_defines.h" + +/** + * @brief Low level wrapper function to call a driver for an ECC key generation + * with a SECP 192 R1 key. + * See @ref psa_generate_key() + * + * @param attributes + * @param priv_key_buffer + * @param pub_key_buffer + * @param priv_key_buffer_length + * @param pub_key_buffer_length + * @return @ref psa_status_t + */ +psa_status_t psa_generate_ecc_p192r1_key_pair( const psa_key_attributes_t *attributes, + uint8_t *priv_key_buffer, uint8_t *pub_key_buffer, + size_t *priv_key_buffer_length, + size_t *pub_key_buffer_length); + +/** + * @brief Low level wrapper function to call a driver for an ECC public key export + * of a SECP 192 R1 key. + * See @ref psa_export_public_key() + * + * @param attributes + * @param key_buffer + * @param key_buffer_size + * @param data + * @param data_size + * @param data_length + * @return psa_status_t + */ +psa_status_t psa_ecc_p192r1_export_public_key( const psa_key_attributes_t *attributes, + uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *data, + size_t data_size, + size_t *data_length); + +/** + * @brief Low level wrapper function to call a driver for an ECC hash signature + * with a SECP 192 R1 key. + * See @ref psa_sign_hash() + * + * @param attributes + * @param alg + * @param key_buffer + * @param key_buffer_size + * @param hash + * @param hash_length + * @param signature + * @param signature_size + * @param signature_length + * @return psa_status_t + */ +psa_status_t psa_ecc_p192r1_sign_hash( const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const uint8_t *key_buffer, size_t key_buffer_size, + const uint8_t *hash, size_t hash_length, + uint8_t *signature, size_t signature_size, + size_t *signature_length); + +/** + * @brief Low level wrapper function to call a driver for an ECC hash verification + * with a SECP 192 R1 key. + * See @ref psa_verify_hash() + * + * @param attributes + * @param alg + * @param key_buffer + * @param key_buffer_size + * @param hash + * @param hash_length + * @param signature + * @param signature_length + * @return psa_status_t + */ +psa_status_t psa_ecc_p192r1_verify_hash(const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const uint8_t *key_buffer, size_t key_buffer_size, + const uint8_t *hash, size_t hash_length, + const uint8_t *signature, size_t signature_length); + +/** + * @brief Low level wrapper function to call a driver for an ECC key generation + * with a SECP 192 R1 key. + * See @ref psa_generate_key() + * + * @param attributes + * @param priv_key_buffer + * @param pub_key_buffer + * @param priv_key_buffer_length + * @param pub_key_buffer_length + * @return @ref psa_status_t + */ +psa_status_t psa_generate_ecc_p256r1_key_pair( const psa_key_attributes_t *attributes, + uint8_t *priv_key_buffer, uint8_t *pub_key_buffer, + size_t *priv_key_buffer_length, + size_t *pub_key_buffer_length); + +/** + * @brief Low level wrapper function to call a driver for an ECC public key export + * of a SECP 256 R1 key. + * See @ref psa_export_public_key() + * + * @param attributes + * @param key_buffer + * @param key_buffer_size + * @param data + * @param data_size + * @param data_length + * @return psa_status_t + */ +psa_status_t psa_ecc_p256r1_export_public_key( const psa_key_attributes_t *attributes, + uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *data, + size_t data_size, + size_t *data_length); + +/** + * @brief Low level wrapper function to call a driver for an ECC hash signature + * with a SECP 256 R1 key. + * See @ref psa_sign_hash() + * + * @param attributes + * @param alg + * @param key_buffer + * @param key_buffer_size + * @param hash + * @param hash_length + * @param signature + * @param signature_size + * @param signature_length + * @return psa_status_t + */ +psa_status_t psa_ecc_p256r1_sign_hash( const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const uint8_t *key_buffer, size_t key_buffer_size, + const uint8_t *hash, size_t hash_length, + uint8_t *signature, size_t signature_size, + size_t *signature_length); + +/** + * @brief Low level wrapper function to call a driver for an ECC hash verification + * with a SECP 256 R1 key. + * See @ref psa_verify_hash() + * + * @param attributes + * @param alg + * @param key_buffer + * @param key_buffer_size + * @param hash + * @param hash_length + * @param signature + * @param signature_length + * @return psa_status_t + */ +psa_status_t psa_ecc_p256r1_verify_hash(const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const uint8_t *key_buffer, size_t key_buffer_size, + const uint8_t *hash, size_t hash_length, + const uint8_t *signature, size_t signature_length); + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_ECC_H */ +/**@}*/ diff --git a/sys/psa_crypto/include/psa_hashes.h b/sys/psa_crypto/include/psa_hashes.h new file mode 100644 index 0000000000..98a7f23867 --- /dev/null +++ b/sys/psa_crypto/include/psa_hashes.h @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @defgroup sys_psa_crypto_hashes PSA Wrapper Functions: Hashes + * @{ + * + * @file psa_hashes.h + * @brief Function declarations for low level wrapper functions for hash operations. + * + * @author Lena Boeckmann + * + */ + +#ifndef PSA_HASHES_H +#define PSA_HASHES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "kernel_defines.h" +#include "psa/crypto.h" +#include "psa/crypto_contexts.h" + +#if IS_USED(MODULE_PSA_HASH_MD5) || defined(DOXYGEN) +/** + * @brief Low level wrapper function to call a driver for an MD5 hash setup + * See @ref psa_hash_setup() + * + * @param ctx + * @return @ref psa_status_t + */ +psa_status_t psa_hashes_md5_setup(psa_hashes_md5_ctx_t *ctx); + +/** + * @brief Low level wrapper function to call a driver for an MD5 hash update + * See @ref psa_hash_update() + * + * @param ctx + * @param input + * @param input_length + * @return psa_status_t + */ +psa_status_t psa_hashes_md5_update(psa_hashes_md5_ctx_t *ctx, + const uint8_t *input, + size_t input_length); + +/** + * @brief Low level wrapper function to call a driver for an MD5 hash finish + * See @ref psa_hash_finish() + * + * @param ctx + * @param hash + * @param hash_size + * @param hash_length + * @return psa_status_t + */ +psa_status_t psa_hashes_md5_finish(psa_hashes_md5_ctx_t *ctx, + uint8_t *hash, + size_t hash_size, + size_t *hash_length); +#endif /* CONFIG_HASHES_MD5 */ + +#if IS_USED(MODULE_PSA_HASH_SHA_1) || defined(DOXYGEN) +/** + * @brief Low level wrapper function to call a driver for an SHA1 hash setup + * See @ref psa_hash_setup() + * + * @param ctx + * @return psa_status_t + */ +psa_status_t psa_hashes_sha1_setup(psa_hashes_sha1_ctx_t *ctx); + +/** + * @brief Low level wrapper function to call a driver for an SHA1 hash update + * See @ref psa_hash_update() + * + * @param ctx + * @param input + * @param input_length + * @return psa_status_t + */ +psa_status_t psa_hashes_sha1_update(psa_hashes_sha1_ctx_t *ctx, + const uint8_t *input, + size_t input_length); + +/** + * @brief Low level wrapper function to call a driver for an SHA1 hash finish + * See @ref psa_hash_finish() + * + * @param ctx + * @param hash + * @param hash_size + * @param hash_length + * @return psa_status_t + */ +psa_status_t psa_hashes_sha1_finish(psa_hashes_sha1_ctx_t *ctx, + uint8_t *hash, + size_t hash_size, + size_t *hash_length); +#endif /* CONFIG_HASHES_SHA1 */ + +#if IS_USED(MODULE_PSA_HASH_SHA_224) || defined(DOXYGEN) +/** + * @brief Low level wrapper function to call a driver for an SHA224 hash setup + * See @ref psa_hash_setup() + * + * @param ctx + * @return psa_status_t + */ +psa_status_t psa_hashes_sha224_setup(psa_hashes_sha224_ctx_t *ctx); + +/** + * @brief Low level wrapper function to call a driver for an SHA224 hash update + * See @ref psa_hash_update() + * + * @param ctx + * @param input + * @param input_length + * @return psa_status_t + */ +psa_status_t psa_hashes_sha224_update(psa_hashes_sha224_ctx_t *ctx, + const uint8_t *input, + size_t input_length); + +/** + * @brief Low level wrapper function to call a driver for an SHA224 hash finish + * See @ref psa_hash_finish() + * + * @param ctx + * @param hash + * @param hash_size + * @param hash_length + * @return psa_status_t + */ +psa_status_t psa_hashes_sha224_finish(psa_hashes_sha224_ctx_t *ctx, + uint8_t *hash, + size_t hash_size, + size_t *hash_length); +#endif /* CONFIG_HASHES_SHA224 */ + +#if IS_USED(MODULE_PSA_HASH_SHA_256) || defined(DOXYGEN) +/** + * @brief Low level wrapper function to call a driver for an SHA256 hash setup + * See @ref psa_hash_setup() + * + * @param ctx + * @return psa_status_t + */ +psa_status_t psa_hashes_sha256_setup(psa_hashes_sha256_ctx_t *ctx); + +/** + * @brief Low level wrapper function to call a driver for an SHA256 hash update + * See @ref psa_hash_update() + * + * @param ctx + * @param input + * @param input_length + * @return psa_status_t + */ +psa_status_t psa_hashes_sha256_update(psa_hashes_sha256_ctx_t *ctx, + const uint8_t *input, + size_t input_length); + +/** + * @brief Low level wrapper function to call a driver for an SHA256 hash finish + * See @ref psa_hash_finish() + * + * @param ctx + * @param hash + * @param hash_size + * @param hash_length + * @return psa_status_t + */ +psa_status_t psa_hashes_sha256_finish(psa_hashes_sha256_ctx_t *ctx, + uint8_t *hash, + size_t hash_size, + size_t *hash_length); +#endif /* CONFIG_HASHES_SHA256 */ + +#if IS_USED(MODULE_PSA_HASH_SHA_512) || defined(DOXYGEN) +/** + * @brief Low level wrapper function to call a driver for an SHA512 hash setup + * See @ref psa_hash_setup() + * + * @param ctx + * @return psa_status_t + */ +psa_status_t psa_hashes_sha512_setup(psa_hashes_sha512_ctx_t *ctx); + +/** + * @brief Low level wrapper function to call a driver for an SHA512 hash update + * See @ref psa_hash_update() + * + * @param ctx + * @param input + * @param input_length + * @return psa_status_t + */ +psa_status_t psa_hashes_sha512_update(psa_hashes_sha512_ctx_t *ctx, + const uint8_t *input, + size_t input_length); + +/** + * @brief Low level wrapper function to call a driver for an SHA512 hash finish + * See @ref psa_hash_finish() + * + * @param ctx + * @param hash + * @param hash_size + * @param hash_length + * @return psa_status_t + */ +psa_status_t psa_hashes_sha512_finish(psa_hashes_sha512_ctx_t *ctx, + uint8_t *hash, + size_t hash_size, + size_t *hash_length); +#endif /* CONFIG_HASHES_SHA512 */ + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_HASHES_H */ +/**@}*/ diff --git a/sys/psa_crypto/include/psa_mac.h b/sys/psa_crypto/include/psa_mac.h new file mode 100644 index 0000000000..1e74dea94c --- /dev/null +++ b/sys/psa_crypto/include/psa_mac.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @defgroup sys_psa_crypto_mac PSA Wrapper Functions: MAC + * @{ + * + * @file psa_mac.h + * @brief Function declarations for low level wrapper functions for MAC operations. + * + * @author Lena Boeckmann + * + */ + +#ifndef PSA_MAC_H +#define PSA_MAC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "kernel_defines.h" +#include "psa/crypto.h" +#include "psa/crypto_contexts.h" + +/** + * @brief Low level wrapper function to call a driver for a HMAC SHA256 computation + * See psa_mac_compute() + * + * @param attributes + * @param key_buffer + * @param key_buffer_size + * @param input + * @param input_length + * @param mac + * @param mac_size + * @param mac_length + * @return psa_status_t + */ +psa_status_t psa_mac_compute_hmac_sha256( const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + const uint8_t *input, + size_t input_length, + uint8_t *mac, + size_t mac_size, + size_t *mac_length); + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_MAC_H */ +/**@}*/ diff --git a/sys/psa_crypto/psa_crypto.c b/sys/psa_crypto/psa_crypto.c new file mode 100644 index 0000000000..ef7158b7b3 --- /dev/null +++ b/sys/psa_crypto/psa_crypto.c @@ -0,0 +1,1931 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @{ + * + * @file + * @brief PSA Crypto API implementation + * + * @author Lena Boeckmann + * + * @} + */ + +#include +#include "psa/crypto.h" +#include "psa_crypto_se_driver.h" +#include "psa_crypto_se_management.h" +#include "psa_crypto_slot_management.h" +#include "psa_crypto_location_dispatch.h" +#include "psa_crypto_algorithm_dispatch.h" + +#include "random.h" +#include "kernel_defines.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +/** + * @brief Set by psa_crypto_init, which is required to be called once before + * PSA Crypto. Must be checked by other operations first. + */ +static uint8_t lib_initialized = 0; + +/** + * @brief Compares the content of two same-sized buffers while maintaining + * constant processing time + * + * @param a Buffer A to compare with B + * @param b Buffer B to compare with A + * @param n Size of the input buffers + * + * @return int + * 0 if buffer contents are the same + * 1 if buffer contents differ + */ +static inline int constant_time_memcmp(const uint8_t *a, const uint8_t *b, size_t n) +{ + uint8_t diff = 0; + + for (size_t i = 0; i < n; i++) { + diff |= a[i] ^ b[i]; + } + + return diff; +} + +const char *psa_status_to_humanly_readable(psa_status_t status) +{ + switch (status) { + case PSA_ERROR_GENERIC_ERROR: + return "PSA_ERROR_GENERIC_ERROR"; + case PSA_ERROR_NOT_SUPPORTED: + return "PSA_ERROR_NOT_SUPPORTED"; + case PSA_ERROR_NOT_PERMITTED: + return "PSA_ERROR_NOT_PERMITTED"; + case PSA_ERROR_BUFFER_TOO_SMALL: + return "PSA_ERROR_BUFFER_TOO_SMALL"; + case PSA_ERROR_ALREADY_EXISTS: + return "PSA_ERROR_ALREADY_EXISTS"; + case PSA_ERROR_DOES_NOT_EXIST: + return "PSA_ERROR_DOES_NOT_EXIST"; + case PSA_ERROR_BAD_STATE: + return "PSA_ERROR_BAD_STATE"; + case PSA_ERROR_INVALID_ARGUMENT: + return "PSA_ERROR_INVALID_ARGUMENT"; + case PSA_ERROR_INSUFFICIENT_MEMORY: + return "PSA_ERROR_INSUFFICIENT_MEMORY"; + case PSA_ERROR_INSUFFICIENT_STORAGE: + return "PSA_ERROR_INSUFFICIENT_STORAGE"; + case PSA_ERROR_COMMUNICATION_FAILURE: + return "PSA_ERROR_COMMUNICATION_FAILURE"; + case PSA_ERROR_STORAGE_FAILURE: + return "PSA_ERROR_STORAGE_FAILURE"; + case PSA_ERROR_DATA_CORRUPT: + return "PSA_ERROR_DATA_CORRUPT"; + case PSA_ERROR_DATA_INVALID: + return "PSA_ERROR_DATA_INVALID"; + case PSA_ERROR_HARDWARE_FAILURE: + return "PSA_ERROR_HARDWARE_FAILURE"; + case PSA_ERROR_CORRUPTION_DETECTED: + return "PSA_ERROR_CORRUPTION_DETECTED"; + case PSA_ERROR_INSUFFICIENT_ENTROPY: + return "PSA_ERROR_INSUFFICIENT_ENTROPY"; + case PSA_ERROR_INVALID_SIGNATURE: + return "PSA_ERROR_INVALID_SIGNATURE"; + case PSA_ERROR_INVALID_PADDING: + return "PSA_ERROR_INVALID_PADDING"; + case PSA_ERROR_INSUFFICIENT_DATA: + return "PSA_ERROR_INSUFFICIENT_DATA"; + case PSA_ERROR_INVALID_HANDLE: + return "PSA_ERROR_INVALID_HANDLE"; + default: + return "Error value not recognized"; + } +} + +psa_status_t psa_crypto_init(void) +{ + lib_initialized = 1; + +#if (IS_USED(MODULE_PSA_KEY_SLOT_MGMT)) + psa_init_key_slots(); +#endif + + return PSA_SUCCESS; +} + +psa_status_t psa_aead_abort(psa_aead_operation_t *operation) +{ + (void)operation; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_aead_decrypt( psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *nonce, + size_t nonce_length, + const uint8_t *additional_data, + size_t additional_data_length, + const uint8_t *ciphertext, + size_t ciphertext_length, + uint8_t *plaintext, + size_t plaintext_size, + size_t *plaintext_length) +{ + (void)key; + (void)alg; + (void)nonce; + (void)nonce_length; + (void)additional_data; + (void)additional_data_length; + (void)ciphertext; + (void)ciphertext_length; + (void)plaintext; + (void)plaintext_size; + (void)plaintext_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_aead_decrypt_setup(psa_aead_operation_t *operation, + psa_key_id_t key, + psa_algorithm_t alg) +{ + (void)operation; + (void)key; + (void)alg; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_aead_encrypt( psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *nonce, + size_t nonce_length, + const uint8_t *additional_data, + size_t additional_data_length, + const uint8_t *plaintext, + size_t plaintext_length, + uint8_t *ciphertext, + size_t ciphertext_size, + size_t *ciphertext_length) +{ + (void)key; + (void)alg; + (void)nonce; + (void)nonce_length; + (void)additional_data; + (void)additional_data_length; + (void)plaintext; + (void)plaintext_length; + (void)ciphertext; + (void)ciphertext_size; + (void)ciphertext_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_aead_encrypt_setup(psa_aead_operation_t *operation, + psa_key_id_t key, + psa_algorithm_t alg) +{ + (void)operation; + (void)key; + (void)alg; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_aead_finish( psa_aead_operation_t *operation, + uint8_t *ciphertext, + size_t ciphertext_size, + size_t *ciphertext_length, + uint8_t *tag, + size_t tag_size, + size_t *tag_length) +{ + (void)operation; + (void)ciphertext; + (void)ciphertext_size; + (void)ciphertext_length; + (void)tag; + (void)tag_size; + (void)tag_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_aead_generate_nonce( psa_aead_operation_t *operation, + uint8_t *nonce, + size_t nonce_size, + size_t *nonce_length) +{ + (void)operation; + (void)nonce; + (void)nonce_size; + (void)nonce_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_aead_set_lengths( psa_aead_operation_t *operation, + size_t ad_length, + size_t plaintext_length) +{ + (void)operation; + (void)ad_length; + (void)plaintext_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_aead_set_nonce(psa_aead_operation_t *operation, + const uint8_t *nonce, + size_t nonce_length) +{ + (void)operation; + (void)nonce; + (void)nonce_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_aead_update( psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + (void)operation; + (void)input; + (void)input_length; + (void)output; + (void)output_size; + (void)output_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_aead_update_ad(psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length) +{ + (void)operation; + (void)input; + (void)input_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_aead_verify( psa_aead_operation_t *operation, + uint8_t *plaintext, + size_t plaintext_size, + size_t *plaintext_length, + const uint8_t *tag, + size_t tag_length) +{ + (void)operation; + (void)plaintext; + (void)plaintext_size; + (void)plaintext_length; + (void)tag; + (void)tag_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_asymmetric_decrypt(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *salt, + size_t salt_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + (void)key; + (void)alg; + (void)input; + (void)input_length; + (void)salt; + (void)salt_length; + (void)output; + (void)output_size; + (void)output_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_asymmetric_encrypt(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *salt, + size_t salt_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + (void)key; + (void)alg; + (void)input; + (void)input_length; + (void)salt; + (void)salt_length; + (void)output; + (void)output_size; + (void)output_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +/** + * @brief Checks whether a key's policy permits the usage of a given algorithm + * + * @param policy Policy of the given key + * @param type Type of the given key + * @param requested_alg Algorithm to be used + * + * @return @ref PSA_SUCCESS + * @ref PSA_ERROR_NOT_PERMITTED + * @ref PSA_ERROR_INVALID_ARGUMENT If @c requested_alg is not a valid algorithm + */ +static psa_status_t psa_key_policy_permits( const psa_key_policy_t *policy, + psa_key_type_t type, + psa_algorithm_t requested_alg) +{ + if (requested_alg == 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (policy->alg == requested_alg) { + return PSA_SUCCESS; + } + + (void)type; + return PSA_ERROR_NOT_PERMITTED; +} + +/** + * @brief Check whether the policy of the key associated with the given ID permits the requested + * usage and return the key slot. + * + * @param id ID of the key to be used + * @param p_slot Pointer to a @c psa_key_slot_t type to return the desired key slot. + * @c NULL if something went wrong. + * @param usage The requested usage of the key + * @param alg The requested algorithm that uses the key + * + * @return @ref PSA_SUCCESS + * @ref PSA_ERROR_NOT_PERMITTED + * @ref PSA_ERROR_DOES_NOT_EXIST + * @ref PSA_ERROR_INVALID_ARGUMENT + * @ref PSA_ERROR_NOT_SUPPORTED + * @ref PSA_ERROR_CORRUPTION_DETECTED + */ +static psa_status_t psa_get_and_lock_key_slot_with_policy( psa_key_id_t id, + psa_key_slot_t **p_slot, + psa_key_usage_t usage, + psa_algorithm_t alg) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + + status = psa_get_and_lock_key_slot(id, p_slot); + if (status != PSA_SUCCESS) { + return status; + } + slot = *p_slot; + + if (PSA_KEY_TYPE_IS_PUBLIC_KEY(slot->attr.type)) { + /* Export is always permitted for asymmetric public keys */ + usage &= ~PSA_KEY_USAGE_EXPORT; + } + + if ((slot->attr.policy.usage & usage) != usage) { + *p_slot = NULL; + psa_unlock_key_slot(slot); + return PSA_ERROR_NOT_PERMITTED; + } + + if (alg != 0) { + status = psa_key_policy_permits( &slot->attr.policy, slot->attr.type, alg); + if (status != PSA_SUCCESS) { + *p_slot = NULL; + psa_unlock_key_slot(slot); + return status; + } + } + return PSA_SUCCESS; +} + +psa_status_t psa_cipher_abort(psa_cipher_operation_t *operation) +{ + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + *operation = psa_cipher_operation_init(); + return PSA_SUCCESS; +} + +/** + * @brief Setup a cipher encrypt or decrypt operation. + * + * See @ref psa_cipher_encrypt_setup(...) + * See @ref psa_cipher_decrypt_setup(...) + * + * @param operation + * @param key + * @param alg + * @param direction Whether encrypt or decrypt, see @ref psa_encrypt_or_decrypt_t + * @return @ref psa_status_t + */ +static psa_status_t psa_cipher_setup( psa_cipher_operation_t *operation, + psa_key_id_t key, + psa_algorithm_t alg, + psa_encrypt_or_decrypt_t direction) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + psa_key_usage_t usage = (direction == PSA_CRYPTO_DRIVER_ENCRYPT ? + PSA_KEY_USAGE_ENCRYPT : + PSA_KEY_USAGE_DECRYPT); + + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!operation) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (!PSA_ALG_IS_CIPHER(alg)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + status = psa_get_and_lock_key_slot_with_policy(key, &slot, usage, alg); + if (status != PSA_SUCCESS) { + psa_cipher_abort(operation); + unlock_status = psa_unlock_key_slot(slot); + return status; + } + + operation->iv_set = 0; + if (alg == PSA_ALG_ECB_NO_PADDING) { + operation->iv_required = 0; + } + else { + operation->iv_required = 1; + } + operation->default_iv_length = PSA_CIPHER_IV_LENGTH(slot->attr.type, alg); + + psa_key_attributes_t attr = slot->attr; + + if (direction == PSA_CRYPTO_DRIVER_ENCRYPT) { + status = psa_location_dispatch_cipher_encrypt_setup(operation, &attr, slot, alg); + } + else if (direction == PSA_CRYPTO_DRIVER_DECRYPT) { + status = psa_location_dispatch_cipher_decrypt_setup(operation, &attr, slot, alg); + } + + if (status != PSA_SUCCESS) { + psa_cipher_abort(operation); + } + + unlock_status = psa_unlock_key_slot(slot); + return ((status == PSA_SUCCESS) ? unlock_status : status); +} + +/** + * @brief Cipher encrypt and decrypt function + * + * See @ref psa_cipher_encrypt(...) + * See @ref psa_cipher_decrypt(...) + * + * @param key + * @param alg + * @param input + * @param input_length + * @param output + * @param output_size + * @param output_length + * @param direction Whether to encrypt or decrypt, see @ref psa_encrypt_or_decrypt_t + * @return @ref psa_status_t + */ +static psa_status_t psa_cipher_encrypt_decrypt( psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length, + psa_encrypt_or_decrypt_t direction) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!input || !output || !output_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (!PSA_ALG_IS_CIPHER(alg)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + psa_key_usage_t usage = (direction == PSA_CRYPTO_DRIVER_ENCRYPT ? + PSA_KEY_USAGE_ENCRYPT : + PSA_KEY_USAGE_DECRYPT); + + status = psa_get_and_lock_key_slot_with_policy(key, &slot, usage, alg); + if (status != PSA_SUCCESS) { + unlock_status = psa_unlock_key_slot(slot); + if (unlock_status != PSA_SUCCESS) { + status = unlock_status; + } + return status; + } + + if (((alg == PSA_ALG_CBC_NO_PADDING) || (alg == PSA_ALG_ECB_NO_PADDING)) && + (input_length % PSA_BLOCK_CIPHER_BLOCK_LENGTH(slot->attr.type))) { + unlock_status = psa_unlock_key_slot(slot); + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (direction == PSA_CRYPTO_DRIVER_ENCRYPT) { + if (output_size < PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(slot->attr.type, alg, input_length)) { + unlock_status = psa_unlock_key_slot(slot); + return PSA_ERROR_BUFFER_TOO_SMALL; + } + status = psa_location_dispatch_cipher_encrypt(&slot->attr, alg, slot, input, input_length, + output, output_size, output_length); + } + else { + size_t iv_length = PSA_CIPHER_IV_LENGTH(slot->attr.type, alg); + if (output_size < (input_length - iv_length)) { + /* Input buffer contains iv + cipher, so output must be at least input_length - IV */ + unlock_status = psa_unlock_key_slot(slot); + return PSA_ERROR_BUFFER_TOO_SMALL; + } + status = psa_location_dispatch_cipher_decrypt(&slot->attr, alg, slot, input, input_length, + output, output_size, output_length); + } + + unlock_status = psa_unlock_key_slot(slot); + return ((status == PSA_SUCCESS) ? unlock_status : status); +} + +psa_status_t psa_cipher_decrypt(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + return psa_cipher_encrypt_decrypt(key, alg, input, input_length, output, output_size, + output_length, PSA_CRYPTO_DRIVER_DECRYPT); +} + +psa_status_t psa_cipher_decrypt_setup(psa_cipher_operation_t *operation, + psa_key_id_t key, + psa_algorithm_t alg) +{ + return psa_cipher_setup(operation, key, alg, PSA_CRYPTO_DRIVER_DECRYPT); +} + +psa_status_t psa_cipher_encrypt(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + return psa_cipher_encrypt_decrypt(key, alg, input, input_length, output, output_size, + output_length, PSA_CRYPTO_DRIVER_ENCRYPT); +} + +psa_status_t psa_cipher_encrypt_setup(psa_cipher_operation_t *operation, + psa_key_id_t key, + psa_algorithm_t alg) +{ + return psa_cipher_setup(operation, key, alg, PSA_CRYPTO_DRIVER_ENCRYPT); +} + +psa_status_t psa_cipher_finish(psa_cipher_operation_t *operation, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + (void)operation; + (void)output; + (void)output_size; + (void)output_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_cipher_generate_iv(psa_cipher_operation_t *operation, + uint8_t *iv, + size_t iv_size, + size_t *iv_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!operation || !iv || !iv_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + *iv_length = 0; + + if (!operation->iv_required || operation->iv_set) { + return PSA_ERROR_BAD_STATE; + } + + if (iv_size < operation->default_iv_length) { + psa_cipher_abort(operation); + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + status = psa_generate_random(iv, iv_size); + if (status != PSA_SUCCESS) { + return status; + } + + operation->iv_set = 1; + *iv_length = iv_size; + + return status; +} + +psa_status_t psa_cipher_set_iv(psa_cipher_operation_t *operation, + const uint8_t *iv, + size_t iv_length) +{ + (void)operation; + (void)iv; + (void)iv_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_cipher_update(psa_cipher_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + (void)operation; + (void)input; + (void)input_length; + (void)output; + (void)output_size; + (void)output_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_hash_setup(psa_hash_operation_t *operation, + psa_algorithm_t alg) +{ + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!operation) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (operation->alg != 0) { + return PSA_ERROR_BAD_STATE; + } + + if (!PSA_ALG_IS_HASH(alg)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + psa_status_t status = psa_algorithm_dispatch_hash_setup(operation, alg); + if (status == PSA_SUCCESS) { + operation->alg = alg; + } + + return status; +} + +psa_status_t psa_hash_update(psa_hash_operation_t *operation, + const uint8_t *input, + size_t input_length) +{ + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!operation || !input) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (operation->alg == 0) { + return PSA_ERROR_BAD_STATE; + } + + psa_status_t status = psa_algorithm_dispatch_hash_update(operation, input, input_length); + + if (status != PSA_SUCCESS) { + psa_hash_abort(operation); + } + return status; +} + +psa_status_t psa_hash_finish(psa_hash_operation_t *operation, + uint8_t *hash, + size_t hash_size, + size_t *hash_length) +{ + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!operation || !hash || !hash_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (operation->alg == 0) { + return PSA_ERROR_BAD_STATE; + } + + uint8_t actual_hash_length = PSA_HASH_LENGTH(operation->alg); + + if (hash_size < actual_hash_length) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + psa_status_t status = + psa_algorithm_dispatch_hash_finish(operation, hash, hash_size, hash_length); + if (status == PSA_SUCCESS) { + *hash_length = actual_hash_length; + } + + /* Make sure operation becomes inactive after successful execution */ + psa_hash_abort(operation); + return status; +} + +psa_status_t psa_hash_verify(psa_hash_operation_t *operation, + const uint8_t *hash, + size_t hash_length) +{ + int status = PSA_ERROR_CORRUPTION_DETECTED; + uint8_t digest[PSA_HASH_MAX_SIZE]; + size_t actual_hash_length = 0; + + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!operation || !hash) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + status = psa_hash_finish(operation, digest, PSA_HASH_MAX_SIZE, &actual_hash_length); + + if (status != PSA_SUCCESS) { + return status; + } + + if (actual_hash_length != hash_length) { + return PSA_ERROR_INVALID_SIGNATURE; + } + + if (constant_time_memcmp(hash, digest, hash_length) != 0) { + return PSA_ERROR_INVALID_SIGNATURE; + } + + return PSA_SUCCESS; +} + +psa_status_t psa_hash_suspend(psa_hash_operation_t *operation, + uint8_t *hash_state, + size_t hash_state_size, + size_t *hash_state_length) +{ + (void)operation; + (void)hash_state; + (void)hash_state_size; + (void)hash_state_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_hash_resume(psa_hash_operation_t *operation, + const uint8_t *hash_state, + size_t hash_state_length) +{ + (void)operation; + (void)hash_state; + (void)hash_state_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_hash_abort(psa_hash_operation_t *operation) +{ + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + *operation = psa_hash_operation_init(); + return PSA_SUCCESS; +} + +psa_status_t psa_hash_clone(const psa_hash_operation_t *source_operation, + psa_hash_operation_t *target_operation) +{ + (void)source_operation; + (void)target_operation; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_hash_compare(psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *hash, + size_t hash_length) +{ + psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!input || !hash) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + status = psa_hash_setup(&operation, alg); + if (status != PSA_SUCCESS) { + return status; + } + status = psa_hash_update(&operation, input, input_length); + if (status != PSA_SUCCESS) { + return status; + } + status = psa_hash_verify(&operation, hash, hash_length); + if (status != PSA_SUCCESS) { + return status; + } + + return PSA_SUCCESS; +} + +psa_status_t psa_hash_compute(psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *hash, + size_t hash_size, + size_t *hash_length) +{ + psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!input || !hash || !hash_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (hash_size < PSA_HASH_LENGTH(alg)) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + *hash_length = hash_size; + status = psa_hash_setup(&operation, alg); + if (status != PSA_SUCCESS) { + return status; + } + status = psa_hash_update(&operation, input, input_length); + if (status != PSA_SUCCESS) { + return status; + } + status = psa_hash_finish(&operation, hash, hash_size, hash_length); + if (status != PSA_SUCCESS) { + return status; + } + + return PSA_SUCCESS; +} + +/* Key Management */ +/** + * @brief Check whether the key policy is valid + * + * @param policy Policy of type @ref psa_key_policy_t of the key to be used + * + * @return @ref PSA_SUCCESS + * @ref PSA_ERROR_INVALID_ARGUMENT + */ +static psa_status_t psa_validate_key_policy(const psa_key_policy_t *policy) +{ + if ((policy->usage & ~(PSA_KEY_USAGE_EXPORT | + PSA_KEY_USAGE_COPY | + PSA_KEY_USAGE_ENCRYPT | + PSA_KEY_USAGE_DECRYPT | + PSA_KEY_USAGE_SIGN_MESSAGE | + PSA_KEY_USAGE_VERIFY_MESSAGE | + PSA_KEY_USAGE_SIGN_HASH | + PSA_KEY_USAGE_VERIFY_HASH | + PSA_KEY_USAGE_DERIVE)) != 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + return PSA_SUCCESS; +} + +/** + * @brief Check whether the size of a symmetric key is supported + * + * @param type Type of the used key as @ref psa_key_type_t + * @param bits Size of the key as @c size_t + * + * @return @ref PSA_SUCCESS + * @ref PSA_ERROR_INVALID_ARGUMENT + * @ref PSA_ERROR_NOT_SUPPORTED + */ +static psa_status_t psa_validate_unstructured_key_size(psa_key_type_t type, size_t bits) +{ + switch (type) { + case PSA_KEY_TYPE_AES: + if (bits != 128 && bits != 192 && bits != 256) { + return PSA_ERROR_INVALID_ARGUMENT; + } + break; + case PSA_KEY_TYPE_HMAC: + if (bits % 8 != 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + break; + default: + (void)bits; + return PSA_ERROR_NOT_SUPPORTED; + break; + } + return PSA_SUCCESS; +} + +/** + * @brief Check whether the key size is valid for key generation + * + * @param type Type of the used key as @ref psa_key_type_t + * @param bits Size of the key as @c size_t + * + * @return @ref PSA_SUCCESS + * @ref PSA_ERROR_INVALID_ARGUMENT + * @ref PSA_ERROR_NOT_SUPPORTED + */ +static psa_status_t psa_validate_key_for_key_generation(psa_key_type_t type, size_t bits) +{ + if (PSA_KEY_TYPE_IS_UNSTRUCTURED(type)) { + return psa_validate_unstructured_key_size(type, bits); + } +#if IS_USED(MODULE_PSA_ASYMMETRIC) || IS_USED(MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC) + else if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(type)) { + return PSA_ECC_KEY_SIZE_IS_VALID(bits) ? PSA_SUCCESS : PSA_ERROR_INVALID_ARGUMENT; + } +#endif + /* TODO: add validation for other key types */ + return PSA_ERROR_NOT_SUPPORTED; +} + +/** + * @brief Check validity of key attributes and get secure element driver in case the key is + * stored on a secure element + * + * @param attributes Key attributes that are to be checked + * @param p_drv Pointer which will contain the SE driver, if one exists + * + * @return @ref PSA_SUCCESS + * @ref PSA_ERROR_INVALID_ARGUMENT + * @ref PSA_ERROR_NOT_SUPPORTED + */ +static psa_status_t psa_validate_key_attributes(const psa_key_attributes_t *attributes, + psa_se_drv_data_t **p_drv) +{ + psa_status_t status = PSA_ERROR_INVALID_ARGUMENT; + psa_key_lifetime_t lifetime = psa_get_key_lifetime(attributes); + psa_key_id_t key = psa_get_key_id(attributes); + + status = psa_validate_key_location(lifetime, p_drv); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_validate_key_persistence(lifetime); + if (status != PSA_SUCCESS) { + return status; + } + + if (PSA_KEY_LIFETIME_IS_VOLATILE(lifetime)) { + if (key != 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + } + else { + if (!psa_is_valid_key_id(key, 0)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + } + + status = psa_validate_key_policy(&attributes->policy); + if (status != PSA_SUCCESS) { + return status; + } + return PSA_SUCCESS; +} + +/** + * @brief Set up a key creation process. + * + * Validate key attributes for key creation and find free slots and drivers if they exists. + * + * @param method Key creation method (see @ref psa_key_creation_method_t) + * @param attributes Key attributes of the key that should be created + * @param p_slot Pointer which will contain a key slot to store the key in + * @param p_drv Pointer to a SE driver if one exists for the given key location + * + * @return @ref psa_status_t + */ +static psa_status_t psa_start_key_creation(psa_key_creation_method_t method, + const psa_key_attributes_t *attributes, + psa_key_slot_t **p_slot, psa_se_drv_data_t **p_drv) +{ + psa_status_t status; + psa_key_id_t key_id; + psa_key_slot_t *slot; + + *p_drv = NULL; + + status = psa_validate_key_attributes(attributes, p_drv); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_allocate_empty_key_slot(&key_id, attributes, p_slot); + if (status != PSA_SUCCESS) { + return status; + } + slot = *p_slot; + slot->attr = *attributes; + + if (PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) { + slot->attr.id = key_id; + } + +#if IS_USED(MODULE_PSA_SECURE_ELEMENT) + /* Find a free slot on a secure element and store SE slot number in key_data */ + if (*p_drv != NULL) { + psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot); + status = psa_find_free_se_slot(attributes, method, *p_drv, slot_number); + if (status != PSA_SUCCESS) { + return status; + } + /* TODO: Start transaction for persistent key storage */ + } +#endif /* CONFIG_PSA_SECURE_ELEMENT */ + + (void)method; + return PSA_SUCCESS; +} + +/** + * @brief Finish up key creation process + * + * @param slot Pointer to slot that the key is stored in + * @param driver SE driver, in case the key creation took place on a secure element + * @param key Pointer which will contain the key ID assigned to the key + * + * @return @ref psa_status_t + */ +static psa_status_t psa_finish_key_creation(psa_key_slot_t *slot, psa_se_drv_data_t *driver, + psa_key_id_t *key) +{ + psa_status_t status = PSA_SUCCESS; + + *key = PSA_KEY_ID_NULL; + /* TODO: Finish persistent key storage */ + /* TODO: Finish SE key storage with transaction */ + + if (status == PSA_SUCCESS) { + *key = slot->attr.id; + status = psa_unlock_key_slot(slot); + } + else { + (void)slot; + } + + (void)driver; + return status; +} + +/** + * @brief Abort key creation and clean up in case of failure + * + * @param slot Slot that the key has been written to + * @param driver SE driver, in case the key creation took place on a secure element + */ +static void psa_fail_key_creation(psa_key_slot_t *slot, psa_se_drv_data_t *driver) +{ + (void)driver; + if (slot == NULL) { + return; + } + /* TODO: Destroy key in secure element (see mbedtls code) */ + /* TODO: Secure Element stop transaction */ + psa_wipe_key_slot(slot); +} + +psa_status_t psa_copy_key(psa_key_id_t source_key, + const psa_key_attributes_t *attributes, + psa_key_id_t *target_key) +{ + (void)source_key; + (void)attributes; + (void)target_key; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_destroy_key(psa_key_id_t key) +{ + psa_status_t status; + psa_key_slot_t *slot; + + status = psa_get_and_lock_key_slot(key, &slot); + if (status != PSA_SUCCESS) { + return status; + } + if (slot->lock_count > 1) { + return PSA_ERROR_CORRUPTION_DETECTED; + } + + return psa_wipe_key_slot(slot); +} + +psa_status_t psa_export_key(psa_key_id_t key, + uint8_t *data, + size_t data_size, + size_t *data_length) +{ + (void)key; + (void)data; + (void)data_size; + (void)data_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +/** + * @brief Export asymmetric public key that is stored in local memory + * + * See @ref psa_export_public_key + * + * @param key_buffer + * @param key_buffer_size + * @param data + * @param data_size + * @param data_length + * + * @return @ref PSA_SUCCESS + * @ref PSA_ERROR_INVALID_ARGUMENT + */ +static psa_status_t psa_builtin_export_public_key( const uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *data, + size_t data_size, + size_t *data_length) +{ + if (key_buffer_size == 0 || data_size == 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (data_size < key_buffer_size) { + DEBUG("PSA Crypto Builtin Export Key: Output buffer too small\n"); + return PSA_ERROR_BUFFER_TOO_SMALL; + } + /** Some implementations and drivers can generate a public key from existing private key + * material. This implementation does not support the recalculation of a public key, yet. + * It requires the key to already exist in local memory and just copies it into the data + * output. */ + memcpy(data, key_buffer, key_buffer_size); + *data_length = key_buffer_size; + + return PSA_SUCCESS; +} + +psa_status_t psa_export_public_key(psa_key_id_t key, + uint8_t *data, + size_t data_size, + size_t *data_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + uint8_t *pubkey_data = NULL; + size_t *pubkey_data_len = NULL; + + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!data || !data_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + *data_length = 0; + + status = psa_get_and_lock_key_slot_with_policy(key, &slot, 0, 0); + if (status != PSA_SUCCESS) { + unlock_status = psa_unlock_key_slot(slot); + if (unlock_status != PSA_SUCCESS) { + status = unlock_status; + } + return status; + } + + if ((data_size == 0) || + (data_size < PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(slot->attr.type, slot->attr.bits))) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + if (!PSA_KEY_TYPE_IS_ECC(slot->attr.type)) { + status = PSA_ERROR_INVALID_ARGUMENT; + unlock_status = psa_unlock_key_slot(slot); + return status; + } + psa_get_public_key_data_from_key_slot(slot, &pubkey_data, &pubkey_data_len); + + status = + psa_builtin_export_public_key(pubkey_data, *pubkey_data_len, data, data_size, data_length); + + unlock_status = psa_unlock_key_slot(slot); + return ((status == PSA_SUCCESS) ? unlock_status : status); +} + +psa_status_t psa_builtin_generate_key(const psa_key_attributes_t *attributes, uint8_t *key_buffer, + size_t key_buffer_size, size_t *key_buffer_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (!attributes || !key_buffer || !key_buffer_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + psa_key_type_t type = attributes->type; + + if (PSA_KEY_TYPE_IS_UNSTRUCTURED(type)) { + status = psa_generate_random(key_buffer, key_buffer_size); + if (status != PSA_SUCCESS) { + return status; + } + *key_buffer_length = key_buffer_size; + return PSA_SUCCESS; + } + (void)key_buffer; + (void)key_buffer_size; + (void)key_buffer_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_generate_key(const psa_key_attributes_t *attributes, + psa_key_id_t *key) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot = NULL; + psa_se_drv_data_t *driver = NULL; + + *key = PSA_KEY_ID_NULL; + + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!attributes || !key) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (psa_get_key_bits(attributes) == 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* Find empty slot */ + status = psa_start_key_creation(PSA_KEY_CREATION_GENERATE, attributes, &slot, &driver); + if (status != PSA_SUCCESS) { + psa_fail_key_creation(slot, driver); + return status; + } + + if (PSA_KEY_LIFETIME_GET_LOCATION(attributes->lifetime) == PSA_KEY_LOCATION_LOCAL_STORAGE) { + status = psa_validate_key_for_key_generation(attributes->type, attributes->bits); + if (status != PSA_SUCCESS) { + return status; + } + + slot->key.data_len = PSA_MAX_KEY_DATA_SIZE; + } + + status = psa_location_dispatch_generate_key(attributes, slot); + + if (status != PSA_SUCCESS) { + psa_fail_key_creation(slot, driver); + return status; + } + + status = psa_finish_key_creation(slot, driver, key); + + if (status != PSA_SUCCESS) { + psa_fail_key_creation(slot, driver); + } + + return status; +} + +psa_status_t psa_builtin_generate_random( uint8_t *output, + size_t output_size) +{ + if (!output) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* TODO: Should point to a CSPRNG API in the future */ + random_bytes(output, output_size); + return PSA_SUCCESS; +} + +psa_status_t psa_generate_random(uint8_t *output, + size_t output_size) +{ + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!output) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + return psa_location_dispatch_generate_random(output, output_size); +} + +psa_status_t psa_get_key_attributes(psa_key_id_t key, + psa_key_attributes_t *attributes) +{ + psa_status_t status; + psa_key_slot_t *slot = NULL; + + if (!attributes) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + psa_reset_key_attributes(attributes); + + status = psa_get_and_lock_key_slot(key, &slot); + if (status != PSA_SUCCESS) { + return status; + } + + *attributes = slot->attr; + + status = psa_unlock_key_slot(slot); + return status; +} + +psa_status_t psa_builtin_import_key(const psa_key_attributes_t *attributes, + const uint8_t *data, size_t data_length, + uint8_t *key_buffer, size_t key_buffer_size, + size_t *key_buffer_length, size_t *bits) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (!attributes || !data || !key_buffer || !key_buffer_length || !bits) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (data_length == 0) { + return PSA_ERROR_NOT_SUPPORTED; + } + + if (data_length > key_buffer_size) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + psa_key_type_t type = attributes->type; + + if (PSA_KEY_TYPE_IS_UNSTRUCTURED(type)) { + *bits = PSA_BYTES_TO_BITS(data_length); + + status = psa_validate_unstructured_key_size(type, *bits); + if (status != PSA_SUCCESS) { + return status; + } + + memcpy(key_buffer, data, data_length); + *key_buffer_length = data_length; + + return PSA_SUCCESS; + } + else if (PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(type)) { + if (data_length > PSA_EXPORT_PUBLIC_KEY_MAX_SIZE) { + return PSA_ERROR_NOT_SUPPORTED; + } + memcpy(key_buffer, data, data_length); + *key_buffer_length = data_length; + return PSA_SUCCESS; + } + return status; +} + +psa_status_t psa_import_key(const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length, + psa_key_id_t *key) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot = NULL; + psa_se_drv_data_t *driver = NULL; + size_t bits; + + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!attributes || !data) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (attributes->bits != 0 && attributes->bits > PSA_BYTES_TO_BITS(data_length)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + *key = PSA_KEY_ID_NULL; + + /* Find empty slot */ + status = psa_start_key_creation(PSA_KEY_CREATION_IMPORT, attributes, &slot, &driver); + if (status != PSA_SUCCESS) { + psa_fail_key_creation(slot, driver); + return status; + } + + bits = slot->attr.bits; + + status = psa_location_dispatch_import_key(attributes, data, data_length, slot, &bits); + + if (status != PSA_SUCCESS) { + psa_fail_key_creation(slot, driver); + return status; + } + + if (slot->attr.bits == 0) { + slot->attr.bits = (psa_key_bits_t)bits; + } + else if (bits != slot->attr.bits) { + psa_fail_key_creation(slot, driver); + return PSA_ERROR_INVALID_ARGUMENT; + } + + status = psa_finish_key_creation(slot, driver, key); + if (status != PSA_SUCCESS) { + psa_fail_key_creation(slot, driver); + } + + return status; +} + +psa_status_t psa_key_derivation_abort(psa_key_derivation_operation_t *operation) +{ + (void)operation; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_key_derivation_get_capacity(const psa_key_derivation_operation_t *operation, + size_t *capacity) +{ + (void)operation; + (void)capacity; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_key_derivation_input_bytes(psa_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + const uint8_t *data, + size_t data_length) +{ + (void)operation; + (void)step; + (void)data; + (void)data_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_key_derivation_input_key(psa_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + psa_key_id_t key) +{ + (void)operation; + (void)step; + (void)key; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_key_derivation_key_agreement(psa_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + psa_key_id_t private_key, + const uint8_t *peer_key, + size_t peer_key_length) +{ + (void)operation; + (void)step; + (void)private_key; + (void)peer_key; + (void)peer_key_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_key_derivation_output_bytes(psa_key_derivation_operation_t *operation, + uint8_t *output, + size_t output_length) +{ + (void)operation; + (void)output; + (void)output_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_key_derivation_output_key(const psa_key_attributes_t *attributes, + psa_key_derivation_operation_t *operation, + psa_key_id_t *key) +{ + (void)attributes; + (void)operation; + (void)key; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_key_derivation_set_capacity(psa_key_derivation_operation_t *operation, + size_t capacity) +{ + (void)operation; + (void)capacity; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_key_derivation_setup(psa_key_derivation_operation_t *operation, + psa_algorithm_t alg) +{ + (void)operation; + (void)alg; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_mac_abort(psa_mac_operation_t *operation) +{ + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + *operation = psa_mac_operation_init(); + + return PSA_ERROR_NOT_SUPPORTED; +} + +/** + * @brief Validate algorithm and key for a MAC operation + * + * @param attr Attributes of the key that is supposed to be used + * @param alg Algorithm for performing the MAC operation + * @param mac_size Size of the MAC that is to be generated + * + * @return @ref PSA_SUCCESS + * @ref PSA_ERROR_NOT_SUPPORTED + * @ref PSA_ERROR_INVALID_ARGUMENT + */ +static psa_status_t psa_mac_validate_alg_and_key_and_size(psa_key_attributes_t *attr, + psa_algorithm_t alg, + size_t mac_size) +{ + psa_key_type_t type = psa_get_key_type(attr); + psa_key_bits_t bits = psa_get_key_bits(attr); + + if (!PSA_ALG_IS_HMAC(alg) || (PSA_ALG_GET_HASH(alg) != PSA_ALG_SHA_256)) { + return PSA_ERROR_NOT_SUPPORTED; + } + + size_t operation_mac_size = PSA_MAC_LENGTH(type, bits, alg); + + if (operation_mac_size < 4) { + /** + * A very short MAC is too short for security since it can be + * brute-forced. Ancient protocols with 32-bit MACs do exist, + * so we make this our minimum, even though 32 bits is still + * too small for security. + */ + return PSA_ERROR_NOT_SUPPORTED; + } + + if (operation_mac_size > PSA_MAC_MAX_SIZE) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (mac_size < operation_mac_size) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + return PSA_SUCCESS; +} + +psa_status_t psa_mac_compute(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *mac, + size_t mac_size, + size_t *mac_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_attributes_t attr = psa_key_attributes_init(); + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!input || !mac || !mac_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + status = psa_get_key_attributes(key, &attr); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_mac_validate_alg_and_key_and_size(&attr, alg, mac_size); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_get_and_lock_key_slot_with_policy(key, &slot, attr.policy.usage, alg); + if (status != PSA_SUCCESS) { + unlock_status = psa_unlock_key_slot(slot); + if (unlock_status != PSA_SUCCESS) { + status = unlock_status; + } + return status; + } + + status = psa_location_dispatch_mac_compute(&slot->attr, alg, slot, input, input_length, mac, + mac_size, mac_length); + + unlock_status = psa_unlock_key_slot(slot); + return ((status == PSA_SUCCESS) ? unlock_status : status); + +} + +psa_status_t psa_mac_sign_finish(psa_mac_operation_t *operation, + uint8_t *mac, + size_t mac_size, + size_t *mac_length) +{ + (void)operation; + (void)mac; + (void)mac_size; + (void)mac_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_mac_sign_setup(psa_mac_operation_t *operation, + psa_key_id_t key, + psa_algorithm_t alg) +{ + (void)operation; + (void)key; + (void)alg; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_mac_update(psa_mac_operation_t *operation, + const uint8_t *input, + size_t input_length) +{ + (void)operation; + (void)input; + (void)input_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_mac_verify(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *mac, + size_t mac_length) +{ + (void)key; + (void)alg; + (void)input; + (void)input_length; + (void)mac; + (void)mac_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_mac_verify_finish(psa_mac_operation_t *operation, + const uint8_t *mac, + size_t mac_length) +{ + (void)operation; + (void)mac; + (void)mac_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_mac_verify_setup(psa_mac_operation_t *operation, + psa_key_id_t key, + psa_algorithm_t alg) +{ + (void)operation; + (void)key; + (void)alg; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_purge_key(psa_key_id_t key) +{ + (void)key; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_raw_key_agreement(psa_algorithm_t alg, + psa_key_id_t private_key, + const uint8_t *peer_key, + size_t peer_key_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + (void)alg; + (void)private_key; + (void)peer_key; + (void)peer_key_length; + (void)output; + (void)output_size; + (void)output_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_sign_hash(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *hash, + size_t hash_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!hash || !signature || !signature_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (!PSA_ALG_IS_ECDSA(alg)) { + return PSA_ERROR_NOT_SUPPORTED; + } + + if (hash_length != PSA_HASH_LENGTH(alg)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + status = psa_get_and_lock_key_slot_with_policy(key, &slot, PSA_KEY_USAGE_SIGN_HASH, alg); + if (status != PSA_SUCCESS) { + unlock_status = psa_unlock_key_slot(slot); + return status; + } + + if (signature_size < PSA_SIGN_OUTPUT_SIZE(slot->attr.type, slot->attr.bits, alg)) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + if (!PSA_KEY_TYPE_IS_KEY_PAIR(slot->attr.type)) { + unlock_status = psa_unlock_key_slot(slot); + return PSA_ERROR_INVALID_ARGUMENT; + } + + psa_key_attributes_t attributes = slot->attr; + + status = psa_location_dispatch_sign_hash(&attributes, alg, slot, hash, hash_length, signature, + signature_size, signature_length); + + unlock_status = psa_unlock_key_slot(slot); + return ((status == PSA_SUCCESS) ? unlock_status : status); +} + +psa_status_t psa_sign_message(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length) +{ + (void)key; + (void)alg; + (void)input; + (void)input_length; + (void)signature; + (void)signature_size; + (void)signature_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_verify_hash(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *hash, + size_t hash_length, + const uint8_t *signature, + size_t signature_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!hash || !signature) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (!PSA_ALG_IS_ECDSA(alg)) { + return PSA_ERROR_NOT_SUPPORTED; + } + + if (hash_length != PSA_HASH_LENGTH(alg)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + status = psa_get_and_lock_key_slot_with_policy(key, &slot, PSA_KEY_USAGE_VERIFY_HASH, alg); + if (status != PSA_SUCCESS) { + unlock_status = psa_unlock_key_slot(slot); + return status; + } + + /** + * An ECC public key has the size `curve_bytes * 2 + 1`. + * So to get the curve size to determine the required signature + * size, we need to revert that calculation. + */ + uint16_t curve_size = PSA_BYTES_TO_BITS(PSA_BITS_TO_BYTES(slot->attr.bits / 2) - 1); + + if (signature_length != PSA_ECDSA_SIGNATURE_SIZE(curve_size)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /** + * When key location is a secure element, this implementation only supports + * the use of public keys stored on the secure element, not key pairs in + * which the public key is stored locally. + */ + if ((PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime) != PSA_KEY_LOCATION_LOCAL_STORAGE) && + PSA_KEY_TYPE_IS_ECC_KEY_PAIR(slot->attr.type)) { + unlock_status = psa_unlock_key_slot(slot); + return PSA_ERROR_NOT_SUPPORTED; + } + + psa_key_attributes_t attributes = slot->attr; + + status = psa_location_dispatch_verify_hash(&attributes, alg, slot, hash, hash_length, signature, + signature_length); + + unlock_status = psa_unlock_key_slot(slot); + return ((status == PSA_SUCCESS) ? unlock_status : status); +} + +psa_status_t psa_verify_message(psa_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *signature, + size_t signature_length) +{ + (void)key; + (void)alg; + (void)input; + (void)input_length; + (void)signature; + (void)signature_length; + return PSA_ERROR_NOT_SUPPORTED; +} diff --git a/sys/psa_crypto/psa_crypto_algorithm_dispatch.c b/sys/psa_crypto/psa_crypto_algorithm_dispatch.c new file mode 100644 index 0000000000..caf5cda7d7 --- /dev/null +++ b/sys/psa_crypto/psa_crypto_algorithm_dispatch.c @@ -0,0 +1,425 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto sys_psa_crypto_alg_disp + * @{ + * + * @file + * @brief Dispatch calls from the PSA Crypto API to an available backend. + * + * @author Lena Boeckmann + * + * @} + */ + +#include +#include "kernel_defines.h" +#include "psa/crypto.h" +#include "psa_mac.h" +#include "psa_hashes.h" +#include "psa_ecc.h" +#include "psa_ciphers.h" +#include "psa_crypto_operation_encoder.h" + +psa_status_t psa_algorithm_dispatch_hash_setup(psa_hash_operation_t *operation, + psa_algorithm_t alg) +{ + psa_status_t status = PSA_ERROR_NOT_SUPPORTED; + + switch (alg) { + #if (IS_USED(MODULE_PSA_HASH_MD5)) + case PSA_ALG_MD5: + status = psa_hashes_md5_setup(&operation->ctx.md5); + if (status != PSA_SUCCESS) { + return status; + } + break; + #endif + #if (IS_USED(MODULE_PSA_HASH_SHA_1)) + case PSA_ALG_SHA_1: + status = psa_hashes_sha1_setup(&operation->ctx.sha1); + if (status != PSA_SUCCESS) { + return status; + } + break; + #endif + #if (IS_USED(MODULE_PSA_HASH_SHA_224)) + case PSA_ALG_SHA_224: + status = psa_hashes_sha224_setup(&operation->ctx.sha224); + if (status != PSA_SUCCESS) { + return status; + } + break; + #endif + #if (IS_USED(MODULE_PSA_HASH_SHA_256)) + case PSA_ALG_SHA_256: + status = psa_hashes_sha256_setup(&operation->ctx.sha256); + if (status != PSA_SUCCESS) { + return status; + } + break; + #endif + #if (IS_USED(MODULE_PSA_HASH_SHA_512)) + case PSA_ALG_SHA_512: + status = psa_hashes_sha512_setup(&operation->ctx.sha512); + if (status != PSA_SUCCESS) { + return status; + } + break; + #endif + default: + (void)status; + (void)operation; + return PSA_ERROR_NOT_SUPPORTED; + } + + operation->alg = alg; + return PSA_SUCCESS; +} + +psa_status_t psa_algorithm_dispatch_hash_update(psa_hash_operation_t *operation, + const uint8_t *input, + size_t input_length) +{ + switch (operation->alg) { + #if (IS_USED(MODULE_PSA_HASH_MD5)) + case PSA_ALG_MD5: + return psa_hashes_md5_update(&operation->ctx.md5, input, input_length); + #endif + #if (IS_USED(MODULE_PSA_HASH_SHA_1)) + case PSA_ALG_SHA_1: + return psa_hashes_sha1_update(&operation->ctx.sha1, input, input_length); + #endif + #if (IS_USED(MODULE_PSA_HASH_SHA_224)) + case PSA_ALG_SHA_224: + return psa_hashes_sha224_update(&operation->ctx.sha224, input, input_length); + #endif + #if (IS_USED(MODULE_PSA_HASH_SHA_256)) + case PSA_ALG_SHA_256: + return psa_hashes_sha256_update(&operation->ctx.sha256, input, input_length); + #endif + #if (IS_USED(MODULE_PSA_HASH_SHA_512)) + case PSA_ALG_SHA_512: + return psa_hashes_sha512_update(&operation->ctx.sha512, input, input_length); + #endif + default: + (void)operation; + (void)input; + (void)input_length; + return PSA_ERROR_NOT_SUPPORTED; + } +} + +psa_status_t psa_algorithm_dispatch_hash_finish(psa_hash_operation_t *operation, + uint8_t *hash, + size_t hash_size, + size_t *hash_length) +{ + switch (operation->alg) { + #if (IS_USED(MODULE_PSA_HASH_MD5)) + case PSA_ALG_MD5: + return psa_hashes_md5_finish(&operation->ctx.md5, hash, hash_size, hash_length); + #endif + #if (IS_USED(MODULE_PSA_HASH_SHA_1)) + case PSA_ALG_SHA_1: + return psa_hashes_sha1_finish(&operation->ctx.sha1, hash, hash_size, hash_length); + #endif + #if (IS_USED(MODULE_PSA_HASH_SHA_224)) + case PSA_ALG_SHA_224: + return psa_hashes_sha224_finish(&operation->ctx.sha224, hash, hash_size, hash_length); + #endif + #if (IS_USED(MODULE_PSA_HASH_SHA_256)) + case PSA_ALG_SHA_256: + return psa_hashes_sha256_finish(&operation->ctx.sha256, hash, hash_size, hash_length); + #endif + #if (IS_USED(MODULE_PSA_HASH_SHA_512)) + case PSA_ALG_SHA_512: + return psa_hashes_sha512_finish(&operation->ctx.sha512, hash, hash_size, hash_length); + #endif + default: + (void)operation; + (void)hash; + (void)hash_size; + (void)hash_length; + return PSA_ERROR_NOT_SUPPORTED; + } +} + +psa_status_t psa_algorithm_dispatch_sign_hash( const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *hash, + size_t hash_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length) +{ + psa_asym_key_t asym_key = PSA_INVALID_OPERATION; + uint8_t *key_data = NULL; + size_t *key_bytes = NULL; + + if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(attributes->type)) { + asym_key = + PSA_ENCODE_ECC_KEY_TYPE(attributes->bits, PSA_KEY_TYPE_ECC_GET_CURVE(attributes->type)); + + if (asym_key == PSA_INVALID_OPERATION) { + return PSA_ERROR_INVALID_ARGUMENT; + } + } + + psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes); + + switch (asym_key) { +#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P192R1) + case PSA_ECC_P192_R1: + return psa_ecc_p192r1_sign_hash(attributes, alg, key_data, *key_bytes, hash, hash_length, + signature, signature_size, signature_length); +#endif +#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P256R1) + case PSA_ECC_P256_R1: + return psa_ecc_p256r1_sign_hash(attributes, alg, key_data, *key_bytes, hash, hash_length, + signature, signature_size, signature_length); +#endif + default: + (void)alg; + (void)slot; + (void)hash; + (void)hash_length; + (void)signature; + (void)signature_size; + (void)signature_length; + return PSA_ERROR_NOT_SUPPORTED; + } +} + +psa_status_t psa_algorithm_dispatch_verify_hash( const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *hash, + size_t hash_length, + const uint8_t *signature, + size_t signature_length) +{ + psa_asym_key_t asym_key = PSA_INVALID_OPERATION; + uint8_t *pubkey_data = NULL; + size_t *pubkey_data_len = NULL; + + if (PSA_KEY_TYPE_IS_ECC(attributes->type)) { + asym_key = + PSA_ENCODE_ECC_KEY_TYPE(attributes->bits, PSA_KEY_TYPE_ECC_GET_CURVE(attributes->type)); + + if (asym_key == PSA_INVALID_OPERATION) { + return PSA_ERROR_INVALID_ARGUMENT; + } + } + + psa_get_public_key_data_from_key_slot(slot, &pubkey_data, &pubkey_data_len); + + switch (asym_key) { +#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P192R1) + case PSA_ECC_P192_R1: + return psa_ecc_p192r1_verify_hash(attributes, alg, pubkey_data, *pubkey_data_len, hash, + hash_length, signature, signature_length); +#endif +#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P256R1) + case PSA_ECC_P256_R1: + return psa_ecc_p256r1_verify_hash(attributes, alg, pubkey_data, *pubkey_data_len, hash, + hash_length, signature, signature_length); +#endif + default: + (void)alg; + (void)slot; + (void)hash; + (void)hash_length; + (void)signature; + (void)signature_length; + return PSA_ERROR_NOT_SUPPORTED; + } +} + +psa_status_t psa_algorithm_dispatch_generate_key( const psa_key_attributes_t *attributes, + psa_key_slot_t *slot) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + uint8_t *key_data = NULL; + size_t *key_bytes = NULL; + + psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes); + + /** + * Only asymmetric key generation needs special key generation algorithms. Symmetric keys can + * be created by generating random bytes. + */ + if (PSA_KEY_TYPE_IS_ASYMMETRIC(attributes->type)) { + psa_asym_key_t asym_key = PSA_INVALID_OPERATION; + uint8_t *pubkey_data = NULL; + size_t *pubkey_data_len = NULL; + psa_get_public_key_data_from_key_slot(slot, &pubkey_data, &pubkey_data_len); + + if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(attributes->type)) { + asym_key = + PSA_ENCODE_ECC_KEY_TYPE(attributes->bits, + PSA_KEY_TYPE_ECC_GET_CURVE(attributes->type)); + + if (asym_key == PSA_INVALID_OPERATION) { + return PSA_ERROR_INVALID_ARGUMENT; + } + } + + switch (asym_key) { +#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P192R1) + case PSA_ECC_P192_R1: + return psa_generate_ecc_p192r1_key_pair(attributes, key_data, pubkey_data, key_bytes, + pubkey_data_len); +#endif +#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P256R1) + case PSA_ECC_P256_R1: + return psa_generate_ecc_p256r1_key_pair(attributes, key_data, pubkey_data, key_bytes, + pubkey_data_len); +#endif + default: + (void)status; + (void)slot; + return PSA_ERROR_NOT_SUPPORTED; + } + } + + return psa_builtin_generate_key(attributes, key_data, *key_bytes, key_bytes); +} + +psa_status_t psa_algorithm_dispatch_cipher_encrypt( const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + psa_cipher_op_t op = PSA_ENCODE_CIPHER_OPERATION(alg, attributes->bits, attributes->type); + uint8_t *key_data = NULL; + size_t *key_bytes = NULL; + + psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes); + + if (op == PSA_INVALID_OPERATION) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + switch (op) { +#if IS_USED(MODULE_PSA_CIPHER_AES_128_CBC) + case PSA_CBC_NO_PAD_AES_128: + return psa_cipher_cbc_aes_128_encrypt(attributes, key_data, *key_bytes, alg, input, + input_length, output, output_size, output_length); +#endif +#if IS_USED(MODULE_PSA_CIPHER_AES_192_CBC) + case PSA_CBC_NO_PAD_AES_192: + return psa_cipher_cbc_aes_192_encrypt(attributes, key_data, *key_bytes, alg, input, + input_length, output, output_size, output_length); +#endif +#if IS_USED(MODULE_PSA_CIPHER_AES_256_CBC) + case PSA_CBC_NO_PAD_AES_256: + return psa_cipher_cbc_aes_256_encrypt(attributes, key_data, *key_bytes, alg, input, + input_length, output, output_size, output_length); +#endif + default: + (void)slot; + (void)input; + (void)input_length; + (void)output; + (void)output_size; + (void)output_length; + return PSA_ERROR_NOT_SUPPORTED; + } +} + +psa_status_t psa_algorithm_dispatch_cipher_decrypt( const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + psa_cipher_op_t op = PSA_ENCODE_CIPHER_OPERATION(alg, attributes->bits, attributes->type); + uint8_t *key_data = NULL; + size_t *key_bytes = NULL; + + psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes); + + if (op == PSA_INVALID_OPERATION) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + switch (op) { +#if IS_USED(MODULE_PSA_CIPHER_AES_128_CBC) + case PSA_CBC_NO_PAD_AES_128: + return psa_cipher_cbc_aes_128_decrypt(attributes, key_data, *key_bytes, alg, input, + input_length, output, output_size, output_length); +#endif +#if IS_USED(MODULE_PSA_CIPHER_AES_192_CBC) + case PSA_CBC_NO_PAD_AES_192: + return psa_cipher_cbc_aes_192_decrypt(attributes, key_data, *key_bytes, alg, input, + input_length, output, output_size, output_length); +#endif +#if IS_USED(MODULE_PSA_CIPHER_AES_256_CBC) + case PSA_CBC_NO_PAD_AES_256: + return psa_cipher_cbc_aes_256_decrypt(attributes, key_data, *key_bytes, alg, input, + input_length, output, output_size, output_length); +#endif + default: + (void)slot; + (void)input; + (void)input_length; + (void)output; + (void)output_size; + (void)output_length; + return PSA_ERROR_NOT_SUPPORTED; + } +} + +psa_status_t psa_algorithm_dispatch_mac_compute(const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *input, + size_t input_length, + uint8_t *mac, + size_t mac_size, + size_t *mac_length) +{ + psa_status_t status = PSA_ERROR_NOT_SUPPORTED; + uint8_t *key_data = NULL; + size_t *key_bytes = NULL; + + psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes); + + switch (alg) { + #if IS_USED(MODULE_PSA_MAC_HMAC_SHA_256) + case PSA_ALG_HMAC(PSA_ALG_SHA_256): + status = psa_mac_compute_hmac_sha256(attributes, key_data, *key_bytes, input, input_length, + mac, mac_size, mac_length); + if (status != PSA_SUCCESS) { + return status; + } + break; + #endif + default: + (void)status; + return PSA_ERROR_NOT_SUPPORTED; + } + + (void)attributes; + (void)input; + (void)input_length; + (void)mac; + (void)mac_size; + (void)mac_length; + return PSA_SUCCESS; +} diff --git a/sys/psa_crypto/psa_crypto_location_dispatch.c b/sys/psa_crypto/psa_crypto_location_dispatch.c new file mode 100644 index 0000000000..c5d03c55c6 --- /dev/null +++ b/sys/psa_crypto/psa_crypto_location_dispatch.c @@ -0,0 +1,441 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto sys_psa_crypto_loc_disp + * @{ + * + * @file + * @brief Dispatch calls from the PSA Crypto API to an available backend. + * + * @author Lena Boeckmann + * + * @} + */ + +#include +#include "kernel_defines.h" +#include "psa/crypto.h" +#include "psa_crypto_algorithm_dispatch.h" +#include "psa_crypto_slot_management.h" +#include "psa_crypto_se_management.h" +#include "psa_crypto_se_driver.h" + +psa_status_t psa_location_dispatch_generate_key(const psa_key_attributes_t *attributes, + psa_key_slot_t *slot) +{ +#if IS_USED(MODULE_PSA_SECURE_ELEMENT) + psa_status_t status; + const psa_drv_se_t *drv; + psa_drv_se_context_t *drv_context; + psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot); + + uint8_t *pubkey_data = NULL; + size_t *pubkey_data_len = NULL; + + psa_get_public_key_data_from_key_slot(slot, &pubkey_data, &pubkey_data_len); + + if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) { + if (drv->key_management == NULL || drv->key_management->p_generate == NULL) { + return PSA_ERROR_NOT_SUPPORTED; + } + + status = drv->key_management->p_generate(drv_context, *slot_number, attributes, pubkey_data, + *pubkey_data_len, pubkey_data_len); + if (status != PSA_SUCCESS) { + /* In case anything goes wrong, free the key slot for reuse. */ + psa_se_drv_data_t *driver = psa_get_se_driver_data(attributes->lifetime); + psa_status_t abort_status = drv->key_management->p_destroy(drv_context, driver->ctx.internal.persistent_data, *slot_number); + return abort_status == PSA_SUCCESS ? status : abort_status; + } + return PSA_SUCCESS; + } +#endif /* MODULE_PSA_SECURE_ELEMENT */ + + return psa_algorithm_dispatch_generate_key(attributes, slot); +} + +psa_status_t psa_location_dispatch_import_key( const psa_key_attributes_t *attributes, + const uint8_t *data, size_t data_length, + psa_key_slot_t *slot, size_t *bits) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(attributes->lifetime); + uint8_t *key_data = NULL; + size_t *key_bytes = NULL; + size_t key_data_size; + + key_data_size = psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes); + +#if IS_USED(MODULE_PSA_SECURE_ELEMENT) + const psa_drv_se_t *drv; + psa_drv_se_context_t *drv_context; + psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot); + + if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) { + if (drv->key_management == NULL || drv->key_management->p_import == NULL) { + return PSA_ERROR_NOT_SUPPORTED; + } + *bits = 0; + + status = drv->key_management->p_import(drv_context, *slot_number, + attributes, data, + data_length, bits); + if (status != PSA_SUCCESS) { + /* In case anything goes wrong, free the key slot for reuse. */ + psa_se_drv_data_t *driver = psa_get_se_driver_data(attributes->lifetime); + psa_status_t abort_status = drv->key_management->p_destroy(drv_context, driver->ctx.internal.persistent_data, *slot_number); + return abort_status == PSA_SUCCESS ? status : abort_status; + } + return PSA_SUCCESS; + } +#endif /* MODULE_PSA_SECURE_ELEMENT */ + + switch (location) { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + return psa_builtin_import_key(attributes, data, data_length, key_data, key_data_size, key_bytes, bits); + default: + (void)status; + return PSA_ERROR_NOT_SUPPORTED; + } +} + +psa_status_t psa_location_dispatch_cipher_encrypt_setup( psa_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const psa_key_slot_t *slot, + psa_algorithm_t alg) +{ +#if IS_USED(MODULE_PSA_SECURE_ELEMENT) + psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(attributes->lifetime); + if (location != PSA_KEY_LOCATION_LOCAL_STORAGE) { + const psa_drv_se_t *drv; + psa_drv_se_context_t *drv_context; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot); + + uint8_t *key_data = NULL; + size_t *key_bytes = NULL; + psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes); + + if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) { + if (drv->cipher == NULL || drv->cipher->p_setup == NULL) { + return PSA_ERROR_NOT_SUPPORTED; + } + + status = drv->cipher->p_setup(drv_context, &operation->backend_ctx.se_ctx, *slot_number, + attributes->policy.alg, PSA_CRYPTO_DRIVER_ENCRYPT); + if (status != PSA_SUCCESS) { + return status; + } + return PSA_SUCCESS; + } + } +#endif /* MODULE_PSA_SECURE_ELEMENT */ + (void)operation; + (void)attributes; + (void)slot; + (void)alg; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_location_dispatch_cipher_decrypt_setup(psa_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const psa_key_slot_t *slot, + psa_algorithm_t alg) +{ + (void)operation; + (void)attributes; + (void)slot; + (void)alg; + return PSA_ERROR_NOT_SUPPORTED; +} + +#if IS_USED(MODULE_PSA_SECURE_ELEMENT) +/** + * @brief Single part function for cipher encryption and decryption on a secure element + * + * Some secure elements don't provide single part operations for cipher encryption. + * This is a wrapper function, to support those. + * + * @param drv + * @param drv_context + * @param attributes + * @param alg + * @param direction + * @param slot + * @param input + * @param input_length + * @param output + * @param output_size + * @param output_length + * @return @ref psa_status_t + */ +static psa_status_t psa_se_cipher_encrypt_decrypt( const psa_drv_se_t *drv, + psa_drv_se_context_t *drv_context, + const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + psa_encrypt_or_decrypt_t direction, + psa_key_slot_number_t slot, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + psa_status_t status; + psa_cipher_operation_t operation = psa_cipher_operation_init(); + psa_se_cipher_context_t *se_ctx = &operation.backend_ctx.se_ctx; + size_t input_offset = 0; + size_t output_offset = 0; + + *output_length = 0; + + if (drv->cipher == NULL || + drv->cipher->p_setup == NULL || + drv->cipher->p_set_iv == NULL || + drv->cipher->p_update == NULL || + drv->cipher->p_finish == NULL) { + return PSA_ERROR_NOT_SUPPORTED; + } + + status = drv->cipher->p_setup(drv_context, se_ctx, slot, alg, direction); + if (status != PSA_SUCCESS) { + return status; + } + + if (alg == PSA_ALG_CBC_NO_PADDING) { + operation.iv_required = 1; + operation.default_iv_length = PSA_CIPHER_IV_LENGTH(psa_get_key_type(attributes), alg); + + if (direction == PSA_CRYPTO_DRIVER_ENCRYPT) { + /* In case of encryption, we need to generate and set an IV. The IV will be written + into the first 16 bytes of the output buffer. */ + size_t iv_length = 0; + status = psa_cipher_generate_iv(&operation, output, operation.default_iv_length, + &iv_length); + + status = drv->cipher->p_set_iv(se_ctx, output, iv_length); + if (status != PSA_SUCCESS) { + return status; + } + /* Increase output buffer offset to IV length to write ciphertext to buffer after IV */ + output_offset += iv_length; + *output_length += iv_length; + } + else { + /* In case of decryption the IV to be used must be provided by the caller and is + contained in the first 16 Bytes of the input buffer. */ + status = drv->cipher->p_set_iv(se_ctx, input, operation.default_iv_length); + + /* Increase input buffer offset to IV length to start decryption + with actual cipher text */ + input_offset += operation.default_iv_length; + } + } + + status = drv->cipher->p_update(se_ctx, input + input_offset, input_length - input_offset, + output + output_offset, output_size - output_offset, + output_length); + if (status != PSA_SUCCESS) { + psa_cipher_abort(&operation); + return status; + } + + status = drv->cipher->p_finish(se_ctx, output, output_size, output_length); + if (status != PSA_SUCCESS) { + return status; + } + return PSA_SUCCESS; +} +#endif /* CONFIG_PSA_SECURE_ELEMENT */ + +psa_status_t psa_location_dispatch_cipher_encrypt( const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + +#if IS_USED(MODULE_PSA_SECURE_ELEMENT) + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + const psa_drv_se_t *drv; + psa_drv_se_context_t *drv_context; + psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot); + + if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) { + if (alg == PSA_ALG_ECB_NO_PADDING) { + if (drv->cipher == NULL || drv->cipher->p_ecb == NULL) { + return PSA_ERROR_NOT_SUPPORTED; + } + status = drv->cipher->p_ecb(drv_context, *slot_number, alg, PSA_CRYPTO_DRIVER_ENCRYPT, + input, input_length, output, output_size); + if (status != PSA_SUCCESS) { + return status; + } + } + + /* The SE interface does not support single part functions for other algorithms than ECB, + so we need to build one ourselves */ + status = psa_se_cipher_encrypt_decrypt(drv, drv_context, attributes, alg, + PSA_CRYPTO_DRIVER_ENCRYPT, *slot_number, input, + input_length, output, output_size, output_length); + + return status; + } + +#endif /* CONFIG_PSA_SECURE_ELEMENT */ + return psa_algorithm_dispatch_cipher_encrypt(attributes, alg, slot, input, input_length, output, + output_size, output_length); +} + +psa_status_t psa_location_dispatch_cipher_decrypt( const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + +#if IS_USED(MODULE_PSA_SECURE_ELEMENT) + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + const psa_drv_se_t *drv; + psa_drv_se_context_t *drv_context; + psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot); + + if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) { + if (alg == PSA_ALG_ECB_NO_PADDING) { + if (drv->cipher == NULL || drv->cipher->p_ecb == NULL) { + return PSA_ERROR_NOT_SUPPORTED; + } + status = drv->cipher->p_ecb(drv_context, *slot_number, alg, PSA_CRYPTO_DRIVER_DECRYPT, + input, input_length, output, output_size); + if (status != PSA_SUCCESS) { + return status; + } + } + + status = psa_se_cipher_encrypt_decrypt(drv, drv_context, attributes, alg, + PSA_CRYPTO_DRIVER_DECRYPT, *slot_number, input, + input_length, output, output_size, output_length); + + return status; + } +#endif /* CONFIG_PSA_SECURE_ELEMENT */ + return psa_algorithm_dispatch_cipher_decrypt(attributes, alg, slot, input, input_length, + output, output_size, output_length); +} + +psa_status_t psa_location_dispatch_sign_hash( const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *hash, + size_t hash_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length) +{ +#if IS_USED(MODULE_PSA_SECURE_ELEMENT) + const psa_drv_se_t *drv; + psa_drv_se_context_t *drv_context; + psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot); + + uint8_t *key_data = NULL; + size_t *key_bytes = NULL; + psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes); + + if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) { + if (drv->asymmetric == NULL || drv->asymmetric->p_sign == NULL) { + return PSA_ERROR_NOT_SUPPORTED; + } + return drv->asymmetric->p_sign(drv_context, *slot_number, alg, hash, hash_length, signature, + signature_size, signature_length); + } + + (void)key_bytes; +#endif /* CONFIG_PSA_SECURE_ELEMENT */ + + return psa_algorithm_dispatch_sign_hash(attributes, alg, slot, hash, hash_length, signature, + signature_size, signature_length); +} + +psa_status_t psa_location_dispatch_verify_hash(const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *hash, + size_t hash_length, + const uint8_t *signature, + size_t signature_length) +{ +#if IS_USED(MODULE_PSA_SECURE_ELEMENT) + const psa_drv_se_t *drv; + psa_drv_se_context_t *drv_context; + psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot); + + uint8_t *key_data = NULL; + size_t *key_bytes = NULL; + psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes); + + if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) { + if (drv->asymmetric == NULL || drv->asymmetric->p_verify == NULL) { + return PSA_ERROR_NOT_SUPPORTED; + } + return drv->asymmetric->p_verify(drv_context, *slot_number, alg, hash, hash_length, + signature, signature_length); + } + + (void)key_bytes; +#endif /* CONFIG_PSA_SECURE_ELEMENT */ + + return psa_algorithm_dispatch_verify_hash(attributes, alg, slot, hash, hash_length, signature, + signature_length); +} + +psa_status_t psa_location_dispatch_mac_compute(const psa_key_attributes_t *attributes, + psa_algorithm_t alg, + const psa_key_slot_t *slot, + const uint8_t *input, + size_t input_length, + uint8_t *mac, + size_t mac_size, + size_t *mac_length) +{ +#if IS_USED(MODULE_PSA_SECURE_ELEMENT) + const psa_drv_se_t *drv; + psa_drv_se_context_t *drv_context; + psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot); + + uint8_t *key_data = NULL; + size_t *key_bytes = NULL; + psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes); + + if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) { + if (drv->mac == NULL || drv->mac->p_mac == NULL) { + return PSA_ERROR_NOT_SUPPORTED; + } + + return drv->mac->p_mac(drv_context, input, input_length, *slot_number, alg, mac, mac_size, + mac_length); + } + + (void)key_bytes; +#endif /* CONFIG_PSA_SECURE_ELEMENT */ + + return psa_algorithm_dispatch_mac_compute(attributes, alg, slot, input, input_length, mac, + mac_size, mac_length); +} + +psa_status_t psa_location_dispatch_generate_random(uint8_t *output, + size_t output_size) +{ + return psa_builtin_generate_random(output, output_size); +} diff --git a/sys/psa_crypto/psa_key_slot_mgmt/Kconfig b/sys/psa_crypto/psa_key_slot_mgmt/Kconfig new file mode 100644 index 0000000000..a064bf1b25 --- /dev/null +++ b/sys/psa_crypto/psa_key_slot_mgmt/Kconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2022 HAW Hamburg +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. +# + +config MODULE_PSA_KEY_SLOT_MGMT + bool + default y if PACKAGE_PSA_ARCH_TESTS diff --git a/sys/psa_crypto/psa_key_slot_mgmt/Makefile b/sys/psa_crypto/psa_key_slot_mgmt/Makefile new file mode 100644 index 0000000000..3d213aadd6 --- /dev/null +++ b/sys/psa_crypto/psa_key_slot_mgmt/Makefile @@ -0,0 +1,4 @@ +MODULE := psa_key_slot_mgmt +INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include + +include $(RIOTBASE)/Makefile.base diff --git a/sys/psa_crypto/psa_key_slot_mgmt/psa_crypto_slot_management.c b/sys/psa_crypto/psa_key_slot_mgmt/psa_crypto_slot_management.c new file mode 100644 index 0000000000..e50317bde4 --- /dev/null +++ b/sys/psa_crypto/psa_key_slot_mgmt/psa_crypto_slot_management.c @@ -0,0 +1,539 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto sys_psa_crypto_slot_mgmt + * @{ + * + * @file + * @brief PSA Crypto Key Slot Management implementation + * + * @author Lena Boeckmann + * + * @} + */ + +#include "clist.h" +#include "psa_crypto_slot_management.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +#if IS_USED(MODULE_PSA_SECURE_ELEMENT) +/** + * @brief Structure for a protected key slot. + * + * These slots hold Slot Numbers for keys in protected storage and, if the key type is an + * asymmetric key pair, the public key. + */ +typedef struct { + clist_node_t node; + size_t lock_count; + psa_key_attributes_t attr; + struct prot_key_data { + psa_key_slot_number_t slot_number; +#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC) + uint8_t pubkey_data[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE]; + size_t pubkey_data_len; +#endif + } key; +} psa_prot_key_slot_t; + +/** + * @brief Array containing the protected key slots + */ +static psa_prot_key_slot_t protected_key_slots[PSA_PROTECTED_KEY_COUNT]; + +/** + * @brief List pointing to empty protected key slots + */ +static clist_node_t protected_list_empty; +#endif /* MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC */ + +#if IS_USED(MODULE_PSA_ASYMMETRIC) +/** + * @brief Structure for asymmetric key pairs. + * + * Contains asymmetric private and public key pairs. + * + */ +typedef struct { + clist_node_t node; + size_t lock_count; + psa_key_attributes_t attr; + struct key_pair_data { + /** Contains asymmetric private key*/ + uint8_t privkey_data[PSA_BITS_TO_BYTES(PSA_MAX_PRIV_KEY_SIZE)]; + /** Contains actual size of asymmetric private key */ + size_t privkey_data_len; + /** Contains asymmetric public key */ + uint8_t pubkey_data[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE]; + /*!< Contains actual size of asymmetric private key */ + size_t pubkey_data_len; + } key; +} psa_key_pair_slot_t; + +/** + * @brief Array containing the asymmetric key slots + */ +static psa_key_pair_slot_t key_pair_slots[PSA_ASYMMETRIC_KEYPAIR_COUNT]; + +/** + * @brief List pointing to empty asymmetric key slots + */ +static clist_node_t key_pair_list_empty; +#endif /* MODULE_PSA_ASYMMETRIC */ + +/** + * @brief Array containing the single key slots + */ +static psa_key_slot_t single_key_slots[PSA_SINGLE_KEY_COUNT]; + +/** + * @brief List pointing to empty single key slots + */ +static clist_node_t single_key_list_empty; + +/** + * @brief Global list of used key slots + */ +static clist_node_t key_slot_list; + +/** + * @brief Counter for volatile key IDs. + */ +static psa_key_id_t key_id_count = PSA_KEY_ID_VOLATILE_MIN; + +/** + * @brief Get the correct empty slot list, depending on the key type + * + * @param attr + * @return clist_node_t* Pointer to the list the key is supposed to be stored in, + * according to its attributes + */ +static clist_node_t * psa_get_empty_key_slot_list(const psa_key_attributes_t *attr) +{ + if (!psa_key_lifetime_is_external(attr->lifetime)) { +#if IS_USED(MODULE_PSA_ASYMMETRIC) + if (PSA_KEY_TYPE_IS_KEY_PAIR(attr->type)) { + return &key_pair_list_empty; + } +#endif /* MODULE_PSA_ASYMMETRIC */ + return &single_key_list_empty; + } +#if IS_USED(MODULE_PSA_SECURE_ELEMENT) + return &protected_list_empty; +#else + return NULL; +#endif /* MODULE_PSA_SECURE_ELEMENT */ +} + +void psa_init_key_slots(void) +{ + DEBUG("List Node Size: %d\n", sizeof(clist_node_t)); +#if IS_USED(MODULE_PSA_SECURE_ELEMENT) + memset(protected_key_slots, 0, sizeof(protected_key_slots)); + +#if PSA_PROTECTED_KEY_COUNT + for (size_t i = 0; i < PSA_PROTECTED_KEY_COUNT; i++) { + clist_rpush(&protected_list_empty, &protected_key_slots[i].node); + } +#endif /* PSA_PROTECTED_KEY_COUNT */ + + DEBUG("Protected Slot Count: %d, Size: %d\n", PSA_PROTECTED_KEY_COUNT, + sizeof(psa_prot_key_slot_t)); + DEBUG("Protected Slot Array Size: %d\n", sizeof(protected_key_slots)); + DEBUG("Protected Slot Empty List Size: %d\n", clist_count(&protected_list_empty)); +#endif /* MODULE_PSA_SECURE_ELEMENT */ + +#if IS_USED(MODULE_PSA_ASYMMETRIC) + memset(key_pair_slots, 0, sizeof(key_pair_slots)); + +#if PSA_ASYMMETRIC_KEYPAIR_COUNT + for (size_t i = 0; i < PSA_ASYMMETRIC_KEYPAIR_COUNT; i++) { + clist_rpush(&key_pair_list_empty, &key_pair_slots[i].node); + } +#endif /* PSA_ASYMMETRIC_KEYPAIR_COUNT */ + DEBUG("Asymmetric Slot Count: %d, Size: %d\n", PSA_ASYMMETRIC_KEYPAIR_COUNT, + sizeof(psa_key_pair_slot_t)); + DEBUG("Asymmetric Slot Array Size: %d\n", sizeof(key_pair_slots)); + DEBUG("Asymmetric Slot Empty List Size: %d\n", clist_count(&key_pair_list_empty)); +#endif /* MODULE_PSA_ASYMMETRIC */ + + memset(single_key_slots, 0, sizeof(single_key_slots)); +#if PSA_SINGLE_KEY_COUNT + for (size_t i = 0; i < PSA_SINGLE_KEY_COUNT; i++) { + clist_rpush(&single_key_list_empty, &single_key_slots[i].node); + } +#endif + DEBUG("Single Key Slot Count: %d, Size: %d\n", PSA_SINGLE_KEY_COUNT, sizeof(psa_key_slot_t)); + DEBUG("Single Key Slot Array Size: %d\n", sizeof(single_key_slots)); + DEBUG("Single Key Slot Empty List Size: %d\n", clist_count(&single_key_list_empty)); +} + +/** + * @brief Wipe key slot with correct key slot size + * + * @param slot Key sloit to be wiped + */ +static void psa_wipe_real_slot_type(psa_key_slot_t *slot) +{ + psa_key_attributes_t attr = slot->attr; + + if (!psa_key_lifetime_is_external(attr.lifetime)) { + if (!PSA_KEY_TYPE_IS_KEY_PAIR(attr.type)) { + memset(slot, 0, sizeof(psa_key_slot_t)); + } +#if IS_USED(MODULE_PSA_ASYMMETRIC) + else { + + memset((psa_key_pair_slot_t *)slot, 0, sizeof(psa_key_pair_slot_t)); + } +#endif + } +#if IS_USED(MODULE_PSA_SECURE_ELEMENT) + else { + memset((psa_prot_key_slot_t *)slot, 0, sizeof(psa_prot_key_slot_t)); + } +#endif +} + +psa_status_t psa_wipe_key_slot(psa_key_slot_t *slot) +{ + /* Get list the slot is stored in */ + clist_node_t *empty_list = psa_get_empty_key_slot_list(&slot->attr); + + if (empty_list == NULL) { + return PSA_ERROR_DOES_NOT_EXIST; + } + + /* Get node to remove from key slot list */ + clist_node_t *n = clist_remove(&key_slot_list, &slot->node); + + if (n == NULL) { + return PSA_ERROR_DOES_NOT_EXIST; + } + + psa_key_slot_t *tmp = container_of(n, psa_key_slot_t, node); + + /* Wipe slot associated with node */ + psa_wipe_real_slot_type(tmp); + + /* Append node to empty list for later reuse */ + clist_rpush(empty_list, n); + return PSA_SUCCESS; +} + +void psa_wipe_all_key_slots(void) +{ + /* Move all list items to empty lists */ + while (!clist_is_empty(&key_slot_list)) { + clist_node_t *to_remove = clist_rpop(&key_slot_list); + psa_key_slot_t *slot = container_of(to_remove, psa_key_slot_t, node); + clist_node_t *empty_list = psa_get_empty_key_slot_list(&slot->attr); + + psa_wipe_real_slot_type(slot); + clist_rpush(empty_list, to_remove); + } +} + +/** + * @brief Check whether a given key ID equals the ID of the given node. + * + * This is the break condition of the @ref clist_foreach function used + * in @ref psa_get_and_lock_key_slot_in_memory. + * clist_foreach iterates over all key slots and calls this function + * to compare each slot's key ID to the given input key ID. + * If they are equal, this function returns True and breaks the foreach + * loop. + * + * For more information see core/lib/include/clist.h. + * + * @param n Pointer to clist node referencing a key slot + * @param arg Pointer to required key ID + * @return int + * 1 if input ID equals node ID + * 0 otherwise + */ +static int node_id_equals_key_id(clist_node_t *n, void *arg) +{ + psa_key_slot_t *slot = container_of(n, psa_key_slot_t, node); + psa_key_id_t id = *((psa_key_id_t *)arg); + + if (slot->attr.id == id) { + return 1; + } + + return 0; +} + +/** + * @brief Find the key slot containing the key with a specified ID + * + * @param id ID of the required key + * @param p_slot Pointer to the slot that will contain the required key + * + * @return @ref PSA_SUCCESS + * @ref PSA_ERROR_INVALID_HANDLE + * @ref PSA_ERROR_CORRUPTION_DETECTED + * @ref PSA_ERROR_NOT_SUPPORTED + */ +static psa_status_t psa_get_and_lock_key_slot_in_memory(psa_key_id_t id, psa_key_slot_t **p_slot) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (psa_key_id_is_volatile(id)) { + clist_node_t *slot_node = clist_foreach(&key_slot_list, node_id_equals_key_id, &id); + if (slot_node == NULL) { + return PSA_ERROR_INVALID_HANDLE; + } + + psa_key_slot_t *slot = container_of(slot_node, psa_key_slot_t, node); + status = psa_lock_key_slot(slot); + if (status == PSA_SUCCESS) { + *p_slot = slot; + } + return status; + } + + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_get_and_lock_key_slot(psa_key_id_t id, psa_key_slot_t **p_slot) +{ + /* TODO validate ID */ + + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + *p_slot = NULL; + + status = psa_get_and_lock_key_slot_in_memory(id, p_slot); + if (status != PSA_ERROR_DOES_NOT_EXIST) { + return status; + } + + /* TODO: get persistent key from storage and load into slot */ + + return status; +} + +/** + * @brief Allocate a free slot for a new key creation + * + * @param p_slot Pointer that will contain the free key slot. + * @param attr Attributes of type @ref psa_key_attrubutes_t for the key to be created + * + * @return @ref PSA_SUCCESS + * @ref PSA_ERROR_DOES_NOT_EXIST No key slots for this type of key exist + * @ref PSA_ERROR_INSUFFICIENT_STORAGE + */ +static psa_status_t psa_allocate_key_slot_in_list(psa_key_slot_t **p_slot, + const psa_key_attributes_t *attr) +{ + clist_node_t *empty_list = psa_get_empty_key_slot_list(attr); + + if (empty_list == NULL) { + return PSA_ERROR_DOES_NOT_EXIST; + } + + /* Check if any empty elements of this key slot type are left */ + if (clist_is_empty(empty_list)) { + DEBUG("Key Slot MGMT: No PSA Key Slot available\n"); + return PSA_ERROR_INSUFFICIENT_STORAGE; + } + + /* TODO: If no slots left: Look for slot in list with persistent key + (key will be stored in persistent memory and slot can be reused) */ + + /* Remove key slote node from empty list and append to actual list */ + clist_node_t *new_slot = clist_rpop(empty_list); + + clist_rpush(&key_slot_list, new_slot); + + psa_key_slot_t *slot = container_of(new_slot, psa_key_slot_t, node); + + *p_slot = slot; + return PSA_SUCCESS; +} + +psa_status_t psa_allocate_empty_key_slot( psa_key_id_t *id, + const psa_key_attributes_t *attr, + psa_key_slot_t **p_slot) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *new_slot = NULL; + + /* Change later, when we also have persistent keys */ + if (key_id_count == PSA_KEY_ID_VOLATILE_MAX) { + DEBUG("Key Slot MGMT: Maximum key ID reached\n"); + return PSA_ERROR_INSUFFICIENT_STORAGE; + } + + status = psa_allocate_key_slot_in_list(&new_slot, attr); + if (status != PSA_SUCCESS) { + *p_slot = NULL; + *id = 0; + return status; + } + + if (new_slot != NULL) { + status = psa_lock_key_slot(new_slot); + if (status != PSA_SUCCESS) { + *p_slot = NULL; + *id = 0; + return status; + } + *id = key_id_count++; + *p_slot = new_slot; + + return PSA_SUCCESS; + } + + status = PSA_ERROR_INSUFFICIENT_MEMORY; + *p_slot = NULL; + *id = 0; + return status; +} + +psa_status_t psa_lock_key_slot(psa_key_slot_t *slot) +{ + if (slot->lock_count >= SIZE_MAX) { + return PSA_ERROR_CORRUPTION_DETECTED; + } + + slot->lock_count++; + + return PSA_SUCCESS; +} + +psa_status_t psa_unlock_key_slot(psa_key_slot_t *slot) +{ + if (slot == NULL) { + return PSA_SUCCESS; + } + + if (slot->lock_count > 0) { + slot->lock_count--; + return PSA_SUCCESS; + } + + return PSA_ERROR_CORRUPTION_DETECTED; +} + +psa_status_t psa_validate_key_location(psa_key_lifetime_t lifetime, psa_se_drv_data_t **p_drv) +{ + if (psa_key_lifetime_is_external(lifetime)) { +#if IS_USED(MODULE_PSA_SECURE_ELEMENT) + psa_se_drv_data_t *driver = psa_get_se_driver_data(lifetime); + if (driver != NULL) { + if (p_drv != NULL) { + *p_drv = driver; + } + return PSA_SUCCESS; + } +#else + (void)p_drv; +#endif /* MODULE_PSA_SECURE_ELEMENT */ + return PSA_ERROR_INVALID_ARGUMENT; + } + else { + (void)p_drv; + return PSA_SUCCESS; + } +} + +psa_status_t psa_validate_key_persistence(psa_key_lifetime_t lifetime) +{ + if (PSA_KEY_LIFETIME_IS_VOLATILE(lifetime)) { + return PSA_SUCCESS; + } + /* TODO: Implement persistent key storage */ + return PSA_ERROR_NOT_SUPPORTED; +} + +int psa_is_valid_key_id(psa_key_id_t id, int vendor) +{ + if ((PSA_KEY_ID_USER_MIN <= id) && + (id <= PSA_KEY_ID_USER_MAX)) { + return 1; + } + + if (vendor + && (PSA_KEY_ID_VENDOR_MIN <= id) + && (id <= PSA_KEY_ID_VENDOR_MAX)) { + return 1; + } + + return 0; +} + +size_t psa_get_key_data_from_key_slot(const psa_key_slot_t *slot, uint8_t **key_data, + size_t **key_bytes) +{ + psa_key_attributes_t attr = slot->attr; + size_t key_data_size = 0; + + *key_data = NULL; + *key_bytes = NULL; + + + if (!psa_key_lifetime_is_external(attr.lifetime)) { + if (!PSA_KEY_TYPE_IS_KEY_PAIR(attr.type)) { + *key_data = (uint8_t *)slot->key.data; + *key_bytes = (size_t *)&slot->key.data_len; + key_data_size = sizeof(slot->key.data); + } +#if IS_USED(MODULE_PSA_ASYMMETRIC) + else { + *key_data = ((psa_key_pair_slot_t *)slot)->key.privkey_data; + *key_bytes = &((psa_key_pair_slot_t *)slot)->key.privkey_data_len; + key_data_size = sizeof(((psa_key_pair_slot_t *)slot)->key.privkey_data); + } +#endif + } + return key_data_size; +} + +#if IS_USED(MODULE_PSA_SECURE_ELEMENT) +psa_key_slot_number_t * psa_key_slot_get_slot_number(const psa_key_slot_t *slot) +{ + return &(((psa_prot_key_slot_t *)slot)->key.slot_number); +} +#endif + +void psa_get_public_key_data_from_key_slot(const psa_key_slot_t *slot, uint8_t **pubkey_data, + size_t **pubkey_data_len) +{ + psa_key_attributes_t attr = slot->attr; + + /* If key type is not asymmetric, no public key exists */ + if (!PSA_KEY_TYPE_IS_ASYMMETRIC(attr.type)) { + *pubkey_data = NULL; + *pubkey_data_len = NULL; + return; + } + + if (!psa_key_lifetime_is_external(attr.lifetime)) { + if (!PSA_KEY_TYPE_IS_KEY_PAIR(attr.type)) { + *pubkey_data = ((psa_key_slot_t *)slot)->key.data; + *pubkey_data_len = &((psa_key_slot_t *)slot)->key.data_len; + return; + } +#if IS_USED(MODULE_PSA_ASYMMETRIC) + else { + *pubkey_data = ((psa_key_pair_slot_t *)slot)->key.pubkey_data; + *pubkey_data_len = &((psa_key_pair_slot_t *)slot)->key.pubkey_data_len; + return; + } +#endif + } +#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC) + *pubkey_data = ((psa_prot_key_slot_t *)slot)->key.pubkey_data; + *pubkey_data_len = &((psa_prot_key_slot_t *)slot)->key.pubkey_data_len; +#endif +} diff --git a/sys/psa_crypto/psa_se_mgmt/Kconfig b/sys/psa_crypto/psa_se_mgmt/Kconfig new file mode 100644 index 0000000000..80f017ad79 --- /dev/null +++ b/sys/psa_crypto/psa_se_mgmt/Kconfig @@ -0,0 +1,53 @@ +# Copyright (c) 2022 HAW Hamburg +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. +# + +menuconfig MODULE_PSA_SECURE_ELEMENT + bool "PSA Secure Elements" + select MODULE_PSA_KEY_SLOT_MGMT + select MODULE_PSA_SE_MGMT + +if MODULE_PSA_SECURE_ELEMENT + +config MODULE_PSA_SECURE_ELEMENT_MULTIPLE + bool "Use multiple secure elements" + +config PSA_MAX_SE_COUNT + int + prompt "Maximum number of secure elements" if MODULE_PSA_SECURE_ELEMENT_MULTIPLE + range 2 255 if MODULE_PSA_SECURE_ELEMENT_MULTIPLE + range 1 255 + +menuconfig MODULE_PSA_SECURE_ELEMENT_ATECCX08A + bool "Microchip ATECCX08A" + select PACKAGE_CRYPTOAUTHLIB + select MODULE_PSA_SECURE_ELEMENT_CONFIG + depends on HAS_PERIPH_I2C + help + When using Cryptoauthlib as a backend for elliptic curve operations, + please also choose the ECC symbol. + +config MODULE_PSA_SECURE_ELEMENT_ATECCX08A_ECC_P256 + bool "Microchip ATECCX08A Elliptic Curve P256" + select PSA_KEY_SIZE_256 + select MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC + depends on MODULE_PSA_SECURE_ELEMENT_ATECCX08A + +config MODULE_PSA_SE_MGMT + bool + +config MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC + bool + help + Indicates that an asymmetric operation is used with secure elements. + +config MODULE_PSA_SECURE_ELEMENT_CONFIG + bool + help + Indicates that this SE driver defines a configuration structure for + persistent driver data. + +endif # MODULE_PSA_SECURE_ELEMENT diff --git a/sys/psa_crypto/psa_se_mgmt/Makefile b/sys/psa_crypto/psa_se_mgmt/Makefile new file mode 100644 index 0000000000..489bd7b228 --- /dev/null +++ b/sys/psa_crypto/psa_se_mgmt/Makefile @@ -0,0 +1,3 @@ +MODULE := psa_se_mgmt + +include $(RIOTBASE)/Makefile.base diff --git a/sys/psa_crypto/psa_se_mgmt/psa_crypto_se_management.c b/sys/psa_crypto/psa_se_mgmt/psa_crypto_se_management.c new file mode 100644 index 0000000000..75598ebd14 --- /dev/null +++ b/sys/psa_crypto/psa_se_mgmt/psa_crypto_se_management.c @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2021 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto psa_crypto_se_mgmt + * @{ + * + * @brief PSA Crypto Secure Element Management implementation + * + * @author Lena Boeckmann + * + * @} + */ + +#include "psa_crypto_se_management.h" +#include "psa_crypto_se_driver.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +/** + * @brief Array containing the registered driver instances. + */ +static psa_se_drv_data_t driver_table[PSA_MAX_SE_COUNT]; + +/** + * @brief Global counter for registered SE devices. + + */ +unsigned psa_se_count = 0; + +psa_status_t psa_register_secure_element(psa_key_location_t location, + const psa_drv_se_t *methods, + void *psa_se_configuration, + const void *drv_transient_data) +{ + size_t i; + psa_se_drv_data_t *temp; + + if (psa_se_count >= PSA_MAX_SE_COUNT) { + DEBUG("SE Registration: Maximum number of Secure Elements reached.\n"); + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + + if (methods->hal_version != PSA_DRV_SE_HAL_VERSION) { + DEBUG("SE Registration: Driver HAL Version not supported.\n"); + return PSA_ERROR_NOT_SUPPORTED; + } + + if (location == PSA_KEY_LOCATION_LOCAL_STORAGE) { + DEBUG("SE Registration: Invalid driver location value.\n"); + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (location > PSA_KEY_LOCATION_SE_MAX) { + DEBUG("SE Registration: Exhausted maximum number of Secure Element location values.\n"); + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (methods->persistent_data_size > PSA_MAX_PERSISTENT_DATA_SIZE) { + DEBUG("SE Registration: Persistent Data is too large.\n"); + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + + /* Find next free slot in driver table */ + for (i = 0; i < psa_se_count; i++) { + if (driver_table[i].location == location) { + DEBUG("SE Registration: Device with location 0x%x already exists.\n", (int)location); + return PSA_ERROR_ALREADY_EXISTS; + } + + if (driver_table[i].location == 0) { + break; + } + } + + temp = &driver_table[i]; + temp->location = location; + temp->methods = methods; + temp->ctx.internal.transient_data = (uintptr_t)drv_transient_data; + temp->ctx.internal.persistent_data = psa_se_configuration; + temp->ctx.internal.persistent_data_size = methods->persistent_data_size; + + /* TODO: Load Persistent data if persistent_data_size != 0 */ + psa_se_count++; + return PSA_SUCCESS; +} + +psa_se_drv_data_t *psa_get_se_driver_data(psa_key_lifetime_t lifetime) +{ + psa_se_drv_data_t *drv = NULL; + psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(lifetime); + + if (location == 0) { + return NULL; + } + + for (size_t i = 0; i < PSA_MAX_SE_COUNT; i++) { + if (driver_table[i].location == location) { + drv = &driver_table[i]; + } + } + + (void)lifetime; + return drv; +} + +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_data_t *driver = psa_get_se_driver_data(lifetime); + + if (p_methods != NULL) { + *p_methods = (driver ? driver->methods : NULL); + } + if (p_drv_context != NULL) { + *p_drv_context = (driver ? &driver->ctx.context : NULL); + } + return (driver != NULL); +} + +const psa_drv_se_t *psa_get_se_driver_methods(const psa_se_drv_data_t *driver) +{ + return driver->methods; +} + +psa_drv_se_context_t *psa_get_se_drv_context(psa_se_drv_data_t *driver) +{ + return &driver->ctx.context; +} + +psa_status_t psa_find_free_se_slot(const psa_key_attributes_t *attributes, + psa_key_creation_method_t method, + psa_se_drv_data_t *driver, + psa_key_slot_number_t *slot_number) +{ + psa_status_t status; + psa_key_location_t key_location = + PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(attributes)); + + if (driver->location != key_location) { + return PSA_ERROR_CORRUPTION_DETECTED; + } + + if (driver->methods->key_management == NULL || + driver->methods->key_management->p_allocate == NULL) { + return PSA_ERROR_NOT_SUPPORTED; + } + + status = driver->methods->key_management->p_allocate(&driver->ctx.context, + driver->ctx.internal.persistent_data, + attributes, method, slot_number); + + return status; +} + +psa_status_t psa_destroy_se_key(psa_se_drv_data_t *driver, + psa_key_slot_number_t slot_number) +{ + if (driver->methods->key_management == NULL || + driver->methods->key_management->p_destroy == NULL) { + return PSA_ERROR_NOT_PERMITTED; + } + return driver->methods->key_management->p_destroy(&driver->ctx.context, + driver->ctx.internal.persistent_data, + slot_number); + + /* TODO: Store Persistent Data */ +} + +psa_status_t psa_load_se_persistent_data(const psa_se_drv_data_t *driver) +{ + (void)driver; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_save_se_persistent_data(const psa_se_drv_data_t *driver) +{ + (void)driver; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_destroy_se_persistent_data(psa_key_location_t location) +{ + (void)location; + return PSA_ERROR_NOT_SUPPORTED; +}