Crypto: Implement additional PSA Crypto APIs

This patch implements additional missing APIs available
in the PSA Crypto API headers.

Change-Id: I453f6829ed2c87a47546514becda599ecd1273a4
Signed-off-by: Antonio de Angelis <antonio.deangelis@arm.com>
diff --git a/secure_fw/services/crypto/crypto_generator.c b/secure_fw/services/crypto/crypto_generator.c
new file mode 100644
index 0000000..1cf138d
--- /dev/null
+++ b/secure_fw/services/crypto/crypto_generator.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 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_get_generator_capacity(psa_invec in_vec[],
+                                               size_t in_len,
+                                               psa_outvec out_vec[],
+                                               size_t out_len)
+{
+    psa_status_t status;
+    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(size_t))) {
+        return PSA_CONNECTION_REFUSED;
+    }
+    const struct tfm_crypto_pack_iovec *iov = in_vec[0].base;
+
+    uint32_t handle = iov->op_handle;
+    size_t *capacity = out_vec[0].base;
+    psa_crypto_generator_t *generator = NULL;
+
+    /* Look up the corresponding operation context */
+    status = tfm_crypto_operation_lookup(TFM_CRYPTO_GENERATOR_OPERATION,
+                                         handle,
+                                         (void **)&generator);
+    if (status != PSA_SUCCESS) {
+        *capacity = 0;
+        return status;
+    }
+
+    return psa_get_generator_capacity(generator, capacity);
+}
+
+psa_status_t tfm_crypto_generator_read(psa_invec in_vec[],
+                                       size_t in_len,
+                                       psa_outvec out_vec[],
+                                       size_t out_len)
+{
+    psa_status_t status;
+    if ((in_len != 1) || (out_len != 1)) {
+        return PSA_CONNECTION_REFUSED;
+    }
+
+    if ((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;
+    uint8_t *output = out_vec[0].base;
+    size_t output_length = out_vec[0].len;
+    psa_crypto_generator_t *generator = NULL;
+
+    /* Look up the corresponding operation context */
+    status = tfm_crypto_operation_lookup(TFM_CRYPTO_GENERATOR_OPERATION,
+                                         handle,
+                                         (void **)&generator);
+    if (status != PSA_SUCCESS) {
+        return status;
+    }
+
+    return psa_generator_read(generator, output, output_length);
+}
+
+psa_status_t tfm_crypto_generator_import_key(psa_invec in_vec[],
+                                             size_t in_len,
+                                             psa_outvec out_vec[],
+                                             size_t out_len)
+{
+    psa_status_t status;
+    if ((in_len != 2) || (out_len != 0)) {
+        return PSA_CONNECTION_REFUSED;
+    }
+
+    if ((in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec)) ||
+        (in_vec[1].len != sizeof(size_t))) {
+        return PSA_CONNECTION_REFUSED;
+    }
+    const struct tfm_crypto_pack_iovec *iov = in_vec[0].base;
+
+    uint32_t handle = iov->op_handle;
+    psa_key_handle_t key_handle = iov->key_handle;
+    psa_key_type_t type = iov->type;
+    size_t bits = *(size_t *)(in_vec[1].base);
+    psa_crypto_generator_t *generator = NULL;
+
+    /* Look up the corresponding operation context */
+    status = tfm_crypto_operation_lookup(TFM_CRYPTO_GENERATOR_OPERATION,
+                                         handle,
+                                         (void **)&generator);
+    if (status != PSA_SUCCESS) {
+        return status;
+    }
+
+    return psa_generator_import_key(key_handle, type, bits, generator);
+}
+
+psa_status_t tfm_crypto_generator_abort(psa_invec in_vec[],
+                                        size_t in_len,
+                                        psa_outvec out_vec[],
+                                        size_t out_len)
+{
+    psa_status_t status;
+    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;
+    psa_crypto_generator_t *generator = NULL;
+
+    /* 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_GENERATOR_OPERATION,
+                                         handle,
+                                         (void **)&generator);
+    if (status != PSA_SUCCESS) {
+        /* Operation does not exist, so abort has no effect */
+        return PSA_SUCCESS;
+    }
+
+    *handle_out = handle;
+
+    status = psa_generator_abort(generator);
+    if (status != PSA_SUCCESS) {
+        return status;
+    }
+
+    status = tfm_crypto_operation_release(handle_out);
+
+    return status;
+}
+
+psa_status_t tfm_crypto_key_derivation(psa_invec in_vec[],
+                                       size_t in_len,
+                                       psa_outvec out_vec[],
+                                       size_t out_len)
+{
+    psa_status_t status;
+    if (!((in_len == 1) || (in_len == 2) || (in_len == 3)) || (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;
+    psa_key_handle_t key_handle = iov->key_handle;
+    psa_algorithm_t alg = iov->alg;
+    const uint8_t *salt = NULL;
+    size_t salt_length = 0;
+    const uint8_t *label = NULL;
+    size_t label_length = 0;
+    size_t capacity = iov->capacity;
+    psa_crypto_generator_t *generator = NULL;
+
+    if (in_len > 1) {
+        salt = in_vec[2].base;
+        salt_length = in_vec[2].len;
+    }
+
+    if (in_len > 2) {
+        label = in_vec[3].base;
+        label_length = in_vec[3].len;
+    }
+
+    /* Allocate the generator context in the secure world */
+    status = tfm_crypto_operation_alloc(TFM_CRYPTO_GENERATOR_OPERATION,
+                                        &handle,
+                                        (void **)&generator);
+    if (status != PSA_SUCCESS) {
+        return status;
+    }
+
+    *handle_out = handle;
+
+    return psa_key_derivation(generator, key_handle, alg, salt, salt_length,
+                              label, label_length, capacity);
+}
+
+psa_status_t tfm_crypto_key_agreement(psa_invec in_vec[],
+                                      size_t in_len,
+                                      psa_outvec out_vec[],
+                                      size_t out_len)
+{
+    psa_status_t status;
+    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;
+    psa_key_handle_t private_key = iov->key_handle;
+    psa_algorithm_t alg = iov->alg;
+    const uint8_t *peer_key = in_vec[1].base;
+    size_t peer_key_length = in_vec[1].len;
+    psa_crypto_generator_t *generator = NULL;
+
+    /* Allocate the generator context in the secure world */
+    status = tfm_crypto_operation_alloc(TFM_CRYPTO_GENERATOR_OPERATION,
+                                        &handle,
+                                        (void **)&generator);
+    if (status != PSA_SUCCESS) {
+        return status;
+    }
+
+    *handle_out = handle;
+
+    return psa_key_agreement(generator, private_key,
+                             peer_key, peer_key_length, alg);
+}
+
+psa_status_t tfm_crypto_generate_random(psa_invec in_vec[],
+                                        size_t in_len,
+                                        psa_outvec out_vec[],
+                                        size_t out_len)
+{
+    if ((in_len != 1) || (out_len != 1)) {
+        return PSA_CONNECTION_REFUSED;
+    }
+
+    if (in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec)) {
+        return PSA_CONNECTION_REFUSED;
+    }
+    uint8_t *output = out_vec[0].base;
+    size_t output_size = out_vec[0].len;
+
+    return psa_generate_random(output, output_size);
+}
+
+psa_status_t tfm_crypto_generate_key(psa_invec in_vec[],
+                                     size_t in_len,
+                                     psa_outvec out_vec[],
+                                     size_t out_len)
+{
+    if (!((in_len == 2) || (in_len == 3)) || (out_len != 0)) {
+        return PSA_CONNECTION_REFUSED;
+    }
+
+    if ((in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec)) ||
+        (in_vec[1].len != sizeof(size_t))) {
+        return PSA_CONNECTION_REFUSED;
+    }
+    const struct tfm_crypto_pack_iovec *iov = in_vec[0].base;
+    psa_key_handle_t key_handle = iov->key_handle;
+    psa_key_type_t type = iov->type;
+    size_t bits = *((size_t *)(in_vec[1].base));
+    const void *extra = NULL;
+    size_t extra_size = 0;
+
+    if (in_len == 3) {
+        extra = in_vec[2].base;
+        extra_size = in_vec[2].len;
+    }
+
+    return psa_generate_key(key_handle, type, bits, extra, extra_size);
+}
+/*!@}*/