Attest: Get device claims from boot status

Boot status might contain general attributes of the device,
which does not belongs to any SW components:
 - boot seed
 - HW version
 - security lifecycle
These device attributes might be provided by bootloader or runtime
software. They are retrieved from boot status if presents, if does
not then callback function is called to get them from runtime
software.

Change-Id: I2e803d19fc15620f07d29ef028bfc794cecc861f
Signed-off-by: Tamas Ban <tamas.ban@arm.com>
diff --git a/bl2/include/tfm_boot_status.h b/bl2/include/tfm_boot_status.h
index ca1679a..dbcc6ce 100644
--- a/bl2/include/tfm_boot_status.h
+++ b/bl2/include/tfm_boot_status.h
@@ -88,12 +88,12 @@
  * component. But they might be part of the boot status.
  */
 #define BOOT_SEED          0x00
-#define HW_ID              0x01
+#define HW_VERSION         0x01
 #define SECURITY_LIFECYCLE 0x02
 
 /* Minor numbers (12 bit) to identify attestation service related data */
 #define TLV_MINOR_IAS_BOOT_SEED       ((SW_GENERAL << 6) | BOOT_SEED)
-#define TLV_MINOR_IAS_HW_ID           ((SW_GENERAL << 6) | HW_ID)
+#define TLV_MINOR_IAS_HW_VERSION      ((SW_GENERAL << 6) | HW_VERSION)
 #define TLV_MINOR_IAS_SLC             ((SW_GENERAL << 6) | SECURITY_LIFECYCLE)
 
 /* Bootloader - It can be more stage */
diff --git a/secure_fw/services/initial_attestation/attestation_core.c b/secure_fw/services/initial_attestation/attestation_core.c
index 6e20954..8afdbe1 100644
--- a/secure_fw/services/initial_attestation/attestation_core.c
+++ b/secure_fw/services/initial_attestation/attestation_core.c
@@ -166,6 +166,48 @@
 }
 
 /*!
+ * \brief Static function to look up specific claim belongs to SW_GENERAL module
+ *
+ * \param[in]   claim    The claim ID to look for
+ * \param[out]  tlv_len  Length of the shared data entry
+ * \param[out]  tlv_ptr  Pointer to a shared data entry which belongs to the
+ *                       SW_GENERAL module.
+ *
+ * \retval    -1          Error, boot status is malformed
+ * \retval     0          Entry not found
+ * \retval     1          Entry found
+ */
+static int32_t attest_get_tlv_by_id(uint8_t    claim,
+                                    uint16_t  *tlv_len,
+                                    uint8_t  **tlv_ptr)
+{
+    uint8_t tlv_id;
+    uint8_t module = SW_GENERAL;
+    int32_t found;
+
+    /* Ensure that look up starting from the beginning of the boot status */
+    *tlv_ptr = NULL;
+
+    /* Look up specific TLV entry which belongs to SW_GENERAL module */
+    do {
+        /* Look up next entry */
+        found = attest_get_tlv_by_module(module, &tlv_id,
+                                         tlv_len, tlv_ptr);
+        if (found != 1) {
+            break;
+        }
+        /* At least one entry was found which belongs to SW_GENERAL,
+         * check whether this one is looked for
+         */
+        if (claim == tlv_id) {
+            break;
+        }
+    } while (found == 1);
+
+    return found;
+}
+
+/*!
  * \brief Static function to add SW component related claims to attestation
  *        token in CBOR format.
  *
@@ -424,15 +466,28 @@
     __attribute__ ((aligned(4)))
     uint8_t boot_seed[BOOT_SEED_SIZE];
     enum tfm_plat_err_t res;
-    struct useful_buf_c claim_value;
+    struct useful_buf_c claim_value = {0};
+    uint16_t tlv_len;
+    uint8_t *tlv_ptr = NULL;
+    int32_t found = 0;
 
-    res = tfm_plat_get_boot_seed(sizeof(boot_seed), boot_seed);
-    if (res != TFM_PLAT_ERR_SUCCESS) {
-        return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
+    /* First look up BOOT_SEED in boot status, it might comes from bootloader */
+    found = attest_get_tlv_by_id(BOOT_SEED, &tlv_len, &tlv_ptr);
+    if (found == 1) {
+        claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE;
+        claim_value.len = tlv_len - SHARED_DATA_ENTRY_HEADER_SIZE;
+    } else {
+        /* If not found in boot status then use callback function to get it
+         * from runtime SW
+         */
+        res = tfm_plat_get_boot_seed(sizeof(boot_seed), boot_seed);
+        if (res != TFM_PLAT_ERR_SUCCESS) {
+            return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
+        }
+        claim_value.ptr = boot_seed;
+        claim_value.len = BOOT_SEED_SIZE;
     }
 
