Add support for key derivation cipher operations

Adds a crypto sub-provider for key derivation operations.

Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: I16db22df273151c72d618724331b8cf22e770580
diff --git a/components/service/crypto/client/psa/component.cmake b/components/service/crypto/client/psa/component.cmake
index ca158d5..80dd54a 100644
--- a/components/service/crypto/client/psa/component.cmake
+++ b/components/service/crypto/client/psa/component.cmake
@@ -27,7 +27,6 @@
 	"${CMAKE_CURRENT_LIST_DIR}/psa_hash.c"
 	"${CMAKE_CURRENT_LIST_DIR}/psa_mac.c"
 	"${CMAKE_CURRENT_LIST_DIR}/psa_key_derivation.c"
-	"${CMAKE_CURRENT_LIST_DIR}/psa_key_agreement.c"
 	"${CMAKE_CURRENT_LIST_DIR}/psa_cipher.c"
 	"${CMAKE_CURRENT_LIST_DIR}/psa_aead.c"
 	)
diff --git a/components/service/crypto/client/psa/psa_key_agreement.c b/components/service/crypto/client/psa/psa_key_agreement.c
deleted file mode 100644
index 5ccafb4..0000000
--- a/components/service/crypto/client/psa/psa_key_agreement.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <string.h>
-#include <stdlib.h>
-#include <psa/crypto.h>
-#include "psa_crypto_client.h"
-#include <protocols/rpc/common/packed-c/status.h>
-#include <protocols/service/crypto/packed-c/opcodes.h>
-#include <common/tlv/tlv.h>
-
-psa_status_t psa_raw_key_agreement(psa_algorithm_t alg,
-	psa_key_id_t private_key,
-	const uint8_t *peer_key,
-	size_t peer_key_length,
-	uint8_t *output,
-	size_t output_size,
-	size_t *output_length)
-{
-	return PSA_ERROR_NOT_SUPPORTED;
-}
diff --git a/components/service/crypto/client/psa/psa_key_derivation.c b/components/service/crypto/client/psa/psa_key_derivation.c
index 8c31006..e518f5a 100644
--- a/components/service/crypto/client/psa/psa_key_derivation.c
+++ b/components/service/crypto/client/psa/psa_key_derivation.c
@@ -8,29 +8,150 @@
 #include <stdlib.h>
 #include <psa/crypto.h>
 #include "psa_crypto_client.h"
