Attest: Register attestation key to crypto

Initial attestation key is provisoned in the SoC during
fabrication. It must be obtained from platform layer and
registered to crypto partition for further usage. This key
is used to sign the initial attestation token (IAT).

Unregister the initial attestation test suite from the
TFM_LVL == 3 compatible test suite list. This is needed,
because this patch introduces partition-to-partition calls
between attestation and crypto partition and crypto
partition currently does not support TFM_LVL == 3 execution.

Change-Id: I57d5b722753cc60084eca0ded852a7a7bcecd883
Signed-off-by: Tamas Ban <tamas.ban@arm.com>
diff --git a/secure_fw/services/crypto/crypto_key.c b/secure_fw/services/crypto/crypto_key.c
index e101420..f2708d5 100644
--- a/secure_fw/services/crypto/crypto_key.c
+++ b/secure_fw/services/crypto/crypto_key.c
@@ -27,7 +27,7 @@
  *        in bytes.
  */
 #ifndef TFM_CRYPTO_MAX_KEY_LENGTH
-#define TFM_CRYPTO_MAX_KEY_LENGTH (32)
+#define TFM_CRYPTO_MAX_KEY_LENGTH (64)
 #endif
 
 struct tfm_crypto_key_storage_s {
diff --git a/secure_fw/services/initial_attestation/CMakeLists.inc b/secure_fw/services/initial_attestation/CMakeLists.inc
index 17ee587..851b860 100644
--- a/secure_fw/services/initial_attestation/CMakeLists.inc
+++ b/secure_fw/services/initial_attestation/CMakeLists.inc
@@ -36,6 +36,7 @@
 		"${INITIAL_ATTESTATION_DIR}/tfm_attestation_secure_api.c"
 		"${INITIAL_ATTESTATION_DIR}/attestation_core.c"
 		"${INITIAL_ATTESTATION_DIR}/attestation_crypto_stub.c"
+		"${INITIAL_ATTESTATION_DIR}/attestation_key.c"
 		)
 
 	#Setting include directories
