Add MAC service level tests

Adds end-to-end service tests for MAC operations provided
by a crypto provider.

Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: I037f0b88348bcbd9bad367230509e72f41351ac6
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_mac.h b/components/service/crypto/client/caller/packed-c/crypto_caller_mac.h
index 41c1d20..2e99580 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_mac.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_mac.h
@@ -289,7 +289,7 @@
 	return psa_status;
 }
 
-static inline size_t crypto_caller_mac_max_update_size(struct service_client *context)
+static inline size_t crypto_caller_mac_max_update_size(const struct service_client *context)
 {
 	/* Returns the maximum number of bytes that may be
 	 * carried as a parameter of the mac_update operation
diff --git a/components/service/crypto/client/cpp/crypto_client.h b/components/service/crypto/client/cpp/crypto_client.h
index 2b5a0f0..eb30655 100644
--- a/components/service/crypto/client/cpp/crypto_client.h
+++ b/components/service/crypto/client/cpp/crypto_client.h
@@ -148,6 +148,35 @@
 	virtual psa_status_t cipher_abort(
 		uint32_t op_handle) = 0;
 
+	/* MAC methods */
+	virtual size_t mac_max_update_size() const = 0;
+
+	virtual psa_status_t mac_sign_setup(
+		uint32_t *op_handle,
+		psa_key_id_t key,
+		psa_algorithm_t alg) = 0;
+
+	virtual psa_status_t mac_verify_setup(
+		uint32_t *op_handle,
+		psa_key_id_t key,
+		psa_algorithm_t alg) = 0;
+
+	virtual psa_status_t mac_update(
+		uint32_t op_handle,
+		const uint8_t *input, size_t input_length) = 0;
+
+	virtual psa_status_t mac_sign_finish(
+		uint32_t op_handle,
+		uint8_t *mac, size_t mac_size, size_t *mac_length) = 0;
+
+	virtual psa_status_t mac_verify_finish(
+		uint32_t op_handle,
+		const uint8_t *mac, size_t mac_length) = 0;
+
+	virtual psa_status_t mac_abort(
+		uint32_t op_handle) = 0;
+
+
 protected:
 	crypto_client();
 	crypto_client(struct rpc_caller *caller);
diff --git a/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.cpp b/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.cpp
index edcac7b..694d9a0 100644
--- a/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.cpp
+++ b/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.cpp
@@ -255,3 +255,58 @@
 	return crypto_caller_cipher_abort(&m_client,
 		op_handle);
 }
+
+/* MAC methods */
+size_t packedc_crypto_client::mac_max_update_size() const
+{
+	return crypto_caller_mac_max_update_size(&m_client);
+}
+
+psa_status_t packedc_crypto_client::mac_sign_setup(
+	uint32_t *op_handle,
+	psa_key_id_t key,
+	psa_algorithm_t alg)
+{
+	return crypto_caller_mac_sign_setup(&m_client,
+		op_handle, key, alg);
+}
+
+psa_status_t packedc_crypto_client::mac_verify_setup(
+	uint32_t *op_handle,
+	psa_key_id_t key,
+	psa_algorithm_t alg)
+{
+	return crypto_caller_mac_verify_setup(&m_client,
+		op_handle, key, alg);
+}
+
+psa_status_t packedc_crypto_client::mac_update(
+	uint32_t op_handle,
+	const uint8_t *input, size_t input_length)
+{
+	return crypto_caller_mac_update(&m_client,
+		op_handle, input, input_length);
+}
+
+psa_status_t packedc_crypto_client::mac_sign_finish(
+	uint32_t op_handle,
+	uint8_t *mac, size_t mac_size, size_t *mac_length)
+{
+	return crypto_caller_mac_sign_finish(&m_client,
+		op_handle, mac, mac_size, mac_length);
+}
+
+psa_status_t packedc_crypto_client::mac_verify_finish(
+	uint32_t op_handle,
+	const uint8_t *mac, size_t mac_length)
+{
+	return crypto_caller_mac_verify_finish(&m_client,
+		op_handle, mac, mac_length);
+}
+
+psa_status_t packedc_crypto_client::mac_abort(
+	uint32_t op_handle)
+{
+	return crypto_caller_mac_abort(&m_client,
+		op_handle);
+}
diff --git a/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.h b/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.h
index 9c30372..32dbdc4 100644
--- a/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.h
+++ b/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.h
@@ -145,6 +145,34 @@
 	psa_status_t cipher_abort(
 		uint32_t op_handle);
 
