From d4c73d6a30ed83e9ce21c1ec405962d9c88b2458 Mon Sep 17 00:00:00 2001 From: Lena Boeckmann Date: Tue, 29 Aug 2023 18:43:32 +0200 Subject: [PATCH 1/8] sys: Add PSA Crypto Module --- doc/doxygen/src/riot-psa-structure.svg | 851 ++++ makefiles/dependency_resolution.inc.mk | 8 + sys/Kconfig | 1 + sys/Makefile | 3 + sys/Makefile.dep | 8 + sys/Makefile.include | 4 + sys/include/psa_crypto/psa/crypto.h | 4053 +++++++++++++++++ sys/include/psa_crypto/psa/crypto_contexts.h | 96 + sys/include/psa_crypto/psa/crypto_includes.h | 56 + sys/include/psa_crypto/psa/crypto_se_config.h | 48 + sys/include/psa_crypto/psa/crypto_sizes.h | 1004 ++++ sys/include/psa_crypto/psa/crypto_struct.h | 224 + sys/include/psa_crypto/psa/crypto_types.h | 503 ++ sys/include/psa_crypto/psa/crypto_values.h | 3486 ++++++++++++++ sys/psa_crypto/Kconfig | 24 + sys/psa_crypto/Kconfig.asymmetric | 61 + sys/psa_crypto/Kconfig.ciphers | 92 + sys/psa_crypto/Kconfig.hashes | 111 + sys/psa_crypto/Kconfig.keys | 55 + sys/psa_crypto/Kconfig.mac | 37 + sys/psa_crypto/Makefile | 15 + sys/psa_crypto/Makefile.dep | 241 + sys/psa_crypto/Makefile.include | 154 + sys/psa_crypto/doc.txt | 996 ++++ sys/psa_crypto/include/psa_ciphers.h | 136 + .../include/psa_crypto_algorithm_dispatch.h | 201 + .../include/psa_crypto_location_dispatch.h | 230 + .../include/psa_crypto_operation_encoder.h | 172 + sys/psa_crypto/include/psa_crypto_se_driver.h | 1314 ++++++ .../include/psa_crypto_se_management.h | 207 + .../include/psa_crypto_slot_management.h | 262 ++ sys/psa_crypto/include/psa_ecc.h | 198 + sys/psa_crypto/include/psa_hashes.h | 232 + sys/psa_crypto/include/psa_mac.h | 60 + sys/psa_crypto/psa_crypto.c | 1931 ++++++++ .../psa_crypto_algorithm_dispatch.c | 425 ++ sys/psa_crypto/psa_crypto_location_dispatch.c | 441 ++ sys/psa_crypto/psa_key_slot_mgmt/Kconfig | 10 + sys/psa_crypto/psa_key_slot_mgmt/Makefile | 4 + .../psa_crypto_slot_management.c | 539 +++ sys/psa_crypto/psa_se_mgmt/Kconfig | 53 + sys/psa_crypto/psa_se_mgmt/Makefile | 3 + .../psa_se_mgmt/psa_crypto_se_management.c | 193 + 43 files changed, 18742 insertions(+) create mode 100644 doc/doxygen/src/riot-psa-structure.svg create mode 100644 sys/include/psa_crypto/psa/crypto.h create mode 100644 sys/include/psa_crypto/psa/crypto_contexts.h create mode 100644 sys/include/psa_crypto/psa/crypto_includes.h create mode 100644 sys/include/psa_crypto/psa/crypto_se_config.h create mode 100644 sys/include/psa_crypto/psa/crypto_sizes.h create mode 100644 sys/include/psa_crypto/psa/crypto_struct.h create mode 100644 sys/include/psa_crypto/psa/crypto_types.h create mode 100644 sys/include/psa_crypto/psa/crypto_values.h create mode 100644 sys/psa_crypto/Kconfig create mode 100644 sys/psa_crypto/Kconfig.asymmetric create mode 100644 sys/psa_crypto/Kconfig.ciphers create mode 100644 sys/psa_crypto/Kconfig.hashes create mode 100644 sys/psa_crypto/Kconfig.keys create mode 100644 sys/psa_crypto/Kconfig.mac create mode 100644 sys/psa_crypto/Makefile create mode 100644 sys/psa_crypto/Makefile.dep create mode 100644 sys/psa_crypto/Makefile.include create mode 100644 sys/psa_crypto/doc.txt create mode 100644 sys/psa_crypto/include/psa_ciphers.h create mode 100644 sys/psa_crypto/include/psa_crypto_algorithm_dispatch.h create mode 100644 sys/psa_crypto/include/psa_crypto_location_dispatch.h create mode 100644 sys/psa_crypto/include/psa_crypto_operation_encoder.h create mode 100644 sys/psa_crypto/include/psa_crypto_se_driver.h create mode 100644 sys/psa_crypto/include/psa_crypto_se_management.h create mode 100644 sys/psa_crypto/include/psa_crypto_slot_management.h create mode 100644 sys/psa_crypto/include/psa_ecc.h create mode 100644 sys/psa_crypto/include/psa_hashes.h create mode 100644 sys/psa_crypto/include/psa_mac.h create mode 100644 sys/psa_crypto/psa_crypto.c create mode 100644 sys/psa_crypto/psa_crypto_algorithm_dispatch.c create mode 100644 sys/psa_crypto/psa_crypto_location_dispatch.c create mode 100644 sys/psa_crypto/psa_key_slot_mgmt/Kconfig create mode 100644 sys/psa_crypto/psa_key_slot_mgmt/Makefile create mode 100644 sys/psa_crypto/psa_key_slot_mgmt/psa_crypto_slot_management.c create mode 100644 sys/psa_crypto/psa_se_mgmt/Kconfig create mode 100644 sys/psa_crypto/psa_se_mgmt/Makefile create mode 100644 sys/psa_crypto/psa_se_mgmt/psa_crypto_se_management.c 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; +} From c01d6897692a08622590db1c63e82ea7c916c84a Mon Sep 17 00:00:00 2001 From: Lena Boeckmann Date: Tue, 29 Aug 2023 18:54:57 +0200 Subject: [PATCH 2/8] pkg: Add cryptocell driver and nrf52 HW features --- cpu/nrf52/Kconfig | 9 + cpu/nrf52/Makefile.dep | 1 + cpu/nrf52/Makefile.features | 16 + cpu/nrf52/periph/Kconfig | 55 +++ cpu/nrf52/periph/Makefile.dep | 39 ++ kconfigs/Kconfig.features | 50 +++ makefiles/features_modules.inc.mk | 9 + pkg/Kconfig | 1 + pkg/driver_cryptocell_310/Kconfig | 19 + pkg/driver_cryptocell_310/Makefile | 36 ++ pkg/driver_cryptocell_310/Makefile.dep | 6 + pkg/driver_cryptocell_310/Makefile.include | 25 ++ pkg/driver_cryptocell_310/contrib/Makefile | 3 + .../contrib/cryptocell_util.c | 83 ++++ pkg/driver_cryptocell_310/doc.txt | 10 + .../driver_cryptocell_310.mk | 3 + .../include/cryptocell_310_util.h | 61 +++ .../include/psa_cryptocell_310_aes_common.h | 73 ++++ .../include/psa_cryptocell_310_ecc_common.h | 115 +++++ .../psa_cryptocell_310_hashes_common.h | 71 +++ pkg/driver_cryptocell_310/include/psa_error.h | 60 +++ .../include/psa_periph_aes_ctx.h | 41 ++ .../include/psa_periph_hashes_ctx.h | 64 +++ .../psa_cryptocell_310/Kconfig | 77 ++++ .../psa_cryptocell_310/Makefile | 4 + .../psa_cryptocell_310/Makefile.dep | 30 ++ .../psa_cryptocell_310/aes_cbc.c | 131 ++++++ .../psa_cryptocell_310/aes_common.c | 112 +++++ .../psa_cryptocell_310/ecc_common.c | 143 ++++++ .../psa_cryptocell_310/ecc_p192.c | 76 ++++ .../psa_cryptocell_310/ecc_p256.c | 74 ++++ .../psa_cryptocell_310/error_conversion.c | 413 ++++++++++++++++++ .../psa_cryptocell_310/hashes_common.c | 87 ++++ .../psa_cryptocell_310/hashes_sha1.c | 43 ++ .../psa_cryptocell_310/hashes_sha224.c | 43 ++ .../psa_cryptocell_310/hashes_sha256.c | 42 ++ .../psa_cryptocell_310/hashes_sha512.c | 43 ++ .../psa_cryptocell_310/hmac.c | 58 +++ sys/auto_init/auto_init.c | 11 +- sys/auto_init/include/auto_init_priorities.h | 10 +- 40 files changed, 2241 insertions(+), 6 deletions(-) create mode 100644 cpu/nrf52/periph/Makefile.dep create mode 100644 pkg/driver_cryptocell_310/Kconfig create mode 100644 pkg/driver_cryptocell_310/Makefile create mode 100644 pkg/driver_cryptocell_310/Makefile.dep create mode 100644 pkg/driver_cryptocell_310/Makefile.include create mode 100644 pkg/driver_cryptocell_310/contrib/Makefile create mode 100644 pkg/driver_cryptocell_310/contrib/cryptocell_util.c create mode 100644 pkg/driver_cryptocell_310/doc.txt create mode 100644 pkg/driver_cryptocell_310/driver_cryptocell_310.mk create mode 100644 pkg/driver_cryptocell_310/include/cryptocell_310_util.h create mode 100644 pkg/driver_cryptocell_310/include/psa_cryptocell_310_aes_common.h create mode 100644 pkg/driver_cryptocell_310/include/psa_cryptocell_310_ecc_common.h create mode 100644 pkg/driver_cryptocell_310/include/psa_cryptocell_310_hashes_common.h create mode 100644 pkg/driver_cryptocell_310/include/psa_error.h create mode 100644 pkg/driver_cryptocell_310/include/psa_periph_aes_ctx.h create mode 100644 pkg/driver_cryptocell_310/include/psa_periph_hashes_ctx.h create mode 100644 pkg/driver_cryptocell_310/psa_cryptocell_310/Kconfig create mode 100644 pkg/driver_cryptocell_310/psa_cryptocell_310/Makefile create mode 100644 pkg/driver_cryptocell_310/psa_cryptocell_310/Makefile.dep create mode 100644 pkg/driver_cryptocell_310/psa_cryptocell_310/aes_cbc.c create mode 100644 pkg/driver_cryptocell_310/psa_cryptocell_310/aes_common.c create mode 100644 pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_common.c create mode 100644 pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_p192.c create mode 100644 pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_p256.c create mode 100644 pkg/driver_cryptocell_310/psa_cryptocell_310/error_conversion.c create mode 100644 pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_common.c create mode 100644 pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_sha1.c create mode 100644 pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_sha224.c create mode 100644 pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_sha256.c create mode 100644 pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_sha512.c create mode 100644 pkg/driver_cryptocell_310/psa_cryptocell_310/hmac.c diff --git a/cpu/nrf52/Kconfig b/cpu/nrf52/Kconfig index ae38d8121e..06fc1501be 100644 --- a/cpu/nrf52/Kconfig +++ b/cpu/nrf52/Kconfig @@ -69,6 +69,15 @@ config CPU_MODEL_NRF52840XXAA select HAS_BLE_PHY_CODED select HAS_RADIO_NRF802154 select HAS_PERIPH_UART_NONBLOCKING + select HAS_PERIPH_HASH_SHA_1 + select HAS_PERIPH_HASH_SHA_224 + select HAS_PERIPH_HASH_SHA_256 + select HAS_PERIPH_HASH_SHA_512 + select HAS_PERIPH_HMAC_SHA_256 + select HAS_PERIPH_CIPHER_AES_128_CBC + select HAS_PERIPH_ECC_P192R1 + select HAS_PERIPH_ECC_P256R1 + select HAS_PERIPH_CRYPTOCELL_310 ## CPU common symbols config CPU_FAM diff --git a/cpu/nrf52/Makefile.dep b/cpu/nrf52/Makefile.dep index 6064e77544..9503c70377 100644 --- a/cpu/nrf52/Makefile.dep +++ b/cpu/nrf52/Makefile.dep @@ -36,5 +36,6 @@ ifneq (,$(filter periph_spi,$(USEMODULE))) USEMODULE += periph_spi_gpio_mode endif +include $(RIOTCPU)/nrf52/periph/Makefile.dep include $(RIOTCPU)/nrf5x_common/Makefile.dep include $(RIOTCPU)/cortexm_common/Makefile.dep diff --git a/cpu/nrf52/Makefile.features b/cpu/nrf52/Makefile.features index 52fd4ec7c0..7b8a3755fc 100644 --- a/cpu/nrf52/Makefile.features +++ b/cpu/nrf52/Makefile.features @@ -10,6 +10,18 @@ ifneq (,$(filter nrf52811xxaa nrf52820xxaa nrf52833xxaa nrf52840xxaa,$(CPU_MODEL FEATURES_PROVIDED += radio_nrf802154 endif +# crypto features +ifneq (,$(filter nrf52840xxaa,$(CPU_MODEL))) + FEATURES_PROVIDED += periph_hash_sha_1 + FEATURES_PROVIDED += periph_hash_sha_224 + FEATURES_PROVIDED += periph_hash_sha_256 + FEATURES_PROVIDED += periph_hash_sha_512 + FEATURES_PROVIDED += periph_hmac_sha_256 + FEATURES_PROVIDED += periph_cipher_aes_128_cbc + FEATURES_PROVIDED += periph_ecc_p192r1 + FEATURES_PROVIDED += periph_ecc_p256r1 +endif + ifeq (,$(filter nrf52832%,$(CPU_MODEL))) FEATURES_PROVIDED += periph_uart_nonblocking endif @@ -33,6 +45,10 @@ ifneq (,$(filter nrf52811% nrf52820% nrf52833% nrf52840%,$(CPU_MODEL))) FEATURES_PROVIDED += ble_phy_coded endif +ifneq (,$(filter nrf52840%,$(CPU_MODEL))) + FEATURES_PROVIDED += periph_cryptocell_310 +endif + FEATURES_PROVIDED += ble_adv_ext include $(RIOTCPU)/nrf5x_common/Makefile.features diff --git a/cpu/nrf52/periph/Kconfig b/cpu/nrf52/periph/Kconfig index eed36b152b..ef2100bdf8 100644 --- a/cpu/nrf52/periph/Kconfig +++ b/cpu/nrf52/periph/Kconfig @@ -12,6 +12,61 @@ config MODULE_SAUL_NRF_VDDH depends on HAS_PERIPH_ADC select MODULE_PERIPH_ADC +config MODULE_PERIPH_CRYPTOCELL_310 + bool + depends on HAS_PERIPH_CRYPTOCELL_310 + select PACKAGE_DRIVER_CRYPTOCELL_310 + +# Asymmetric Crypto Peripheral +config MODULE_PERIPH_ECC_P192R1 + bool + depends on HAS_PERIPH_ECC_P192R1 + select MODULE_PERIPH_CRYPTOCELL_310 + select MODULE_PSA_CRYPTOCELL_310_ECC_P192 + +config MODULE_PERIPH_ECC_P256R1 + bool + depends on HAS_PERIPH_ECC_P256R1 + select MODULE_PERIPH_CRYPTOCELL_310 + select MODULE_PSA_CRYPTOCELL_310_ECC_P256 + +# Hash Related Symbols +config MODULE_PERIPH_HASH_SHA_1 + bool + depends on HAS_PERIPH_HASH_SHA_1 + select MODULE_PERIPH_CRYPTOCELL_310 + select MODULE_PSA_CRYPTOCELL_310_HASHES_SHA1 + +config MODULE_PERIPH_HASH_SHA_224 + bool + depends on HAS_PERIPH_HASH_SHA_224 + select MODULE_PERIPH_CRYPTOCELL_310 + select MODULE_PSA_CRYPTOCELL_310_HASHES_SHA224 + +config MODULE_PERIPH_HASH_SHA_256 + bool + depends on HAS_PERIPH_HASH_SHA_256 + select MODULE_PERIPH_CRYPTOCELL_310 + select MODULE_PSA_CRYPTOCELL_310_HASHES_SHA256 + +config MODULE_PERIPH_HASH_SHA_512 + bool + depends on HAS_PERIPH_HASH_SHA_512 + select MODULE_PERIPH_CRYPTOCELL_310 + select MODULE_PSA_CRYPTOCELL_310_HASHES_SHA512 + +config MODULE_PERIPH_CIPHER_AES_128_CBC + bool + depends on HAS_PERIPH_CIPHER_AES_128_CBC + select MODULE_PERIPH_CRYPTOCELL_310 + select MODULE_PSA_CRYPTOCELL_310_AES_CBC + +config MODULE_PERIPH_HMAC_SHA_256 + bool + depends on HAS_PERIPH_HMAC_SHA_256 + select MODULE_PERIPH_CRYPTOCELL_310 + select MODULE_PSA_CRYPTOCELL_310_HMAC + endif # TEST_KCONFIG config HAVE_SAUL_NRF_VDDH diff --git a/cpu/nrf52/periph/Makefile.dep b/cpu/nrf52/periph/Makefile.dep new file mode 100644 index 0000000000..28f2d30fb3 --- /dev/null +++ b/cpu/nrf52/periph/Makefile.dep @@ -0,0 +1,39 @@ +ifneq (,$(filter periph_ecc_p192r1,$(USEMODULE))) + USEPKG += driver_cryptocell_310 + USEMODULE += psa_cryptocell_310_ecc_p192 +endif + +ifneq (,$(filter periph_ecc_p256r1,$(USEMODULE))) + USEPKG += driver_cryptocell_310 + USEMODULE += psa_cryptocell_310_ecc_p256 +endif + +ifneq (,$(filter periph_hash_sha_1,$(USEMODULE))) + USEPKG += driver_cryptocell_310 + USEMODULE += psa_cryptocell_310_hashes_sha1 +endif + +ifneq (,$(filter periph_hash_sha_224,$(USEMODULE))) + USEPKG += driver_cryptocell_310 + USEMODULE += psa_cryptocell_310_hashes_sha224 +endif + +ifneq (,$(filter periph_hash_sha_256,$(USEMODULE))) + USEPKG += driver_cryptocell_310 + USEMODULE += psa_cryptocell_310_hashes_sha256 +endif + +ifneq (,$(filter periph_hash_sha_512,$(USEMODULE))) + USEPKG += driver_cryptocell_310 + USEMODULE += psa_cryptocell_310_hashes_sha512 +endif + +ifneq (,$(filter periph_cipher_aes_128_cbc,$(USEMODULE))) + USEPKG += driver_cryptocell_310 + USEMODULE += psa_cryptocell_310_aes_cbc +endif + +ifneq (,$(filter periph_hmac_sha_256,$(USEMODULE))) + USEPKG += driver_cryptocell_310 + USEMODULE += psa_cryptocell_310_hmac +endif diff --git a/kconfigs/Kconfig.features b/kconfigs/Kconfig.features index d45aa29074..b2314d914e 100644 --- a/kconfigs/Kconfig.features +++ b/kconfigs/Kconfig.features @@ -134,6 +134,11 @@ config HAS_CPU_CHECK_ADDRESS help Indicates that address validity check is supported. +config HAS_PERIPH_CRYPTOCELL_310 + bool + help + Indicates that a cryptocell peripheral is present. + config HAS_DBGPIN bool help @@ -188,6 +193,11 @@ config HAS_PERIPH_CAN help Indicates that a CAN peripheral is present. +config HAS_PERIPH_CIPHER_AES_128_CBC + bool + help + Indicates that there is AES 128 CBC hardware acceleration present + config HAS_PERIPH_CORETIMER bool help @@ -208,6 +218,16 @@ config HAS_PERIPH_DMA help Indicates that a DMA peripheral is present. +config HAS_PERIPH_ECC_P192R1 + bool + help + Indicates that there is ECC P192R1 hardware acceleration peripheral present. + +config HAS_PERIPH_ECC_P256R1 + bool + help + Indicates that there is ECC P256R1 hardware acceleration peripheral present. + config HAS_PERIPH_EEPROM bool help @@ -285,6 +305,36 @@ config HAS_PERIPH_GPIO_LL_IRQ_UNMASK Indicates that the GPIO peripheral supports unmasking interrupts without clearing pending IRQs that came in while masked. +config HAS_PERIPH_HASH_MD5 + bool + help + Indicates that there is MD5 hardware acceleration present. + +config HAS_PERIPH_HASH_SHA_1 + bool + help + Indicates that there is SHA-1 hardware acceleration present. + +config HAS_PERIPH_HASH_SHA_224 + bool + help + Indicates that there is SHA-224 hardware acceleration present. + +config HAS_PERIPH_HASH_SHA_256 + bool + help + Indicates that there is SHA-256 hardware acceleration present. + +config HAS_PERIPH_HASH_SHA_512 + bool + help + Indicates that there is SHA-512 hardware acceleration present. + +config HAS_PERIPH_HMAC_SHA_256 + bool + help + Indicates that there is HMAC SHA-256 hardware acceleration present. + config HAS_PERIPH_HWRNG bool help diff --git a/makefiles/features_modules.inc.mk b/makefiles/features_modules.inc.mk index 2586c4682a..a45e4cbf88 100644 --- a/makefiles/features_modules.inc.mk +++ b/makefiles/features_modules.inc.mk @@ -11,9 +11,13 @@ USEMODULE += $(PERIPH_FEATURES) # Add all USED periph_% init modules unless they are blacklisted PERIPH_IGNORE_MODULES := \ + periph_cipher_aes_128_cbc \ periph_clic \ periph_common \ periph_coretimer \ + periph_cryptocell_310 \ + periph_ecc_p192r1 \ + periph_ecc_p256r1 \ periph_eth \ periph_eth_common \ periph_flash \ @@ -25,6 +29,11 @@ PERIPH_IGNORE_MODULES := \ periph_gpio_ll_irq_level_triggered_low \ periph_gpio_ll_irq_unmask \ periph_gpio_mux \ + periph_hash_sha_1 \ + periph_hash_sha_224 \ + periph_hash_sha_256 \ + periph_hash_sha_512 \ + periph_hmac_sha_256 \ periph_i2c_hw \ periph_i2c_sw \ periph_init% \ diff --git a/pkg/Kconfig b/pkg/Kconfig index c2d0e8d7ef..537594aa57 100644 --- a/pkg/Kconfig +++ b/pkg/Kconfig @@ -17,6 +17,7 @@ rsource "corejson/Kconfig" rsource "cryptoauthlib/Kconfig" rsource "driver_atwinc15x0/Kconfig" rsource "driver_bme680/Kconfig" +rsource "driver_cryptocell_310/Kconfig" rsource "driver_sx126x/Kconfig" rsource "elk/Kconfig" rsource "emlearn/Kconfig" diff --git a/pkg/driver_cryptocell_310/Kconfig b/pkg/driver_cryptocell_310/Kconfig new file mode 100644 index 0000000000..411982bfc4 --- /dev/null +++ b/pkg/driver_cryptocell_310/Kconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2020 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 PACKAGE_DRIVER_CRYPTOCELL_310 + bool + depends on CPU_MODEL_NRF52840XXAA + depends on TEST_KCONFIG + depends on HAS_PERIPH_CRYPTOCELL_310 + depends on MODULE_PERIPH_CRYPTOCELL_310 + select MODULE_DRIVER_CRYPTOCELL_310_CONTRIB + +config MODULE_DRIVER_CRYPTOCELL_310_CONTRIB + bool + +rsource "psa_cryptocell_310/Kconfig" diff --git a/pkg/driver_cryptocell_310/Makefile b/pkg/driver_cryptocell_310/Makefile new file mode 100644 index 0000000000..43f5d2338e --- /dev/null +++ b/pkg/driver_cryptocell_310/Makefile @@ -0,0 +1,36 @@ +PKG_NAME=driver_cryptocell_310 +PKG_URL=https://www.nordicsemi.com/-/media/Software-and-other-downloads/SDKs/nRF5/Binaries +PKG_VERSION=17.1.0 +PKG_EXT=zip +PKG_DIR_NAME=nRF5_SDK_17.1.0_ddde560 +PKG_LICENSE=ARM Object Code and Header Files License + +PKG_SOURCE_DIR ?= $(PKGDIRBASE)/$(PKG_NAME) +NRF_CC310_PATH = $(PKG_DIR_NAME)/external/nrf_cc310 +PKG_ZIPFILE = $(PKG_DIR_NAME).$(PKG_EXT) + +ifneq ($(RIOTBASE),) +include $(RIOTBASE)/Makefile.base +endif + +.PHONY: all clean distclean prepare + +prepare: $(PKG_PREPARED) + @: + +all: $(PKGDIRBASE)/$(PKG_ZIPFILE) + $(Q)$(UNZIP_HERE) -D -n -d $(PKGDIRBASE) $(PKGDIRBASE)/$(PKG_ZIPFILE) + $(Q) mkdir -p $(PKG_SOURCE_DIR)/include + $(Q)cp $(PKGDIRBASE)/$(NRF_CC310_PATH)/include/* $(PKG_SOURCE_DIR)/include + $(Q)cp $(PKGDIRBASE)/$(NRF_CC310_PATH)/lib/cortex-m4/hard-float/libnrf_cc310_0.9.13.a $(PKG_SOURCE_DIR) + $(Q)rm -rf $(PKGDIRBASE)/$(PKG_DIR_NAME) + +$(PKGDIRBASE)/$(PKG_ZIPFILE): + $(QQ)mkdir -p $(PKGDIRBASE) + $(Q)$(DOWNLOAD_TO_FILE) $(PKGDIRBASE)/$(PKG_ZIPFILE) $(PKG_URL)/$(PKG_ZIPFILE) + +clean:: + rm -rf $(PKG_SOURCE_DIR) + +distclean:: + rm -rf $(PKG_SOURCE_DIR) $(PKGDIRBASE)/$(PKG_ZIPFILE) diff --git a/pkg/driver_cryptocell_310/Makefile.dep b/pkg/driver_cryptocell_310/Makefile.dep new file mode 100644 index 0000000000..71b6dec28b --- /dev/null +++ b/pkg/driver_cryptocell_310/Makefile.dep @@ -0,0 +1,6 @@ +USEMODULE += driver_cryptocell_310_contrib +FEATURES_REQUIRED += periph_cryptocell_310 + +ifneq (,$(filter psa_cryptocell_310_%,$(USEMODULE))) + include $(RIOTPKG)/driver_cryptocell_310/psa_cryptocell_310/Makefile.dep +endif diff --git a/pkg/driver_cryptocell_310/Makefile.include b/pkg/driver_cryptocell_310/Makefile.include new file mode 100644 index 0000000000..dfcc0d2767 --- /dev/null +++ b/pkg/driver_cryptocell_310/Makefile.include @@ -0,0 +1,25 @@ +INCLUDES += -I$(PKGDIRBASE)/driver_cryptocell_310/include +INCLUDES += -I$(RIOTPKG)/driver_cryptocell_310/include +DIRS += $(RIOTPKG)/driver_cryptocell_310/contrib + +ARCHIVES += $(PKGDIRBASE)/driver_cryptocell_310/libnrf_cc310_0.9.13.a + +ifneq (,$(filter psa_cryptocell_310_%, $(USEMODULE))) + DIRS += $(RIOTPKG)/driver_cryptocell_310/psa_cryptocell_310 + INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include +endif + +CFLAGS += -Wno-cast-align + +PSEUDOMODULES += psa_cryptocell_310_aes_cbc +PSEUDOMODULES += psa_cryptocell_310_aes_common +PSEUDOMODULES += psa_cryptocell_310_ecc_common +PSEUDOMODULES += psa_cryptocell_310_ecc_p192 +PSEUDOMODULES += psa_cryptocell_310_ecc_p256 +PSEUDOMODULES += psa_cryptocell_310_error_conversion +PSEUDOMODULES += psa_cryptocell_310_hashes_common +PSEUDOMODULES += psa_cryptocell_310_hashes_sha1 +PSEUDOMODULES += psa_cryptocell_310_hashes_sha224 +PSEUDOMODULES += psa_cryptocell_310_hashes_sha256 +PSEUDOMODULES += psa_cryptocell_310_hashes_sha512 +PSEUDOMODULES += psa_cryptocell_310_hmac diff --git a/pkg/driver_cryptocell_310/contrib/Makefile b/pkg/driver_cryptocell_310/contrib/Makefile new file mode 100644 index 0000000000..337ea09f1b --- /dev/null +++ b/pkg/driver_cryptocell_310/contrib/Makefile @@ -0,0 +1,3 @@ +MODULE = driver_cryptocell_310_contrib + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/driver_cryptocell_310/contrib/cryptocell_util.c b/pkg/driver_cryptocell_310/contrib/cryptocell_util.c new file mode 100644 index 0000000000..2a20241db3 --- /dev/null +++ b/pkg/driver_cryptocell_310/contrib/cryptocell_util.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2020 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 pkg_driver_cryptocell_310 + * @{ + * + * @file + * @brief Setup function necessary to enable ARM CryptoCell module + * + * @author Lena Boeckmann + */ + +#include "vendor/nrf52840.h" +#include "sns_silib.h" +#include "kernel_defines.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +CRYS_RND_WorkBuff_t *rndWorkBuff_ptr; +CRYS_RND_State_t *rndState_ptr; + +CRYS_RND_State_t rndState = { 0 }; +CRYS_RND_WorkBuff_t rndWorkBuff = { 0 }; + +/* Defined by the CryptoCell Library */ +extern void CRYPTOCELL_IRQHandler(void); + +/* This function must be defined to use the CryptoCell module on the NRF52840 board */ +void isr_cryptocell(void) +{ + CRYPTOCELL_IRQHandler(); +} + +void cryptocell_310_enable(void) +{ + NRF_CRYPTOCELL->ENABLE = 1; + NVIC_EnableIRQ(CRYPTOCELL_IRQn); +} + +void cryptocell_310_disable(void) +{ + NRF_CRYPTOCELL->ENABLE = 0; + NVIC_DisableIRQ(CRYPTOCELL_IRQn); +} + +void driver_cryptocell_310_setup(void) +{ + int ret = 0; + + rndState_ptr = &rndState; + rndWorkBuff_ptr = &rndWorkBuff; + + cryptocell_310_enable(); + + ret = SaSi_LibInit(); + if (ret != SA_SILIB_RET_OK) { + DEBUG("SaSi_LibInit failed: 0x%x\n", ret); + } + + ret = CRYS_RndInit(rndState_ptr, rndWorkBuff_ptr); + if (ret != SA_SILIB_RET_OK) { + DEBUG("CRYS_RndInit failed: 0x%x\n", ret); + } +} + +void driver_cryptocell_310_terminate(void) +{ + int ret = 0; + + SaSi_LibFini(); + + ret = CRYS_RND_UnInstantiation(rndState_ptr); + if (ret != SA_SILIB_RET_OK) { + DEBUG("CRYS_RND_UnInstatiation failed: 0x%x\n", ret); + } +} diff --git a/pkg/driver_cryptocell_310/doc.txt b/pkg/driver_cryptocell_310/doc.txt new file mode 100644 index 0000000000..71a8804ef9 --- /dev/null +++ b/pkg/driver_cryptocell_310/doc.txt @@ -0,0 +1,10 @@ +/** + * @defgroup pkg_driver_cryptocell_310 ARM CryptoCell 310 Driver + * @ingroup pkg drivers_misc + * @brief Provides the driver for the ARM CryptoCell 310 hardware accelerator + * @see https://infocenter.nordicsemi.com/topic/sdk_nrf5_v17.1.0/group__cryptocell__api.html + * + * @note The source of this package is not a git repository, but a zip file downloaded + * from the Nordic Semiconductor software center. It is quite large and takes a + * while to download. + */ diff --git a/pkg/driver_cryptocell_310/driver_cryptocell_310.mk b/pkg/driver_cryptocell_310/driver_cryptocell_310.mk new file mode 100644 index 0000000000..5836b5137f --- /dev/null +++ b/pkg/driver_cryptocell_310/driver_cryptocell_310.mk @@ -0,0 +1,3 @@ +MODULE = driver_cryptocell_310 + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/driver_cryptocell_310/include/cryptocell_310_util.h b/pkg/driver_cryptocell_310/include/cryptocell_310_util.h new file mode 100644 index 0000000000..4040eb8f13 --- /dev/null +++ b/pkg/driver_cryptocell_310/include/cryptocell_310_util.h @@ -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. + */ + +/** + * @ingroup pkg_driver_cryptocell_310 + * @{ + * + * @file + * @brief Utility functions to setup and terminate the CryptoCell 310 driver + * + * @author Lena Boeckmann + * + */ +#ifndef CRYPTOCELL_310_UTIL_H +#define CRYPTOCELL_310_UTIL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Enable CryptoCell module and IRQs. + * + * Must be called before using crypto functions. + * CryptoCell peripheral will be enabled after this call. + */ +void cryptocell_310_enable(void); + +/** + * @brief Disable CryptoCell module and IRQs. + * + * Should be called after using crypto functions. + * CryptoCell peripheral will be disabled after this call. + */ +void cryptocell_310_disable(void); + +/** + * @brief Enables CryptoCell module, IRQs and crypto libraries on nrf52840. + * + * Must be called once before using the CryptoCell lib. + */ +void driver_cryptocell_310_setup(void); + +/** + * @brief Finishes the use of the CryptoCell library. + * + * Should be called after using the CryptoCell lib. + */ +void driver_cryptocell_310_terminate(void); + +#ifdef __cplusplus +} +#endif + +#endif /* CRYPTOCELL_310_UTIL_H */ +/** @} */ diff --git a/pkg/driver_cryptocell_310/include/psa_cryptocell_310_aes_common.h b/pkg/driver_cryptocell_310/include/psa_cryptocell_310_aes_common.h new file mode 100644 index 0000000000..400e90d4b4 --- /dev/null +++ b/pkg/driver_cryptocell_310/include/psa_cryptocell_310_aes_common.h @@ -0,0 +1,73 @@ +/* + * 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 pkg_driver_cryptocell_310 + * @{ + * + * @file + * @brief Common AES functions used by all PSA Crypto wrappers + * for the CryptoCell 310 AES APIs. + * + * @author Lena Boeckmann + * + */ + +#ifndef PSA_CRYPTOCELL_310_AES_COMMON_H +#define PSA_CRYPTOCELL_310_AES_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "psa/crypto.h" + +/** + * @brief Common setup function for AES operations + * + * @param ctx Driver specific AES context of the type @c SaSiAesUserContext_t + * @param direction Encrypt or decrypt direction of type @c SaSiAesEncryptMode_t + * @param mode Operation mode (e.g. CBC, CCM) of type @c SaSiAesOperationMode_t + * @param padding Operation padding type of type @c SaSiAesPaddingType_t + * @param iv Constant buffer containing the IV for the operation + * @param key_buffer Constant buffer containing an AES key + * @param key_size Size of AES key in use. + * @return psa_status_t + */ +psa_status_t cryptocell_310_common_aes_setup(SaSiAesUserContext_t *ctx, + SaSiAesEncryptMode_t direction, + SaSiAesOperationMode_t mode, + SaSiAesPaddingType_t padding, + const uint8_t *iv, + const uint8_t *key_buffer, + size_t key_size); + +/** + * @brief Common function for an AES encryption + * + * @param ctx AES context of the type @c SaSiAesUserContext_t + * @param input Constant input buffer of plain text to encrypt + * @param input_length Length of the input buffer + * @param output Output buffer to write the cipher + * @param output_buffer_size Size of the output buffer. Must be at least @c input_length + * @param output_length Pointer to output length. Will contain actual length of cipher + * @return psa_status_t + */ +psa_status_t cryptocell_310_common_aes_encrypt_decrypt(SaSiAesUserContext_t *ctx, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_buffer_size, + size_t *output_length); + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTOCELL_310_AES_COMMON_H */ +/** @} */ diff --git a/pkg/driver_cryptocell_310/include/psa_cryptocell_310_ecc_common.h b/pkg/driver_cryptocell_310/include/psa_cryptocell_310_ecc_common.h new file mode 100644 index 0000000000..d3e1cc6478 --- /dev/null +++ b/pkg/driver_cryptocell_310/include/psa_cryptocell_310_ecc_common.h @@ -0,0 +1,115 @@ +/* + * 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 pkg_driver_cryptocell_310 + * @{ + * + * @file + * @brief Common ECC functions used by all PSA Crypto wrappers + * for the CryptoCell 310 ECC APIs. + * + * @author Lena Boeckmann + * + */ + +#ifndef PSA_CRYPTOCELL_310_ECC_COMMON_H +#define PSA_CRYPTOCELL_310_ECC_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "psa/crypto.h" + +#include "sns_silib.h" +#include "crys_ecpki_build.h" +#include "crys_ecpki_ecdsa.h" +#include "crys_ecpki_kg.h" +#include "crys_ecpki_domain.h" + +/** + * @brief Map PSA hash encodings to CryptoCell specific hash encodings + * + * @param hash psa_algorithm_t + */ +#define MAP_PSA_HASH_TO_CRYS_HASH(hash) \ + ((hash == PSA_ALG_SHA_1) ? CRYS_ECPKI_AFTER_HASH_SHA1_mode : \ + (hash == PSA_ALG_SHA_224) ? CRYS_ECPKI_AFTER_HASH_SHA224_mode : \ + (hash == PSA_ALG_SHA_256) ? CRYS_ECPKI_AFTER_HASH_SHA256_mode : \ + (hash == PSA_ALG_SHA_384) ? CRYS_ECPKI_AFTER_HASH_SHA384_mode : \ + (hash == PSA_ALG_SHA_512) ? CRYS_ECPKI_AFTER_HASH_SHA512_mode : \ + 0) + +/** + * @brief Common ECC key generation function + * + * @param priv_key_buffer Output buffer to write ECC private key + * @param pub_key_buffer Output buffer to write ECC public key + * @param priv_key_buffer_length Output pointer to write private key length + * @param pub_key_buffer_length Output pointer to write public key length + * @param domain ECC domain of type @c CRYS_ECPKI_DomainID_t + * @return psa_status_t + */ +psa_status_t cryptocell_310_common_ecc_generate_key_pair(uint8_t *priv_key_buffer, + uint8_t *pub_key_buffer, + uint32_t *priv_key_buffer_length, + uint32_t *pub_key_buffer_length, + CRYS_ECPKI_DomainID_t domain); + +/** + * @brief Common ECC hash signature function + * + * @param priv_key Pointer to ECC private key + * @param priv_key_size Size of private key + * @param hash Hash of the message to sign + * @param hash_length Length of the message hash + * @param signature Output buffer to write the generated signature + * @param signature_length Pointer to store the actual length of the signature + * @param hash_mode Mode used to hash the message of type @c CRYS_ECPKI_HASH_OpMode_t + * @param domain ECC domain of type @c CRYS_ECPKI_DomainID_t + * @return psa_status_t + */ +psa_status_t cryptocell_310_common_ecc_sign_hash(const uint8_t *priv_key, + uint32_t priv_key_size, + const uint8_t *hash, + size_t hash_length, + uint8_t *signature, + size_t *signature_length, + CRYS_ECPKI_HASH_OpMode_t hash_mode, + CRYS_ECPKI_DomainID_t domain); + +/** + * @brief Common ECC hash verification function + * + * @param pub_key Pointer to ECC public key + * @param pub_key_size Size of public key + * @param hash Hash of the message to sign + * @param hash_length Length of the message hash + * @param signature Buffer containing the signature to be verified + * @param signature_length Actual length of the signature + * @param hash_mode Mode used to hash the message of type + * @c CRYS_ECPKI_HASH_OpMode_t + * @param domain ECC domain of type @c CRYS_ECPKI_DomainID_t + * @return psa_status_t + */ +psa_status_t cryptocell_310_common_ecc_verify_hash(const uint8_t *pub_key, + size_t pub_key_size, + const uint8_t *hash, + size_t hash_length, + const uint8_t *signature, + size_t signature_length, + CRYS_ECPKI_HASH_OpMode_t hash_mode, + CRYS_ECPKI_DomainID_t domain); + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTOCELL_310_ECC_COMMON_H */ +/** @} */ diff --git a/pkg/driver_cryptocell_310/include/psa_cryptocell_310_hashes_common.h b/pkg/driver_cryptocell_310/include/psa_cryptocell_310_hashes_common.h new file mode 100644 index 0000000000..aeb3a25443 --- /dev/null +++ b/pkg/driver_cryptocell_310/include/psa_cryptocell_310_hashes_common.h @@ -0,0 +1,71 @@ +/* + * 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 pkg_driver_cryptocell_310 + * @{ + * + * @file + * @brief Common hash functions used by all PSA Crypto wrappers + * for the CryptoCell 310 hash APIs. + * + * @author Lena Boeckmann + * + */ +#ifndef PSA_CRYPTOCELL_310_HASHES_COMMON_H +#define PSA_CRYPTOCELL_310_HASHES_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "psa/crypto.h" +#include "crys_hash.h" + +/** + * @brief Common hash setup function + * + * @param ctx Driver specific hash context of type @c CRYS_HASHUserContext_t + * @param mode Hash mode of type @c CRYS_HASH_OperationMode_t + * @return psa_status_t + */ +psa_status_t cryptocell_310_common_hash_setup(CRYS_HASHUserContext_t *ctx, + CRYS_HASH_OperationMode_t mode); + +/** + * @brief Common hash update function + * + * @param ctx Driver specific hash context of type @c CRYS_HASHUserContext_t + * @param input Input that is going to be hashed + * @param input_length Length of @p input + * @return psa_status_t + */ +psa_status_t cryptocell_310_common_hash_update(CRYS_HASHUserContext_t *ctx, + const uint8_t *input, + size_t input_length); + +/** + * @brief Common hash finish function + * + * @param ctx Driver specific hash context of type @c CRYS_HASHUserContext_t + * @param hash Output buffer to write the computated hash + * @param hash_size Size of @p hash + * @param hash_length Pointer where the actual length of the hash will be stored + * @return psa_status_t + */ +psa_status_t cryptocell_310_common_hash_finish(CRYS_HASHUserContext_t *ctx, + uint8_t *hash, + size_t hash_size, + size_t *hash_length); + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTOCELL_310_HASHES_COMMON_H */ +/** @} */ diff --git a/pkg/driver_cryptocell_310/include/psa_error.h b/pkg/driver_cryptocell_310/include/psa_error.h new file mode 100644 index 0000000000..31fa7e361d --- /dev/null +++ b/pkg/driver_cryptocell_310/include/psa_error.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 pkg_driver_cryptocell_310 + * @{ + * + * @file + * @brief Glue code translating between PSA Crypto and the CryptoCell 310 driver APIs + * + * @author Lena Boeckmann + * + */ +#ifndef PSA_ERROR_H +#define PSA_ERROR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "psa/crypto.h" +#include "crys_ecpki_error.h" +#include "crys_hash_error.h" +#include "ssi_aes_error.h" + +/** + * @brief Convert CryptoCell CRYS errors to PSA status values + * + * @param error Error value of type @c CRYSError_t + * @return @ref psa_status_t + */ +psa_status_t CRYS_to_psa_error(CRYSError_t error); + +/** + * @brief Convert CryptoCell SaSi errors to PSA status values + * + * @param error Error value of type @c SaSiStatus + * @return @ref psa_status_t + */ +psa_status_t SaSi_to_psa_error(SaSiStatus error); + +/** + * @brief Function to print CryptoCell Error values in clear text. + * + * @param status Error value of type @c SaSiStatus or @c CRYSError_t + * @return const char* + */ +const char *cryptocell310_status_to_humanly_readable(uint32_t status); + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_ERROR_H */ +/** @} */ diff --git a/pkg/driver_cryptocell_310/include/psa_periph_aes_ctx.h b/pkg/driver_cryptocell_310/include/psa_periph_aes_ctx.h new file mode 100644 index 0000000000..ce0f7360c6 --- /dev/null +++ b/pkg/driver_cryptocell_310/include/psa_periph_aes_ctx.h @@ -0,0 +1,41 @@ +/* + * 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 pkg_driver_cryptocell_310 + * @{ + * + * @file + * @brief CryptoCell 310 driver specific AES contexts + * + * @author Lena Boeckmann + * + */ +#ifndef PSA_PERIPH_AES_CTX_H +#define PSA_PERIPH_AES_CTX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ssi_aes.h" +#include "kernel_defines.h" + +#if IS_USED(MODULE_PERIPH_CIPHER_AES_128_CBC) || DOXYGEN +/** + * @brief Map driver specific AES context to PSA context + */ +typedef SaSiAesUserContext_t psa_cipher_aes_128_ctx_t; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_PERIPH_AES_CTX_H */ +/** @} */ diff --git a/pkg/driver_cryptocell_310/include/psa_periph_hashes_ctx.h b/pkg/driver_cryptocell_310/include/psa_periph_hashes_ctx.h new file mode 100644 index 0000000000..c4e5f74b6e --- /dev/null +++ b/pkg/driver_cryptocell_310/include/psa_periph_hashes_ctx.h @@ -0,0 +1,64 @@ +/* + * 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 pkg_driver_cryptocell_310 + * @{ + * + * @file + * @brief CryptoCell 310 driver specific hash contexts + * + * @author Lena Boeckmann + * + */ + +#ifndef PSA_PERIPH_HASHES_CTX_H +#define PSA_PERIPH_HASHES_CTX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "kernel_defines.h" +#include "crys_hash.h" + +#if IS_USED(MODULE_PERIPH_HASH_SHA_1) || DOXYGEN +/** + * @brief Map driver specific SHA1 context to PSA context + */ +typedef CRYS_HASHUserContext_t psa_hashes_sha1_ctx_t; +#endif + +#if IS_USED(MODULE_PERIPH_HASH_SHA_224) || DOXYGEN +/** + * @brief Map driver specific SHA224 context to PSA context + */ +typedef CRYS_HASHUserContext_t psa_hashes_sha224_ctx_t; +#endif + +#if IS_USED(MODULE_PERIPH_HASH_SHA_256) || DOXYGEN +/** + * @brief Map driver specific SHA256 context to PSA context + */ +typedef CRYS_HASHUserContext_t psa_hashes_sha256_ctx_t; +#endif + +#if IS_USED(MODULE_PERIPH_HASH_SHA_512) || DOXYGEN +/** + * @brief Map driver specific SHA512 context to PSA context + */ +typedef CRYS_HASHUserContext_t psa_hashes_sha512_ctx_t; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_PERIPH_HASHES_CTX_H */ +/** @} */ diff --git a/pkg/driver_cryptocell_310/psa_cryptocell_310/Kconfig b/pkg/driver_cryptocell_310/psa_cryptocell_310/Kconfig new file mode 100644 index 0000000000..f3d167dca0 --- /dev/null +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/Kconfig @@ -0,0 +1,77 @@ +# 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. +# + +# Hashes + +config MODULE_PSA_CRYPTOCELL_310_HASHES_SHA1 + bool + depends on MODULE_PSA_CRYPTO + select MODULE_PSA_CRYPTOCELL_310 + select MODULE_PSA_CRYPTOCELL_310_HASHES_COMMON + +config MODULE_PSA_CRYPTOCELL_310_HASHES_SHA224 + bool + depends on MODULE_PSA_CRYPTO + select MODULE_PSA_CRYPTOCELL_310 + select MODULE_PSA_CRYPTOCELL_310_HASHES_COMMON + +config MODULE_PSA_CRYPTOCELL_310_HASHES_SHA256 + bool + depends on MODULE_PSA_CRYPTO + select MODULE_PSA_CRYPTOCELL_310 + select MODULE_PSA_CRYPTOCELL_310_HASHES_COMMON + +config MODULE_PSA_CRYPTOCELL_310_HASHES_SHA512 + bool + depends on MODULE_PSA_CRYPTO + select MODULE_PSA_CRYPTOCELL_310 + select MODULE_PSA_CRYPTOCELL_310_HASHES_COMMON + +# MAC + +config MODULE_PSA_CRYPTOCELL_310_HMAC + bool + depends on MODULE_PSA_CRYPTO + select MODULE_PSA_CRYPTOCELL_310 + +# AES + +config MODULE_PSA_CRYPTOCELL_310_AES_CBC + bool + depends on MODULE_PSA_CRYPTO + select MODULE_PSA_CRYPTOCELL_310 + select MODULE_PSA_CRYPTOCELL_310_AES_COMMON + +# ECC + +config MODULE_PSA_CRYPTOCELL_310_ECC_P192 + bool + depends on MODULE_PSA_CRYPTO + select MODULE_PSA_CRYPTOCELL_310 + select MODULE_PSA_CRYPTOCELL_310_ECC_COMMON + +config MODULE_PSA_CRYPTOCELL_310_ECC_P256 + bool + depends on MODULE_PSA_CRYPTO + select MODULE_PSA_CRYPTOCELL_310 + select MODULE_PSA_CRYPTOCELL_310_ECC_COMMON + +config MODULE_PSA_CRYPTOCELL_310 + bool "PSA CryptoCell Wrapper" + select MODULE_PSA_CRYPTOCELL_310_ERROR_CONVERSION + +config MODULE_PSA_CRYPTOCELL_310_HASHES_COMMON + bool + +config MODULE_PSA_CRYPTOCELL_310_ECC_COMMON + bool + +config MODULE_PSA_CRYPTOCELL_310_AES_COMMON + bool + +config MODULE_PSA_CRYPTOCELL_310_ERROR_CONVERSION + bool diff --git a/pkg/driver_cryptocell_310/psa_cryptocell_310/Makefile b/pkg/driver_cryptocell_310/psa_cryptocell_310/Makefile new file mode 100644 index 0000000000..427f531eff --- /dev/null +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/Makefile @@ -0,0 +1,4 @@ +BASE_MODULE := psa_cryptocell_310 +SUBMODULES := 1 + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/driver_cryptocell_310/psa_cryptocell_310/Makefile.dep b/pkg/driver_cryptocell_310/psa_cryptocell_310/Makefile.dep new file mode 100644 index 0000000000..fd18dfb6bd --- /dev/null +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/Makefile.dep @@ -0,0 +1,30 @@ +USEMODULE += psa_cryptocell_310 +USEMODULE += psa_cryptocell_310_error_conversion + +ifneq (,$(filter psa_cryptocell_310_hashes_sha1,$(USEMODULE))) + USEMODULE += psa_cryptocell_310_hashes_common +endif + +ifneq (,$(filter psa_cryptocell_310_hashes_sha224,$(USEMODULE))) + USEMODULE += psa_cryptocell_310_hashes_common +endif + +ifneq (,$(filter psa_cryptocell_310_hashes_sha256,$(USEMODULE))) + USEMODULE += psa_cryptocell_310_hashes_common +endif + +ifneq (,$(filter psa_cryptocell_310_hashes_sha512,$(USEMODULE))) + USEMODULE += psa_cryptocell_310_hashes_common +endif + +ifneq (,$(filter psa_cryptocell_310_aes_cbc,$(USEMODULE))) + USEMODULE += psa_cryptocell_310_aes_common +endif + +ifneq (,$(filter psa_cryptocell_310_ecc_p192,$(USEMODULE))) + USEMODULE += psa_cryptocell_310_ecc_common +endif + +ifneq (,$(filter psa_cryptocell_310_ecc_p256,$(USEMODULE))) + USEMODULE += psa_cryptocell_310_ecc_common +endif diff --git a/pkg/driver_cryptocell_310/psa_cryptocell_310/aes_cbc.c b/pkg/driver_cryptocell_310/psa_cryptocell_310/aes_cbc.c new file mode 100644 index 0000000000..233e2a47e8 --- /dev/null +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/aes_cbc.c @@ -0,0 +1,131 @@ +/* + * 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 pkg_driver_cryptocell_310 + * @{ + * + * @brief Glue code translating between PSA Crypto and the CryptoCell 310 AES 128 CBC APIs + * + * @author Lena Boeckmann + * + * @} + */ + +#include "psa_error.h" +#include "psa_cryptocell_310_aes_common.h" +#include "ssi_aes.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +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) +{ + if ((alg != PSA_ALG_CBC_PKCS7) && (alg != PSA_ALG_CBC_NO_PADDING)) { + DEBUG("%s : Invalid CBC padding type\n", __FILE__); + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (key_buffer_size < PSA_BITS_TO_BYTES(attributes->bits)) { + DEBUG("%s : Key buffer too small\n", __FILE__); + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + size_t iv_length = 0; + size_t key_size = PSA_BITS_TO_BYTES(attributes->bits); + + psa_cipher_operation_t operation = psa_cipher_operation_init(); + operation.iv_required = 1; + operation.default_iv_length = PSA_CIPHER_IV_LENGTH(attributes->type, alg); + + SaSiAesPaddingType_t padding = + (alg == PSA_ALG_CBC_PKCS7) ? SASI_AES_PADDING_PKCS7 : SASI_AES_PADDING_NONE; + + status = psa_cipher_generate_iv(&operation, output, operation.default_iv_length, &iv_length); + if (status != PSA_SUCCESS) { + return status; + } + + status = cryptocell_310_common_aes_setup((SaSiAesUserContext_t *)&operation.backend_ctx.cipher_ctx.aes_128, + SASI_AES_ENCRYPT, SASI_AES_MODE_CBC, padding, output, key_buffer, + key_size); + if (status != PSA_SUCCESS) { + return status; + } + + status = cryptocell_310_common_aes_encrypt_decrypt( + (SaSiAesUserContext_t *)&operation.backend_ctx.cipher_ctx.aes_128, + input, input_length, output + iv_length, output_size - iv_length, + output_length); + if (status != PSA_SUCCESS) { + return status; + } + + *output_length = output_size; + + return PSA_SUCCESS; +} + +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) +{ + if ((alg != PSA_ALG_CBC_PKCS7) && (alg != PSA_ALG_CBC_NO_PADDING)) { + DEBUG("%s : Invalid CBC padding type\n", __FILE__); + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (key_buffer_size < PSA_BITS_TO_BYTES(attributes->bits)) { + DEBUG("%s : Key buffer too small\n", __FILE__); + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + size_t key_size = PSA_BITS_TO_BYTES(attributes->bits); + + psa_cipher_operation_t operation = psa_cipher_operation_init(); + operation.iv_required = 1; + operation.default_iv_length = PSA_CIPHER_IV_LENGTH(attributes->type, alg); + + SaSiAesPaddingType_t padding = + (alg == PSA_ALG_CBC_PKCS7) ? SASI_AES_PADDING_PKCS7 : SASI_AES_PADDING_NONE; + + status = cryptocell_310_common_aes_setup((SaSiAesUserContext_t *)&operation.backend_ctx.cipher_ctx.aes_128, + SASI_AES_DECRYPT, SASI_AES_MODE_CBC, padding, input, key_buffer, + key_size); + if (status != PSA_SUCCESS) { + return status; + } + + status = cryptocell_310_common_aes_encrypt_decrypt( + (SaSiAesUserContext_t *)&operation.backend_ctx.cipher_ctx.aes_128, + input + operation.default_iv_length, input_length - operation. + default_iv_length, output, output_size, output_length); + if (status != PSA_SUCCESS) { + return status; + } + + *output_length = PSA_CIPHER_DECRYPT_OUTPUT_SIZE(attributes->type, alg, input_length); + + return PSA_SUCCESS; +} diff --git a/pkg/driver_cryptocell_310/psa_cryptocell_310/aes_common.c b/pkg/driver_cryptocell_310/psa_cryptocell_310/aes_common.c new file mode 100644 index 0000000000..c782cf09b7 --- /dev/null +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/aes_common.c @@ -0,0 +1,112 @@ +/* + * 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 pkg_driver_cryptocell_310 + * @{ + * + * @brief Common AES functions used by all PSA Crypto wrappers + * for the CryptoCell 310 AES APIs. + * + * @author Lena Boeckmann + * + * @} + */ + +#include "psa/crypto.h" +#include "vendor/nrf52840.h" +#include "ssi_aes.h" +#include "sns_silib.h" +#include "psa_error.h" +#include "cryptocell_310_util.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +#define CC310_MAX_AES_INPUT_BLOCK (0xFFF0) + +psa_status_t cryptocell_310_common_aes_setup(SaSiAesUserContext_t *ctx, + SaSiAesEncryptMode_t direction, + SaSiAesOperationMode_t mode, + SaSiAesPaddingType_t padding, + const uint8_t *iv, + const uint8_t *key_buffer, + size_t key_size) +{ + SaSiAesUserKeyData_t key; + + SaSiStatus ret = SaSi_AesInit(ctx, direction, mode, padding); + if (ret != SASI_OK) { + DEBUG("SaSi_AesInit failed with %s\n", cryptocell310_status_to_humanly_readable(ret)); + return SaSi_to_psa_error(ret); + } + + key.keySize = key_size; + key.pKey = (uint8_t *)key_buffer; + + ret = SaSi_AesSetKey(ctx, SASI_AES_USER_KEY, &key, sizeof(key)); + if (ret != SASI_OK) { + DEBUG("SaSi_AesSetKey failed with %s\n", cryptocell310_status_to_humanly_readable(ret)); + return SaSi_to_psa_error(ret); + } + + ret = SaSi_AesSetIv(ctx, (uint8_t *)iv); + if (ret != SASI_OK) { + DEBUG("SaSi_AesSetIv failed with %s\n", cryptocell310_status_to_humanly_readable(ret)); + return SaSi_to_psa_error(ret); + } + + return PSA_SUCCESS; +} + +psa_status_t cryptocell_310_common_aes_encrypt_decrypt(SaSiAesUserContext_t *ctx, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + SaSiStatus ret = 0; + size_t offset = 0; + size_t size; + size_t length = input_length; + *output_length = output_size; + + do { + if (length > CC310_MAX_AES_INPUT_BLOCK) { + size = CC310_MAX_AES_INPUT_BLOCK; + length -= CC310_MAX_AES_INPUT_BLOCK; + } + else { + size = length; + length = 0; + } + + cryptocell_310_enable(); + ret = SaSi_AesBlock(ctx, (uint8_t *)(input + offset), size, output + offset); + cryptocell_310_disable(); + if (ret != SASI_OK) { + DEBUG("SaSi_AesBlock failed with %s\n", cryptocell310_status_to_humanly_readable(ret)); + return SaSi_to_psa_error(ret); + } + + offset += size; + } while ((length > 0) && (ret == SASI_OK)); + + cryptocell_310_enable(); + ret = SaSi_AesFinish(ctx, length, (uint8_t *)(input + offset), input_length, output, + output_length); + cryptocell_310_disable(); + + if (ret != SASI_OK) { + DEBUG("SaSi_AesFinish failed with %s\n", cryptocell310_status_to_humanly_readable(ret)); + return SaSi_to_psa_error(ret); + } + + return PSA_SUCCESS; +} diff --git a/pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_common.c b/pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_common.c new file mode 100644 index 0000000000..5ac6bd3c2f --- /dev/null +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_common.c @@ -0,0 +1,143 @@ +/* + * 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 pkg_driver_cryptocell_310 + * @{ + * + * @brief Common ECC functions used by all PSA Crypto wrappers + * for the CryptoCell 310 ECC APIs. + * + * @author Lena Boeckmann + * + * @} + */ + +#include "psa_error.h" +#include "psa_cryptocell_310_ecc_common.h" +#include "cryptocell_310_util.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +extern CRYS_RND_State_t *rndState_ptr; + +CRYS_ECPKI_Domain_t *pDomain; +SaSiRndGenerateVectWorkFunc_t rndGenerateVectFunc; + +psa_status_t cryptocell_310_common_ecc_generate_key_pair(uint8_t *priv_key_buffer, + uint8_t *pub_key_buffer, + uint32_t *priv_key_buffer_length, + uint32_t *pub_key_buffer_length, + CRYS_ECPKI_DomainID_t domain) +{ + CRYS_ECPKI_UserPrivKey_t priv_key; + CRYS_ECPKI_UserPublKey_t pub_key; + CRYS_ECPKI_KG_FipsContext_t FipsBuff; + CRYS_ECPKI_KG_TempData_t TempECCKGBuff; + CRYSError_t ret; + + rndGenerateVectFunc = CRYS_RND_GenerateVector; + pDomain = (CRYS_ECPKI_Domain_t *)CRYS_ECPKI_GetEcDomain(domain); + + cryptocell_310_enable(); + ret = CRYS_ECPKI_GenKeyPair(rndState_ptr, rndGenerateVectFunc, pDomain, &priv_key, &pub_key, + &TempECCKGBuff, &FipsBuff); + cryptocell_310_disable(); + if (ret != CRYS_OK) { + DEBUG("CRYS_ECPKI_GenKeyPair failed with %s\n", cryptocell310_status_to_humanly_readable(ret)); + return CRYS_to_psa_error(ret); + } + + ret = CRYS_ECPKI_ExportPrivKey(&priv_key, priv_key_buffer, priv_key_buffer_length); + if (ret != CRYS_OK) { + DEBUG("CRYS_ECPKI_ExportPrivKey failed with %s\n", cryptocell310_status_to_humanly_readable(ret)); + return CRYS_to_psa_error(ret); + } + + ret = CRYS_ECPKI_ExportPublKey(&pub_key, CRYS_EC_PointUncompressed, pub_key_buffer, + pub_key_buffer_length); + if (ret != CRYS_OK) { + DEBUG("CRYS_ECPKI_ExportPubKey failed with %s\n", cryptocell310_status_to_humanly_readable(ret)); + return CRYS_to_psa_error(ret); + } + + return PSA_SUCCESS; +} + +psa_status_t cryptocell_310_common_ecc_sign_hash(const uint8_t *priv_key, + uint32_t priv_key_size, + const uint8_t *hash, + size_t hash_length, + uint8_t *signature, + size_t *signature_length, + CRYS_ECPKI_HASH_OpMode_t hash_mode, + CRYS_ECPKI_DomainID_t domain) +{ + CRYS_ECDSA_SignUserContext_t SignUserContext; + CRYS_ECPKI_UserPrivKey_t user_priv_key; + CRYSError_t ret = 0; + + rndGenerateVectFunc = CRYS_RND_GenerateVector; + pDomain = (CRYS_ECPKI_Domain_t *)CRYS_ECPKI_GetEcDomain(domain); + + ret = CRYS_ECPKI_BuildPrivKey(pDomain, priv_key, priv_key_size, &user_priv_key); + if (ret != CRYS_OK) { + DEBUG("CRYS_ECPKI_BuildPrivKey failed with %s\n", cryptocell310_status_to_humanly_readable(ret)); + return CRYS_to_psa_error(ret); + } + + cryptocell_310_enable(); + ret = CRYS_ECDSA_Sign(rndState_ptr, rndGenerateVectFunc, + &SignUserContext, &user_priv_key, hash_mode, (uint8_t *)hash, hash_length, + signature, (uint32_t *)signature_length); + cryptocell_310_disable(); + if (ret != CRYS_OK) { + DEBUG("CRYS_ECDSA_Sign failed with %s\n", cryptocell310_status_to_humanly_readable(ret)); + return CRYS_to_psa_error(ret); + } + + return PSA_SUCCESS; +} + +psa_status_t cryptocell_310_common_ecc_verify_hash(const uint8_t *pub_key, + size_t pub_key_size, + const uint8_t *hash, + size_t hash_length, + const uint8_t *signature, + size_t signature_length, + CRYS_ECPKI_HASH_OpMode_t hash_mode, + CRYS_ECPKI_DomainID_t domain) +{ + CRYS_ECDSA_VerifyUserContext_t VerifyUserContext; + CRYS_ECPKI_UserPublKey_t user_pub_key; + CRYSError_t ret = 0; + + pDomain = (CRYS_ECPKI_Domain_t *)CRYS_ECPKI_GetEcDomain(domain); + + /** + * For more security, use CRYS_ECPKI_BuildPublKeyPartlyCheck or + * CRYS_ECPKI_BuildPublKeyFullCheck -> Those take longer and use more memory space + * */ + ret = CRYS_ECPKI_BuildPublKey(pDomain, (uint8_t *)pub_key, pub_key_size, &user_pub_key); + if (ret != CRYS_OK) { + DEBUG("CRYS_ECPKI_BuildPublKey failed with %s\n", cryptocell310_status_to_humanly_readable(ret)); + return CRYS_to_psa_error(ret); + } + + cryptocell_310_enable(); + ret = CRYS_ECDSA_Verify(&VerifyUserContext, &user_pub_key, hash_mode, (uint8_t *)signature, + signature_length, (uint8_t *)hash, hash_length); + cryptocell_310_disable(); + + if (ret != CRYS_OK) { + DEBUG("CRYS_ECDSA_Verify failed with %s\n", cryptocell310_status_to_humanly_readable(ret)); + return CRYS_to_psa_error(ret); + } + return PSA_SUCCESS; +} diff --git a/pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_p192.c b/pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_p192.c new file mode 100644 index 0000000000..955e38a46c --- /dev/null +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_p192.c @@ -0,0 +1,76 @@ +/* + * 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 pkg_driver_cryptocell_310 + * @{ + * + * @file + * @brief Glue code translating between PSA Crypto and the CryptoCell 310 ECC P192 APIs + * + * @author Lena Boeckmann + * + * @} + */ + +#include "psa_cryptocell_310_ecc_common.h" + +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) +{ + *priv_key_buffer_length = PSA_BITS_TO_BYTES(attributes->bits); + *pub_key_buffer_length = PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(attributes->type, attributes->bits); + + return cryptocell_310_common_ecc_generate_key_pair(priv_key_buffer, pub_key_buffer, + (uint32_t *)priv_key_buffer_length, + (uint32_t *)pub_key_buffer_length, + CRYS_ECPKI_DomainID_secp192r1); +} + +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) +{ + CRYS_ECPKI_HASH_OpMode_t hash_mode = MAP_PSA_HASH_TO_CRYS_HASH(PSA_ALG_GET_HASH(alg)); + + (void)signature_size; + (void)key_buffer_size; + + return cryptocell_310_common_ecc_sign_hash(key_buffer, + PSA_BITS_TO_BYTES(attributes->bits), + hash, hash_length, signature, + signature_length, hash_mode, + CRYS_ECPKI_DomainID_secp192r1); +} + +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) +{ + CRYS_ECPKI_HASH_OpMode_t hash_mode = MAP_PSA_HASH_TO_CRYS_HASH(PSA_ALG_GET_HASH(alg)); + + (void)attributes; + return cryptocell_310_common_ecc_verify_hash(key_buffer, key_buffer_size, + hash, hash_length, signature, + signature_length, hash_mode, + CRYS_ECPKI_DomainID_secp192r1); +} diff --git a/pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_p256.c b/pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_p256.c new file mode 100644 index 0000000000..41d5296425 --- /dev/null +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_p256.c @@ -0,0 +1,74 @@ +/* + * 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 pkg_driver_cryptocell_310 + * @{ + * + * @file + * @brief Glue code translating between PSA Crypto and the CryptoCell 310 ECC P256 APIs + * + * @author Lena Boeckmann + * + * @} + */ + +#include "psa_cryptocell_310_ecc_common.h" + +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) +{ + *priv_key_buffer_length = PSA_BITS_TO_BYTES(attributes->bits); + *pub_key_buffer_length = PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(attributes->type, attributes->bits); + + return cryptocell_310_common_ecc_generate_key_pair(priv_key_buffer, pub_key_buffer, + (uint32_t *)priv_key_buffer_length, + (uint32_t *)pub_key_buffer_length, + CRYS_ECPKI_DomainID_secp256r1); +} + +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) +{ + (void)key_buffer_size; + CRYS_ECPKI_HASH_OpMode_t hash_mode = MAP_PSA_HASH_TO_CRYS_HASH(PSA_ALG_GET_HASH(alg)); + *signature_length = signature_size; + return cryptocell_310_common_ecc_sign_hash(key_buffer, + PSA_BITS_TO_BYTES(attributes->bits), + hash, hash_length, signature, + signature_length, hash_mode, + CRYS_ECPKI_DomainID_secp256r1); +} + +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) +{ + CRYS_ECPKI_HASH_OpMode_t hash_mode = MAP_PSA_HASH_TO_CRYS_HASH(PSA_ALG_GET_HASH(alg)); + + (void)attributes; + return cryptocell_310_common_ecc_verify_hash(key_buffer, key_buffer_size, + hash, hash_length, signature, + signature_length, hash_mode, + CRYS_ECPKI_DomainID_secp256r1); +} diff --git a/pkg/driver_cryptocell_310/psa_cryptocell_310/error_conversion.c b/pkg/driver_cryptocell_310/psa_cryptocell_310/error_conversion.c new file mode 100644 index 0000000000..437f2cd997 --- /dev/null +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/error_conversion.c @@ -0,0 +1,413 @@ +/* + * 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 pkg_driver_cryptocell_310 + * @{ + * + * @file + * @brief Glue code translating between PSA Crypto and the CryptoCell 310 driver APIs + * + * @author Lena Boeckmann + * + * @} + */ + +#include "psa_error.h" + +psa_status_t CRYS_to_psa_error(CRYSError_t error) +{ + switch (error) { + case CRYS_HASH_ILLEGAL_OPERATION_MODE_ERROR: + case CRYS_HASH_IS_NOT_SUPPORTED: + return PSA_ERROR_NOT_SUPPORTED; + case CRYS_HASH_USER_CONTEXT_CORRUPTED_ERROR: + return PSA_ERROR_CORRUPTION_DETECTED; + case CRYS_ECDSA_SIGN_USER_CONTEXT_VALIDATION_TAG_ERROR: + case CRYS_ECDSA_SIGN_USER_PRIV_KEY_VALIDATION_TAG_ERROR: + case CRYS_ECDSA_VERIFY_USER_CONTEXT_VALIDATION_TAG_ERROR: + case CRYS_ECDSA_VERIFY_SIGNER_PUBL_KEY_VALIDATION_TAG_ERROR: + case CRYS_ECDSA_VERIFY_INVALID_SIGNATURE_IN_PTR_ERROR: + case CRYS_ECDSA_SIGN_INVALID_MESSAGE_DATA_IN_PTR_ERROR: + case CRYS_ECDSA_SIGN_INVALID_MESSAGE_DATA_IN_SIZE_ERROR: + case CRYS_ECDSA_VERIFY_INVALID_DOMAIN_ID_ERROR: + case CRYS_ECDSA_VERIFY_INVALID_USER_CONTEXT_PTR_ERROR: + case CRYS_ECDSA_VERIFY_INVALID_SIGNER_PUBL_KEY_PTR_ERROR: + case CRYS_ECDSA_VERIFY_ILLEGAL_HASH_OP_MODE_ERROR: + case CRYS_HASH_DATA_IN_POINTER_INVALID_ERROR: + case CRYS_ECDSA_VERIFY_INVALID_SIGNATURE_SIZE_ERROR: + case CRYS_ECDSA_VERIFY_INVALID_MESSAGE_DATA_IN_PTR_ERROR: + case CRYS_ECDSA_VERIFY_INVALID_MESSAGE_DATA_IN_SIZE_ERROR: + case CRYS_ECDSA_SIGN_INVALID_EPHEMERAL_KEY_PTR_ERROR: + case CRYS_ECDSA_SIGN_INVALID_RND_CONTEXT_PTR_ERROR: + case CRYS_ECDSA_SIGN_INVALID_RND_FUNCTION_PTR_ERROR: + case CRYS_ECDSA_SIGN_INVALID_DOMAIN_ID_ERROR: + case CRYS_ECDSA_SIGN_INVALID_USER_CONTEXT_PTR_ERROR: + case CRYS_ECDSA_SIGN_INVALID_USER_PRIV_KEY_PTR_ERROR: + case CRYS_ECDSA_SIGN_ILLEGAL_HASH_OP_MODE_ERROR: + case CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_PTR_ERROR: + case CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_SIZE_PTR_ERROR: + case CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_SIZE_ERROR: + case CRYS_ECC_ILLEGAL_PARAMS_ACCORDING_TO_PRIV_ERROR: + case CRYS_ECC_ILLEGAL_HASH_MODE_ERROR: + case CRYS_ECPKI_ILLEGAL_DOMAIN_ID_ERROR: + case CRYS_ECPKI_DOMAIN_PTR_ERROR: + case CRYS_ECPKI_RND_CONTEXT_PTR_ERROR: + case CRYS_ECPKI_BUILD_KEY_INVALID_COMPRESSION_MODE_ERROR: + case CRYS_ECPKI_BUILD_KEY_ILLEGAL_DOMAIN_ID_ERROR: + case CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_IN_PTR_ERROR: + case CRYS_ECPKI_BUILD_KEY_INVALID_USER_PRIV_KEY_PTR_ERROR: + case CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_SIZE_ERROR: + case CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_DATA_ERROR: + case CRYS_ECPKI_BUILD_KEY_INVALID_PUBL_KEY_IN_PTR_ERROR: + case CRYS_ECPKI_BUILD_KEY_INVALID_USER_PUBL_KEY_PTR_ERROR: + case CRYS_ECPKI_BUILD_KEY_INVALID_PUBL_KEY_SIZE_ERROR: + case CRYS_ECPKI_BUILD_KEY_INVALID_PUBL_KEY_DATA_ERROR: + case CRYS_ECPKI_BUILD_KEY_INVALID_CHECK_MODE_ERROR: + case CRYS_ECPKI_BUILD_KEY_INVALID_TEMP_BUFF_PTR_ERROR: + case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_USER_PUBL_KEY_PTR_ERROR: + case CRYS_ECPKI_EXPORT_PUBL_KEY_ILLEGAL_COMPRESSION_MODE_ERROR: + case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_EXTERN_PUBL_KEY_PTR_ERROR: + case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_SIZE_PTR_ERROR: + case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_SIZE_ERROR: + case CRYS_ECPKI_EXPORT_PUBL_KEY_ILLEGAL_DOMAIN_ID_ERROR: + case CRYS_ECPKI_EXPORT_PUBL_KEY_ILLEGAL_VALIDATION_TAG_ERROR: + case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_DATA_ERROR: + case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_USER_PRIV_KEY_PTR_ERROR: + case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_EXTERN_PRIV_KEY_PTR_ERROR: + case CRYS_ECPKI_EXPORT_PRIV_KEY_ILLEGAL_VALIDATION_TAG_ERROR: + case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_PRIV_KEY_SIZE_PTR_ERROR: + case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_PRIV_KEY_SIZE_ERROR: + case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_PRIV_KEY_DATA_ERROR: + case CRYS_ECPKI_BUILD_DOMAIN_ID_IS_NOT_VALID_ERROR: + case CRYS_ECPKI_BUILD_DOMAIN_DOMAIN_PTR_ERROR: + case CRYS_ECPKI_BUILD_DOMAIN_EC_PARAMETR_PTR_ERROR: + case CRYS_ECPKI_BUILD_DOMAIN_EC_PARAMETR_SIZE_ERROR: + case CRYS_ECPKI_BUILD_DOMAIN_COFACTOR_PARAMS_ERROR: + case CRYS_ECPKI_BUILD_DOMAIN_SECURITY_STRENGTH_ERROR: + case CRYS_ECPKI_BUILD_SCA_RESIST_ILLEGAL_MODE_ERROR: + case CRYS_ECDH_SVDP_DH_INVALID_PARTNER_PUBL_KEY_PTR_ERROR: + case CRYS_ECDH_SVDP_DH_PARTNER_PUBL_KEY_VALID_TAG_ERROR: + case CRYS_ECDH_SVDP_DH_INVALID_USER_PRIV_KEY_PTR_ERROR: + case CRYS_ECDH_SVDP_DH_USER_PRIV_KEY_VALID_TAG_ERROR: + case CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_PTR_ERROR: + case CRYS_ECDH_SVDP_DH_INVALID_TEMP_DATA_PTR_ERROR: + case CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_SIZE_PTR_ERROR: + case CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_SIZE_ERROR: + case CRYS_ECDH_SVDP_DH_ILLEGAL_DOMAIN_ID_ERROR: + case CRYS_ECPKI_GEN_KEY_INVALID_PRIVATE_KEY_PTR_ERROR: + case CRYS_ECPKI_GEN_KEY_INVALID_PUBLIC_KEY_PTR_ERROR: + case CRYS_ECPKI_GEN_KEY_INVALID_TEMP_DATA_PTR_ERROR: + case CRYS_ECPKI_INVALID_RND_FUNC_PTR_ERROR: + case CRYS_ECPKI_INVALID_RND_CTX_PTR_ERROR: + case CRYS_ECPKI_INVALID_DOMAIN_ID_ERROR: + case CRYS_ECPKI_INVALID_PRIV_KEY_TAG_ERROR: + case CRYS_ECPKI_INVALID_PUBL_KEY_TAG_ERROR: + case CRYS_ECPKI_INVALID_DATA_IN_PASSED_STRUCT_ERROR: + case CRYS_HASH_DATA_SIZE_ILLEGAL: + case CRYS_HASH_INVALID_RESULT_BUFFER_POINTER_ERROR: + case CRYS_HASH_ILLEGAL_PARAMS_ERROR: + case CRYS_HASH_INVALID_USER_CONTEXT_POINTER_ERROR: + case CRYS_HASH_LAST_BLOCK_ALREADY_PROCESSED_ERROR: + case CRYS_HASH_CTX_SIZES_ERROR: + return PSA_ERROR_INVALID_ARGUMENT; + default: + return PSA_ERROR_GENERIC_ERROR; + } +} + +psa_status_t SaSi_to_psa_error(SaSiStatus error) +{ + switch (error) { + case SASI_AES_INVALID_USER_CONTEXT_POINTER_ERROR: + case SASI_AES_INVALID_IV_OR_TWEAK_PTR_ERROR: + case SASI_AES_ILLEGAL_OPERATION_MODE_ERROR: + case SASI_AES_ILLEGAL_KEY_SIZE_ERROR: + case SASI_AES_INVALID_KEY_POINTER_ERROR: + case SASI_AES_INVALID_ENCRYPT_MODE_ERROR: + case SASI_AES_DATA_IN_POINTER_INVALID_ERROR: + case SASI_AES_DATA_OUT_POINTER_INVALID_ERROR: + case SASI_AES_DATA_IN_SIZE_ILLEGAL: + case SASI_AES_DATA_OUT_DATA_IN_OVERLAP_ERROR: + case SASI_AES_DATA_OUT_SIZE_POINTER_INVALID_ERROR: + case SASI_AES_CTX_SIZES_ERROR: + case SASI_AES_ILLEGAL_PARAMS_ERROR: + case SASI_AES_CTR_ILLEGAL_BLOCK_OFFSET_ERROR: + case SASI_AES_CTR_ILLEGAL_COUNTER_ERROR: + return PSA_ERROR_INVALID_ARGUMENT; + case SASI_AES_DATA_IN_BUFFER_SIZE_ERROR: + case SASI_AES_DATA_OUT_BUFFER_SIZE_ERROR: + return PSA_ERROR_BUFFER_TOO_SMALL; + case SASI_AES_ILLEGAL_PADDING_TYPE_ERROR: + case SASI_AES_INCORRECT_PADDING_ERROR: + return PSA_ERROR_INVALID_PADDING; + case SASI_AES_CORRUPTED_OUTPUT_ERROR: + case SASI_AES_USER_CONTEXT_CORRUPTED_ERROR: + return PSA_ERROR_CORRUPTION_DETECTED; + case SASI_AES_DECRYPTION_NOT_ALLOWED_ON_THIS_MODE: + case SASI_AES_ADDITIONAL_BLOCK_NOT_PERMITTED_ERROR: + return PSA_ERROR_NOT_PERMITTED; + case SASI_AES_KEY_TYPE_NOT_SUPPORTED_ERROR: + case SASI_AES_IS_NOT_SUPPORTED: + return PSA_ERROR_NOT_SUPPORTED; + case SASI_OUT_OF_RESOURCE_ERROR: + return PSA_ERROR_INSUFFICIENT_MEMORY; + default: + return PSA_ERROR_GENERIC_ERROR; + } +} + +const char *cryptocell310_status_to_humanly_readable(uint32_t status) +{ + switch(status) { + case CRYS_ECDH_SVDP_DH_NOT_CONCENT_PUBL_AND_PRIV_DOMAIN_ID_ERROR: + return "CRYS_ECDH_SVDP_DH_NOT_CONCENT_PUBL_AND_PRIV_DOMAIN_ID_ERROR"; + case CRYS_ECDSA_SIGN_INVALID_IS_EPHEMER_KEY_INTERNAL_ERROR: + return "CRYS_ECDSA_SIGN_INVALID_IS_EPHEMER_KEY_INTERNAL_ERROR"; + case CRYS_ECDSA_SIGN_SIGNING_ERROR: + return "CRYS_ECDSA_SIGN_SIGNING_ERROR"; + case CRYS_ECDSA_VERIFY_INCONSISTENT_VERIFY_ERROR: + return "CRYS_ECDSA_VERIFY_INCONSISTENT_VERIFY_ERROR"; + case CRYS_ECPKI_PKI_INTERNAL_ERROR: + return "CRYS_ECPKI_PKI_INTERNAL_ERROR"; + case CRYS_HASH_ILLEGAL_OPERATION_MODE_ERROR: + return "CRYS_HASH_ILLEGAL_OPERATION_MODE_ERROR"; + case CRYS_HASH_IS_NOT_SUPPORTED: + return "CRYS_HASH_IS_NOT_SUPPORTED"; + case CRYS_HASH_USER_CONTEXT_CORRUPTED_ERROR: + return "CRYS_HASH_USER_CONTEXT_CORRUPTED_ERROR"; + case CRYS_ECDSA_SIGN_USER_CONTEXT_VALIDATION_TAG_ERROR: + return "CRYS_ECDSA_SIGN_USER_CONTEXT_VALIDATION_TAG_ERROR"; + case CRYS_ECDSA_SIGN_USER_PRIV_KEY_VALIDATION_TAG_ERROR: + return "CRYS_ECDSA_SIGN_USER_PRIV_KEY_VALIDATION_TAG_ERROR"; + case CRYS_ECDSA_VERIFY_USER_CONTEXT_VALIDATION_TAG_ERROR: + return "CRYS_ECDSA_VERIFY_USER_CONTEXT_VALIDATION_TAG_ERROR"; + case CRYS_ECDSA_VERIFY_SIGNER_PUBL_KEY_VALIDATION_TAG_ERROR: + return "CRYS_ECDSA_VERIFY_SIGNER_PUBL_KEY_VALIDATION_TAG_ERROR"; + case CRYS_ECDSA_VERIFY_INVALID_SIGNATURE_IN_PTR_ERROR: + return "CRYS_ECDSA_VERIFY_INVALID_SIGNATURE_IN_PTR_ERROR"; + case CRYS_ECDSA_SIGN_INVALID_MESSAGE_DATA_IN_PTR_ERROR: + return "CRYS_ECDSA_SIGN_INVALID_MESSAGE_DATA_IN_PTR_ERROR"; + case CRYS_ECDSA_SIGN_INVALID_MESSAGE_DATA_IN_SIZE_ERROR: + return "CRYS_ECDSA_SIGN_INVALID_MESSAGE_DATA_IN_SIZE_ERROR"; + case CRYS_ECDSA_VERIFY_INVALID_DOMAIN_ID_ERROR: + return "CRYS_ECDSA_VERIFY_INVALID_DOMAIN_ID_ERROR"; + case CRYS_ECDSA_VERIFY_INVALID_USER_CONTEXT_PTR_ERROR: + return "CRYS_ECDSA_VERIFY_INVALID_USER_CONTEXT_PTR_ERROR"; + case CRYS_ECDSA_VERIFY_INVALID_SIGNER_PUBL_KEY_PTR_ERROR: + return "CRYS_ECDSA_VERIFY_INVALID_SIGNER_PUBL_KEY_PTR_ERROR"; + case CRYS_ECDSA_VERIFY_ILLEGAL_HASH_OP_MODE_ERROR: + return "CRYS_ECDSA_VERIFY_ILLEGAL_HASH_OP_MODE_ERROR"; + case CRYS_HASH_DATA_IN_POINTER_INVALID_ERROR: + return "CRYS_HASH_DATA_IN_POINTER_INVALID_ERROR"; + case CRYS_ECDSA_VERIFY_INVALID_SIGNATURE_SIZE_ERROR: + return "CRYS_ECDSA_VERIFY_INVALID_SIGNATURE_SIZE_ERROR"; + case CRYS_ECDSA_VERIFY_INVALID_MESSAGE_DATA_IN_PTR_ERROR: + return "CRYS_ECDSA_VERIFY_INVALID_MESSAGE_DATA_IN_PTR_ERROR"; + case CRYS_ECDSA_VERIFY_INVALID_MESSAGE_DATA_IN_SIZE_ERROR: + return "CRYS_ECDSA_VERIFY_INVALID_MESSAGE_DATA_IN_SIZE_ERROR"; + case CRYS_ECDSA_SIGN_INVALID_EPHEMERAL_KEY_PTR_ERROR: + return "CRYS_ECDSA_SIGN_INVALID_EPHEMERAL_KEY_PTR_ERROR"; + case CRYS_ECDSA_SIGN_INVALID_RND_CONTEXT_PTR_ERROR: + return "CRYS_ECDSA_SIGN_INVALID_RND_CONTEXT_PTR_ERROR"; + case CRYS_ECDSA_SIGN_INVALID_RND_FUNCTION_PTR_ERROR: + return "CRYS_ECDSA_SIGN_INVALID_RND_FUNCTION_PTR_ERROR"; + case CRYS_ECDSA_SIGN_INVALID_DOMAIN_ID_ERROR: + return "CRYS_ECDSA_SIGN_INVALID_DOMAIN_ID_ERROR"; + case CRYS_ECDSA_SIGN_INVALID_USER_CONTEXT_PTR_ERROR: + return "CRYS_ECDSA_SIGN_INVALID_USER_CONTEXT_PTR_ERROR"; + case CRYS_ECDSA_SIGN_INVALID_USER_PRIV_KEY_PTR_ERROR: + return "CRYS_ECDSA_SIGN_INVALID_USER_PRIV_KEY_PTR_ERROR"; + case CRYS_ECDSA_SIGN_ILLEGAL_HASH_OP_MODE_ERROR: + return "CRYS_ECDSA_SIGN_ILLEGAL_HASH_OP_MODE_ERROR"; + case CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_PTR_ERROR: + return "CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_PTR_ERROR"; + case CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_SIZE_PTR_ERROR: + return "CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_SIZE_PTR_ERROR"; + case CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_SIZE_ERROR: + return "CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_SIZE_ERROR"; + case CRYS_ECC_ILLEGAL_PARAMS_ACCORDING_TO_PRIV_ERROR: + return "CRYS_ECC_ILLEGAL_PARAMS_ACCORDING_TO_PRIV_ERROR"; + case CRYS_ECC_ILLEGAL_HASH_MODE_ERROR: + return "CRYS_ECC_ILLEGAL_HASH_MODE_ERROR"; + case CRYS_ECPKI_ILLEGAL_DOMAIN_ID_ERROR: + return "CRYS_ECPKI_ILLEGAL_DOMAIN_ID_ERROR"; + case CRYS_ECPKI_DOMAIN_PTR_ERROR: + return "CRYS_ECPKI_DOMAIN_PTR_ERROR"; + case CRYS_ECPKI_RND_CONTEXT_PTR_ERROR: + return "CRYS_ECPKI_RND_CONTEXT_PTR_ERROR"; + case CRYS_ECPKI_BUILD_KEY_INVALID_COMPRESSION_MODE_ERROR: + return "CRYS_ECPKI_BUILD_KEY_INVALID_COMPRESSION_MODE_ERROR"; + case CRYS_ECPKI_BUILD_KEY_ILLEGAL_DOMAIN_ID_ERROR: + return "CRYS_ECPKI_BUILD_KEY_ILLEGAL_DOMAIN_ID_ERROR"; + case CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_IN_PTR_ERROR: + return "CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_IN_PTR_ERROR"; + case CRYS_ECPKI_BUILD_KEY_INVALID_USER_PRIV_KEY_PTR_ERROR: + return "CRYS_ECPKI_BUILD_KEY_INVALID_USER_PRIV_KEY_PTR_ERROR"; + case CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_SIZE_ERROR: + return "CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_SIZE_ERROR"; + case CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_DATA_ERROR: + return "CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_DATA_ERROR"; + case CRYS_ECPKI_BUILD_KEY_INVALID_PUBL_KEY_IN_PTR_ERROR: + return "CRYS_ECPKI_BUILD_KEY_INVALID_PUBL_KEY_IN_PTR_ERROR"; + case CRYS_ECPKI_BUILD_KEY_INVALID_USER_PUBL_KEY_PTR_ERROR: + return "CRYS_ECPKI_BUILD_KEY_INVALID_USER_PUBL_KEY_PTR_ERROR"; + case CRYS_ECPKI_BUILD_KEY_INVALID_PUBL_KEY_SIZE_ERROR: + return "CRYS_ECPKI_BUILD_KEY_INVALID_PUBL_KEY_SIZE_ERROR"; + case CRYS_ECPKI_BUILD_KEY_INVALID_PUBL_KEY_DATA_ERROR: + return "CRYS_ECPKI_BUILD_KEY_INVALID_PUBL_KEY_DATA_ERROR"; + case CRYS_ECPKI_BUILD_KEY_INVALID_CHECK_MODE_ERROR: + return "CRYS_ECPKI_BUILD_KEY_INVALID_CHECK_MODE_ERROR"; + case CRYS_ECPKI_BUILD_KEY_INVALID_TEMP_BUFF_PTR_ERROR: + return "CRYS_ECPKI_BUILD_KEY_INVALID_TEMP_BUFF_PTR_ERROR"; + case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_USER_PUBL_KEY_PTR_ERROR: + return "CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_USER_PUBL_KEY_PTR_ERROR"; + case CRYS_ECPKI_EXPORT_PUBL_KEY_ILLEGAL_COMPRESSION_MODE_ERROR: + return "CRYS_ECPKI_EXPORT_PUBL_KEY_ILLEGAL_COMPRESSION_MODE_ERROR"; + case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_EXTERN_PUBL_KEY_PTR_ERROR: + return "CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_EXTERN_PUBL_KEY_PTR_ERROR"; + case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_SIZE_PTR_ERROR: + return "CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_SIZE_PTR_ERROR"; + case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_SIZE_ERROR: + return "CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_SIZE_ERROR"; + case CRYS_ECPKI_EXPORT_PUBL_KEY_ILLEGAL_DOMAIN_ID_ERROR: + return "CRYS_ECPKI_EXPORT_PUBL_KEY_ILLEGAL_DOMAIN_ID_ERROR"; + case CRYS_ECPKI_EXPORT_PUBL_KEY_ILLEGAL_VALIDATION_TAG_ERROR: + return "CRYS_ECPKI_EXPORT_PUBL_KEY_ILLEGAL_VALIDATION_TAG_ERROR"; + case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_DATA_ERROR: + return "CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_DATA_ERROR"; + case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_USER_PRIV_KEY_PTR_ERROR: + return "CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_USER_PRIV_KEY_PTR_ERROR"; + case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_EXTERN_PRIV_KEY_PTR_ERROR: + return "CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_EXTERN_PRIV_KEY_PTR_ERROR"; + case CRYS_ECPKI_EXPORT_PRIV_KEY_ILLEGAL_VALIDATION_TAG_ERROR: + return "CRYS_ECPKI_EXPORT_PRIV_KEY_ILLEGAL_VALIDATION_TAG_ERROR"; + case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_PRIV_KEY_SIZE_PTR_ERROR: + return "CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_PRIV_KEY_SIZE_PTR_ERROR"; + case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_PRIV_KEY_SIZE_ERROR: + return "CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_PRIV_KEY_SIZE_ERROR"; + case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_PRIV_KEY_DATA_ERROR: + return "CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_PRIV_KEY_DATA_ERROR"; + case CRYS_ECPKI_BUILD_DOMAIN_ID_IS_NOT_VALID_ERROR: + return "CRYS_ECPKI_BUILD_DOMAIN_ID_IS_NOT_VALID_ERROR"; + case CRYS_ECPKI_BUILD_DOMAIN_DOMAIN_PTR_ERROR: + return "CRYS_ECPKI_BUILD_DOMAIN_DOMAIN_PTR_ERROR"; + case CRYS_ECPKI_BUILD_DOMAIN_EC_PARAMETR_PTR_ERROR: + return "CRYS_ECPKI_BUILD_DOMAIN_EC_PARAMETR_PTR_ERROR"; + case CRYS_ECPKI_BUILD_DOMAIN_EC_PARAMETR_SIZE_ERROR: + return "CRYS_ECPKI_BUILD_DOMAIN_EC_PARAMETR_SIZE_ERROR"; + case CRYS_ECPKI_BUILD_DOMAIN_COFACTOR_PARAMS_ERROR: + return "CRYS_ECPKI_BUILD_DOMAIN_COFACTOR_PARAMS_ERROR"; + case CRYS_ECPKI_BUILD_DOMAIN_SECURITY_STRENGTH_ERROR: + return "CRYS_ECPKI_BUILD_DOMAIN_SECURITY_STRENGTH_ERROR"; + case CRYS_ECPKI_BUILD_SCA_RESIST_ILLEGAL_MODE_ERROR: + return "CRYS_ECPKI_BUILD_SCA_RESIST_ILLEGAL_MODE_ERROR"; + case CRYS_ECDH_SVDP_DH_INVALID_PARTNER_PUBL_KEY_PTR_ERROR: + return "CRYS_ECDH_SVDP_DH_INVALID_PARTNER_PUBL_KEY_PTR_ERROR"; + case CRYS_ECDH_SVDP_DH_PARTNER_PUBL_KEY_VALID_TAG_ERROR: + return "CRYS_ECDH_SVDP_DH_PARTNER_PUBL_KEY_VALID_TAG_ERROR"; + case CRYS_ECDH_SVDP_DH_INVALID_USER_PRIV_KEY_PTR_ERROR: + return "CRYS_ECDH_SVDP_DH_INVALID_USER_PRIV_KEY_PTR_ERROR"; + case CRYS_ECDH_SVDP_DH_USER_PRIV_KEY_VALID_TAG_ERROR: + return "CRYS_ECDH_SVDP_DH_USER_PRIV_KEY_VALID_TAG_ERROR"; + case CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_PTR_ERROR: + return "CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_PTR_ERROR"; + case CRYS_ECDH_SVDP_DH_INVALID_TEMP_DATA_PTR_ERROR: + return "CRYS_ECDH_SVDP_DH_INVALID_TEMP_DATA_PTR_ERROR"; + case CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_SIZE_PTR_ERROR: + return "CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_SIZE_PTR_ERROR"; + case CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_SIZE_ERROR: + return "CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_SIZE_ERROR"; + case CRYS_ECDH_SVDP_DH_ILLEGAL_DOMAIN_ID_ERROR: + return "CRYS_ECDH_SVDP_DH_ILLEGAL_DOMAIN_ID_ERROR"; + case CRYS_ECPKI_GEN_KEY_INVALID_PRIVATE_KEY_PTR_ERROR: + return "CRYS_ECPKI_GEN_KEY_INVALID_PRIVATE_KEY_PTR_ERROR"; + case CRYS_ECPKI_GEN_KEY_INVALID_PUBLIC_KEY_PTR_ERROR: + return "CRYS_ECPKI_GEN_KEY_INVALID_PUBLIC_KEY_PTR_ERROR"; + case CRYS_ECPKI_GEN_KEY_INVALID_TEMP_DATA_PTR_ERROR: + return "CRYS_ECPKI_GEN_KEY_INVALID_TEMP_DATA_PTR_ERROR"; + case CRYS_ECPKI_INVALID_RND_FUNC_PTR_ERROR: + return "CRYS_ECPKI_INVALID_RND_FUNC_PTR_ERROR"; + case CRYS_ECPKI_INVALID_RND_CTX_PTR_ERROR: + return "CRYS_ECPKI_INVALID_RND_CTX_PTR_ERROR"; + case CRYS_ECPKI_INVALID_DOMAIN_ID_ERROR: + return "CRYS_ECPKI_INVALID_DOMAIN_ID_ERROR"; + case CRYS_ECPKI_INVALID_PRIV_KEY_TAG_ERROR: + return "CRYS_ECPKI_INVALID_PRIV_KEY_TAG_ERROR"; + case CRYS_ECPKI_INVALID_PUBL_KEY_TAG_ERROR: + return "CRYS_ECPKI_INVALID_PUBL_KEY_TAG_ERROR"; + case CRYS_ECPKI_INVALID_DATA_IN_PASSED_STRUCT_ERROR: + return "CRYS_ECPKI_INVALID_DATA_IN_PASSED_STRUCT_ERROR"; + case CRYS_HASH_DATA_SIZE_ILLEGAL: + return "CRYS_HASH_DATA_SIZE_ILLEGAL"; + case CRYS_HASH_INVALID_RESULT_BUFFER_POINTER_ERROR: + return "CRYS_HASH_INVALID_RESULT_BUFFER_POINTER_ERROR"; + case CRYS_HASH_ILLEGAL_PARAMS_ERROR: + return "CRYS_HASH_ILLEGAL_PARAMS_ERROR"; + case CRYS_HASH_INVALID_USER_CONTEXT_POINTER_ERROR: + return "CRYS_HASH_INVALID_USER_CONTEXT_POINTER_ERROR"; + case CRYS_HASH_LAST_BLOCK_ALREADY_PROCESSED_ERROR: + return "CRYS_HASH_LAST_BLOCK_ALREADY_PROCESSED_ERROR"; + case CRYS_HASH_CTX_SIZES_ERROR: + return "CRYS_HASH_CTX_SIZES_ERROR"; + case SASI_AES_INVALID_USER_CONTEXT_POINTER_ERROR: + return "SASI_AES_INVALID_USER_CONTEXT_POINTER_ERROR"; + case SASI_AES_INVALID_IV_OR_TWEAK_PTR_ERROR: + return "SASI_AES_INVALID_IV_OR_TWEAK_PTR_ERROR"; + case SASI_AES_ILLEGAL_OPERATION_MODE_ERROR: + return "SASI_AES_ILLEGAL_OPERATION_MODE_ERROR"; + case SASI_AES_ILLEGAL_KEY_SIZE_ERROR: + return "SASI_AES_ILLEGAL_KEY_SIZE_ERROR"; + case SASI_AES_INVALID_KEY_POINTER_ERROR: + return "SASI_AES_INVALID_KEY_POINTER_ERROR"; + case SASI_AES_INVALID_ENCRYPT_MODE_ERROR: + return "SASI_AES_INVALID_ENCRYPT_MODE_ERROR"; + case SASI_AES_DATA_IN_POINTER_INVALID_ERROR: + return "SASI_AES_DATA_IN_POINTER_INVALID_ERROR"; + case SASI_AES_DATA_OUT_POINTER_INVALID_ERROR: + return "SASI_AES_DATA_OUT_POINTER_INVALID_ERROR"; + case SASI_AES_DATA_IN_SIZE_ILLEGAL: + return "SASI_AES_DATA_IN_SIZE_ILLEGAL"; + case SASI_AES_DATA_OUT_DATA_IN_OVERLAP_ERROR: + return "SASI_AES_DATA_OUT_DATA_IN_OVERLAP_ERROR"; + case SASI_AES_DATA_OUT_SIZE_POINTER_INVALID_ERROR: + return "SASI_AES_DATA_OUT_SIZE_POINTER_INVALID_ERROR"; + case SASI_AES_CTX_SIZES_ERROR: + return "SASI_AES_CTX_SIZES_ERROR"; + case SASI_AES_ILLEGAL_PARAMS_ERROR: + return "SASI_AES_ILLEGAL_PARAMS_ERROR"; + case SASI_AES_CTR_ILLEGAL_BLOCK_OFFSET_ERROR: + return "SASI_AES_CTR_ILLEGAL_BLOCK_OFFSET_ERROR"; + case SASI_AES_CTR_ILLEGAL_COUNTER_ERROR: + return "SASI_AES_CTR_ILLEGAL_COUNTER_ERROR"; + case SASI_AES_DATA_IN_BUFFER_SIZE_ERROR: + return "SASI_AES_DATA_IN_BUFFER_SIZE_ERROR"; + case SASI_AES_DATA_OUT_BUFFER_SIZE_ERROR: + return "SASI_AES_DATA_OUT_BUFFER_SIZE_ERROR"; + case SASI_AES_ILLEGAL_PADDING_TYPE_ERROR: + return "SASI_AES_ILLEGAL_PADDING_TYPE_ERROR"; + case SASI_AES_INCORRECT_PADDING_ERROR: + return "SASI_AES_INCORRECT_PADDING_ERROR"; + case SASI_AES_CORRUPTED_OUTPUT_ERROR: + return "SASI_AES_CORRUPTED_OUTPUT_ERROR"; + case SASI_AES_USER_CONTEXT_CORRUPTED_ERROR: + return "SASI_AES_USER_CONTEXT_CORRUPTED_ERROR"; + case SASI_AES_DECRYPTION_NOT_ALLOWED_ON_THIS_MODE: + return "SASI_AES_DECRYPTION_NOT_ALLOWED_ON_THIS_MODE"; + case SASI_AES_ADDITIONAL_BLOCK_NOT_PERMITTED_ERROR: + return "SASI_AES_ADDITIONAL_BLOCK_NOT_PERMITTED_ERROR"; + case SASI_AES_KEY_TYPE_NOT_SUPPORTED_ERROR: + return "SASI_AES_KEY_TYPE_NOT_SUPPORTED_ERROR"; + case SASI_AES_IS_NOT_SUPPORTED: + return "SASI_AES_IS_NOT_SUPPORTED"; + case SASI_OUT_OF_RESOURCE_ERROR: + return "SASI_OUT_OF_RESOURCE_ERROR"; + default: + return "Error value not recognized"; + } +} diff --git a/pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_common.c b/pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_common.c new file mode 100644 index 0000000000..e999ee011f --- /dev/null +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_common.c @@ -0,0 +1,87 @@ +/* + * 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 pkg_driver_cryptocell_310 + * @{ + * + * @brief Common hash functions used by all PSA Crypto wrappers + * for the CryptoCell 310 hash APIs. + * + * @author Lena Boeckmann + * + * @} + */ + +#include "psa/crypto.h" +#include "psa_error.h" +#include "cryptocell_310_util.h" +#include "crys_hash.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +#define CC310_MAX_HASH_INPUT_BLOCK (0xFFF0) + +psa_status_t cryptocell_310_common_hash_setup(CRYS_HASHUserContext_t *ctx, + CRYS_HASH_OperationMode_t mode) +{ + CRYSError_t ret = CRYS_HASH_Init(ctx, mode); + + if (ret != CRYS_OK) { + DEBUG("CRYS_HASH_Init failed with %s\n", cryptocell310_status_to_humanly_readable(ret)); + return CRYS_to_psa_error(ret); + } + return PSA_SUCCESS; +} + +psa_status_t cryptocell_310_common_hash_update(CRYS_HASHUserContext_t *ctx, + const uint8_t *input, + size_t input_length) +{ + CRYSError_t ret = 0; + size_t offset = 0; + size_t size; + + do { + if (input_length > CC310_MAX_HASH_INPUT_BLOCK) { + size = CC310_MAX_HASH_INPUT_BLOCK; + input_length -= CC310_MAX_HASH_INPUT_BLOCK; + } + else { + size = input_length; + input_length = 0; + } + + cryptocell_310_enable(); + ret = CRYS_HASH_Update(ctx, (uint8_t *)(input + offset), size); + cryptocell_310_disable(); + + offset += size; + } while ((input_length > 0) && (ret == CRYS_OK)); + + if (ret != CRYS_OK) { + DEBUG("CRYS_HASH_Update failed with %s\n", cryptocell310_status_to_humanly_readable(ret)); + return CRYS_to_psa_error(ret); + } + return PSA_SUCCESS; +} + +psa_status_t cryptocell_310_common_hash_finish(CRYS_HASHUserContext_t *ctx, uint8_t *hash, size_t hash_size, + size_t *hash_length) +{ + cryptocell_310_enable(); + CRYSError_t ret = CRYS_HASH_Finish(ctx, (uint32_t *)hash); + cryptocell_310_disable(); + if (ret != CRYS_OK) { + DEBUG("CRYS_HASH_Finish failed with %s\n", cryptocell310_status_to_humanly_readable(ret)); + return CRYS_to_psa_error(ret); + } + *hash_length = hash_size; + return PSA_SUCCESS; +} diff --git a/pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_sha1.c b/pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_sha1.c new file mode 100644 index 0000000000..45832369d1 --- /dev/null +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_sha1.c @@ -0,0 +1,43 @@ +/* + * 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 pkg_driver_cryptocell_310 + * @{ + * + * @brief Glue code translating between PSA Crypto and the CryptoCell 310 SHA1 APIs + * + * @author Lena Boeckmann + * + * @} + */ + +#include +#include "kernel_defines.h" +#include "psa_periph_hashes_ctx.h" +#include "psa_cryptocell_310_hashes_common.h" + +psa_status_t psa_hashes_sha1_setup(psa_hashes_sha1_ctx_t *ctx) +{ + return cryptocell_310_common_hash_setup((CRYS_HASHUserContext_t *)ctx, CRYS_HASH_SHA1_mode); +} + +psa_status_t psa_hashes_sha1_update(psa_hashes_sha1_ctx_t *ctx, + const uint8_t *input, + size_t input_length) +{ + return cryptocell_310_common_hash_update((CRYS_HASHUserContext_t *)ctx, input, input_length); +} + +psa_status_t psa_hashes_sha1_finish(psa_hashes_sha1_ctx_t *ctx, + uint8_t *hash, + size_t hash_size, + size_t *hash_length) +{ + return cryptocell_310_common_hash_finish((CRYS_HASHUserContext_t *)ctx, hash, hash_size, hash_length); +} diff --git a/pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_sha224.c b/pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_sha224.c new file mode 100644 index 0000000000..f5a07e5a8d --- /dev/null +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_sha224.c @@ -0,0 +1,43 @@ +/* + * 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 pkg_driver_cryptocell_310 + * @{ + * + * @brief Glue code translating between PSA Crypto and the CryptoCell 310 SHA224 APIs + * + * @author Lena Boeckmann + * + * @} + */ + +#include +#include "kernel_defines.h" +#include "psa_periph_hashes_ctx.h" +#include "psa_cryptocell_310_hashes_common.h" + +psa_status_t psa_hashes_sha224_setup(psa_hashes_sha224_ctx_t *ctx) +{ + return cryptocell_310_common_hash_setup((CRYS_HASHUserContext_t *)ctx, CRYS_HASH_SHA224_mode); +} + +psa_status_t psa_hashes_sha224_update(psa_hashes_sha224_ctx_t *ctx, + const uint8_t *input, + size_t input_length) +{ + return cryptocell_310_common_hash_update((CRYS_HASHUserContext_t *)ctx, input, input_length); +} + +psa_status_t psa_hashes_sha224_finish(psa_hashes_sha224_ctx_t *ctx, + uint8_t *hash, + size_t hash_size, + size_t *hash_length) +{ + return cryptocell_310_common_hash_finish((CRYS_HASHUserContext_t *)ctx, hash, hash_size, hash_length); +} diff --git a/pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_sha256.c b/pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_sha256.c new file mode 100644 index 0000000000..9aa04021f5 --- /dev/null +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_sha256.c @@ -0,0 +1,42 @@ +/* + * 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 pkg_driver_cryptocell_310 + * @{ + * + * @brief Glue code translating between PSA Crypto and the CryptoCell 310 SHA256 APIs + * + * @author Lena Boeckmann + * + * @} + */ + +#include "kernel_defines.h" +#include "psa_periph_hashes_ctx.h" +#include "psa_cryptocell_310_hashes_common.h" + +psa_status_t psa_hashes_sha256_setup(psa_hashes_sha256_ctx_t *ctx) +{ + return cryptocell_310_common_hash_setup((CRYS_HASHUserContext_t *)ctx, CRYS_HASH_SHA256_mode); +} + +psa_status_t psa_hashes_sha256_update(psa_hashes_sha256_ctx_t *ctx, + const uint8_t *input, + size_t input_length) +{ + return cryptocell_310_common_hash_update((CRYS_HASHUserContext_t *)ctx, input, input_length); +} + +psa_status_t psa_hashes_sha256_finish(psa_hashes_sha256_ctx_t *ctx, + uint8_t *hash, + size_t hash_size, + size_t *hash_length) +{ + return cryptocell_310_common_hash_finish((CRYS_HASHUserContext_t *)ctx, hash, hash_size, hash_length); +} diff --git a/pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_sha512.c b/pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_sha512.c new file mode 100644 index 0000000000..906ba9f55c --- /dev/null +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/hashes_sha512.c @@ -0,0 +1,43 @@ +/* + * 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 pkg_driver_cryptocell_310 + * @{ + * + * @brief Glue code translating between PSA Crypto and the CryptoCell 310 SHA512 APIs + * + * @author Lena Boeckmann + * + * @} + */ + +#include +#include "kernel_defines.h" +#include "psa_periph_hashes_ctx.h" +#include "psa_cryptocell_310_hashes_common.h" + +psa_status_t psa_hashes_sha512_setup(psa_hashes_sha512_ctx_t *ctx) +{ + return cryptocell_310_common_hash_setup((CRYS_HASHUserContext_t *)ctx, CRYS_HASH_SHA512_mode); +} + +psa_status_t psa_hashes_sha512_update(psa_hashes_sha512_ctx_t *ctx, + const uint8_t *input, + size_t input_length) +{ + return cryptocell_310_common_hash_update((CRYS_HASHUserContext_t *)ctx, input, input_length); +} + +psa_status_t psa_hashes_sha512_finish( psa_hashes_sha512_ctx_t *ctx, + uint8_t *hash, + size_t hash_size, + size_t *hash_length) +{ + return cryptocell_310_common_hash_finish((CRYS_HASHUserContext_t *)ctx, hash, hash_size, hash_length); +} diff --git a/pkg/driver_cryptocell_310/psa_cryptocell_310/hmac.c b/pkg/driver_cryptocell_310/psa_cryptocell_310/hmac.c new file mode 100644 index 0000000000..4bb691666f --- /dev/null +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/hmac.c @@ -0,0 +1,58 @@ +/* + * 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 pkg_driver_cryptocell_310 + * @{ + * + * @brief Glue code translating between PSA Crypto and the CryptoCell 310 driver APIs + * + * @author Lena Boeckmann + * + * @} + */ + +#include "kernel_defines.h" +#include "psa/crypto.h" +#include "psa_error.h" + +#include "crys_hmac.h" +#include "crys_hmac_error.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +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) +{ + CRYSError_t ret; + size_t required_mac_length = + PSA_MAC_LENGTH(attributes->type, attributes->bits, PSA_ALG_SHA_256); + + if (mac_size < required_mac_length) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + ret = CRYS_HMAC(CRYS_HASH_SHA256_mode, (uint8_t *)key_buffer, key_buffer_size, (uint8_t *)input, + input_length, (uint32_t *)mac); + if (ret != CRYS_OK) { + DEBUG("CRYS_HMAC failed with %s\n", cryptocell310_status_to_humanly_readable(ret)); + return CRYS_to_psa_error(ret); + } + + *mac_length = required_mac_length; + + (void)mac_size; + return PSA_SUCCESS; +} diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index 4d92bf2d87..8f2212c336 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -278,11 +278,14 @@ AUTO_INIT(auto_init_mbedtls, AUTO_INIT_PRIO_MOD_MBEDTLS); #endif #if IS_USED(MODULE_AUTO_INIT_SECURITY) -#if IS_USED(MODULE_CRYPTOAUTHLIB) -extern void auto_init_atca(void); -AUTO_INIT(auto_init_atca, - AUTO_INIT_PRIO_MOD_CRYPTOAUTHLIB); +extern void auto_init_security(void); +AUTO_INIT(auto_init_security, + AUTO_INIT_PRIO_MOD_SECURITY); #endif +#if IS_USED(MODULE_DRIVER_CRYPTOCELL_310) +extern void driver_cryptocell_310_setup(void); +AUTO_INIT(driver_cryptocell_310_setup, + AUTO_INIT_PRIO_MOD_DRIVER_CRYPTOCELL_310); #endif #if IS_USED(MODULE_TEST_UTILS_INTERACTIVE_SYNC) && !IS_USED(MODULE_SHELL) extern void test_utils_interactive_sync(void); diff --git a/sys/auto_init/include/auto_init_priorities.h b/sys/auto_init/include/auto_init_priorities.h index beb87e6f05..d87d43cdcb 100644 --- a/sys/auto_init/include/auto_init_priorities.h +++ b/sys/auto_init/include/auto_init_priorities.h @@ -317,11 +317,11 @@ extern "C" { */ #define AUTO_INIT_PRIO_MOD_MBEDTLS 1440 #endif -#ifndef AUTO_INIT_PRIO_MOD_CRYPTOAUTHLIB +#ifndef AUTO_INIT_PRIO_MOD_SECURITY /** * @brief CryptoAuthLib priority */ -#define AUTO_INIT_PRIO_MOD_CRYPTOAUTHLIB 1450 +#define AUTO_INIT_PRIO_MOD_SECURITY 1450 #endif #ifndef AUTO_INIT_PRIO_MOD_TEST_UTILS_INTERACTIVE_SYNC /** @@ -389,6 +389,12 @@ extern "C" { */ #define AUTO_INIT_PRIO_MOD_GNRC_IPV6_STATIC_ADDR 1560 #endif +#ifndef AUTO_INIT_PRIO_MOD_DRIVER_CRYPTOCELL_310 +/** + * @brief CryptoCell Driver Priority + */ +#define AUTO_INIT_PRIO_MOD_DRIVER_CRYPTOCELL_310 1570 +#endif #ifdef __cplusplus } From a6f3b59e7ae849ed3fee5be2f9f14eed0ca3ba3e Mon Sep 17 00:00:00 2001 From: Lena Boeckmann Date: Tue, 29 Aug 2023 19:13:50 +0200 Subject: [PATCH 3/8] pkg/micro-ecc: Add PSA Crypto Wrappers --- pkg/micro-ecc/Kconfig | 2 + pkg/micro-ecc/Makefile.include | 7 +++ pkg/micro-ecc/psa_uecc/Kconfig | 19 ++++++++ pkg/micro-ecc/psa_uecc/Makefile | 4 ++ pkg/micro-ecc/psa_uecc/p192.c | 84 +++++++++++++++++++++++++++++++++ pkg/micro-ecc/psa_uecc/p256.c | 84 +++++++++++++++++++++++++++++++++ 6 files changed, 200 insertions(+) create mode 100644 pkg/micro-ecc/psa_uecc/Kconfig create mode 100644 pkg/micro-ecc/psa_uecc/Makefile create mode 100644 pkg/micro-ecc/psa_uecc/p192.c create mode 100644 pkg/micro-ecc/psa_uecc/p256.c diff --git a/pkg/micro-ecc/Kconfig b/pkg/micro-ecc/Kconfig index 318d4ee1e6..a880e9f3a2 100644 --- a/pkg/micro-ecc/Kconfig +++ b/pkg/micro-ecc/Kconfig @@ -15,3 +15,5 @@ config PACKAGE_MICRO-ECC https://github.com/kmackay/micro-ecc and adds `hwrng_read` as the default RNG function if it is available on the target platform. + +rsource "psa_uecc/Kconfig" diff --git a/pkg/micro-ecc/Makefile.include b/pkg/micro-ecc/Makefile.include index 4d6987be64..377bc7317d 100644 --- a/pkg/micro-ecc/Makefile.include +++ b/pkg/micro-ecc/Makefile.include @@ -6,3 +6,10 @@ CFLAGS += -Wno-unused-variable # llvm fails to allocate registers for inline assembly :/ TOOLCHAINS_BLACKLIST += llvm + +ifneq (,$(filter psa_uecc_%, $(USEMODULE))) + PSEUDOMODULES += psa_uecc_p192 + PSEUDOMODULES += psa_uecc_p256 + DIRS += $(RIOTPKG)/micro-ecc/psa_uecc + INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include +endif diff --git a/pkg/micro-ecc/psa_uecc/Kconfig b/pkg/micro-ecc/psa_uecc/Kconfig new file mode 100644 index 0000000000..60c9d0d090 --- /dev/null +++ b/pkg/micro-ecc/psa_uecc/Kconfig @@ -0,0 +1,19 @@ +# 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. +# + +config MODULE_PSA_UECC_P192 + bool + depends on MODULE_PSA_CRYPTO + select MODULE_PSA_UECC + +config MODULE_PSA_UECC_P256 + bool + depends on MODULE_PSA_CRYPTO + select MODULE_PSA_UECC + +config MODULE_PSA_UECC + bool diff --git a/pkg/micro-ecc/psa_uecc/Makefile b/pkg/micro-ecc/psa_uecc/Makefile new file mode 100644 index 0000000000..0327595f58 --- /dev/null +++ b/pkg/micro-ecc/psa_uecc/Makefile @@ -0,0 +1,4 @@ +BASE_MODULE := psa_uecc +SUBMODULES := 1 + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/micro-ecc/psa_uecc/p192.c b/pkg/micro-ecc/psa_uecc/p192.c new file mode 100644 index 0000000000..901efa0a5a --- /dev/null +++ b/pkg/micro-ecc/psa_uecc/p192.c @@ -0,0 +1,84 @@ +/* + * 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 pkg_micro-ecc + * @{ + * + * @brief Glue code translating between PSA Crypto and the Micro-ECC APIs + * + * @author Lena Boeckmann + * + * @} + */ + +#include "psa/crypto.h" +#include "uECC.h" + +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) +{ + int ret = 0; + + *priv_key_buffer_length = PSA_BITS_TO_BYTES(attributes->bits); + *pub_key_buffer_length = PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(attributes->type, attributes->bits); + + const struct uECC_Curve_t *curve = uECC_secp192r1(); + + ret = uECC_make_key(pub_key_buffer, priv_key_buffer, curve); + if (!ret) { + return PSA_ERROR_GENERIC_ERROR; + } + + return PSA_SUCCESS; +} + +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) +{ + int ret = 0; + const struct uECC_Curve_t *curve = uECC_secp192r1(); + + ret = uECC_sign(key_buffer, hash, hash_length, signature, curve); + if (!ret) { + return PSA_ERROR_GENERIC_ERROR; + } + + *signature_length = signature_size; + + (void)alg; + (void)attributes; + (void)key_buffer_size; + return PSA_SUCCESS; +} + +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) +{ + int ret = 0; + const struct uECC_Curve_t *curve = uECC_secp192r1(); + + ret = uECC_verify(key_buffer, hash, hash_length, signature, curve); + if (!ret) { + return PSA_ERROR_GENERIC_ERROR; + } + + (void)alg; + (void)attributes; + (void)key_buffer_size; + (void)signature_length; + return PSA_SUCCESS; +} diff --git a/pkg/micro-ecc/psa_uecc/p256.c b/pkg/micro-ecc/psa_uecc/p256.c new file mode 100644 index 0000000000..397454d23b --- /dev/null +++ b/pkg/micro-ecc/psa_uecc/p256.c @@ -0,0 +1,84 @@ +/* + * 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 pkg_micro-ecc + * @{ + * + * @brief Glue code translating between PSA Crypto and the Micro-ECC APIs + * + * @author Lena Boeckmann + * + * @} + */ + +#include "psa/crypto.h" +#include "uECC.h" + +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) +{ + int ret = 0; + + *priv_key_buffer_length = PSA_BITS_TO_BYTES(attributes->bits); + *pub_key_buffer_length = PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(attributes->type, attributes->bits); + + const struct uECC_Curve_t *curve = uECC_secp256r1(); + + ret = uECC_make_key(pub_key_buffer, priv_key_buffer, curve); + if (!ret) { + return PSA_ERROR_GENERIC_ERROR; + } + + return PSA_SUCCESS; +} + +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 ret = 0; + const struct uECC_Curve_t *curve = uECC_secp256r1(); + + ret = uECC_sign(key_buffer, hash, hash_length, signature, curve); + if (!ret) { + return PSA_ERROR_GENERIC_ERROR; + } + + *signature_length = signature_size; + + (void)alg; + (void)attributes; + (void)key_buffer_size; + return PSA_SUCCESS; +} + +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) +{ + int ret = 0; + const struct uECC_Curve_t *curve = uECC_secp256r1(); + + ret = uECC_verify(key_buffer, hash, hash_length, signature, curve); + if (!ret) { + return PSA_ERROR_GENERIC_ERROR; + } + + (void)alg; + (void)attributes; + (void)key_buffer_size; + (void)signature_length; + return PSA_SUCCESS; +} From 40902cd947eb73a60589a85a541e205e27460fec Mon Sep 17 00:00:00 2001 From: Lena Boeckmann Date: Tue, 29 Aug 2023 19:19:42 +0200 Subject: [PATCH 4/8] pkg/cryptoauthlib: Add PSA Wrappers --- boards/common/nrf52/include/cfg_i2c_default.h | 8 + pkg/cryptoauthlib/Kconfig | 9 +- pkg/cryptoauthlib/Makefile | 2 +- pkg/cryptoauthlib/Makefile.dep | 8 + pkg/cryptoauthlib/Makefile.include | 10 + pkg/cryptoauthlib/contrib/atca.c | 37 +- pkg/cryptoauthlib/doc.txt | 221 +++++- pkg/cryptoauthlib/include/atca.h | 33 + pkg/cryptoauthlib/include/atca_config.h | 2 +- pkg/cryptoauthlib/include/atca_params.h | 59 +- pkg/cryptoauthlib/psa_atca_driver/Makefile | 1 + .../psa_atca_driver/psa_atca_se_driver.c | 691 ++++++++++++++++++ sys/auto_init/security/auto_init_atca.c | 50 +- sys/auto_init/security/init.c | 30 + tests/pkg/cryptoauthlib_compare_sha256/main.c | 15 +- 15 files changed, 1114 insertions(+), 62 deletions(-) create mode 100644 pkg/cryptoauthlib/psa_atca_driver/Makefile create mode 100644 pkg/cryptoauthlib/psa_atca_driver/psa_atca_se_driver.c create mode 100644 sys/auto_init/security/init.c diff --git a/boards/common/nrf52/include/cfg_i2c_default.h b/boards/common/nrf52/include/cfg_i2c_default.h index 6b59e974b8..93e86530e1 100644 --- a/boards/common/nrf52/include/cfg_i2c_default.h +++ b/boards/common/nrf52/include/cfg_i2c_default.h @@ -36,7 +36,15 @@ static const i2c_conf_t i2c_config[] = { .scl = 27, .sda = 26, .speed = I2C_SPEED_NORMAL + }, +#ifdef BOARD_NRF52840DK + { + .dev = NRF_TWIM0, + .scl = 28, + .sda = 29, + .speed = I2C_SPEED_NORMAL } +#endif }; #define I2C_NUMOF ARRAY_SIZE(i2c_config) /** @} */ diff --git a/pkg/cryptoauthlib/Kconfig b/pkg/cryptoauthlib/Kconfig index 7c74e16fb9..7b46269936 100644 --- a/pkg/cryptoauthlib/Kconfig +++ b/pkg/cryptoauthlib/Kconfig @@ -9,6 +9,7 @@ menuconfig PACKAGE_CRYPTOAUTHLIB bool "Microchip CryptoAuthentication Library package" depends on TEST_KCONFIG depends on !HAS_ARCH_EFM32 + depends on HAS_PERIPH_I2C select MODULE_AUTO_INIT_SECURITY select MODULE_CRYPTOAUTHLIB_CONTRIB @@ -20,6 +21,12 @@ config MODULE_CRYPTOAUTHLIB_CONTRIB select MODULE_PERIPH_I2C select MODULE_PERIPH_I2C_RECONFIGURE if HAS_PERIPH_I2C_RECONFIGURE +config MODULE_PSA_ATCA_DRIVER + bool + depends on PACKAGE_CRYPTOAUTHLIB + default y if MODULE_PSA_CRYPTO + select PSA_KEY_MANAGEMENT + config MODULE_CRYPTOAUTHLIB_TEST bool "Module for cryptoauthlib tests" depends on TEST_KCONFIG @@ -56,4 +63,4 @@ config MODULE_CRYPTOAUTHLIB_TEST_API_CRYPTO config MODULE_CRYPTOAUTHLIB_TEST_VECTORS bool -endif +endif # PACKAGE_CRYPTOAUTHLIB diff --git a/pkg/cryptoauthlib/Makefile b/pkg/cryptoauthlib/Makefile index e0a2211310..555e4ce1bf 100644 --- a/pkg/cryptoauthlib/Makefile +++ b/pkg/cryptoauthlib/Makefile @@ -10,7 +10,7 @@ include $(RIOTBASE)/pkg/pkg.mk CMAKE_MINIMAL_VERSION = 3.6.0 -CFLAGS += $(INCLUDES) +CFLAGS += $(INCLUDES) # for some reason this is needed by llvm, but not for gcc CFLAGS += -DATCA_HAL_I2C CFLAGS += -Wno-cast-align CFLAGS += -Wno-char-subscripts diff --git a/pkg/cryptoauthlib/Makefile.dep b/pkg/cryptoauthlib/Makefile.dep index 0544351a58..207d4f5b09 100644 --- a/pkg/cryptoauthlib/Makefile.dep +++ b/pkg/cryptoauthlib/Makefile.dep @@ -19,3 +19,11 @@ endif # Some EFM32 CPU families define AES_COUNT, which is also defined by this # library. FEATURES_BLACKLIST += arch_efm32 + +ifneq (,$(filter psa_crypto,$(USEMODULE))) + USEMODULE += psa_atca_driver +endif + +ifneq (,$(filter psa_secure_element_ateccx08a_ecc_p256, $(USEMODULE))) + USEMODULE += psa_secure_element_asymmetric +endif diff --git a/pkg/cryptoauthlib/Makefile.include b/pkg/cryptoauthlib/Makefile.include index cf37947461..dbeadf22bb 100644 --- a/pkg/cryptoauthlib/Makefile.include +++ b/pkg/cryptoauthlib/Makefile.include @@ -7,6 +7,11 @@ INCLUDES += -I$(PKG_SOURCE_DIR)/app INCLUDES += -I$(PKG_SOURCE_DIR)/lib/calib INCLUDES += -I$(RIOTPKG)/cryptoauthlib/include +ifneq (,$(filter psa_crypto, $(USEMODULE))) + DIRS += $(RIOTPKG)/cryptoauthlib/psa_atca_driver + INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include +endif + DIRS += $(RIOTPKG)/cryptoauthlib/contrib ARCHIVES += $(BINDIR)/cryptoauthlib.a @@ -21,3 +26,8 @@ ifneq (,$(filter cryptoauthlib_test,$(USEMODULE))) INCLUDES += -I$(PKG_TESTINCLDIR)/vectors INCLUDES += -I$(PKG_SOURCE_DIR)/third_party/unity endif + +ifneq (,$(filter psa_crypto,$(USEMODULE))) + PSEUDOMODULES += psa_secure_element_ateccx08a + PSEUDOMODULES += psa_secure_element_ateccx08a_ecc_p256 +endif diff --git a/pkg/cryptoauthlib/contrib/atca.c b/pkg/cryptoauthlib/contrib/atca.c index 9670909a7a..60c15afcc8 100644 --- a/pkg/cryptoauthlib/contrib/atca.c +++ b/pkg/cryptoauthlib/contrib/atca.c @@ -27,7 +27,6 @@ #include "atca.h" #include "atca_params.h" - /* Timer functions */ void atca_delay_us(uint32_t delay) { @@ -65,7 +64,7 @@ ATCA_STATUS hal_i2c_post_init(ATCAIface iface) ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t word_address, uint8_t *txdata, int txlength) { - (void) word_address; + (void)word_address; ATCAIfaceCfg *cfg = atgetifacecfg(iface); int ret; @@ -84,7 +83,7 @@ ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t word_address, uint8_t *txdata, ATCA_STATUS hal_i2c_receive(ATCAIface iface, uint8_t word_address, uint8_t *rxdata, uint16_t *rxlength) { - (void) word_address; + (void)word_address; ATCAIfaceCfg *cfg = atgetifacecfg(iface); uint8_t retries = cfg->rx_retries; int ret = -1; @@ -170,24 +169,24 @@ ATCA_STATUS hal_i2c_sleep(ATCAIface iface) return ATCA_SUCCESS; } -ATCA_STATUS hal_i2c_control(ATCAIface iface, uint8_t option, void* param, size_t paramlen) +ATCA_STATUS hal_i2c_control(ATCAIface iface, uint8_t option, void *param, size_t paramlen) { - (void) param; - (void) paramlen; + (void)param; + (void)paramlen; switch (option) { - case ATCA_HAL_CONTROL_WAKE: - return hal_i2c_wake(iface); - case ATCA_HAL_CONTROL_IDLE: - return hal_i2c_idle(iface); - case ATCA_HAL_CONTROL_SLEEP: - return hal_i2c_sleep(iface); - case ATCA_HAL_CHANGE_BAUD: - return ATCA_UNIMPLEMENTED; - case ATCA_HAL_CONTROL_SELECT: - case ATCA_HAL_CONTROL_DESELECT: - return ATCA_SUCCESS; - default: - return ATCA_BAD_PARAM; + case ATCA_HAL_CONTROL_WAKE: + return hal_i2c_wake(iface); + case ATCA_HAL_CONTROL_IDLE: + return hal_i2c_idle(iface); + case ATCA_HAL_CONTROL_SLEEP: + return hal_i2c_sleep(iface); + case ATCA_HAL_CHANGE_BAUD: + return ATCA_UNIMPLEMENTED; + case ATCA_HAL_CONTROL_SELECT: + case ATCA_HAL_CONTROL_DESELECT: + return ATCA_SUCCESS; + default: + return ATCA_BAD_PARAM; } return ATCA_UNIMPLEMENTED; } diff --git a/pkg/cryptoauthlib/doc.txt b/pkg/cryptoauthlib/doc.txt index 0cdd4a0f51..aaf9d1937c 100644 --- a/pkg/cryptoauthlib/doc.txt +++ b/pkg/cryptoauthlib/doc.txt @@ -1,6 +1,6 @@ /** * @defgroup pkg_cryptoauthlib Microchip CryptoAuthentication Library - * @ingroup pkg drivers_misc sys_crypto + * @ingroup pkg drivers_misc * @brief Provides the library for Microchip CryptoAuth devices * @see https://github.com/MicrochipTech/cryptoauthlib * @@ -8,22 +8,19 @@ * * This package provides support for the official library for Microchip CryptoAuth devices. * - * - * ## Warning - * - * Some functions can only be used, when the data, config and otp zones of the - * device are locked. Locking is permanent and cannot be undone. Be careful if - * you're not sure you've configured everything correctly. - * For more information we refer to the data sheet of the device. - * + * @warning Some functions can only be used, when the data, config and otp zones + * of the device are locked. Locking is permanent and cannot be undone. + * Be careful if you're not sure you've configured everything correctly. + * For more information please refer to the data sheet of the device. * * ## Usage * * Add + * @code * USEPKG += cryptoauthlib + * @endcode * to your Makefile. * - * * ### Shell * * To facilitate the device configuration the RIOT shell provides some @@ -33,7 +30,6 @@ * The shell handler is enabled, if cryptoauthlib is included as a package in the * Makefile of an application that also includes the shell (e.g. examples/default). * - * * ### No poll mode * * After sending a command to the device, responses are usually polled to enable @@ -41,25 +37,11 @@ * Alternatively ATCA_NO_POLL can be enabled through CFLAGS to simply * wait for the max execution time of a command before reading the response. * - * * ## Implementation status * * This implementation was partly tested with ATECC508A and ATECC608A devices. - * We haven't tested the functions that require locking the device, yet. There's - * a wrapper in the cryptoauthlib/contrib folder, which implements most of the - * HAL functions. - * Currently the functions hal_i2c_discover_devices and hal_i2c_discover_buses - * are unimplemented, as well as hal_i2c_post_init. - * - * ### Wake function - * - * The wake function only works when a 0x00 byte is sent on an i2c interface that - * runs with with 133kHz or less. - * Currently RIOT sets the baudrate to the default value of 100 kHz and there's - * no interface to change that. If the default speed ever changes to a value - * higher than 133 kHz the wake function needs to be adapted. - * For more information on how to send a proper wake condition we refer to the - * data sheet of the device. + * Currently the functions `hal_i2c_release`, `hal_i2c_discover_devices` and + * `hal_i2c_discover_buses` are unimplemented, as well as `hal_i2c_post_init`. * * ## Tests * @@ -72,4 +54,189 @@ * permanently. Unlocking is not possible! * Also there is a test for comparing the runtime of the RIOT software implementation * and the CryptoAuth hardware implementation for calculating a SHA-256 hash value. + * + * ## Using Multiple ATECCX08A Devices {#multi-ateccx08a} + * + * When using more than one device, you can either connect devices with different + * I2C addresses to one bus or devices with the same address to separate buses. + * The ATECCX08A devices provide a way to change the I2C address during device + * configuration (for more details, read the datasheet or the API documentation). + * + * ATECCX08A device parameters are configured in + * `RIOT/pkg/cryptoauthlib/include/atca_params.h`. + * There you can specify your device's address, the I2C bus to use and more by + * defining `ATCA_PARAMS`. Per default one device is defined in RIOT (example shown below). + * + * @code + * #define ATCA_PARAM_I2C (I2C_DEV(0)) + * #define ATCA_PARAM_ADDR (ATCA_I2C_ADDR) + * #define ATCA_RX_RETRIES (20) + * #define ATCA_DEVTYPE (ATECC608A) + * + * #define ATCA_PARAMS { .iface_type = ATCA_I2C_IFACE, \ + * .devtype = ATCA_DEVTYPE, \ + * .atcai2c.address = ATCA_PARAM_ADDR, \ + * .atcai2c.bus = ATCA_PARAM_I2C, \ + * .atcai2c.baud = -1, \ + * .wake_delay = 1500, \ + * .rx_retries = ATCA_RX_RETRIES } + * @endcode + * + * If you want to use more than one device, the best way is to create a file called + * `custom_atca_params.h` in your application folder (you can see an example of this in + * `examples/psa_crypto`). + * + * In your custom file you can now add a second device to `ATCA_PARAMS`: + * @code + * #define ATCA_PARAM_I2C_DEV0 (I2C_DEV(0)) + * #define ATCA_PARAM_ADDR_DEV0 (ATCA_I2C_ADDR_DEV0) + * #define ATCA_RX_RETRIES_DEV0 (20) + * #define ATCA_DEVTYPE_DEV0 (ATECC608A) + * + * #define ATCA_PARAM_I2C_DEV1 (I2C_DEV(0)) + * #define ATCA_PARAM_ADDR_DEV1 (ATCA_I2C_ADDR_DEV1) + * #define ATCA_RX_RETRIES_DEV1 (20) + * #define ATCA_DEVTYPE_DEV1 (ATECC608A) + * + * #define ATCA_PARAMS { .iface_type = ATCA_I2C_IFACE, \ + * .devtype = ATCA_DEVTYPE_DEV0, \ + * .atcai2c.address = ATCA_PARAM_ADDR_DEV0, \ + * .atcai2c.bus = ATCA_PARAM_I2C_DEV0, \ + * .atcai2c.baud = -1, \ + * .wake_delay = 1500, \ + * .rx_retries = ATCA_RX_RETRIES }, \ + * { .iface_type = ATCA_I2C_IFACE, \ + * .devtype = ATCA_DEVTYPE_DEV1, \ + * .atcai2c.address = ATCA_PARAM_ADDR_DEV1, \ + * .atcai2c.bus = ATCA_PARAM_I2C_DEV1, \ + * .atcai2c.baud = -1, \ + * .wake_delay = 1500, \ + * .rx_retries = ATCA_RX_RETRIES } + * @endcode + * + * Now you just need to add the following to your Makefile: + * @code + * CFLAGS += -DCUSTOM_ATCA_PARAMS + * INCLUDES += -I$(APPDIR) + * @endcode + * + * This way your custom params file is included in the build process and both your + * devices will be initialized by the `auto_init` module. + * + * To use them you need to utilize the `calib`-API of the cryptoauth driver, which + * allows you to pass a device handle. Pointers to all initialized devices are stored + * in the `atca_devs_ptr` array, which is included in `atca_params.h`. + * Include `atca_params.h` in your source file and pass the device handle as shown below. + * + * @code {.c} + * ATCADevice dev = atca_devs_ptr[0]; + * calib_sha_start(dev); + * @endcode + * + * ## Using Cryptoauthlib as a backend for PSA Crypto {#psa-cryptoauthlib} + * + * To use cryptoauthlib as a backend for [PSA Crypto](#sys_psa_crypto), it is best to + * overwrite the `atca_params.h` file with your own `custom_atca_params.h` file, similar + * to the one described in [Using Multiple ATECCX08A Devices](#multi-ateccx08a). + * + * When using PSA, the `ATCA_PARAMS` define contains an additional value: A location + * value of the type @ref psa_key_location_t. Each secure element you use needs its own + * location value. The primary device can get the value + * @ref PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT. All others must be within the range of + * @ref PSA_KEY_LOCATION_SE_MIN and @ref PSA_KEY_LOCATION_SE_MAX. + * + * Your structure should now look like this: + * @code + * #define PSA_ATCA_LOCATION (PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT) + * #define ATCA_PARAM_I2C (I2C_DEV(0)) + * #define ATCA_PARAM_ADDR (ATCA_I2C_ADDR) + * #define ATCA_DEVTYPE (ATECC608A) + * #define ATCA_RX_RETRIES (20) + * + * #define ATCA_PARAMS { .atca_loc = PSA_ATCA_LOCATION,\ + * .cfg = {\ + * .iface_type = ATCA_I2C_IFACE, \ + * .devtype = ATCA_DEVTYPE, \ + * .atcai2c.address = ATCA_PARAM_ADDR, \ + * .atcai2c.bus = ATCA_PARAM_I2C, \ + * .atcai2c.baud = -1, \ + * .wake_delay = 1500, \ + * .rx_retries = ATCA_RX_RETRIES } \ + * } + * @endcode + * + * When using multiple SEs, just add more device parameters as shown in section + * [Using Multiple ATECCX08A Devices](#multi-ateccx08a). + * + * ## Slot Configurations + * The ATECCX08A devices have their own key management, which can be configured by + * setting flags in the device's configuration and data zone. There is a large variety + * of possible configurations, which can not entirely be represented by PSA Crypto. + * + * For now we assume that users are familiar with their device's datasheet and have configured + * it in a way that it is usable. PSA can not yet work with keys that are already stored on the + * device, which means all key slots must be writable after locking the configuration and data zone. + * + * For ECC operations this means that key slot configurations need to allow at least the + * use of the `gen_key` command, for AES and HMAC key slots it means that clear write operations + * must be allowed. + * + * @warning In case of AES and HMAC keys this may lead to security issues, + * as it allows for manipulating key material. + * + * Users need to make their configurations known to PSA Crypto. + * For this you need to initialize a list of key slot configuration structures, with a structure + * for each slot. + * + * For these devices the structure looks like this: + * @code {.c} + * typedef struct { + * psa_key_type_t key_type_allowed; // Declare the key type allowed in this slot + * uint8_t key_persistent; // Ignore for now, PSA does not yet support persistent keys + * uint8_t slot_occupied; // Set to 0, PSA will set this to one after writing a key + * } psa_atca_slot_config_t; + * @endcode + * + * To make your configurations known to PSA, simply add the following to your `custom_atca_params.h` + * file (these values are only an example, of course you need to modify them according to + * your needs). + * + * @code {.c} + * #define ATCA_SLOTS_DEV0 { { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + * { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + * { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + * { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + * { PSA_KEY_TYPE_AES, 0, 0 }, \ + * { PSA_KEY_TYPE_HMAC, 0, 0 }, \ + * { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + * { 0, 1, 1 }, \ + * { 0, 0, 0 }, \ + * { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + * { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + * { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + * { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + * { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + * { 0, 0, 0 }, \ + * { 0, 0, 0 }} + * + * #define ATCA_CONFIG_LIST { ATCA_SLOTS_DEV0 } + * @endcode + * + * To use multiple devices, define `ATCA_SLOTS_DEV0` - `ATCA_SLOTS_DEVX` and add them to + * `ATCA_CONFIG_LIST` like so: + * + * @code {.c} + * #define ATCA_CONFIG_LIST { ATCA_SLOTS_DEV0 }, \ + * { ATCA_SLOTS_DEV1 }, \ + * ... \ + * { ATCA_SLOTS_DEVX } + * @endcode + * + * A usage example for this can be found in `examples/psa_crypto`. + * + * ## Troubleshooting + * + * ### Device Initialization fails + * + * Make sure the I2C bus speed is set to `I2C_SPEED_NORMAL`. */ diff --git a/pkg/cryptoauthlib/include/atca.h b/pkg/cryptoauthlib/include/atca.h index 5f33d4c477..75109c2630 100644 --- a/pkg/cryptoauthlib/include/atca.h +++ b/pkg/cryptoauthlib/include/atca.h @@ -29,6 +29,7 @@ extern "C" { /** * @brief Default device and word addresses for ATECC508A + * @{ */ #define ATCA_I2C_ADDR (0xC0) /**< Default device address is 0xC0 */ @@ -36,6 +37,38 @@ extern "C" { #define ATCA_SLEEP_ADDR (0x01) /**< Word address to write to for sleep mode */ #define ATCA_IDLE_ADDR (0x02) /**< Word address to write to for idle mode */ #define ATCA_DATA_ADDR (0x03) /**< Word address to read and write to data area */ +/** @} */ + +#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) +#include "psa/crypto_types.h" + +/** + * @brief Structure containing the Cryptoauthlib specific AES context + */ +typedef struct { + uint8_t iv[16]; + psa_encrypt_or_decrypt_t direction; + union atca_context { + atca_aes_cbc_ctx_t aes_cbc; + } aes_ctx; +} psa_atca_cipher_context_t; + +/** + * @brief Structure containing information about which type of key + * can be held by a specific key slot on an ATECCX08 device. + * + * If a slot should be ignored by the implementation, + * just mark it as persistent and occupied. + */ +typedef struct { + /* Type of key permitted for slot */ + psa_key_type_t key_type_allowed; + /* Specify if key should be stored persistently or can be overwritten */ + uint8_t key_persistent; + /* Specify whether slot is already occupied */ + uint8_t slot_occupied; +} psa_atca_slot_config_t; +#endif /* MODULE_PSA_SECURE_ELEMENT_ATECCX08A */ #ifdef __cplusplus } diff --git a/pkg/cryptoauthlib/include/atca_config.h b/pkg/cryptoauthlib/include/atca_config.h index de9491b4d9..da93b09a49 100644 --- a/pkg/cryptoauthlib/include/atca_config.h +++ b/pkg/cryptoauthlib/include/atca_config.h @@ -49,4 +49,4 @@ extern "C" { } #endif #endif /* ATCA_CONFIG_H */ -/** @} */ \ No newline at end of file +/** @} */ diff --git a/pkg/cryptoauthlib/include/atca_params.h b/pkg/cryptoauthlib/include/atca_params.h index 3a49d585f7..4058be52b8 100644 --- a/pkg/cryptoauthlib/include/atca_params.h +++ b/pkg/cryptoauthlib/include/atca_params.h @@ -22,8 +22,19 @@ #include "board.h" #include "periph/i2c.h" +#include "atca.h" #include "cryptoauthlib.h" +#include "kernel_defines.h" + +#ifdef CUSTOM_ATCA_PARAMS +#include "custom_atca_params.h" +#endif + +#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) +#include "psa/crypto_types.h" +#endif + #ifdef __cplusplus extern "C" { #endif @@ -45,8 +56,9 @@ extern "C" { */ #ifndef ATCA_PARAM_I2C -#define ATCA_PARAM_I2C I2C_DEV(0) +#define ATCA_PARAM_I2C (I2C_DEV(0)) #endif + #ifndef ATCA_PARAM_ADDR #define ATCA_PARAM_ADDR (ATCA_I2C_ADDR) #endif @@ -58,17 +70,37 @@ extern "C" { #endif #ifndef ATCA_PARAMS -#define ATCA_PARAMS { .iface_type = ATCA_I2C_IFACE, \ - .devtype = ATCA_DEVTYPE, \ - .atcai2c.address = ATCA_PARAM_ADDR, \ - .atcai2c.bus = ATCA_PARAM_I2C, \ - .atcai2c.baud = -1, /**< Not used in RIOT */ \ - .wake_delay = 1500, \ - .rx_retries = ATCA_RX_RETRIES } +/** + * @brief Configuration parameters for the primary ATCA device + */ +#define ATCA_PARAMS { .iface_type = ATCA_I2C_IFACE, \ + .devtype = ATCA_DEVTYPE, \ + .atcai2c.address = ATCA_PARAM_ADDR, \ + .atcai2c.bus = ATCA_PARAM_I2C, \ + .atcai2c.baud = -1, /**< Not used in RIOT */ \ + .wake_delay = 1500, \ + .rx_retries = ATCA_RX_RETRIES } #endif /**@}*/ +#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) +/** + * @brief Structure to store ATCA device configuration + */ +typedef struct { + psa_key_location_t atca_loc; + ATCAIfaceCfg cfg; /**< ATCA configuration parameters */ +} atca_params_t; + +/** + * @brief Allocation of ATCA device descriptors + */ +static const atca_params_t atca_params[] = +{ + ATCA_PARAMS +}; +#else /** * @brief Allocation of ATCA device descriptors */ @@ -76,6 +108,17 @@ static const ATCAIfaceCfg atca_params[] = { ATCA_PARAMS }; +#endif + +/** + * @brief Number of connected devices + */ +#define ATCA_NUMOF (ARRAY_SIZE(atca_params)) + +/** + * @brief List of device pointers for all available devices + */ +extern ATCADevice atca_devs_ptr[ATCA_NUMOF]; #ifdef __cplusplus } diff --git a/pkg/cryptoauthlib/psa_atca_driver/Makefile b/pkg/cryptoauthlib/psa_atca_driver/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/pkg/cryptoauthlib/psa_atca_driver/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/pkg/cryptoauthlib/psa_atca_driver/psa_atca_se_driver.c b/pkg/cryptoauthlib/psa_atca_driver/psa_atca_se_driver.c new file mode 100644 index 0000000000..e998e7c809 --- /dev/null +++ b/pkg/cryptoauthlib/psa_atca_driver/psa_atca_se_driver.c @@ -0,0 +1,691 @@ +/* + * 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 Glue code translating between PSA Crypto and the Microchip Cryptoauth Library APIs + * + * @author Lena Boeckmann + * + * @} + */ + +#include "atca_params.h" +#include "psa/crypto.h" +#include "psa_crypto_se_driver.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +/** + * @brief AES block size supported by ATCA devices + */ +#define AES_128_BLOCK_SIZE (16) + +/** + * @brief AES key size supported by ATCA devices + */ +#define AES_128_KEY_SIZE (16) + +/** + * @brief Size of an ellipic curve public key supported by ATCA devices + */ +#define ECC_P256_PUB_KEY_SIZE (64) + +/** + * @brief Maximum IV length supported by ATCA devices + */ +#define ATCA_MAX_IV_LEN (16) + +/** + * @brief Size of ATCA TempKey Register + */ +#define ATCA_WRITE_BUFFER_SIZE (32) + +/** + * @brief Check whether a specified algorithm is supported by this driver + * + * @param alg Algorithm of type @ref psa_algorithm_t + * + * @return int + * 1 if @c alg is supported + * 0 otherwise + */ +#define ALG_IS_SUPPORTED(alg) \ + ((alg == PSA_ALG_ECB_NO_PADDING) || \ + (alg == PSA_ALG_CBC_NO_PADDING) || \ + (alg == PSA_ALG_ECDSA(PSA_ALG_SHA_256)) || \ + (alg == PSA_ALG_HMAC(PSA_ALG_SHA_256))) + +/** + * @brief Check whether a specified key size is supported by this driver + * + * @param size Size of the specified key + * @param type Type of the specified key + * + * @return int + * 1 if @c size is supported + * 0 otherwise + */ +#define KEY_SIZE_IS_SUPPORTED(size, type) \ + ((type == PSA_KEY_TYPE_AES && size == AES_128_KEY_SIZE) || \ + (PSA_KEY_TYPE_IS_ECC(type) && size == (ECC_P256_PUB_KEY_SIZE + 1)) || \ + (type == PSA_KEY_TYPE_HMAC && size == 32)) + +/** + * @brief Convert ATCA status values to PSA errors + * + * @param error + * + * @return @ref psa_status_t + */ +static psa_status_t atca_to_psa_error(ATCA_STATUS error) +{ + switch (error) { + case ATCA_NOT_LOCKED: + case ATCA_EXECUTION_ERROR: + case ATCA_FUNC_FAIL: + return PSA_ERROR_BAD_STATE; + case ATCA_WAKE_FAILED: + case ATCA_RX_FAIL: + case ATCA_RX_NO_RESPONSE: + case ATCA_TX_TIMEOUT: + case ATCA_RX_TIMEOUT: + case ATCA_TOO_MANY_COMM_RETRIES: + case ATCA_COMM_FAIL: + case ATCA_TIMEOUT: + case ATCA_TX_FAIL: + return PSA_ERROR_COMMUNICATION_FAILURE; + case ATCA_RX_CRC_ERROR: + case ATCA_STATUS_CRC: + return PSA_ERROR_DATA_CORRUPT; + case ATCA_SMALL_BUFFER: + return PSA_ERROR_BUFFER_TOO_SMALL; + case ATCA_BAD_OPCODE: + case ATCA_BAD_PARAM: + case ATCA_INVALID_SIZE: + case ATCA_INVALID_ID: + return PSA_ERROR_INVALID_ARGUMENT; + case ATCA_UNIMPLEMENTED: + return PSA_ERROR_NOT_SUPPORTED; + default: + return PSA_ERROR_GENERIC_ERROR; + } +} + +const char *atca_status_to_humanly_readable(ATCA_STATUS status) +{ + switch (status) { + case ATCA_NOT_LOCKED: + return "ATCA_NOT_LOCKED"; + case ATCA_EXECUTION_ERROR: + return "ATCA_EXECUTION_ERROR"; + case ATCA_FUNC_FAIL: + return "ATCA_FUNC_FAIL"; + case ATCA_WAKE_FAILED: + return "ATCA_WAKE_FAILED"; + case ATCA_RX_FAIL: + return "ATCA_RX_FAIL"; + case ATCA_RX_NO_RESPONSE: + return "ATCA_RX_NO_RESPONSE"; + case ATCA_TX_TIMEOUT: + return "ATCA_TX_TIMEOUT"; + case ATCA_RX_TIMEOUT: + return "ATCA_RX_TIMEOUT"; + case ATCA_TOO_MANY_COMM_RETRIES: + return "ATCA_TOO_MANY_COMM_RETRIES"; + case ATCA_COMM_FAIL: + return "ATCA_COMM_FAIL"; + case ATCA_TIMEOUT: + return "ATCA_TIMEOUT"; + case ATCA_TX_FAIL: + return "ATCA_TX_FAIL"; + case ATCA_RX_CRC_ERROR: + return "ATCA_RX_CRC_ERROR"; + case ATCA_STATUS_CRC: + return "ATCA_STATUS_CRC"; + case ATCA_SMALL_BUFFER: + return "ATCA_SMALL_BUFFER"; + case ATCA_BAD_OPCODE: + return "ATCA_BAD_OPCODE"; + case ATCA_BAD_PARAM: + return "ATCA_BAD_PARAM"; + case ATCA_INVALID_SIZE: + return "ATCA_INVALID_SIZE"; + case ATCA_INVALID_ID: + return "ATCA_INVALID_ID"; + case ATCA_UNIMPLEMENTED: + return "ATCA_UNIMPLEMENTED"; + default: + return "Error value not recognized"; + } +} + +/* Secure Element Cipher Functions */ +/** + * @brief Set up a driver specific AES CBC mode operation + * + * @param ctx + * @param dev + * @param key_slot + */ +static void atca_cbc_setup(atca_aes_cbc_ctx_t *ctx, + ATCADevice dev, + psa_key_slot_number_t key_slot) +{ + ctx->device = dev; + ctx->key_id = key_slot; + ctx->key_block = 0; +} + +psa_status_t atca_cipher_setup(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) +{ + ATCADevice dev = (ATCADevice)drv_context->transient_data; + psa_se_cipher_context_t *ctx = (psa_se_cipher_context_t *)op_context; + + /* Only device type ATECC608 supports AES operations */ + if (dev->mIface.mIfaceCFG->devtype != ATECC608) { + DEBUG("ATCA Cipher Setup: Only ATECC608 devices support AES operations.\n"); + return PSA_ERROR_NOT_SUPPORTED; + } + + switch (algorithm) { + case PSA_ALG_CBC_NO_PADDING: + atca_cbc_setup(&ctx->drv_ctx.atca_aes_cbc, dev, key_slot); + break; + default: + DEBUG("ATCA Cipher Setup: Algorithm not supported by implementation.\n"); + return PSA_ERROR_NOT_SUPPORTED; + } + ctx->direction = direction; + + return PSA_SUCCESS; +} + +psa_status_t atca_cipher_set_iv(void *op_context, + const uint8_t *p_iv, + size_t iv_length) +{ + + atca_aes_cbc_ctx_t *ctx = &((psa_se_cipher_context_t *)op_context)->drv_ctx.atca_aes_cbc; + + if (iv_length != ATCA_MAX_IV_LEN) { + DEBUG("ATCA Cipher Set IV: Invalid IV length: Expected %d, was %d\n", \ + ATCA_MAX_IV_LEN, iv_length); + return PSA_ERROR_INVALID_ARGUMENT; + } + + memcpy(ctx->ciphertext, p_iv, iv_length); + + return PSA_SUCCESS; +} + +psa_status_t atca_cipher_update(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) +{ + psa_se_cipher_context_t *ctx = (psa_se_cipher_context_t *)op_context; + ATCA_STATUS status = ATCA_EXECUTION_ERROR; + size_t offset = 0; + + for (size_t data_block = 0; data_block < (input_size / AES_128_BLOCK_SIZE); data_block++) { + offset = data_block * AES_128_BLOCK_SIZE; + if (ctx->direction == PSA_CRYPTO_DRIVER_ENCRYPT) { + status = atcab_aes_cbc_encrypt_block(&ctx->drv_ctx.atca_aes_cbc, p_input + offset, + p_output + offset); + } + else { + status = atcab_aes_cbc_decrypt_block(&ctx->drv_ctx.atca_aes_cbc, p_input + offset, + p_output + offset); + } + + if (status != ATCA_SUCCESS) { + DEBUG("ATCA Cipher Update failed. ATCA Error: %s\n", + atca_status_to_humanly_readable(status)); + return atca_to_psa_error(status); + } + } + + *p_output_length += input_size; + + (void)output_size; + return PSA_SUCCESS; +} + +psa_status_t atca_cipher_finish(void *op_context, + uint8_t *p_output, + size_t output_size, + size_t *p_output_length) +{ + (void)op_context; + (void)p_output; + (void)output_size; + (void)p_output_length; + return PSA_SUCCESS; +} + +psa_status_t atca_cipher_ecb(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) +{ + ATCA_STATUS status; + ATCADevice dev = (ATCADevice)drv_context->transient_data; + size_t offset = 0; + + if (dev->mIface.mIfaceCFG->devtype != ATECC608) { + DEBUG("ATCA Cipher ECB: Only ATECC608 devices support AES operations.\n"); + return PSA_ERROR_NOT_SUPPORTED; + } + + if (algorithm != PSA_ALG_ECB_NO_PADDING || direction != PSA_CRYPTO_DRIVER_ENCRYPT) { + DEBUG("ATCA Cipher ECB: Only AES ECB encryption without padding is supported.\n"); + return PSA_ERROR_NOT_SUPPORTED; + } + + if (input_size % AES_128_BLOCK_SIZE != 0) { + DEBUG("ATCA Cipher ECB: Input must be multiple of 16, was %d.\n", input_size); + return PSA_ERROR_INVALID_ARGUMENT; + } + + do { + status = calib_aes_encrypt(dev, key_slot, 0, p_input + offset, p_output + offset); + if (status != ATCA_SUCCESS) { + DEBUG("ATCA Cipher ECB encrypt failed. ATCA Error: %s\n", + atca_status_to_humanly_readable(status)); + return atca_to_psa_error(status); + } + + offset += AES_128_BLOCK_SIZE; + } while (offset < input_size); + + (void)output_size; + return PSA_SUCCESS; +} + +/* Secure Element Key Management Functions */ + +psa_status_t atca_allocate(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) +{ + if (!ALG_IS_SUPPORTED(attributes->policy.alg)) { + DEBUG("ATCA allocate: Algorithm is not supported by device.\n"); + return PSA_ERROR_NOT_SUPPORTED; + } + + psa_key_type_t type = attributes->type; + psa_se_config_t *device_config = (psa_se_config_t *)persistent_data; + psa_atca_slot_config_t *slot_config = device_config->slots; + + for (int i = 0; i < 16; i++) { + if (slot_config[i].key_type_allowed == type) { + /* If a slot is occupied, but the stored key is not marked as persistent, + we treat it as an empty slot and overwrite the key */ + if (slot_config[i].slot_occupied && slot_config[i].key_persistent) { + continue; + } + + *key_slot = i; + + (&slot_config[i])->slot_occupied = 1; + + DEBUG("Allocating slot %d for key type %x\n", (int)*key_slot, attributes->type); + + if (PSA_KEY_LIFETIME_GET_PERSISTENCE(attributes->lifetime) != \ + PSA_KEY_PERSISTENCE_VOLATILE) { + (&slot_config[i])->key_persistent = 1; + } + return PSA_SUCCESS; + } + } + + (void)drv_context; + (void)method; + + DEBUG("ATCA allocate: No free slot available.\n"); + return PSA_ERROR_INSUFFICIENT_STORAGE; +} + +psa_status_t atca_destroy(psa_drv_se_context_t *drv_context, + void *persistent_data, + psa_key_slot_number_t key_slot) +{ + /** + * The ATECCX08A driver does not provide a key destruction function. + * + * This function just sets the `slot_occupied` flag in the driver's persistent + * data to 0, in case the key generation or import goes wrong, so the slot can + * be reused. + */ + psa_atca_slot_config_t *slot_config = (psa_atca_slot_config_t *)persistent_data; + + DEBUG("Setting Key Slot %d to not occupied.\n", (int)key_slot); + (&slot_config[key_slot])->slot_occupied = 0; + + (void)drv_context; + + return PSA_SUCCESS; +} + +psa_status_t atca_import(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) +{ + ATCA_STATUS status; + ATCADevice dev = (ATCADevice)drv_context->transient_data; + + if (!ALG_IS_SUPPORTED(attributes->policy.alg)) { + DEBUG("ATCA import: Algorithm is not supported by device.\n"); + return PSA_ERROR_NOT_SUPPORTED; + } + + if (!KEY_SIZE_IS_SUPPORTED(data_length, attributes->type)) { + DEBUG("ATCA import: Key size is not supported by device.\n"); + return PSA_ERROR_NOT_SUPPORTED; + } + + if (PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(attributes->type)) { + status = calib_write_pubkey(dev, key_slot, data + 1); + if (status != ATCA_SUCCESS) { + DEBUG("ATCA Write Pubkey failed. ATCA Error: %s\n", + atca_status_to_humanly_readable(status)); + return atca_to_psa_error(status); + } + *bits = PSA_BYTES_TO_BITS(data_length); + + return PSA_SUCCESS; + } + else { + if (data_length > ATCA_WRITE_BUFFER_SIZE) { + DEBUG("ATCA import: Key size too large.\n"); + return PSA_ERROR_INVALID_ARGUMENT; + } + + uint8_t buf_in[ATCA_WRITE_BUFFER_SIZE] = { 0 }; + /* AES keys can be written to slots in 32 or 64 byte chunks. For this we + copy them into a 32 byte buffer first and pad the empty bits with 0 */ + memcpy(buf_in, data, data_length); + status = calib_write_bytes_zone(dev, ATCA_ZONE_DATA, key_slot, 0, buf_in, sizeof(buf_in)); + if (status != ATCA_SUCCESS) { + DEBUG("ATCA Write AES key failed. ATCA Error: %s\n", + atca_status_to_humanly_readable(status)); + return atca_to_psa_error(status); + } + + *bits = PSA_BYTES_TO_BITS(data_length); + + return PSA_SUCCESS; + } + + DEBUG("ATCA import: Operation is not supported.\n"); + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t atca_generate_key(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) +{ + ATCA_STATUS status; + ATCADevice dev = (ATCADevice)drv_context->transient_data; + + if (!PSA_KEY_TYPE_IS_ECC(attributes->type)) { + DEBUG("ATCA Generate Key: Only ECC key generation is supported.\n"); + return PSA_ERROR_NOT_SUPPORTED; + } + + if (pubkey_size > PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(attributes->type, attributes->bits)) { + DEBUG("ATCA Generate Key: Pubkey size not supported. Expected %d, was %d.\n", \ + PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(attributes->type, attributes->bits), pubkey_size); + return PSA_ERROR_NOT_SUPPORTED; + } + + if (pubkey != NULL) { + /** + * PSA supports the uncompressed binary format to encode ECC public keys. + * This means, that both the x and y coordinate are stored. + * This format is encoded by adding an extra byte containing the value 0x04 + * (see also "Technical Guideline BSI TR-03111"). + * + * The ATECCX08A stores and exports the x and y coordinate, so all we need to do is + * add the byte before the coordinates. + */ + pubkey[0] = 0x04; + *pubkey_length = PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(attributes->type, attributes->bits); + status = calib_genkey(dev, key_slot, &pubkey[1]); + } + else { + status = calib_genkey(dev, key_slot, NULL); + } + + if (status != ATCA_SUCCESS) { + DEBUG("ATCA Genkey failed. ATCA Error: %s\n", + atca_status_to_humanly_readable(status)); + return atca_to_psa_error(status); + } + + return PSA_SUCCESS; +} + +psa_status_t atca_export_public_key(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) +{ + ATCA_STATUS status; + ATCADevice dev = (ATCADevice)drv_context->transient_data; + + if (data_size < ECC_P256_PUB_KEY_SIZE) { + DEBUG("ATCA Export public key: Buffer too small, expected %d, was %d\n", \ + ECC_P256_PUB_KEY_SIZE, data_size); + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + status = calib_get_pubkey(dev, key_slot, &p_data[1]); + if (status != ATCA_SUCCESS) { + DEBUG("ATCA Get Pubkey failed. ATCA Error: %s\n", + atca_status_to_humanly_readable(status)); + return atca_to_psa_error(status); + } + + /** + * PSA supports the uncompressed binary format to encode ECC public keys. + * This means, that both the x and y coordinate are stored. + * This format is encoded by adding an extra byte containing the value 0x04 + * (see also "Technical Guideline BSI TR-03111"). + * + * The ATECCX08A stored and exports the x and y coordinate, so all we need to do is + * add the byte before the coordinates. + */ + p_data[0] = 0x04; + + /* Since we added the encoding byte, the stored public key is now 65 bytes long instead of 64 */ + *p_data_length = ECC_P256_PUB_KEY_SIZE + 1; + + return PSA_SUCCESS; +} + +psa_status_t atca_sign(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) +{ + ATCA_STATUS status; + ATCADevice dev = (ATCADevice)drv_context->transient_data; + + if (alg != PSA_ALG_ECDSA(PSA_ALG_SHA_256)) { + DEBUG("ATCA Sign: Only ECDSA with SHA256 Messages is supported.\n"); + return PSA_ERROR_NOT_SUPPORTED; + } + + if ((signature_size != ECC_P256_PUB_KEY_SIZE) || \ + (hash_length != PSA_HASH_LENGTH(PSA_ALG_SHA_256))) { + DEBUG("ATCA Sign: Invalid signature or hash size. Expected Sig: %d |\ + Hash %d, were Sig: %d | Hash: %d\n",\ + ECC_P256_PUB_KEY_SIZE, PSA_HASH_LENGTH(PSA_ALG_SHA_256),\ + signature_size, hash_length); + return PSA_ERROR_INVALID_ARGUMENT; + } + + status = calib_sign(dev, key_slot, p_hash, p_signature); + if (status != ATCA_SUCCESS) { + DEBUG("ATCA Sign failed. ATCA Error: %s\n", + atca_status_to_humanly_readable(status)); + return atca_to_psa_error(status); + } + + *p_signature_length = signature_size; + return PSA_SUCCESS; +} + +psa_status_t atca_verify(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) +{ + ATCA_STATUS status; + ATCADevice dev = (ATCADevice)drv_context->transient_data; + + bool is_verified; + + /* We only support the operation on public keys, if they're stored on a device. */ + if (alg != PSA_ALG_ECDSA(PSA_ALG_SHA_256)) { + DEBUG("ATCA Verify: Only ECDSA with SHA256 Messages is supported.\n"); + return PSA_ERROR_NOT_SUPPORTED; + } + + if ((signature_length != ECC_P256_PUB_KEY_SIZE) || \ + (hash_length != PSA_HASH_LENGTH(PSA_ALG_SHA_256))) { + DEBUG("ATCA Sign: Invalid signature or hash size. Expected Sig: %d |\ + Hash %d, were Sig: %d | Hash: %d\n",\ + ECC_P256_PUB_KEY_SIZE, PSA_HASH_LENGTH(PSA_ALG_SHA_256),\ + signature_length, hash_length); + return PSA_ERROR_INVALID_ARGUMENT; + } + + status = calib_verify_stored(dev, p_hash, p_signature, key_slot, &is_verified); + if (status != ATCA_SUCCESS) { + DEBUG("ATCA Verify failed. ATCA Error: %s\n", + atca_status_to_humanly_readable(status)); + return atca_to_psa_error(status); + } + + return is_verified ? PSA_SUCCESS : PSA_ERROR_INVALID_SIGNATURE; +} + +psa_status_t atca_generate_mac(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) +{ + ATCA_STATUS status; + ATCADevice dev = (ATCADevice)drv_context->transient_data; + + if (!PSA_ALG_IS_HMAC(alg)) { + DEBUG("ATCA Generate MAC: Only HMAC SHA256 is supported.\n"); + return PSA_ERROR_NOT_SUPPORTED; + } + + if (mac_size < PSA_HASH_LENGTH(PSA_ALG_SHA_256)) { + DEBUG("ATCA Generate Mac: Buffer too small, expected %d, was %d\n", \ + PSA_HASH_LENGTH(PSA_ALG_SHA_256), mac_size); + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + status = calib_sha_hmac(dev, p_input, input_length, key_slot, p_mac, SHA_MODE_TARGET_OUT_ONLY); + if (status != ATCA_SUCCESS) { + DEBUG("ATCA SHA HMAC failed. ATCA Error: %s\n", + atca_status_to_humanly_readable(status)); + return atca_to_psa_error(status); + } + *p_mac_length = PSA_HASH_LENGTH(PSA_ALG_SHA_256); + + return PSA_SUCCESS; +} + +static psa_drv_se_mac_t atca_mac = { + .context_size = 0, + .p_setup = NULL, + .p_update = NULL, + .p_finish = NULL, + .p_finish_verify = NULL, + .p_abort = NULL, + .p_mac = atca_generate_mac, + .p_mac_verify = NULL, +}; + +static psa_drv_se_cipher_t atca_cipher = { + .context_size = 0, + .p_setup = atca_cipher_setup, + .p_set_iv = atca_cipher_set_iv, + .p_update = atca_cipher_update, + .p_finish = atca_cipher_finish, + .p_abort = NULL, + .p_ecb = atca_cipher_ecb +}; + +static psa_drv_se_key_management_t atca_key_management = { + .p_allocate = atca_allocate, + .p_validate_slot_number = NULL, + .p_import = atca_import, + .p_generate = atca_generate_key, + .p_destroy = atca_destroy, + .p_export = NULL, + .p_export_public = atca_export_public_key +}; + +static psa_drv_se_asymmetric_t atca_asymmetric = { + .p_sign = atca_sign, + .p_verify = atca_verify, + .p_encrypt = NULL, + .p_decrypt = NULL +}; + +psa_drv_se_t atca_methods = { + .hal_version = PSA_DRV_SE_HAL_VERSION, + .persistent_data_size = 0, + .p_init = NULL, + .key_management = &atca_key_management, + .mac = &atca_mac, + .cipher = &atca_cipher, + .aead = NULL, + .asymmetric = &atca_asymmetric, + .derivation = NULL +}; diff --git a/sys/auto_init/security/auto_init_atca.c b/sys/auto_init/security/auto_init_atca.c index a625c5aebd..a9a8fdf428 100644 --- a/sys/auto_init/security/auto_init_atca.c +++ b/sys/auto_init/security/auto_init_atca.c @@ -19,18 +19,62 @@ #include "log.h" #include "atca.h" #include "atca_params.h" +#include "kernel_defines.h" #define ENABLE_DEBUG 0 #include "debug.h" -#define ATCA_NUMOF (ARRAY_SIZE(atca_params)) +#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) +#include "psa/crypto.h" +#include "psa_crypto_se_management.h" +extern psa_drv_se_t atca_methods; + +psa_se_config_t atca_config_list[] = { ATCA_CONFIG_LIST }; +#endif + +ATCADevice atca_devs_ptr[ATCA_NUMOF]; + +static struct atca_device atca_devs[ATCA_NUMOF]; + +#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) void auto_init_atca(void) { + DEBUG("[auto_init_atca] Number of secure elements: %d\n", ATCA_NUMOF); for (unsigned i = 0; i < ATCA_NUMOF; i++) { - if (atcab_init((ATCAIfaceCfg *)&atca_params[i]) != ATCA_SUCCESS) { - LOG_ERROR("[auto_init_atca] error initializing cryptoauth device #%u\n", i); + int status = initATCADevice((ATCAIfaceCfg *)&atca_params[i].cfg, (ATCADevice)&atca_devs[i]); + if (status != ATCA_SUCCESS) { + LOG_ERROR("[auto_init_atca] error initializing cryptoauth device #%u, status: %d\n", + i, status); + continue; + } + atca_devs_ptr[i] = &atca_devs[i]; + + DEBUG("[auto_init_atca] Registering Driver with address: %x and location: %lx\n", atca_params[i].cfg.atcai2c.address, atca_params[i].atca_loc); + status = psa_register_secure_element(atca_params[i].atca_loc, + &atca_methods, + &atca_config_list[i], + &atca_devs[i]); + if (status != PSA_SUCCESS) { + LOG_ERROR( + "[auto_init_atca] PSA Crypto – error registering cryptoauth PSA driver\ + for device #%u, status: %s\n", i, psa_status_to_humanly_readable(status)); continue; } } } +#else +void auto_init_atca(void) +{ + DEBUG("[auto_init_atca] Number of secure elements: %d\n", ATCA_NUMOF); + for (unsigned i = 0; i < ATCA_NUMOF; i++) { + int status = initATCADevice((ATCAIfaceCfg *)&atca_params[i], (ATCADevice)&atca_devs[i]); + if (status != ATCA_SUCCESS) { + LOG_ERROR("[auto_init_atca] error initializing cryptoauth device #%u, status: %d\n", + i, status); + continue; + } + atca_devs_ptr[i] = &atca_devs[i]; + } +} +#endif diff --git a/sys/auto_init/security/init.c b/sys/auto_init/security/init.c new file mode 100644 index 0000000000..54ec8b5be5 --- /dev/null +++ b/sys/auto_init/security/init.c @@ -0,0 +1,30 @@ +/* + * 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_auto_init + * @{ + * @file + * @brief Initializes security modules + * + * @author Bennet Blischke + * @author Lena Boeckmann + * @} + */ + +#define ENABLE_DEBUG 0 +#include "debug.h" + +void auto_init_security(void) +{ +#if IS_USED(MODULE_CRYPTOAUTHLIB) + extern void auto_init_atca(void); + DEBUG("auto_init_security: atca\n"); + auto_init_atca(); +#endif +} diff --git a/tests/pkg/cryptoauthlib_compare_sha256/main.c b/tests/pkg/cryptoauthlib_compare_sha256/main.c index 6cd744e921..c990997076 100644 --- a/tests/pkg/cryptoauthlib_compare_sha256/main.c +++ b/tests/pkg/cryptoauthlib_compare_sha256/main.c @@ -50,8 +50,19 @@ static int test_riot_sha256(uint8_t *teststring, uint16_t len, static int test_atca_sha(uint8_t *teststring, uint16_t len, uint8_t *expected, uint8_t *result) { - atcab_sha_start(); - atcab_sha_end(result, len, teststring); + ATCA_STATUS status; + ATCADevice dev = atca_devs_ptr[0]; + + status = calib_sha_start(dev); + if (status != ATCA_SUCCESS) { + printf("ATCA SHA start failed: %02x\n", status); + } + + status = calib_sha_end(dev, result, len, teststring); + if (status != ATCA_SUCCESS) { + printf("ATCA SHA end failed: %02x\n", status); + } + return memcmp(expected, result, SHA256_HASH_SIZE); } From b63ca7941e55a5596d54ba7b1eba9f31b7bf8a3b Mon Sep 17 00:00:00 2001 From: Lena Boeckmann Date: Tue, 29 Aug 2023 19:25:14 +0200 Subject: [PATCH 5/8] sys/crypto: Add PSA Crypto Wrappers --- makefiles/pseudomodules.inc.mk | 5 ++ sys/crypto/Kconfig | 1 + sys/crypto/Makefile | 4 ++ sys/crypto/psa_riot_cipher/Kconfig | 38 ++++++++++ sys/crypto/psa_riot_cipher/Makefile | 4 ++ sys/crypto/psa_riot_cipher/aes_128_cbc.c | 91 ++++++++++++++++++++++++ sys/crypto/psa_riot_cipher/aes_256_cbc.c | 61 ++++++++++++++++ sys/crypto/psa_riot_cipher/aes_common.c | 68 ++++++++++++++++++ sys/crypto/psa_riot_cipher/aes_common.h | 59 +++++++++++++++ sys/include/crypto/psa/riot_ciphers.h | 44 ++++++++++++ 10 files changed, 375 insertions(+) create mode 100644 sys/crypto/psa_riot_cipher/Kconfig create mode 100644 sys/crypto/psa_riot_cipher/Makefile create mode 100644 sys/crypto/psa_riot_cipher/aes_128_cbc.c create mode 100644 sys/crypto/psa_riot_cipher/aes_256_cbc.c create mode 100644 sys/crypto/psa_riot_cipher/aes_common.c create mode 100644 sys/crypto/psa_riot_cipher/aes_common.h create mode 100644 sys/include/crypto/psa/riot_ciphers.h diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index bf89174d1d..f753f23173 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -388,6 +388,11 @@ PSEUDOMODULES += posix_headers PSEUDOMODULES += printf_float PSEUDOMODULES += prng PSEUDOMODULES += prng_% +PSEUDOMODULES += psa_riot_cipher_aes_common +PSEUDOMODULES += psa_riot_cipher_aes_128_ecb +PSEUDOMODULES += psa_riot_cipher_aes_128_cbc +PSEUDOMODULES += psa_riot_cipher_aes_192_cbc +PSEUDOMODULES += psa_riot_cipher_aes_256_cbc PSEUDOMODULES += fortuna_reseed ## @defgroup pseudomodule_random_cmd random_cmd ## @ingroup sys_shell_commands diff --git a/sys/crypto/Kconfig b/sys/crypto/Kconfig index 9311436a8a..b22afcd729 100644 --- a/sys/crypto/Kconfig +++ b/sys/crypto/Kconfig @@ -33,6 +33,7 @@ config MODULE_CRYPTO_AES_UNROLL endmenu # Crypto AES options +rsource "psa_riot_cipher/Kconfig" rsource "modes/Kconfig" endif # Crypto diff --git a/sys/crypto/Makefile b/sys/crypto/Makefile index 9e7ab5fd30..7ff0741848 100644 --- a/sys/crypto/Makefile +++ b/sys/crypto/Makefile @@ -4,4 +4,8 @@ endif CFLAGS += -DRIOT_CHACHA_PRNG_DEFAULT="$(RIOT_CHACHA_PRNG_DEFAULT)" +ifneq (,$(filter psa_riot_cipher_%,$(USEMODULE))) + DIRS += psa_riot_cipher +endif + include $(RIOTBASE)/Makefile.base diff --git a/sys/crypto/psa_riot_cipher/Kconfig b/sys/crypto/psa_riot_cipher/Kconfig new file mode 100644 index 0000000000..a57a94f160 --- /dev/null +++ b/sys/crypto/psa_riot_cipher/Kconfig @@ -0,0 +1,38 @@ +# 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. +# + +config MODULE_PSA_RIOT_CIPHER_AES_128_ECB + bool + depends on MODULE_PSA_CRYPTO + select MODULE_CRYPTO_AES_128 + select MODULE_PSA_RIOT_CIPHER + +config MODULE_PSA_RIOT_CIPHER_AES_128_CBC + bool + depends on MODULE_PSA_CRYPTO + select MODULE_CRYPTO_AES_128 + select MODULE_PSA_RIOT_CIPHER + +config MODULE_PSA_RIOT_CIPHER_AES_192_CBC + bool + depends on MODULE_PSA_CRYPTO + select MODULE_CRYPTO_AES_192 + select MODULE_PSA_RIOT_CIPHER + +config MODULE_PSA_RIOT_CIPHER_AES_256_CBC + bool + depends on MODULE_PSA_CRYPTO + select MODULE_CRYPTO_AES_192 + select MODULE_PSA_RIOT_CIPHER + +config MODULE_PSA_RIOT_CIPHER + bool + select MODULE_PSA_RIOT_CIPHER_AES_COMMON + select MODULE_CIPHER_MODES + +config MODULE_PSA_RIOT_CIPHER_AES_COMMON + bool diff --git a/sys/crypto/psa_riot_cipher/Makefile b/sys/crypto/psa_riot_cipher/Makefile new file mode 100644 index 0000000000..aacc8d4aaf --- /dev/null +++ b/sys/crypto/psa_riot_cipher/Makefile @@ -0,0 +1,4 @@ +BASE_MODULE := psa_riot_cipher +SUBMODULES := 1 + +include $(RIOTBASE)/Makefile.base diff --git a/sys/crypto/psa_riot_cipher/aes_128_cbc.c b/sys/crypto/psa_riot_cipher/aes_128_cbc.c new file mode 100644 index 0000000000..09cf654322 --- /dev/null +++ b/sys/crypto/psa_riot_cipher/aes_128_cbc.c @@ -0,0 +1,91 @@ +/* + * 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 Glue code translating between PSA Crypto and the RIOT Cipher module + * + * @author Lena Boeckmann + * + * @} + */ + +#include "psa/crypto.h" +#include "crypto/modes/cbc.h" +#include "aes_common.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +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) +{ + DEBUG("RIOT AES 128 Cipher"); + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_cipher_operation_t operation = psa_cipher_operation_init(); + size_t iv_length = 0; + size_t required_output_buf_size = PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES, + PSA_ALG_CBC_NO_PADDING, input_length); + + if (output_size < required_output_buf_size) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + operation.iv_required = 1; + operation.default_iv_length = PSA_CIPHER_IV_LENGTH(attributes->type, alg); + *output_length = 0; + + status = psa_cipher_generate_iv(&operation, output, operation.default_iv_length, &iv_length); + if (status != PSA_SUCCESS) { + return status; + } + + return cbc_aes_common_encrypt_decrypt(&operation.backend_ctx.cipher_ctx.aes_128, key_buffer, + key_buffer_size, output, input, input_length, + output + iv_length, output_length, PSA_CRYPTO_DRIVER_ENCRYPT); +} + +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) +{ + DEBUG("RIOT AES 128 Cipher"); + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_cipher_operation_t operation = psa_cipher_operation_init(); + size_t required_output_buf_size = PSA_CIPHER_DECRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES, + PSA_ALG_CBC_NO_PADDING, input_length); + + if (output_size < required_output_buf_size) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + operation.iv_required = 1; + operation.default_iv_length = PSA_CIPHER_IV_LENGTH(attributes->type, alg); + *output_length = 0; + + return cbc_aes_common_encrypt_decrypt(&operation.backend_ctx.cipher_ctx.aes_128, key_buffer, + key_buffer_size, input, input + operation.default_iv_length, + input_length - operation.default_iv_length, output, + output_length, PSA_CRYPTO_DRIVER_DECRYPT); +} diff --git a/sys/crypto/psa_riot_cipher/aes_256_cbc.c b/sys/crypto/psa_riot_cipher/aes_256_cbc.c new file mode 100644 index 0000000000..66c1a9bcd8 --- /dev/null +++ b/sys/crypto/psa_riot_cipher/aes_256_cbc.c @@ -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. + */ + +/** + * @ingroup sys_psa_crypto + * @{ + * + * @file + * @brief Glue code translating between PSA Crypto and the RIOT Cipher module + * + * @author Lena Boeckmann + * + * @} + */ + +#include "psa/crypto.h" +#include "crypto/modes/cbc.h" +#include "aes_common.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +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) +{ + DEBUG("RIOT AES 256 Cipher"); + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_cipher_operation_t operation = psa_cipher_operation_init(); + size_t iv_length = 0; + size_t required_output_buf_size = PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES, + PSA_ALG_CBC_NO_PADDING, input_length); + + if (output_size < required_output_buf_size) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + operation.iv_required = 1; + operation.default_iv_length = PSA_CIPHER_IV_LENGTH(attributes->type, alg); + *output_length = 0; + + status = psa_cipher_generate_iv(&operation, output, operation.default_iv_length, &iv_length); + if (status != PSA_SUCCESS) { + return status; + } + status = cbc_aes_common(&operation.backend_ctx.cipher_ctx.aes_256, key_buffer, key_buffer_size, + output, input, input_length, output + operation.default_iv_length, + output_length); + return status; +} diff --git a/sys/crypto/psa_riot_cipher/aes_common.c b/sys/crypto/psa_riot_cipher/aes_common.c new file mode 100644 index 0000000000..48e86ad435 --- /dev/null +++ b/sys/crypto/psa_riot_cipher/aes_common.c @@ -0,0 +1,68 @@ +/* + * 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 + * @brief Glue code translating between PSA Crypto and the RIOT Cipher module + * + * @author Lena Boeckmann + * + * @} + */ + +#include "psa/crypto.h" +#include "crypto/modes/cbc.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +psa_status_t cipher_to_psa_error(int error) +{ + switch (error) { + case CIPHER_ERR_INVALID_KEY_SIZE: + case CIPHER_ERR_INVALID_LENGTH: + case CIPHER_ERR_BAD_CONTEXT_SIZE: + return PSA_ERROR_INVALID_ARGUMENT; + default: + return PSA_ERROR_GENERIC_ERROR; + } +} + +psa_status_t cbc_aes_common_encrypt_decrypt(cipher_t *ctx, + const uint8_t *key_buffer, + size_t key_buffer_size, + const uint8_t *iv, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t *output_length, + psa_encrypt_or_decrypt_t direction) +{ + int ret = 0; + + ret = cipher_init(ctx, CIPHER_AES, key_buffer, key_buffer_size); + if (ret != CIPHER_INIT_SUCCESS) { + return cipher_to_psa_error(ret); + } + + if (direction == PSA_CRYPTO_DRIVER_ENCRYPT) { + ret = cipher_encrypt_cbc(ctx, (uint8_t *)iv, input, input_length, output); + } + else { + ret = cipher_decrypt_cbc(ctx, (uint8_t *)iv, input, input_length, output); + } + if (ret <= 0) { + return cipher_to_psa_error(ret); + } + + *output_length = ret; + return PSA_SUCCESS; +} diff --git a/sys/crypto/psa_riot_cipher/aes_common.h b/sys/crypto/psa_riot_cipher/aes_common.h new file mode 100644 index 0000000000..d70041bb01 --- /dev/null +++ b/sys/crypto/psa_riot_cipher/aes_common.h @@ -0,0 +1,59 @@ +/* + * 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. + */ + +/** + * @cond + * @ingroup sys_crypto + * @{ + * + * @brief Glue code translating between PSA Crypto and the RIOT Cipher module + * + * @author Lena Boeckmann + * + */ + +#ifndef AES_COMMON_H +#define AES_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "psa/crypto.h" +#include "crypto/modes/cbc.h" + +/** + * @brief Converts errors of the RIOT cipher module to PSA status values + * + * @param error + * @return @ref psa_status_t + */ +psa_status_t cipher_to_psa_error(int error); + +/** + * @brief Common AES CBC Encrypt function + * + * @return @ref psa_status_t + */ +psa_status_t cbc_aes_common_encrypt_decrypt(cipher_t *ctx, + const uint8_t *key_buffer, + size_t key_buffer_size, + const uint8_t *iv, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t *output_length, + psa_encrypt_or_decrypt_t direction); + +#ifdef __cplusplus +} +#endif + +#endif /* AES_COMMON_H */ +/** @} */ +/** @endcond */ diff --git a/sys/include/crypto/psa/riot_ciphers.h b/sys/include/crypto/psa/riot_ciphers.h new file mode 100644 index 0000000000..433be055fa --- /dev/null +++ b/sys/include/crypto/psa/riot_ciphers.h @@ -0,0 +1,44 @@ +/* + * 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 + * @{ + * + * @brief Contexts for the RIOT cipher module + * + * @author Lena Boeckmann + * + */ + +#ifndef CRYPTO_PSA_RIOT_CIPHERS_H +#define CRYPTO_PSA_RIOT_CIPHERS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "crypto/ciphers.h" +#include "kernel_defines.h" + +#if IS_USED(MODULE_PSA_RIOT_CIPHER_AES_128_CBC) +typedef cipher_t psa_cipher_aes_128_ctx_t; +#endif +#if IS_USED(MODULE_PSA_RIOT_CIPHER_AES_192_CBC) +typedef cipher_t psa_cipher_aes_192_ctx_t; +#endif +#if IS_USED(MODULE_PSA_RIOT_CIPHER_AES_256_CBC) +typedef cipher_t psa_cipher_aes_256_ctx_t; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* CRYPTO_PSA_RIOT_CIPHERS_H */ +/** @} */ From 2584298ade49c1385d6eb27991d38911ba54a3bc Mon Sep 17 00:00:00 2001 From: Lena Boeckmann Date: Tue, 29 Aug 2023 19:27:03 +0200 Subject: [PATCH 6/8] sys/hashes: Add PSA Crypto Wrappers --- makefiles/pseudomodules.inc.mk | 5 ++ sys/hashes/Kconfig | 2 + sys/hashes/Makefile | 6 +++ sys/hashes/psa_riot_hashes/Kconfig | 39 +++++++++++++++ sys/hashes/psa_riot_hashes/Makefile | 4 ++ sys/hashes/psa_riot_hashes/hmac_sha256.c | 38 +++++++++++++++ sys/hashes/psa_riot_hashes/md5.c | 47 ++++++++++++++++++ sys/hashes/psa_riot_hashes/sha_1.c | 47 ++++++++++++++++++ sys/hashes/psa_riot_hashes/sha_224.c | 47 ++++++++++++++++++ sys/hashes/psa_riot_hashes/sha_256.c | 47 ++++++++++++++++++ sys/include/hashes/psa/riot_hashes.h | 61 ++++++++++++++++++++++++ 11 files changed, 343 insertions(+) create mode 100644 sys/hashes/psa_riot_hashes/Kconfig create mode 100644 sys/hashes/psa_riot_hashes/Makefile create mode 100644 sys/hashes/psa_riot_hashes/hmac_sha256.c create mode 100644 sys/hashes/psa_riot_hashes/md5.c create mode 100644 sys/hashes/psa_riot_hashes/sha_1.c create mode 100644 sys/hashes/psa_riot_hashes/sha_224.c create mode 100644 sys/hashes/psa_riot_hashes/sha_256.c create mode 100644 sys/include/hashes/psa/riot_hashes.h diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index f753f23173..695fe7ea4e 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -393,6 +393,11 @@ PSEUDOMODULES += psa_riot_cipher_aes_128_ecb PSEUDOMODULES += psa_riot_cipher_aes_128_cbc PSEUDOMODULES += psa_riot_cipher_aes_192_cbc PSEUDOMODULES += psa_riot_cipher_aes_256_cbc +PSEUDOMODULES += psa_riot_hashes_md5 +PSEUDOMODULES += psa_riot_hashes_sha_1 +PSEUDOMODULES += psa_riot_hashes_sha_224 +PSEUDOMODULES += psa_riot_hashes_sha_256 +PSEUDOMODULES += psa_riot_hashes_hmac_sha256 PSEUDOMODULES += fortuna_reseed ## @defgroup pseudomodule_random_cmd random_cmd ## @ingroup sys_shell_commands diff --git a/sys/hashes/Kconfig b/sys/hashes/Kconfig index e4fed6e819..05c88932c2 100644 --- a/sys/hashes/Kconfig +++ b/sys/hashes/Kconfig @@ -9,3 +9,5 @@ config MODULE_HASHES bool "Hash algorithms" depends on TEST_KCONFIG select MODULE_CRYPTO + +rsource "psa_riot_hashes/Kconfig" diff --git a/sys/hashes/Makefile b/sys/hashes/Makefile index 48422e909a..fe8fe4002d 100644 --- a/sys/hashes/Makefile +++ b/sys/hashes/Makefile @@ -1 +1,7 @@ +MODULE := hashes + +ifneq (,$(filter psa_riot_hashes_%,$(USEMODULE))) + DIRS += psa_riot_hashes +endif + include $(RIOTBASE)/Makefile.base diff --git a/sys/hashes/psa_riot_hashes/Kconfig b/sys/hashes/psa_riot_hashes/Kconfig new file mode 100644 index 0000000000..981d62fe62 --- /dev/null +++ b/sys/hashes/psa_riot_hashes/Kconfig @@ -0,0 +1,39 @@ +# 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. +# + +config MODULE_PSA_RIOT_HASHES_MD5 + bool + depends on MODULE_PSA_CRYPTO + select MODULE_PSA_RIOT_HASHES + select MODULE_HASHES + +config MODULE_PSA_RIOT_HASHES_SHA_1 + bool + depends on MODULE_PSA_CRYPTO + select MODULE_PSA_RIOT_HASHES + select MODULE_HASHES + +config MODULE_PSA_RIOT_HASHES_SHA_224 + bool + depends on MODULE_PSA_CRYPTO + select MODULE_PSA_RIOT_HASHES + select MODULE_HASHES + +config MODULE_PSA_RIOT_HASHES_SHA_256 + bool + depends on MODULE_PSA_CRYPTO + select MODULE_PSA_RIOT_HASHES + select MODULE_HASHES + +config MODULE_PSA_RIOT_HASHES_HMAC_SHA256 + bool + depends on MODULE_PSA_CRYPTO + select MODULE_PSA_RIOT_HASHES + select MODULE_HASHES + +config MODULE_PSA_RIOT_HASHES + bool diff --git a/sys/hashes/psa_riot_hashes/Makefile b/sys/hashes/psa_riot_hashes/Makefile new file mode 100644 index 0000000000..9b24b47126 --- /dev/null +++ b/sys/hashes/psa_riot_hashes/Makefile @@ -0,0 +1,4 @@ +BASE_MODULE := psa_riot_hashes +SUBMODULES := 1 + +include $(RIOTBASE)/Makefile.base diff --git a/sys/hashes/psa_riot_hashes/hmac_sha256.c b/sys/hashes/psa_riot_hashes/hmac_sha256.c new file mode 100644 index 0000000000..13258358a7 --- /dev/null +++ b/sys/hashes/psa_riot_hashes/hmac_sha256.c @@ -0,0 +1,38 @@ +/* + * 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 + * @{ + * + * @brief Glue code translating between PSA Crypto and the RIOT Hash module + * + * @author Lena Boeckmann + * + * @} + */ + +#include "psa/crypto.h" +#include "hashes/psa/riot_hashes.h" + +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) +{ + hmac_sha256(key_buffer, key_buffer_size, input, input_length, mac); + *mac_length = 32; + + (void)mac_size; + (void)attributes; + return PSA_SUCCESS; +} diff --git a/sys/hashes/psa_riot_hashes/md5.c b/sys/hashes/psa_riot_hashes/md5.c new file mode 100644 index 0000000000..ce7bd8c250 --- /dev/null +++ b/sys/hashes/psa_riot_hashes/md5.c @@ -0,0 +1,47 @@ +/* + * 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 + * @{ + * + * @brief Glue code translating between PSA Crypto and the RIOT Hash module + * + * @author Lena Boeckmann + * + * @} + */ + +#include "psa/crypto.h" +#include "hashes/psa/riot_hashes.h" + +psa_status_t psa_hashes_md5_setup(psa_hashes_md5_ctx_t *ctx) +{ + md5_init((md5_ctx_t *)ctx); + return PSA_SUCCESS; +} + +psa_status_t psa_hashes_md5_update(psa_hashes_md5_ctx_t *ctx, + const uint8_t *input, + size_t input_length) +{ + md5_update((md5_ctx_t *)ctx, input, input_length); + return PSA_SUCCESS; +} + +psa_status_t psa_hashes_md5_finish(psa_hashes_md5_ctx_t *ctx, + uint8_t *hash, + size_t hash_size, + size_t *hash_length) +{ + md5_final((md5_ctx_t *)ctx, hash); + + (void)hash_size; + (void)hash_length; + return PSA_SUCCESS; +} diff --git a/sys/hashes/psa_riot_hashes/sha_1.c b/sys/hashes/psa_riot_hashes/sha_1.c new file mode 100644 index 0000000000..4b1da8c7b4 --- /dev/null +++ b/sys/hashes/psa_riot_hashes/sha_1.c @@ -0,0 +1,47 @@ +/* + * 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 + * @{ + * + * @brief Glue code translating between PSA Crypto and the RIOT Hash module + * + * @author Lena Boeckmann + * + * @} + */ + +#include "psa/crypto.h" +#include "hashes/psa/riot_hashes.h" + +psa_status_t psa_hashes_sha1_setup(psa_hashes_sha1_ctx_t *ctx) +{ + sha1_init((sha1_context *)ctx); + return PSA_SUCCESS; +} + +psa_status_t psa_hashes_sha1_update(psa_hashes_sha1_ctx_t *ctx, + const uint8_t *input, + size_t input_length) +{ + sha1_update((sha1_context *)ctx, input, input_length); + return PSA_SUCCESS; +} + +psa_status_t psa_hashes_sha1_finish(psa_hashes_sha1_ctx_t *ctx, + uint8_t *hash, + size_t hash_size, + size_t *hash_length) +{ + sha1_final((sha1_context *)ctx, hash); + + (void)hash_size; + (void)hash_length; + return PSA_SUCCESS; +} diff --git a/sys/hashes/psa_riot_hashes/sha_224.c b/sys/hashes/psa_riot_hashes/sha_224.c new file mode 100644 index 0000000000..d49185b30e --- /dev/null +++ b/sys/hashes/psa_riot_hashes/sha_224.c @@ -0,0 +1,47 @@ +/* + * 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 + * @{ + * + * @brief Glue code translating between PSA Crypto and the RIOT Hash module + * + * @author Lena Boeckmann + * + * @} + */ + +#include "psa/crypto.h" +#include "hashes/psa/riot_hashes.h" + +psa_status_t psa_hashes_sha224_setup(psa_hashes_sha224_ctx_t *ctx) +{ + sha224_init((sha224_context_t *)ctx); + return PSA_SUCCESS; +} + +psa_status_t psa_hashes_sha224_update(psa_hashes_sha224_ctx_t *ctx, + const uint8_t *input, + size_t input_length) +{ + sha224_update((sha224_context_t *)ctx, input, input_length); + return PSA_SUCCESS; +} + +psa_status_t psa_hashes_sha224_finish(psa_hashes_sha224_ctx_t *ctx, + uint8_t *hash, + size_t hash_size, + size_t *hash_length) +{ + sha224_final((sha224_context_t *)ctx, hash); + + (void)hash_size; + (void)hash_length; + return PSA_SUCCESS; +} diff --git a/sys/hashes/psa_riot_hashes/sha_256.c b/sys/hashes/psa_riot_hashes/sha_256.c new file mode 100644 index 0000000000..ab166d9c15 --- /dev/null +++ b/sys/hashes/psa_riot_hashes/sha_256.c @@ -0,0 +1,47 @@ +/* + * 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 + * @{ + * + * @brief Glue code translating between PSA Crypto and the RIOT Hash module + * + * @author Lena Boeckmann + * + * @} + */ + +#include "psa/crypto.h" +#include "hashes/psa/riot_hashes.h" + +psa_status_t psa_hashes_sha256_setup(psa_hashes_sha256_ctx_t *ctx) +{ + sha256_init((sha256_context_t *)ctx); + return PSA_SUCCESS; +} + +psa_status_t psa_hashes_sha256_update(psa_hashes_sha256_ctx_t *ctx, + const uint8_t *input, + size_t input_length) +{ + sha256_update((sha256_context_t *)ctx, input, input_length); + return PSA_SUCCESS; +} + +psa_status_t psa_hashes_sha256_finish(psa_hashes_sha256_ctx_t *ctx, + uint8_t *hash, + size_t hash_size, + size_t *hash_length) +{ + sha256_final((sha256_context_t *)ctx, hash); + + (void)hash_size; + (void)hash_length; + return PSA_SUCCESS; +} diff --git a/sys/include/hashes/psa/riot_hashes.h b/sys/include/hashes/psa/riot_hashes.h new file mode 100644 index 0000000000..2638560f05 --- /dev/null +++ b/sys/include/hashes/psa/riot_hashes.h @@ -0,0 +1,61 @@ +/* + * 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 + * @{ + * + * @brief Contexts for the RIOT hashes module + * + * @author Lena Boeckmann + * + */ + +#ifndef HASHES_PSA_RIOT_HASHES_H +#define HASHES_PSA_RIOT_HASHES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "kernel_defines.h" + +#if (IS_USED(MODULE_PSA_RIOT_HASHES_MD5)) +#include "hashes/md5.h" + +typedef md5_ctx_t psa_hashes_md5_ctx_t; +#endif + +#if (IS_USED(MODULE_PSA_RIOT_HASHES_SHA_1)) +#include "hashes/sha1.h" + +typedef sha1_context psa_hashes_sha1_ctx_t; +#endif + +#if (IS_USED(MODULE_PSA_RIOT_HASHES_SHA_224)) +#include "hashes/sha224.h" + +typedef sha224_context_t psa_hashes_sha224_ctx_t; +#endif + +#if (IS_USED(MODULE_PSA_RIOT_HASHES_SHA_256)) +#include "hashes/sha256.h" + +typedef sha256_context_t psa_hashes_sha256_ctx_t; +#endif + +#if (IS_USED(MODULE_PSA_RIOT_HASHES_HMAC_SHA256)) +#include "hashes/sha256.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* HASHES_PSA_RIOT_HASHES_H */ +/** @} */ From c71441d74a2d201ca8efbbb1055b016f5c12a814 Mon Sep 17 00:00:00 2001 From: Lena Boeckmann Date: Tue, 29 Aug 2023 19:27:27 +0200 Subject: [PATCH 7/8] examples: Add PSA Crypto example --- examples/psa_crypto/Makefile | 116 ++++++++++++ examples/psa_crypto/Makefile.ci | 28 +++ examples/psa_crypto/README.md | 102 +++++++++++ examples/psa_crypto/app.config.test | 6 + examples/psa_crypto/app.config.test.base | 11 ++ examples/psa_crypto/app.config.test.custom | 8 + examples/psa_crypto/app.config.test.multi_se | 9 + examples/psa_crypto/app.config.test.se | 6 + examples/psa_crypto/custom_atca_params.h | 125 +++++++++++++ examples/psa_crypto/example_cipher_aes_128.c | 131 ++++++++++++++ examples/psa_crypto/example_ecdsa_p256.c | 177 +++++++++++++++++++ examples/psa_crypto/example_hmac_sha256.c | 111 ++++++++++++ examples/psa_crypto/main.c | 90 ++++++++++ examples/psa_crypto/tests/01-run.py | 13 ++ 14 files changed, 933 insertions(+) create mode 100644 examples/psa_crypto/Makefile create mode 100644 examples/psa_crypto/Makefile.ci create mode 100644 examples/psa_crypto/README.md create mode 100644 examples/psa_crypto/app.config.test create mode 100644 examples/psa_crypto/app.config.test.base create mode 100644 examples/psa_crypto/app.config.test.custom create mode 100644 examples/psa_crypto/app.config.test.multi_se create mode 100644 examples/psa_crypto/app.config.test.se create mode 100644 examples/psa_crypto/custom_atca_params.h create mode 100644 examples/psa_crypto/example_cipher_aes_128.c create mode 100644 examples/psa_crypto/example_ecdsa_p256.c create mode 100644 examples/psa_crypto/example_hmac_sha256.c create mode 100644 examples/psa_crypto/main.c create mode 100755 examples/psa_crypto/tests/01-run.py diff --git a/examples/psa_crypto/Makefile b/examples/psa_crypto/Makefile new file mode 100644 index 0000000000..3ecba20ed3 --- /dev/null +++ b/examples/psa_crypto/Makefile @@ -0,0 +1,116 @@ +# This has to be the absolute path to the RIOT base directory: +RIOTBASE ?= $(CURDIR)/../.. + +APPLICATION = example_psa_crypto + +BOARD ?= native + +# Necessary configurations when using Kconfig dependency resolution +# The file `app.config.test` is always used for the build configuration. +# The config files below are only added if needed. +ifeq (1, $(TEST_KCONFIG)) + ifeq (1, $(SECURE_ELEMENT)) + CFLAGS += -DSECURE_ELEMENT # Application specific (not needed by PSA) + CFLAGS += -DCUSTOM_ATCA_PARAMS # Application specific (not needed by PSA) + INCLUDES += -I$(APPDIR) # Application specific (not needed by PSA) + KCONFIG_ADD_CONFIG += $(APPDIR)/app.config.test.se + else ifeq (2, $(SECURE_ELEMENT)) + CFLAGS += -DSECURE_ELEMENT # Application specific (not needed by PSA) + CFLAGS += -DMULTIPLE_SE # Application specific (not needed by PSA) + CFLAGS += -DCUSTOM_ATCA_PARAMS # Application specific (not needed by PSA) + INCLUDES += -I$(APPDIR) + KCONFIG_ADD_CONFIG += $(APPDIR)/app.config.test.multi_se + else ifdef CUSTOM_BACKEND + KCONFIG_ADD_CONFIG += $(APPDIR)/app.config.test.base + KCONFIG_ADD_CONFIG += $(APPDIR)/app.config.test.custom + else + KCONFIG_ADD_CONFIG += $(APPDIR)/app.config.test.base + endif +else + USEMODULE += ztimer + USEMODULE += ztimer_usec + + USEMODULE += psa_crypto + + # Hashes are needed for ECDSA operations (including secure elements), which + # is why we always build them + USEMODULE += psa_hash + USEMODULE += psa_hash_sha_256 + + ifeq (1, $(SECURE_ELEMENT)) + # When using a secure element, the type is required. + # Also you can specify the number of key slots required to store keys. + CFLAGS += -DSECURE_ELEMENT # Application specific (not needed by PSA) + CFLAGS += -DCUSTOM_ATCA_PARAMS # Application specific (not needed by PSA) + INCLUDES += -I$(APPDIR) # Application specific (not needed by PSA) + + CFLAGS += -DCONFIG_PSA_PROTECTED_KEY_COUNT=4 + CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=1 + USEMODULE += psa_secure_element + USEMODULE += psa_secure_element_ateccx08a + USEMODULE += psa_secure_element_ateccx08a_ecc_p256 + else ifeq (2, $(SECURE_ELEMENT)) + CFLAGS += -DSECURE_ELEMENT # Application specific (not needed by PSA) + CFLAGS += -DMULTIPLE_SE # Application specific (not needed by PSA) + CFLAGS += -DCUSTOM_ATCA_PARAMS # Application specific (not needed by PSA) + INCLUDES += -I$(APPDIR) # Application specific (not needed by PSA) + CFLAGS += -DCONFIG_PSA_MAX_SE_COUNT=2 + CFLAGS += -DCONFIG_PSA_PROTECTED_KEY_COUNT=8 + CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=2 + USEMODULE += psa_secure_element + USEMODULE += psa_secure_element_multiple + USEMODULE += psa_secure_element_ateccx08a + USEMODULE += psa_secure_element_ateccx08a_ecc_p256 + else ifdef CUSTOM_BACKEND + # Necessary configuration when using Make dependency resolution + # This first part chooses the operation. If nothing else es specified, + # a default backend is built depending on the platform capabilities. + USEMODULE += psa_cipher + USEMODULE += psa_cipher_aes_128_cbc + + USEMODULE += psa_mac + USEMODULE += psa_mac_hmac_sha_256 + + USEMODULE += psa_asymmetric + USEMODULE += psa_asymmetric_ecc_p256r1 + + # If you want to use a custom backend, you need to do it this way. + USEMODULE += psa_cipher_aes_128_cbc_custom_backend + USEMODULE += psa_cipher_aes_128_cbc_backend_riot # force custom backend + + USEMODULE += psa_mac_hmac_sha_256_custom_backend + USEMODULE += psa_mac_hmac_sha_256_backend_riot # force custom backend + + USEMODULE += psa_hash_sha_256_custom_backend + USEMODULE += psa_hash_sha_256_backend_riot + + USEMODULE += psa_asymmetric_ecc_p256r1_custom_backend + USEMODULE += psa_asymmetric_ecc_p256r1_backend_microecc # force custom backend + else + # Necessary configuration when using Make dependency resolution + # This part only chooses the operation. If nothing else es specified, + # a default backend is built depending on the platform capabilities. + USEMODULE += psa_cipher + USEMODULE += psa_cipher_aes_128_cbc + + USEMODULE += psa_mac + USEMODULE += psa_mac_hmac_sha_256 + + USEMODULE += psa_asymmetric + USEMODULE += psa_asymmetric_ecc_p256r1 + endif + + ifndef SECURE_ELEMENT + CFLAGS += -DCONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1 + CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=3 + endif +endif + +ifndef SECURE_ELEMENT + # The software implementations need a larger stack, so we increase the stack size. + CFLAGS += -DTHREAD_STACKSIZE_MAIN=\(12*THREAD_STACKSIZE_DEFAULT\) +endif + +SHOULD_RUN_KCONFIG := + +include $(RIOTBASE)/Makefile.include diff --git a/examples/psa_crypto/Makefile.ci b/examples/psa_crypto/Makefile.ci new file mode 100644 index 0000000000..622ae711a6 --- /dev/null +++ b/examples/psa_crypto/Makefile.ci @@ -0,0 +1,28 @@ +BOARD_INSUFFICIENT_MEMORY := \ + arduino-duemilanove \ + arduino-leonardo \ + arduino-mega2560 \ + arduino-nano \ + arduino-uno \ + atmega328p \ + atmega328p-xplained-mini \ + atmega8 \ + bluepill-stm32f030c8 \ + i-nucleo-lrwan1 \ + nucleo-f030r8 \ + nucleo-f031k6 \ + nucleo-f042k6 \ + nucleo-f303k8 \ + nucleo-f334r8 \ + nucleo-l011k4 \ + nucleo-l031k6 \ + nucleo-l053r8 \ + samd10-xmini \ + slstk3400a \ + stk3200 \ + stm32f030f4-demo \ + stm32f0discovery \ + stm32g0316-disco \ + stm32l0538-disco \ + waspmote-pro \ + # diff --git a/examples/psa_crypto/README.md b/examples/psa_crypto/README.md new file mode 100644 index 0000000000..5564fca302 --- /dev/null +++ b/examples/psa_crypto/README.md @@ -0,0 +1,102 @@ +# Example Applications for PSA Crypto +This example application is supposed to show two things: +1. How to use basic functions of the PSA Crypto API +2. How to configure the implementation with Kconfig dependency resolution vs. Make dependency resolution + +## Basic usage of PSA Crypto +There are three example operations: +- AES 128 CBC +- HMAC SHA256 +- ECDSA with a P256 curve + +Each comes in its own sourcefile called `example_.c`. To see which functions to call to perform each operations, please read the code. + +The application measures the processing times of the example operations. The table below shows the expected runtime values +for software and hardware backends as well as secure elements, measured on the nRF52840dk (this is only to show the expected difference, values will differ on other platforms). + +| Operations | Backends | Runtime \[us\] | +|-------------|----------------|------------------| +| HMAC SHA256 | CryptoCell 310 | 282 | +| | RIOT Hashes | 468 | +| | ATECC608A | 56376 | +| AES 128 CBC | CryptoCell 310 | 140 | +| | RIOT Cipher | 295 | +| | ATECC608A | 68819 | +| ECDSA P256 | CryptoCell 310 | 60931 | +| | Micro-ECC | 522424 | +| | ATECC608A | 285542 | + + +## Configuration of the API +There are two ways to configure the API: module selection via Kconfig and module selection +via Makefiles. + +To see which modules should be chosen for each configuration, please read the Makefile and +the `app.config.test.*` files. + +### Kconfig +> **NOTE:** In this application all the configurations are in separate app.config files +> for demonstration purposes. You can also write all configs into one file or choose them +> via `menuconfig`. +> To access the GUI, run `TEST_KCONFIG=1 BOARD= make menuconfig`. + +When building the application with the `TEST_KCONFIG=1` option, the first config file parsed by the build system is `app.config.test`. This selects the PSA Crypto module and other modules our application needs (e.g. ztimer). If you need cryptographic keys, you can specify the number of key slots needed for key storage (the default is set to 5). +The graph below shows how the `app.config` files in this application are included. +Selections in `app.config.test` are always applied. +The others are only added, if you specify the corresponding build option. + +```mermaid + flowchart TD; + app.config.test -- default --> app.config.test.base; + app.config.test.base -- CUSTOM_BACKEND=1 --> app.config.test.custom; + app.config.test -- SECURE_ELEMENT=1 --> app.config.test.se; + app.config.test -- SECURE_ELEMENT=2 --> app.config.test.multi_se; +``` +If you build this without specifying anything else, the symbols in `app.config.test.base` +are added and PSA Crypto will automatically choose a default crypto backend depending on the platform you're building for. +For example when your platform is `native`, software implementations are built. +When you specify `BOARD=nrf52840dk`, the hardware accelerator of the board will be built. + +If you want to force a custom backend, you can specify that in the Kconfig file. This application already contains the configuration for a custom backend (see `app.config.test.custom`), which will be added to the application build when you define `CUSTOM_BACKEND=1`. + +Instead of or in addition to the default and custom implementations you can use a secure element as a backend (see Section [Using Secure Elements](#using-secure-elements]). +Secure elements are independent of the other backends. In this application, when you +choose secure elements, they are built instead of the other backends. + +Please note that the build options `CUSTOM_BACKEND` and `SECURE_ELEMENT` only apply to this specific application and have nothing to do with the PSA implementation. + +### Make +All the configurations in the Kconfig files can also be applied using Make dependency resolution. The Makefile contains all the modules that must be selected when building the different configurations. +They can all be built as described above, but *without* defining TEST_KCONFIG. + +To prevent conflicts when building this application multiple times with different backends, it is best to remove the `bin` directory in between builds. + +## Using Secure Elements +> **NOTE:** +> Currently this implementation only supports Microchip ATECCX08A devices. Those devices need to be configured and locked to be able to correctly use them. +> This implementation assumes that you have done that and that you know your device's configuration. + +You can build this app either with one secure element or two secure elements (`SECURE_ELEMENT=1` or `SECURE_ELEMENT=2`). To be able to use your device, make sure, you've completed the following procedure. + +In the application folder you can find a file called `custom_atca_params.h`, which overwrites the device parameters in `atca_params.h` in the cryptoauthlib package folder. +To use more than one secure element, you need to specify device parameters for both of them. +This application assumes that you connect two devices with different I2C addresses on the same I2C bus. +Alternatively you can connect two devices with the same address on separate buses. +You can modify `custom_atca_params.h` according to your device configurations and requirements. + +For PSA Crypto, you also need to define a location value. Here these are defined as `PSA_ATCA_LOCATION_DEV0` and `PSA_ATCA_LOCATION_DEV1`. They can be any value between `PSA_KEY_LOCATION_SE_MIN` and `PSA_KEY_LOCATION_SE_MAX`. +A special value is `PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT`, which can be used when only one secure element is needed. + +Below the `ATCA_PARAMS` definitions, you can see the slot configurations. +Here you need to specify for each connected secure element what kind of key can be stored in which slot, and whether a slot is already occupied. The structure is declared in `pkg/cryptoauthlib/include/atca.h` and contains the following elements: +1. `key_type_allowed` (takes `psa_key_type_t`) +2. `key_persistent` (is 0, can be ignored for now, since PSA does not yet support persistent storage) +3. `slot_occupied` (should be 0 at start up, PSA will use this to mark slots as occupied) + +The list in `custom_atca_params.h` contains an example configuration. If your device configuration is not compatible, you'll need to change the values as necessary. +This is required, so the implementation can allocate free key slots and can generate and import new keys. If the device configuration does not match the values in the list or if your key slots are not writeable, you will get execution errors. + +The current implementation does not support the use of keys that are already stored on the device. + +## Note +If you need more information about the build options, please refer to the API documentation. diff --git a/examples/psa_crypto/app.config.test b/examples/psa_crypto/app.config.test new file mode 100644 index 0000000000..d5a63d3a56 --- /dev/null +++ b/examples/psa_crypto/app.config.test @@ -0,0 +1,6 @@ +CONFIG_MODULE_PSA_CRYPTO=y + +CONFIG_MODULE_PSA_HASH=y +CONFIG_MODULE_PSA_HASH_SHA_256=y + +CONFIG_ZTIMER_USEC=y diff --git a/examples/psa_crypto/app.config.test.base b/examples/psa_crypto/app.config.test.base new file mode 100644 index 0000000000..fe97dea42c --- /dev/null +++ b/examples/psa_crypto/app.config.test.base @@ -0,0 +1,11 @@ +CONFIG_MODULE_PSA_CIPHER=y +CONFIG_MODULE_PSA_CIPHER_AES_128_CBC=y + +CONFIG_MODULE_PSA_MAC=y +CONFIG_MODULE_PSA_MAC_HMAC_SHA_256=y + +CONFIG_MODULE_PSA_ASYMMETRIC=y +CONFIG_MODULE_PSA_ASYMMETRIC_ECC_P256R1=y + +CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1 +CONFIG_PSA_SINGLE_KEY_COUNT=3 diff --git a/examples/psa_crypto/app.config.test.custom b/examples/psa_crypto/app.config.test.custom new file mode 100644 index 0000000000..e05eb8c604 --- /dev/null +++ b/examples/psa_crypto/app.config.test.custom @@ -0,0 +1,8 @@ +# force software backends +CONFIG_MODULE_PSA_CIPHER_AES_128_CBC_BACKEND_RIOT=y +CONFIG_MODULE_PSA_HASH_SHA_256_BACKEND_RIOT=y +CONFIG_MODULE_PSA_MAC_HMAC_SHA_256_BACKEND_RIOT=y +CONFIG_MODULE_PSA_ASYMMETRIC_ECC_P256R1_BACKEND_MICROECC=y + +CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1 +CONFIG_PSA_SINGLE_KEY_COUNT=3 diff --git a/examples/psa_crypto/app.config.test.multi_se b/examples/psa_crypto/app.config.test.multi_se new file mode 100644 index 0000000000..4d22339308 --- /dev/null +++ b/examples/psa_crypto/app.config.test.multi_se @@ -0,0 +1,9 @@ + +CONFIG_MODULE_PSA_SECURE_ELEMENT=y +CONFIG_MODULE_PSA_SECURE_ELEMENT_ATECCX08A=y +CONFIG_MODULE_PSA_SECURE_ELEMENT_ATECCX08A_ECC_P256=y +CONFIG_MODULE_PSA_SECURE_ELEMENT_MULTIPLE=y + +CONFIG_PSA_MAX_SE_COUNT=2 +CONFIG_PSA_PROTECTED_KEY_COUNT=8 +CONFIG_PSA_SINGLE_KEY_COUNT=2 diff --git a/examples/psa_crypto/app.config.test.se b/examples/psa_crypto/app.config.test.se new file mode 100644 index 0000000000..939fb1055b --- /dev/null +++ b/examples/psa_crypto/app.config.test.se @@ -0,0 +1,6 @@ +CONFIG_MODULE_PSA_SECURE_ELEMENT=y +CONFIG_MODULE_PSA_SECURE_ELEMENT_ATECCX08A=y +CONFIG_MODULE_PSA_SECURE_ELEMENT_ATECCX08A_ECC_P256=y + +CONFIG_PSA_PROTECTED_KEY_COUNT=4 +CONFIG_PSA_SINGLE_KEY_COUNT=1 diff --git a/examples/psa_crypto/custom_atca_params.h b/examples/psa_crypto/custom_atca_params.h new file mode 100644 index 0000000000..c3d4efbce4 --- /dev/null +++ b/examples/psa_crypto/custom_atca_params.h @@ -0,0 +1,125 @@ +/* + * 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 examples + * @{ + * + * @file + * @brief Example custom atca_params.h file to use multiple ATECC608A + * secure elements as backends for PSA Crypto + * + * @author Lena Boeckmann + * + */ +#ifndef CUSTOM_ATCA_PARAMS_H +#define CUSTOM_ATCA_PARAMS_H + +#include "cryptoauthlib.h" +#include "psa/crypto.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PSA_ATCA_LOCATION_DEV0 (PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT) +#define ATCA_PARAM_I2C_DEV0 (I2C_DEV(0)) /*!< Change this to the bus you want to use */ +#define ATCA_PARAM_ADDR_DEV0 (0xC0) /*!< Change this to your first device's address */ +#define ATCA_DEVTYPE_DEV0 (ATECC608A) +#define ATCA_RX_RETRIES (20) + +#ifdef MULTIPLE_SE +#define PSA_ATCA_LOCATION_DEV1 (PSA_KEY_LOCATION_SE_MIN) +#define ATCA_PARAM_I2C_DEV1 (I2C_DEV(0)) /*!< Change this to the bus you want to use */ +#define ATCA_PARAM_ADDR_DEV1 (0xCC) /*!< Change this to your second device's address */ +#define ATCA_DEVTYPE_DEV1 (ATECC608A) + +#define ATCA_PARAMS { .atca_loc = PSA_ATCA_LOCATION_DEV0,\ + .cfg = {\ + .iface_type = ATCA_I2C_IFACE, \ + .devtype = ATCA_DEVTYPE_DEV0, \ + .atcai2c.address = ATCA_PARAM_ADDR_DEV0, \ + .atcai2c.bus = ATCA_PARAM_I2C_DEV0, \ + .atcai2c.baud = -1, /**< Not used in RIOT */ \ + .wake_delay = 1500, \ + .rx_retries = ATCA_RX_RETRIES } \ + }, \ + { .atca_loc = PSA_ATCA_LOCATION_DEV1,\ + .cfg = {\ + .iface_type = ATCA_I2C_IFACE, \ + .devtype = ATCA_DEVTYPE_DEV1, \ + .atcai2c.address = ATCA_PARAM_ADDR_DEV1, \ + .atcai2c.bus = ATCA_PARAM_I2C_DEV1, \ + .atcai2c.baud = -1, /**< Not used in RIOT */ \ + .wake_delay = 1500, \ + .rx_retries = ATCA_RX_RETRIES } \ + } +#else +#define ATCA_PARAMS { .atca_loc = PSA_ATCA_LOCATION_DEV0,\ + .cfg = {\ + .iface_type = ATCA_I2C_IFACE, \ + .devtype = ATCA_DEVTYPE_DEV0, \ + .atcai2c.address = ATCA_PARAM_ADDR_DEV0, \ + .atcai2c.bus = ATCA_PARAM_I2C_DEV0, \ + .atcai2c.baud = -1, /**< Not used in RIOT */ \ + .wake_delay = 1500, \ + .rx_retries = ATCA_RX_RETRIES } \ + } +#endif /* MULTIPLE_SE */ + +#define ATCA_SLOTS_DEV0 { \ + { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { PSA_KEY_TYPE_AES, 0, 0 }, \ + { PSA_KEY_TYPE_HMAC, 0, 0 }, \ + { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { 0, 1, 1 }, \ + { 0, 0, 0 }, \ + { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { 0, 0, 0 }, \ + { 0, 0, 0 }} + +#ifdef MULTIPLE_SE +#define ATCA_SLOTS_DEV1 { \ + { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { PSA_KEY_TYPE_AES, 0, 0 }, \ + { PSA_KEY_TYPE_HMAC, 0, 0 }, \ + { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { 0, 1, 1 }, \ + { 0, 0, 0 }, \ + { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \ + { 0, 0, 0 }, \ + { 0, 0, 0 }} +#endif + +#ifdef MULTIPLE_SE +#define ATCA_CONFIG_LIST { ATCA_SLOTS_DEV0 }, \ + { ATCA_SLOTS_DEV1 } +#else +#define ATCA_CONFIG_LIST { ATCA_SLOTS_DEV0 } +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* CUSTOM_ATCA_PARAMS_H */ +/** @} */ diff --git a/examples/psa_crypto/example_cipher_aes_128.c b/examples/psa_crypto/example_cipher_aes_128.c new file mode 100644 index 0000000000..f3f5513f3a --- /dev/null +++ b/examples/psa_crypto/example_cipher_aes_128.c @@ -0,0 +1,131 @@ +/* + * 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 examples + * @{ + * + * @brief Example functions for AES CBC encryption with PSA Crypto + * + * @author Lena Boeckmann + * + * @} + */ + +#include +#include + +#include "psa/crypto.h" + +#define AES_128_KEY_SIZE (16) +#define AES_256_KEY_SIZE (32) + +static const uint8_t KEY_128[] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c +}; + +static uint8_t PLAINTEXT[] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51 +}; +static uint8_t PLAINTEXT_LEN = 32; + +/** + * @brief Example function to perform an AES-128 CBC encryption and decryption + * with the PSA Crypto API. + * + * @return psa_status_t + */ +psa_status_t example_cipher_aes_128(void) +{ + psa_status_t status = PSA_ERROR_DOES_NOT_EXIST; + psa_key_id_t key_id = 0; + psa_key_attributes_t attr = psa_key_attributes_init(); + psa_key_usage_t usage = PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT; + + size_t encr_output_size = PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES, + PSA_ALG_CBC_NO_PADDING, PLAINTEXT_LEN); + + uint8_t cipher_out[encr_output_size]; + uint8_t plain_out[sizeof(PLAINTEXT)]; + size_t output_len = 0; + + psa_set_key_algorithm(&attr, PSA_ALG_CBC_NO_PADDING); + psa_set_key_usage_flags(&attr, usage); + psa_set_key_bits(&attr, 128); + psa_set_key_type(&attr, PSA_KEY_TYPE_AES); + +#ifdef SECURE_ELEMENT + psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION + (PSA_KEY_LIFETIME_VOLATILE, PSA_ATCA_LOCATION_DEV0); + psa_set_key_lifetime(&attr, lifetime); +#endif + + status = psa_import_key(&attr, KEY_128, AES_128_KEY_SIZE, &key_id); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_cipher_encrypt(key_id, PSA_ALG_CBC_NO_PADDING, PLAINTEXT, + PLAINTEXT_LEN, cipher_out, encr_output_size, &output_len); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_cipher_decrypt(key_id, PSA_ALG_CBC_NO_PADDING, cipher_out, + sizeof(cipher_out), plain_out, sizeof(plain_out), &output_len); + if (status == PSA_SUCCESS) { + return (memcmp(PLAINTEXT, plain_out, sizeof(plain_out)) ? -1 : 0); + } + return status; +} + +#ifdef MULTIPLE_SE +psa_status_t example_cipher_aes_128_sec_se(void) +{ + psa_status_t status = PSA_ERROR_DOES_NOT_EXIST; + psa_key_id_t key_id = 0; + psa_key_attributes_t attr = psa_key_attributes_init(); + psa_key_usage_t usage = PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT; + psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( + PSA_KEY_LIFETIME_VOLATILE, PSA_ATCA_LOCATION_DEV1); + + size_t encr_output_size = PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES, + PSA_ALG_CBC_NO_PADDING, PLAINTEXT_LEN); + uint8_t cipher_out[encr_output_size]; + uint8_t plain_out[sizeof(PLAINTEXT)]; + size_t output_len = 0; + + psa_set_key_lifetime(&attr, lifetime); + psa_set_key_algorithm(&attr, PSA_ALG_CBC_NO_PADDING); + psa_set_key_usage_flags(&attr, usage); + psa_set_key_bits(&attr, 128); + psa_set_key_type(&attr, PSA_KEY_TYPE_AES); + + status = psa_import_key(&attr, KEY_128, AES_128_KEY_SIZE, &key_id); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_cipher_encrypt(key_id, PSA_ALG_CBC_NO_PADDING, PLAINTEXT, + PLAINTEXT_LEN, cipher_out, encr_output_size, &output_len); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_cipher_decrypt(key_id, PSA_ALG_CBC_NO_PADDING, cipher_out, + sizeof(cipher_out), plain_out, sizeof(plain_out), &output_len); + if (status == PSA_SUCCESS) { + return (memcmp(PLAINTEXT, plain_out, sizeof(plain_out)) ? -1 : 0); + } + return status; +} +#endif diff --git a/examples/psa_crypto/example_ecdsa_p256.c b/examples/psa_crypto/example_ecdsa_p256.c new file mode 100644 index 0000000000..54ed87941d --- /dev/null +++ b/examples/psa_crypto/example_ecdsa_p256.c @@ -0,0 +1,177 @@ +/* + * 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 examples + * @{ + * + * @brief Example functions for ECDSA with PSA Crypto + * + * @author Lena Boeckmann + * + * @} + */ + +#include +#include + +#include "psa/crypto.h" + +#define ECDSA_MESSAGE_SIZE (127) +#define ECC_KEY_SIZE (256) + +/** + * @brief Example function to perform an ECDSA operation with a NIST P256 curve + * with the PSA Crypto API. + * + * @return psa_status_t + */ +psa_status_t example_ecdsa_p256(void) +{ + psa_key_id_t privkey_id; + psa_key_attributes_t privkey_attr = psa_key_attributes_init(); + psa_key_id_t pubkey_id; + psa_key_attributes_t pubkey_attr = psa_key_attributes_init(); + + psa_key_usage_t usage = PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH; + psa_key_type_t type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); + psa_algorithm_t alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256); + psa_key_bits_t bits = ECC_KEY_SIZE; + uint8_t bytes = + PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), bits); + + uint8_t public_key[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(PSA_KEY_TYPE_ECC_KEY_PAIR( + PSA_ECC_FAMILY_SECP_R1), + ECC_KEY_SIZE)] = { 0 }; + size_t pubkey_length; + uint8_t signature[PSA_SIGN_OUTPUT_SIZE(type, bits, alg)]; + size_t sig_length; + uint8_t msg[ECDSA_MESSAGE_SIZE] = { 0x0b }; + uint8_t hash[PSA_HASH_LENGTH(PSA_ALG_SHA_256)]; + size_t hash_length; + + psa_set_key_algorithm(&privkey_attr, alg); + psa_set_key_usage_flags(&privkey_attr, usage); + psa_set_key_type(&privkey_attr, type); + psa_set_key_bits(&privkey_attr, bits); + +#ifdef SECURE_ELEMENT + psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( + PSA_KEY_LIFETIME_VOLATILE, PSA_ATCA_LOCATION_DEV0); + psa_set_key_lifetime(&privkey_attr, lifetime); +#endif + + psa_status_t status = PSA_ERROR_DOES_NOT_EXIST; + + status = psa_generate_key(&privkey_attr, &privkey_id); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_export_public_key(privkey_id, public_key, sizeof(public_key), &pubkey_length); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_hash_compute(PSA_ALG_SHA_256, msg, sizeof(msg), hash, sizeof(hash), &hash_length); + if (status != PSA_SUCCESS) { + return status; + } + +#ifdef SECURE_ELEMENT + psa_set_key_lifetime(&pubkey_attr, lifetime); +#endif + psa_set_key_algorithm(&pubkey_attr, alg); + psa_set_key_usage_flags(&pubkey_attr, PSA_KEY_USAGE_VERIFY_HASH); + psa_set_key_bits(&pubkey_attr, PSA_BYTES_TO_BITS(bytes)); + psa_set_key_type(&pubkey_attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); + + status = psa_import_key(&pubkey_attr, public_key, pubkey_length, &pubkey_id); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_sign_hash(privkey_id, alg, hash, sizeof(hash), signature, sizeof(signature), + &sig_length); + if (status != PSA_SUCCESS) { + return status; + } + + return psa_verify_hash(pubkey_id, alg, hash, sizeof(hash), signature, sig_length); +} + +#ifdef MULTIPLE_SE +psa_status_t example_ecdsa_p256_sec_se(void) +{ + psa_key_id_t privkey_id; + psa_key_attributes_t privkey_attr = psa_key_attributes_init(); + psa_key_id_t pubkey_id; + psa_key_attributes_t pubkey_attr = psa_key_attributes_init(); + + psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( + PSA_KEY_LIFETIME_VOLATILE, PSA_ATCA_LOCATION_DEV1); + psa_key_usage_t usage = PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH; + psa_key_type_t type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); + psa_algorithm_t alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256); + psa_key_bits_t bits = 256; + uint8_t bytes = + PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), bits); + + uint8_t public_key[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(PSA_KEY_TYPE_ECC_KEY_PAIR( + PSA_ECC_FAMILY_SECP_R1), 256)] = { 0 }; + size_t pubkey_length; + + uint8_t signature[PSA_SIGN_OUTPUT_SIZE(type, bits, alg)]; + size_t sig_length; + uint8_t msg[ECDSA_MESSAGE_SIZE] = { 0x0b }; + uint8_t hash[PSA_HASH_LENGTH(PSA_ALG_SHA_256)]; + size_t hash_length; + + psa_set_key_lifetime(&privkey_attr, lifetime); + psa_set_key_algorithm(&privkey_attr, alg); + psa_set_key_usage_flags(&privkey_attr, usage); + psa_set_key_type(&privkey_attr, type); + psa_set_key_bits(&privkey_attr, bits); + + psa_status_t status = PSA_ERROR_DOES_NOT_EXIST; + + status = psa_generate_key(&privkey_attr, &privkey_id); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_export_public_key(privkey_id, public_key, sizeof(public_key), &pubkey_length); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_hash_compute(PSA_ALG_SHA_256, msg, sizeof(msg), hash, sizeof(hash), &hash_length); + if (status != PSA_SUCCESS) { + return status; + } + + psa_set_key_lifetime(&pubkey_attr, lifetime); + psa_set_key_algorithm(&pubkey_attr, alg); + psa_set_key_usage_flags(&pubkey_attr, PSA_KEY_USAGE_VERIFY_HASH); + psa_set_key_bits(&pubkey_attr, PSA_BYTES_TO_BITS(bytes)); + psa_set_key_type(&pubkey_attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); + + status = psa_import_key(&pubkey_attr, public_key, pubkey_length, &pubkey_id); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_sign_hash(privkey_id, alg, hash, sizeof(hash), signature, sizeof(signature), + &sig_length); + if (status != PSA_SUCCESS) { + return status; + } + + return psa_verify_hash(pubkey_id, alg, hash, sizeof(hash), signature, sig_length); +} +#endif diff --git a/examples/psa_crypto/example_hmac_sha256.c b/examples/psa_crypto/example_hmac_sha256.c new file mode 100644 index 0000000000..712cad3a17 --- /dev/null +++ b/examples/psa_crypto/example_hmac_sha256.c @@ -0,0 +1,111 @@ +/* + * 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 examples + * @{ + * + * @brief Example functions for HMAC SHA256 with PSA Crypto + * + * @author Lena Boeckmann + * + * @} + */ + +#include +#include + +#include "psa/crypto.h" + +static const uint8_t HMAC_KEY[] = { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b +}; +static size_t HMAC_KEY_LEN = 32; + +static const uint8_t HMAC_MSG[] = { + 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x68, 0x6d, 0x61, 0x63, 0x32, 0x35, 0x36 +}; +static size_t HMAC_MSG_LEN = 32; + +/** + * @brief Example function to perform an HMAC SHA-256 computation + * with the PSA Crypto API. + * + * @return psa_status_t + */ +psa_status_t example_hmac_sha256(void) +{ + psa_key_attributes_t attr = psa_key_attributes_init(); + psa_key_id_t key_id = 0; + psa_key_usage_t usage = PSA_KEY_USAGE_SIGN_MESSAGE; + + size_t digest_size = + PSA_MAC_LENGTH(PSA_KEY_TYPE_HMAC, HMAC_KEY_LEN, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + uint8_t digest[digest_size]; + size_t output_len = 0; + + psa_set_key_algorithm(&attr, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + psa_set_key_usage_flags(&attr, usage); + psa_set_key_bits(&attr, PSA_BYTES_TO_BITS(HMAC_KEY_LEN)); + psa_set_key_type(&attr, PSA_KEY_TYPE_HMAC); + +#ifdef SECURE_ELEMENT + psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( + PSA_KEY_LIFETIME_VOLATILE, PSA_ATCA_LOCATION_DEV0); + psa_set_key_lifetime(&attr, lifetime); +#endif + + psa_status_t status = PSA_ERROR_DOES_NOT_EXIST; + status = psa_import_key(&attr, HMAC_KEY, HMAC_KEY_LEN, &key_id); + if (status != PSA_SUCCESS) { + return status; + } + + return psa_mac_compute(key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256), + HMAC_MSG, HMAC_MSG_LEN, digest, digest_size, + &output_len); +} + +#if MULTIPLE_SE +psa_status_t example_hmac_sha256_sec_se(void) +{ + psa_key_attributes_t attr = psa_key_attributes_init(); + psa_key_id_t key_id = 0; + psa_key_usage_t usage = PSA_KEY_USAGE_SIGN_MESSAGE; + psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( + PSA_KEY_LIFETIME_VOLATILE, PSA_ATCA_LOCATION_DEV1); + + size_t digest_size = + PSA_MAC_LENGTH(PSA_KEY_TYPE_HMAC, HMAC_KEY_LEN, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + uint8_t digest[digest_size]; + size_t output_len = 0; + + psa_set_key_lifetime(&attr, lifetime); + psa_set_key_algorithm(&attr, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + psa_set_key_usage_flags(&attr, usage); + psa_set_key_bits(&attr, PSA_BYTES_TO_BITS(HMAC_KEY_LEN)); + psa_set_key_type(&attr, PSA_KEY_TYPE_HMAC); + + psa_status_t status = PSA_ERROR_DOES_NOT_EXIST; + + status = psa_import_key(&attr, HMAC_KEY, HMAC_KEY_LEN, &key_id); + if (status != PSA_SUCCESS) { + return status; + } + + return psa_mac_compute(key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256), + HMAC_MSG, HMAC_MSG_LEN, digest, digest_size, + &output_len); +} +#endif diff --git a/examples/psa_crypto/main.c b/examples/psa_crypto/main.c new file mode 100644 index 0000000000..9a1672ffec --- /dev/null +++ b/examples/psa_crypto/main.c @@ -0,0 +1,90 @@ +/* + * 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 examples + * @{ + * + * @brief Example application for PSA Crypto + * + * @author Lena Boeckmann + * + * @} + */ + +#include +#include "psa/crypto.h" +#include "ztimer.h" + +extern psa_status_t example_cipher_aes_128(void); +extern psa_status_t example_hmac_sha256(void); +extern psa_status_t example_ecdsa_p256(void); + +#ifdef MULTIPLE_SE +extern psa_status_t example_cipher_aes_128_sec_se(void); +extern psa_status_t example_hmac_sha256_sec_se(void); +extern psa_status_t example_ecdsa_p256_sec_se(void); +#endif + +int main(void) +{ + psa_status_t status; + + psa_crypto_init(); + + ztimer_acquire(ZTIMER_USEC); + ztimer_now_t start = ztimer_now(ZTIMER_USEC); + + status = example_hmac_sha256(); + printf("HMAC SHA256 took %d us\n", (int)(ztimer_now(ZTIMER_USEC) - start)); + if (status != PSA_SUCCESS) { + printf("HMAC SHA256 failed: %s\n", psa_status_to_humanly_readable(status)); + } + + start = ztimer_now(ZTIMER_USEC); + status = example_cipher_aes_128(); + printf("Cipher AES 128 took %d us\n", (int)(ztimer_now(ZTIMER_USEC) - start)); + if (status != PSA_SUCCESS) { + printf("Cipher AES 128 failed: %s\n", psa_status_to_humanly_readable(status)); + } + + start = ztimer_now(ZTIMER_USEC); + status = example_ecdsa_p256(); + printf("ECDSA took %d us\n", (int)(ztimer_now(ZTIMER_USEC) - start)); + if (status != PSA_SUCCESS) { + printf("ECDSA failed: %s\n", psa_status_to_humanly_readable(status)); + } + +#ifdef MULTIPLE_SE + puts("Running Examples with secondary SE:"); + status = example_hmac_sha256_sec_se(); + printf("HMAC SHA256 took %d us\n", (int)(ztimer_now(ZTIMER_USEC) - start)); + if (status != PSA_SUCCESS) { + printf("HMAC SHA256 failed: %s\n", psa_status_to_humanly_readable(status)); + } + + start = ztimer_now(ZTIMER_USEC); + status = example_cipher_aes_128_sec_se(); + printf("Cipher AES 128 took %d us\n", (int)(ztimer_now(ZTIMER_USEC) - start)); + if (status != PSA_SUCCESS) { + printf("Cipher AES 128 failed: %s\n", psa_status_to_humanly_readable(status)); + } + + start = ztimer_now(ZTIMER_USEC); + status = example_ecdsa_p256_sec_se(); + printf("ECDSA took %d us\n", (int)(ztimer_now(ZTIMER_USEC) - start)); + if (status != PSA_SUCCESS) { + printf("ECDSA failed: %s\n", psa_status_to_humanly_readable(status)); + } +#endif + + ztimer_release(ZTIMER_USEC); + + puts("All Done"); + return 0; +} diff --git a/examples/psa_crypto/tests/01-run.py b/examples/psa_crypto/tests/01-run.py new file mode 100755 index 0000000000..25257b8ca8 --- /dev/null +++ b/examples/psa_crypto/tests/01-run.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 + +import sys +from testrunner import run + + +def testfunc(child): + child.expect_exact('All Done') + print("[TEST PASSED]") + + +if __name__ == "__main__": + sys.exit(run(testfunc)) From a0ccbce5a854194f3350328eae48c94d71f4c8be Mon Sep 17 00:00:00 2001 From: Lena Boeckmann Date: Tue, 29 Aug 2023 19:28:45 +0200 Subject: [PATCH 8/8] dist/tools/codespell: Add ignored words --- dist/tools/codespell/ignored_words.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dist/tools/codespell/ignored_words.txt b/dist/tools/codespell/ignored_words.txt index d0acc35204..8f6863da28 100644 --- a/dist/tools/codespell/ignored_words.txt +++ b/dist/tools/codespell/ignored_words.txt @@ -162,3 +162,9 @@ noe # NWE (Negative Write Enable) ==> NEW nwe + +# rsource (used to include Kconfig files) ==> resource, source +rsource + +# SHS (abbreviation for Secure Hash Standard) => SSH, NHS +shs