Add crypto support for symmetric cipher operations

Adds a sub-provider for symmetric cipher operations.

Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: Ic36195ae6eeb2fb81d06f83755fa400d219febc0
diff --git a/components/service/crypto/client/psa/psa_cipher.c b/components/service/crypto/client/psa/psa_cipher.c
index 955e747..6ebf1b5 100644
--- a/components/service/crypto/client/psa/psa_cipher.c
+++ b/components/service/crypto/client/psa/psa_cipher.c
@@ -10,20 +10,75 @@
 #include "psa_crypto_client.h"
 #include <protocols/rpc/common/packed-c/status.h>
 #include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/cipher.h>
 #include <common/tlv/tlv.h>
 
+static psa_status_t common_cipher_setup(psa_cipher_operation_t *operation,
+	psa_key_id_t key,
+	psa_algorithm_t alg,
+	uint32_t opcode)
+{
+	psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+	struct ts_crypto_cipher_setup_in req_msg;
+	size_t req_len = sizeof(struct ts_crypto_cipher_setup_in);
+
+	req_msg.key_id = key;
+	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,
+				opcode, &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_cipher_setup_out)) {
+
+					struct ts_crypto_cipher_setup_out resp_msg;
+					memcpy(&resp_msg, resp_buf, sizeof(struct ts_crypto_cipher_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_cipher_encrypt_setup(psa_cipher_operation_t *operation,
 	psa_key_id_t key,
 	psa_algorithm_t alg)
 {
-	return PSA_ERROR_NOT_SUPPORTED;
+	return common_cipher_setup(operation, key, alg, TS_CRYPTO_OPCODE_CIPHER_ENCRYPT_SETUP);
 }
 
 psa_status_t psa_cipher_decrypt_setup(psa_cipher_operation_t *operation,
 	psa_key_id_t key,
 	psa_algorithm_t alg)
 {
-	return PSA_ERROR_NOT_SUPPORTED;
+	return common_cipher_setup(operation, key, alg, TS_CRYPTO_OPCODE_CIPHER_DECRYPT_SETUP);
 }
 
 psa_status_t psa_cipher_generate_iv(psa_cipher_operation_t *operation,
@@ -31,14 +86,112 @@
 	size_t iv_size,
 	size_t *iv_length)
 {
-	return PSA_ERROR_NOT_SUPPORTED;
+	psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+	struct ts_crypto_cipher_generate_iv_in req_msg;
+	size_t req_fixed_len = sizeof(struct ts_crypto_cipher_generate_iv_in);
+	size_t req_len = req_fixed_len;
+
+	*iv_length = 0;
+	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_CIPHER_GENERATE_IV, &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_CIPHER_GENERATE_IV_OUT_TAG_IV, &decoded_record)) {
+
+					if (decoded_record.length <= iv_size) {
+
+						memcpy(iv, decoded_record.value, decoded_record.length);
+						*iv_length = decoded_record.length;
+					}
+					else {
+						/* Provided buffer is too small */
+						psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+					}
+				}
+				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_cipher_set_iv(psa_cipher_operation_t *operation,
 	const uint8_t *iv,
 	size_t iv_length)
 {
-	return PSA_ERROR_NOT_SUPPORTED;
+	psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+	struct ts_crypto_cipher_set_iv_in req_msg;
+	size_t req_fixed_len = sizeof(struct ts_crypto_cipher_set_iv_in);
+	size_t req_len = req_fixed_len;
+
+	req_msg.op_handle = operation->handle;
+
+	/* Mandatory input data parameter */
+	struct tlv_record data_record;
+	data_record.tag = TS_CRYPTO_CIPHER_SET_IV_IN_TAG_IV;
+	data_record.length = iv_length;
+	data_record.value = iv;
+	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_CIPHER_SET_IV, &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_cipher_update(psa_cipher_operation_t *operation,
@@ -48,7 +201,76 @@
 	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_cipher_update_in req_msg;
+	size_t req_fixed_len = sizeof(struct ts_crypto_cipher_update_in);
+	size_t req_len = req_fixed_len;
+
+	*output_length = 0;
+	req_msg.op_handle = operation->handle;
+
+	/* Mandatory input data parameter */
+	struct tlv_record data_record;
+	data_record.tag = TS_CRYPTO_CIPHER_UPDATE_IN_TAG_DATA;
+	data_record.length = input_length;
+	data_record.value = input;
+	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_CIPHER_UPDATE, &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_CIPHER_UPDATE_OUT_TAG_DATA, &decoded_record)) {
+
+					if (decoded_record.length <= output_size) {
+
+						memcpy(output, decoded_record.value, decoded_record.length);
+						*output_length = decoded_record.length;
+					}
+					else {
+						/* Provided buffer is too small */
+						psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+					}
+				}
+				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_cipher_finish(psa_cipher_operation_t *operation,
@@ -56,10 +278,97 @@
 	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_cipher_finish_in req_msg;
+	size_t req_fixed_len = sizeof(struct ts_crypto_cipher_finish_in);
+	size_t req_len = req_fixed_len;
+
+	*output_length = 0;
+	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_CIPHER_FINISH, &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_CIPHER_FINISH_OUT_TAG_DATA, &decoded_record)) {
+
+					if (decoded_record.length <= output_size) {
+
+						memcpy(output, decoded_record.value, decoded_record.length);
+						*output_length = decoded_record.length;
+					}
+					else {
+						/* Provided buffer is too small */
+						psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+					}
+				}
+				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_cipher_abort(psa_cipher_operation_t *operation)
 {
-	return PSA_ERROR_NOT_SUPPORTED;
+	psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+	struct ts_crypto_cipher_abort_in req_msg;
+	size_t req_fixed_len = sizeof(struct ts_crypto_cipher_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_CIPHER_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;
 }