+#include "psa_crypto_client_key_attributes.h"
 #include <protocols/rpc/common/packed-c/status.h>
 #include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_derivation.h>
 #include <common/tlv/tlv.h>
 
 psa_status_t psa_key_derivation_setup(
 	psa_key_derivation_operation_t *operation,
 	psa_algorithm_t alg)
 {
-	return PSA_ERROR_NOT_SUPPORTED;
+	psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+	struct ts_crypto_key_derivation_setup_in req_msg;
+	size_t req_len = sizeof(struct ts_crypto_key_derivation_setup_in);
+
+	req_msg.alg = alg;
+
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
+
+	call_handle = rpc_caller_begin(psa_crypto_client_instance.caller, &req_buf, req_len);
+
+	if (call_handle) {
+
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
+
+		memcpy(req_buf, &req_msg, req_len);
+
+		psa_crypto_client_instance.rpc_status =
+			rpc_caller_invoke(psa_crypto_client_instance.caller, call_handle,
+				TS_CRYPTO_OPCODE_KEY_DERIVATION_SETUP, &opstatus, &resp_buf, &resp_len);
+
+		if (psa_crypto_client_instance.rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+			psa_status = opstatus;
+
+			if (psa_status == PSA_SUCCESS) {
+
+				if (resp_len >= sizeof(struct ts_crypto_key_derivation_setup_out)) {
+
+					struct ts_crypto_key_derivation_setup_out resp_msg;
+					memcpy(&resp_msg, resp_buf, sizeof(struct ts_crypto_key_derivation_setup_out));
+					operation->handle = resp_msg.op_handle;
+				}
+				else {
+					/* Failed to decode response message */
+					psa_status = PSA_ERROR_GENERIC_ERROR;
+				}
+			}
+		}
+
+		rpc_caller_end(psa_crypto_client_instance.caller, call_handle);
+	}
+
+	return psa_status;
 }
 
 psa_status_t psa_key_derivation_get_capacity(
 	const psa_key_derivation_operation_t *operation,
 	size_t *capacity)
 {
-	return PSA_ERROR_NOT_SUPPORTED;
+	psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+	struct ts_crypto_key_derivation_get_capacity_in req_msg;
+	size_t req_len = sizeof(struct ts_crypto_key_derivation_get_capacity_in);
+
+	req_msg.op_handle = operation->handle;
+
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
+
+	call_handle = rpc_caller_begin(psa_crypto_client_instance.caller, &req_buf, req_len);
+
+	if (call_handle) {
+
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
+
+		memcpy(req_buf, &req_msg, req_len);
+
+		psa_crypto_client_instance.rpc_status =
+			rpc_caller_invoke(psa_crypto_client_instance.caller, call_handle,
+				TS_CRYPTO_OPCODE_KEY_DERIVATION_GET_CAPACITY, &opstatus, &resp_buf, &resp_len);
+
+		if (psa_crypto_client_instance.rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+			psa_status = opstatus;
+
+			if (psa_status == PSA_SUCCESS) {
+
+				if (resp_len >= sizeof(struct ts_crypto_key_derivation_get_capacity_out)) {
+
+					struct ts_crypto_key_derivation_get_capacity_out resp_msg;
+					memcpy(&resp_msg, resp_buf, sizeof(struct ts_crypto_key_derivation_get_capacity_out));
+					*capacity = resp_msg.capacity;
+				}
+				else {
+					/* Failed to decode response message */
+					psa_status = PSA_ERROR_GENERIC_ERROR;
+				}
+			}
+		}
+
+		rpc_caller_end(psa_crypto_client_instance.caller, call_handle);
+	}
+
+	return psa_status;
 }
 
 psa_status_t psa_key_derivation_set_capacity(
 	psa_key_derivation_operation_t *operation,
 	size_t capacity)
 {
-	return PSA_ERROR_NOT_SUPPORTED;
+	psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+	struct ts_crypto_key_derivation_set_capacity_in req_msg;
+	size_t req_len = sizeof(struct ts_crypto_key_derivation_set_capacity_in);
+
+	req_msg.op_handle = operation->handle;
+	req_msg.capacity = capacity;
+
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
+
+	call_handle = rpc_caller_begin(psa_crypto_client_instance.caller, &req_buf, req_len);
+
+	if (call_handle) {
+
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
+
+		memcpy(req_buf, &req_msg, req_len);
+
+		psa_crypto_client_instance.rpc_status =
+			rpc_caller_invoke(psa_crypto_client_instance.caller, call_handle,
+				TS_CRYPTO_OPCODE_KEY_DERIVATION_SET_CAPACITY, &opstatus, &resp_buf, &resp_len);
+
+		if (psa_crypto_client_instance.rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+
+		rpc_caller_end(psa_crypto_client_instance.caller, call_handle);
+	}
+
+	return psa_status;
 }
 
 psa_status_t psa_key_derivation_input_bytes(
@@ -39,7 +160,48 @@
 	const uint8_t *data,
 	size_t data_length)
 {
-	return PSA_ERROR_NOT_SUPPORTED;
+	psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+	struct ts_crypto_key_derivation_input_bytes_in req_msg;
+	size_t req_fixed_len = sizeof(struct ts_crypto_key_derivation_input_bytes_in);
+	size_t req_len = req_fixed_len;
+
+	req_msg.op_handle = operation->handle;
+	req_msg.step = step;
+
+	/* Mandatory input data parameter */
+	struct tlv_record data_record;
+	data_record.tag = TS_CRYPTO_KEY_DERIVATION_INPUT_BYTES_IN_TAG_DATA;
+	data_record.length = data_length;
+	data_record.value = data;
+	req_len += tlv_required_space(data_record.length);
+
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
+
+	call_handle = rpc_caller_begin(psa_crypto_client_instance.caller, &req_buf, req_len);
+
+	if (call_handle) {
+
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
+		struct tlv_iterator req_iter;
+
+		memcpy(req_buf, &req_msg, req_fixed_len);
+
+		tlv_iterator_begin(&req_iter, &req_buf[req_fixed_len], req_len - req_fixed_len);
+		tlv_encode(&req_iter, &data_record);
+
+		psa_crypto_client_instance.rpc_status =
+			rpc_caller_invoke(psa_crypto_client_instance.caller, call_handle,
+				TS_CRYPTO_OPCODE_KEY_DERIVATION_INPUT_BYTES, &opstatus, &resp_buf, &resp_len);
+
+		if (psa_crypto_client_instance.rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+
+		rpc_caller_end(psa_crypto_client_instance.caller, call_handle);
+	}
+
+	return psa_status;
 }
 
 psa_status_t psa_key_derivation_input_key(
@@ -47,7 +209,195 @@
 	psa_key_derivation_step_t step,
 	psa_key_id_t key)
 {
-	return PSA_ERROR_NOT_SUPPORTED;
+	psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+	struct ts_crypto_key_derivation_input_key_in req_msg;
+	size_t req_len = sizeof(struct ts_crypto_key_derivation_input_key_in);
+
+	req_msg.op_handle = operation->handle;
+	req_msg.step = step;
+	req_msg.key_id = key;
+
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
+
+	call_handle = rpc_caller_begin(psa_crypto_client_instance.caller, &req_buf, req_len);
+
+	if (call_handle) {
+
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
+
+		memcpy(req_buf, &req_msg, req_len);
+
+		psa_crypto_client_instance.rpc_status =
+			rpc_caller_invoke(psa_crypto_client_instance.caller, call_handle,
+				TS_CRYPTO_OPCODE_KEY_DERIVATION_INPUT_KEY, &opstatus, &resp_buf, &resp_len);
+
+		if (psa_crypto_client_instance.rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+
+		rpc_caller_end(psa_crypto_client_instance.caller, call_handle);
+	}
+
+	return psa_status;
+}
+
+psa_status_t psa_key_derivation_output_bytes(
+	psa_key_derivation_operation_t *operation,
+	uint8_t *output,
+	size_t output_length)
+{
+	psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+	struct ts_crypto_key_derivation_output_bytes_in req_msg;
+	size_t req_fixed_len = sizeof(struct ts_crypto_key_derivation_output_bytes_in);
+	size_t req_len = req_fixed_len;
+
+	req_msg.op_handle = operation->handle;
+	req_msg.output_len = output_length;
+
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
+
+	call_handle = rpc_caller_begin(psa_crypto_client_instance.caller, &req_buf, req_len);
+
+	if (call_handle) {
+
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
+
+		memcpy(req_buf, &req_msg, req_fixed_len);
+
+		psa_crypto_client_instance.rpc_status =
+			rpc_caller_invoke(psa_crypto_client_instance.caller, call_handle,
+				TS_CRYPTO_OPCODE_KEY_DERIVATION_OUTPUT_BYTES, &opstatus, &resp_buf, &resp_len);
+
+		if (psa_crypto_client_instance.rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+			psa_status = opstatus;
+
+			if (psa_status == PSA_SUCCESS) {
+
+				struct tlv_const_iterator resp_iter;
+				struct tlv_record decoded_record;
+				tlv_const_iterator_begin(&resp_iter, resp_buf, resp_len);
+
+				if (tlv_find_decode(&resp_iter,
+					TS_CRYPTO_KEY_DERIVATION_OUTPUT_BYTES_OUT_TAG_DATA, &decoded_record)) {
+
+					if (decoded_record.length == output_length) {
+
+						memcpy(output, decoded_record.value, decoded_record.length);
+					}
+					else {
+						/* Should have returned the requested number of bytes */
+						psa_status = PSA_ERROR_GENERIC_ERROR;
+					}
+				}
+				else {
+					/* Mandatory response parameter missing */
+					psa_status = PSA_ERROR_GENERIC_ERROR;
+				}
+			}
+		}
+
+		rpc_caller_end(psa_crypto_client_instance.caller, call_handle);
+	}
+
+	return psa_status;
+}
+
+psa_status_t psa_key_derivation_output_key(
+	const psa_key_attributes_t *attributes,
+	psa_key_derivation_operation_t *operation,
+	psa_key_id_t *key)
+{
+	psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+	struct ts_crypto_key_derivation_output_key_in req_msg;
+	size_t req_len = sizeof(struct ts_crypto_key_derivation_output_key_in);
+
+	/* Set default outputs for failure case */
+	*key = 0;
+
+	req_msg.op_handle = operation->handle;
+	psa_crypto_client_translate_key_attributes_to_proto(&req_msg.attributes, attributes);
+
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
+
+	call_handle = rpc_caller_begin(psa_crypto_client_instance.caller, &req_buf, req_len);
+
+	if (call_handle) {
+
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
+
+		memcpy(req_buf, &req_msg, req_len);
+
+		psa_crypto_client_instance.rpc_status =
+			rpc_caller_invoke(psa_crypto_client_instance.caller, call_handle,
+				TS_CRYPTO_OPCODE_KEY_DERIVATION_OUTPUT_KEY, &opstatus, &resp_buf, &resp_len);
+
+		if (psa_crypto_client_instance.rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+			psa_status = opstatus;
+
+			if (psa_status == PSA_SUCCESS) {
+
+				if (resp_len >= sizeof(struct ts_crypto_key_derivation_output_key_out)) {
+
+					struct ts_crypto_key_derivation_output_key_out resp_msg;
+					memcpy(&resp_msg, resp_buf,
+						sizeof(struct ts_crypto_key_derivation_output_key_out));
+					*key = resp_msg.key_id;
+				}
+				else {
+					/* Failed to decode response message */
+					psa_status = PSA_ERROR_GENERIC_ERROR;
+				}
+			}
+		}
+
+		rpc_caller_end(psa_crypto_client_instance.caller, call_handle);
+	}
+
+	return psa_status;
+}
+
+psa_status_t psa_key_derivation_abort(
+	psa_key_derivation_operation_t *operation)
+{
+	psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+	struct ts_crypto_key_derivation_abort_in req_msg;
+	size_t req_fixed_len = sizeof(struct ts_crypto_key_derivation_abort_in);
+	size_t req_len = req_fixed_len;
+
+	req_msg.op_handle = operation->handle;
+
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
+
+	call_handle = rpc_caller_begin(psa_crypto_client_instance.caller, &req_buf, req_len);
+
+	if (call_handle) {
+
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
+
+		memcpy(req_buf, &req_msg, req_fixed_len);
+
+		psa_crypto_client_instance.rpc_status =
+			rpc_caller_invoke(psa_crypto_client_instance.caller, call_handle,
+				TS_CRYPTO_OPCODE_KEY_DERIVATION_ABORT, &opstatus, &resp_buf, &resp_len);
+
+		if (psa_crypto_client_instance.rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+
+		rpc_caller_end(psa_crypto_client_instance.caller, call_handle);
+	}
+
+	return psa_status;
 }
 
 psa_status_t psa_key_derivation_key_agreement(
@@ -57,27 +407,127 @@
 	const uint8_t *peer_key,
 	size_t peer_key_length)
 {
-	return PSA_ERROR_NOT_SUPPORTED;
+	psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+	struct ts_crypto_key_derivation_key_agreement_in req_msg;
+	size_t req_fixed_len = sizeof(struct ts_crypto_key_derivation_key_agreement_in);
+	size_t req_len = req_fixed_len;
+
+	req_msg.op_handle = operation->handle;
+	req_msg.step = step;
+	req_msg.private_key_id = private_key;
+
+	/* Mandatory input data parameter */
+	struct tlv_record data_record;
+	data_record.tag = TS_CRYPTO_KEY_DERIVATION_KEY_AGREEMENT_IN_TAG_PEER_KEY;
+	data_record.length = peer_key_length;
+	data_record.value = peer_key;
+	req_len += tlv_required_space(data_record.length);
+
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
+
+	call_handle = rpc_caller_begin(psa_crypto_client_instance.caller, &req_buf, req_len);
+
+	if (call_handle) {
+
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
+		struct tlv_iterator req_iter;
+
+		memcpy(req_buf, &req_msg, req_fixed_len);
+
+		tlv_iterator_begin(&req_iter, &req_buf[req_fixed_len], req_len - req_fixed_len);
+		tlv_encode(&req_iter, &data_record);
+
+		psa_crypto_client_instance.rpc_status =
+			rpc_caller_invoke(psa_crypto_client_instance.caller, call_handle,
+				TS_CRYPTO_OPCODE_KEY_DERIVATION_KEY_AGREEMENT, &opstatus, &resp_buf, &resp_len);
+
+		if (psa_crypto_client_instance.rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+
+		rpc_caller_end(psa_crypto_client_instance.caller, call_handle);
+	}
+
+	return psa_status;
 }
 
-psa_status_t psa_key_derivation_output_bytes(
-	psa_key_derivation_operation_t *operation,
+psa_status_t psa_raw_key_agreement(psa_algorithm_t alg,
+	psa_key_id_t private_key,
+	const uint8_t *peer_key,
+	size_t peer_key_length,
 	uint8_t *output,
-	size_t output_length)
+	size_t output_size,
+	size_t *output_length)
 {
-	return PSA_ERROR_NOT_SUPPORTED;
-}
+	psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+	struct ts_crypto_raw_key_agreement_in req_msg;
+	size_t req_fixed_len = sizeof(struct ts_crypto_raw_key_agreement_in);
+	size_t req_len = req_fixed_len;
 
-psa_status_t psa_key_derivation_output_key(
-	const psa_key_attributes_t *attributes,
-	psa_key_derivation_operation_t *operation,
-	psa_key_id_t *key)
-{
-	return PSA_ERROR_NOT_SUPPORTED;
-}
+	req_msg.alg = alg;
+	req_msg.private_key_id = private_key;
 
-psa_status_t psa_key_derivation_abort(
-	psa_key_derivation_operation_t *operation)
-{
-	return PSA_ERROR_NOT_SUPPORTED;
+	/* Mandatory input data parameter */
+	struct tlv_record data_record;
+	data_record.tag = TS_CRYPTO_RAW_KEY_AGREEMENT_IN_TAG_PEER_KEY;
+	data_record.length = peer_key_length;
+	data_record.value = peer_key;
+	req_len += tlv_required_space(data_record.length);
+
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
+
+	call_handle = rpc_caller_begin(psa_crypto_client_instance.caller, &req_buf, req_len);
+
+	if (call_handle) {
+
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
+		struct tlv_iterator req_iter;
+
+		memcpy(req_buf, &req_msg, req_fixed_len);
+
+		tlv_iterator_begin(&req_iter, &req_buf[req_fixed_len], req_len - req_fixed_len);
+		tlv_encode(&req_iter, &data_record);
+
+		psa_crypto_client_instance.rpc_status =
+			rpc_caller_invoke(psa_crypto_client_instance.caller, call_handle,
+				TS_CRYPTO_OPCODE_KEY_DERIVATION_RAW_KEY_AGREEMENT, &opstatus, &resp_buf, &resp_len);
+
+		if (psa_crypto_client_instance.rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+			psa_status = opstatus;
+
+			if (psa_status == PSA_SUCCESS) {
+
+				struct tlv_const_iterator resp_iter;
+				struct tlv_record decoded_record;
+				tlv_const_iterator_begin(&resp_iter, resp_buf, resp_len);
+
+				if (tlv_find_decode(&resp_iter,
+					TS_CRYPTO_RAW_KEY_AGREEMENT_OUT_TAG_OUTPUT, &decoded_record)) {
+
+					if (decoded_record.length <= output_size) {
+
+						memcpy(output, decoded_record.value, decoded_record.length);
+						*output_length = decoded_record.length;
+					}
+					else {
+						/* Insufficient buffer space */
+						psa_status = PSA_ERROR_INVALID_ARGUMENT;
+					}
+				}
+				else {
+					/* Mandatory response parameter missing */
+					psa_status = PSA_ERROR_GENERIC_ERROR;
+				}
+			}
+		}
+
+		rpc_caller_end(psa_crypto_client_instance.caller, call_handle);
+	}
+
+	return psa_status;
 }
diff --git a/components/service/crypto/factory/full/crypto_provider_factory.c b/components/service/crypto/factory/full/crypto_provider_factory.c
index 1e1d902..af130aa 100644
--- a/components/service/crypto/factory/full/crypto_provider_factory.c
+++ b/components/service/crypto/factory/full/crypto_provider_factory.c
@@ -13,6 +13,8 @@
 #include <service/crypto/provider/extension/hash/serializer/packed-c/packedc_hash_provider_serializer.h>
 #include <service/crypto/provider/extension/cipher/cipher_provider.h>
 #include <service/crypto/provider/extension/cipher/serializer/packed-c/packedc_cipher_provider_serializer.h>
+#include <service/crypto/provider/extension/key_derivation/key_derivation_provider.h>
+#include <service/crypto/provider/extension/key_derivation/serializer/packed-c/packedc_key_derivation_provider_serializer.h>
 
 /**
  * A crypto provider factory that constucts a full-featured
@@ -26,35 +28,46 @@
 	struct crypto_provider crypto_provider;
 	struct hash_provider hash_provider;
 	struct cipher_provider cipher_provider;
+	struct key_derivation_provider key_derivation_provider;
 
 } instance;
 
 struct crypto_provider *crypto_provider_factory_create(void)
 {
-	/* Initialize the base crypto provider */
+	/* Initialize the base crypto provider -----------------------*/
 	crypto_provider_init(&instance.crypto_provider);
 
 	crypto_provider_register_serializer(&instance.crypto_provider,
 		TS_RPC_ENCODING_PROTOBUF, pb_crypto_provider_serializer_instance());
-
 	crypto_provider_register_serializer(&instance.crypto_provider,
 		TS_RPC_ENCODING_PACKED_C, packedc_crypto_provider_serializer_instance());
 
-	/* Extend with hash operations */
+	/* Extend with hash operations ---------------------------------*/
 	hash_provider_init(&instance.hash_provider);
 
 	hash_provider_register_serializer(&instance.hash_provider,
 		TS_RPC_ENCODING_PACKED_C, packedc_hash_provider_serializer_instance());
 
-	crypto_provider_extend(&instance.crypto_provider, &instance.hash_provider.base_provider);
+	crypto_provider_extend(&instance.crypto_provider,
+		&instance.hash_provider.base_provider);
 
-	/* Extend with symmetric cipher operations */
+	/* Extend with symmetric cipher operations --------------------*/
 	cipher_provider_init(&instance.cipher_provider);
 
 	cipher_provider_register_serializer(&instance.cipher_provider,
 		TS_RPC_ENCODING_PACKED_C, packedc_cipher_provider_serializer_instance());
 
-	crypto_provider_extend(&instance.crypto_provider, &instance.cipher_provider.base_provider);
+	crypto_provider_extend(&instance.crypto_provider,
+		&instance.cipher_provider.base_provider);
+
+	/* Extend with key derivation operations ----------------------*/
+	key_derivation_provider_init(&instance.key_derivation_provider);
+
+	key_derivation_provider_register_serializer(&instance.key_derivation_provider,
+		TS_RPC_ENCODING_PACKED_C, packedc_key_derivation_provider_serializer_instance());
+
+	crypto_provider_extend(&instance.crypto_provider,
+		&instance.key_derivation_provider.base_provider);
 
 	return &instance.crypto_provider;
 }
diff --git a/components/service/crypto/provider/crypto_context_pool.h b/components/service/crypto/provider/crypto_context_pool.h
index 8d7e564..e58d88b 100644
--- a/components/service/crypto/provider/crypto_context_pool.h
+++ b/components/service/crypto/provider/crypto_context_pool.h
@@ -34,7 +34,8 @@
 	CRYPTO_CONTEXT_OP_ID_NONE,
 	CRYPTO_CONTEXT_OP_ID_HASH,
 	CRYPTO_CONTEXT_OP_ID_MAC,
-	CRYPTO_CONTEXT_OP_ID_CIPHER
+	CRYPTO_CONTEXT_OP_ID_CIPHER,
+	CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION
 };
 
 /**
@@ -50,9 +51,10 @@
 
 	union context_variant
 	{
-		struct psa_hash_operation_s hash;
-		struct psa_mac_operation_s mac;
-		struct psa_cipher_operation_s cipher;
+		psa_hash_operation_t hash;
+		psa_mac_operation_t mac;
+		psa_cipher_operation_t cipher;
+		psa_key_derivation_operation_t key_derivation;
 	} op;
 };
 
diff --git a/components/service/crypto/provider/extension/key_derivation/component.cmake b/components/service/crypto/provider/extension/key_derivation/component.cmake
new file mode 100644
index 0000000..2b9970e
--- /dev/null
+++ b/components/service/crypto/provider/extension/key_derivation/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}/key_derivation_provider.c"
+	)
diff --git a/components/service/crypto/provider/extension/key_derivation/key_derivation_provider.c b/components/service/crypto/provider/extension/key_derivation/key_derivation_provider.c
new file mode 100644
index 0000000..b35712b
--- /dev/null
+++ b/components/service/crypto/provider/extension/key_derivation/key_derivation_provider.c
@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 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/extension/key_derivation/key_derivation_provider.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <psa/crypto.h>
+
+/* Service request handlers */
+static rpc_status_t key_derivation_setup_handler(void *context, struct call_req* req);
+static rpc_status_t key_derivation_get_capacity_handler(void *context, struct call_req* req);
+static rpc_status_t key_derivation_set_capacity_handler(void *context, struct call_req* req);
+static rpc_status_t key_derivation_input_bytes_handler(void *context, struct call_req* req);
+static rpc_status_t key_derivation_input_key_handler(void *context, struct call_req* req);
+static rpc_status_t key_derivation_output_bytes_handler(void *context, struct call_req* req);
+static rpc_status_t key_derivation_output_key_handler(void *context, struct call_req* req);
+static rpc_status_t key_derivation_abort_handler(void *context, struct call_req* req);
+static rpc_status_t key_derivation_key_agreement_handler(void *context, struct call_req* req);
+static rpc_status_t key_derivation_raw_key_agreement_handler(void *context, struct call_req* req);
+
+/* Handler mapping table for service */
+static const struct service_handler handler_table[] = {
+	{TS_CRYPTO_OPCODE_KEY_DERIVATION_SETUP,				key_derivation_setup_handler},
+	{TS_CRYPTO_OPCODE_KEY_DERIVATION_GET_CAPACITY,		key_derivation_get_capacity_handler},
+	{TS_CRYPTO_OPCODE_KEY_DERIVATION_SET_CAPACITY,		key_derivation_set_capacity_handler},
+	{TS_CRYPTO_OPCODE_KEY_DERIVATION_INPUT_BYTES,		key_derivation_input_bytes_handler},
+	{TS_CRYPTO_OPCODE_KEY_DERIVATION_INPUT_KEY,			key_derivation_input_key_handler},
+	{TS_CRYPTO_OPCODE_KEY_DERIVATION_OUTPUT_BYTES,		key_derivation_output_bytes_handler},
+	{TS_CRYPTO_OPCODE_KEY_DERIVATION_OUTPUT_KEY,		key_derivation_output_key_handler},
+	{TS_CRYPTO_OPCODE_KEY_DERIVATION_ABORT,				key_derivation_abort_handler},
+	{TS_CRYPTO_OPCODE_KEY_DERIVATION_KEY_AGREEMENT,		key_derivation_key_agreement_handler},
+	{TS_CRYPTO_OPCODE_KEY_DERIVATION_RAW_KEY_AGREEMENT,	key_derivation_raw_key_agreement_handler}
+};
+
+void key_derivation_provider_init(struct key_derivation_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));
+}
+
+void key_derivation_provider_deinit(struct key_derivation_provider *context)
+{
+	crypto_context_pool_deinit(&context->context_pool);
+}
+
+void key_derivation_provider_register_serializer(struct key_derivation_provider *context,
+	unsigned int encoding, const struct key_derivation_provider_serializer *serializer)
+{
+	if (encoding < TS_RPC_ENCODING_LIMIT)
+		context->serializers[encoding] = serializer;
+}
+
+static const struct key_derivation_provider_serializer* get_serializer(void *context,
+	const struct call_req *req)
+{
+	struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
+	const struct key_derivation_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 key_derivation_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 key_derivation_provider_serializer *serializer = get_serializer(context, req);
+	struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
+
+	psa_algorithm_t alg;
+
+	if (serializer)
+		rpc_status = serializer->deserialize_key_derivation_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_KEY_DERIVATION, call_req_get_caller_id(req),
+				&op_handle);
+
+		if (crypto_context) {
+
+			psa_status_t psa_status;
+
+			crypto_context->op.key_derivation = psa_key_derivation_operation_init();
+			psa_status = psa_key_derivation_setup(&crypto_context->op.key_derivation, alg);
+
+			if (psa_status == PSA_SUCCESS) {
+
+				struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+				rpc_status = serializer->serialize_key_derivation_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 key_derivation_get_capacity_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 key_derivation_provider_serializer *serializer = get_serializer(context, req);
+	struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
+
+	uint32_t op_handle;
+
+	if (serializer)
+		rpc_status = serializer->deserialize_key_derivation_get_capacity_req(req_buf, &op_handle);
+
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+		psa_status_t psa_status = PSA_ERROR_BAD_STATE;
+
+		struct crypto_context *crypto_context =
+			crypto_context_pool_find(&this_instance->context_pool,
+				CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, call_req_get_caller_id(req),
+				op_handle);
+
+		if (crypto_context) {
+
+			size_t capacity;
+
+			psa_status = psa_key_derivation_get_capacity(&crypto_context->op.key_derivation,
+				&capacity);
+
+			if (psa_status == PSA_SUCCESS) {
+
+				struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+				rpc_status = serializer->serialize_key_derivation_get_capacity_resp(resp_buf,
+					capacity);
+			}
+		}
+
+		call_req_set_opstatus(req, psa_status);
+	}
+
+	return rpc_status;
+}
+
+static rpc_status_t key_derivation_set_capacity_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 key_derivation_provider_serializer *serializer = get_serializer(context, req);
+	struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
+
+	uint32_t op_handle;
+	size_t capacity;
+
+	if (serializer)
+		rpc_status = serializer->deserialize_key_derivation_set_capacity_req(req_buf,
+			&op_handle, &capacity);
+
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+		psa_status_t psa_status = PSA_ERROR_BAD_STATE;
+
+		struct crypto_context *crypto_context =
+			crypto_context_pool_find(&this_instance->context_pool,
+				CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, call_req_get_caller_id(req),
+				op_handle);
+
+		if (crypto_context) {
+
+			psa_status = psa_key_derivation_set_capacity(&crypto_context->op.key_derivation,
+				capacity);
+		}
+
+		call_req_set_opstatus(req, psa_status);
+	}
+
+	return rpc_status;
+}
+
+static rpc_status_t key_derivation_input_bytes_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 key_derivation_provider_serializer *serializer = get_serializer(context, req);
+	struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
+
+	uint32_t op_handle;
+	psa_key_derivation_step_t step;
+	const uint8_t *data;
+	size_t data_len;
+
+	if (serializer)
+		rpc_status = serializer->deserialize_key_derivation_input_bytes_req(req_buf,
+			&op_handle, &step, &data, &data_len);
+
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+		psa_status_t psa_status = PSA_ERROR_BAD_STATE;
+
+		struct crypto_context *crypto_context =
+			crypto_context_pool_find(&this_instance->context_pool,
+				CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, call_req_get_caller_id(req),
+				op_handle);
+
+		if (crypto_context) {
+
+			psa_status = psa_key_derivation_input_bytes(&crypto_context->op.key_derivation,
+				step, data, data_len);
+		}
+
+		call_req_set_opstatus(req, psa_status);
+	}
+
+	return rpc_status;
+}
+
+static rpc_status_t key_derivation_input_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 key_derivation_provider_serializer *serializer = get_serializer(context, req);
+	struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
+
+	uint32_t op_handle;
+	psa_key_derivation_step_t step;
+	psa_key_id_t key_id;
+
+	if (serializer)
+		rpc_status = serializer->deserialize_key_derivation_input_key_req(req_buf,
+			&op_handle, &step, &key_id);
+
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+		psa_status_t psa_status = PSA_ERROR_BAD_STATE;
+
+		struct crypto_context *crypto_context =
+			crypto_context_pool_find(&this_instance->context_pool,
+				CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, call_req_get_caller_id(req),
+				op_handle);
+
+		if (crypto_context) {
+
+			psa_status = psa_key_derivation_input_key(&crypto_context->op.key_derivation,
+				step, key_id);
+		}
+
+		call_req_set_opstatus(req, psa_status);
+	}
+
+	return rpc_status;
+}
+
+static rpc_status_t key_derivation_output_bytes_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 key_derivation_provider_serializer *serializer = get_serializer(context, req);
+	struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
+
+	uint32_t op_handle;
+	size_t output_len;
+
+	if (serializer)
+		rpc_status = serializer->deserialize_key_derivation_output_bytes_req(req_buf,
+			&op_handle, &output_len);
+
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+		psa_status_t psa_status = PSA_ERROR_BAD_STATE;
+
+		struct crypto_context *crypto_context =
+			crypto_context_pool_find(&this_instance->context_pool,
+				CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, call_req_get_caller_id(req),
+				op_handle);
+
+		if (crypto_context) {
+
+			uint8_t *output = malloc(output_len);
+
+			if (output) {
+
+				psa_status = psa_key_derivation_output_bytes(&crypto_context->op.key_derivation,
+					output, output_len);
+
+				if (psa_status == PSA_SUCCESS) {
+
+					struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+					rpc_status = serializer->serialize_key_derivation_output_bytes_resp(resp_buf,
+						output, output_len);
+				}
+
+				free(output);
+			}
+			else {
+
+				psa_status = PSA_ERROR_INSUFFICIENT_MEMORY;
+			}
+		}
+
+		call_req_set_opstatus(req, psa_status);
+	}
+
+	return rpc_status;
+}
+
+static rpc_status_t key_derivation_output_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 key_derivation_provider_serializer *serializer = get_serializer(context, req);
+	struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
+
+	uint32_t op_handle;
+	psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+	if (serializer)
+		rpc_status = serializer->deserialize_key_derivation_output_key_req(req_buf,
+			&op_handle, &attributes);
+
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+		psa_status_t psa_status = PSA_ERROR_BAD_STATE;
+
+		struct crypto_context *crypto_context =
+			crypto_context_pool_find(&this_instance->context_pool,
+				CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, call_req_get_caller_id(req),
+				op_handle);
+
+		if (crypto_context) {
+
+			psa_key_id_t key_id;
+
+			psa_status = psa_key_derivation_output_key(&attributes,
+				&crypto_context->op.key_derivation,
+				&key_id);
+
+			if (psa_status == PSA_SUCCESS) {
+
+				struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+				rpc_status = serializer->serialize_key_derivation_output_key_resp(resp_buf,
+					key_id);
+			}
+		}
+
+		call_req_set_opstatus(req, psa_status);
+	}
+
+	psa_reset_key_attributes(&attributes);
+
+	return rpc_status;
+}
+
+static rpc_status_t key_derivation_abort_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 key_derivation_provider_serializer *serializer = get_serializer(context, req);
+	struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
+
+	uint32_t op_handle;
+
+	if (serializer)
+		rpc_status = serializer->deserialize_key_derivation_abort_req(req_buf, &op_handle);
+
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+		/* Return success if operation is no longer active and
+		 * doesn't need aborting.
+		 */
+		psa_status_t psa_status = PSA_SUCCESS;
+
+		struct crypto_context *crypto_context =
+			crypto_context_pool_find(&this_instance->context_pool,
+				CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, call_req_get_caller_id(req),
+				op_handle);
+
+		if (crypto_context) {
+
+			psa_status = psa_key_derivation_abort(&crypto_context->op.key_derivation);
+			crypto_context_pool_free(&this_instance->context_pool, crypto_context);
+		}
+
+		call_req_set_opstatus(req, psa_status);
+	}
+
+	return rpc_status;
+}
+
+static rpc_status_t key_derivation_key_agreement_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 key_derivation_provider_serializer *serializer = get_serializer(context, req);
+	struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
+
+	uint32_t op_handle;
+	psa_key_derivation_step_t step;
+	psa_key_id_t private_key_id;
+	const uint8_t *peer_key;
+	size_t peer_key_len;
+
+	if (serializer)
+		rpc_status = serializer->deserialize_key_derivation_key_agreement_req(req_buf,
+			&op_handle, &step, &private_key_id, &peer_key, &peer_key_len);
+
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+		psa_status_t psa_status = PSA_ERROR_BAD_STATE;
+
+		struct crypto_context *crypto_context =
+			crypto_context_pool_find(&this_instance->context_pool,
+				CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, call_req_get_caller_id(req),
+				op_handle);
+
+		if (crypto_context) {
+
+			psa_status = psa_key_derivation_key_agreement(&crypto_context->op.key_derivation,
+				step, private_key_id, peer_key, peer_key_len);
+		}
+
+		call_req_set_opstatus(req, psa_status);
+	}
+
+	return rpc_status;
+}
+
+static rpc_status_t key_derivation_raw_key_agreement_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 key_derivation_provider_serializer *serializer = get_serializer(context, req);
+	struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
+
+	psa_algorithm_t alg;
+	psa_key_id_t private_key_id;
+	const uint8_t *peer_key;
+	size_t peer_key_len;
+
+	if (serializer)
+		rpc_status = serializer->deserialize_key_derivation_raw_key_agreement_req(req_buf,
+			&alg, &private_key_id, &peer_key, &peer_key_len);
+
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+		size_t output_len;
+		uint8_t output[PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE];
+
+		psa_status_t psa_status = psa_raw_key_agreement(
+			alg, private_key_id, peer_key, peer_key_len,
+			output, sizeof(output), &output_len);
+
+		if (psa_status == PSA_SUCCESS) {
+
+			struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+			rpc_status = serializer->serialize_key_derivation_raw_key_agreement_resp(resp_buf,
+				output, output_len);
+		}
+
+		call_req_set_opstatus(req, psa_status);
+	}
+
+	return rpc_status;
+}
diff --git a/components/service/crypto/provider/extension/key_derivation/key_derivation_provider.h b/components/service/crypto/provider/extension/key_derivation/key_derivation_provider.h
new file mode 100644
index 0000000..86e6b7b
--- /dev/null
+++ b/components/service/crypto/provider/extension/key_derivation/key_derivation_provider.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef KEY_DERIVATION_PROVIDER_H
+#define KEY_DERIVATION_PROVIDER_H
+
+#include <rpc/common/endpoint/rpc_interface.h>
+#include <service/common/provider/service_provider.h>
+#include <service/crypto/provider/extension/key_derivation/serializer/key_derivation_provider_serializer.h>
+#include <service/crypto/provider/crypto_context_pool.h>
+#include <protocols/rpc/common/packed-c/encoding.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A service provider that can be used to add key_derivation operations to the base
+ * crypto provider.
+ */
+struct key_derivation_provider
+{
+	struct service_provider base_provider;
+	struct crypto_context_pool context_pool;
+	const struct key_derivation_provider_serializer *serializers[TS_RPC_ENCODING_LIMIT];
+};
+
+/*
+ * Initializes an instance of the key_derivation service provider.
+ */
+void key_derivation_provider_init(struct key_derivation_provider *context);
+
+/*
+ * When operation of the provider is no longer required, this function
+ * frees any resource used by the previously initialized provider instance.
+ */
+void key_derivation_provider_deinit(struct key_derivation_provider *context);
+
+/*
+ * Register a serializer for supportng a particular parameter encoding.
+ */
+void key_derivation_provider_register_serializer(struct key_derivation_provider *context,
+	unsigned int encoding, const struct key_derivation_provider_serializer *serializer);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* KEY_DERIVATION_PROVIDER_H */
diff --git a/components/service/crypto/provider/extension/key_derivation/serializer/key_derivation_provider_serializer.h b/components/service/crypto/provider/extension/key_derivation/serializer/key_derivation_provider_serializer.h
new file mode 100644
index 0000000..4bbeb41
--- /dev/null
+++ b/components/service/crypto/provider/extension/key_derivation/serializer/key_derivation_provider_serializer.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef KEY_DERIVATION_PROVIDER_SERIALIZER_H
+#define KEY_DERIVATION_PROVIDER_SERIALIZER_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <psa/crypto.h>
+#include <rpc/common/endpoint/rpc_interface.h>
+
+/* Provides a common interface for parameter serialization operations
+ * for the key_derivation service provider.
+ */
+struct key_derivation_provider_serializer {
+
+	/* Operation: key_derivation_setup */
+	rpc_status_t (*deserialize_key_derivation_setup_req)(const struct call_param_buf *req_buf,
+		psa_algorithm_t *alg);
+
+	rpc_status_t (*serialize_key_derivation_setup_resp)(struct call_param_buf *resp_buf,
+		uint32_t op_handle);
+
+	/* Operation: key_derivation_get_capacity */
+	rpc_status_t (*deserialize_key_derivation_get_capacity_req)(const struct call_param_buf *req_buf,
+		uint32_t *op_handle);
+
+	rpc_status_t (*serialize_key_derivation_get_capacity_resp)(struct call_param_buf *resp_buf,
+		size_t capacity);
+
+	/* Operation: key_derivation_set_capacity */
+	rpc_status_t (*deserialize_key_derivation_set_capacity_req)(const struct call_param_buf *req_buf,
+		uint32_t *op_handle,
+		size_t *capacity);
+
+	/* Operation: key_derivation_input_bytes */
+	rpc_status_t (*deserialize_key_derivation_input_bytes_req)(const struct call_param_buf *req_buf,
+		uint32_t *op_handle,
+		psa_key_derivation_step_t *step,
+		const uint8_t **data, size_t *data_len);
+
+	/* Operation: key_derivation_input_key */
+	rpc_status_t (*deserialize_key_derivation_input_key_req)(const struct call_param_buf *req_buf,
+		uint32_t *op_handle,
+		psa_key_derivation_step_t *step,
+		psa_key_id_t *key_id);
+
+	/* Operation: key_derivation_output_bytes */
+	rpc_status_t (*deserialize_key_derivation_output_bytes_req)(const struct call_param_buf *req_buf,
+		uint32_t *op_handle,
+		size_t *output_len);
+
+	rpc_status_t (*serialize_key_derivation_output_bytes_resp)(struct call_param_buf *resp_buf,
+		const uint8_t *data, size_t data_len);
+
+	/* Operation: key_derivation_output_key */
+	rpc_status_t (*deserialize_key_derivation_output_key_req)(const struct call_param_buf *req_buf,
+		uint32_t *op_handle,
+		psa_key_attributes_t *attributes);
+
+	rpc_status_t (*serialize_key_derivation_output_key_resp)(struct call_param_buf *resp_buf,
+		psa_key_id_t key_id);
+
+	/* Operation: key_derivation_abort */
+	rpc_status_t (*deserialize_key_derivation_abort_req)(const struct call_param_buf *req_buf,
+		uint32_t *op_handle);
+
+	/* Operation: key_derivation_key_agreement */
+	rpc_status_t (*deserialize_key_derivation_key_agreement_req)(const struct call_param_buf *req_buf,
+		uint32_t *op_handle,
+		psa_key_derivation_step_t *step,
+		psa_key_id_t *private_key_id,
+		const uint8_t **peer_key, size_t *peer_key_len);
+
+	/* Operation: key_derivation_raw_key_agreement */
+	rpc_status_t (*deserialize_key_derivation_raw_key_agreement_req)(const struct call_param_buf *req_buf,
+		psa_algorithm_t *alg,
+		psa_key_id_t *private_key_id,
+		const uint8_t **peer_key, size_t *peer_key_len);
+
+	rpc_status_t (*serialize_key_derivation_raw_key_agreement_resp)(struct call_param_buf *resp_buf,
+		const uint8_t *output, size_t output_len);
+};
+
+#endif /* KEY_DERIVATION_PROVIDER_SERIALIZER_H */
diff --git a/components/service/crypto/provider/extension/key_derivation/serializer/packed-c/component.cmake b/components/service/crypto/provider/extension/key_derivation/serializer/packed-c/component.cmake
new file mode 100644
index 0000000..9cea7a0
--- /dev/null
+++ b/components/service/crypto/provider/extension/key_derivation/serializer/packed-c/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}/packedc_key_derivation_provider_serializer.c"
+	)
diff --git a/components/service/crypto/provider/extension/key_derivation/serializer/packed-c/packedc_key_derivation_provider_serializer.c b/components/service/crypto/provider/extension/key_derivation/serializer/packed-c/packedc_key_derivation_provider_serializer.c
new file mode 100644
index 0000000..0d92f50
--- /dev/null
+++ b/components/service/crypto/provider/extension/key_derivation/serializer/packed-c/packedc_key_derivation_provider_serializer.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <common/tlv/tlv.h>
+#include <psa/crypto.h>
+#include <protocols/service/crypto/packed-c/key_derivation.h>
+#include <service/crypto/provider/serializer/packed-c/packedc_key_attributes_translator.h>
+#include "packedc_key_derivation_provider_serializer.h"
+
+/* Operation: key_derivation_setup */
+static rpc_status_t deserialize_key_derivation_setup_req(
+	const struct call_param_buf *req_buf,
+	psa_algorithm_t *alg)
+{
+	rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+	struct ts_crypto_key_derivation_setup_in recv_msg;
+	size_t expected_fixed_len = sizeof(struct ts_crypto_key_derivation_setup_in);
+
+	if (expected_fixed_len <= req_buf->data_len) {
+
+		memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+		*alg = recv_msg.alg;
+		rpc_status = TS_RPC_CALL_ACCEPTED;
+	}
+
+	return rpc_status;
+}
+
+static rpc_status_t serialize_key_derivation_setup_resp(
+	struct call_param_buf *resp_buf,
+	uint32_t op_handle)
+{
+	rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+	struct ts_crypto_key_derivation_setup_out resp_msg;
+	size_t fixed_len = sizeof(struct ts_crypto_key_derivation_setup_out);
+
+	resp_msg.op_handle = op_handle;
+
+	if (fixed_len <= resp_buf->size) {
+
+		memcpy(resp_buf->data, &resp_msg, fixed_len);
+		resp_buf->data_len = fixed_len;
+		rpc_status = TS_RPC_CALL_ACCEPTED;
+	}
+
+	return rpc_status;
+}
+
+/* Operation: key_derivation_get_capacity */
+static rpc_status_t deserialize_key_derivation_get_capacity_req(
+	const struct call_param_buf *req_buf,
+	uint32_t *op_handle)
+{
+	rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+	struct ts_crypto_key_derivation_get_capacity_in recv_msg;
+	size_t expected_fixed_len = sizeof(struct ts_crypto_key_derivation_get_capacity_in);
+
+	if (expected_fixed_len <= req_buf->data_len) {
+
+		memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+		*op_handle = recv_msg.op_handle;
+		rpc_status = TS_RPC_CALL_ACCEPTED;
+	}
+
+	return rpc_status;
+}
+
+static rpc_status_t serialize_key_derivation_get_capacity_resp(
+	struct call_param_buf *resp_buf,
+	size_t capacity)
+{
+	rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+	struct ts_crypto_key_derivation_get_capacity_out resp_msg;
+	size_t fixed_len = sizeof(struct ts_crypto_key_derivation_get_capacity_out);
+
+	resp_msg.capacity = capacity;
+
+	if (fixed_len <= resp_buf->size) {
+
+		memcpy(resp_buf->data, &resp_msg, fixed_len);
+		resp_buf->data_len = fixed_len;
+		rpc_status = TS_RPC_CALL_ACCEPTED;
+	}
+
+	return rpc_status;
+}
+
+/* Operation: key_derivation_set_capacity */
+static rpc_status_t deserialize_key_derivation_set_capacity_req(
+	const struct call_param_buf *req_buf,
+	uint32_t *op_handle,
+	size_t *capacity)
+{
+	rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+	struct ts_crypto_key_derivation_set_capacity_in recv_msg;
+	size_t expected_fixed_len = sizeof(struct ts_crypto_key_derivation_set_capacity_in);
+
+	if (expected_fixed_len <= req_buf->data_len) {
+
+		memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+		*op_handle = recv_msg.op_handle;
+		*capacity = recv_msg.capacity;
+		rpc_status = TS_RPC_CALL_ACCEPTED;
+	}
+
+	return rpc_status;
+}
+
+/* Operation: key_derivation_input_bytes */
+static rpc_status_t deserialize_key_derivation_input_bytes_req(
+	const struct call_param_buf *req_buf,
+	uint32_t *op_handle,
+	psa_key_derivation_step_t *step,
+	const uint8_t **data, size_t *data_len)
+{
+	rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+	struct ts_crypto_key_derivation_input_bytes_in recv_msg;
+	size_t expected_fixed_len = sizeof(struct ts_crypto_key_derivation_input_bytes_in);
+
+	if (expected_fixed_len <= req_buf->data_len) {
+
+		struct tlv_const_iterator req_iter;
+		struct tlv_record decoded_record;
+
+		rpc_status = TS_RPC_CALL_ACCEPTED;
+
+		memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+
+		*op_handle = recv_msg.op_handle;
+		*step = recv_msg.step;
+
+		tlv_const_iterator_begin(&req_iter,
+			(uint8_t*)req_buf->data + expected_fixed_len,
+			req_buf->data_len - expected_fixed_len);
+
+		if (tlv_find_decode(&req_iter,
+			TS_CRYPTO_KEY_DERIVATION_INPUT_BYTES_IN_TAG_DATA, &decoded_record)) {
+
+			*data = decoded_record.value;
+			*data_len = decoded_record.length;
+		}
+		else {
+			/* Default to a zero length data */
+			*data_len = 0;
+		}
+	}
+
+	return rpc_status;
+}
+
+/* Operation: key_derivation_input_key */
+static rpc_status_t deserialize_key_derivation_input_key_req(
+	const struct call_param_buf *req_buf,
+	uint32_t *op_handle,
+	psa_key_derivation_step_t *step,
+	psa_key_id_t *key_id)
+{
+	rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+	struct ts_crypto_key_derivation_input_key_in recv_msg;
+	size_t expected_fixed_len = sizeof(struct ts_crypto_key_derivation_input_key_in);
+
+	if (expected_fixed_len <= req_buf->data_len) {
+
+		memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+		*op_handle = recv_msg.op_handle;
+		*step = recv_msg.step;
+		*key_id = recv_msg.key_id;
+		rpc_status = TS_RPC_CALL_ACCEPTED;
+	}
+
+	return rpc_status;
+}
+
+/* Operation: key_derivation_output_bytes */
+static rpc_status_t deserialize_key_derivation_output_bytes_req(
+	const struct call_param_buf *req_buf,
+	uint32_t *op_handle,
+	size_t *output_len)
+{
+	rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+	struct ts_crypto_key_derivation_output_bytes_in recv_msg;
+	size_t expected_fixed_len = sizeof(struct ts_crypto_key_derivation_output_bytes_in);
+
+	if (expected_fixed_len <= req_buf->data_len) {
+
+		memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+		*op_handle = recv_msg.op_handle;
+		*output_len = recv_msg.output_len;
+		rpc_status = TS_RPC_CALL_ACCEPTED;
+	}
+
+	return rpc_status;
+}
+
+static rpc_status_t serialize_key_derivation_output_bytes_resp(
+	struct call_param_buf *resp_buf,
+	const uint8_t *data, size_t data_len)
+{
+	rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+	struct tlv_iterator resp_iter;
+
+	struct tlv_record out_record;
+	out_record.tag = TS_CRYPTO_KEY_DERIVATION_OUTPUT_BYTES_OUT_TAG_DATA;
+	out_record.length = data_len;
+	out_record.value = data;
+
+	tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
+
+	if (tlv_encode(&resp_iter, &out_record)) {
+
+		resp_buf->data_len = tlv_required_space(data_len);
+		rpc_status = TS_RPC_CALL_ACCEPTED;
+	}
+
+	return rpc_status;
+}
+
+/* Operation: key_derivation_output_key */
+static rpc_status_t deserialize_key_derivation_output_key_req(
+	const struct call_param_buf *req_buf,
+	uint32_t *op_handle,
+	psa_key_attributes_t *attributes)
+{
+	rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+	struct ts_crypto_key_derivation_output_key_in recv_msg;
+	size_t expected_fixed_len = sizeof(struct ts_crypto_key_derivation_output_key_in);
+
+	if (expected_fixed_len <= req_buf->data_len) {
+
+		memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+
+		*op_handle = recv_msg.op_handle;
+		packedc_crypto_provider_translate_key_attributes_from_proto(attributes,
+			&recv_msg.attributes);
+
+		rpc_status = TS_RPC_CALL_ACCEPTED;
+	}
+
+	return rpc_status;
+}
+
+static rpc_status_t serialize_key_derivation_output_key_resp(
+	struct call_param_buf *resp_buf,
+	psa_key_id_t key_id)
+{
+	rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+	struct ts_crypto_key_derivation_output_key_out resp_msg;
+	size_t fixed_len = sizeof(struct ts_crypto_key_derivation_output_key_out);
+
+	resp_msg.key_id = key_id;
+
+	if (fixed_len <= resp_buf->size) {
+
+		memcpy(resp_buf->data, &resp_msg, fixed_len);
+		resp_buf->data_len = fixed_len;
+		rpc_status = TS_RPC_CALL_ACCEPTED;
+	}
+
+	return rpc_status;
+}
+
+/* Operation: key_derivation_abort */
+static rpc_status_t deserialize_key_derivation_abort_req(
+	const struct call_param_buf *req_buf,
+	uint32_t *op_handle)
+{
+	rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+	struct ts_crypto_key_derivation_abort_in recv_msg;
+	size_t expected_fixed_len = sizeof(struct ts_crypto_key_derivation_abort_in);
+
+	if (expected_fixed_len <= req_buf->data_len) {
+
+		memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+		*op_handle = recv_msg.op_handle;
+		rpc_status = TS_RPC_CALL_ACCEPTED;
+	}
+
+	return rpc_status;
+}
+
+/* Operation: key_derivation_key_agreement */
+static rpc_status_t deserialize_key_derivation_key_agreement_req(
+	const struct call_param_buf *req_buf,
+	uint32_t *op_handle,
+	psa_key_derivation_step_t *step,
+	psa_key_id_t *private_key_id,
+	const uint8_t **peer_key, size_t *peer_key_len)
+{
+	rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+	struct ts_crypto_key_derivation_key_agreement_in recv_msg;
+	size_t expected_fixed_len = sizeof(struct ts_crypto_key_derivation_key_agreement_in);
+
+	if (expected_fixed_len <= req_buf->data_len) {
+
+		struct tlv_const_iterator req_iter;
+		struct tlv_record decoded_record;
+
+		rpc_status = TS_RPC_CALL_ACCEPTED;
+
+		memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+
+		*op_handle = recv_msg.op_handle;
+		*step = recv_msg.step;
+		*private_key_id = recv_msg.private_key_id;
+
+		tlv_const_iterator_begin(&req_iter,
+			(uint8_t*)req_buf->data + expected_fixed_len,
+			req_buf->data_len - expected_fixed_len);
+
+		if (tlv_find_decode(&req_iter,
+			TS_CRYPTO_KEY_DERIVATION_KEY_AGREEMENT_IN_TAG_PEER_KEY, &decoded_record)) {
+
+			*peer_key = decoded_record.value;
+			*peer_key_len = decoded_record.length;
+		}
+		else {
+			/* Default to a zero length data */
+			*peer_key_len = 0;
+		}
+	}
+
+	return rpc_status;
+}
+
+/* Operation: key_derivation_raw_key_agreement */
+static rpc_status_t deserialize_key_derivation_raw_key_agreement_req(
+	const struct call_param_buf *req_buf,
+	psa_algorithm_t *alg,
+	psa_key_id_t *private_key_id,
+	const uint8_t **peer_key, size_t *peer_key_len)
+{
+	rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+	struct ts_crypto_raw_key_agreement_in recv_msg;
+	size_t expected_fixed_len = sizeof(struct ts_crypto_raw_key_agreement_in);
+
+	if (expected_fixed_len <= req_buf->data_len) {
+
+		struct tlv_const_iterator req_iter;
+		struct tlv_record decoded_record;
+
+		rpc_status = TS_RPC_CALL_ACCEPTED;
+
+		memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+
+		*alg = recv_msg.alg;
+		*private_key_id = recv_msg.private_key_id;
+
+		tlv_const_iterator_begin(&req_iter,
+			(uint8_t*)req_buf->data + expected_fixed_len,
+			req_buf->data_len - expected_fixed_len);
+
+		if (tlv_find_decode(&req_iter,
+			TS_CRYPTO_RAW_KEY_AGREEMENT_IN_TAG_PEER_KEY, &decoded_record)) {
+
+			*peer_key = decoded_record.value;
+			*peer_key_len = decoded_record.length;
+		}
+		else {
+			/* Default to a zero length data */
+			*peer_key_len = 0;
+		}
+	}
+
+	return rpc_status;
+}
+
+static rpc_status_t serialize_key_derivation_raw_key_agreement_resp(
+	struct call_param_buf *resp_buf,
+	const uint8_t *output, size_t output_len)
+{
+	rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+	struct tlv_iterator resp_iter;
+
+	struct tlv_record out_record;
+	out_record.tag = TS_CRYPTO_RAW_KEY_AGREEMENT_OUT_TAG_OUTPUT;
+	out_record.length = output_len;
+	out_record.value = output;
+
+	tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
+
+	if (tlv_encode(&resp_iter, &out_record)) {
+
+		resp_buf->data_len = tlv_required_space(output_len);
+		rpc_status = TS_RPC_CALL_ACCEPTED;
+	}
+
+	return rpc_status;
+}
+
+/* Singleton method to provide access to the serializer instance */
+const struct key_derivation_provider_serializer
+	*packedc_key_derivation_provider_serializer_instance(void)
+{
+	static const struct key_derivation_provider_serializer instance = {
+		deserialize_key_derivation_setup_req,
+		serialize_key_derivation_setup_resp,
+		deserialize_key_derivation_get_capacity_req,
+		serialize_key_derivation_get_capacity_resp,
+		deserialize_key_derivation_set_capacity_req,
+		deserialize_key_derivation_input_bytes_req,
+		deserialize_key_derivation_input_key_req,
+		deserialize_key_derivation_output_bytes_req,
+		serialize_key_derivation_output_bytes_resp,
+		deserialize_key_derivation_output_key_req,
+		serialize_key_derivation_output_key_resp,
+		deserialize_key_derivation_abort_req,
+		deserialize_key_derivation_key_agreement_req,
+		deserialize_key_derivation_raw_key_agreement_req,
+		serialize_key_derivation_raw_key_agreement_resp
+	};
+
+	return &instance;
+}
diff --git a/components/service/crypto/provider/extension/key_derivation/serializer/packed-c/packedc_key_derivation_provider_serializer.h b/components/service/crypto/provider/extension/key_derivation/serializer/packed-c/packedc_key_derivation_provider_serializer.h
new file mode 100644
index 0000000..a6f2b9a
--- /dev/null
+++ b/components/service/crypto/provider/extension/key_derivation/serializer/packed-c/packedc_key_derivation_provider_serializer.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PACKEDC_KEY_DERIVATION_PROVIDER_SERIALIZER_H
+#define PACKEDC_KEY_DERIVATION_PROVIDER_SERIALIZER_H
+
+#include <service/crypto/provider/extension/key_derivation/serializer/key_derivation_provider_serializer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Singleton method to provide access to the packed-c serializer
+ * for the key_derivation service provider.
+ */
+const struct key_derivation_provider_serializer
+    *packedc_key_derivation_provider_serializer_instance(void);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PACKEDC_KEY_DERIVATION_PROVIDER_SERIALIZER_H */
diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index 7d12298..25ef2dc 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -73,6 +73,8 @@
 		"components/service/crypto/provider/extension/hash/serializer/packed-c"
 		"components/service/crypto/provider/extension/cipher"
 		"components/service/crypto/provider/extension/cipher/serializer/packed-c"
