Crypto: Add Crypto service
This change introduces the implementation of the Crypto
service based on the interface psa_crypto.h
This patch introduces changes for:
-- Secure Service, including manifest
-- Platform
-- Non-Secure interface
Change-Id: I3b68266ca80f4cd2bda2a1cd2b28b51c654b4c59
Signed-off-by: Antonio de Angelis <antonio.deangelis@arm.com>
diff --git a/secure_fw/services/crypto/crypto_cipher.c b/secure_fw/services/crypto/crypto_cipher.c
new file mode 100644
index 0000000..96980d2
--- /dev/null
+++ b/secure_fw/services/crypto/crypto_cipher.c
@@ -0,0 +1,471 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <limits.h>
+
+#include "tfm_crypto_defs.h"
+
+/* Pre include Mbed TLS headers */
+#define LIB_PREFIX_NAME __tfm_crypto__
+#include "mbedtls_global_symbols.h"
+
+/* Include the Mbed TLS configuration file, the way Mbed TLS does it
+ * in each of its header files.
+ */
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "platform/ext/common/tfm_mbedtls_config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include "psa_crypto.h"
+
+/* The file "psa_crypto_struct.h" contains definitions for
+ * implementation-specific structs that are declared in "psa_crypto.h".
+ */
+#include "psa_crypto_struct.h"
+
+#include "tfm_crypto_api.h"
+#include "crypto_utils.h"
+
+/**
+ * \brief For a TFM_CRYPTO_CIPHER_OPERATION, define the possible
+ * modes of configuration.
+ *
+ */
+enum tfm_crypto_cipher_mode_t {
+ TFM_CRYPTO_CIPHER_MODE_DECRYPT = 0,
+ TFM_CRYPTO_CIPHER_MODE_ENCRYPT = 1,
+};
+
+static enum tfm_crypto_err_t tfm_crypto_cipher_setup(
+ psa_cipher_operation_t *handle,
+ psa_key_slot_t key,
+ psa_algorithm_t alg,
+ enum tfm_crypto_cipher_mode_t c_mode)
+{
+ const mbedtls_cipher_info_t *info = NULL;
+ psa_algorithm_t padding_mode = PSA_ALG_BLOCK_CIPHER_PAD_NONE;
+ psa_key_type_t key_type;
+ size_t key_size;
+ enum tfm_crypto_err_t err;
+ uint8_t key_data[TFM_CRYPTO_MAX_KEY_LENGTH];
+ uint32_t ret;
+ mbedtls_cipher_type_t type = MBEDTLS_CIPHER_NONE;
+ mbedtls_cipher_padding_t mbedtls_padding_mode = MBEDTLS_PADDING_NONE;
+
+ struct psa_cipher_operation_s *operation = NULL;
+
+ /* Validate pointers */
+ err = tfm_crypto_memory_check(handle,
+ sizeof(psa_cipher_operation_t),
+ TFM_MEMORY_ACCESS_RW);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (!PSA_ALG_IS_CIPHER(alg)) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ /* FIXME: Check that key is compatible with alg */
+ err = tfm_crypto_get_key_information(key, &key_type, &key_size);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ err = tfm_crypto_export_key(key, &key_data[0], TFM_CRYPTO_MAX_KEY_LENGTH,
+ &key_size);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ /* Mbed TLS cipher setup */
+ if (PSA_BYTES_TO_BITS(key_size) == 128) {
+ if (alg == PSA_ALG_CBC_BASE) {
+ type = MBEDTLS_CIPHER_AES_128_CBC;
+ } else if (alg == PSA_ALG_CFB_BASE) {
+ if (c_mode == TFM_CRYPTO_CIPHER_MODE_ENCRYPT) {
+ type = MBEDTLS_CIPHER_AES_128_CFB128;
+ }
+ }
+ }
+
+ /* The requested alg/key/mode is not supported */
+ if (type == MBEDTLS_CIPHER_NONE) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ /* Allocate the operation context in the TFM space */
+ err = tfm_crypto_operation_alloc(TFM_CRYPTO_CIPHER_OPERATION, handle);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+
+
+ /* Look up the corresponding operation context */
+ err = tfm_crypto_operation_lookup(TFM_CRYPTO_CIPHER_OPERATION,
+ handle,
+ (void **)&operation);
+
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ /* Bind the algorithm to the cipher operation */
+ operation->alg = alg;
+
+ /* Mbed TLS cipher init */
+ mbedtls_cipher_init(&(operation->ctx.cipher));
+ info = mbedtls_cipher_info_from_type(type);
+ ret = mbedtls_cipher_setup(&(operation->ctx.cipher), info);
+ if (ret != 0) {
+ /* Release the operation context */
+ tfm_crypto_operation_release(handle);
+ return TFM_CRYPTO_ERR_PSA_ERROR_COMMUNICATION_FAILURE;
+ }
+
+ /* FIXME: Check based on the algorithm, if we need to have an IV */
+ operation->iv_required = 1;
+
+ /* Bind the key to the cipher operation */
+ operation->key = key;
+ operation->key_set = 1;
+
+ /* Mbed TLS cipher set key */
+ if (c_mode == TFM_CRYPTO_CIPHER_MODE_ENCRYPT) {
+
+ ret = mbedtls_cipher_setkey(&(operation->ctx.cipher),
+ &key_data[0],
+ PSA_BYTES_TO_BITS(key_size),
+ MBEDTLS_ENCRYPT);
+
+ } else if (c_mode == TFM_CRYPTO_CIPHER_MODE_DECRYPT) {
+
+ ret = mbedtls_cipher_setkey(&(operation->ctx.cipher),
+ &key_data[0],
+ PSA_BYTES_TO_BITS(key_size),
+ MBEDTLS_DECRYPT);
+ } else {
+ /* Release the operation context */
+ tfm_crypto_operation_release(handle);
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (ret != 0) {
+ /* Release the operation context */
+ tfm_crypto_operation_release(handle);
+ return TFM_CRYPTO_ERR_PSA_ERROR_COMMUNICATION_FAILURE;
+ }
+
+ /* Mbed TLS cipher set padding mode in case of CBC */
+ if ((alg & ~PSA_ALG_BLOCK_CIPHER_PADDING_MASK) == PSA_ALG_CBC_BASE) {
+
+ /* Check the value of padding field */
+ padding_mode = alg & PSA_ALG_BLOCK_CIPHER_PADDING_MASK;
+
+ switch (padding_mode) {
+ case PSA_ALG_BLOCK_CIPHER_PAD_PKCS7:
+ mbedtls_padding_mode = MBEDTLS_PADDING_PKCS7;
+ break;
+ case PSA_ALG_BLOCK_CIPHER_PAD_NONE:
+ mbedtls_padding_mode = MBEDTLS_PADDING_NONE;
+ break;
+ default:
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ ret = mbedtls_cipher_set_padding_mode(&(operation->ctx.cipher),
+ mbedtls_padding_mode);
+ if (ret != 0) {
+ /* Release the operation context */
+ tfm_crypto_operation_release(handle);
+ return TFM_CRYPTO_ERR_PSA_ERROR_COMMUNICATION_FAILURE;
+ }
+ }
+
+ return TFM_CRYPTO_ERR_PSA_SUCCESS;
+}
+
+/*!
+ * \defgroup public_psa Public functions, PSA
+ *
+ */
+
+/*!@{*/
+enum tfm_crypto_err_t tfm_crypto_encrypt_set_iv(
+ psa_cipher_operation_t *handle,
+ const unsigned char *iv,
+ size_t iv_length)
+{
+ int ret;
+ enum tfm_crypto_err_t err;
+ struct psa_cipher_operation_s *operation = NULL;
+
+ /* Validate pointers */
+ err = tfm_crypto_memory_check(handle,
+ sizeof(psa_cipher_operation_t),
+ TFM_MEMORY_ACCESS_RW);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+ err = tfm_crypto_memory_check((void *)iv, iv_length, TFM_MEMORY_ACCESS_RO);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* Look up the corresponding operation context */
+ err = tfm_crypto_operation_lookup(TFM_CRYPTO_CIPHER_OPERATION,
+ handle,
+ (void **)&operation);
+
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ if (operation->iv_required == 0) {
+ /* Release the operation context */
+ tfm_crypto_operation_release(handle);
+ return TFM_CRYPTO_ERR_PSA_ERROR_NOT_PERMITTED;
+ }
+
+ if (iv_length > PSA_CIPHER_IV_MAX_SIZE) {
+ /* Release the operation context */
+ tfm_crypto_operation_release(handle);
+ return TFM_CRYPTO_ERR_PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ /* Bind the IV to the cipher operation */
+ ret = mbedtls_cipher_set_iv(&(operation->ctx.cipher), iv, iv_length);
+ if (ret != 0) {
+ /* Release the operation context */
+ tfm_crypto_operation_release(handle);
+ return TFM_CRYPTO_ERR_PSA_ERROR_COMMUNICATION_FAILURE;
+ }
+ operation->iv_set = 1;
+ operation->iv_size = iv_length;
+
+ /* Reset the context after IV is set */
+ ret = mbedtls_cipher_reset(&(operation->ctx.cipher));
+ if (ret != 0) {
+ /* Release the operation context */
+ tfm_crypto_operation_release(handle);
+ return TFM_CRYPTO_ERR_PSA_ERROR_COMMUNICATION_FAILURE;
+ }
+
+ return TFM_CRYPTO_ERR_PSA_SUCCESS;
+}
+
+enum tfm_crypto_err_t tfm_crypto_encrypt_setup(
+ psa_cipher_operation_t *handle,
+ psa_key_slot_t key,
+ psa_algorithm_t alg)
+{
+ return tfm_crypto_cipher_setup(handle,
+ key,
+ alg,
+ TFM_CRYPTO_CIPHER_MODE_ENCRYPT);
+}
+
+enum tfm_crypto_err_t tfm_crypto_decrypt_setup(
+ psa_cipher_operation_t *handle,
+ psa_key_slot_t key,
+ psa_algorithm_t alg)
+{
+ return tfm_crypto_cipher_setup(handle,
+ key,
+ alg,
+ TFM_CRYPTO_CIPHER_MODE_DECRYPT);
+}
+
+enum tfm_crypto_err_t tfm_crypto_cipher_update(
+ psa_cipher_operation_t *handle,
+ const uint8_t *input,
+ size_t input_length,
+ unsigned char *output,
+ size_t output_size,
+ size_t *output_length)
+{
+ int ret;
+ enum tfm_crypto_err_t err;
+ size_t olen;
+ struct psa_cipher_operation_s *operation = NULL;
+
+ /* Validate pointers */
+ err = tfm_crypto_memory_check(handle,
+ sizeof(psa_cipher_operation_t),
+ TFM_MEMORY_ACCESS_RW);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+ err = tfm_crypto_memory_check((void *)input,
+ input_length,
+ TFM_MEMORY_ACCESS_RO);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+ err = tfm_crypto_memory_check(output,
+ output_size,
+ TFM_MEMORY_ACCESS_RW);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+ err = tfm_crypto_memory_check(output_length,
+ sizeof(size_t),
+ TFM_MEMORY_ACCESS_RW);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* Look up the corresponding operation context */
+ err = tfm_crypto_operation_lookup(TFM_CRYPTO_CIPHER_OPERATION,
+ handle,
+ (void **)&operation);
+
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ /* If the IV is required and it's not been set yet */
+ if ((operation->iv_required == 1) && (operation->iv_set == 0)) {
+
+ if (operation->ctx.cipher.operation != MBEDTLS_DECRYPT) {
+ /* Release the operation context */
+ tfm_crypto_operation_release(handle);
+ return TFM_CRYPTO_ERR_PSA_ERROR_BAD_STATE;
+ }
+
+ /* This call is used to set the IV on the object */
+ err = tfm_crypto_encrypt_set_iv(handle, input, input_length);
+
+ *output_length = 0;
+
+ return err;
+ }
+
+ /* If the key is not set, setup phase has not been completed */
+ if (operation->key_set == 0) {
+ /* Release the operation context */
+ tfm_crypto_operation_release(handle);
+ return TFM_CRYPTO_ERR_PSA_ERROR_BAD_STATE;
+ }
+
+ *output_length = 0;
+
+ ret = mbedtls_cipher_update(&(operation->ctx.cipher), input, input_length,
+ output, &olen);
+
+ if ((ret != 0) || (olen == 0)) {
+ /* Release the operation context */
+ tfm_crypto_operation_release(handle);
+ return TFM_CRYPTO_ERR_PSA_ERROR_COMMUNICATION_FAILURE;
+ }
+
+ /* Assign the output buffer length */
+ *output_length = olen;
+
+ return TFM_CRYPTO_ERR_PSA_SUCCESS;
+}
+
+enum tfm_crypto_err_t tfm_crypto_cipher_finish(
+ psa_cipher_operation_t *handle,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length)
+{
+ int ret;
+ enum tfm_crypto_err_t err;
+ size_t olen;
+ struct psa_cipher_operation_s *operation = NULL;
+
+ /* Validate pointers */
+ err = tfm_crypto_memory_check(handle,
+ sizeof(psa_cipher_operation_t),
+ TFM_MEMORY_ACCESS_RW);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+ err = tfm_crypto_memory_check(output,
+ output_size,
+ TFM_MEMORY_ACCESS_RW);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+ err = tfm_crypto_memory_check(output_length,
+ sizeof(size_t),
+ TFM_MEMORY_ACCESS_RW);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ *output_length = 0;
+
+ /* Look up the corresponding operation context */
+ err = tfm_crypto_operation_lookup(TFM_CRYPTO_CIPHER_OPERATION,
+ handle,
+ (void **)&operation);
+
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ ret = mbedtls_cipher_finish(&(operation->ctx.cipher), output, &olen);
+ if (ret != 0) {
+ /* Release the operation context */
+ tfm_crypto_operation_release(handle);
+ return TFM_CRYPTO_ERR_PSA_ERROR_COMMUNICATION_FAILURE;
+ }
+
+ *output_length = olen;
+
+ /* Clear the Mbed TLS context */
+ mbedtls_cipher_free(&(operation->ctx.cipher));
+
+ /* Release the operation context */
+ err = tfm_crypto_operation_release(handle);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ return TFM_CRYPTO_ERR_PSA_SUCCESS;
+}
+
+enum tfm_crypto_err_t tfm_crypto_cipher_abort(psa_cipher_operation_t *handle)
+{
+ enum tfm_crypto_err_t err;
+ struct psa_cipher_operation_s *operation = NULL;
+
+ /* Validate pointers */
+ err = tfm_crypto_memory_check(handle,
+ sizeof(psa_cipher_operation_t),
+ TFM_MEMORY_ACCESS_RW);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* Look up the corresponding operation context */
+ err = tfm_crypto_operation_lookup(TFM_CRYPTO_CIPHER_OPERATION,
+ handle,
+ (void **)&operation);
+
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ /* Clear the Mbed TLS context */
+ mbedtls_cipher_free(&(operation->ctx.cipher));
+
+ /* Release the operation context */
+ err = tfm_crypto_operation_release(handle);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ return TFM_CRYPTO_ERR_PSA_SUCCESS;
+}
+/*!@}*/