Add crypto service

Change-Id: Ifd55a4caaf0b95e3d1b6504863fba112a7e18f15
Signed-off-by: Julian Hall <julian.hall@arm.com>
diff --git a/components/service/crypto/test/unit/component.cmake b/components/service/crypto/test/unit/component.cmake
new file mode 100644
index 0000000..bdb38bc
--- /dev/null
+++ b/components/service/crypto/test/unit/component.cmake
@@ -0,0 +1,16 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/crypto_msg_encode_decode.cpp"
+	"${CMAKE_CURRENT_LIST_DIR}/poc_crypto_ops.cpp"
+	"${CMAKE_CURRENT_LIST_DIR}/crypto_fault_tests.cpp"
+	)
+
diff --git a/components/service/crypto/test/unit/crypto_fault_tests.cpp b/components/service/crypto/test/unit/crypto_fault_tests.cpp
new file mode 100644
index 0000000..63a4b39
--- /dev/null
+++ b/components/service/crypto/test/unit/crypto_fault_tests.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string>
+#include <cstring>
+#include <cstdint>
+#include <service/crypto/client/test/standalone/standalone_crypto_client.h>
+#include <CppUTest/TestHarness.h>
+
+TEST_GROUP(CryptoFaultTests)
+{
+    void setup()
+    {
+        m_crypto_client = new standalone_crypto_client;
+    }
+
+    void teardown()
+    {
+        m_crypto_client->deinit();
+        delete m_crypto_client;
+        m_crypto_client = NULL;
+    }
+
+    test_crypto_client *m_crypto_client;
+};
+
+TEST(CryptoFaultTests, volatileKeyWithBrokenStorage)
+{
+    /* Inject broken secure storage fault */
+    m_crypto_client->inject_fault(test_crypto_client::FAILED_TO_DISCOVER_SECURE_STORAGE);
+    m_crypto_client->init();
+
+    psa_status_t status;
+    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_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
+    psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP_R1));
+    psa_set_key_bits(&attributes, 256);
+
+    /* Expect generation of volatile key to still work with fault */
+    psa_key_handle_t key_handle;
+    status = m_crypto_client->generate_key(&attributes, &key_handle);
+    CHECK_EQUAL(PSA_SUCCESS, status);
+
+    psa_reset_key_attributes(&attributes);
+}
+
+TEST(CryptoFaultTests, persistentKeysWithBrokenStorage)
+{
+    /* Inject broken secure storage fault */
+    m_crypto_client->inject_fault(test_crypto_client::FAILED_TO_DISCOVER_SECURE_STORAGE);
+    m_crypto_client->init();
+
+    psa_status_t status;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH);
+    psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
+    psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP_R1));
+    psa_set_key_bits(&attributes, 256);
+
+    /* Expect persist key generation to fail */
+    psa_key_id_t key_id_1 = 1;
+    psa_set_key_id(&attributes, key_id_1);
+    psa_key_handle_t key_handle_1;
+    status = m_crypto_client->generate_key(&attributes, &key_handle_1);
+    CHECK(PSA_SUCCESS != status);
+
+    psa_reset_key_attributes(&attributes);
+}
+
+TEST(CryptoFaultTests, randomNumbersWithBrokenStorage)
+{
+    /* Inject broken secure storage fault */
+    m_crypto_client->inject_fault(test_crypto_client::FAILED_TO_DISCOVER_SECURE_STORAGE);
+    m_crypto_client->init();
+
+    psa_status_t status;
+    uint8_t num12_128bit[16];
+
+    memset(num12_128bit, 0, sizeof(num12_128bit));
+
+    /* Expect random number generation to work, despite the broken storage */
+    status = m_crypto_client->generate_random(num12_128bit, sizeof(num12_128bit));
+    CHECK_EQUAL(PSA_SUCCESS, status);
+}
diff --git a/components/service/crypto/test/unit/crypto_msg_encode_decode.cpp b/components/service/crypto/test/unit/crypto_msg_encode_decode.cpp
new file mode 100644
index 0000000..ea8e388
--- /dev/null
+++ b/components/service/crypto/test/unit/crypto_msg_encode_decode.cpp
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <string>
+#include <CppUTest/TestHarness.h>
+#include <service/crypto/protobuf/generate_key.pb.h>
+#include <service/crypto/protobuf/export_public_key.pb.h>
+#include <service/crypto/protobuf/sign_hash.pb.h>
+#include <pb.h>
+#include <pb_encode.h>
+#include <pb_decode.h>
+
+
+TEST_GROUP(CryptoMsgTests) {
+
+	void setup() {
+        print_info = false;
+    }
+
+	/* Nanopb encode/decode methods */
+	static bool encode_byte_array(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
+
+		const pb_bytes_array_t *byte_array = (const pb_bytes_array_t *)*arg;
+		if (!pb_encode_tag_for_field(stream, field)) return false;
+
+		return pb_encode_string(stream, byte_array->bytes, byte_array->size);
+	}
+
+	static bool decode_byte_array(pb_istream_t *stream, const pb_field_t *field, void **arg) {
+
+		(void)field;
+		pb_bytes_array_t *byte_array = (pb_bytes_array_t *)*arg;
+		if (stream->bytes_left > byte_array->size) return false;
+
+		return pb_read(stream, byte_array->bytes, stream->bytes_left);
+	}
+
+	static pb_callback_t out_byte_array(const pb_bytes_array_t *byte_array) {
+
+		pb_callback_t callback;
+		callback.funcs.encode = encode_byte_array;
+		callback.arg = (void*)byte_array;
+
+		return callback;
+	}
+
+	static pb_callback_t in_byte_array(pb_bytes_array_t *byte_array) {
+
+		pb_callback_t callback;
+		callback.funcs.decode = decode_byte_array;
+		callback.arg = (void*)byte_array;
+		return callback;
+	}
+
+	bool print_info;
+};
+
+TEST(CryptoMsgTests, GenerateKeyInMsgTest) {
+	/* Sender - set values and serialize */
+	ts_crypto_GenerateKeyIn sent_msg = ts_crypto_GenerateKeyIn_init_default;
+	ts_crypto_KeyAttributes sent_key_attributes = ts_crypto_KeyAttributes_init_default;
+
+	sent_key_attributes.type =
+		ts_crypto_KeyType_KEY_TYPE_ECC_PUBLIC_KEY_BASE |
+		ts_crypto_EccCurve_ECC_CURVE_SECP_R1;
+
+	sent_key_attributes.key_bits = 256;
+	sent_key_attributes.lifetime = ts_crypto_KeyLifetime_KEY_LIFETIME_PERSISTENT;
+	sent_key_attributes.id = 3;
+
+	sent_key_attributes.has_policy = true;
+	sent_key_attributes.policy.usage = ts_crypto_KeyUsage_KEY_USAGE_SIGN_HASH;
+	sent_key_attributes.policy.alg =
+		ts_crypto_Alg_ALG_DETERMINISTIC_ECDSA_BASE |
+		ts_crypto_Alg_ALG_SHA_256;
+
+	sent_msg.attributes = sent_key_attributes;
+	sent_msg.has_attributes = true;
+
+	size_t sent_msg_len;
+	CHECK(pb_get_encoded_size(&sent_msg_len, ts_crypto_GenerateKeyIn_fields, &sent_msg));
+	uint8_t *sent_msg_buf = (uint8_t*)malloc(sent_msg_len);
+	CHECK(sent_msg_len > 0);
+	CHECK(sent_msg_buf);
+
+	pb_ostream_t ostream = pb_ostream_from_buffer(sent_msg_buf, sent_msg_len);
+	CHECK(pb_encode(&ostream, ts_crypto_GenerateKeyIn_fields, &sent_msg));
+	CHECK_EQUAL(sent_msg_len, ostream.bytes_written);
+
+	/* Receiver - deserialize and use values */
+	ts_crypto_GenerateKeyIn recv_msg = ts_crypto_GenerateKeyIn_init_default;
+
+	pb_istream_t istream = pb_istream_from_buffer(sent_msg_buf, sent_msg_len);
+	CHECK_EQUAL(sent_msg_len, istream.bytes_left);
+	CHECK(pb_decode(&istream, ts_crypto_GenerateKeyIn_fields, &recv_msg));
+	CHECK_EQUAL(0, istream.bytes_left);
+
+	free(sent_msg_buf);
+
+	CHECK(recv_msg.has_attributes);
+	CHECK_EQUAL(sent_key_attributes.type, recv_msg.attributes.type);
+	CHECK_EQUAL(sent_key_attributes.key_bits, recv_msg.attributes.key_bits);
+	CHECK_EQUAL(sent_key_attributes.lifetime, recv_msg.attributes.lifetime);
+	CHECK_EQUAL(sent_key_attributes.id, recv_msg.attributes.id);
+
+	CHECK(recv_msg.attributes.has_policy);
+	CHECK_EQUAL(sent_key_attributes.policy.usage, recv_msg.attributes.policy.usage);
+	CHECK_EQUAL(sent_key_attributes.policy.alg, recv_msg.attributes.policy.alg);
+
+	if (print_info) {
+		printf("Serialized op_export_public_key len: %ld\n", sent_msg_len);
+	}
+}
+
+TEST(CryptoMsgTests, ExportPublicKeyInMsgTest) {
+	/* Sender - set values and serialize */
+	ts_crypto_ExportPublicKeyIn sent_msg = ts_crypto_ExportPublicKeyIn_init_default;
+
+	sent_msg.handle = 55;
+
+	size_t sent_msg_len;
+	CHECK(pb_get_encoded_size(&sent_msg_len, ts_crypto_ExportPublicKeyIn_fields, &sent_msg));
+	uint8_t *sent_msg_buf = (uint8_t*)malloc(sent_msg_len);
+	CHECK(sent_msg_len > 0);
+	CHECK(sent_msg_buf);
+
+	pb_ostream_t ostream = pb_ostream_from_buffer(sent_msg_buf, sent_msg_len);
+	CHECK(pb_encode(&ostream, ts_crypto_ExportPublicKeyIn_fields, &sent_msg));
+	CHECK_EQUAL(sent_msg_len, ostream.bytes_written);
+
+	/* Receiver - deserialize and use values */
+	ts_crypto_ExportPublicKeyIn recv_msg = ts_crypto_ExportPublicKeyIn_init_default;
+
+	pb_istream_t istream = pb_istream_from_buffer(sent_msg_buf, sent_msg_len);
+	CHECK_EQUAL(sent_msg_len, istream.bytes_left);
+	CHECK(pb_decode(&istream, ts_crypto_ExportPublicKeyIn_fields, &recv_msg));
+	CHECK_EQUAL(0, istream.bytes_left);
+
+	CHECK_EQUAL(sent_msg.handle, recv_msg.handle);
+
+	free(sent_msg_buf);
+
+	if (print_info) {
+		printf("Serialized op_export_public_key len: %ld\n", sent_msg_len);
+	}
+}
+
+TEST(CryptoMsgTests, ExportPublicKeyOutMsgTest) {
+	/* Sender - set values and serialize */
+	ts_crypto_ExportPublicKeyOut sent_msg = ts_crypto_ExportPublicKeyOut_init_default;
+
+	PB_BYTES_ARRAY_T(5) example_key = {5, {0x31, 0x32, 0x33, 0x34, 0x35}};
+	sent_msg.data = out_byte_array((const pb_bytes_array_t *)&example_key);
+
+	size_t sent_msg_len;
+	CHECK(pb_get_encoded_size(&sent_msg_len, ts_crypto_ExportPublicKeyOut_fields, &sent_msg));
+	uint8_t *sent_msg_buf = (uint8_t*)malloc(sent_msg_len);
+	CHECK(sent_msg_len > 0);
+	CHECK(sent_msg_buf);
+
+	pb_ostream_t ostream = pb_ostream_from_buffer(sent_msg_buf, sent_msg_len);
+	CHECK(pb_encode(&ostream, ts_crypto_ExportPublicKeyOut_fields, &sent_msg));
+	CHECK_EQUAL(sent_msg_len, ostream.bytes_written);
+
+	/* Receiver - deserialize and use values */
+	PB_BYTES_ARRAY_T(5) recv_key = {5, {0}};
+	ts_crypto_ExportPublicKeyOut recv_msg = ts_crypto_ExportPublicKeyOut_init_default;
+	recv_msg.data = in_byte_array((pb_bytes_array_t *)&recv_key);
+
+	pb_istream_t istream = pb_istream_from_buffer(sent_msg_buf, sent_msg_len);
+	CHECK_EQUAL(sent_msg_len, istream.bytes_left);
+	CHECK(pb_decode(&istream, ts_crypto_ExportPublicKeyOut_fields, &recv_msg));
+	CHECK_EQUAL(0, istream.bytes_left);
+
+	free(sent_msg_buf);
+
+	CHECK_EQUAL(example_key.size, recv_key.size);
+	CHECK(memcmp(example_key.bytes, recv_key.bytes, example_key.size) == 0);
+
+	if (print_info) {
+		printf("Serialized result_export_public_key len: %ld\n", sent_msg_len);
+	}
+}
+
+TEST(CryptoMsgTests, SignHashInMsgTest) {
+	/* Sender - set values and serialize */
+	ts_crypto_SignHashIn sent_msg = ts_crypto_SignHashIn_init_default;
+
+	PB_BYTES_ARRAY_T(6) msg_to_sign = {6, {0x34, 0x32, 0x33, 0x34, 0x35, 0x36}};
+	sent_msg.hash = out_byte_array((const pb_bytes_array_t *)&msg_to_sign);
+
+	sent_msg.handle = 71;
+    sent_msg.alg =
+		ts_crypto_Alg_ALG_DETERMINISTIC_ECDSA_BASE |
+		ts_crypto_Alg_ALG_SHA_256;
+
+	size_t sent_msg_len;
+	CHECK(pb_get_encoded_size(&sent_msg_len, ts_crypto_SignHashIn_fields, &sent_msg));
+	uint8_t *sent_msg_buf = (uint8_t*)malloc(sent_msg_len);
+	CHECK(sent_msg_len > 0);
+	CHECK(sent_msg_buf);
+
+	pb_ostream_t ostream = pb_ostream_from_buffer(sent_msg_buf, sent_msg_len);
+	CHECK(pb_encode(&ostream, ts_crypto_SignHashIn_fields, &sent_msg));
+	CHECK_EQUAL(sent_msg_len, ostream.bytes_written);
+
+	/* Receiver - deserialize and use values */
+	PB_BYTES_ARRAY_T(6) recv_msg_to_sign = {6, {0}};
+	ts_crypto_SignHashIn recv_msg = ts_crypto_SignHashIn_init_default;
+	recv_msg.hash = in_byte_array((pb_bytes_array_t *)&recv_msg_to_sign);
+
+	pb_istream_t istream = pb_istream_from_buffer(sent_msg_buf, sent_msg_len);
+	CHECK_EQUAL(sent_msg_len, istream.bytes_left);
+	CHECK(pb_decode(&istream, ts_crypto_SignHashIn_fields, &recv_msg));
+	CHECK_EQUAL(0, istream.bytes_left);
+
+	free(sent_msg_buf);
+
+	CHECK_EQUAL(sent_msg.handle, recv_msg.handle);
+	CHECK_EQUAL(sent_msg.alg, recv_msg.alg);
+
+	CHECK_EQUAL(msg_to_sign.size, recv_msg_to_sign.size);
+	CHECK(memcmp(msg_to_sign.bytes, recv_msg_to_sign.bytes, msg_to_sign.size) == 0);
+
+	if (print_info) {
+		printf("Serialized op_asym_sign len: %ld\n", sent_msg_len);
+	}
+}
+
+TEST(CryptoMsgTests, SignHashOutMsgTest) {
+	/* Sender - set values and serialize */
+	ts_crypto_SignHashOut sent_msg = ts_crypto_SignHashOut_init_default;
+
+	PB_BYTES_ARRAY_T(10) example_signature = {10, {0x01, 0x02, 0x5a, 0x7c, 0x35, 0x01, 0x02, 0x5a, 0x7c, 0x35}};
+	sent_msg.signature = out_byte_array((const pb_bytes_array_t *)&example_signature);
+
+	size_t sent_msg_len;
+	CHECK(pb_get_encoded_size(&sent_msg_len, ts_crypto_SignHashOut_fields, &sent_msg));
+	uint8_t *sent_msg_buf = (uint8_t*)malloc(sent_msg_len);
+	CHECK(sent_msg_len > 0);
+	CHECK(sent_msg_buf);
+
+	pb_ostream_t ostream = pb_ostream_from_buffer(sent_msg_buf, sent_msg_len);
+	CHECK(pb_encode(&ostream, ts_crypto_SignHashOut_fields, &sent_msg));
+	CHECK_EQUAL(sent_msg_len, ostream.bytes_written);
+
+	/* Receiver - deserialize and use values */
+	PB_BYTES_ARRAY_T(10) recv_signature = {10, {0}};
+	ts_crypto_SignHashOut recv_msg = ts_crypto_SignHashOut_init_default;
+	recv_msg.signature = in_byte_array((pb_bytes_array_t *)&recv_signature);
+
+	pb_istream_t istream = pb_istream_from_buffer(sent_msg_buf, sent_msg_len);
+	CHECK_EQUAL(sent_msg_len, istream.bytes_left);
+	CHECK(pb_decode(&istream, ts_crypto_SignHashOut_fields, &recv_msg));
+	CHECK_EQUAL(0, istream.bytes_left);
+
+	free(sent_msg_buf);
+
+	CHECK_EQUAL(example_signature.size, recv_signature.size);
+	CHECK(memcmp(example_signature.bytes, recv_signature.bytes, example_signature.size) == 0);
+
+	if (print_info) {
+		printf("Serialized result_asym_sign len: %ld\n", sent_msg_len);
+	}
+}
diff --git a/components/service/crypto/test/unit/poc_crypto_ops.cpp b/components/service/crypto/test/unit/poc_crypto_ops.cpp
new file mode 100644
index 0000000..30be0eb
--- /dev/null
+++ b/components/service/crypto/test/unit/poc_crypto_ops.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <cstdio>
+#include <cstring>
+#include <psa/crypto.h>
+#include <CppUTest/TestHarness.h>
+
+/* Tests to prototype each of the Crypto operations used for the PoC Crypto SP
+ * demonstrator.
+ */
+TEST_GROUP(PocCryptoOpTests) {
+
+    void setup() {
+        print_info = false;
+        (void)psa_crypto_init();
+    }
+
+    void generateEcdsaKeyPair() {
+        psa_status_t status;
+        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_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
+        psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP_R1));
+        psa_set_key_bits(&attributes, 256);
+
+        status = psa_generate_key(&attributes, &ecdsa_key_handle);
+        CHECK_EQUAL(PSA_SUCCESS, status);
+
+        psa_reset_key_attributes(&attributes);
+
+        if (print_info)	{
+            printf("Generated ECDSA key pair\n");
+            printf("    Inputs: attributes: %ld\n", sizeof(attributes));
+            printf("    Outputs: handle: %ld status: %ld\n", sizeof(ecdsa_key_handle), sizeof(status));
+        }
+    }
+
+    void exportPublicKey() {
+        psa_status_t status;
+        exported_key_len = 0;
+        psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+        status = psa_get_key_attributes(ecdsa_key_handle, &attributes);
+
+        CHECK_EQUAL(PSA_SUCCESS, status);
+
+        size_t max_export_size = PSA_KEY_EXPORT_MAX_SIZE(PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(psa_get_key_type(&attributes)),
+                                    psa_get_key_bits(&attributes));
+
+        status = psa_export_public_key(ecdsa_key_handle, exported_key, sizeof(exported_key),
+                                        &exported_key_len);
+
+        CHECK_EQUAL(PSA_SUCCESS, status);
+        CHECK_EQUAL(max_export_size, exported_key_len);
+
+        psa_reset_key_attributes(&attributes);
+
+        if (print_info) {
+            printf("Exported a public key\n");
+            printf("    Inputs: handle: %ld\n", sizeof(ecdsa_key_handle));
+            printf("    Outputs: exported_length: %ld status: %ld\n", sizeof(exported_key_len), sizeof(status));
+            printf("    Outputs: space of key value: %ld bytes\n", exported_key_len);
+        }
+    }
+
+    void signMessage() {
+        psa_status_t status;
+        uint8_t hash[20];
+        uint8_t signature[PSA_SIGNATURE_MAX_SIZE];
+        size_t signature_length;
+        psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+        memset(hash, 0x55, sizeof(hash));
+
+        status = psa_get_key_attributes(ecdsa_key_handle, &attributes);
+
+        CHECK_EQUAL(PSA_SUCCESS, status);
+
+        status = psa_sign_hash(ecdsa_key_handle, psa_get_key_algorithm(&attributes),
+                                hash, sizeof(hash),
+                                signature, sizeof(signature),
+                                &signature_length);
+        CHECK_EQUAL(PSA_SUCCESS, status);
+
+        psa_reset_key_attributes(&attributes);
+
+        if (print_info) {
+            printf("Signed a message\n");
+            printf("    Inputs: handle: %ld algo 1 message %ld\n", sizeof(ecdsa_key_handle), sizeof(hash));
+            printf("    Outputs: signature: %ld\n", signature_length);
+        }
+    }
+
+    bool print_info;
+    psa_key_handle_t ecdsa_key_handle;
+    uint8_t exported_key[PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(256)];
+    size_t exported_key_len;
+};
+
+TEST(PocCryptoOpTests, checkOpSequence) {
+
+    generateEcdsaKeyPair();
+    exportPublicKey();
+    signMessage();
+}
\ No newline at end of file