]> granicus.if.org Git - esp-idf/commitdiff
secure boot: Pad to avoid data after the signature mapping into the address space
authorAngus Gratton <angus@espressif.com>
Fri, 13 Jul 2018 01:52:57 +0000 (11:52 +1000)
committerAngus Gratton <gus@projectgus.com>
Mon, 23 Jul 2018 03:45:55 +0000 (13:45 +1000)
Because address space is mapped in 64KB pages, it was possible for unauthenticated data after the
app .bin to become mapped into the flash cache address space.

This problem is solved by 2 changes:

* "esptool elf2image --secure-pad" will pad the image so that the signature block ends close to the
  64KB boundary. Due to alignment constraints it will be 12 bytes too short after signing (but
  with flash encryption, these 12 bytes are still encrypted as part of the last block and can't be
  arbitrarily changed).
* By default, secure boot now requires all app partitions to be a multiple of 64KB in size.

components/bootloader/Kconfig.projbuild
components/bootloader_support/src/secure_boot_signatures.c
components/esptool_py/Makefile.projbuild
components/esptool_py/esptool
components/partition_table/Makefile.projbuild
components/partition_table/gen_esp32part.py

index 8af0dc3161273fcfa8078c966dff096123affb1e..75dae508aedf86ea9e5e5deabfd61c178c87f6ea 100644 (file)
@@ -275,6 +275,13 @@ config SECURE_BOOT_ALLOW_JTAG
 
           Only set this option in testing environments.
 
+config SECURE_BOOT_ALLOW_SHORT_APP_PARTITION
+       bool "Allow app partition length not 64KB aligned"
+       depends on SECURE_BOOT_INSECURE
+       help
+           If not set (default), app partition size must be a multiple of 64KB. App images are padded to 64KB length, and the bootloader checks any trailing bytes after the signature (before the next 64KB boundary) have not been written. This is because flash cache maps entire 64KB pages into the address space. This prevents an attacker from appending unverified data after the app image in the flash, causing it to be mapped into the address space.
+
+           Setting this option allows the app partition length to be unaligned, and disables padding of the app image to this length. It is generally not recommended to set this option, unless you have a legacy partitioning scheme which doesn't support 64KB aligned partition lengths.
 
 config FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_ENCRYPT
     bool "Leave UART bootloader encryption enabled"
index 988ab7935f2c45e14a9127f64be9b2608716726a..ddb7ad73a614b629370532736ca55e9f3c258896 100644 (file)
@@ -84,10 +84,13 @@ esp_err_t esp_secure_boot_verify_signature_block(const esp_secure_boot_sig_block
         return ESP_FAIL;
     }
 
+    ESP_LOGD(TAG, "Verifying secure boot signature");
+
     is_valid = uECC_verify(signature_verification_key_start,
                                 image_digest,
                                 DIGEST_LEN,
                                 sig_block->signature,
                                 uECC_secp256r1());
+    ESP_LOGD(TAG, "Verification result %d", is_valid);
     return is_valid ? ESP_OK : ESP_ERR_IMAGE_INVALID;
 }
index 330d4061e5a29d1876660890f7046fae7a1e1ee3..25f4b8e6f7efeddfb4a5150684b4633dee06e0f7 100644 (file)
@@ -31,6 +31,14 @@ endif
 
 ESPTOOL_ELF2IMAGE_OPTIONS :=
 
+ifdef CONFIG_SECURE_BOOT_ENABLED
+ifndef CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION
+ifndef IS_BOOTLOADER_BUILD
+ESPTOOL_ELF2IMAGE_OPTIONS += --secure-pad
+endif
+endif
+endif
+
 ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z,-u) $(ESPTOOL_WRITE_FLASH_OPTIONS)
 
 ESPTOOL_ALL_FLASH_ARGS += $(APP_OFFSET) $(APP_BIN)
index da31d9d7a1bb496995f8e30a6be259689948e43e..fd8c25d2160505fb9d5abbe56f85116a136afb05 160000 (submodule)
@@ -1 +1 @@
-Subproject commit da31d9d7a1bb496995f8e30a6be259689948e43e
+Subproject commit fd8c25d2160505fb9d5abbe56f85116a136afb05
index 9e4e61052fe5ee4c2923538917e5e9f06efb83ae..4973201f381f2fc8f3eb4a860e785dad8e4f2c24 100644 (file)
@@ -9,7 +9,7 @@
 .PHONY: partition_table partition_table-flash partition_table-clean partition_table_get_info
 
 PARTITION_MD5_OPT :=
