bootutil: allow encryption key TLVs in swap status

Add a new option that when enabled, allows a swap status to store
an encrypted key TLV instead of plain keys. When a new swap operation is
started the encryption keys are saved to the swap status area to allow
for resuming (because it is challenging to find those TLV in the middle
of a swap operation).

Previously those keys were saved in plain text, so it would be easy to
dump them if the images were stored in external flash. With this new
option one can choose to save the TLV instead, which uses more flash
but does not leak secrets. The amount of flash required varies depending
on the size of the TLV, which is 48 for AES-128-KW, 512 for RSA and 240
for ECIES-P256.

Signed-off-by: Fabio Utzig <utzig@apache.org>
diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c
index a29a27d..ab79b8b 100644
--- a/boot/bootutil/src/bootutil_misc.c
+++ b/boot/bootutil/src/bootutil_misc.c
@@ -161,7 +161,11 @@
            boot_status_sz(min_write_sz)           +
 #ifdef MCUBOOT_ENC_IMAGES
            /* encryption keys */
+#  if MCUBOOT_SWAP_SAVE_ENCTLV
+           BOOT_ENC_TLV_ALIGN_SIZE * 2            +
+#  else
            BOOT_ENC_KEY_SIZE * 2                  +
+#  endif
 #endif
            /* swap_type + copy_done + image_ok + swap_size */
            BOOT_MAX_ALIGN * 4                     +
@@ -231,7 +235,12 @@
 static inline uint32_t
 boot_enc_key_off(const struct flash_area *fap, uint8_t slot)
 {
+#if MCUBOOT_SWAP_SAVE_ENCTLV
+    return boot_swap_size_off(fap) - ((slot + 1) *
+            ((((BOOT_ENC_TLV_SIZE - 1) / BOOT_MAX_ALIGN) + 1) * BOOT_MAX_ALIGN));
+#else
     return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_KEY_SIZE);
+#endif
 }
 #endif
 
@@ -390,16 +399,34 @@
 
 #ifdef MCUBOOT_ENC_IMAGES
 int
-boot_read_enc_key(int image_index, uint8_t slot, uint8_t *enckey)
+boot_read_enc_key(int image_index, uint8_t slot, struct boot_status *bs)
 {
     uint32_t off;
     const struct flash_area *fap;
+#if MCUBOOT_SWAP_SAVE_ENCTLV
+    int i;
+#endif
     int rc;
 
     rc = boot_find_status(image_index, &fap);
     if (rc == 0) {
         off = boot_enc_key_off(fap, slot);
-        rc = flash_area_read(fap, off, enckey, BOOT_ENC_KEY_SIZE);
+#if MCUBOOT_SWAP_SAVE_ENCTLV
+        rc = flash_area_read(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
+        if (rc == 0) {
+            for (i = 0; i < BOOT_ENC_TLV_ALIGN_SIZE; i++) {
+                if (bs->enctlv[slot][i] != 0xff) {
+                    break;
+                }
+            }
+            /* Only try to decrypt non-erased TLV metadata */
+            if (i != BOOT_ENC_TLV_ALIGN_SIZE) {
+                rc = boot_enc_decrypt(bs->enctlv[slot], bs->enckey[slot]);
+            }
+        }
+#else
+        rc = flash_area_read(fap, off, bs->enckey[slot], BOOT_ENC_KEY_SIZE);
+#endif
         flash_area_close(fap);
     }
 
@@ -526,7 +553,8 @@
 
 #ifdef MCUBOOT_ENC_IMAGES
 int
-boot_write_enc_key(const struct flash_area *fap, uint8_t slot, const uint8_t *enckey)
+boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
+        const struct boot_status *bs)
 {
     uint32_t off;
     int rc;
@@ -535,7 +563,11 @@
     BOOT_LOG_DBG("writing enc_key; fa_id=%d off=0x%lx (0x%lx)",
                  fap->fa_id, (unsigned long)off,
                  (unsigned long)fap->fa_off + off);
-    rc = flash_area_write(fap, off, enckey, BOOT_ENC_KEY_SIZE);
+#if MCUBOOT_SWAP_SAVE_ENCTLV
+    rc = flash_area_write(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
+#else
+    rc = flash_area_write(fap, off, bs->enckey[slot], BOOT_ENC_KEY_SIZE);
+#endif
     if (rc != 0) {
         return BOOT_EFLASH;
     }