-    claim_value.ptr = boot_seed;
-    claim_value.len  = BOOT_SEED_SIZE;
     attest_token_add_bstr(token_ctx,
                           EAT_CBOR_ARM_LABEL_BOOT_SEED,
                           &claim_value);
@@ -531,15 +586,30 @@
     uint8_t hw_version[HW_VERSION_MAX_SIZE];
     enum tfm_plat_err_t res_plat;
     uint32_t size = sizeof(hw_version);
-    struct useful_buf_c claim_value;
+    struct useful_buf_c claim_value = {0};
+    uint16_t tlv_len;
+    uint8_t *tlv_ptr = NULL;
+    int32_t found = 0;
 
-    res_plat = tfm_plat_get_hw_version(&size, hw_version);
-    if (res_plat != TFM_PLAT_ERR_SUCCESS) {
-        return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
+    /* First look up HW version in boot status, it might comes
+     * from bootloader
+     */
+    found = attest_get_tlv_by_id(HW_VERSION, &tlv_len, &tlv_ptr);
+    if (found == 1) {
+        claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE;
+        claim_value.len = tlv_len - SHARED_DATA_ENTRY_HEADER_SIZE;
+    } else {
+        /* If not found in boot status then use callback function to get it
+         * from runtime SW
+         */
+        res_plat = tfm_plat_get_hw_version(&size, hw_version);
+        if (res_plat != TFM_PLAT_ERR_SUCCESS) {
+            return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
+        }
+        claim_value.ptr = hw_version;
+        claim_value.len = size;
     }
 
-    claim_value.ptr = hw_version;
-    claim_value.len  = size;
     attest_token_add_tstr(token_ctx,
                           EAT_CBOR_ARM_LABEL_HW_VERSION,
                           &claim_value);
@@ -585,8 +655,37 @@
 attest_add_security_lifecycle_claim(struct attest_token_ctx *token_ctx)
 {
     enum tfm_security_lifecycle_t security_lifecycle;
+    uint32_t slc_value;
+    int32_t res;
+    struct useful_buf_c claim_value = {0};
+    uint16_t tlv_len;
+    uint8_t *tlv_ptr = NULL;
+    int32_t found = 0;
 
-    security_lifecycle = tfm_attest_hal_get_security_lifecycle();
+    /* First look up lifecycle state in boot status, it might comes
+     * from bootloader
+     */
+    found = attest_get_tlv_by_id(SECURITY_LIFECYCLE, &tlv_len, &tlv_ptr);
+    if (found == 1) {
+        claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE;
+        claim_value.len = tlv_len - SHARED_DATA_ENTRY_HEADER_SIZE;
+        res = get_uint(claim_value.ptr, claim_value.len, &slc_value);
+        if (res) {
+            return PSA_ATTEST_ERR_GENERAL;
+        }
+        security_lifecycle = (enum tfm_security_lifecycle_t)slc_value;
+    } else {
+        /* If not found in boot status then use callback function to get it
+         * from runtime SW
+         */
+        security_lifecycle = tfm_attest_hal_get_security_lifecycle();
+    }
+
+    /* Sanity check */
+    if (security_lifecycle < TFM_SLC_UNKNOWN ||
+        security_lifecycle > TFM_SLC_DECOMMISSIONED) {
+        return PSA_ATTEST_ERR_GENERAL;
+    }
 
     attest_token_add_integer(token_ctx,
                              EAT_CBOR_ARM_LABEL_SECURITY_LIFECYCLE,