Boot: Save the boot measurements of BL2

These measurements are not encoded; they are shared with the measured
boot secure partition in a raw format. When these measurements are used,
sharing the CBOR encoded measurements from the TLV area is unnecessary.

Change-Id: I61d0598123d2be964439d320b8bc7c53b00ec58e
Signed-off-by: David Vincze <david.vincze@arm.com>
diff --git a/bl2/src/shared_data.c b/bl2/src/shared_data.c
index b2f3e42..73d0f73 100644
--- a/bl2/src/shared_data.c
+++ b/bl2/src/shared_data.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -10,6 +10,23 @@
 #include "bootutil/image.h"
 #include "flash_map/flash_map.h"
 #include "sysflash/sysflash.h"
+#include "mcuboot_config/mcuboot_config.h"
+
+#if defined(CONFIG_TFM_BOOT_STORE_MEASUREMENTS) && !defined(MCUBOOT_MEASURED_BOOT)
+#include <stdio.h>
+#include "boot_hal.h"
+#include "boot_measurement.h"
+#include "bootutil_priv.h"
+#include "psa/crypto.h"
+
+#define MCUBOOT_HASH_ALG    PSA_ALG_SHA_256
+#define MCUBOOT_HASH_SIZE   (32)
+
+#ifdef MCUBOOT_HW_KEY
+#include  "bootutil/crypto/sha256.h"
+#define SIG_BUF_SIZE (MCUBOOT_SIGN_RSA_LEN / 8)
+#endif
+#endif /* CONFIG_TFM_BOOT_STORE_MEASUREMENTS && !MCUBOOT_MEASURED_BOOT */
 
 /* Firmware Update specific macros */
 #define TLV_MAJOR_FWU   0x2
@@ -20,11 +37,123 @@
                      ((uint16_t)((sw_module & MODULE_MASK) << 6) | \
                       (uint16_t)(claim & CLAIM_MASK))
 
-extern int
-boot_add_data_to_shared_area(uint8_t        major_type,
-                             uint16_t       minor_type,
-                             size_t         size,
-                             const uint8_t *data);
+#ifdef TFM_PARTITION_FIRMWARE_UPDATE
+extern int boot_add_data_to_shared_area(uint8_t        major_type,
+                                        uint16_t       minor_type,
+                                        size_t         size,
+                                        const uint8_t *data);
+#endif /* TFM_PARTITION_FIRMWARE_UPDATE */
+
+
+#if defined(CONFIG_TFM_BOOT_STORE_MEASUREMENTS) && !defined(MCUBOOT_MEASURED_BOOT)
+/**
+ * Collect boot measurement and available associated metadata from the
+ * TLV area of an image.
+ *
+ * @param[in]  hdr        Pointer to the image header stored in RAM.
+ * @param[in]  fap        Pointer to the flash area where image is stored.
+ * @param[out] metadata   Pointer to measurement metadata structure.
+ * @param[out] measurement_buf          Buffer to store the boot measurement.
+ * @param[in]  measurement_buf_size     As an input value it indicates the size
+ *                                      of the measurement buffer in bytes.
+ *
+ * @return                0 on success; nonzero on failure.
+ *
+ */
+static int collect_image_measurement_and_metadata(
+                                    const struct image_header *hdr,
+                                    const struct flash_area *fap,
+                                    struct boot_measurement_metadata *metadata,
+                                    uint8_t *measurement_buf,
+                                    size_t   measurement_buf_size)
+{
+    struct image_tlv_iter it;
+    uint32_t off;
+    uint16_t len;
+    uint16_t type;
+#ifdef MCUBOOT_HW_KEY
+    /* Few extra bytes for encoding and for public exponent. */
+    uint8_t key_buf[SIG_BUF_SIZE + 24];
+    bootutil_sha256_context sha256_ctx;
+#endif
+    int rc;
+
+    /* Copy the software version information from the image header. */
+    rc = snprintf(metadata->sw_version, sizeof(metadata->sw_version),
+                  "%u.%u.%u+%u",
+                  hdr->ih_ver.iv_major,
+                  hdr->ih_ver.iv_minor,
+                  hdr->ih_ver.iv_revision,
+                  hdr->ih_ver.iv_build_num);
+    if ((rc < 0) || (rc >= sizeof(metadata->sw_version))) {
+        return -1;
+    }
+
+    /* Traverse through all of the TLVs for the required items. */
+    rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
+    if (rc) {
+        return rc;
+    }
+
+    while (true) {
+        rc = bootutil_tlv_iter_next(&it, &off, &len, &type);
+        if (rc < 0) {
+            return -1;
+        } else if (rc > 0) {
+            break;
+        }
+
+        if (type == IMAGE_TLV_SHA256) {
+            /* Retrieve the image hash (measurement value) from the TLV area. */
+            if (len > measurement_buf_size) {
+                return -1;
+            }
+            rc = LOAD_IMAGE_DATA(hdr, fap, off, measurement_buf, len);
+            if (rc) {
+                return -1;
+            }
+#ifdef MCUBOOT_HW_KEY
+        } else if (type == IMAGE_TLV_PUBKEY) {
+            /* Retrieve the signer ID (hash of PUBKEY) from the TLV area. */
+            if (len > sizeof(key_buf)) {
+                /* Something is wrong with the public key, proceed without
+                 * the signer ID.
+                 */
+                continue;
+            }
+            rc = LOAD_IMAGE_DATA(hdr, fap, off, key_buf, len);
+            if (rc) {
+                /* Proceed without this piece of data. */
+                continue;
+            }
+
+            /* Calculate the hash of the public key (signer ID). */
+            bootutil_sha256_init(&sha256_ctx);
+            bootutil_sha256_update(&sha256_ctx, key_buf, len);
+            bootutil_sha256_finish(&sha256_ctx, metadata->signer_id);
+#else
+        } else if (type == IMAGE_TLV_KEYHASH) {
+            /* Retrieve the signer ID (hash of PUBKEY) from the TLV area. */
+            if (len != MCUBOOT_HASH_SIZE) {
+                /* Something is wrong with the key hash, proceed without
+                 * the signer ID.
+                 */
+                continue;
+            }
+            rc = LOAD_IMAGE_DATA(hdr, fap, off,
+                                 metadata->signer_id, MCUBOOT_HASH_SIZE);
+            if (rc) {
+                /* Proceed without this piece of data. */
+                continue;
+            }
+#endif /* MCUBOOT_HW_KEY */
+            metadata->signer_id_size = MCUBOOT_HASH_SIZE;
+        }
+    }
+
+    return 0;
+}
+#endif /* CONFIG_TFM_BOOT_STORE_MEASUREMENTS && !MCUBOOT_MEASURED_BOOT */
 
 /**
  * Add application specific data to the shared memory area between the
@@ -38,16 +167,31 @@
 int boot_save_shared_data(const struct image_header *hdr,
                           const struct flash_area *fap)
 {
-    uint16_t fwu_minor;
     struct image_version image_ver;
     const struct flash_area *temp_fap;
     uint8_t mcuboot_image_id = 0;
     uint8_t i;
+    int32_t rc;
+#ifdef TFM_PARTITION_FIRMWARE_UPDATE
+    uint16_t fwu_minor;
+#endif
+#if defined(CONFIG_TFM_BOOT_STORE_MEASUREMENTS) && !defined(MCUBOOT_MEASURED_BOOT)
+    enum boot_measurement_slot_t slot_id;
+    uint8_t image_hash[MCUBOOT_HASH_SIZE];
+    struct boot_measurement_metadata metadata = {
+        .measurement_type = MCUBOOT_HASH_ALG,
+        .sw_type = "",
+        .sw_version = "",
+        .signer_id = { 0 },
+        .signer_id_size = 0,
+    };
+#endif /* CONFIG_TFM_BOOT_STORE_MEASUREMENTS && !MCUBOOT_MEASURED_BOOT */
 
     if (hdr == NULL || fap == NULL) {
         return -1;
     }
 
