| /* |
| * Copyright (c) 2019-2022, Arm Limited. All rights reserved. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| * |
| */ |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include "tfm_mbedcrypto_include.h" |
| |
| #include "tfm_crypto_api.h" |
| #include "tfm_crypto_defs.h" |
| #include "tfm_crypto_private.h" |
| |
| /*! |
| * \defgroup public_psa Public functions, PSA |
| * |
| */ |
| |
| /*!@{*/ |
| psa_status_t tfm_crypto_aead_encrypt(psa_invec in_vec[], |
| size_t in_len, |
| psa_outvec out_vec[], |
| size_t out_len) |
| { |
| #ifdef TFM_CRYPTO_AEAD_MODULE_DISABLED |
| return PSA_ERROR_NOT_SUPPORTED; |
| #else |
| psa_status_t status = PSA_SUCCESS; |
| |
| CRYPTO_IN_OUT_LEN_VALIDATE(in_len, 1, 3, out_len, 0, 1); |
| |
| if ((in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec))) { |
| return PSA_ERROR_PROGRAMMER_ERROR; |
| } |
| |
| const struct tfm_crypto_pack_iovec *iov = in_vec[0].base; |
| const struct tfm_crypto_aead_pack_input *aead_pack_input = &iov->aead_in; |
| psa_key_id_t key_id = iov->key_id; |
| psa_algorithm_t alg = iov->alg; |
| const uint8_t *nonce = aead_pack_input->nonce; |
| size_t nonce_length = aead_pack_input->nonce_length; |
| const uint8_t *plaintext = in_vec[1].base; |
| size_t plaintext_length = in_vec[1].len; |
| uint8_t *ciphertext = out_vec[0].base; |
| size_t ciphertext_size = out_vec[0].len; |
| const uint8_t *additional_data = in_vec[2].base; |
| size_t additional_data_length = in_vec[2].len; |
| mbedtls_svc_key_id_t encoded_key; |
| |
| /* Initialise ciphertext_length to zero. */ |
| out_vec[0].len = 0; |
| |
| status = tfm_crypto_encode_id_and_owner(key_id, &encoded_key); |
| if (status != PSA_SUCCESS) { |
| return status; |
| } |
| |
| return psa_aead_encrypt(encoded_key, alg, nonce, nonce_length, |
| additional_data, additional_data_length, |
| plaintext, plaintext_length, |
| ciphertext, ciphertext_size, &out_vec[0].len); |
| #endif /* TFM_CRYPTO_AEAD_MODULE_DISABLED */ |
| } |
| |
| psa_status_t tfm_crypto_aead_decrypt(psa_invec in_vec[], |
| size_t in_len, |
| psa_outvec out_vec[], |
| size_t out_len) |
| { |
| #ifdef TFM_CRYPTO_AEAD_MODULE_DISABLED |
| return PSA_ERROR_NOT_SUPPORTED; |
| #else |
| psa_status_t status = PSA_SUCCESS; |
| |
| CRYPTO_IN_OUT_LEN_VALIDATE(in_len, 1, 3, out_len, 0, 1); |
| |
| if ((in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec))) { |
| return PSA_ERROR_PROGRAMMER_ERROR; |
| } |
| |
| const struct tfm_crypto_pack_iovec *iov = in_vec[0].base; |
| const struct tfm_crypto_aead_pack_input *aead_pack_input = &iov->aead_in; |
| psa_key_id_t key_id = iov->key_id; |
| psa_algorithm_t alg = iov->alg; |
| const uint8_t *nonce = aead_pack_input->nonce; |
| size_t nonce_length = aead_pack_input->nonce_length; |
| const uint8_t *ciphertext = in_vec[1].base; |
| size_t ciphertext_length = in_vec[1].len; |
| uint8_t *plaintext = out_vec[0].base; |
| size_t plaintext_size = out_vec[0].len; |
| const uint8_t *additional_data = in_vec[2].base; |
| size_t additional_data_length = in_vec[2].len; |
| mbedtls_svc_key_id_t encoded_key; |
| |
| /* Initialise plaintext_length to zero. */ |
| out_vec[0].len = 0; |
| |
| status = tfm_crypto_encode_id_and_owner(key_id, &encoded_key); |
| if (status != PSA_SUCCESS) { |
| return status; |
| } |
| |
| return psa_aead_decrypt(encoded_key, alg, nonce, nonce_length, |
| additional_data, additional_data_length, |
| ciphertext, ciphertext_length, |
| plaintext, plaintext_size, &out_vec[0].len); |
| #endif /* TFM_CRYPTO_AEAD_MODULE_DISABLED */ |
| } |
| |
| psa_status_t tfm_crypto_aead_encrypt_setup(psa_invec in_vec[], |
| size_t in_len, |
| psa_outvec out_vec[], |
| size_t out_len) |
| { |
| #ifdef TFM_CRYPTO_AEAD_MODULE_DISABLED |
| return PSA_ERROR_NOT_SUPPORTED; |
| #else |
| psa_status_t status = PSA_SUCCESS; |
| psa_aead_operation_t *operation = NULL; |
| |
| CRYPTO_IN_OUT_LEN_VALIDATE(in_len, 1, 1, out_len, 1, 1); |
| |
| if ((in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec))) { |
| return PSA_ERROR_PROGRAMMER_ERROR; |
| } |
| 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_id_t key_id = iov->key_id; |
| psa_algorithm_t alg = iov->alg; |
| mbedtls_svc_key_id_t encoded_key; |
| |
| /* Init the handle in the operation with the one passed from the iov */ |
| *handle_out = iov->op_handle; |
| |
| /* Allocate the operation context in the secure world */ |
| status = tfm_crypto_operation_alloc(TFM_CRYPTO_AEAD_OPERATION, |
| &handle, |
| (void **)&operation); |
| if (status != PSA_SUCCESS) { |
| return status; |
| } |
| |
| *handle_out = handle; |
| |
| status = tfm_crypto_encode_id_and_owner(key_id, &encoded_key); |
| if (status != PSA_SUCCESS) { |
| goto exit; |
| } |
| |
| status = psa_aead_encrypt_setup(operation, encoded_key, alg); |
| if (status != PSA_SUCCESS) { |
| goto exit; |
| } |
| |
| return status; |
| |
| exit: |
| /* Release the operation context, ignore if the operation fails. */ |
| (void)tfm_crypto_operation_release(handle_out); |
| return status; |
| #endif /* TFM_CRYPTO_AEAD_MODULE_DISABLED */ |
| } |
| |
| psa_status_t tfm_crypto_aead_decrypt_setup(psa_invec in_vec[], |
| size_t in_len, |
| psa_outvec out_vec[], |
| size_t out_len) |
| { |
| #ifdef TFM_CRYPTO_AEAD_MODULE_DISABLED |
| return PSA_ERROR_NOT_SUPPORTED; |
| #else |
| psa_status_t status = PSA_SUCCESS; |
| psa_aead_operation_t *operation = NULL; |
| |
| CRYPTO_IN_OUT_LEN_VALIDATE(in_len, 1, 1, out_len, 1, 1); |
| |
| if ((in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec))) { |
| return PSA_ERROR_PROGRAMMER_ERROR; |
| } |
| 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_id_t key_id = iov->key_id; |
| psa_algorithm_t alg = iov->alg; |
| mbedtls_svc_key_id_t encoded_key; |
| |
| /* Init the handle in the operation with the one passed from the iov */ |
| *handle_out = iov->op_handle; |
| |
| /* Allocate the operation context in the secure world */ |
| status = tfm_crypto_operation_alloc(TFM_CRYPTO_AEAD_OPERATION, |
| &handle, |
| (void **)&operation); |
| if (status != PSA_SUCCESS) { |
| return status; |
| } |
| |
| *handle_out = handle; |
| |
| status = tfm_crypto_encode_id_and_owner(key_id, &encoded_key); |
| if (status != PSA_SUCCESS) { |
| goto exit; |
| } |
| |
| status = psa_aead_decrypt_setup(operation, encoded_key, alg); |
| if (status != PSA_SUCCESS) { |
| goto exit; |
| } |
| |
| return status; |
| |
| exit: |
| /* Release the operation context, ignore if the operation fails. */ |
| (void)tfm_crypto_operation_release(handle_out); |
| return status; |
| #endif /* TFM_CRYPTO_AEAD_MODULE_DISABLED */ |
| } |
| |
| psa_status_t tfm_crypto_aead_abort(psa_invec in_vec[], |
| size_t in_len, |
| psa_outvec out_vec[], |
| size_t out_len) |
| { |
| #ifdef TFM_CRYPTO_AEAD_MODULE_DISABLED |
| return PSA_ERROR_NOT_SUPPORTED; |
| #else |
| psa_status_t status = PSA_SUCCESS; |
| psa_aead_operation_t *operation = NULL; |
| |
| CRYPTO_IN_OUT_LEN_VALIDATE(in_len, 1, 1, out_len, 1, 1); |
| |
| if ((in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec)) || |
| (out_vec[0].len != sizeof(uint32_t))) { |
| return PSA_ERROR_PROGRAMMER_ERROR; |
| } |
| 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_AEAD_OPERATION, |
| handle, |
| (void **)&operation); |
| if (status != PSA_SUCCESS) { |
| /* Operation does not exist, so abort has no effect */ |
| return PSA_SUCCESS; |
| } |
| |
| status = psa_aead_abort(operation); |
| |
| if (status != PSA_SUCCESS) { |
| /* Release the operation context, ignore if the operation fails. */ |
| (void)tfm_crypto_operation_release(handle_out); |
| return status; |
| } |
| |
| return tfm_crypto_operation_release(handle_out); |
| #endif /* TFM_CRYPTO_AEAD_MODULE_DISABLED */ |
| } |
| |
| psa_status_t tfm_crypto_aead_finish(psa_invec in_vec[], |
| size_t in_len, |
| psa_outvec out_vec[], |
| size_t out_len) |
| { |
| #ifdef TFM_CRYPTO_AEAD_MODULE_DISABLED |
| return PSA_ERROR_NOT_SUPPORTED; |
| #else |
| psa_status_t status = PSA_SUCCESS; |
| psa_aead_operation_t *operation = NULL; |
| |
| CRYPTO_IN_OUT_LEN_VALIDATE(in_len, 1, 1, out_len, 2, 3); |
| |
| if ((in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec)) || |
| (out_vec[0].len != sizeof(uint32_t))) { |
| return PSA_ERROR_PROGRAMMER_ERROR; |
| } |
| 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; |
| uint8_t *ciphertext = out_vec[2].base; |
| size_t ciphertext_size = out_vec[2].len; |
| uint8_t *tag = out_vec[1].base; |
| size_t tag_size = out_vec[1].len; |
| |
| /* Init the handle in the operation with the one passed from the iov */ |
| *handle_out = iov->op_handle; |
| |
| /* Initialise tag and ciphertext lengths to zero */ |
| out_vec[1].len = 0; |
| out_vec[2].len = 0; |
| |
| /* Look up the corresponding operation context */ |
| status = tfm_crypto_operation_lookup(TFM_CRYPTO_AEAD_OPERATION, |
| handle, |
| (void **)&operation); |
| if (status != PSA_SUCCESS) { |
| return status; |
| } |
| |
| status = psa_aead_finish(operation, |
| ciphertext, ciphertext_size, &out_vec[2].len, |
| tag, tag_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; |
| #endif /* TFM_CRYPTO_AEAD_MODULE_DISABLED */ |
| } |
| |
| psa_status_t tfm_crypto_aead_generate_nonce(psa_invec in_vec[], |
| size_t in_len, |
| psa_outvec out_vec[], |
| size_t out_len) |
| { |
| #ifdef TFM_CRYPTO_AEAD_MODULE_DISABLED |
| return PSA_ERROR_NOT_SUPPORTED; |
| #else |
| psa_status_t status = PSA_SUCCESS; |
| psa_aead_operation_t *operation = NULL; |
| |
| CRYPTO_IN_OUT_LEN_VALIDATE(in_len, 1, 1, out_len, 2, 2); |
| |
| if ((in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec)) || |
| (out_vec[0].len != sizeof(uint32_t))) { |
| return PSA_ERROR_PROGRAMMER_ERROR; |
| } |
| 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; |
| uint8_t *nonce = out_vec[1].base; |
| size_t nonce_size = out_vec[1].len; |
| |
| /* Init the handle in the operation with the one passed from the iov */ |
| *handle_out = iov->op_handle; |
| |
| /* Initialise nonce length to zero */ |
| out_vec[1].len = 0; |
| |
| /* Look up the corresponding operation context */ |
| status = tfm_crypto_operation_lookup(TFM_CRYPTO_AEAD_OPERATION, |
| handle, |
| (void **)&operation); |
| if (status != PSA_SUCCESS) { |
| return status; |
| } |
| |
| status = psa_aead_generate_nonce(operation, |
| nonce, nonce_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; |
| #endif /* TFM_CRYPTO_AEAD_MODULE_DISABLED */ |
| } |
| |
| psa_status_t tfm_crypto_aead_set_nonce(psa_invec in_vec[], |
| size_t in_len, |
| psa_outvec out_vec[], |
| size_t out_len) |
| { |
| #ifdef TFM_CRYPTO_AEAD_MODULE_DISABLED |
| return PSA_ERROR_NOT_SUPPORTED; |
| #else |
| psa_status_t status = PSA_SUCCESS; |
| psa_aead_operation_t *operation = NULL; |
| |
| CRYPTO_IN_OUT_LEN_VALIDATE(in_len, 2, 2, out_len, 1, 1); |
| |
| if ((in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec)) || |
| (out_vec[0].len != sizeof(uint32_t))) { |
| return PSA_ERROR_PROGRAMMER_ERROR; |
| } |
| 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 *nonce = in_vec[1].base; |
| size_t nonce_size = 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_AEAD_OPERATION, |
| handle, |
| (void **)&operation); |
| if (status != PSA_SUCCESS) { |
| return status; |
| } |
| |
| status = psa_aead_set_nonce(operation, nonce, nonce_size); |
| |
| if (status != PSA_SUCCESS) { |
| /* Release the operation context, ignore if the operation fails. */ |
| (void)tfm_crypto_operation_release(handle_out); |
| } |
| |
| return status; |
| #endif /* TFM_CRYPTO_AEAD_MODULE_DISABLED */ |
| } |
| |
| psa_status_t tfm_crypto_aead_set_lengths(psa_invec in_vec[], |
| size_t in_len, |
| psa_outvec out_vec[], |
| size_t out_len) |
| { |
| #ifdef TFM_CRYPTO_AEAD_MODULE_DISABLED |
| return PSA_ERROR_NOT_SUPPORTED; |
| #else |
| psa_status_t status = PSA_SUCCESS; |
| psa_aead_operation_t *operation = NULL; |
| |
| CRYPTO_IN_OUT_LEN_VALIDATE(in_len, 1, 1, out_len, 1, 1); |
| |
| if ((in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec)) || |
| (out_vec[0].len != sizeof(uint32_t))) { |
| return PSA_ERROR_PROGRAMMER_ERROR; |
| } |
| 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; |
| size_t ad_length = iov->ad_length; |
| size_t plaintext_length = iov->plaintext_length; |
| |
| /* 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_AEAD_OPERATION, |
| handle, |
| (void **)&operation); |
| if (status != PSA_SUCCESS) { |
| return status; |
| } |
| status = psa_aead_set_lengths(operation, |
| ad_length, |
| plaintext_length); |
| |
| if (status != PSA_SUCCESS) { |
| /* Release the operation context, ignore if the operation fails. */ |
| (void)tfm_crypto_operation_release(handle_out); |
| } |
| |
| return status; |
| #endif /* TFM_CRYPTO_AEAD_MODULE_DISABLED */ |
| } |
| |
| psa_status_t tfm_crypto_aead_update(psa_invec in_vec[], |
| size_t in_len, |
| psa_outvec out_vec[], |
| size_t out_len) |
| { |
| #ifdef TFM_CRYPTO_AEAD_MODULE_DISABLED |
| return PSA_ERROR_NOT_SUPPORTED; |
| #else |
| psa_status_t status = PSA_SUCCESS; |
| psa_aead_operation_t *operation = NULL; |
| |
| CRYPTO_IN_OUT_LEN_VALIDATE(in_len, 2, 2, out_len, 2, 2); |
| |
| if ((in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec)) || |
| (out_vec[0].len != sizeof(uint32_t))) { |
| return PSA_ERROR_PROGRAMMER_ERROR; |
| } |
| 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; |
| uint8_t *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; |
| |
| /* Look up the corresponding operation context */ |
| status = tfm_crypto_operation_lookup(TFM_CRYPTO_AEAD_OPERATION, |
| handle, |
| (void **)&operation); |
| if (status != PSA_SUCCESS) { |
| return status; |
| } |
| |
| status = psa_aead_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; |
| #endif /* TFM_CRYPTO_AEAD_MODULE_DISABLED */ |
| } |
| |
| psa_status_t tfm_crypto_aead_update_ad(psa_invec in_vec[], |
| size_t in_len, |
| psa_outvec out_vec[], |
| size_t out_len) |
| { |
| #ifdef TFM_CRYPTO_AEAD_MODULE_DISABLED |
| return PSA_ERROR_NOT_SUPPORTED; |
| #else |
| psa_status_t status = PSA_SUCCESS; |
| psa_aead_operation_t *operation = NULL; |
| |
| CRYPTO_IN_OUT_LEN_VALIDATE(in_len, 2, 2, out_len, 1, 1); |
| |
| if ((in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec)) || |
| (out_vec[0].len != sizeof(uint32_t))) { |
| return PSA_ERROR_PROGRAMMER_ERROR; |
| } |
| 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; |
| |
| /* 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_AEAD_OPERATION, |
| handle, |
| (void **)&operation); |
| if (status != PSA_SUCCESS) { |
| return status; |
| } |
| |
| status = psa_aead_update_ad(operation, input, input_length); |
| |
| if (status != PSA_SUCCESS) { |
| /* Release the operation context, ignore if the operation fails. */ |
| (void)tfm_crypto_operation_release(handle_out); |
| } |
| |
| return status; |
| #endif /* TFM_CRYPTO_AEAD_MODULE_DISABLED */ |
| } |
| |
| psa_status_t tfm_crypto_aead_verify(psa_invec in_vec[], |
| size_t in_len, |
| psa_outvec out_vec[], |
| size_t out_len) |
| { |
| #ifdef TFM_CRYPTO_AEAD_MODULE_DISABLED |
| return PSA_ERROR_NOT_SUPPORTED; |
| #else |
| psa_status_t status = PSA_SUCCESS; |
| psa_aead_operation_t *operation = NULL; |
| |
| CRYPTO_IN_OUT_LEN_VALIDATE(in_len, 2, 2, out_len, 1, 2); |
| |
| if ((in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec)) || |
| (out_vec[0].len != sizeof(uint32_t))) { |
| return PSA_ERROR_PROGRAMMER_ERROR; |
| } |
| 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 *tag = in_vec[1].base; |
| size_t tag_length = in_vec[1].len; |
| uint8_t *plaintext = out_vec[1].base; |
| size_t plaintext_size = out_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_AEAD_OPERATION, |
| handle, |
| (void **)&operation); |
| if (status != PSA_SUCCESS) { |
| return status; |
| } |
| |
| status = psa_aead_verify(operation, |
| plaintext, plaintext_size, &out_vec[1].len, |
| tag, tag_length); |
| |
| if (status == PSA_SUCCESS) { |
| /* Release the operation context, ignore if the operation fails. */ |
| (void)tfm_crypto_operation_release(handle_out); |
| } |
| |
| return status; |
| #endif /* TFM_CRYPTO_AEAD_MODULE_DISABLED */ |
| } |
| /*!@}*/ |