+		"components/service/crypto/provider/extension/key_derivation"
+		"components/service/crypto/provider/extension/key_derivation/serializer/packed-c"
 		"components/service/crypto/provider/test"
 		"components/service/crypto/backend/mbedcrypto"
 		"components/service/crypto/factory/full"
diff --git a/deployments/crypto/opteesp/CMakeLists.txt b/deployments/crypto/opteesp/CMakeLists.txt
index 23e2159..dab9ae1 100644
--- a/deployments/crypto/opteesp/CMakeLists.txt
+++ b/deployments/crypto/opteesp/CMakeLists.txt
@@ -52,6 +52,8 @@
 		"components/service/crypto/provider/extension/hash/serializer/packed-c"
 		"components/service/crypto/provider/extension/cipher"
 		"components/service/crypto/provider/extension/cipher/serializer/packed-c"
+		"components/service/crypto/provider/extension/key_derivation"
+		"components/service/crypto/provider/extension/key_derivation/serializer/packed-c"
 		"components/service/crypto/factory/full"
 		"components/service/crypto/backend/mbedcrypto"
 		"components/service/crypto/backend/mbedcrypto/trng_adapter/platform"
diff --git a/deployments/libts/linux-pc/CMakeLists.txt b/deployments/libts/linux-pc/CMakeLists.txt
index f8e259c..eb56006 100644
--- a/deployments/libts/linux-pc/CMakeLists.txt
+++ b/deployments/libts/linux-pc/CMakeLists.txt
@@ -61,6 +61,8 @@
 		"components/service/crypto/provider/extension/hash/serializer/packed-c"
 		"components/service/crypto/provider/extension/cipher"
 		"components/service/crypto/provider/extension/cipher/serializer/packed-c"
