boot: serial_recovery: Add image hash support

Adds support for outputting the image hash TLV in serial recovery
mode, which is needed to comply with the img_mgmt MCUmgr group
requirements.

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
diff --git a/boot/boot_serial/src/boot_serial.c b/boot/boot_serial/src/boot_serial.c
index c9a9a37..437e732 100644
--- a/boot/boot_serial/src/boot_serial.c
+++ b/boot/boot_serial/src/boot_serial.c
@@ -82,7 +82,7 @@
 #define MCUBOOT_SERIAL_MAX_RECEIVE_SIZE 512
 #endif
 
-#define BOOT_SERIAL_OUT_MAX     (128 * BOOT_IMAGE_NUMBER)
+#define BOOT_SERIAL_OUT_MAX     (160 * BOOT_IMAGE_NUMBER)
 #define BOOT_SERIAL_FRAME_MTU   124 /* 127 - pkt start (2 bytes) and stop (1 byte) */
 
 #ifdef __ZEPHYR__
@@ -121,6 +121,11 @@
 
 static void boot_serial_output(void);
 
+#ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
+static int boot_serial_get_hash(const struct image_header *hdr,
+                                const struct flash_area *fap, uint8_t *hash);
+#endif
+
 static zcbor_state_t cbor_state[2];
 
 void reset_cbor_state(void)
@@ -217,6 +222,9 @@
     uint32_t slot, area_id;
     const struct flash_area *fap;
     uint8_t image_index;
+#ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
+    uint8_t hash[32];
+#endif
 
     zcbor_map_start_encode(cbor_state, 1);
     zcbor_tstr_put_lit_cast(cbor_state, "images");
@@ -261,6 +269,11 @@
                 }
             }
 
+#ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
+            /* Retrieve SHA256 hash of image for identification */
+            rc = boot_serial_get_hash(&hdr, fap, hash);
+#endif
+
             flash_area_close(fap);
 
             if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
@@ -276,9 +289,18 @@
 
             zcbor_tstr_put_lit_cast(cbor_state, "slot");
             zcbor_uint32_put(cbor_state, slot);
+
+#ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
+            if (rc == 0) {
+                zcbor_tstr_put_lit_cast(cbor_state, "hash");
+                zcbor_bstr_encode_ptr(cbor_state, hash, sizeof(hash));
+            }
+#endif
+
             zcbor_tstr_put_lit_cast(cbor_state, "version");
 
             bs_list_img_ver((char *)tmpbuf, sizeof(tmpbuf), &hdr.ih_ver);
+
             zcbor_tstr_encode_ptr(cbor_state, tmpbuf, strlen((char *)tmpbuf));
             zcbor_map_end_encode(cbor_state, 20);
         }
@@ -985,3 +1007,50 @@
     boot_serial_read_console(f,timeout_in_ms);
 }
 #endif
+
+#ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
+/* Function to find the hash of an image, returns 0 on success. */
+static int boot_serial_get_hash(const struct image_header *hdr,
+                                const struct flash_area *fap, uint8_t *hash)
+{
+    struct image_tlv_iter it;
+    uint32_t offset;
+    uint16_t len;
+    uint16_t type;
+    int rc;
+
+    /* Manifest data is concatenated to the end of the image.
+     * It is encoded in TLV format.
+     */
+    rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
+    if (rc) {
+        return -1;
+    }
+
+    /* Traverse through the TLV area to find the image hash TLV. */
+    while (true) {
+        rc = bootutil_tlv_iter_next(&it, &offset, &len, &type);
+        if (rc < 0) {
+            return -1;
+        } else if (rc > 0) {
+            break;
+        }
+
+        if (type == IMAGE_TLV_SHA256) {
+            /* Get the image's hash value from the manifest section. */
+            if (len != 32) {
+                return -1;
+            }
+
+            rc = flash_area_read(fap, offset, hash, len);
+            if (rc) {
+                return -1;
+            }
+
+            return 0;
+        }
+    }
+
+    return -1;
+}
+#endif
diff --git a/boot/zephyr/Kconfig.serial_recovery b/boot/zephyr/Kconfig.serial_recovery
index e703d59..d5c0101 100644
--- a/boot/zephyr/Kconfig.serial_recovery
+++ b/boot/zephyr/Kconfig.serial_recovery
@@ -168,4 +168,11 @@
 	help
 	  timeout in ms for MCUboot to wait to allow for DFU to be invoked.
 
+config BOOT_SERIAL_IMG_GRP_HASH
+	bool "Image list hash support"
+	default y
+	help
+	  If y, image list responses will include the image hash (adds ~100
+	  bytes of flash).
+
 endif # MCUBOOT_SERIAL
diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h
index 1092687..a235e15 100644
--- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h
+++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h
@@ -205,6 +205,10 @@
 #define MCUBOOT_SERIAL_WAIT_FOR_DFU
 #endif
 
+#ifdef CONFIG_BOOT_SERIAL_IMG_GRP_HASH
+#define MCUBOOT_SERIAL_IMG_GRP_HASH
+#endif
+
 /*
  * The option enables code, currently in boot_serial, that attempts
  * to erase flash progressively, as update fragments are received,