blob: e49b14593d664f8258b95952a33eb75961ee1e84 [file] [log] [blame]
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stddef.h>
#include <stdint.h>
/* FixMe: Use PSA_CONNECTION_REFUSED when performing parameter
* integrity checks but this will have to be revised
* when the full set of error codes mandated by PSA FF
* is available.
*/
#include "tfm_mbedcrypto_include.h"
#include "tfm_crypto_api.h"
#include "tfm_crypto_defs.h"
/*!
* \defgroup public_psa Public functions, PSA
*
*/
/*!@{*/
psa_status_t tfm_crypto_cipher_set_iv(psa_invec in_vec[],
size_t in_len,
psa_outvec out_vec[],
size_t out_len)
{
psa_status_t status = PSA_SUCCESS;
psa_cipher_operation_t *operation = NULL;
if ((in_len != 2) || (out_len != 1)) {
return PSA_CONNECTION_REFUSED;
}
if ((in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec)) ||
(out_vec[0].len != sizeof(uint32_t))) {
return PSA_CONNECTION_REFUSED;
}
const struct tfm_crypto_pack_iovec *iov = in_vec[0].base;
uint32_t handle = iov->op_handle;
uint32_t *handle_out = out_vec[0].base;
const unsigned char *iv = in_vec[1].base;
size_t iv_length = in_vec[1].len;
/* Init the handle in the operation with the one passed from the iov */
*handle_out = iov->op_handle;
/* Look up the corresponding operation context */
status = tfm_crypto_operation_lookup(TFM_CRYPTO_CIPHER_OPERATION,
handle,
(void **)&operation);
if (status != PSA_SUCCESS) {
return status;
}
status = psa_cipher_set_iv(operation, iv, iv_length);
if (status != PSA_SUCCESS) {
/* Release the operation context, ignore if the operation fails. */
(void)tfm_crypto_operation_release(handle_out);
return status;
}
return status;
}
/**
* TODO: psa_cipher_generate_iv(...)
*
*/
psa_status_t tfm_crypto_cipher_encrypt_setup(psa_invec in_vec[],
size_t in_len,
psa_outvec out_vec[],
size_t out_len)
{
psa_status_t status = PSA_SUCCESS;
psa_cipher_operation_t *operation = NULL;
if ((in_len != 1) || (out_len != 1)) {
return PSA_CONNECTION_REFUSED;
}
if ((out_vec[0].len != sizeof(uint32_t)) ||
(in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec))) {
return PSA_CONNECTION_REFUSED;
}
const struct tfm_crypto_pack_iovec *iov = in_vec[0].base;
uint32_t handle = iov->op_handle;
uint32_t *handle_out = out_vec[0].base;
psa_key_handle_t key_handle = iov->key_handle;
psa_algorithm_t alg = iov->alg;
/* Allocate the operation context in the secure world */
status = tfm_crypto_operation_alloc(TFM_CRYPTO_CIPHER_OPERATION,
&handle,
(void **)&operation);
if (status != PSA_SUCCESS) {
return status;
}
*handle_out = handle;
status = psa_cipher_encrypt_setup(operation, key_handle, alg);
if (status != PSA_SUCCESS) {
/* Release the operation context, ignore if the operation fails. */
(void)tfm_crypto_operation_release(handle_out);
return status;
}
return status;
}
psa_status_t tfm_crypto_cipher_decrypt_setup(psa_invec in_vec[],
size_t in_len,
psa_outvec out_vec[],
size_t out_len)
{
psa_status_t status = PSA_SUCCESS;
psa_cipher_operation_t *operation = NULL;
if ((in_len != 1) || (out_len != 1)) {
return PSA_CONNECTION_REFUSED;
}
if ((out_vec[0].len != sizeof(uint32_t)) ||
(in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec))) {
return PSA_CONNECTION_REFUSED;
}
const struct tfm_crypto_pack_iovec *iov = in_vec[0].base;
uint32_t handle = iov->op_handle;
uint32_t *handle_out = out_vec[0].base;
psa_key_handle_t key_handle = iov->key_handle;
psa_algorithm_t alg = iov->alg;
/* Allocate the operation context in the secure world */
status = tfm_crypto_operation_alloc(TFM_CRYPTO_CIPHER_OPERATION,
&handle,
(void **)&operation);
if (status != PSA_SUCCESS) {
return status;
}
*handle_out = handle;
status = psa_cipher_decrypt_setup(operation, key_handle, alg);
if (status != PSA_SUCCESS) {
/* Release the operation context, ignore if the operation fails. */
(void)tfm_crypto_operation_release(handle_out);
return status;
}
return status;
}
psa_status_t tfm_crypto_cipher_update(psa_invec in_vec[],
size_t in_len,
psa_outvec out_vec[],
size_t out_len)
{
psa_status_t status = PSA_SUCCESS;
psa_cipher_operation_t *operation = NULL;
if ((in_len != 2) || (out_len != 2)) {
return PSA_CONNECTION_REFUSED;
}
if ((in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec)) ||
(out_vec[0].len != sizeof(uint32_t))) {
return PSA_CONNECTION_REFUSED;
}
const struct tfm_crypto_pack_iovec *iov = in_vec[0].base;
uint32_t handle = iov->op_handle;
uint32_t *handle_out = out_vec[0].base;
const uint8_t *input = in_vec[1].base;
size_t input_length = in_vec[1].len;
unsigned char *output = out_vec[1].base;
size_t output_size = out_vec[1].len;
/* Init the handle in the operation with the one passed from the iov */
*handle_out = iov->op_handle;
/* Initialise the output_length to zero */
out_vec[1].len = 0;
/* Look up the corresponding operation context */
status = tfm_crypto_operation_lookup(TFM_CRYPTO_CIPHER_OPERATION,
handle,
(void **)&operation);
if (status != PSA_SUCCESS) {
return status;
}
status = psa_cipher_update(operation, input, input_length,
output, output_size, &out_vec[1].len);
if (status != PSA_SUCCESS) {
/* Release the operation context, ignore if the operation fails. */
(void)tfm_crypto_operation_release(handle_out);
return status;
}
return status;
}
psa_status_t tfm_crypto_cipher_finish(psa_invec in_vec[],
size_t in_len,
psa_outvec out_vec[],
size_t out_len)
{
psa_status_t status = PSA_SUCCESS;
psa_cipher_operation_t *operation = NULL;
if ((in_len != 1) || (out_len != 2)) {
return PSA_CONNECTION_REFUSED;
}
if ((in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec)) ||
(out_vec[0].len != sizeof(uint32_t))) {
return PSA_CONNECTION_REFUSED;
}
const struct tfm_crypto_pack_iovec *iov = in_vec[0].base;
uint32_t handle = iov->op_handle;
uint32_t *handle_out = out_vec[0].base;
unsigned char *output = out_vec[1].base;
size_t output_size = out_vec[1].len;
/* Init the handle in the operation with the one passed from the iov */
*handle_out = iov->op_handle;
/* Initialise the output_length to zero */
out_vec[1].len = 0;
/* Look up the corresponding operation context */
status = tfm_crypto_operation_lookup(TFM_CRYPTO_CIPHER_OPERATION,
handle,
(void **)&operation);
if (status != PSA_SUCCESS) {
return status;
}
status = psa_cipher_finish(operation, output, output_size, &out_vec[1].len);
if (status != PSA_SUCCESS) {
/* Release the operation context, ignore if the operation fails. */
(void)tfm_crypto_operation_release(handle_out);
return status;
}
status = tfm_crypto_operation_release(handle_out);
return status;
}
psa_status_t tfm_crypto_cipher_abort(psa_invec in_vec[],
size_t in_len,
psa_outvec out_vec[],
size_t out_len)
{
psa_status_t status = PSA_SUCCESS;
psa_cipher_operation_t *operation = NULL;
if ((in_len != 1) || (out_len != 1)) {
return PSA_CONNECTION_REFUSED;
}
if ((in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec)) ||
(out_vec[0].len != sizeof(uint32_t))) {
return PSA_CONNECTION_REFUSED;
}
const struct tfm_crypto_pack_iovec *iov = in_vec[0].base;
uint32_t handle = iov->op_handle;
uint32_t *handle_out = out_vec[0].base;
/* Init the handle in the operation with the one passed from the iov */
*handle_out = iov->op_handle;
/* Look up the corresponding operation context */
status = tfm_crypto_operation_lookup(TFM_CRYPTO_CIPHER_OPERATION,
handle,
(void **)&operation);
if (status != PSA_SUCCESS) {
return status;
}
status = psa_cipher_abort(operation);
if (status != PSA_SUCCESS) {
/* Release the operation context, ignore if the operation fails. */
(void)tfm_crypto_operation_release(handle_out);
return status;
}
status = tfm_crypto_operation_release(handle_out);
return status;
}
/*!@}*/