diff --git a/secure_fw/services/initial_attestation/attestation_key.c b/secure_fw/services/initial_attestation/attestation_key.c
new file mode 100644
index 0000000..c075668
--- /dev/null
+++ b/secure_fw/services/initial_attestation/attestation_key.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "attestation_key.h"
+#include <stdint.h>
+#include <stddef.h>
+#include "tfm_crypto_defs.h"
+#include "psa_crypto.h"
+#include "psa_crypto_platform.h"
+#include "psa_initial_attestation_api.h"
+#include "platform/include/tfm_plat_defs.h"
+#include "platform/include/tfm_plat_crypto_keys.h"
+
+/*!
+ * \var private_key_registered
+ *
+ * \brief Indicates whether the private part of the attestation key pair was
+ *        registered to crypto service or not.
+ */
+static uint32_t private_key_registered = 0;
+
+/*!
+ * \var public_key_registered
+ *
+ * \brief Indicates whether the public part of the attestation key pair was
+ *        registered to crypto service or not.
+ */
+static uint32_t public_key_registered = 0;
+
+/**
+ * \brief Map the curve type definition by RFC8152 (COSE) to PSA curve types
+ *
+ * \param[in]  cose_curve  COSE curve type definition \ref ecc_curve_t.
+ *
+ * \return    Return PSA curve type according to \ref psa_ecc_curve_t. If
+ *            mapping is not possible then return with USHRT_MAX.
+ */
+static inline psa_ecc_curve_t
+attest_map_elliptic_curve_type(enum ecc_curve_t cose_curve)
+{
+    psa_ecc_curve_t psa_curve;
+
+    /*FixMe: Mapping is not complete, missing ones: ED25519, ED448 */
+    switch (cose_curve) {
+    case P_256:
+        psa_curve = PSA_ECC_CURVE_SECP256R1;
+        break;
+    case P_384:
+        psa_curve = PSA_ECC_CURVE_SECP384R1;
+        break;
+    case P_521:
+        psa_curve = PSA_ECC_CURVE_SECP521R1;
+        break;
+    case X25519:
+        psa_curve = PSA_ECC_CURVE_CURVE25519;
+        break;
+    case X448:
+        psa_curve = PSA_ECC_CURVE_CURVE448;
+        break;
+    default:
+        psa_curve = USHRT_MAX;
+    }
+
+    return psa_curve;
+}
+
+enum psa_attest_err_t
+attest_register_initial_attestation_key(void)
+{
+    enum tfm_plat_err_t plat_res;
+    psa_ecc_curve_t psa_curve;
+    enum ecc_curve_t cose_curve;
+    struct ecc_key_t attest_key = {0};
+    uint8_t  key_buf[ECC_P_256_KEY_SIZE];
+    psa_key_type_t attest_key_type;
+    size_t public_key_size;
+    psa_status_t crypto_res;
+    psa_key_policy_t policy;
+
+    /* Key(s) should be unregistered at this point */
+    if (private_key_registered != 0 || public_key_registered != 0) {
+        return PSA_ATTEST_ERR_GENERAL;
+    }
+
+    /* Get the initial attestation key */
+    plat_res = tfm_plat_get_initial_attest_key(key_buf, sizeof(key_buf),
+                                               &attest_key, &cose_curve);
+
+    /* Check the availability of the private key */
+    if (plat_res != TFM_PLAT_ERR_SUCCESS || attest_key.priv_key == NULL) {
+        return PSA_ATTEST_ERR_GENERAL;
+    }
+
+    /* Mapping of COSE curve type to PSA curve types */
+    psa_curve = attest_map_elliptic_curve_type(cose_curve);
+    if (psa_curve == USHRT_MAX) {
+        return PSA_ATTEST_ERR_GENERAL;
+    }
+
+    /* Setup the key policy for private key */
+    psa_key_policy_init(&policy);
+    psa_key_policy_set_usage(&policy, PSA_KEY_USAGE_SIGN, 0); /* FixMe: alg */
+    crypto_res = psa_set_key_policy((psa_key_slot_t)ATTEST_PRIVATE_KEY_SLOT,
+                                    &policy);
+    if (crypto_res != PSA_SUCCESS) {
+        return PSA_ATTEST_ERR_GENERAL;
+    }
+
+    /* Set key type for private key */
+    /* FixMe: Use PSA_KEY_TYPE_ECC_KEYPAIR(psa_curve) when ECC key type will be
+     * supported in Crypto service
+     */
+    attest_key_type = PSA_KEY_TYPE_RAW_DATA;
+
+    /* Register private key to crypto service */
+    crypto_res = psa_import_key((psa_key_slot_t)ATTEST_PRIVATE_KEY_SLOT,
+                                attest_key_type,
+                                attest_key.priv_key,
+                                attest_key.priv_key_size);
+
+    if (crypto_res != PSA_SUCCESS) {
+        return PSA_ATTEST_ERR_GENERAL;
+    }
+    private_key_registered = 1;
+
+    /* Check whether public key is available, not mandatory */
+    if (attest_key.pubx_key == NULL) {
+        return PSA_ATTEST_ERR_SUCCESS;
+    }
+
+    /* Setup the key policy for public key */
+    psa_key_policy_init(&policy);
+    psa_key_policy_set_usage(&policy, PSA_KEY_USAGE_VERIFY, 0); /* FixMe: alg */
+    crypto_res = psa_set_key_policy((psa_key_slot_t)ATTEST_PUBLIC_KEY_SLOT,
+                                    &policy);
+    if (crypto_res != PSA_SUCCESS) {
+        return PSA_ATTEST_ERR_GENERAL;
+    }
+
+    /* Set key type for public key */
+    /* FixMe: Use PSA_KEY_TYPE_ECC_PUBLIC_KEY(psa_curve) when ECC key type will
+     * be supported in Crypto service
+     */
+    attest_key_type = PSA_KEY_TYPE_RAW_DATA;
+
+    /* Register public key to crypto service */
+    public_key_size = attest_key.pubx_key_size + attest_key.puby_key_size;
+
+    crypto_res = psa_import_key((psa_key_slot_t)ATTEST_PUBLIC_KEY_SLOT,
+                                attest_key_type,
+                                attest_key.pubx_key,
+                                public_key_size);
+
+    if (crypto_res != PSA_SUCCESS) {
+        return PSA_ATTEST_ERR_GENERAL;
+    }
+    public_key_registered = 1;
+
+    return PSA_ATTEST_ERR_SUCCESS;
+}
+
+enum psa_attest_err_t
+attest_unregister_initial_attestation_key(void)
+{
+    psa_status_t crypto_res;
+
+    /* Only private key is mandatory */
+    if (private_key_registered != 1) {
+        return PSA_ATTEST_ERR_GENERAL;
+    }
+
+    crypto_res = psa_destroy_key((psa_key_slot_t)ATTEST_PRIVATE_KEY_SLOT);
+    if (crypto_res != PSA_SUCCESS) {
+        return PSA_ATTEST_ERR_GENERAL;
+    }
+    private_key_registered = 0;
+
+    if (public_key_registered) {
+        crypto_res = psa_destroy_key((psa_key_slot_t)ATTEST_PUBLIC_KEY_SLOT);
+        if (crypto_res != PSA_SUCCESS) {
+            return PSA_ATTEST_ERR_GENERAL;
+        }
+        public_key_registered = 0;
+    }
+
+    return PSA_ATTEST_ERR_SUCCESS;
+}
diff --git a/secure_fw/services/initial_attestation/attestation_key.h b/secure_fw/services/initial_attestation/attestation_key.h
new file mode 100644
index 0000000..c565752
--- /dev/null
+++ b/secure_fw/services/initial_attestation/attestation_key.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __ATTESTATION_KEY_H__
+#define __ATTESTATION_KEY_H__
+
+#include "psa_initial_attestation_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \def ATTEST_PRIVATE_KEY_SLOT
+ *
+ * \brief Key slot number to store the initial attestation private key.
+ *
+ * Private key is used by initial attestation service to sign the
+ * initial attestation token (IAT).
+ */
+#define ATTEST_PRIVATE_KEY_SLOT (1u)
+
+/**
+ * \def ATTEST_PUBLIC_KEY_SLOT
+ *
+ * \brief Key slot number to store the initial attestation public key.
+ *
+ * Public key is used by initial attestation test suit to verify the signature
+ * of the initial attestation token (IAT).
+ */
+#define ATTEST_PUBLIC_KEY_SLOT  (2u)
+
+/**
+ * \brief Get the initial attestation key from platform layer and register it
+ *        to crypto service for further usage (signing or verification).
+ *
+ * Private key MUST be present on the device, public key is optional.
+ *
+ * \retval  PSA_ATTEST_ERR_SUCCESS   Key(s) was registered.
+ * \retval  PSA_ATTEST_ERR_GENERAL   Key(s) could not be registered.
+ */
+enum psa_attest_err_t attest_register_initial_attestation_key(void);
+
+/**
+ * \brief Unregister the initial attestation key(s) from crypto service to do
+ *        not occupy key slot(s).
+ *
+ * \retval  PSA_ATTEST_ERR_SUCCESS   Key(s) was unregistered.
+ * \retval  PSA_ATTEST_ERR_GENERAL   Key(s) could not be unregistered.
+ */
+enum psa_attest_err_t attest_unregister_initial_attestation_key(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ATTESTATION_KEY_H__ */
diff --git a/secure_fw/services/initial_attestation/manifest.yaml b/secure_fw/services/initial_attestation/manifest.yaml
index 0847262..4d607af 100644
--- a/secure_fw/services/initial_attestation/manifest.yaml
+++ b/secure_fw/services/initial_attestation/manifest.yaml
@@ -37,6 +37,7 @@
   "source_files": [
     "attestation_core.c",
     "attestation_crypto_stub.c",
+    "attestation_key.c",
   ],
   "tfm_linker_pattern": [
     "library_list": [
diff --git a/test/framework/non_secure_suites.c b/test/framework/non_secure_suites.c
index f7e1f07..724182b 100644
--- a/test/framework/non_secure_suites.c
+++ b/test/framework/non_secure_suites.c
@@ -21,8 +21,6 @@
 #if TFM_LVL == 3
 #ifdef SERVICES_TEST_NS
     /* List test cases which compliant with level 3 isolation */
-    /* Non-secure initial attestation service test cases */
-    {&register_testsuite_ns_attestation_interface, 0, 0, 0},
 
 #ifdef TFM_PARTITION_TEST_CORE
     /* Non-secure invert test cases */
diff --git a/test/framework/secure_suites.c b/test/framework/secure_suites.c
index b2572fd..0f7bb64 100644
--- a/test/framework/secure_suites.c
+++ b/test/framework/secure_suites.c
@@ -20,8 +20,6 @@
 #if TFM_LVL == 3
 #ifdef SERVICES_TEST_S
     /* List test cases which compliant with level 3 isolation */
-    /* Secure initial attestation service test cases */
-    {&register_testsuite_s_attestation_interface, 0, 0, 0},
 #endif /* SERVICES_TEST_S */
 
 #else /* TFM_LVL == 3 */