Add hash operation support to Crypto service provider
Adds support for multi-step hash operations. Only includes
protocol support for packed-c serialization at the moment.
Protobuf serialization still needs to be added. Includes
crypto context management that can be used for any multi-
step operations such as MAC and symmetric encrypt/decrypt.
Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: Ib51a9737f1987e1e7531da7edb38d9dc4095cc7e
diff --git a/components/service/crypto/provider/mbedcrypto/component.cmake b/components/service/crypto/provider/mbedcrypto/component.cmake
index 0df1138..6413cb9 100644
--- a/components/service/crypto/provider/mbedcrypto/component.cmake
+++ b/components/service/crypto/provider/mbedcrypto/component.cmake
@@ -10,6 +10,7 @@
target_sources(${TGT} PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/crypto_provider.c"
+ "${CMAKE_CURRENT_LIST_DIR}/crypto_context_pool.c"
)
target_include_directories(${TGT}
diff --git a/components/service/crypto/provider/mbedcrypto/crypto_context_pool.c b/components/service/crypto/provider/mbedcrypto/crypto_context_pool.c
new file mode 100644
index 0000000..753cb9f
--- /dev/null
+++ b/components/service/crypto/provider/mbedcrypto/crypto_context_pool.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+#include "crypto_context_pool.h"
+
+static void add_to_free_list(struct crypto_context_pool *pool,
+ struct crypto_context *context);
+
+static uint32_t alloc_op_handle(struct crypto_context_pool *pool);
+static bool op_handle_in_use(struct crypto_context_pool *pool, uint32_t candidate);
+
+
+void crypto_context_pool_init(struct crypto_context_pool *pool)
+{
+ pool->free = NULL;
+ pool->active_head = NULL;
+ pool->active_tail = NULL;
+ pool->most_recent_op_handle = 0;
+
+ for (size_t i = 0; i < CRYPTO_CONTEXT_POOL_SIZE; i++) {
+
+ add_to_free_list(pool, &pool->contexts[i]);
+ }
+}
+
+void crypto_context_pool_deinit(struct crypto_context_pool *pool)
+{
+ (void)pool;
+}
+
+struct crypto_context *crypto_context_pool_alloc(struct crypto_context_pool *pool,
+ enum crypto_context_op_id usage,
+ uint32_t client_id,
+ uint32_t *op_handle)
+{
+ struct crypto_context *context = NULL;
+
+ /* Re-cycle least-recently used context if there are no free contexts */
+ if (!pool->free && pool->active_tail) crypto_context_pool_free(pool, pool->active_tail);
+
+ /* Active context are held in a linked list in most recently allocated order */
+ if (pool->free) {
+
+ context = pool->free;
+ pool->free = context->next;
+
+ context->next = pool->active_head;
+ context->prev = NULL;
+ pool->active_head = context;
+
+ if (!pool->active_tail) pool->active_tail = context;
+ if (context->next) context->next->prev = context;
+
+ context->usage = usage;
+ context->client_id = client_id;
+
+ context->op_handle = alloc_op_handle(pool);
+ *op_handle = context->op_handle;
+ }
+
+ return context;
+}
+
+void crypto_context_pool_free(struct crypto_context_pool *pool,
+ struct crypto_context *context)
+{
+ /* Remove from active list */
+ if (context->prev) {
+ context->prev->next = context->next;
+ }
+ else {
+ pool->active_head = context->next;
+ }
+
+ if (context->next) {
+ context->next->prev = context->prev;
+ }
+ else {
+ pool->active_tail = context->prev;
+ }
+
+ /* Add to free list */
+ add_to_free_list(pool, context);
+}
+
+struct crypto_context *crypto_context_pool_find(struct crypto_context_pool *pool,
+ enum crypto_context_op_id usage,
+ uint32_t client_id,
+ uint32_t op_handle)
+{
+ /* Finds an active context that looks as though it legitimately belongs to the
+ * requesting client. Defends against bad behaviour from the client such
+ * as misusing a context for a different operation from the one that was
+ * setup.
+ */
+ struct crypto_context *found = NULL;
+ struct crypto_context *context = pool->active_head;
+
+ while (context) {
+
+ if ((context->op_handle == op_handle) &&
+ (context->usage == usage) &&
+ (context->client_id == client_id)) {
+
+ found = context;
+ break;
+ }
+
+ context = context->next;
+ }
+
+ return found;
+}
+
+static void add_to_free_list(struct crypto_context_pool *pool,
+ struct crypto_context *context)
+{
+ context->usage = CRYPTO_CONTEXT_OP_ID_NONE;
+ context->op_handle = 0;
+ context->next = pool->free;
+ context->prev = NULL;
+ pool->free = context;
+}
+
+static uint32_t alloc_op_handle(struct crypto_context_pool *pool)
+{
+ /* op handles need to be unique and to minimize the probability
+ * of a client using a stale handle that collides with a legitmately
+ * active one, use a rolling 32-bit integer.
+ */
+ uint32_t candidate = pool->most_recent_op_handle + 1;
+
+ while (op_handle_in_use(pool, candidate)) ++candidate;
+
+ pool->most_recent_op_handle = candidate;
+
+ return candidate;
+}
+
+static bool op_handle_in_use(struct crypto_context_pool *pool, uint32_t candidate)
+{
+ bool in_use = false;
+ struct crypto_context *context = pool->active_head;
+
+ while (context && !in_use) {
+
+ in_use = (candidate == context->op_handle);
+ context = context->next;
+ }
+
+ return in_use;
+}
diff --git a/components/service/crypto/provider/mbedcrypto/crypto_context_pool.h b/components/service/crypto/provider/mbedcrypto/crypto_context_pool.h
new file mode 100644
index 0000000..8d7e564
--- /dev/null
+++ b/components/service/crypto/provider/mbedcrypto/crypto_context_pool.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CRYPTO_CONTEXT_POOL_H
+#define CRYPTO_CONTEXT_POOL_H
+
+#include <stdint.h>
+#include <psa/crypto.h>
+
+/**
+ * Some crypto transactions require state to be held between separate
+ * service operations. A typical multi-call transaction such as a
+ * hash calculation comprises a setup, one or more updates and a finish
+ * operation. This pool is used for allocating state context for multi-call
+ * transactions. For a well behaved client, a fresh context is allocated
+ * on a setup and freed on the finish. To cope with badly behaved clients
+ * that may never finish a transaction, if no free contexts are available
+ * for a new transaction, the least recently used active context is
+ * recycled.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Identifier for the operation type that a context is used for.
+ */
+enum crypto_context_op_id
+{
+ CRYPTO_CONTEXT_OP_ID_NONE,
+ CRYPTO_CONTEXT_OP_ID_HASH,
+ CRYPTO_CONTEXT_OP_ID_MAC,
+ CRYPTO_CONTEXT_OP_ID_CIPHER
+};
+
+/**
+ * A crypto context, used to hold state for a multi-step transaction.
+ */
+struct crypto_context
+{
+ enum crypto_context_op_id usage;
+ uint32_t client_id;
+ uint32_t op_handle;
+ struct crypto_context *next;
+ struct crypto_context *prev;
+
+ union context_variant
+ {
+ struct psa_hash_operation_s hash;
+ struct psa_mac_operation_s mac;
+ struct psa_cipher_operation_s cipher;
+ } op;
+};
+
+/**
+ * The default pool size. This may be overridden to meet the needs
+ * of a particular deployment.
+ */
+#ifndef CRYPTO_CONTEXT_POOL_SIZE
+#define CRYPTO_CONTEXT_POOL_SIZE (10)
+#endif
+
+/**
+ * The crypto context pool structure.
+ */
+struct crypto_context_pool
+{
+ struct crypto_context contexts[CRYPTO_CONTEXT_POOL_SIZE];
+ struct crypto_context *free;
+ struct crypto_context *active_head;
+ struct crypto_context *active_tail;
+ uint32_t most_recent_op_handle;
+};
+
+/*
+ * Initializes a crypto_context_pool, called once during setup.
+ */
+void crypto_context_pool_init(struct crypto_context_pool *pool);
+
+/*
+ * De-initializes a crypto_context_pool, called once during tear-down.
+ */
+void crypto_context_pool_deinit(struct crypto_context_pool *pool);
+
+/*
+ * Allocate a fresh context. On success, a pointer to a crypto_context object
+ * is returned and an op handle is provided for reacqiring the context during
+ * sunsequent operations.
+ */
+struct crypto_context *crypto_context_pool_alloc(struct crypto_context_pool *pool,
+ enum crypto_context_op_id usage,
+ uint32_t client_id,
+ uint32_t *op_handle);
+
+/*
+ * Frees a context after use.
+ */
+void crypto_context_pool_free(struct crypto_context_pool *pool,
+ struct crypto_context *context);
+
+/*
+ * Find an allocated context. Returns NULL is no qualifying context is held.
+ */
+struct crypto_context *crypto_context_pool_find(struct crypto_context_pool *pool,
+ enum crypto_context_op_id usage,
+ uint32_t client_id,
+ uint32_t op_handle);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* CRYPTO_CONTEXT_POOL_H */
diff --git a/components/service/crypto/provider/mbedcrypto/crypto_provider.c b/components/service/crypto/provider/mbedcrypto/crypto_provider.c
index 1b2fffd..292c180 100644
--- a/components/service/crypto/provider/mbedcrypto/crypto_provider.c
+++ b/components/service/crypto/provider/mbedcrypto/crypto_provider.c
@@ -24,559 +24,697 @@
static rpc_status_t asymmetric_decrypt_handler(void *context, struct call_req* req);
static rpc_status_t asymmetric_encrypt_handler(void *context, struct call_req* req);
static rpc_status_t generate_random_handler(void *context, struct call_req* req);
+static rpc_status_t hash_setup_handler(void *context, struct call_req* req);
+static rpc_status_t hash_update_handler(void *context, struct call_req* req);
+static rpc_status_t hash_finish_handler(void *context, struct call_req* req);
/* Handler mapping table for service */
static const struct service_handler handler_table[] = {
- {TS_CRYPTO_OPCODE_NOP, nop_handler},
- {TS_CRYPTO_OPCODE_GENERATE_KEY, generate_key_handler},
- {TS_CRYPTO_OPCODE_DESTROY_KEY, destroy_key_handler},
- {TS_CRYPTO_OPCODE_EXPORT_KEY, export_key_handler},
- {TS_CRYPTO_OPCODE_EXPORT_PUBLIC_KEY, export_public_key_handler},
- {TS_CRYPTO_OPCODE_IMPORT_KEY, import_key_handler},
- {TS_CRYPTO_OPCODE_SIGN_HASH, sign_hash_handler},
- {TS_CRYPTO_OPCODE_VERIFY_HASH, verify_hash_handler},
- {TS_CRYPTO_OPCODE_ASYMMETRIC_DECRYPT, asymmetric_decrypt_handler},
- {TS_CRYPTO_OPCODE_ASYMMETRIC_ENCRYPT, asymmetric_encrypt_handler},
- {TS_CRYPTO_OPCODE_GENERATE_RANDOM, generate_random_handler}
+ {TS_CRYPTO_OPCODE_NOP, nop_handler},
+ {TS_CRYPTO_OPCODE_GENERATE_KEY, generate_key_handler},
+ {TS_CRYPTO_OPCODE_DESTROY_KEY, destroy_key_handler},
+ {TS_CRYPTO_OPCODE_EXPORT_KEY, export_key_handler},
+ {TS_CRYPTO_OPCODE_EXPORT_PUBLIC_KEY, export_public_key_handler},
+ {TS_CRYPTO_OPCODE_IMPORT_KEY, import_key_handler},
+ {TS_CRYPTO_OPCODE_SIGN_HASH, sign_hash_handler},
+ {TS_CRYPTO_OPCODE_VERIFY_HASH, verify_hash_handler},
+ {TS_CRYPTO_OPCODE_ASYMMETRIC_DECRYPT, asymmetric_decrypt_handler},
+ {TS_CRYPTO_OPCODE_ASYMMETRIC_ENCRYPT, asymmetric_encrypt_handler},
+ {TS_CRYPTO_OPCODE_GENERATE_RANDOM, generate_random_handler},
+ {TS_CRYPTO_OPCODE_HASH_SETUP, hash_setup_handler},
+ {TS_CRYPTO_OPCODE_HASH_UPDATE, hash_update_handler},
+ {TS_CRYPTO_OPCODE_HASH_FINISH, hash_finish_handler}
};
struct rpc_interface *mbed_crypto_provider_init(struct mbed_crypto_provider *context,
- struct storage_backend *storage_backend,
- int trng_instance)
+ struct storage_backend *storage_backend,
+ int trng_instance)
{
- struct rpc_interface *rpc_interface = NULL;
+ struct rpc_interface *rpc_interface = NULL;
- trng_adapter_init(trng_instance);
+ crypto_context_pool_init(&context->context_pool);
+ trng_adapter_init(trng_instance);
- /*
- * A storage provider is required for persistent key storage. As this
- * is a mandatory feature of the crypto service, insist on a storage
- * provider being available.
- */
- if (context && storage_backend) {
+ /*
+ * A storage provider is required for persistent key storage. As this
+ * is a mandatory feature of the crypto service, insist on a storage
+ * provider being available.
+ */
+ if (context && storage_backend) {
- for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
- context->serializers[encoding] = NULL;
+ for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
+ context->serializers[encoding] = NULL;
- service_provider_init(&context->base_provider, context,
- handler_table, sizeof(handler_table)/sizeof(struct service_handler));
+ service_provider_init(&context->base_provider, context,
+ handler_table, sizeof(handler_table)/sizeof(struct service_handler));
- if ((psa_its_frontend_init(storage_backend) == PSA_SUCCESS) &&
- (psa_crypto_init() == PSA_SUCCESS)) {
+ if ((psa_its_frontend_init(storage_backend) == PSA_SUCCESS) &&
+ (psa_crypto_init() == PSA_SUCCESS)) {
- rpc_interface = service_provider_get_rpc_interface(&context->base_provider);
- }
- }
+ rpc_interface = service_provider_get_rpc_interface(&context->base_provider);
+ }
+ }
- return rpc_interface;
+ return rpc_interface;
}
void mbed_crypto_provider_deinit(struct mbed_crypto_provider *context)
{
- (void)context;
- trng_adapter_deinit();
+ trng_adapter_deinit();
+ crypto_context_pool_deinit(&context->context_pool);
}
void mbed_crypto_provider_register_serializer(struct mbed_crypto_provider *context,
- unsigned int encoding, const struct crypto_provider_serializer *serializer)
+ unsigned int encoding, const struct crypto_provider_serializer *serializer)
{
- if (encoding < TS_RPC_ENCODING_LIMIT)
- context->serializers[encoding] = serializer;
+ if (encoding < TS_RPC_ENCODING_LIMIT)
+ context->serializers[encoding] = serializer;
}
static const struct crypto_provider_serializer* get_crypto_serializer(void *context,
- const struct call_req *req)
+ const struct call_req *req)
{
- struct mbed_crypto_provider *this_instance = (struct mbed_crypto_provider*)context;
- const struct crypto_provider_serializer* serializer = NULL;
- unsigned int encoding = call_req_get_encoding(req);
+ struct mbed_crypto_provider *this_instance = (struct mbed_crypto_provider*)context;
+ const struct crypto_provider_serializer* serializer = NULL;
+ unsigned int encoding = call_req_get_encoding(req);
- if (encoding < TS_RPC_ENCODING_LIMIT) serializer = this_instance->serializers[encoding];
+ if (encoding < TS_RPC_ENCODING_LIMIT) serializer = this_instance->serializers[encoding];
- return serializer;
+ return serializer;
}
static rpc_status_t nop_handler(void *context, struct call_req* req)
{
- /* Responds to a request by returning success */
- rpc_status_t rpc_status = TS_RPC_CALL_ACCEPTED;
- psa_status_t psa_status = PSA_SUCCESS;
+ /* Responds to a request by returning success */
+ rpc_status_t rpc_status = TS_RPC_CALL_ACCEPTED;
+ psa_status_t psa_status = PSA_SUCCESS;
- (void)context;
- call_req_set_opstatus(req, psa_status);
+ (void)context;
+ call_req_set_opstatus(req, psa_status);
- return rpc_status;
+ return rpc_status;
}
static rpc_status_t generate_key_handler(void *context, struct call_req* req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
- psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
- if (serializer)
- rpc_status = serializer->deserialize_generate_key_req(req_buf, &attributes);
+ if (serializer)
+ rpc_status = serializer->deserialize_generate_key_req(req_buf, &attributes);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
- psa_status_t psa_status;
- psa_key_id_t id;
+ psa_status_t psa_status;
+ psa_key_id_t id;
- psa_status = psa_generate_key(&attributes, &id);
+ psa_status = psa_generate_key(&attributes, &id);
- if (psa_status == PSA_SUCCESS) {
+ if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_generate_key_resp(resp_buf, id);
- }
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ rpc_status = serializer->serialize_generate_key_resp(resp_buf, id);
+ }
- call_req_set_opstatus(req, psa_status);
- }
+ call_req_set_opstatus(req, psa_status);
+ }
- psa_reset_key_attributes(&attributes);
+ psa_reset_key_attributes(&attributes);
- return rpc_status;
+ return rpc_status;
}
static rpc_status_t destroy_key_handler(void *context, struct call_req* req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
- psa_key_id_t id;
+ psa_key_id_t id;
- if (serializer)
- rpc_status = serializer->deserialize_destroy_key_req(req_buf, &id);
+ if (serializer)
+ rpc_status = serializer->deserialize_destroy_key_req(req_buf, &id);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
- psa_status_t psa_status;
+ psa_status_t psa_status;
- psa_status = psa_destroy_key(id);
- call_req_set_opstatus(req, psa_status);
- }
+ psa_status = psa_destroy_key(id);
+ call_req_set_opstatus(req, psa_status);
+ }
- return rpc_status;
+ return rpc_status;
}
static rpc_status_t export_key_handler(void *context, struct call_req* req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
- psa_key_id_t id;
+ psa_key_id_t id;
- if (serializer)
- rpc_status = serializer->deserialize_export_key_req(req_buf, &id);
+ if (serializer)
+ rpc_status = serializer->deserialize_export_key_req(req_buf, &id);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
- psa_status_t psa_status;
- psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ psa_status_t psa_status;
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
- psa_status = psa_get_key_attributes(id, &attributes);
+ psa_status = psa_get_key_attributes(id, &attributes);
- if (psa_status == PSA_SUCCESS) {
+ if (psa_status == PSA_SUCCESS) {
- size_t max_export_size = PSA_EXPORT_KEY_OUTPUT_SIZE(
- psa_get_key_type(&attributes),
- psa_get_key_bits(&attributes));
+ size_t max_export_size = PSA_EXPORT_KEY_OUTPUT_SIZE(
+ psa_get_key_type(&attributes),
+ psa_get_key_bits(&attributes));
- uint8_t *key_buffer = malloc(max_export_size);
+ uint8_t *key_buffer = malloc(max_export_size);
- if (key_buffer) {
+ if (key_buffer) {
- size_t export_size;
- psa_status = psa_export_key(id, key_buffer, max_export_size, &export_size);
+ size_t export_size;
+ psa_status = psa_export_key(id, key_buffer, max_export_size, &export_size);
- if (psa_status == PSA_SUCCESS) {
+ if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_export_key_resp(resp_buf, key_buffer, export_size);
- }
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ rpc_status = serializer->serialize_export_key_resp(resp_buf, key_buffer, export_size);
+ }
- free(key_buffer);
- }
- else {
- /* Failed to allocate key buffer */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
- }
- }
+ free(key_buffer);
+ }
+ else {
+ /* Failed to allocate key buffer */
+ rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ }
+ }
- call_req_set_opstatus(req, psa_status);
- psa_reset_key_attributes(&attributes);
- }
+ call_req_set_opstatus(req, psa_status);
+ psa_reset_key_attributes(&attributes);
+ }
- return rpc_status;
+ return rpc_status;
}
static rpc_status_t export_public_key_handler(void *context, struct call_req* req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
- psa_key_id_t id;
+ psa_key_id_t id;
- if (serializer)
- rpc_status = serializer->deserialize_export_public_key_req(req_buf, &id);
+ if (serializer)
+ rpc_status = serializer->deserialize_export_public_key_req(req_buf, &id);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
- psa_status_t psa_status;
- psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ psa_status_t psa_status;
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
- psa_status = psa_get_key_attributes(id, &attributes);
+ psa_status = psa_get_key_attributes(id, &attributes);
- if (psa_status == PSA_SUCCESS) {
+ if (psa_status == PSA_SUCCESS) {
- size_t max_export_size = PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(
- PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(psa_get_key_type(&attributes)),
- psa_get_key_bits(&attributes));
+ size_t max_export_size = PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(
+ PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(psa_get_key_type(&attributes)),
+ psa_get_key_bits(&attributes));
- uint8_t *key_buffer = malloc(max_export_size);
+ uint8_t *key_buffer = malloc(max_export_size);
- if (key_buffer) {
+ if (key_buffer) {
- size_t export_size;
- psa_status = psa_export_public_key(id, key_buffer, max_export_size, &export_size);
+ size_t export_size;
+ psa_status = psa_export_public_key(id, key_buffer, max_export_size, &export_size);
- if (psa_status == PSA_SUCCESS) {
+ if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_export_public_key_resp(resp_buf, key_buffer, export_size);
- }
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ rpc_status = serializer->serialize_export_public_key_resp(resp_buf, key_buffer, export_size);
+ }
- free(key_buffer);
- }
- else {
- /* Failed to allocate key buffer */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
- }
- }
+ free(key_buffer);
+ }
+ else {
+ /* Failed to allocate key buffer */
+ rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ }
+ }
- call_req_set_opstatus(req, psa_status);
- psa_reset_key_attributes(&attributes);
- }
+ call_req_set_opstatus(req, psa_status);
+ psa_reset_key_attributes(&attributes);
+ }
- return rpc_status;
+ return rpc_status;
}
static rpc_status_t import_key_handler(void *context, struct call_req* req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
- if (serializer) {
+ if (serializer) {
- size_t key_data_len = serializer->max_deserialised_parameter_size(req_buf);
- uint8_t *key_buffer = malloc(key_data_len);
+ size_t key_data_len = serializer->max_deserialised_parameter_size(req_buf);
+ uint8_t *key_buffer = malloc(key_data_len);
- if (key_buffer) {
+ if (key_buffer) {
- psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
- rpc_status = serializer->deserialize_import_key_req(req_buf, &attributes, key_buffer, &key_data_len);
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ rpc_status = serializer->deserialize_import_key_req(req_buf, &attributes, key_buffer, &key_data_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
- psa_status_t psa_status;
- psa_key_id_t id;
+ psa_status_t psa_status;
+ psa_key_id_t id;
- psa_status = psa_import_key(&attributes, key_buffer, key_data_len, &id);
+ psa_status = psa_import_key(&attributes, key_buffer, key_data_len, &id);
- if (psa_status == PSA_SUCCESS) {
+ if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_import_key_resp(resp_buf, id);
- }
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ rpc_status = serializer->serialize_import_key_resp(resp_buf, id);
+ }
- call_req_set_opstatus(req, psa_status);
- }
+ call_req_set_opstatus(req, psa_status);
+ }
- psa_reset_key_attributes(&attributes);
- free(key_buffer);
- }
- else {
+ psa_reset_key_attributes(&attributes);
+ free(key_buffer);
+ }
+ else {
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
- }
- }
+ rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ }
+ }
- return rpc_status;
+ return rpc_status;
}
static rpc_status_t sign_hash_handler(void *context, struct call_req* req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
- psa_key_id_t id;
- psa_algorithm_t alg;
- size_t hash_len = PSA_HASH_MAX_SIZE;
- uint8_t hash_buffer[PSA_HASH_MAX_SIZE];
+ psa_key_id_t id;
+ psa_algorithm_t alg;
+ size_t hash_len = PSA_HASH_MAX_SIZE;
+ uint8_t hash_buffer[PSA_HASH_MAX_SIZE];
- if (serializer)
- rpc_status = serializer->deserialize_sign_hash_req(req_buf, &id, &alg, hash_buffer, &hash_len);
+ if (serializer)
+ rpc_status = serializer->deserialize_sign_hash_req(req_buf, &id, &alg, hash_buffer, &hash_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
- psa_status_t psa_status;
- size_t sig_len;
- uint8_t sig_buffer[PSA_SIGNATURE_MAX_SIZE];
+ psa_status_t psa_status;
+ size_t sig_len;
+ uint8_t sig_buffer[PSA_SIGNATURE_MAX_SIZE];
- psa_status = psa_sign_hash(id, alg,
- hash_buffer, hash_len,
- sig_buffer, sizeof(sig_buffer), &sig_len);
+ psa_status = psa_sign_hash(id, alg,
+ hash_buffer, hash_len,
+ sig_buffer, sizeof(sig_buffer), &sig_len);
- if (psa_status == PSA_SUCCESS) {
+ if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_sign_hash_resp(resp_buf, sig_buffer, sig_len);
- }
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ rpc_status = serializer->serialize_sign_hash_resp(resp_buf, sig_buffer, sig_len);
+ }
- call_req_set_opstatus(req, psa_status);
- }
+ call_req_set_opstatus(req, psa_status);
+ }
- return rpc_status;
+ return rpc_status;
}
static rpc_status_t verify_hash_handler(void *context, struct call_req* req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
- psa_key_id_t id;
- psa_algorithm_t alg;
- size_t hash_len = PSA_HASH_MAX_SIZE;
- uint8_t hash_buffer[PSA_HASH_MAX_SIZE];
- size_t sig_len = PSA_SIGNATURE_MAX_SIZE;
- uint8_t sig_buffer[PSA_SIGNATURE_MAX_SIZE];
+ psa_key_id_t id;
+ psa_algorithm_t alg;
+ size_t hash_len = PSA_HASH_MAX_SIZE;
+ uint8_t hash_buffer[PSA_HASH_MAX_SIZE];
+ size_t sig_len = PSA_SIGNATURE_MAX_SIZE;
+ uint8_t sig_buffer[PSA_SIGNATURE_MAX_SIZE];
- if (serializer)
- rpc_status = serializer->deserialize_verify_hash_req(req_buf, &id, &alg,
- hash_buffer, &hash_len,
- sig_buffer, &sig_len);
+ if (serializer)
+ rpc_status = serializer->deserialize_verify_hash_req(req_buf, &id, &alg,
+ hash_buffer, &hash_len,
+ sig_buffer, &sig_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
- psa_status_t psa_status;
+ psa_status_t psa_status;
- psa_status = psa_verify_hash(id, alg,
- hash_buffer, hash_len,
- sig_buffer, sig_len);
+ psa_status = psa_verify_hash(id, alg,
+ hash_buffer, hash_len,
+ sig_buffer, sig_len);
- call_req_set_opstatus(req, psa_status);
- }
+ call_req_set_opstatus(req, psa_status);
+ }
- return rpc_status;
+ return rpc_status;
}
static rpc_status_t asymmetric_decrypt_handler(void *context, struct call_req* req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
- if (serializer) {
+ if (serializer) {
- size_t max_param_size = serializer->max_deserialised_parameter_size(req_buf);
+ size_t max_param_size = serializer->max_deserialised_parameter_size(req_buf);
- psa_key_id_t id;
- psa_algorithm_t alg;
- size_t ciphertext_len = max_param_size;
- uint8_t *ciphertext_buffer = malloc(ciphertext_len);
- size_t salt_len = max_param_size;
- uint8_t *salt_buffer = malloc(salt_len);
+ psa_key_id_t id;
+ psa_algorithm_t alg;
+ size_t ciphertext_len = max_param_size;
+ uint8_t *ciphertext_buffer = malloc(ciphertext_len);
+ size_t salt_len = max_param_size;
+ uint8_t *salt_buffer = malloc(salt_len);
- if (ciphertext_buffer && salt_buffer) {
+ if (ciphertext_buffer && salt_buffer) {
- rpc_status = serializer->deserialize_asymmetric_decrypt_req(req_buf,
- &id, &alg,
- ciphertext_buffer, &ciphertext_len,
- salt_buffer, &salt_len);
+ rpc_status = serializer->deserialize_asymmetric_decrypt_req(req_buf,
+ &id, &alg,
+ ciphertext_buffer, &ciphertext_len,
+ salt_buffer, &salt_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
- psa_status_t psa_status;
- psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ psa_status_t psa_status;
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
- psa_status = psa_get_key_attributes(id, &attributes);
+ psa_status = psa_get_key_attributes(id, &attributes);
- if (psa_status == PSA_SUCCESS) {
+ if (psa_status == PSA_SUCCESS) {
- size_t max_decrypt_size = PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(
- psa_get_key_type(&attributes),
- psa_get_key_bits(&attributes),
- alg);
+ size_t max_decrypt_size = PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(
+ psa_get_key_type(&attributes),
+ psa_get_key_bits(&attributes),
+ alg);
- size_t plaintext_len;
- uint8_t *plaintext_buffer = malloc(max_decrypt_size);
+ size_t plaintext_len;
+ uint8_t *plaintext_buffer = malloc(max_decrypt_size);
- if (plaintext_buffer) {
+ if (plaintext_buffer) {
- /* Salt is an optional parameter */
- uint8_t *salt = (salt_len) ? salt_buffer : NULL;
+ /* Salt is an optional parameter */
+ uint8_t *salt = (salt_len) ? salt_buffer : NULL;
- psa_status = psa_asymmetric_decrypt(id, alg,
- ciphertext_buffer, ciphertext_len,
- salt, salt_len,
- plaintext_buffer, max_decrypt_size, &plaintext_len);
+ psa_status = psa_asymmetric_decrypt(id, alg,
+ ciphertext_buffer, ciphertext_len,
+ salt, salt_len,
+ plaintext_buffer, max_decrypt_size, &plaintext_len);
- if (psa_status == PSA_SUCCESS) {
+ if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_asymmetric_decrypt_resp(resp_buf,
- plaintext_buffer, plaintext_len);
- }
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ rpc_status = serializer->serialize_asymmetric_decrypt_resp(resp_buf,
+ plaintext_buffer, plaintext_len);
+ }
- free(plaintext_buffer);
- }
- else {
- /* Failed to allocate ouptput buffer */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
- }
- }
+ free(plaintext_buffer);
+ }
+ else {
+ /* Failed to allocate ouptput buffer */
+ rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ }
+ }
- call_req_set_opstatus(req, psa_status);
- psa_reset_key_attributes(&attributes);
- }
- }
- else {
- /* Failed to allocate buffers */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
- }
+ call_req_set_opstatus(req, psa_status);
+ psa_reset_key_attributes(&attributes);
+ }
+ }
+ else {
+ /* Failed to allocate buffers */
+ rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ }
- free(ciphertext_buffer);
- free(salt_buffer);
- }
+ free(ciphertext_buffer);
+ free(salt_buffer);
+ }
- return rpc_status;
+ return rpc_status;
}
static rpc_status_t asymmetric_encrypt_handler(void *context, struct call_req* req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
- if (serializer) {
+ if (serializer) {
- size_t max_param_size = serializer->max_deserialised_parameter_size(req_buf);
+ size_t max_param_size = serializer->max_deserialised_parameter_size(req_buf);
- psa_key_id_t id;
- psa_algorithm_t alg;
- size_t plaintext_len = max_param_size;
- uint8_t *plaintext_buffer = malloc(plaintext_len);
- size_t salt_len = max_param_size;
- uint8_t *salt_buffer = malloc(salt_len);
+ psa_key_id_t id;
+ psa_algorithm_t alg;
+ size_t plaintext_len = max_param_size;
+ uint8_t *plaintext_buffer = malloc(plaintext_len);
+ size_t salt_len = max_param_size;
+ uint8_t *salt_buffer = malloc(salt_len);
- if (plaintext_buffer && salt_buffer) {
+ if (plaintext_buffer && salt_buffer) {
- rpc_status = serializer->deserialize_asymmetric_encrypt_req(req_buf,
- &id, &alg,
- plaintext_buffer, &plaintext_len,
- salt_buffer, &salt_len);
+ rpc_status = serializer->deserialize_asymmetric_encrypt_req(req_buf,
+ &id, &alg,
+ plaintext_buffer, &plaintext_len,
+ salt_buffer, &salt_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
- psa_status_t psa_status;
- psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ psa_status_t psa_status;
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
- psa_status = psa_get_key_attributes(id, &attributes);
+ psa_status = psa_get_key_attributes(id, &attributes);
- if (psa_status == PSA_SUCCESS) {
+ if (psa_status == PSA_SUCCESS) {
- size_t max_encrypt_size = PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(
- psa_get_key_type(&attributes),
- psa_get_key_bits(&attributes),
- alg);
+ size_t max_encrypt_size = PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(
+ psa_get_key_type(&attributes),
+ psa_get_key_bits(&attributes),
+ alg);
- size_t ciphertext_len;
- uint8_t *ciphertext_buffer = malloc(max_encrypt_size);
+ size_t ciphertext_len;
+ uint8_t *ciphertext_buffer = malloc(max_encrypt_size);
- if (ciphertext_buffer) {
+ if (ciphertext_buffer) {
- /* Salt is an optional parameter */
- uint8_t *salt = (salt_len) ? salt_buffer : NULL;
+ /* Salt is an optional parameter */
+ uint8_t *salt = (salt_len) ? salt_buffer : NULL;
- psa_status = psa_asymmetric_encrypt(id, alg,
- plaintext_buffer, plaintext_len,
- salt, salt_len,
- ciphertext_buffer, max_encrypt_size, &ciphertext_len);
+ psa_status = psa_asymmetric_encrypt(id, alg,
+ plaintext_buffer, plaintext_len,
+ salt, salt_len,
+ ciphertext_buffer, max_encrypt_size, &ciphertext_len);
- if (psa_status == PSA_SUCCESS) {
+ if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_asymmetric_encrypt_resp(resp_buf,
- ciphertext_buffer, ciphertext_len);
- }
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ rpc_status = serializer->serialize_asymmetric_encrypt_resp(resp_buf,
+ ciphertext_buffer, ciphertext_len);
+ }
- free(ciphertext_buffer);
- }
- else {
- /* Failed to allocate ouptput buffer */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
- }
- }
+ free(ciphertext_buffer);
+ }
+ else {
+ /* Failed to allocate ouptput buffer */
+ rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ }
+ }
- call_req_set_opstatus(req, psa_status);
- psa_reset_key_attributes(&attributes);
- }
- }
- else {
- /* Failed to allocate buffers */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
- }
+ call_req_set_opstatus(req, psa_status);
+ psa_reset_key_attributes(&attributes);
+ }
+ }
+ else {
+ /* Failed to allocate buffers */
+ rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ }
- free(plaintext_buffer);
- free(salt_buffer);
- }
+ free(plaintext_buffer);
+ free(salt_buffer);
+ }
- return rpc_status;
+ return rpc_status;
}
static rpc_status_t generate_random_handler(void *context, struct call_req* req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
- size_t output_size;
+ size_t output_size;
- if (serializer)
- rpc_status = serializer->deserialize_generate_random_req(req_buf, &output_size);
+ if (serializer)
+ rpc_status = serializer->deserialize_generate_random_req(req_buf, &output_size);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
- psa_status_t psa_status;
- uint8_t *output_buffer = malloc(output_size);
+ psa_status_t psa_status;
+ uint8_t *output_buffer = malloc(output_size);
- if (output_buffer) {
+ if (output_buffer) {
- psa_status = psa_generate_random(output_buffer, output_size);
+ psa_status = psa_generate_random(output_buffer, output_size);
- if (psa_status == PSA_SUCCESS) {
+ if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_generate_random_resp(resp_buf,
- output_buffer, output_size);
- }
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ rpc_status = serializer->serialize_generate_random_resp(resp_buf,
+ output_buffer, output_size);
+ }
- call_req_set_opstatus(req, psa_status);
- free(output_buffer);
- }
- else {
- /* Failed to allocate output buffer */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
- }
- }
+ call_req_set_opstatus(req, psa_status);
+ free(output_buffer);
+ }
+ else {
+ /* Failed to allocate output buffer */
+ rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ }
+ }
- return rpc_status;
+ return rpc_status;
+}
+
+static rpc_status_t hash_setup_handler(void *context, struct call_req* req)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+ struct mbed_crypto_provider *this_instance = (struct mbed_crypto_provider*)context;
+
+ psa_algorithm_t alg;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_hash_setup_req(req_buf, &alg);
+
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+ uint32_t op_handle;
+
+ struct crypto_context *crypto_context =
+ crypto_context_pool_alloc(&this_instance->context_pool,
+ CRYPTO_CONTEXT_OP_ID_HASH, call_req_get_caller_id(req),
+ &op_handle);
+
+ if (crypto_context) {
+
+ psa_status_t psa_status;
+
+ crypto_context->op.hash = psa_hash_operation_init();
+ psa_status = psa_hash_setup(&crypto_context->op.hash, alg);
+
+ if (psa_status == PSA_SUCCESS) {
+
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ rpc_status = serializer->serialize_hash_setup_resp(resp_buf, op_handle);
+ }
+
+ if ((psa_status != PSA_SUCCESS) || (rpc_status != TS_RPC_CALL_ACCEPTED)) {
+
+ crypto_context_pool_free(&this_instance->context_pool, crypto_context);
+ }
+
+ call_req_set_opstatus(req, psa_status);
+ }
+ else {
+ /* Failed to allocate crypto context for transaction */
+ rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ }
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t hash_update_handler(void *context, struct call_req* req)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+ struct mbed_crypto_provider *this_instance = (struct mbed_crypto_provider*)context;
+
+ uint32_t op_handle;
+ const uint8_t *data;
+ size_t data_len;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_hash_update_req(req_buf, &op_handle, &data, &data_len);
+
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+ struct crypto_context *crypto_context =
+ crypto_context_pool_find(&this_instance->context_pool,
+ CRYPTO_CONTEXT_OP_ID_HASH, call_req_get_caller_id(req),
+ op_handle);
+
+ if (crypto_context) {
+
+ psa_status_t psa_status = psa_hash_update(&crypto_context->op.hash, data, data_len);
+ call_req_set_opstatus(req, psa_status);
+ }
+ else {
+ /* Requested context doesn't exist */
+ rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ }
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t hash_finish_handler(void *context, struct call_req* req)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+ struct mbed_crypto_provider *this_instance = (struct mbed_crypto_provider*)context;
+
+ uint32_t op_handle;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_hash_finish_req(req_buf, &op_handle);
+
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+ struct crypto_context *crypto_context =
+ crypto_context_pool_find(&this_instance->context_pool,
+ CRYPTO_CONTEXT_OP_ID_HASH, call_req_get_caller_id(req),
+ op_handle);
+
+ if (crypto_context) {
+
+ psa_status_t psa_status;
+ size_t hash_len;
+ uint8_t hash[PSA_HASH_MAX_SIZE];
+
+ psa_status = psa_hash_finish(&crypto_context->op.hash, hash, sizeof(hash), &hash_len);
+
+ if (psa_status == PSA_SUCCESS) {
+
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ rpc_status = serializer->serialize_hash_finish_resp(resp_buf, hash, hash_len);
+ }
+
+ crypto_context_pool_free(&this_instance->context_pool, crypto_context);
+
+ call_req_set_opstatus(req, psa_status);
+ }
+ else {
+ /* Requested context doesn't exist */
+ rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ }
+ }
+
+ return rpc_status;
}
diff --git a/components/service/crypto/provider/mbedcrypto/crypto_provider.h b/components/service/crypto/provider/mbedcrypto/crypto_provider.h
index 3c0f8d8..19bc2c2 100644
--- a/components/service/crypto/provider/mbedcrypto/crypto_provider.h
+++ b/components/service/crypto/provider/mbedcrypto/crypto_provider.h
@@ -12,6 +12,7 @@
#include <service/crypto/provider/serializer/crypto_provider_serializer.h>
#include <service/secure_storage/backend/storage_backend.h>
#include <protocols/rpc/common/packed-c/encoding.h>
+#include "crypto_context_pool.h"
#ifdef __cplusplus
extern "C" {
@@ -20,6 +21,7 @@
struct mbed_crypto_provider
{
struct service_provider base_provider;
+ struct crypto_context_pool context_pool;
const struct crypto_provider_serializer *serializers[TS_RPC_ENCODING_LIMIT];
};
diff --git a/components/service/crypto/provider/mbedcrypto/test/component.cmake b/components/service/crypto/provider/mbedcrypto/test/component.cmake
new file mode 100644
index 0000000..4f754a2
--- /dev/null
+++ b/components/service/crypto/provider/mbedcrypto/test/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/crypto_context_pool_tests.cpp"
+ )
diff --git a/components/service/crypto/provider/mbedcrypto/test/crypto_context_pool_tests.cpp b/components/service/crypto/provider/mbedcrypto/test/crypto_context_pool_tests.cpp
new file mode 100644
index 0000000..1b6a12e
--- /dev/null
+++ b/components/service/crypto/provider/mbedcrypto/test/crypto_context_pool_tests.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+#include <service/crypto/provider/mbedcrypto/crypto_context_pool.h>
+#include <CppUTest/TestHarness.h>
+
+/*
+ * Component tests for the crypto_context_pool.
+ */
+TEST_GROUP(CryptoContextPoolTests)
+{
+ void setup()
+ {
+ crypto_context_pool_init(&pool_under_test);
+ }
+
+ void teardown()
+ {
+ crypto_context_pool_deinit(&pool_under_test);
+ }
+
+ struct crypto_context_pool pool_under_test;
+};
+
+TEST(CryptoContextPoolTests, checkEmptyPool)
+{
+ struct crypto_context *context =
+ crypto_context_pool_find(&pool_under_test, CRYPTO_CONTEXT_OP_ID_HASH, 0, 0);
+
+ /* Expect a freshly initialized pool to fail to find a context */
+ CHECK_FALSE(context);
+}
+
+TEST(CryptoContextPoolTests, singleContext)
+{
+ uint32_t op_handle;
+ uint32_t client_id = 22;
+
+ struct crypto_context *initial_context =
+ crypto_context_pool_alloc(&pool_under_test,
+ CRYPTO_CONTEXT_OP_ID_HASH, client_id,
+ &op_handle);
+
+ CHECK_TRUE(initial_context);
+
+ struct crypto_context *follow_on_context =
+ crypto_context_pool_find(&pool_under_test,
+ CRYPTO_CONTEXT_OP_ID_HASH, client_id,
+ op_handle);
+
+ UNSIGNED_LONGS_EQUAL(initial_context, follow_on_context);
+
+ crypto_context_pool_free(&pool_under_test, initial_context);
+}
+
+TEST(CryptoContextPoolTests, multipleContexts)
+{
+ /* Test multiple concurrent contexts but never exceeding the pool size */
+ struct crypto_context *context;
+ uint32_t zombie_handle_1, zombie_handle_2;
+
+ /* First start a couple of zombie contexts. This will occur if a client
+ * starts a transaction but never finishes it. This could happen due to a
+ * misbehaving client or if a client process crashes. This checks that
+ * recycling of least recently used contexts is working.
+ */
+ context = crypto_context_pool_alloc(&pool_under_test,
+ CRYPTO_CONTEXT_OP_ID_MAC, 77,
+ &zombie_handle_1);
+ CHECK_TRUE(context);
+
+ context = crypto_context_pool_alloc(&pool_under_test,
+ CRYPTO_CONTEXT_OP_ID_CIPHER, 88,
+ &zombie_handle_2);
+ CHECK_TRUE(context);
+
+ /* Now run through the normal life-cycle for a load of concurrent contexts */
+ for (unsigned int i = 0; i < 1000; ++i) {
+
+ uint32_t op_handles[CRYPTO_CONTEXT_POOL_SIZE];
+ unsigned int num_concurrent = (rand() % CRYPTO_CONTEXT_POOL_SIZE) + 1;
+
+ /* Start some concurrent contexts, each belonging to different clients */
+ for (unsigned int context_index = 0; context_index < num_concurrent; ++context_index) {
+
+ context = crypto_context_pool_alloc(&pool_under_test,
+ CRYPTO_CONTEXT_OP_ID_HASH, context_index,
+ &op_handles[context_index]);
+
+ CHECK_TRUE(context);
+ }
+
+ /* Expect the find to work for all active contexts */
+ for (unsigned int context_index = 0; context_index < num_concurrent; ++context_index) {
+
+ context = crypto_context_pool_find(&pool_under_test,
+ CRYPTO_CONTEXT_OP_ID_HASH, context_index,
+ op_handles[context_index]);
+
+ CHECK_TRUE(context);
+ }
+
+ /* Then find and free all contexts */
+ for (unsigned int context_index = 0; context_index < num_concurrent; ++context_index) {
+
+ context = crypto_context_pool_find(&pool_under_test,
+ CRYPTO_CONTEXT_OP_ID_HASH, context_index,
+ op_handles[context_index]);
+
+ CHECK_TRUE(context);
+
+ crypto_context_pool_free(&pool_under_test, context);
+ }
+ }
+
+ /* Expect the zombie contexts to have been recycled */
+ context = crypto_context_pool_find(&pool_under_test,
+ CRYPTO_CONTEXT_OP_ID_MAC, 77,
+ zombie_handle_1);
+ CHECK_FALSE(context);
+
+ context = crypto_context_pool_find(&pool_under_test,
+ CRYPTO_CONTEXT_OP_ID_CIPHER, 88,
+ zombie_handle_2);
+ CHECK_FALSE(context);
+}