Add crypto service

Change-Id: Ifd55a4caaf0b95e3d1b6504863fba112a7e18f15
Signed-off-by: Julian Hall <julian.hall@arm.com>
diff --git a/components/service/crypto/client/test/component.cmake b/components/service/crypto/client/test/component.cmake
new file mode 100644
index 0000000..0374e84
--- /dev/null
+++ b/components/service/crypto/client/test/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# 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}/test_crypto_client.cpp"
+	)
+
diff --git a/components/service/crypto/client/test/mock/component.cmake b/components/service/crypto/client/test/mock/component.cmake
new file mode 100644
index 0000000..8202578
--- /dev/null
+++ b/components/service/crypto/client/test/mock/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# 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}/mock_crypto_client.cpp"
+	)
+
diff --git a/components/service/crypto/client/test/mock/mock_crypto_client.cpp b/components/service/crypto/client/test/mock/mock_crypto_client.cpp
new file mode 100644
index 0000000..8e55d34
--- /dev/null
+++ b/components/service/crypto/client/test/mock/mock_crypto_client.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "mock_crypto_client.h"
+
+mock_crypto_client::mock_crypto_client() :
+    test_crypto_client(),
+    m_crypto_provider(),
+    m_storage_provider(),
+    m_crypto_caller(),
+    m_storage_caller()
+{
+
+}
+
+mock_crypto_client::~mock_crypto_client()
+{
+
+}
+
+bool mock_crypto_client::init()
+{
+    bool should_do = test_crypto_client::init();
+
+    if (should_do) {
+
+        struct call_ep *storage_ep = mock_store_provider_init(&m_storage_provider);
+        struct rpc_caller *storage_caller = direct_caller_init_default(&m_storage_caller, storage_ep);
+
+        struct call_ep *crypto_ep = mbed_crypto_provider_init(&m_crypto_provider, storage_caller);
+        struct rpc_caller *crypto_caller = direct_caller_init_default(&m_crypto_caller, crypto_ep);
+
+        crypto_client::set_caller(crypto_caller);
+    }
+
+    return should_do;
+}
+
+bool mock_crypto_client::deinit()
+{
+    bool should_do = test_crypto_client::deinit();
+
+    if (should_do) {
+
+        mbed_crypto_provider_deinit(&m_crypto_provider);
+        mock_store_provider_deinit(&m_storage_provider);
+
+        direct_caller_deinit(&m_storage_caller);
+        direct_caller_deinit(&m_crypto_caller);
+    }
+
+    return should_do;
+}
+
+/* Test Methods */
+bool mock_crypto_client::keystore_reset_is_supported() const
+{
+    return true;
+}
+
+void mock_crypto_client::keystore_reset()
+{
+    mock_store_reset(&m_storage_provider);
+}
+
+bool mock_crypto_client::keystore_key_exists_is_supported() const
+{
+    return true;
+}
+
+bool mock_crypto_client::keystore_key_exists(uint32_t id) const
+{
+    return mock_store_exists(&m_storage_provider, id);
+}
+
+bool mock_crypto_client::keystore_keys_held_is_supported() const
+{
+    return true;
+}
+
+size_t mock_crypto_client::keystore_keys_held() const
+{
+    return mock_store_num_items(&m_storage_provider);
+}
+
+/* Factory for creating mock_crypto_client objects */
+class mock_crypto_client_factory : public test_crypto_client::factory
+{
+public:
+    mock_crypto_client_factory() :
+        test_crypto_client::factory()
+    {
+        test_crypto_client::register_factory(this);
+    }
+
+    ~mock_crypto_client_factory()
+    {
+        test_crypto_client::deregister_factory(this);
+    }
+
+    test_crypto_client *create()
+    {
+        return new mock_crypto_client;
+    };
+};
+
+/*
+ * Static construction causes this to be registered
+ * as the default factory for constructing test_crypto_client objects.
+ */
+static mock_crypto_client_factory default_factory;
diff --git a/components/service/crypto/client/test/mock/mock_crypto_client.h b/components/service/crypto/client/test/mock/mock_crypto_client.h
new file mode 100644
index 0000000..92ee6a9
--- /dev/null
+++ b/components/service/crypto/client/test/mock/mock_crypto_client.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MOCK_CRYPTO_CLIENT_H
+#define MOCK_CRYPTO_CLIENT_H
+
+#include <service/crypto/client/test/test_crypto_client.h>
+#include <rpc/direct/direct_caller.h>
+#include <service/crypto/provider/mbedcrypto/crypto_provider.h>
+#include <service/secure_storage/provider/mock_store/mock_store_provider.h>
+
+/*
+ * A specialization of the crypto_client class that extends it to add crypto
+ * and storage providers to offer a viable crypto service from a single object.
+ * The mock_store storage provider is used for persistent key storage.
+ * This is only used for test purposes and should not be used for production
+ * deployments.  Provides methods used for inspecting service state that
+ * support test.
+ */
+class mock_crypto_client : public test_crypto_client
+{
+public:
+    mock_crypto_client();
+    virtual ~mock_crypto_client();
+
+    bool init();
+    bool deinit();
+
+    /* Test support methods */
+    bool keystore_reset_is_supported() const;
+    void keystore_reset();
+
+    bool keystore_key_exists_is_supported() const;
+    bool keystore_key_exists(uint32_t id) const;
+
+    bool keystore_keys_held_is_supported() const;
+    size_t keystore_keys_held() const;
+
+private:
+    struct mbed_crypto_provider m_crypto_provider;
+    struct mock_store_provider m_storage_provider;
+    struct direct_caller m_crypto_caller;
+    struct direct_caller m_storage_caller;
+};
+
+#endif /* MOCK_CRYPTO_CLIENT_H */
diff --git a/components/service/crypto/client/test/standalone/component.cmake b/components/service/crypto/client/test/standalone/component.cmake
new file mode 100644
index 0000000..13488e8
--- /dev/null
+++ b/components/service/crypto/client/test/standalone/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# 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}/standalone_crypto_client.cpp"
+	)
+
diff --git a/components/service/crypto/client/test/standalone/standalone_crypto_client.cpp b/components/service/crypto/client/test/standalone/standalone_crypto_client.cpp
new file mode 100644
index 0000000..da3224d
--- /dev/null
+++ b/components/service/crypto/client/test/standalone/standalone_crypto_client.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "standalone_crypto_client.h"
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/psa/packed-c/status.h>
+
+standalone_crypto_client::standalone_crypto_client() :
+    test_crypto_client(),
+    m_crypto_provider(),
+    m_storage_provider(),
+    m_crypto_caller(),
+    m_storage_caller(),
+    m_dummy_storage_caller()
+{
+
+}
+
+standalone_crypto_client::~standalone_crypto_client()
+{
+
+}
+
+bool standalone_crypto_client::init()
+{
+    bool should_do = test_crypto_client::init();
+
+    if (should_do) {
+
+        struct rpc_caller *storage_caller;
+
+        if (!is_fault_injected(FAILED_TO_DISCOVER_SECURE_STORAGE)) {
+
+            /* Establish rpc session with storage provider */
+            struct call_ep *storage_ep = sfs_provider_init(&m_storage_provider);
+            storage_caller = direct_caller_init_default(&m_storage_caller, storage_ep);
+        }
+        else {
+
+            /*
+             * Missing storage service fault injected.  To allow a somewhat viable
+             * crypto service to be started, use a dummy _caller that will safely
+             * terminate storage calls with an appropriate error.
+             */
+            storage_caller = dummy_caller_init(&m_dummy_storage_caller,
+                        TS_RPC_CALL_ACCEPTED, PSA_ERROR_STORAGE_FAILURE);
+        }
+
+        struct call_ep *crypto_ep = mbed_crypto_provider_init(&m_crypto_provider, storage_caller);
+        struct rpc_caller *crypto_caller = direct_caller_init_default(&m_crypto_caller, crypto_ep);
+
+        crypto_client::set_caller(crypto_caller);
+    }
+
+    return should_do;
+}
+
+bool standalone_crypto_client::deinit()
+{
+    bool should_do = test_crypto_client::deinit();
+
+    if (should_do) {
+
+        mbed_crypto_provider_deinit(&m_crypto_provider);
+
+        direct_caller_deinit(&m_storage_caller);
+        direct_caller_deinit(&m_crypto_caller);
+    }
+
+    return should_do;
+}
+
+/* Fault injection */
+bool standalone_crypto_client::is_fault_supported(enum fault_code code) const
+{
+    return (code == test_crypto_client::FAILED_TO_DISCOVER_SECURE_STORAGE);
+}
+
+/* Test Methods */
+bool standalone_crypto_client::keystore_reset_is_supported() const
+{
+    return test_crypto_client::keystore_reset_is_supported();
+}
+
+void standalone_crypto_client::keystore_reset()
+{
+    test_crypto_client::keystore_reset();
+}
+
+bool standalone_crypto_client::keystore_key_exists_is_supported() const
+{
+    return test_crypto_client::keystore_key_exists_is_supported() ;
+}
+
+bool standalone_crypto_client::keystore_key_exists(uint32_t id) const
+{
+    return test_crypto_client::keystore_key_exists(id);
+}
+
+bool standalone_crypto_client::keystore_keys_held_is_supported() const
+{
+    return test_crypto_client::keystore_keys_held_is_supported();
+}
+
+size_t standalone_crypto_client::keystore_keys_held() const
+{
+    return test_crypto_client::keystore_keys_held();
+}
+
+/* Factory for creating standalone_crypto_client objects */
+class standalone_crypto_client_factory : public test_crypto_client::factory
+{
+public:
+    standalone_crypto_client_factory() :
+        test_crypto_client::factory()
+    {
+        test_crypto_client::register_factory(this);
+    }
+
+    ~standalone_crypto_client_factory()
+    {
+        test_crypto_client::deregister_factory(this);
+    }
+
+    test_crypto_client *create()
+    {
+        return new standalone_crypto_client;
+    };
+};
+
+/*
+ * Static construction causes this to be registered
+ * as the default factory for constructing test_crypto_client objects.
+ */
+static standalone_crypto_client_factory default_factory;
diff --git a/components/service/crypto/client/test/standalone/standalone_crypto_client.h b/components/service/crypto/client/test/standalone/standalone_crypto_client.h
new file mode 100644
index 0000000..9327fdc
--- /dev/null
+++ b/components/service/crypto/client/test/standalone/standalone_crypto_client.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STANDALONE_CRYPTO_CLIENT_H
+#define STANDALONE_CRYPTO_CLIENT_H
+
+#include <service/crypto/client/test/test_crypto_client.h>
+#include <rpc/direct/direct_caller.h>
+#include <rpc/dummy/dummy_caller.h>
+#include <service/crypto/provider/mbedcrypto/crypto_provider.h>
+#include <service/secure_storage/provider/secure_flash_store/sfs_provider.h>
+
+/*
+ * A specialization of the crypto_client class that extends it to add crypto
+ * and storage providers to offer a viable crypto service from a single object.
+ * This is only used for test purposes and should not be used for production
+ * deployments.  Provides methods used for inspecting service state that
+ * support test.
+ */
+class standalone_crypto_client : public test_crypto_client
+{
+public:
+    standalone_crypto_client();
+    virtual ~standalone_crypto_client();
+
+    bool init();
+    bool deinit();
+
+    /* Test support methods */
+    bool keystore_reset_is_supported() const;
+    void keystore_reset();
+
+    bool keystore_key_exists_is_supported() const;
+    bool keystore_key_exists(uint32_t id) const;
+
+    bool keystore_keys_held_is_supported() const;
+    size_t keystore_keys_held() const;
+
+private:
+    bool is_fault_supported(enum fault_code code) const;
+
+    struct mbed_crypto_provider m_crypto_provider;
+    struct sfs_provider m_storage_provider;
+    struct direct_caller m_crypto_caller;
+    struct direct_caller m_storage_caller;
+    struct dummy_caller m_dummy_storage_caller;
+};
+
+#endif /* STANDALONE_CRYPTO_CLIENT_H */
diff --git a/components/service/crypto/client/test/test_crypto_client.cpp b/components/service/crypto/client/test/test_crypto_client.cpp
new file mode 100644
index 0000000..7232790
--- /dev/null
+++ b/components/service/crypto/client/test/test_crypto_client.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cassert>
+#include "test_crypto_client.h"
+
+test_crypto_client::factory *test_crypto_client::m_default_factory = NULL;
+
+test_crypto_client::test_crypto_client() :
+    crypto_client(),
+    m_is_initialized(false),
+    m_injected_faults()
+{
+
+}
+
+test_crypto_client::~test_crypto_client()
+{
+    deinit();
+}
+
+bool test_crypto_client::init()
+{
+    bool success = !m_is_initialized;
+    m_is_initialized = true;
+    return success;
+}
+
+bool test_crypto_client::deinit()
+{
+    bool success = m_is_initialized;
+    m_is_initialized = false;
+    return success;
+}
+
+test_crypto_client *test_crypto_client::create_default()
+{
+    /*
+     * It's mandatory to include a concrete test_crypto_client
+     * that registers its own factory in a deployment if you
+     * want to use this factory method.
+     */
+    assert(m_default_factory);
+    return m_default_factory->create();
+}
+
+void test_crypto_client::register_factory(factory *factory)
+{
+    /*
+     * Don't allow overriding of an existing default.  This
+     * will happen if two test_crypto_client components have
+     * been included in a deployment.
+     */
+    assert(!m_default_factory);
+    m_default_factory = factory;
+}
+
+void test_crypto_client::deregister_factory(factory *factory)
+{
+    if (m_default_factory == factory) m_default_factory = NULL;
+}
+
+bool test_crypto_client::inject_fault(enum fault_code code)
+{
+    assert(!m_is_initialized);
+
+    bool is_supported = is_fault_supported(code);
+    if (is_supported) m_injected_faults.push_back(code);
+    return is_supported;
+}
+
+bool test_crypto_client::is_fault_supported(enum fault_code code) const
+{
+    /* Derived classes may override this if fault simualtion is supported */
+    (void)code;
+    return false;
+}
+
+bool test_crypto_client::is_fault_injected(enum fault_code code) const
+{
+    bool is_injected = false;
+
+    for (size_t i = 0; !is_injected && i < m_injected_faults.size(); ++i) {
+        is_injected = (m_injected_faults[i] == code);
+    }
+
+    return is_injected;
+}
+
+/*
+ * Test methods by default are not supported.  Calling a non-supported
+ * method will trigger an assert.  A class derived from this one may
+ * pick and choose which test methods it supports.
+ */
+bool test_crypto_client::keystore_reset_is_supported() const { return false; }
+void test_crypto_client::keystore_reset() { assert(false); }
+
+bool test_crypto_client::keystore_key_exists_is_supported() const { return false; }
+bool test_crypto_client::keystore_key_exists(uint32_t id) const { (void)id; assert(false); return false; }
+
+bool test_crypto_client::keystore_keys_held_is_supported() const { return false; }
+size_t test_crypto_client::keystore_keys_held() const { assert(false); return 0; }
\ No newline at end of file
diff --git a/components/service/crypto/client/test/test_crypto_client.h b/components/service/crypto/client/test/test_crypto_client.h
new file mode 100644
index 0000000..5b927db
--- /dev/null
+++ b/components/service/crypto/client/test/test_crypto_client.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEST_CRYPTO_CLIENT_H
+#define TEST_CRYPTO_CLIENT_H
+
+#include <service/crypto/client/cpp/crypto_client.h>
+#include <vector>
+
+/*
+ * A specialization of the crypto_client class that extends it to add
+ * virtial methods to support test.  Depending on the deployment,
+ * real implementations of test methods may or may not exist.  For example,
+ * for a real distributed deployment where the key store is located in
+ * a secure processing environment, back door test methods that peak
+ * into the keystore are clearly not possible (or at least desirable!).
+ * Each virtual test method is paired with a is_supported() method to
+ * allow test cases to adapt to circumstances.
+ */
+class test_crypto_client : public crypto_client
+{
+public:
+    virtual ~test_crypto_client();
+
+    virtual bool init();
+    virtual bool deinit();
+
+    /*
+     * A factory method for contsructing the default class
+     * of test_crypto_client for the deployment.
+     */
+    static test_crypto_client *create_default();
+
+    /*
+     * Fault conditions that may be injected to allow error
+     * handling to be tested.
+     */
+    enum fault_code
+    {
+        FAILED_TO_DISCOVER_SECURE_STORAGE
+    };
+
+    /*
+     * Injects the specified fault.  May be called multiple
+     * times to inject different fault conditions.  Faults
+     * should be injected prior to calling the init() method
+     * to allow startup faults to be simulated.  Returns true
+     * if the fault condition can be simulated.
+     */
+    bool inject_fault(enum fault_code code);
+
+    /* Wipe all keys held in the keystore */
+    virtual bool keystore_reset_is_supported() const;
+    virtual void keystore_reset();
+
+    /* Check if a key is held in the keystore */
+    virtual bool keystore_key_exists_is_supported() const;
+    virtual bool keystore_key_exists(uint32_t id) const;
+
+    /* Return the number of keys in the keystore */
+    virtual bool keystore_keys_held_is_supported() const;
+    virtual size_t keystore_keys_held() const;
+
+    /* An abstract factory for constructing concrete test_crypto_client objects */
+    class factory
+    {
+    public:
+        virtual test_crypto_client *create() = 0;
+    };
+
+    static void register_factory(factory *factory);
+    static void deregister_factory(factory *factory);
+
+protected:
+    test_crypto_client();
+    virtual bool is_fault_supported(enum fault_code code) const;
+    bool is_fault_injected(enum fault_code code) const;
+
+private:
+    bool m_is_initialized;
+    std::vector<fault_code> m_injected_faults;
+    static factory *m_default_factory;
+};
+
+#endif /* STANDALONE_CRYPTO_CLIENT_H */