bootutil: update to new protected TLV format
Implements the validation system where hashing is performed over header
+ payload + protected TLVs.
Signed-off-by: Fabio Utzig <utzig@apache.org>
diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c
index 1381808..9fbd88f 100644
--- a/boot/bootutil/src/image_validate.c
+++ b/boot/bootutil/src/image_validate.c
@@ -61,15 +61,15 @@
uint16_t hdr_size;
uint32_t off;
int rc;
-#ifdef MCUBOOT_ENC_IMAGES
- uint32_t protected_off;
uint32_t blk_off;
-#endif
+ uint32_t tlv_off;
#if (BOOT_IMAGE_NUMBER == 1) || !defined(MCUBOOT_ENC_IMAGES)
(void)enc_state;
(void)image_index;
(void)hdr_size;
+ (void)blk_off;
+ (void)tlv_off;
#endif
#ifdef MCUBOOT_ENC_IMAGES
@@ -89,25 +89,18 @@
}
/* Hash is computed over image header and image itself. */
- hdr_size = hdr->ih_hdr_size;
- size = BOOT_TLV_OFF(hdr);
+ size = hdr_size = hdr->ih_hdr_size;
+ size += hdr->ih_img_size;
+ tlv_off = size;
-#ifdef MCUBOOT_ENC_IMAGES
- protected_off = size;
-#endif
-
-#if (MCUBOOT_IMAGE_NUMBER > 1)
- /* If dependency TLVs are present then the TLV info header and the
- * dependency TLVs are also protected and have to be included in the hash
- * calculation.
- */
- if (hdr->ih_protect_tlv_size != 0) {
- size += hdr->ih_protect_tlv_size;
- }
-#endif
+ /* If protected TLVs are present they are also hashed. */
+ size += hdr->ih_protect_tlv_size;
for (off = 0; off < size; off += blk_sz) {
blk_sz = size - off;
+ if (blk_sz > tmp_buf_sz) {
+ blk_sz = tmp_buf_sz;
+ }
#ifdef MCUBOOT_ENC_IMAGES
/* The only data that is encrypted in an image is the payload;
* both header and TLVs (when protected) are not.
@@ -115,24 +108,20 @@
if ((off < hdr_size) && ((off + blk_sz) > hdr_size)) {
/* read only the header */
blk_sz = hdr_size - off;
- } else if (off >= protected_off) {
- /* read protected TLVs */
- blk_sz = size - off;
- } else if ((off + blk_sz) > protected_off) {
- /* do not copy beyond image payload */
- blk_sz = protected_off - off;
+ }
+ if ((off < tlv_off) && ((off + blk_sz) > tlv_off)) {
+ /* read only up to the end of the image payload */
+ blk_sz = tlv_off - off;
}
#endif
- if (blk_sz > tmp_buf_sz) {
- blk_sz = tmp_buf_sz;
- }
rc = flash_area_read(fap, off, tmp_buf, blk_sz);
if (rc) {
return rc;
}
#ifdef MCUBOOT_ENC_IMAGES
if (MUST_DECRYPT(fap, image_index, hdr)) {
- if (off >= hdr_size && off < protected_off) {
+ /* Only payload is encrypted (area between header and TLVs) */
+ if (off >= hdr_size && off < tlv_off) {
blk_off = (off - hdr_size) & 0xf;
boot_encrypt(enc_state, image_index, fap, off - hdr_size,
blk_sz, blk_off, tmp_buf);
diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c
index 045be52..fbbe561 100644
--- a/boot/bootutil/src/loader.c
+++ b/boot/bootutil/src/loader.c
@@ -253,6 +253,7 @@
const struct flash_area *fap;
struct image_tlv_info info;
uint32_t off;
+ uint32_t protect_tlv_size;
int area_id;
int rc;
@@ -274,12 +275,28 @@
goto done;
}
+ protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size;
+ if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) {
+ if (protect_tlv_size != info.it_tlv_tot) {
+ rc = BOOT_EBADIMAGE;
+ goto done;
+ }
+
+ if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) {
+ rc = BOOT_EFLASH;
+ goto done;
+ }
+ } else if (protect_tlv_size != 0) {
+ rc = BOOT_EBADIMAGE;
+ goto done;
+ }
+
if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
rc = BOOT_EBADIMAGE;
goto done;
}
- *size = off + info.it_tlv_tot;
+ *size = off + protect_tlv_size + info.it_tlv_tot;
rc = 0;
done:
diff --git a/boot/bootutil/src/tlv.c b/boot/bootutil/src/tlv.c
index aaebee3..9108be4 100644
--- a/boot/bootutil/src/tlv.c
+++ b/boot/bootutil/src/tlv.c
@@ -48,6 +48,18 @@
return -1;
}
+ if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) {
+ if (hdr->ih_protect_tlv_size != info.it_tlv_tot) {
+ return -1;
+ }
+
+ if (flash_area_read(fap, off_ + info.it_tlv_tot, &info, sizeof(info))) {
+ return -1;
+ }
+ } else if (hdr->ih_protect_tlv_size != 0) {
+ return -1;
+ }
+
if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
return -1;
}
@@ -56,10 +68,10 @@
it->fap = fap;
it->type = type;
it->prot = prot;
- off_ += sizeof(info);
- it->tlv_off = off_;
- it->prot_len = off_ + it->hdr->ih_protect_tlv_size;
- it->tlv_end = off_ + info.it_tlv_tot;
+ it->prot_end = off_ + it->hdr->ih_protect_tlv_size;
+ it->tlv_end = off_ + it->hdr->ih_protect_tlv_size + info.it_tlv_tot;
+ // position on first TLV
+ it->tlv_off = off_ + sizeof(info);
return 0;
}
@@ -87,13 +99,17 @@
}
while (it->tlv_off < it->tlv_end) {
+ if (it->hdr->ih_protect_tlv_size > 0 && it->tlv_off == it->prot_end) {
+ it->tlv_off += sizeof(struct image_tlv_info);
+ }
+
rc = flash_area_read(it->fap, it->tlv_off, &tlv, sizeof tlv);
if (rc) {
return -1;
}
/* No more TLVs in the protected area */
- if (it->prot && it->tlv_off >= it->prot_len) {
+ if (it->prot && it->tlv_off >= it->prot_end) {
return 1;
}