Attest: Fetch symmetric Initial Attestation Key

Implement attest_register_initial_attest_key() to fetch and register a
symmetric Initial Attestation Key (IAK).
Add tfm_plat_get_symmetric_iak() to receive the key raw data from
platform.

Add attest_get_signing_key_handle() to get the key handle of the
initial attestation key for signing IAT.
Replace attest_get_initial_attestation_private_key_handle() with
attest_get_signing_key_handle().

Also add a binary symmetric IAK file for token verification in
other tools.

Change-Id: Id2e3647cc85abd0eacbf2a0e53b6d2cd927acaaf
Signed-off-by: David Hu <david.hu@arm.com>
diff --git a/platform/ext/common/template/crypto_keys.c b/platform/ext/common/template/crypto_keys.c
index c5564e5..e005205 100644
--- a/platform/ext/common/template/crypto_keys.c
+++ b/platform/ext/common/template/crypto_keys.c
@@ -30,9 +30,15 @@
              {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \
               0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
 
+#ifdef SYMMETRIC_INITIAL_ATTESTATION
+extern const psa_algorithm_t tfm_attest_hmac_sign_alg;
+extern const uint8_t initial_attestation_hmac_sha256_key[];
+extern const size_t initial_attestation_hmac_sha256_key_size;
+#else /* SYMMETRIC_INITIAL_ATTESTATION */
 extern const psa_ecc_curve_t initial_attestation_curve_type;
 extern const uint8_t  initial_attestation_private_key[];
 extern const uint32_t initial_attestation_private_key_size;
+#endif /* SYMMETRIC_INITIAL_ATTESTATION */
 
 extern const struct tfm_plat_rotpk_t device_rotpk[];
 extern const uint32_t rotpk_key_cnt;
@@ -77,6 +83,33 @@
     return TFM_PLAT_ERR_SUCCESS;
 }
 
+#ifdef SYMMETRIC_INITIAL_ATTESTATION
+enum tfm_plat_err_t tfm_plat_get_symmetric_iak(uint8_t *key_buf,
+                                               size_t buf_len,
+                                               size_t *key_len,
+                                               psa_algorithm_t *key_alg)
+{
+    if (!key_buf || !key_len || !key_alg) {
+        return TFM_PLAT_ERR_INVALID_INPUT;
+    }
+
+    if (buf_len < initial_attestation_hmac_sha256_key_size) {
+        return TFM_PLAT_ERR_INVALID_INPUT;
+    }
+
+    /*
+     * Actual implementation may derive a key with other input, other than
+     * directly providing provisioned symmetric initial attestation key.
+     */
+    copy_key(key_buf, initial_attestation_hmac_sha256_key,
+             initial_attestation_hmac_sha256_key_size);
+
+    *key_alg = tfm_attest_hmac_sign_alg;
+    *key_len = initial_attestation_hmac_sha256_key_size;
+
+    return TFM_PLAT_ERR_SUCCESS;
+}
+#else /* SYMMETRIC_INITIAL_ATTESTATION */
 enum tfm_plat_err_t
 tfm_plat_get_initial_attest_key(uint8_t          *key_buf,
                                 uint32_t          size,
@@ -110,6 +143,7 @@
 
     return TFM_PLAT_ERR_SUCCESS;
 }
+#endif /* SYMMETRIC_INITIAL_ATTESTATION */
 
 #ifdef BL2
 enum tfm_plat_err_t
diff --git a/platform/ext/common/template/tfm_initial_attestation_key_material.c b/platform/ext/common/template/tfm_initial_attestation_key_material.c
index 65e91c0..25dec5c 100644
--- a/platform/ext/common/template/tfm_initial_attestation_key_material.c
+++ b/platform/ext/common/template/tfm_initial_attestation_key_material.c
@@ -11,6 +11,38 @@
 #include "psa/crypto_types.h"
 #include "psa/crypto_values.h"
 
