1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/psa_crypto/psa_crypto_location_dispatch.c
2024-04-17 12:42:05 +02:00

475 lines
20 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 sys_psa_crypto_loc_disp
* @{
*
* @file
* @brief Dispatch calls from the PSA Crypto API to an available backend.
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include <stdio.h>
#include "kernel_defines.h"
#include "psa/crypto.h"
#include "psa_crypto_algorithm_dispatch.h"
#include "psa_crypto_se_management.h"
#include "psa_crypto_se_driver.h"
#if IS_USED(MODULE_PSA_KEY_MANAGEMENT)
#include "psa_crypto_slot_management.h"
psa_status_t psa_location_dispatch_generate_key(const psa_key_attributes_t *attributes,
psa_key_slot_t *slot)
{
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
psa_status_t status;
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
uint8_t *pubkey_data = NULL;
size_t *pubkey_data_len = NULL;
psa_get_public_key_data_from_key_slot(slot, &pubkey_data, &pubkey_data_len);
if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
if (drv->key_management == NULL || drv->key_management->p_generate == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
status = drv->key_management->p_generate(drv_context, *slot_number, attributes, pubkey_data,
*pubkey_data_len, pubkey_data_len);
if (status != PSA_SUCCESS) {
/* In case anything goes wrong, free the key slot for reuse. */
psa_se_drv_data_t *driver = psa_get_se_driver_data(attributes->lifetime);
psa_status_t abort_status = drv->key_management->p_destroy(drv_context, driver->ctx.internal.persistent_data, *slot_number);
return abort_status == PSA_SUCCESS ? status : abort_status;
}
return PSA_SUCCESS;
}
#endif /* MODULE_PSA_SECURE_ELEMENT */
return psa_algorithm_dispatch_generate_key(attributes, slot);
}
psa_status_t psa_location_dispatch_import_key( const psa_key_attributes_t *attributes,
const uint8_t *data, size_t data_length,
psa_key_slot_t *slot, size_t *bits)
{
psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(attributes->lifetime);
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
if (drv->key_management == NULL || drv->key_management->p_import == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
*bits = 0;
status = drv->key_management->p_import(drv_context, *slot_number,
attributes, data,
data_length, bits);
if (status != PSA_SUCCESS) {
/* In case anything goes wrong, free the key slot for reuse. */
psa_se_drv_data_t *driver = psa_get_se_driver_data(attributes->lifetime);
psa_status_t abort_status = drv->key_management->p_destroy(drv_context, driver->ctx.internal.persistent_data, *slot_number);
return abort_status == PSA_SUCCESS ? status : abort_status;
}
return PSA_SUCCESS;
}
#endif /* MODULE_PSA_SECURE_ELEMENT */
switch (location) {
case PSA_KEY_LOCATION_LOCAL_STORAGE:
return psa_algorithm_dispatch_import_key(attributes, data, data_length, slot, bits);
default:
return PSA_ERROR_NOT_SUPPORTED;
}
}
#endif /* MODULE_PSA_KEY_MANAGEMENT */
#if IS_USED(MODULE_PSA_CIPHER)
psa_status_t psa_location_dispatch_cipher_encrypt_setup( psa_cipher_operation_t *operation,
const psa_key_attributes_t *attributes,
const psa_key_slot_t *slot,
psa_algorithm_t alg)
{
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(attributes->lifetime);
if (location != PSA_KEY_LOCATION_LOCAL_STORAGE) {
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
uint8_t *key_data = NULL;
size_t *key_bytes = NULL;
psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
if (drv->cipher == NULL || drv->cipher->p_setup == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
status = drv->cipher->p_setup(drv_context, &operation->backend_ctx.se_ctx, *slot_number,
attributes->policy.alg, PSA_CRYPTO_DRIVER_ENCRYPT);
if (status != PSA_SUCCESS) {
return status;
}
return PSA_SUCCESS;
}
}
#endif /* MODULE_PSA_SECURE_ELEMENT */
(void)operation;
(void)attributes;
(void)slot;
(void)alg;
return PSA_ERROR_NOT_SUPPORTED;
}
psa_status_t psa_location_dispatch_cipher_decrypt_setup(psa_cipher_operation_t *operation,
const psa_key_attributes_t *attributes,
const psa_key_slot_t *slot,
psa_algorithm_t alg)
{
(void)operation;
(void)attributes;
(void)slot;
(void)alg;
return PSA_ERROR_NOT_SUPPORTED;
}
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
/**
* @brief Single part function for cipher encryption and decryption on a secure element
*
* Some secure elements don't provide single part operations for cipher encryption.
* This is a wrapper function, to support those.
*
* @param drv
* @param drv_context
* @param attributes
* @param alg
* @param direction
* @param slot
* @param input
* @param input_length
* @param output
* @param output_size
* @param output_length
* @return @ref psa_status_t
*/
static psa_status_t psa_se_cipher_encrypt_decrypt( const psa_drv_se_t *drv,
psa_drv_se_context_t *drv_context,
const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
psa_encrypt_or_decrypt_t direction,
psa_key_slot_number_t slot,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
psa_status_t status;
psa_cipher_operation_t operation = psa_cipher_operation_init();
psa_se_cipher_context_t *se_ctx = &operation.backend_ctx.se_ctx;
size_t input_offset = 0;
size_t output_offset = 0;
*output_length = 0;
if (drv->cipher == NULL ||
drv->cipher->p_setup == NULL ||
drv->cipher->p_set_iv == NULL ||
drv->cipher->p_update == NULL ||
drv->cipher->p_finish == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
status = drv->cipher->p_setup(drv_context, se_ctx, slot, alg, direction);
if (status != PSA_SUCCESS) {
return status;
}
if (alg == PSA_ALG_CBC_NO_PADDING) {
operation.iv_required = 1;
operation.default_iv_length = PSA_CIPHER_IV_LENGTH(psa_get_key_type(attributes), alg);
if (direction == PSA_CRYPTO_DRIVER_ENCRYPT) {
/* In case of encryption, we need to generate and set an IV. The IV will be written
into the first 16 bytes of the output buffer. */
size_t iv_length = 0;
status = psa_cipher_generate_iv(&operation, output, operation.default_iv_length,
&iv_length);
status = drv->cipher->p_set_iv(se_ctx, output, iv_length);
if (status != PSA_SUCCESS) {
return status;
}
/* Increase output buffer offset to IV length to write ciphertext to buffer after IV */
output_offset += iv_length;
*output_length += iv_length;
}
else {
/* In case of decryption the IV to be used must be provided by the caller and is
contained in the first 16 Bytes of the input buffer. */
status = drv->cipher->p_set_iv(se_ctx, input, operation.default_iv_length);
/* Increase input buffer offset to IV length to start decryption
with actual cipher text */
input_offset += operation.default_iv_length;
}
}
status = drv->cipher->p_update(se_ctx, input + input_offset, input_length - input_offset,
output + output_offset, output_size - output_offset,
output_length);
if (status != PSA_SUCCESS) {
psa_cipher_abort(&operation);
return status;
}
status = drv->cipher->p_finish(se_ctx, output, output_size, output_length);
if (status != PSA_SUCCESS) {
return status;
}
return PSA_SUCCESS;
}
#endif /* CONFIG_PSA_SECURE_ELEMENT */
psa_status_t psa_location_dispatch_cipher_encrypt( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
if (alg == PSA_ALG_ECB_NO_PADDING) {
if (drv->cipher == NULL || drv->cipher->p_ecb == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
status = drv->cipher->p_ecb(drv_context, *slot_number, alg, PSA_CRYPTO_DRIVER_ENCRYPT,
input, input_length, output, output_size);
if (status != PSA_SUCCESS) {
return status;
}
}
/* The SE interface does not support single part functions for other algorithms than ECB,
so we need to build one ourselves */
status = psa_se_cipher_encrypt_decrypt(drv, drv_context, attributes, alg,
PSA_CRYPTO_DRIVER_ENCRYPT, *slot_number, input,
input_length, output, output_size, output_length);
return status;
}
#endif /* CONFIG_PSA_SECURE_ELEMENT */
return psa_algorithm_dispatch_cipher_encrypt(attributes, alg, slot, input, input_length, output,
output_size, output_length);
}
psa_status_t psa_location_dispatch_cipher_decrypt( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
if (alg == PSA_ALG_ECB_NO_PADDING) {
if (drv->cipher == NULL || drv->cipher->p_ecb == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
status = drv->cipher->p_ecb(drv_context, *slot_number, alg, PSA_CRYPTO_DRIVER_DECRYPT,
input, input_length, output, output_size);
if (status != PSA_SUCCESS) {
return status;
}
}
status = psa_se_cipher_encrypt_decrypt(drv, drv_context, attributes, alg,
PSA_CRYPTO_DRIVER_DECRYPT, *slot_number, input,
input_length, output, output_size, output_length);
return status;
}
#endif /* CONFIG_PSA_SECURE_ELEMENT */
return psa_algorithm_dispatch_cipher_decrypt(attributes, alg, slot, input, input_length,
output, output_size, output_length);
}
#endif /* MODULE_PSA_CIPHER */
#if IS_USED(MODULE_PSA_ASYMMETRIC)
psa_status_t psa_location_dispatch_sign_hash( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *hash,
size_t hash_length,
uint8_t *signature,
size_t signature_size,
size_t *signature_length)
{
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
uint8_t *key_data = NULL;
size_t *key_bytes = NULL;
psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
if (drv->asymmetric == NULL || drv->asymmetric->p_sign == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
return drv->asymmetric->p_sign(drv_context, *slot_number, alg, hash, hash_length, signature,
signature_size, signature_length);
}
(void)key_bytes;
#endif /* CONFIG_PSA_SECURE_ELEMENT */
return psa_algorithm_dispatch_sign_hash(attributes, alg, slot, hash, hash_length, signature,
signature_size, signature_length);
}
psa_status_t psa_location_dispatch_sign_message(const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *input,
size_t input_length,
uint8_t *signature,
size_t signature_size,
size_t *signature_length)
{
/* TODO: implement MODULE_PSA_SECURE_ELEMENT support */
return psa_algorithm_dispatch_sign_message(attributes, alg, slot, input, input_length, signature,
signature_size, signature_length);
}
psa_status_t psa_location_dispatch_verify_hash(const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *hash,
size_t hash_length,
const uint8_t *signature,
size_t signature_length)
{
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
uint8_t *key_data = NULL;
size_t *key_bytes = NULL;
psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
if (drv->asymmetric == NULL || drv->asymmetric->p_verify == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
return drv->asymmetric->p_verify(drv_context, *slot_number, alg, hash, hash_length,
signature, signature_length);
}
(void)key_bytes;
#endif /* CONFIG_PSA_SECURE_ELEMENT */
return psa_algorithm_dispatch_verify_hash(attributes, alg, slot, hash, hash_length, signature,
signature_length);
}
psa_status_t psa_location_dispatch_verify_message( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *input,
size_t input_length,
const uint8_t *signature,
size_t signature_length)
{
/* TODO: implement MODULE_PSA_SECURE_ELEMENT support */
return psa_algorithm_dispatch_verify_message(attributes, alg, slot, input, input_length, signature,
signature_length);
}
#endif /* MODULE_PSA_ASYMMETRIC */
#if IS_USED(MODULE_PSA_MAC)
psa_status_t psa_location_dispatch_mac_compute(const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *input,
size_t input_length,
uint8_t *mac,
size_t mac_size,
size_t *mac_length)
{
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
uint8_t *key_data = NULL;
size_t *key_bytes = NULL;
psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
if (drv->mac == NULL || drv->mac->p_mac == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
return drv->mac->p_mac(drv_context, input, input_length, *slot_number, alg, mac, mac_size,
mac_length);
}
(void)key_bytes;
#endif /* CONFIG_PSA_SECURE_ELEMENT */
return psa_algorithm_dispatch_mac_compute(attributes, alg, slot, input, input_length, mac,
mac_size, mac_length);
}
#endif /* MODULE_PSA_MAC */
psa_status_t psa_location_dispatch_generate_random(uint8_t *output,
size_t output_size)
{
return psa_builtin_generate_random(output, output_size);
}