+	/* MAC methods */
+	size_t mac_max_update_size() const;
+
+	psa_status_t mac_sign_setup(
+		uint32_t *op_handle,
+		psa_key_id_t key,
+		psa_algorithm_t alg);
+
+	psa_status_t mac_verify_setup(
+		uint32_t *op_handle,
+		psa_key_id_t key,
+		psa_algorithm_t alg);
+
+	psa_status_t mac_update(
+		uint32_t op_handle,
+		const uint8_t *input, size_t input_length);
+
+	psa_status_t mac_sign_finish(
+		uint32_t op_handle,
+		uint8_t *mac, size_t mac_size, size_t *mac_length);
+
+	psa_status_t mac_verify_finish(
+		uint32_t op_handle,
+		const uint8_t *mac, size_t mac_length);
+
+	psa_status_t mac_abort(
+		uint32_t op_handle);
+
 };
 
 #endif /* PACKEDC_CRYPTO_CLIENT_H */
diff --git a/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.cpp b/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.cpp
index 6c0fe76..0941857 100644
--- a/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.cpp
+++ b/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.cpp
@@ -844,3 +844,52 @@
 {
 	return PSA_ERROR_NOT_SUPPORTED;
 }
+
+/* MAC methods */
+size_t protobuf_crypto_client::mac_max_update_size() const
+{
+	return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t protobuf_crypto_client::mac_sign_setup(
+	uint32_t *op_handle,
+	psa_key_id_t key,
+	psa_algorithm_t alg)
+{
+	return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t protobuf_crypto_client::mac_verify_setup(
+	uint32_t *op_handle,
+	psa_key_id_t key,
+	psa_algorithm_t alg)
+{
+	return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t protobuf_crypto_client::mac_update(
+	uint32_t op_handle,
+	const uint8_t *input, size_t input_length)
+{
+	return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t protobuf_crypto_client::mac_sign_finish(
+	uint32_t op_handle,
+	uint8_t *mac, size_t mac_size, size_t *mac_length)
+{
+	return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t protobuf_crypto_client::mac_verify_finish(
+	uint32_t op_handle,
+	const uint8_t *mac, size_t mac_length)
+{
+	return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t protobuf_crypto_client::mac_abort(
+	uint32_t op_handle)
+{
+	return PSA_ERROR_NOT_SUPPORTED;
+}
diff --git a/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.h b/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.h
index d152f04..e9be6ea 100644
--- a/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.h
+++ b/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.h
@@ -145,6 +145,34 @@
 	psa_status_t cipher_abort(
 		uint32_t op_handle);
 
+	/* MAC methods */
+	size_t mac_max_update_size() const;
+
+	psa_status_t mac_sign_setup(
+		uint32_t *op_handle,
+		psa_key_id_t key,
+		psa_algorithm_t alg);
+
+	psa_status_t mac_verify_setup(
+		uint32_t *op_handle,
+		psa_key_id_t key,
+		psa_algorithm_t alg);
+
+	psa_status_t mac_update(
+		uint32_t op_handle,
+		const uint8_t *input, size_t input_length);
+
+	psa_status_t mac_sign_finish(
+		uint32_t op_handle,
+		uint8_t *mac, size_t mac_size, size_t *mac_length);
+
+	psa_status_t mac_verify_finish(
+		uint32_t op_handle,
+		const uint8_t *mac, size_t mac_length);
+
+	psa_status_t mac_abort(
+		uint32_t op_handle);
+
 
 private:
 
diff --git a/components/service/crypto/test/service/extension/mac/component.cmake b/components/service/crypto/test/service/extension/mac/component.cmake
new file mode 100644
index 0000000..86465e8
--- /dev/null
+++ b/components/service/crypto/test/service/extension/mac/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}/mac_service_scenarios.cpp"
+	)
diff --git a/components/service/crypto/test/service/extension/mac/mac_service_scenarios.cpp b/components/service/crypto/test/service/extension/mac/mac_service_scenarios.cpp
new file mode 100644
index 0000000..b1b6149
--- /dev/null
+++ b/components/service/crypto/test/service/extension/mac/mac_service_scenarios.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cstring>
+#include <cstdint>
+#include <CppUTest/TestHarness.h>
+#include "mac_service_scenarios.h"
+
+
+mac_service_scenarios::mac_service_scenarios(crypto_client *crypto_client) :
+	m_crypto_client(crypto_client),
+	m_ref_input(NULL),
+	m_keyid(0)
+{
+
+}
+
+mac_service_scenarios::~mac_service_scenarios()
+{
+	destroy_key();
+
+	delete m_crypto_client;
+	m_crypto_client = NULL;
+
+	delete [] m_ref_input;
+	m_ref_input = NULL;
+}
+
+void mac_service_scenarios::create_ref_input(size_t size)
+{
+	m_ref_input = new uint8_t[size];
+	memset(m_ref_input, 0x61, size);
+}
+
+psa_status_t mac_service_scenarios::generate_key()
+{
+	destroy_key();
+
+	psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+	psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
+	psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH);
+	psa_set_key_algorithm(&attributes, PSA_ALG_CMAC);
+	psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
+	psa_set_key_bits(&attributes, 256);
+
+	psa_status_t status = m_crypto_client->generate_key(&attributes, &m_keyid);
+
+	psa_reset_key_attributes(&attributes);
+
+	return status;
+}
+
+void mac_service_scenarios::destroy_key()
+{
+	if (m_keyid) {
+
+		m_crypto_client->destroy_key(m_keyid);
+		m_keyid = 0;
+	}
+}
+
+void mac_service_scenarios::signAndVerify()
+{
+	size_t max_payload = m_crypto_client->mac_max_update_size();
+	static const size_t input_size = 19999;
+	psa_status_t status;
+
+	create_ref_input(input_size);
+
+	status = generate_key();
+	CHECK_EQUAL(PSA_SUCCESS, status);
+
+	/* Calculate MAC over input data */
+	uint32_t op_handle = 0;
+	size_t input_byte_count = 0;
+
+	status = m_crypto_client->mac_sign_setup(&op_handle, m_keyid, PSA_ALG_CMAC);
+	CHECK_EQUAL(PSA_SUCCESS, status);
+
+	while (input_byte_count < input_size) {
+
+		size_t bytes_left = input_size - input_byte_count;
+		size_t update_len = (bytes_left < max_payload) ? bytes_left : max_payload;
+
+		status = m_crypto_client->mac_update(op_handle,
+			&m_ref_input[input_byte_count], update_len);
+		CHECK_EQUAL(PSA_SUCCESS, status);
+
+		input_byte_count += update_len;
+	}
+
+	size_t mac_len;
+	uint8_t mac[PSA_MAC_MAX_SIZE];
+
+	status = m_crypto_client->mac_sign_finish(op_handle, mac, sizeof(mac), &mac_len);
+	CHECK_EQUAL(PSA_SUCCESS, status);
+
+	/* Verify MAC */
+	op_handle = 0;
+	input_byte_count = 0;
+
+	status = m_crypto_client->mac_verify_setup(&op_handle, m_keyid, PSA_ALG_CMAC);
+	CHECK_EQUAL(PSA_SUCCESS, status);
+
+	while (input_byte_count < input_size) {
+
+		size_t bytes_left = input_size - input_byte_count;
+		size_t update_len = (bytes_left < max_payload) ? bytes_left : max_payload;
+
+		status = m_crypto_client->mac_update(op_handle,
+			&m_ref_input[input_byte_count], update_len);
+		CHECK_EQUAL(PSA_SUCCESS, status);
+
+		input_byte_count += update_len;
+	}
+
+	status = m_crypto_client->mac_verify_finish(op_handle, mac, mac_len);
+	CHECK_EQUAL(PSA_SUCCESS, status);
+}
+
+void mac_service_scenarios::macAbort()
+{
+	/* Aborts a mac operation prior to the first update */
+	uint32_t op_handle = 0;
+	psa_status_t status = generate_key();
+	CHECK_EQUAL(PSA_SUCCESS, status);
+
+	status = m_crypto_client->mac_sign_setup(&op_handle, m_keyid, PSA_ALG_CMAC);
+	CHECK_EQUAL(PSA_SUCCESS, status);
+
+	status = m_crypto_client->mac_abort(op_handle);
+	CHECK_EQUAL(PSA_SUCCESS, status);
+
+	size_t mac_len;
+	uint8_t mac[PSA_MAC_MAX_SIZE];
+
+	status = m_crypto_client->mac_sign_finish(op_handle, mac, sizeof(mac), &mac_len);
+	CHECK_EQUAL(PSA_ERROR_BAD_STATE, status);
+}
diff --git a/components/service/crypto/test/service/extension/mac/mac_service_scenarios.h b/components/service/crypto/test/service/extension/mac/mac_service_scenarios.h
new file mode 100644
index 0000000..b3f3d06
--- /dev/null
+++ b/components/service/crypto/test/service/extension/mac/mac_service_scenarios.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MAC_SERVICE_SCENARIOS_H
+#define MAC_SERVICE_SCENARIOS_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <service/crypto/client/cpp/crypto_client.h>
+
+/*
+ * Service-level test scenarios for the mac extension to the crypto service
+ * that may be reused using different concrete crypto_clients to check
+ * end-to-end operation using different protocol serialization schemes.
+ */
+class mac_service_scenarios
+{
+public:
+	mac_service_scenarios(crypto_client *crypto_client);
+	~mac_service_scenarios();
+
+	void signAndVerify();
+	void macAbort();
+
+private:
+
+	psa_status_t generate_key();
+	void destroy_key();
+
+	void create_ref_input(size_t size);
+
+	crypto_client *m_crypto_client;
+	uint8_t *m_ref_input;
+	psa_key_id_t m_keyid;
+};
+
+#endif /* MAC_SERVICE_SCENARIOS_H */
diff --git a/components/service/crypto/test/service/extension/mac/packed-c/component.cmake b/components/service/crypto/test/service/extension/mac/packed-c/component.cmake
new file mode 100644
index 0000000..a8d3361
--- /dev/null
+++ b/components/service/crypto/test/service/extension/mac/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}/mac_service_packedc_tests.cpp"
+	)
diff --git a/components/service/crypto/test/service/extension/mac/packed-c/mac_service_packedc_tests.cpp b/components/service/crypto/test/service/extension/mac/packed-c/mac_service_packedc_tests.cpp
new file mode 100644
index 0000000..6ead054
--- /dev/null
+++ b/components/service/crypto/test/service/extension/mac/packed-c/mac_service_packedc_tests.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.h>
+#include <service/crypto/test/service/extension/mac/mac_service_scenarios.h>
+#include <protocols/rpc/common/packed-c/encoding.h>
+#include <service_locator.h>
+#include <CppUTest/TestHarness.h>
+
+/*
+ * Service-level mac tests that use the packed-c access protocol serialization
+ */
+TEST_GROUP(CryptoMacServicePackedcTests)
+{
+	void setup()
+	{
+		struct rpc_caller *caller;
+		int status;
+
+		m_rpc_session_handle = NULL;
+		m_crypto_service_context = NULL;
+		m_scenarios = NULL;
+
+		service_locator_init();
+
+		m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0", &status);
+		CHECK_TRUE(m_crypto_service_context);
+
+		m_rpc_session_handle = service_context_open(m_crypto_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
+		CHECK_TRUE(m_rpc_session_handle);
+
+		m_scenarios = new mac_service_scenarios(new packedc_crypto_client(caller));
+	}
+
+	void teardown()
+	{
+		delete m_scenarios;
+		m_scenarios = NULL;
+
+		service_context_close(m_crypto_service_context, m_rpc_session_handle);
+		m_rpc_session_handle = NULL;
+
+		service_context_relinquish(m_crypto_service_context);
+		m_crypto_service_context = NULL;
+	}
+
+	rpc_session_handle m_rpc_session_handle;
+	struct service_context *m_crypto_service_context;
+	mac_service_scenarios *m_scenarios;
+};
+
+TEST(CryptoMacServicePackedcTests, signAndVerify)
+{
+	m_scenarios->signAndVerify();
+}
+
+TEST(CryptoMacServicePackedcTests, macAbort)
+{
+	m_scenarios->macAbort();
+}
diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index ca894c9..ad04fba 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -94,6 +94,8 @@
 		"components/service/crypto/test/service/extension/hash/packed-c"
 		"components/service/crypto/test/service/extension/cipher"
 		"components/service/crypto/test/service/extension/cipher/packed-c"
+		"components/service/crypto/test/service/extension/mac"
+		"components/service/crypto/test/service/extension/mac/packed-c"
 		"components/service/crypto/test/protocol"
 		"components/service/secure_storage/include"
 		"components/service/secure_storage/frontend/psa/its"
diff --git a/deployments/ts-service-test/ts-service-test.cmake b/deployments/ts-service-test/ts-service-test.cmake
index 07a34ec..fedb821 100644
--- a/deployments/ts-service-test/ts-service-test.cmake
+++ b/deployments/ts-service-test/ts-service-test.cmake
@@ -40,6 +40,8 @@
 		"components/service/crypto/test/service/extension/hash/packed-c"
 		"components/service/crypto/test/service/extension/cipher"
 		"components/service/crypto/test/service/extension/cipher/packed-c"
+		"components/service/crypto/test/service/extension/mac"
+		"components/service/crypto/test/service/extension/mac/packed-c"
 		"components/service/crypto/client/psa"
 		"components/service/crypto/client/cpp"
 		"components/service/crypto/client/cpp/protocol/protobuf"