Place TLV size into TLV itself
To allow the signatures to be replaced, move the size of the TLV into a
small "info" header at the start of the TLV.
Note that this causes image swapping to lose robustness. This is fixed
by a later commit.
Based on work by Marko Kiiskila <marko@runtime.io>
Signed-off-by: Marko Kiiskila <marko@runtime.io>
Signed-off-by: David Brown <david.brown@linaro.org>
JIRA: MCUB-65
diff --git a/boot/bootutil/include/bootutil/image.h b/boot/bootutil/include/bootutil/image.h
index c4ab8a9..35a8321 100644
--- a/boot/bootutil/include/bootutil/image.h
+++ b/boot/bootutil/include/bootutil/image.h
@@ -30,6 +30,7 @@
#define IMAGE_MAGIC 0x96f3b83c
#define IMAGE_MAGIC_NONE 0xffffffff
+#define IMAGE_TLV_INFO_MAGIC 0x6907
#define IMAGE_HEADER_SIZE 32
@@ -46,6 +47,13 @@
/*
* Image trailer TLV types.
+ *
+ * Signature is generated by computing signature over the image hash.
+ * Currently the only image hash type is SHA256.
+ *
+ * Signature comes in the form of 2 TLVs.
+ * 1st on identifies the public key which should be used to verify it.
+ * 2nd one is the actual signature.
*/
#define IMAGE_TLV_KEYHASH 0x01 /* hash of the public key */
#define IMAGE_TLV_SHA256 0x10 /* SHA256 of image hdr and body */
@@ -60,13 +68,10 @@
uint32_t iv_build_num;
};
-#define IMAGE_SIZE(hdr) \
- ((hdr)->ih_tlv_size + (hdr)->ih_hdr_size + (hdr)->ih_img_size)
-
/** Image header. All fields are in little endian byte order. */
struct image_header {
uint32_t ih_magic;
- uint16_t ih_tlv_size; /* Combined size of trailing TLVs (bytes). */
+ uint16_t _pad00;
uint8_t _pad0;
uint8_t _pad1;
uint16_t ih_hdr_size; /* Size of image header (bytes). */
@@ -77,6 +82,12 @@
uint32_t _pad3;
};
+/** Image TLV header. All fields in little endian. */
+struct image_tlv_info {
+ uint16_t it_magic;
+ uint16_t it_tlv_tot; /* size of TLV area (including tlv_info header) */
+};
+
/** Image trailer TLV format. All fields in little endian. */
struct image_tlv {
uint8_t it_type; /* IMAGE_TLV_[...]. */
diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c
index 8004533..003620c 100644
--- a/boot/bootutil/src/image_validate.c
+++ b/boot/bootutil/src/image_validate.c
@@ -146,6 +146,7 @@
uint32_t off;
uint32_t size;
int sha256_valid = 0;
+ struct image_tlv_info info;
#ifdef EXPECTED_SIG_TLV
int valid_signature = 0;
int key_id = -1;
@@ -165,9 +166,19 @@
memcpy(out_hash, hash, 32);
}
+ /* The TLVs come after the image. */
/* After image there are TLVs. */
off = hdr->ih_img_size + hdr->ih_hdr_size;
- size = off + hdr->ih_tlv_size;
+
+ rc = flash_area_read(fap, off, &info, sizeof(info));
+ if (rc) {
+ return rc;
+ }
+ if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
+ return -1;
+ }
+ size = off + info.it_tlv_tot;
+ off += sizeof(info);
/*
* Traverse through all of the TLVs, performing any checks we know
diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c
index 1923fbc..82d39f8 100644
--- a/boot/bootutil/src/loader.c
+++ b/boot/bootutil/src/loader.c
@@ -228,6 +228,43 @@
}
#endif /* !MCUBOOT_OVERWRITE_ONLY */
+/*
+ * Compute the total size of the given image. Includes the size of
+ * the TLVs.
+ */
+static int
+boot_read_image_size(int slot, struct image_header *hdr, uint32_t *size)
+{
+ const struct flash_area *fap;
+ struct image_tlv_info info;
+ int area_id;
+ int rc;
+
+ area_id = flash_area_id_from_image_slot(slot);
+ rc = flash_area_open(area_id, &fap);
+ if (rc != 0) {
+ rc = BOOT_EFLASH;
+ goto done;
+ }
+
+ rc = flash_area_read(fap, hdr->ih_hdr_size + hdr->ih_img_size,
+ &info, sizeof(info));
+ if (rc != 0) {
+ rc = BOOT_EFLASH;
+ goto done;
+ }
+ if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
+ rc = BOOT_EBADIMAGE;
+ goto done;
+ }
+ *size = hdr->ih_hdr_size + hdr->ih_img_size + info.it_tlv_tot;
+ rc = 0;
+
+done:
+ flash_area_close(fap);
+ return 0;
+}
+
static int
boot_read_image_header(int slot, struct image_header *out_hdr)
{
@@ -1029,12 +1066,14 @@
hdr = boot_img_hdr(&boot_data, 0);
if (hdr->ih_magic == IMAGE_MAGIC) {
- copy_size = hdr->ih_hdr_size + hdr->ih_img_size + hdr->ih_tlv_size;
+ rc = boot_read_image_size(0, hdr, ©_size);
+ assert(rc == 0);
}
hdr = boot_img_hdr(&boot_data, 1);
if (hdr->ih_magic == IMAGE_MAGIC) {
- size = hdr->ih_hdr_size + hdr->ih_img_size + hdr->ih_tlv_size;
+ rc = boot_read_image_size(1, hdr, &size);
+ assert(rc == 0);
}
if (!size || !copy_size || size == copy_size) {
@@ -1044,10 +1083,11 @@
hdr = &tmp_hdr;
if (hdr->ih_magic == IMAGE_MAGIC) {
if (!size) {
- size = hdr->ih_hdr_size + hdr->ih_img_size + hdr->ih_tlv_size;
+ rc = boot_read_image_size(2, hdr, &size);
} else {
- copy_size = hdr->ih_hdr_size + hdr->ih_img_size + hdr->ih_tlv_size;
+ rc = boot_read_image_size(2, hdr, &size);
}
+ assert(rc == 0);
}
}