+		"components/service/crypto/provider/extension/key_derivation"
+		"components/service/crypto/provider/extension/key_derivation/serializer/packed-c"
 		"components/service/crypto/factory/full"
 		"components/service/crypto/backend/mbedcrypto"
 		"components/service/crypto/backend/mbedcrypto/trng_adapter/linux"
diff --git a/deployments/se-proxy/opteesp/CMakeLists.txt b/deployments/se-proxy/opteesp/CMakeLists.txt
index 988b1fc..f8975e7 100644
--- a/deployments/se-proxy/opteesp/CMakeLists.txt
+++ b/deployments/se-proxy/opteesp/CMakeLists.txt
@@ -64,6 +64,8 @@
 		"components/service/crypto/provider/extension/hash/serializer/packed-c"
 		"components/service/crypto/provider/extension/cipher"
 		"components/service/crypto/provider/extension/cipher/serializer/packed-c"
+		"components/service/crypto/provider/extension/key_derivation"
+		"components/service/crypto/provider/extension/key_derivation/serializer/packed-c"
 		"components/service/crypto/factory/full"
 		"components/service/secure_storage/include"
 		"components/service/secure_storage/frontend/secure_storage_provider"
diff --git a/protocols/service/crypto/packed-c/cipher.h b/protocols/service/crypto/packed-c/cipher.h
index 72cd427..48fb470 100644
--- a/protocols/service/crypto/packed-c/cipher.h
+++ b/protocols/service/crypto/packed-c/cipher.h
@@ -9,13 +9,10 @@
 #include <stdint.h>
 
 /**
- * Cipher operations on arbitrary sized data involve three operations,
- * a setup, called once, an update called 1..* times and a finish
- * to finalise theh hash operation.  Operations may be aborted
- * using the abort operation.
+ * Protocol definitions for symmetric cipher operations
+ * using the packed-c serialization.
  */
 