+    /* Look for the given flash area to determine the image ID. */
     for (i = 0; i < MCUBOOT_IMAGE_NUMBER; i++) {
         if (flash_area_open(FLASH_AREA_IMAGE_PRIMARY(i),
                             &temp_fap) != 0) {
@@ -66,10 +210,58 @@
 
     image_ver = hdr->ih_ver;
 
+#ifdef TFM_PARTITION_FIRMWARE_UPDATE
     /* Currently hardcode it to 0 which indicates the full image. */
     fwu_minor = SET_FWU_MINOR(mcuboot_image_id, SW_VERSION);
-    return boot_add_data_to_shared_area(TLV_MAJOR_FWU,
-                                        fwu_minor,
-                                        sizeof(image_ver),
-                                        (const uint8_t *)&image_ver);
+    rc = boot_add_data_to_shared_area(TLV_MAJOR_FWU,
+                                      fwu_minor,
+                                      sizeof(image_ver),
+                                      (const uint8_t *)&image_ver);
+    if (rc) {
+        return rc;
+    }
+#endif /* TFM_PARTITION_FIRMWARE_UPDATE */
+
+#if defined(CONFIG_TFM_BOOT_STORE_MEASUREMENTS) && !defined(MCUBOOT_MEASURED_BOOT)
+    /* Determine the index of the measurement slot. */
+    slot_id = BOOT_MEASUREMENT_SLOT_RT_0 + mcuboot_image_id;
+
+    switch (slot_id) {
+    case BOOT_MEASUREMENT_SLOT_RT_0:
+        strlcpy(metadata.sw_type, "RT_0",
+                sizeof(metadata.sw_type));
+        break;
+    case BOOT_MEASUREMENT_SLOT_RT_1:
+        strlcpy(metadata.sw_type, "RT_1",
+                sizeof(metadata.sw_type));
+        break;
+    case BOOT_MEASUREMENT_SLOT_RT_2:
+        strlcpy(metadata.sw_type, "RT_2",
+                sizeof(metadata.sw_type));
+        break;
+    default:
+        /* Proceed without this piece of data. */
+        break;
+    }
+
+    rc = collect_image_measurement_and_metadata(hdr, fap,
+                                                &metadata,
+                                                image_hash,
+                                                sizeof(image_hash));
+    if (rc) {
+        return rc;
+    }
+
+    /* Save the boot measurement(s) about the runtime image(s).
+     * If there are multiple images, the measurement slot will be extended
+     * with the subsequent measurements.
+     */
+    rc = boot_store_measurement((uint8_t)slot_id, image_hash,
+                                sizeof(image_hash), &metadata, false);
+    if (rc) {
+        return rc;
+    }
+#endif /* CONFIG_TFM_BOOT_STORE_MEASUREMENTS && !MCUBOOT_MEASURED_BOOT */
+
+    return 0;
 }