-ifneq ("$(CONFIG_PARTITION_TABLE_MD5)", "y")
+ifndef CONFIG_PARTITION_TABLE_MD5
 PARTITION_MD5_OPT := "--disable-md5sum"
 endif
 
@@ -18,11 +18,18 @@ ifneq ("$(CONFIG_ESPTOOLPY_FLASHSIZE)", "")
 PARTITION_FLASHSIZE_OPT := --flash-size $(CONFIG_ESPTOOLPY_FLASHSIZE)
 endif
 
+PARTITION_SECURE_OPT :=
+ifdef CONFIG_SECURE_BOOT_ENABLED
+ifndef CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION
+PARTITION_SECURE_OPT += --secure
+endif
+endif
+
 # Address of partition table
 PARTITION_TABLE_OFFSET := $(CONFIG_PARTITION_TABLE_OFFSET)
 PARTITION_TABLE_OFFSET_ARG := --offset $(PARTITION_TABLE_OFFSET)
 
-GEN_ESP32PART := $(PYTHON) $(COMPONENT_PATH)/gen_esp32part.py -q $(PARTITION_MD5_OPT) $(PARTITION_FLASHSIZE_OPT) $(PARTITION_TABLE_OFFSET_ARG)
+GEN_ESP32PART := $(PYTHON) $(COMPONENT_PATH)/gen_esp32part.py -q $(PARTITION_MD5_OPT) $(PARTITION_FLASHSIZE_OPT) $(PARTITION_TABLE_OFFSET_ARG) $(PARTITION_SECURE_OPT)
 GET_PART_INFO := $(COMPONENT_PATH)/parttool.py -q
 
 # if CONFIG_PARTITION_TABLE_FILENAME is unset, means we haven't re-generated config yet...
index 8871e90507446e3a34fe5c7edc5a9bbb5d53b532..92bf35a233592ad55d1f3c30ee674d0f3a34d3f5 100755 (executable)
@@ -37,6 +37,7 @@ __version__ = '1.1'
 
 quiet = False
 md5sum = True
+secure = False
 offset_part_table = 0
 
 def status(msg):
@@ -324,6 +325,8 @@ class PartitionDefinition(object):
         align = self.ALIGNMENT.get(self.type, 4)
         if self.offset % align:
             raise ValidationError(self, "Offset 0x%x is not aligned to 0x%x" % (self.offset, align))
+        if self.size % align and secure:
+            raise ValidationError(self, "Size 0x%x is not aligned to 0x%x" % (self.size, align))
         if self.size is None:
             raise ValidationError(self, "Size field is not set")
 
@@ -408,6 +411,7 @@ def main():
     global quiet
     global md5sum
     global offset_part_table
+    global secure
     parser = argparse.ArgumentParser(description='ESP32 partition table utility')
 
     parser.add_argument('--flash-size', help='Optional flash size limit, checks partition table fits in flash',
@@ -416,7 +420,7 @@ def main():
     parser.add_argument('--verify', '-v', help='Verify partition table fields', default=True, action='store_false')
     parser.add_argument('--quiet', '-q', help="Don't print status messages to stderr", action='store_true')
     parser.add_argument('--offset', '-o', help='Set offset partition table', default='0x8000')
-    
+    parser.add_argument('--secure', help="Require app partitions to be suitable for secure boot", action='store_true')
     parser.add_argument('input', help='Path to CSV or binary file to parse. Will use stdin if omitted.', type=argparse.FileType('rb'), default=sys.stdin)
     parser.add_argument('output', help='Path to output converted binary or CSV file. Will use stdout if omitted, unless the --display argument is also passed (in which case only the summary is printed.)',
                         nargs='?',
@@ -426,6 +430,7 @@ def main():
 
     quiet = args.quiet
     md5sum = not args.disable_md5sum
+    secure = args.secure
     offset_part_table = int(args.offset, 0)
     input = args.input.read()
     input_is_binary = input[0:2] == PartitionDefinition.MAGIC_BYTES