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;
         }