+#ifdef SYMMETRIC_INITIAL_ATTESTATION
+/*
+ * This file contains the hard coded version of the secret key for HMAC.
+ *
+ * A HMAC-SHA256 key is 32 bytes long.
+ *
+ * This key is used to sign the initial attestation token in COSE_Mac0.
+ * The secret key is stored in raw format, without any encoding(ASN.1, COSE).
+ *
+ * #######  DO NOT USE THIS KEY IN PRODUCTION #######
+ */
+
+/* HMAC-SHA256 by default */
+const psa_algorithm_t tfm_attest_hmac_sign_alg = PSA_ALG_HMAC(PSA_ALG_SHA_256);
+
+/* Symmetric initial attestation key in raw format, without any encoding.
+ * It is used in HMAC-SHA256.
+ * It MUST be present on the device.
+ */
+TFM_LINK_SET_RO_IN_PARTITION_SECTION("TFM_SP_INITIAL_ATTESTATION")
+const uint8_t initial_attestation_hmac_sha256_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
+};
+
+TFM_LINK_SET_RO_IN_PARTITION_SECTION("TFM_SP_INITIAL_ATTESTATION")
+const size_t initial_attestation_hmac_sha256_key_size =
+        sizeof(initial_attestation_hmac_sha256_key);
+#else /* SYMMETRIC_INITIAL_ATTESTATION */
 /*
  * This file contains the hard coded version of the ECDSA P-256 secret key in:
  * platform/ext/common/template/tfm_initial_attestation_key.pem
@@ -43,3 +75,4 @@
 TFM_LINK_SET_RO_IN_PARTITION_SECTION("TFM_SP_INITIAL_ATTESTATION")
 const uint32_t initial_attestation_private_key_size =
         sizeof(initial_attestation_private_key);
+#endif /* SYMMETRIC_INITIAL_ATTESTATION */
diff --git a/platform/ext/common/template/tfm_symmetric_iak.key b/platform/ext/common/template/tfm_symmetric_iak.key
new file mode 100644
index 0000000..06f8bce
--- /dev/null
+++ b/platform/ext/common/template/tfm_symmetric_iak.key
Binary files differ
diff --git a/platform/include/tfm_plat_crypto_keys.h b/platform/include/tfm_plat_crypto_keys.h
index 7ee9570..f9934cd 100644
--- a/platform/include/tfm_plat_crypto_keys.h
+++ b/platform/include/tfm_plat_crypto_keys.h
@@ -82,6 +82,29 @@
                                                  uint8_t *key,
                                                  size_t key_size);
 
