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;
+}
+/*!@}*/