Boot: Save SW component's boot satus info

Bootloader must provide certain attributes of the
authenticated SW components to the runtime SW.
These informations are included to the initial
attestation token.

Change-Id: I35f9cd4321e1f8ca776303bcb1e32d11cb5dabe6
Signed-off-by: Tamas Ban <tamas.ban@arm.com>
diff --git a/bl2/src/boot_record.c b/bl2/src/boot_record.c
index b12b9e9..e24d2c4 100644
--- a/bl2/src/boot_record.c
+++ b/bl2/src/boot_record.c
@@ -8,8 +8,11 @@
 #include "boot_record.h"
 #include "tfm_boot_status.h"
 #include "target.h"
+#include "../ext/mcuboot/bootutil/include/bootutil/image.h"
+#include "../ext/mcuboot/include/flash_map/flash_map.h"
 #include <stdint.h>
 #include <string.h>
+#include <stdio.h>
 
 /*!
  * \var shared_memory_init_done
@@ -33,6 +36,217 @@
  */
 #define SHARED_MEMORY_INITIALZED   (1u)
 
+/*!
+ * \brief Add the measurement data of SW component to the shared memory area
+ *
+ * Measurements data are:
+ *  - measurement value:  Hash of the image, read out from the image's manifest
+ *                        section.
+ *  - measurement type:   Short test description: SHA256, etc.
+ *  - signer ID:          Hash of the image public key, read out from the
+ *                        image's manifest section.
+ *
+ * \param[in]  sw_module  Identifier of the SW component
+ * \param[in]  hdr        Pointer to the image header stored in RAM
+ * \param[in]  fap        Pointer to the flash area where image is stored
+ *
+ * \return Returns error code as specified in \ref boot_status_err_t
+ */
+static enum boot_status_err_t
+boot_save_sw_measurements(uint8_t sw_module,
+                          const struct image_header *hdr,
+                          const struct flash_area *fap)
+{
+    struct image_tlv_info tlv_header;
+    struct image_tlv tlv_entry;
+    uintptr_t tlv_end, offset;
+    uint8_t buf[32];
+    int32_t res;
+    uint16_t ias_minor;
+    enum shared_memory_err_t res2;
+    char measure_type[] = "SHA256";
+
+    /* Manifest data is concatenated to the end of the image. It is encoded in
+     * TLV format.
+     */
+    offset = hdr->ih_img_size + hdr->ih_hdr_size;
+
+    res = flash_area_read(fap, offset, &tlv_header, sizeof(tlv_header));
+    if (res) {
+        return BOOT_STATUS_ERROR;
+    }
+    if (tlv_header.it_magic != IMAGE_TLV_INFO_MAGIC) {
+        return BOOT_STATUS_ERROR;
+    }
+    tlv_end = offset + tlv_header.it_tlv_tot;
+    offset += sizeof(tlv_header);
+
+    /* Iterates over the manifest data and copy the relevant attributes to the
+     * shared data area:
+     *  - image hash:      SW component measurement value
+     *  - public key hash: Signer ID
+     */
+    for (; offset < tlv_end; offset += sizeof(tlv_entry) + tlv_entry.it_len) {
+        res = flash_area_read(fap, offset, &tlv_entry, sizeof(tlv_entry));
+        if (res) {
+            return BOOT_STATUS_ERROR;
+        }
+
+        if (tlv_entry.it_type == IMAGE_TLV_SHA256) {
+            /* Get the image's hash value from the manifest section */
+            res = flash_area_read(fap, offset + sizeof(tlv_entry),
+                                  buf, tlv_entry.it_len);
+            if (res) {
+                return BOOT_STATUS_ERROR;
+            }
+
+            /* Add the image's hash value to the shared data area */
+            ias_minor = SET_IAS_MINOR(sw_module, SW_MEASURE_VALUE);
+            res2 = boot_add_data_to_shared_area(TLV_MAJOR_IAS,
+                                                ias_minor,
+                                                tlv_entry.it_len,
+                                                buf);
+            if (res2) {
+                return BOOT_STATUS_ERROR;
+            }
+
+            /* Add the measurement type to the shared data area */
+            ias_minor = SET_IAS_MINOR(sw_module, SW_MEASURE_TYPE);
+            res2 = boot_add_data_to_shared_area(TLV_MAJOR_IAS,
+                                                ias_minor,
+                                                sizeof(measure_type) - 1,
+                                                (const uint8_t *)measure_type);
+            if (res2) {
+                return BOOT_STATUS_ERROR;
+            }
+
+#ifdef MCUBOOT_SIGN_RSA
+        } else if (tlv_entry.it_type == IMAGE_TLV_KEYHASH) {
+            /* Get the hash of the public key from the manifest section */
+            res = flash_area_read(fap, offset + sizeof(tlv_entry),
+                                  buf, tlv_entry.it_len);
+            if (res) {
+                return BOOT_STATUS_ERROR;
+            }
+
+            /* Add the hash of the public key to the shared data area */
+            ias_minor = SET_IAS_MINOR(sw_module, SW_SIGNER_ID);
+            res2 = boot_add_data_to_shared_area(TLV_MAJOR_IAS,
+                                                ias_minor,
+                                                tlv_entry.it_len,
+                                                buf);
+            if (res2) {
+                return BOOT_STATUS_ERROR;
+            }
+#endif
+        }
+    }
+
+    return BOOT_STATUS_OK;
+}
+
+/*!
+ * \brief Add the security epoch counter of SW component to the shared
+ *        memory area
+ *
+ * \param[in]  sw_module  Identifier of the SW component
+ *
+ * \return Returns error code as specified in \ref boot_status_err_t
+ */
+static enum boot_status_err_t
+boot_save_sw_epoch(uint8_t sw_module)
+{
+    /*FixMe: Epoch does not exist in the current MCUBoot image manifest. Use a
+     *       hard coded value for now.
+     */
+    uint32_t epoch = 0;
+    uint16_t ias_minor;
+    enum shared_memory_err_t res;
+
+    /* Add the security epoch counter of the SW components to the shared data */
+    ias_minor = SET_IAS_MINOR(sw_module, SW_EPOCH);
+    res = boot_add_data_to_shared_area(TLV_MAJOR_IAS,
+                                       ias_minor,
+                                       sizeof(epoch),
+                                       (const uint8_t *)&epoch);
+    if (res) {
+        return BOOT_STATUS_ERROR;
+    }
+
+    return BOOT_STATUS_OK;
+}
+
+/*!
+ * \brief Add a type identifier(short test name) of SW component to the shared
+ *        memory area
+ *
+ * \param[in]  sw_module  Identifier of the SW component
+ *
+ * \return Returns error code as specified in \ref boot_status_err_t
+ */
+static enum boot_status_err_t
+boot_save_sw_type(uint8_t sw_module)
+{
+    /*FixMe: Use a hard coded value for now. Later on when multiple image will
+     *       be handled by MCUBoot then this must be revisited.
+     */
+    uint16_t ias_minor;
+    enum shared_memory_err_t res;
+    char sw_type[] = "NSPE_SPE";
+
+    /* Add the type identifier of the SW component to the shared data area */
+    ias_minor = SET_IAS_MINOR(sw_module, SW_TYPE);
+    res = boot_add_data_to_shared_area(TLV_MAJOR_IAS,
+                                       ias_minor,
+                                       sizeof(sw_type) - 1,
+                                       (const uint8_t *)sw_type);
+    if (res) {
+        return BOOT_STATUS_ERROR;
+    }
+
+    return BOOT_STATUS_OK;
+}
+
+/*!
+ * \brief Add the version of SW component to the shared memory area
+ *
+ * \param[in]  sw_module  Identifier of the SW component
+ * \param[in]  hdr        Pointer to the image header stored in RAM
+ *
+ * \return Returns error code as specified in \ref boot_status_err_t
+ */
+static enum boot_status_err_t
+boot_save_sw_version(uint8_t sw_module,
+                     const struct image_header *hdr)
+{
+    int32_t cnt;
+    enum shared_memory_err_t res;
+    char sw_version[14]; /* 8bit.8bit.16bit: 3 + 1 + 3 + 1 + 5 + 1 */
+    uint16_t ias_minor;
+
+    /* FixMe: snprintf can be replaced with a custom implementation */
+    cnt = snprintf(sw_version, sizeof(sw_version), "%u.%u.%u",
+                   hdr->ih_ver.iv_major,
+                   hdr->ih_ver.iv_minor,
+                   hdr->ih_ver.iv_revision);
+    if (cnt < 0 || cnt >= sizeof(sw_version)) {
+        return BOOT_STATUS_ERROR;
+    }
+
+    /* Add the version of the SW component to the shared data area */
+    ias_minor = SET_IAS_MINOR(sw_module, SW_VERSION);
+    res = boot_add_data_to_shared_area(TLV_MAJOR_IAS,
+                                       ias_minor,
+                                       cnt,
+                                       (const uint8_t *)sw_version);
+    if (res) {
+        return BOOT_STATUS_ERROR;
+    }
+
+    return BOOT_STATUS_OK;
+}
+
+/* See in boot_record.h */
 enum shared_memory_err_t
 boot_add_data_to_shared_area(uint8_t        major_type,
                              uint16_t       minor_type,
@@ -65,7 +279,7 @@
     /* Iterates over the TLV section looks for the same entry if found then
      * returns with error: SHARED_MEMORY_OVERWRITE
      */
-    for(; offset < tlv_end; offset += tlv_entry.tlv_len) {
+    for (; offset < tlv_end; offset += tlv_entry.tlv_len) {
         tlv_entry = *((struct shared_data_tlv_entry *)offset);
         if (GET_MAJOR(tlv_entry.tlv_type) == major_type &&
             GET_MINOR(tlv_entry.tlv_type) == minor_type) {
@@ -93,3 +307,34 @@
 
     return SHARED_MEMORY_OK;
 }
+
+/* See in boot_record.h */
+enum boot_status_err_t
+boot_save_boot_status(uint8_t sw_module,
+                      const struct image_header *hdr,
+                      const struct flash_area *fap)
+{
+    enum boot_status_err_t res;
+
+    res = boot_save_sw_type(sw_module);
+    if (res) {
+        return res;
+    }
+
+    res = boot_save_sw_version(sw_module, hdr);
+    if (res) {
+        return res;
+    }
+
+    res = boot_save_sw_epoch(sw_module);
+    if (res) {
+        return res;
+    }
+
+    res = boot_save_sw_measurements(sw_module, hdr, fap);
+    if (res) {
+        return res;
+    }
+
+    return BOOT_STATUS_OK;
+}