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);
}
}
diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py
index 9a9225f..7eb6c0c 100644
--- a/scripts/imgtool/image.py
+++ b/scripts/imgtool/image.py
@@ -21,6 +21,8 @@
'ECDSA224': 0x21,
'ECDSA256': 0x22, }
+TLV_INFO_SIZE = 4
+TLV_INFO_MAGIC = 0x6907
TLV_HEADER_SIZE = 4
# Sizes of the image trailer, depending on flash write size.
@@ -46,7 +48,8 @@
self.buf += payload
def get(self):
- return bytes(self.buf)
+ header = struct.pack('<HH', TLV_INFO_MAGIC, TLV_INFO_SIZE + len(self.buf))
+ return header + bytes(self.buf)
class Image():
@classmethod
diff --git a/sim/src/tlv.rs b/sim/src/tlv.rs
index c9e4a6d..f2191f6 100644
--- a/sim/src/tlv.rs
+++ b/sim/src/tlv.rs
@@ -60,7 +60,7 @@
/// Retrieve the size that the TLV will occupy. This can be called at any time.
pub fn get_size(&self) -> u16 {
- self.size
+ 4 + self.size
}
/// Add bytes to the covered hash.
@@ -72,6 +72,12 @@
pub fn make_tlv(self) -> Vec<u8> {
let mut result: Vec<u8> = vec![];
+ let size = self.get_size();
+ result.push(0x07);
+ result.push(0x69);
+ result.push((size & 0xFF) as u8);
+ result.push(((size >> 8) & 0xFF) as u8);
+
if self.kinds.contains(&TlvKinds::SHA256) {
let hash = digest::digest(&digest::SHA256, &self.payload);
let hash = hash.as_ref();