DPE: Support host build

If `-DHOST_BUILD=ON` is added to the CMake command line
then the DPE library will be built as a stand-alone
Linux program. Not tested on Windows.

It allows the rapid development, build and test cycles
of the DPE library in a native environment without
the need to execute the code on FVP.

Change-Id: I4923c2aba9636d96bfe1aca4e7d5b731270382fa
Signed-off-by: Tamas Ban <tamas.ban@arm.com>
diff --git a/partitions/dice_protection_environment/test/host/CMakeLists.txt b/partitions/dice_protection_environment/test/host/CMakeLists.txt
new file mode 100644
index 0000000..4576d71
--- /dev/null
+++ b/partitions/dice_protection_environment/test/host/CMakeLists.txt
@@ -0,0 +1,132 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2024, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+cmake_minimum_required(VERSION 3.15)
+
+Project("DPE Host Build" LANGUAGES C)
+
+set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
+set(CMAKE_POLICY_DEFAULT_CMP0048 NEW)
+set(ENABLE_TESTING OFF)
+set(ENABLE_PROGRAMS OFF)
+set(MBEDTLS_FATAL_WARNINGS OFF)
+set(ENABLE_DOCS OFF)
+set(INSTALL_MBEDTLS_HEADERS OFF)
+
+############################### Crypto Library #################################
+
+add_subdirectory(${MBEDCRYPTO_PATH} mbedtls)
+
+############################### QCBOR Library ##################################
+
+add_subdirectory(${QCBOR_PATH} qcbor)
+
+# Entirely disable the floating-point support
+target_compile_definitions(qcbor
+    PRIVATE
+        QCBOR_DISABLE_FLOAT_HW_USE
+        QCBOR_OPT_DISABLE_FLOAT_PREFERRED
+        QCBOR_OPT_DISABLE_FLOAT_ALL
+)
+
+############################### T_COSE Library #################################
+
+set(T_COSE_PATH ${TFM_PATH}/lib/ext/t_cose)
+
+# Empty target just to make build working
+add_library(tfm_config INTERFACE)
+
+# Empty target just to make build working
+add_library(psa_crypto_config INTERFACE)
+
+include(${T_COSE_PATH}/tfm_t_cose.cmake)
+
+add_library(t_cose STATIC EXCLUDE_FROM_ALL)
+
+target_link_libraries(t_cose
+    PUBLIC
+        tfm_t_cose_defs
+    PRIVATE
+        tfm_t_cose_common
+        qcbor
+        mbedtls
+)
+
+############################### DPE Library ####################################
+
+add_library(dpe_lib STATIC EXCLUDE_FROM_ALL)
+
+target_sources(dpe_lib
+    PUBLIC
+        ../../interface/src/dpe_cmd_encode.c
+    PRIVATE
+        ../../dpe_certificate.c
+        ../../dpe_cmd_decode.c
+        ../../dpe_context_mngr.c
+        ../../dpe_crypto_interface.c
+        ../../dpe_log.c
+)
+
+target_include_directories(dpe_lib
+    PUBLIC
+        ../../interface/include
+        ../..
+        ${TFM_PATH}/platform/ext/target/arm/rse/common       # platform_locality.h
+        ${TFM_PATH}/platform/ext/target/arm/rse/common/dpe   # dpe_plat.h
+        ${TFM_PATH}/secure_fw/partitions/lib/runtime/include # tfm_sp_log.h
+    PRIVATE
+        ${TFM_PATH}/secure_fw/include                        # array.h
+
+)
+
+# Linked due to the headers
+target_link_libraries(dpe_lib
+    PUBLIC
+        t_cose
+        mbedtls
+        qcbor
+)
+
+target_compile_definitions(dpe_lib
+    PUBLIC
+        TFM_PARTITION_LOG_LEVEL=${TFM_PARTITION_LOG_LEVEL}
+    PRIVATE
+        DPE_TEST_MODE
+)
+
+############################### DPE Host App ###################################
+
+add_executable(dpe_host)
+
+target_sources(dpe_host
+    PRIVATE
+        ./cmd.c
+        ./main.c
+        ./plat.c
+        ./root_keys.c
+        ./client.c
+)
+
+target_link_libraries(dpe_host
+    PUBLIC
+        dpe_lib
+)
+
+target_include_directories(dpe_host
+    PRIVATE
+        .
+)
+
+target_compile_definitions(dpe_host
+    PRIVATE
+)
+
+target_compile_options(dpe_host
+    PRIVATE
+        -Og
+        -g
+)
diff --git a/partitions/dice_protection_environment/test/host/DeriveContext.cbor b/partitions/dice_protection_environment/test/host/DeriveContext.cbor
new file mode 100644
index 0000000..64de303
--- /dev/null
+++ b/partitions/dice_protection_environment/test/host/DeriveContext.cbor
Binary files differ
diff --git a/partitions/dice_protection_environment/test/host/client.c b/partitions/dice_protection_environment/test/host/client.c
new file mode 100644
index 0000000..ec96c70
--- /dev/null
+++ b/partitions/dice_protection_environment/test/host/client.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "dpe_client.h"
+#include "dpe_cmd_decode.h"
+
+#define CLIENT_ID_NS -1
+
+int32_t dpe_client_call(const char *cmd_input, size_t cmd_input_size,
+                        char *cmd_output, size_t *cmd_output_size)
+{
+    int32_t err;
+
+    err = dpe_command_decode(CLIENT_ID_NS,
+                             cmd_input, cmd_input_size,
+                             cmd_output, cmd_output_size);
+
+    return err;
+}
diff --git a/partitions/dice_protection_environment/test/host/cmd.c b/partitions/dice_protection_environment/test/host/cmd.c
new file mode 100644
index 0000000..2256749
--- /dev/null
+++ b/partitions/dice_protection_environment/test/host/cmd.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "dice_protection_environment.h"
+#include "dpe_client.h"
+#include "dpe_context_mngr.h"
+#include "dpe_cmd_decode.h"
+#include "dpe_cmd_encode.h"
+
+#include "cmd.h"
+#include "root_keys.h"
+
+#include "tfm_sp_log.h"
+
+#define CLIENT_ID_NS -1
+
+static void print_buf(const unsigned char *buf, size_t size)
+{
+    size_t i;
+
+    if (buf != NULL) {
+        for (i = 0; i < size; ++i) {
+            if ((i & 0xF) == 0) {
+                LOG_DBGFMT("\r\n");
+            }
+            if (buf[i] < 0x10) {
+                LOG_DBGFMT(" 0%x", buf[i]);
+            } else {
+                LOG_DBGFMT(" %x", buf[i]);
+            }
+        }
+    }
+    LOG_DBGFMT("\r\n");
+    LOG_DBGFMT("\r\n");
+}
+
+static dpe_error_t
+cbor_cmd(const char *cmd_in_buf, size_t cmd_in_size, int *context_handle)
+{
+    char cmd_out_buf[2 * 4096];
+    size_t cmd_out_size = sizeof(cmd_out_buf);
+    dpe_error_t err;
+
+    (void)context_handle;
+
+    LOG_DBGFMT("DPE request (%ld):\n", cmd_in_size);
+    print_buf(cmd_in_buf, cmd_in_size);
+
+    err = dpe_command_decode(CLIENT_ID_NS,
+                             cmd_in_buf, cmd_in_size,
+                             cmd_out_buf, &cmd_out_size);
+
+    LOG_DBGFMT("DPE response (%ld):\n", cmd_out_size);
+    print_buf(cmd_out_buf, cmd_out_size);
+
+    return err;
+}
+
+/*
+ * DPE Library Init:
+ * - crypto_lib
+ * - platform
+ * - context manager
+ */
+void dpe_lib_init(int *context_handle)
+{
+    int ret;
+    dpe_error_t err;
+
+    ret = psa_crypto_init();
+    if (ret != 0) {
+        printf("ERROR: Crypto init failed! (%d)\n", ret);
+        exit(1);
+    }
+
+    ret = register_rot_cdi();
+    if (ret != 0) {
+        printf("ERROR: RoT CDI registration failed! (%d)\n", ret);
+        exit(1);
+    }
+
+    ret = register_root_attest_key();
+    if (ret != 0) {
+        printf("ERROR: Root attest key registration failed! (%d)\n", ret);
+        exit(1);
+    }
+
+    err = initialise_context_mngr(context_handle);
+    if (err != DPE_NO_ERROR) {
+        printf("ERROR: Context manager init failed (%d)\n", err);
+        exit(1);
+    }
+}
+
+dpe_error_t exec_dpe_cmd(enum cmd cmd, const char *cmd_in_buf,
+                         size_t cmd_in_size, int *context_handle)
+{
+    switch(cmd) {
+    case CBOR:
+        return cbor_cmd(cmd_in_buf, cmd_in_size, context_handle);
+    default:
+        printf("ERROR: Unknown command\n");
+        exit(1);
+    }
+}
diff --git a/partitions/dice_protection_environment/test/host/cmd.h b/partitions/dice_protection_environment/test/host/cmd.h
new file mode 100644
index 0000000..0c6ad86
--- /dev/null
+++ b/partitions/dice_protection_environment/test/host/cmd.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef _CMD_H_
+#define _CMD_H_
+
+enum cmd {
+    CBOR, /* CBOR encoded */
+    MAX_CMD_VAL
+};
+
+int exec_dpe_cmd(enum cmd cmd, const char *cmd_in_buf, size_t cmd_in_size, int *context_handle);
+
+void dpe_lib_init(int *context_handle);
+
+#endif /* _CMD_H_ */
diff --git a/partitions/dice_protection_environment/test/host/main.c b/partitions/dice_protection_environment/test/host/main.c
new file mode 100644
index 0000000..9a72951
--- /dev/null
+++ b/partitions/dice_protection_environment/test/host/main.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "dice_protection_environment.h"
+#include "tfm_sp_log.h"
+
+#include "cmd.h"
+
+static int read_cmd(const char path[], char *cmd_buf, size_t *cmd_buf_size)
+{
+    FILE *fd;
+    size_t cmd_size;
+
+    if ((fd = fopen(path, "r")) == NULL) {
+        printf("ERROR: File (%s) cannot be opened.\n", path);
+        return -1;
+    }
+
+    fseek(fd, 0, SEEK_END);
+    cmd_size = ftell(fd);
+    rewind(fd);
+
+    if (*cmd_buf_size < cmd_size) {
+        printf("ERROR: cmd_buf is too small\n");
+        return -1;
+    }
+
+    for (size_t i = 0; i < cmd_size; ++i) {
+        cmd_buf[i] = fgetc(fd);
+    }
+    *cmd_buf_size = cmd_size;
+
+    fclose(fd);
+
+    return 0;
+}
+
+int main(int argc, char **argv)
+{
+    int context_handle;
+    int ret;
+    char cmd_in_buf[4096] = {0};
+    size_t cmd_in_size = sizeof(cmd_in_buf);
+    dpe_error_t err;
+
+    dpe_lib_init(&context_handle);
+
+    if (argc == 2) {
+        ret = read_cmd(argv[1], cmd_in_buf, &cmd_in_size);
+        if (ret < 0) {
+            exit(1);
+        }
+
+        err = exec_dpe_cmd(CBOR, cmd_in_buf, cmd_in_size, &context_handle);
+        if (err != DPE_NO_ERROR) {
+            printf("DPE command decode/execution failed (%d)\n", ret);
+            exit(1);
+        }
+    } else {
+        printf("Wrong number of input params! It must be 1!\n");
+        exit(1);
+    }
+
+    exit(0);
+}
diff --git a/partitions/dice_protection_environment/test/host/plat.c b/partitions/dice_protection_environment/test/host/plat.c
new file mode 100644
index 0000000..3be08bd
--- /dev/null
+++ b/partitions/dice_protection_environment/test/host/plat.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdio.h>
+
+#include "dpe_plat.h"
+#include "tfm_sp_log.h"
+
+extern psa_key_id_t rot_cdi_id;
+extern psa_key_id_t root_attest_key_id;
+
+psa_key_id_t dpe_plat_get_rot_cdi_key_id(void)
+{
+    return rot_cdi_id;
+}
+
+psa_key_id_t dpe_plat_get_root_attest_key_id(void)
+{
+    return root_attest_key_id;
+}
+
+
+int dpe_plat_share_context_with_ap(int ctx_handle)
+{
+    return 0;
+}
+
+
+int32_t dpe_plat_get_client_locality(int32_t client_id)
+{
+    return 0;
+}
diff --git a/partitions/dice_protection_environment/test/host/root_keys.c b/partitions/dice_protection_environment/test/host/root_keys.c
new file mode 100644
index 0000000..83e09c1
--- /dev/null
+++ b/partitions/dice_protection_environment/test/host/root_keys.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "psa/crypto.h"
+
+/*
+ * The DPE implementation assumes that the runtime has no access to the UDS and
+ * a previous boot stage already done the RoT CDI derivation from the UDS.
+ * Therefore when the RoT certificate is created the RoT CDI derivation step is
+ * skipped. The RoT CDI is assumed to be already known by the Crypto service.
+ * It can be referenced by a handle: rot_cdi_id.
+ */
+psa_key_id_t rot_cdi_id = PSA_KEY_ID_NULL;
+
+/*
+ * Use this hard coded data as the RoT CDI. In normal operation this value is
+ * derived by BL1_1.
+ */
+static const char rot_cdi[] = {
+    0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
+    0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
+    0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
+    0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
+};
+
+/* In normal operation this is done by Crypto service init */
+int register_rot_cdi(void)
+{
+    psa_status_t status;
+    psa_key_attributes_t attr = psa_key_attributes_init();
+    psa_algorithm_t algorithm = PSA_ALG_HKDF(PSA_ALG_SHA_256);
+
+    /* Setup the key policy */
+    psa_set_key_bits(&attr, 256);
+    psa_set_key_algorithm(&attr, algorithm);
+    psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT);
+    psa_set_key_type(&attr, PSA_KEY_TYPE_DERIVE);
+
+    status = psa_import_key(&attr, rot_cdi, sizeof(rot_cdi), &rot_cdi_id);
+    if (status != PSA_SUCCESS) {
+        return status;
+    }
+
+    return PSA_SUCCESS;
+}
+
+psa_key_id_t root_attest_key_id = PSA_KEY_ID_NULL;
+
+/* The RoT certificate is signed by the root attestation key. */
+static const char root_attest_key[] = {
+    0xA9, 0xB4, 0x54, 0xB2, 0x6D, 0x6F, 0x90, 0xA4,
+    0xEA, 0x31, 0x19, 0x35, 0x64, 0xCB, 0xA9, 0x1F,
+    0xEC, 0x6F, 0x9A, 0x00, 0x2A, 0x7D, 0xC0, 0x50,
+    0x4B, 0x92, 0xA1, 0x93, 0x71, 0x34, 0x58, 0x5F,
+};
+
+/* In normal operation this is done by Crypto service init */
+int register_root_attest_key(void)
+{
+    psa_status_t status;
+    psa_key_attributes_t attr = psa_key_attributes_init();
+    psa_algorithm_t algorithm = PSA_ALG_ECDSA(PSA_ALG_SHA_256);
+    psa_key_type_t type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1);
+
+    /* Setup the key policy */
+    psa_set_key_type(&attr, type);
+    psa_set_key_algorithm(&attr, algorithm);
+    psa_set_key_bits(&attr, 256);
+    psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_EXPORT);
+
+    status = psa_import_key(&attr, root_attest_key, sizeof(root_attest_key),
+                            &root_attest_key_id);
+    if (status != PSA_SUCCESS) {
+        return status;
+    }
+
+    return PSA_SUCCESS;
+}
diff --git a/partitions/dice_protection_environment/test/host/root_keys.h b/partitions/dice_protection_environment/test/host/root_keys.h
new file mode 100644
index 0000000..6e6171e
--- /dev/null
+++ b/partitions/dice_protection_environment/test/host/root_keys.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef _ROOT_KEYS_H_
+#define _ROOT_KEYS_H_
+
+int register_rot_cdi(void);
+int register_root_attest_key(void);
+
+#endif /* _ROOT_KEYS_H_ */