mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
pkg/cryptoauthlib: Add PSA Wrappers
This commit is contained in:
parent
a6f3b59e7a
commit
40902cd947
@ -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)
|
||||
/** @} */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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`.
|
||||
*/
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -49,4 +49,4 @@ extern "C" {
|
||||
}
|
||||
#endif
|
||||
#endif /* ATCA_CONFIG_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
|
||||
}
|
||||
|
1
pkg/cryptoauthlib/psa_atca_driver/Makefile
Normal file
1
pkg/cryptoauthlib/psa_atca_driver/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
691
pkg/cryptoauthlib/psa_atca_driver/psa_atca_se_driver.c
Normal file
691
pkg/cryptoauthlib/psa_atca_driver/psa_atca_se_driver.c
Normal file
@ -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 <lena.boeckmann@haw-hamburg.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#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
|
||||
};
|
@ -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
|
||||
|
30
sys/auto_init/security/init.c
Normal file
30
sys/auto_init/security/init.c
Normal file
@ -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 <bennet.blischke@haw-hamburg.de>
|
||||
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg,de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#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
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user