+#ifdef SYMMETRIC_INITIAL_ATTESTATION
+/**
+ * \brief Get the symmetric Initial Attestation Key (IAK)
+ *
+ * The device MUST contain a symmetric IAK, which is used to sign the token.
+ * So far only HMAC is supported in symmetric key algorithm based Initial
+ * Attestation.
+ * Keys must be provided in raw format, just binary data without any encoding
+ * (DER, COSE). Caller provides a buffer to copy all the raw data.
+ *
+ * \param[out]  key_buf     Buffer to store the initial attestation key.
+ * \param[in]   buf_len     The length of buffer.
+ * \param[out]  key_len     Buffer to carry the length of the initial
+ *                          attestation key.
+ * \param[out]  key_alg     The key algorithm. Only HMAC is supported so far.
+ *
+ * \return Returns error code specified in \ref tfm_plat_err_t
+ */
+enum tfm_plat_err_t tfm_plat_get_symmetric_iak(uint8_t *key_buf,
+                                               size_t buf_len,
+                                               size_t *key_len,
+                                               psa_algorithm_t *key_alg);
+#else /* SYMMETRIC_INITIAL_ATTESTATION */
 /**
  * \brief Get the initial attestation key
  *
@@ -115,6 +138,7 @@
                                 uint32_t          size,
                                 struct ecc_key_t *ecc_key,
                                 psa_ecc_curve_t  *curve_type);
+#endif /* SYMMETRIC_INITIAL_ATTESTATION */
 
 /**
  * \brief Get the hash of the corresponding Root of Trust Public Key for
diff --git a/secure_fw/partitions/initial_attestation/CMakeLists.inc b/secure_fw/partitions/initial_attestation/CMakeLists.inc
index ae61037..b0c18c1 100644
--- a/secure_fw/partitions/initial_attestation/CMakeLists.inc
+++ b/secure_fw/partitions/initial_attestation/CMakeLists.inc
@@ -41,10 +41,15 @@
 	"${INITIAL_ATTESTATION_DIR}/tfm_attestation.c"
 	"${INITIAL_ATTESTATION_DIR}/tfm_attestation_req_mngr.c"
 	"${INITIAL_ATTESTATION_DIR}/attestation_core.c"
-	"${INITIAL_ATTESTATION_DIR}/attestation_key.c"
 	"${INITIAL_ATTESTATION_DIR}/attest_token.c"
 	)
 
+if (SYMMETRIC_INITIAL_ATTESTATION)
+	list(APPEND ATTEST_C_SRC "${INITIAL_ATTESTATION_DIR}/attest_symmetric_key.c")
+else()
+	list(APPEND ATTEST_C_SRC "${INITIAL_ATTESTATION_DIR}/attestation_key.c")
+endif()
+
 if (ATTEST_INCLUDE_OPTIONAL_CLAIMS)
 	set_property(SOURCE ${ATTEST_C_SRC} APPEND PROPERTY COMPILE_DEFINITIONS INCLUDE_OPTIONAL_CLAIMS)
 endif()
diff --git a/secure_fw/partitions/initial_attestation/attest_symmetric_key.c b/secure_fw/partitions/initial_attestation/attest_symmetric_key.c
new file mode 100644
index 0000000..39aa112
--- /dev/null
+++ b/secure_fw/partitions/initial_attestation/attest_symmetric_key.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2019, Laurence Lundblade.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "attestation_key.h"
+#include "platform/include/tfm_plat_crypto_keys.h"
+#include "psa/crypto.h"
+
+/* Only support HMAC as MAC algorithm in COSE_Mac0 so far */
+#define SYMMETRIC_IAK_MAX_SIZE        PSA_MAC_MAX_SIZE
+
+/* Symmetric IAK handle */
+static psa_key_handle_t symmetric_iak_handle = 0;
+
+static psa_status_t destroy_iak(psa_key_handle_t *iak_handle)
+{
+    psa_status_t res;
+
+    res = psa_destroy_key(*iak_handle);
+
+    *iak_handle = 0;
+    return res;
+}
+
+enum psa_attest_err_t attest_register_initial_attestation_key(void)
+{
+    uint8_t key_buf[SYMMETRIC_IAK_MAX_SIZE];
+    psa_algorithm_t key_alg;
+    psa_key_handle_t key_handle;
+    size_t key_len;
+    enum tfm_plat_err_t plat_res;
+    psa_status_t psa_res;
+    psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+    if (symmetric_iak_handle) {
+        return PSA_ATTEST_ERR_GENERAL;
+    }
+
+    /* Get the symmetric initial attestation key for HMAC operation */
+    plat_res = tfm_plat_get_symmetric_iak(key_buf, sizeof(key_buf),
+                                          &key_len, &key_alg);
+    /* In case the buffer size was not checked, although unlikely */
+    if (sizeof(key_buf) < key_len) {
+        /*
+         * Something critical following key_buf may be overwritten.
+         * Directly jump into fatal error handling.
+         *
+         * TODO: Should be replaced by a call to psa_panic() when it
+         * becomes available.
+         */
+        while (1) {
+            ;
+        }
+    }
+    if (plat_res != TFM_PLAT_ERR_SUCCESS) {
+        return PSA_ATTEST_ERR_GENERAL;
+    }
+
+    /*
+     * Verify if HMAC algorithm is valid.
+     * According to COSE (RFC 8152), only SHA-256, SHA-384 and SHA-512 are
+     * supported in HMAC.
+     */
+    if ((key_alg != PSA_ALG_HMAC(PSA_ALG_SHA_256)) &&
+        (key_alg != PSA_ALG_HMAC(PSA_ALG_SHA_384)) &&
+        (key_alg != PSA_ALG_HMAC(PSA_ALG_SHA_512))) {
+        return PSA_ATTEST_ERR_GENERAL;
+    }
+
+    /* Setup the key attributes */
+    psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_SIGN);
+    psa_set_key_algorithm(&key_attributes, key_alg);
+    psa_set_key_type(&key_attributes, PSA_KEY_TYPE_HMAC);
+
+    /* Register the symmetric key to Crypto service */
+    psa_res = psa_import_key(&key_attributes, key_buf, key_len, &key_handle);
+    if (psa_res != PSA_SUCCESS) {
+        return PSA_ATTEST_ERR_GENERAL;
+    }
+
+    symmetric_iak_handle = key_handle;
+
+    return PSA_ATTEST_ERR_SUCCESS;
+}
+
+enum psa_attest_err_t attest_unregister_initial_attestation_key(void)
+{
+    if (!symmetric_iak_handle) {
+        return PSA_ATTEST_ERR_GENERAL;
+    }
+
+    destroy_iak(&symmetric_iak_handle);
+
+    return PSA_ATTEST_ERR_SUCCESS;
+}
+
+enum psa_attest_err_t
+attest_get_signing_key_handle(psa_key_handle_t *key_handle)
+{
+    if (!symmetric_iak_handle) {
+        return PSA_ATTEST_ERR_GENERAL;
+    }
+
+    *key_handle = symmetric_iak_handle;
+
+    return PSA_ATTEST_ERR_SUCCESS;
+}
diff --git a/secure_fw/partitions/initial_attestation/attest_token.c b/secure_fw/partitions/initial_attestation/attest_token.c
index f3f8d70..3060df4 100644
--- a/secure_fw/partitions/initial_attestation/attest_token.c
+++ b/secure_fw/partitions/initial_attestation/attest_token.c
@@ -118,8 +118,7 @@
 
     t_cose_sign1_sign_init(&(me->signer_ctx), t_cose_options, cose_alg_id);
 
