blob: c3125e0291b2b9afee1fc45e7dccd8e42c99378b [file] [log] [blame]
/*
* Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PACKEDC_CRYPTO_CALLER_AEAD_H
#define PACKEDC_CRYPTO_CALLER_AEAD_H
#include <string.h>
#include <stdlib.h>
#include <psa/crypto.h>
#include "rpc_caller_session.h"
#include <service/common/client/service_client.h>
#include <protocols/rpc/common/packed-c/status.h>
#include <protocols/service/crypto/packed-c/opcodes.h>
#include <protocols/service/crypto/packed-c/aead.h>
#include <common/tlv/tlv.h>
#ifdef __cplusplus
extern "C" {
#endif
static inline psa_status_t common_aead_setup(struct service_client *context,
uint32_t *op_handle,
psa_key_id_t key,
psa_algorithm_t alg,
uint32_t opcode)
{
psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
struct ts_crypto_aead_setup_in req_msg;
size_t req_len = sizeof(struct ts_crypto_aead_setup_in);
req_msg.key_id = key;
req_msg.alg = alg;
rpc_call_handle call_handle;
uint8_t *req_buf;
call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len,
sizeof(struct ts_crypto_aead_setup_out));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
service_status_t service_status;
memcpy(req_buf, &req_msg, req_len);
context->rpc_status =
rpc_caller_session_invoke(call_handle, opcode,
&resp_buf, &resp_len, &service_status);
if (context->rpc_status == RPC_SUCCESS) {
psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
if (resp_len >= sizeof(struct ts_crypto_aead_setup_out)) {
struct ts_crypto_aead_setup_out resp_msg;
memcpy(&resp_msg, resp_buf, sizeof(struct ts_crypto_aead_setup_out));
*op_handle = resp_msg.op_handle;
}
else {
/* Failed to decode response message */
psa_status = PSA_ERROR_GENERIC_ERROR;
}
}
}
rpc_caller_session_end(call_handle);
}
return psa_status;
}
static inline psa_status_t crypto_caller_aead_encrypt_setup(struct service_client *context,
uint32_t *op_handle,
psa_key_id_t key,
psa_algorithm_t alg)
{
return common_aead_setup(context,
op_handle, key, alg, TS_CRYPTO_OPCODE_AEAD_ENCRYPT_SETUP);
}
static inline psa_status_t crypto_caller_aead_decrypt_setup(struct service_client *context,
uint32_t *op_handle,
psa_key_id_t key,
psa_algorithm_t alg)
{
return common_aead_setup(context,
op_handle, key, alg, TS_CRYPTO_OPCODE_AEAD_DECRYPT_SETUP);
}
static inline psa_status_t crypto_caller_aead_generate_nonce(struct service_client *context,
uint32_t op_handle,
uint8_t *nonce,
size_t nonce_size,
size_t *nonce_length)
{
psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
struct ts_crypto_aead_generate_nonce_in req_msg;
const size_t req_fixed_len = sizeof(struct ts_crypto_aead_generate_nonce_in);
size_t req_len = req_fixed_len;
*nonce_length = 0;
req_msg.op_handle = op_handle;
rpc_call_handle call_handle;
uint8_t *req_buf;
call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
service_status_t service_status;
memcpy(req_buf, &req_msg, req_fixed_len);
context->rpc_status =
rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_AEAD_GENERATE_NONCE,
&resp_buf, &resp_len, &service_status);
if (context->rpc_status == RPC_SUCCESS) {
psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
struct tlv_const_iterator resp_iter;
struct tlv_record decoded_record;
tlv_const_iterator_begin(&resp_iter, resp_buf, resp_len);
if (tlv_find_decode(&resp_iter,
TS_CRYPTO_AEAD_GENERATE_NONCE_OUT_TAG_NONCE, &decoded_record)) {
if (decoded_record.length <= nonce_size) {
memcpy(nonce, decoded_record.value, decoded_record.length);
*nonce_length = decoded_record.length;
}
else {
/* Provided buffer is too small */
psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
}
}
else {
/* Mandatory response parameter missing */
psa_status = PSA_ERROR_GENERIC_ERROR;
}
}
}
rpc_caller_session_end(call_handle);
}
return psa_status;
}
static inline psa_status_t crypto_caller_aead_set_nonce(struct service_client *context,
uint32_t op_handle,
const uint8_t *nonce,
size_t nonce_length)
{
psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
struct ts_crypto_aead_set_nonce_in req_msg;
const size_t req_fixed_len = sizeof(struct ts_crypto_aead_set_nonce_in);
size_t req_len = req_fixed_len;
req_msg.op_handle = op_handle;
/* Mandatory input data parameter */
struct tlv_record data_record;
data_record.tag = TS_CRYPTO_AEAD_SET_NONCE_IN_TAG_NONCE;
data_record.length = nonce_length;
data_record.value = nonce;
req_len += tlv_required_space(data_record.length);
rpc_call_handle call_handle;
uint8_t *req_buf;
call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
tlv_iterator_begin(&req_iter, &req_buf[req_fixed_len], req_len - req_fixed_len);
tlv_encode(&req_iter, &data_record);
context->rpc_status =
rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_AEAD_SET_NONCE,
&resp_buf, &resp_len, &service_status);
if (context->rpc_status == RPC_SUCCESS)
psa_status = service_status;
rpc_caller_session_end(call_handle);
}
return psa_status;
}
static inline psa_status_t crypto_caller_aead_set_lengths(struct service_client *context,
uint32_t op_handle,
size_t ad_length,
size_t plaintext_length)
{
psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
struct ts_crypto_aead_set_lengths_in req_msg;
const size_t req_fixed_len = sizeof(struct ts_crypto_aead_set_lengths_in);
size_t req_len = req_fixed_len;
req_msg.op_handle = op_handle;
req_msg.ad_length = ad_length;
req_msg.plaintext_length = plaintext_length;
rpc_call_handle call_handle;
uint8_t *req_buf;
call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
service_status_t service_status;
memcpy(req_buf, &req_msg, req_fixed_len);
context->rpc_status =
rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_AEAD_SET_LENGTHS,
&resp_buf, &resp_len, &service_status);
if (context->rpc_status == RPC_SUCCESS)
psa_status = service_status;
rpc_caller_session_end(call_handle);
}
return psa_status;
}
static inline psa_status_t crypto_caller_aead_update_ad(struct service_client *context,
uint32_t op_handle,
const uint8_t *input,
size_t input_length)
{
psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
struct ts_crypto_aead_update_ad_in req_msg;
const size_t req_fixed_len = sizeof(struct ts_crypto_aead_update_ad_in);
size_t req_len = req_fixed_len;
req_msg.op_handle = op_handle;
/* Mandatory input data parameter */
struct tlv_record data_record;
data_record.tag = TS_CRYPTO_AEAD_UPDATE_AD_IN_TAG_DATA;
data_record.length = input_length;
data_record.value = input;
req_len += tlv_required_space(data_record.length);
rpc_call_handle call_handle;
uint8_t *req_buf;
call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
tlv_iterator_begin(&req_iter, &req_buf[req_fixed_len], req_len - req_fixed_len);
tlv_encode(&req_iter, &data_record);
context->rpc_status =
rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_AEAD_UPDATE_AD,
&resp_buf, &resp_len, &service_status);
if (context->rpc_status == RPC_SUCCESS)
psa_status = service_status;
rpc_caller_session_end(call_handle);
}
return psa_status;
}
static inline psa_status_t crypto_caller_aead_update(struct service_client *context,
uint32_t op_handle,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
struct ts_crypto_aead_update_in req_msg;
const size_t req_fixed_len = sizeof(struct ts_crypto_aead_update_in);
size_t req_len = req_fixed_len;
*output_length = 0;
req_msg.op_handle = op_handle;
/* Mandatory input data parameter */
struct tlv_record data_record;
data_record.tag = TS_CRYPTO_AEAD_UPDATE_IN_TAG_DATA;
data_record.length = input_length;
data_record.value = input;
req_len += tlv_required_space(data_record.length);
rpc_call_handle call_handle;
uint8_t *req_buf;
call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
tlv_iterator_begin(&req_iter, &req_buf[req_fixed_len], req_len - req_fixed_len);
tlv_encode(&req_iter, &data_record);
context->rpc_status =
rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_AEAD_UPDATE,
&resp_buf, &resp_len, &service_status);
if (context->rpc_status == RPC_SUCCESS) {
psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
struct tlv_const_iterator resp_iter;
struct tlv_record decoded_record;
tlv_const_iterator_begin(&resp_iter, resp_buf, resp_len);
if (tlv_find_decode(&resp_iter,
TS_CRYPTO_AEAD_UPDATE_OUT_TAG_DATA, &decoded_record)) {
if (decoded_record.length <= output_size) {
memcpy(output, decoded_record.value, decoded_record.length);
*output_length = decoded_record.length;
}
else {
/* Provided buffer is too small */
psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
}
}
else {
/* Mandatory response parameter missing */
psa_status = PSA_ERROR_GENERIC_ERROR;
}
}
}
rpc_caller_session_end(call_handle);
}
return psa_status;
}
static inline psa_status_t crypto_caller_aead_finish(struct service_client *context,
uint32_t op_handle,
uint8_t *aeadtext,
size_t aeadtext_size,
size_t *aeadtext_length,
uint8_t *tag,
size_t tag_size,
size_t *tag_length)
{
psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
struct ts_crypto_aead_finish_in req_msg;
const size_t req_fixed_len = sizeof(struct ts_crypto_aead_finish_in);
size_t req_len = req_fixed_len;
*aeadtext_length = 0;
*tag_length = 0;
req_msg.op_handle = op_handle;
rpc_call_handle call_handle;
uint8_t *req_buf;
call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
service_status_t service_status;
memcpy(req_buf, &req_msg, req_fixed_len);
context->rpc_status =
rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_AEAD_FINISH,
&resp_buf, &resp_len, &service_status);
if (context->rpc_status == RPC_SUCCESS) {
psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
struct tlv_const_iterator resp_iter;
struct tlv_record decoded_record;
tlv_const_iterator_begin(&resp_iter, resp_buf, resp_len);
if (tlv_find_decode(&resp_iter,
TS_CRYPTO_AEAD_FINISH_OUT_TAG_CIPHERTEXT, &decoded_record)) {
if (decoded_record.length <= aeadtext_size) {
if (decoded_record.length && aeadtext)
memcpy(aeadtext, decoded_record.value,
decoded_record.length);
*aeadtext_length = decoded_record.length;
}
else {
/* Provided buffer is too small */
psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
}
}
else {
/* Mandatory response parameter missing */
psa_status = PSA_ERROR_GENERIC_ERROR;
}
if ((psa_status == PSA_SUCCESS) && tlv_find_decode(&resp_iter,
TS_CRYPTO_AEAD_FINISH_OUT_TAG_TAG, &decoded_record)) {
if (decoded_record.length <= tag_size) {
memcpy(tag, decoded_record.value, decoded_record.length);
*tag_length = decoded_record.length;
}
else {
/* Provided buffer is too small */
psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
}
}
else {
/* Mandatory response parameter missing */
psa_status = PSA_ERROR_GENERIC_ERROR;
}
}
}
rpc_caller_session_end(call_handle);
}
return psa_status;
}
static inline psa_status_t crypto_caller_aead_verify(struct service_client *context,
uint32_t op_handle,
uint8_t *plaintext,
size_t plaintext_size,
size_t *plaintext_length,
const uint8_t *tag,
size_t tag_length)
{
psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
struct ts_crypto_aead_verify_in req_msg;
const size_t req_fixed_len = sizeof(struct ts_crypto_aead_verify_in);
size_t req_len = req_fixed_len;
*plaintext_length = 0;
req_msg.op_handle = op_handle;
/* Mandatory input data parameter */
struct tlv_record data_record;
data_record.tag = TS_CRYPTO_AEAD_VERIFY_IN_TAG_TAG;
data_record.length = tag_length;
data_record.value = tag;
req_len += tlv_required_space(data_record.length);
rpc_call_handle call_handle;
uint8_t *req_buf;
call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
tlv_iterator_begin(&req_iter, &req_buf[req_fixed_len], req_len - req_fixed_len);
tlv_encode(&req_iter, &data_record);
context->rpc_status =
rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_AEAD_VERIFY,
&resp_buf, &resp_len, &service_status);
if (context->rpc_status == RPC_SUCCESS) {
psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
struct tlv_const_iterator resp_iter;
struct tlv_record decoded_record;
tlv_const_iterator_begin(&resp_iter, resp_buf, resp_len);
if (tlv_find_decode(&resp_iter,
TS_CRYPTO_AEAD_VERIFY_OUT_TAG_PLAINTEXT, &decoded_record)) {
if (decoded_record.length <= plaintext_size) {
if (decoded_record.length && plaintext)
memcpy(plaintext, decoded_record.value,
decoded_record.length);
*plaintext_length = decoded_record.length;
}
else {
/* Provided buffer is too small */
psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
}
}
else {
/* Mandatory response parameter missing */
psa_status = PSA_ERROR_GENERIC_ERROR;
}
}
}
rpc_caller_session_end(call_handle);
}
return psa_status;
}
static inline psa_status_t crypto_caller_aead_abort(struct service_client *context,
uint32_t op_handle)
{
psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
struct ts_crypto_aead_abort_in req_msg;
const size_t req_fixed_len = sizeof(struct ts_crypto_aead_abort_in);
size_t req_len = req_fixed_len;
req_msg.op_handle = op_handle;
rpc_call_handle call_handle;
uint8_t *req_buf;
call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
service_status_t service_status;
memcpy(req_buf, &req_msg, req_fixed_len);
context->rpc_status =
rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_AEAD_ABORT,
&resp_buf, &resp_len, &service_status);
if (context->rpc_status == RPC_SUCCESS)
psa_status = service_status;
rpc_caller_session_end(call_handle);
}
return psa_status;
}
/**
* The maximum data length that may be carried in an update operation will be
* constrained by the maximum call payload capacity imposed by the end-to-end
* RPC call path. These functions return the maximum update size when serialization
* overheads are considered. This allows large paylaods to be processed in
* maximum size chunks.
*/
static inline size_t crypto_caller_aead_max_update_ad_size(const struct service_client *context)
{
/* Returns the maximum number of bytes of additional data that may be
* carried as a parameter of the aead_update_ad operation
* using the packed-c encoding.
*/
size_t payload_space = context->service_info.max_payload;
size_t overhead = sizeof(struct ts_crypto_aead_update_ad_in) + TLV_HDR_LEN;
return (payload_space > overhead) ? payload_space - overhead : 0;
}
static inline size_t crypto_caller_aead_max_update_size(const struct service_client *context)
{
/* Returns the maximum number of bytes that may be
* carried as a parameter of the aead_update operation
* using the packed-c encoding.
*/
size_t payload_space = context->service_info.max_payload;
size_t overhead = sizeof(struct ts_crypto_aead_update_in) + TLV_HDR_LEN;
/* Allow for output to be a whole number of blocks */
overhead += PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE;
return (payload_space > overhead) ? payload_space - overhead : 0;
}
#ifdef __cplusplus
}
#endif
#endif /* PACKEDC_CRYPTO_CALLER_AEAD_H */