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); }