-    attest_ret =
-        attest_get_initial_attestation_private_key_handle(&private_key);
+    attest_ret = attest_get_signing_key_handle(&private_key);
     if (attest_ret != PSA_ATTEST_ERR_SUCCESS) {
         return ATTEST_TOKEN_ERR_SIGNING_KEY;
     }
diff --git a/secure_fw/partitions/initial_attestation/attestation_core.c b/secure_fw/partitions/initial_attestation/attestation_core.c
index 6b239d3..0399ceb 100644
--- a/secure_fw/partitions/initial_attestation/attestation_core.c
+++ b/secure_fw/partitions/initial_attestation/attestation_core.c
@@ -931,6 +931,19 @@
     return error_mapping_to_psa_status_t(attest_err);
 }
 
+#ifdef SYMMETRIC_INITIAL_ATTESTATION
+psa_status_t
+initial_attest_get_public_key(const psa_invec  *in_vec,  uint32_t num_invec,
+                                    psa_outvec *out_vec, uint32_t num_outvec)
+{
+    (void)in_vec;
+    (void)num_invec;
+    (void)out_vec;
+    (void)num_outvec;
+
+    return PSA_ERROR_NOT_SUPPORTED;
+}
+#else /* SYMMETRIC_INITIAL_ATTESTATION */
 psa_status_t
 initial_attest_get_public_key(const psa_invec  *in_vec,  uint32_t num_invec,
                                     psa_outvec *out_vec, uint32_t num_outvec)
@@ -978,3 +991,4 @@
 error:
     return error_mapping_to_psa_status_t(attest_err);
 }
+#endif /* SYMMETRIC_INITIAL_ATTESTATION */
diff --git a/secure_fw/partitions/initial_attestation/attestation_key.c b/secure_fw/partitions/initial_attestation/attestation_key.c
index 58e690f..f0e7e99 100644
--- a/secure_fw/partitions/initial_attestation/attestation_key.c
+++ b/secure_fw/partitions/initial_attestation/attestation_key.c
@@ -128,7 +128,7 @@
 }
 
 enum psa_attest_err_t
-attest_get_initial_attestation_private_key_handle(psa_key_handle_t *handle)
+attest_get_signing_key_handle(psa_key_handle_t *handle)
 {
     if (attestation_key_handle == ATTEST_KEY_HANDLE_NOT_LOADED) {
         return PSA_ATTEST_ERR_GENERAL;
diff --git a/secure_fw/partitions/initial_attestation/attestation_key.h b/secure_fw/partitions/initial_attestation/attestation_key.h
index cb35a94..5525479 100644
--- a/secure_fw/partitions/initial_attestation/attestation_key.h
+++ b/secure_fw/partitions/initial_attestation/attestation_key.h
@@ -8,6 +8,7 @@
 #ifndef __ATTESTATION_KEY_H__
 #define __ATTESTATION_KEY_H__
 
+#include "attestation.h"
 #include "psa/initial_attestation.h"
 #include "psa/crypto.h"
 #include "q_useful_buf.h"
@@ -40,16 +41,19 @@
 attest_unregister_initial_attestation_key();
 
 /**
- * \brief Get a handle to the attestion private key.
+ * \brief Get the handle of the key for signing token
+ *        In asymmetric key algorithm based initial attestation, it is the
+ *        handle of the initial attestation private key.
+ *        In symmetric key algorithm based initial attestation, it is the
+ *        handle of symmetric initial attestation key.
  *
- * \param[out] key_handle Key handle for private key
+ * \param[out] key_handle            The handle of the key for signing token.
  *
- * \retval  PSA_ATTEST_ERR_SUCCESS   Private key was successfully returned.
- * \retval  PSA_ATTEST_ERR_GENERAL   Private key could not be returned.
+ * \retval  PSA_ATTEST_ERR_SUCCESS   Key handle was successfully returned.
+ * \retval  PSA_ATTEST_ERR_GENERAL   Key handle could not be returned.
  */
-
 enum psa_attest_err_t
-attest_get_initial_attestation_private_key_handle(psa_key_handle_t *key_handle);
+attest_get_signing_key_handle(psa_key_handle_t *key_handle);
 
 /**
  * \brief Get the public key derived from the initial attestation private key.