-
 /****************************************
  * cipher_setup operation definition (encrypt or decrypt)
  */
diff --git a/protocols/service/crypto/packed-c/hash.h b/protocols/service/crypto/packed-c/hash.h
index 36ed3f6..41abfe1 100644
--- a/protocols/service/crypto/packed-c/hash.h
+++ b/protocols/service/crypto/packed-c/hash.h
@@ -9,12 +9,10 @@
 #include <stdint.h>
 
 /**
- * Hash operations on arbitrary sized data involve three operations,
- * a setup, called once, an update called 1..* times and a finish
- * to finalise theh hash operation.
+ * Protocol definitions for hash operations
+ * using the packed-c serialization.
  */
 
-
 /****************************************
  * hash_setup operation definition
  */
diff --git a/protocols/service/crypto/packed-c/key_derivation.h b/protocols/service/crypto/packed-c/key_derivation.h
new file mode 100644
index 0000000..c778ebc
--- /dev/null
+++ b/protocols/service/crypto/packed-c/key_derivation.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TS_CRYPTO_KEY_DERIVATION_H
+#define TS_CRYPTO_KEY_DERIVATION_H
+
+#include <stdint.h>
+#include "key_attributes.h"
+
+/**
+ * Protocol definitions for key derivation operations
+ * using the packed-c serialization.
+ */
+
+
+/****************************************
+ * key_derivation_setup operation definition
+ */
+
+/* Mandatory fixed sized input parameters */
+struct __attribute__ ((__packed__)) ts_crypto_key_derivation_setup_in
+{
+  uint32_t alg;
+};
+
+/* Mandatory fixed sized output parameters */
+struct __attribute__ ((__packed__)) ts_crypto_key_derivation_setup_out
+{
+  uint32_t op_handle;
+};
+
+/****************************************
+ * key_derivation_get_capacity operation definition
+ */
+
+/* Mandatory fixed sized input parameters */
+struct __attribute__ ((__packed__)) ts_crypto_key_derivation_get_capacity_in
+{
+  uint32_t op_handle;
+};
+
+/* Mandatory fixed sized output parameters */
+struct __attribute__ ((__packed__)) ts_crypto_key_derivation_get_capacity_out
+{
+  uint32_t capacity;
+};
+
+/****************************************
+ * key_derivation_set_capacity operation definition
+ */
+
+/* Mandatory fixed sized input parameters */
+struct __attribute__ ((__packed__)) ts_crypto_key_derivation_set_capacity_in
+{
+  uint32_t op_handle;
+  uint32_t capacity;
+};
+
+/****************************************
+ * key_derivation_input_bytes operation definition
+ */
+
+/* Mandatory fixed sized input parameters */
+struct __attribute__ ((__packed__)) ts_crypto_key_derivation_input_bytes_in
+{
+  uint32_t op_handle;
+  uint32_t step;
+};
+
+/* Mandatory variable length input parameter tags */
+enum
+{
+    TS_CRYPTO_KEY_DERIVATION_INPUT_BYTES_IN_TAG_DATA  = 1
+};
+
+/****************************************
+ * key_derivation_input_key operation definition
+ */
+
+/* Mandatory fixed sized input parameters */
+struct __attribute__ ((__packed__)) ts_crypto_key_derivation_input_key_in
+{
+  uint32_t op_handle;
+  uint32_t step;
+  uint32_t key_id;
+};
+
+/****************************************
+ * key_derivation_output_bytes operation definition
+ */
+
+/* Mandatory fixed sized input parameters */
+struct __attribute__ ((__packed__)) ts_crypto_key_derivation_output_bytes_in
+{
+  uint32_t op_handle;
+  uint32_t output_len;
+};
+
+/* Mandatory variable length output parameter tags */
+enum
+{
+    TS_CRYPTO_KEY_DERIVATION_OUTPUT_BYTES_OUT_TAG_DATA  = 1
+};
+
+/****************************************
+ * key_derivation_output_key operation definition
+ */
+
+/* Mandatory fixed sized input parameters */
+struct __attribute__ ((__packed__)) ts_crypto_key_derivation_output_key_in
+{
+  uint32_t op_handle;
+  struct ts_crypto_key_attributes attributes;
+};
+
+/* Mandatory fixed sized output parameters */
+struct __attribute__ ((__packed__)) ts_crypto_key_derivation_output_key_out
+{
+  uint32_t key_id;
+};
+
+/****************************************
+ * key_derivation_abort operation definition
+ */
+
+/* Mandatory fixed sized input parameters */
+struct __attribute__ ((__packed__)) ts_crypto_key_derivation_abort_in
+{
+  uint32_t op_handle;
+};
+
+/****************************************
+ * key_derivation_key_agreement operation definition
+ */
+
+/* Mandatory fixed sized input parameters */
+struct __attribute__ ((__packed__)) ts_crypto_key_derivation_key_agreement_in
+{
+  uint32_t op_handle;
+  uint32_t step;
+  uint32_t private_key_id;
+};
+
+/* Mandatory variable length input parameter tags */
+enum
+{
+    TS_CRYPTO_KEY_DERIVATION_KEY_AGREEMENT_IN_TAG_PEER_KEY  = 1
+};
+
+/****************************************
+ * raw_key_agreement operation definition
+ */
+
+/* Mandatory fixed sized input parameters */
+struct __attribute__ ((__packed__)) ts_crypto_raw_key_agreement_in
+{
+  uint32_t alg;
+  uint32_t private_key_id;
+};
+
+/* Mandatory variable length input parameter tags */
+enum
+{
+    TS_CRYPTO_RAW_KEY_AGREEMENT_IN_TAG_PEER_KEY  = 1
+};
+
+/* Mandatory variable length output parameter tags */
+enum
+{
+    TS_CRYPTO_RAW_KEY_AGREEMENT_OUT_TAG_OUTPUT  = 1
+};
+
+#endif /* TS_CRYPTO_KEY_DERIVATION_H */
diff --git a/protocols/service/crypto/packed-c/opcodes.h b/protocols/service/crypto/packed-c/opcodes.h
index e06ab68..7ef5905 100644
--- a/protocols/service/crypto/packed-c/opcodes.h
+++ b/protocols/service/crypto/packed-c/opcodes.h
@@ -46,4 +46,17 @@
 #define TS_CRYPTO_OPCODE_CIPHER_FINISH          (TS_CRYPTO_OPCODE_CIPHER_BASE + 6)
 #define TS_CRYPTO_OPCODE_CIPHER_ABORT           (TS_CRYPTO_OPCODE_CIPHER_BASE + 7)
 
