mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
692 lines
22 KiB
C
692 lines
22 KiB
C
/*
|
|
* 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
|
|
};
|