Allow alternative backends for crypto provider

The crypto service provider is refactored to make it easy to add
alternative backends.  There is still only a single backend that
uses the mbedcrypto library from MbedTLS.  However, all dependencies
from the crypto provider on mbedcrypto have been removed, allowing
the crypto provider to be used with alternative implementations
of the PSA Crypto API.

Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: Ic5d1d9d47d149b634d147712749fdee48f260d85
diff --git a/components/service/crypto/provider/crypto_provider.c b/components/service/crypto/provider/crypto_provider.c
new file mode 100644
index 0000000..3dc2a41
--- /dev/null
+++ b/components/service/crypto/provider/crypto_provider.c
@@ -0,0 +1,698 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stdint.h>
+#include <stdlib.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <service/crypto/provider/crypto_provider.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <psa/crypto.h>
+
+/* Service request handlers */
+static rpc_status_t nop_handler(void *context, struct call_req* req);
+static rpc_status_t generate_key_handler(void *context, struct call_req* req);
+static rpc_status_t destroy_key_handler(void *context, struct call_req* req);
+static rpc_status_t export_key_handler(void *context, struct call_req* req);
+static rpc_status_t export_public_key_handler(void *context, struct call_req* req);
+static rpc_status_t import_key_handler(void *context, struct call_req* req);
+static rpc_status_t sign_hash_handler(void *context, struct call_req* req);
+static rpc_status_t verify_hash_handler(void *context, struct call_req* req);
+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_HASH_SETUP,           hash_setup_handler},
+	{TS_CRYPTO_OPCODE_HASH_UPDATE,          hash_update_handler},
+	{TS_CRYPTO_OPCODE_HASH_FINISH,          hash_finish_handler}
+};
+
+struct rpc_interface *crypto_provider_init(struct crypto_provider *context)
+{
+	crypto_context_pool_init(&context->context_pool);
+
+	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));
+
+	return service_provider_get_rpc_interface(&context->base_provider);
+}
+
+void crypto_provider_deinit(struct crypto_provider *context)
+{
+	crypto_context_pool_deinit(&context->context_pool);
+}
+
+void crypto_provider_register_serializer(struct crypto_provider *context,
+				unsigned int encoding, const struct crypto_provider_serializer *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)
+{
+	struct crypto_provider *this_instance = (struct 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];
+
+	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;
+
+	(void)context;
+	call_req_set_opstatus(req, psa_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);
+
+	psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+	if (serializer)
+		rpc_status = serializer->deserialize_generate_key_req(req_buf, &attributes);
+
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+		psa_status_t psa_status;
+		psa_key_id_t id;
+
+		psa_status = psa_generate_key(&attributes, &id);
+
+		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);
+		}
+
+		call_req_set_opstatus(req, psa_status);
+	}
+
+	psa_reset_key_attributes(&attributes);
+
+	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);
+
+	psa_key_id_t id;
+
+	if (serializer)
+		rpc_status = serializer->deserialize_destroy_key_req(req_buf, &id);
+
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+		psa_status_t psa_status;
+
+		psa_status = psa_destroy_key(id);
+		call_req_set_opstatus(req, psa_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);
+
+	psa_key_id_t id;
+
+	if (serializer)
+		rpc_status = serializer->deserialize_export_key_req(req_buf, &id);
+
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+		psa_status_t psa_status;
+		psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+		psa_status = psa_get_key_attributes(id, &attributes);
+
+		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));
+
+			uint8_t *key_buffer = malloc(max_export_size);
+
+			if (key_buffer) {
+
+				size_t export_size;
+				psa_status = psa_export_key(id, key_buffer, max_export_size, &export_size);
+
+				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);
+				}
+
+				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);
+	}
+
+	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);
+
+	psa_key_id_t id;
+
+	if (serializer)
+		rpc_status = serializer->deserialize_export_public_key_req(req_buf, &id);
+
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+		psa_status_t psa_status;
+		psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+		psa_status = psa_get_key_attributes(id, &attributes);
+
+		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));
+
+			uint8_t *key_buffer = malloc(max_export_size);
+
+			if (key_buffer) {
+
+				size_t export_size;
+				psa_status = psa_export_public_key(id, key_buffer, max_export_size, &export_size);
+
+				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);
+				}
+
+				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);
+	}
+
+	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);
+
+	if (serializer) {
+
+		size_t key_data_len = serializer->max_deserialised_parameter_size(req_buf);
+		uint8_t *key_buffer = malloc(key_data_len);
+
+		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);
+
+			if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+				psa_status_t psa_status;
+				psa_key_id_t id;
+
+				psa_status = psa_import_key(&attributes, key_buffer, key_data_len, &id);
+
+				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);
+				}
+
+				call_req_set_opstatus(req, psa_status);
+			}
+
+			psa_reset_key_attributes(&attributes);
+			free(key_buffer);
+		}
+		else {
+
+			rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+		}
+	}
+
+	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);
+
+	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 (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 = psa_sign_hash(id, alg,
+					hash_buffer, hash_len,
+					sig_buffer, sizeof(sig_buffer), &sig_len);
+
+		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);
+		}
+
+		call_req_set_opstatus(req, psa_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);
+
+	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 (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+		psa_status_t psa_status;
+
+		psa_status = psa_verify_hash(id, alg,
+					hash_buffer, hash_len,
+					sig_buffer, sig_len);
+
+		call_req_set_opstatus(req, psa_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);
+
+	if (serializer) {
+
+		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);
+
+		if (ciphertext_buffer && salt_buffer) {
+
+			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) {
+
+				psa_status_t psa_status;
+				psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+				psa_status = psa_get_key_attributes(id, &attributes);
+
+				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 plaintext_len;
+					uint8_t *plaintext_buffer = malloc(max_decrypt_size);
+
+					if (plaintext_buffer) {
+
+						/* 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);
+
+						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);
+						}
+
+						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;
+		}
+
+		free(ciphertext_buffer);
+		free(salt_buffer);
+	}
+
+	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);
+
+	if (serializer) {
+
+		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);
+
+		if (plaintext_buffer && salt_buffer) {
+
+			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) {
+
+				psa_status_t psa_status;
+				psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+				psa_status = psa_get_key_attributes(id, &attributes);
+
+				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 ciphertext_len;
+					uint8_t *ciphertext_buffer = malloc(max_encrypt_size);
+
+					if (ciphertext_buffer) {
+
+						/* 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);
+
+						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);
+						}
+
+						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;
+		}
+
+		free(plaintext_buffer);
+		free(salt_buffer);
+	}
+
+	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);
+
+	size_t output_size;
+
+	if (serializer)
+		rpc_status = serializer->deserialize_generate_random_req(req_buf, &output_size);
+
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+		psa_status_t psa_status;
+		uint8_t *output_buffer = malloc(output_size);
+
+		if (output_buffer) {
+
+			psa_status = psa_generate_random(output_buffer, output_size);
+
+			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);
+			}
+
+			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;
+}
+
+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 crypto_provider *this_instance = (struct 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 crypto_provider *this_instance = (struct 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 crypto_provider *this_instance = (struct 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;
+}