+/* Key derivation operations */
+#define TS_CRYPTO_OPCODE_KEY_DERIVATION_BASE                (0x0400)
+#define TS_CRYPTO_OPCODE_KEY_DERIVATION_SETUP               (TS_CRYPTO_OPCODE_KEY_DERIVATION_BASE + 1)
+#define TS_CRYPTO_OPCODE_KEY_DERIVATION_GET_CAPACITY        (TS_CRYPTO_OPCODE_KEY_DERIVATION_BASE + 2)
+#define TS_CRYPTO_OPCODE_KEY_DERIVATION_SET_CAPACITY        (TS_CRYPTO_OPCODE_KEY_DERIVATION_BASE + 3)
+#define TS_CRYPTO_OPCODE_KEY_DERIVATION_INPUT_BYTES         (TS_CRYPTO_OPCODE_KEY_DERIVATION_BASE + 4)
+#define TS_CRYPTO_OPCODE_KEY_DERIVATION_INPUT_KEY           (TS_CRYPTO_OPCODE_KEY_DERIVATION_BASE + 5)
+#define TS_CRYPTO_OPCODE_KEY_DERIVATION_OUTPUT_BYTES        (TS_CRYPTO_OPCODE_KEY_DERIVATION_BASE + 6)
+#define TS_CRYPTO_OPCODE_KEY_DERIVATION_OUTPUT_KEY          (TS_CRYPTO_OPCODE_KEY_DERIVATION_BASE + 7)
+#define TS_CRYPTO_OPCODE_KEY_DERIVATION_ABORT               (TS_CRYPTO_OPCODE_KEY_DERIVATION_BASE + 8)
+#define TS_CRYPTO_OPCODE_KEY_DERIVATION_KEY_AGREEMENT       (TS_CRYPTO_OPCODE_KEY_DERIVATION_BASE + 9)
+#define TS_CRYPTO_OPCODE_KEY_DERIVATION_RAW_KEY_AGREEMENT   (TS_CRYPTO_OPCODE_KEY_DERIVATION_BASE + 10)
+
 #endif /* TS_CRYPTO_OPCODES_H */