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/ext/mcuboot/bootutil/src/loader.c b/bl2/ext/mcuboot/bootutil/src/loader.c
index f038785..52602b8 100644
--- a/bl2/ext/mcuboot/bootutil/src/loader.c
+++ b/bl2/ext/mcuboot/bootutil/src/loader.c
@@ -251,12 +251,12 @@
  * Validate image hash/signature in a slot.
  */
 static int
-boot_image_check(struct image_header *hdr, const struct flash_area *fap, uint8_t *out_hash)
+boot_image_check(struct image_header *hdr, const struct flash_area *fap)
 {
     static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
 
     if (bootutil_img_validate(hdr, fap, tmpbuf, BOOT_TMPBUF_SZ,
-                              NULL, 0, out_hash)) {
+                              NULL, 0, NULL)) {
         return BOOT_EBADIMAGE;
     }
     return 0;
@@ -267,7 +267,6 @@
 {
     const struct flash_area *fap;
     struct image_header *hdr;
-    uint8_t hash[32];
     int rc;
 
     hdr = boot_img_hdr(&boot_data, slot);
@@ -282,7 +281,7 @@
     }
 
     if ((hdr->ih_magic != IMAGE_MAGIC ||
-        boot_image_check(hdr, fap, hash) != 0)) {
+        boot_image_check(hdr, fap) != 0)) {
         if (slot != 0) {
             rc = flash_area_erase(fap, 0, fap->fa_size);
             if(rc != 0) {
@@ -296,13 +295,6 @@
         BOOT_LOG_ERR("Authentication failed! Image in slot %d is not valid.",
                      slot);
         return -1;
-    } else {
-        if (0 != boot_add_data_to_shared_area(TLV_MAJOR_IAS,
-                                              TLV_MINOR_IAS_S_NS_MEASURE_VALUE,
-                                              sizeof(hash),
-                                              hash)) {
-            BOOT_LOG_ERR("Failed to add data to shared area");
-        }
     }
 
     flash_area_close(fap);
@@ -1375,6 +1367,14 @@
     rsp->br_image_off = boot_img_slot_off(&boot_data, 0);
     rsp->br_hdr = boot_img_hdr(&boot_data, slot);
 
+    /* Save boot status to shared memory area */
+    rc = boot_save_boot_status(SW_S_NS,
+                               rsp->br_hdr,
+                               BOOT_IMG_AREA(&boot_data, slot));
+    if (rc) {
+        BOOT_LOG_ERR("Failed to add data to shared area");
+    }
+
  out:
     flash_area_close(BOOT_SCRATCH_AREA(&boot_data));
     for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
@@ -1691,6 +1691,14 @@
         rc = BOOT_EBADIMAGE;
     }
 
+    /* Save boot status to shared memory area */
+    rc = boot_save_boot_status(SW_S_NS,
+                               rsp->br_hdr,
+                               BOOT_IMG_AREA(&boot_data, slot));
+    if (rc) {
+        BOOT_LOG_ERR("Failed to add data to shared area");
+    }
+
 out:
    for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
        flash_area_close(BOOT_IMG_AREA(&boot_data, BOOT_NUM_SLOTS - 1 - slot));
diff --git a/bl2/include/boot_record.h b/bl2/include/boot_record.h
index f7a6308..217a206 100644
--- a/bl2/include/boot_record.h
+++ b/bl2/include/boot_record.h
@@ -11,6 +11,8 @@
 #include <stdint.h>
 #include <stddef.h>
 #include <limits.h>
+#include "../ext/mcuboot/bootutil/include/bootutil/image.h"
+#include "../ext/mcuboot/include/flash_map/flash_map.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -31,6 +33,16 @@
 };
 
 /*!
+ * \enum boot_status_err_t
+ *
+ * \brief Return values for saving boot status information to shared memory are
+ */
+enum boot_status_err_t {
+    BOOT_STATUS_OK,
+    BOOT_STATUS_ERROR,
+};
+
+/*!
  * \brief Add a data item to the shared data area between bootloader and
  *        runtime SW
  *
@@ -47,6 +59,21 @@
                              size_t         size,
                              const uint8_t *data);
 
+/*!
+ * \brief Add an image's all boot status information to the shared data area
+ *        between bootloader and runtime SW
+ *
+ * \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
+ */
+enum boot_status_err_t
+boot_save_boot_status(uint8_t sw_module,
+                      const struct image_header *hdr,
+                      const struct flash_area *fap);
+
 #ifdef __cplusplus
 }
 #endif
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;
+}