build system: Add espefuse/espsecure support for secure boot

This commit is contained in:
Angus Gratton 2016-11-01 10:50:16 +11:00
parent cf732bb663
commit 4ba1b73eba
6 changed files with 147 additions and 21 deletions

View file

@ -20,12 +20,65 @@ config LOG_BOOTLOADER_LEVEL_VERBOSE
endchoice
config LOG_BOOTLOADER_LEVEL
int
default 0 if LOG_BOOTLOADER_LEVEL_NONE
default 1 if LOG_BOOTLOADER_LEVEL_ERROR
default 2 if LOG_BOOTLOADER_LEVEL_WARN
default 3 if LOG_BOOTLOADER_LEVEL_INFO
default 4 if LOG_BOOTLOADER_LEVEL_DEBUG
default 5 if LOG_BOOTLOADER_LEVEL_VERBOSE
int
default 0 if LOG_BOOTLOADER_LEVEL_NONE
default 1 if LOG_BOOTLOADER_LEVEL_ERROR
default 2 if LOG_BOOTLOADER_LEVEL_WARN
default 3 if LOG_BOOTLOADER_LEVEL_INFO
default 4 if LOG_BOOTLOADER_LEVEL_DEBUG
default 5 if LOG_BOOTLOADER_LEVEL_VERBOSE
choice SECURE_BOOTLOADER
bool "Secure bootloader"
default SECURE_BOOTLOADER_DISABLED
help
Build a bootloader with the secure boot flag enabled.
Secure bootloader can be one-time-flash (chip will only ever
boot that particular bootloader), or a digest key can be used
to allow the secure bootloader to be re-flashed with
modifications. Secure boot also permanently disables JTAG.
See docs/security/secure-boot.rst for details.
config SECURE_BOOTLOADER_DISABLED
bool "Disabled"
config SECURE_BOOTLOADER_ONE_TIME_FLASH
bool "One-time flash"
help
On first boot, the bootloader will generate a key which is not readable externally or by software. A digest is generated from the bootloader image itself. This digest will be verified on each subsequent boot.
Enabling this option means that the bootloader cannot be changed after the first time it is booted.
config SECURE_BOOTLOADER_REFLASHABLE
bool "Reflashable"
help
Generate the bootloader digest key on the computer instead of inside
the chip. Allows the secure bootloader to be re-flashed by using the
same key.
This option is less secure than one-time flash, because a leak of the digest key allows reflashing of any device that uses it.
endchoice
config SECURE_BOOTLOADER_KEY_FILE
string "Secure bootloader digest key file"
depends on SECURE_BOOTLOADER_REFLASHABLE
default secure_boot_key.bin
help
Path to the key file for a reflashable secure boot digest.
File must contain 32 randomly generated bytes.
Path is evaluated relative to the project directory.
You can generate a new key by running the following command:
espsecure.py generate_key secure_boot_key.bin
See docs/security/secure-boot.rst for details.
config SECURE_BOOTLOADER_ENABLED
bool
default SECURE_BOOTLOADER_ONE_TIME_FLASH || SECURE_BOOTLOADER_REFLASHABLE
endmenu

View file

@ -15,6 +15,8 @@ BOOTLOADER_BUILD_DIR=$(abspath $(BUILD_DIR_BASE)/bootloader)
BOOTLOADER_BIN=$(BOOTLOADER_BUILD_DIR)/bootloader.bin
BOOTLOADER_SDKCONFIG=$(BOOTLOADER_BUILD_DIR)/sdkconfig
SECURE_BOOT_KEYFILE=$(abspath $(call dequote,$(CONFIG_SECURE_BOOTLOADER_KEY_FILE)))
# Custom recursive make for bootloader sub-project
BOOTLOADER_MAKE=+$(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src \
V=$(V) SDKCONFIG=$(BOOTLOADER_SDKCONFIG) \
@ -31,18 +33,67 @@ bootloader-clean:
clean: bootloader-clean
ifdef CONFIG_SECURE_BOOTLOADER_DISABLED
# If secure boot disabled, bootloader flashing is integrated
# with 'make flash' and no warnings are printed.
bootloader: $(BOOTLOADER_BIN)
@echo "$(SEPARATOR)"
@echo "Bootloader built. Default flash command is:"
@echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $(BOOTLOADER_BIN)"
all_binaries: $(BOOTLOADER_BIN)
ESPTOOL_ALL_FLASH_ARGS += 0x1000 $(BOOTLOADER_BIN)
# bootloader-flash calls flash in the bootloader dummy project
bootloader-flash: $(BOOTLOADER_BIN)
$(BOOTLOADER_MAKE) flash
else ifdef CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH
# One time flashing requires user to run esptool.py command themselves,
# and warning is printed about inability to reflash.
bootloader: $(BOOTLOADER_BIN)
@echo $(SEPARATOR)
@echo "Bootloader built. One-time flash command is:"
@echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $(BOOTLOADER_BIN)"
@echo $(SEPARATOR)
@echo "* IMPORTANT: After first boot, BOOTLOADER CANNOT BE RE-FLASHED on same device"
else ifdef CONFIG_SECURE_BOOTLOADER_REFLASHABLE
# Reflashable secure bootloader (recommended for testing only)
# generates a digest binary (bootloader + digest) and prints
# instructions for reflashing. User must run commands manually.
BOOTLOADER_DIGEST_BIN=$(BOOTLOADER_BUILD_DIR)/bootloader-reflash-digest.bin
bootloader: $(BOOTLOADER_DIGEST_BIN)
@echo $(SEPARATOR)
@echo "Bootloader built and secure digest generated. First time flash command is:"
@echo "$(ESPEFUSEPY) burn_key secure_boot $(SECURE_BOOT_KEYFILE)"
@echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $(BOOTLOADER_BIN)"
@echo $(SEPARATOR)
@echo "To reflash the bootloader after initial flash:"
@echo "$(ESPTOOLPY_WRITE_FLASH) 0x0 $(BOOTLOADER_DIGEST_BIN)"
@echo $(SEPARATOR)
@echo "* After first boot, only re-flashes of this kind (with same key) will be accepted."
@echo "* NOT RECOMMENDED TO RE-FLASH the same bootloader-reflash-digest.bin to multiple production devices"
$(BOOTLOADER_DIGEST_BIN): $(BOOTLOADER_BIN) $(SECURE_BOOT_KEYFILE)
@echo "DIGEST $< + $(SECURE_BOOT_KEYFILE) -> $@"
$(Q) $(ESPSECUREPY) digest_secure_bootloader -k $(SECURE_BOOT_KEYFILE) -o $@ $<
$(SECURE_BOOT_KEYFILE):
@echo $(SEPARATOR)
@echo "Need to generate secure boot digest key first. Run following command:"
@echo "$(ESPSECUREPY) generate_key $@"
@echo "Keep key file safe after generating."
@exit 1
else
$(error Bad sdkconfig - one of CONFIG_SECURE_BOOTLOADER_DISABLED, CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH, CONFIG_SECURE_BOOTLOADER_REFLASHABLE must be set)
endif
all_binaries: $(BOOTLOADER_BIN)
# synchronise the project level config to the bootloader's
# config
$(BOOTLOADER_SDKCONFIG): $(PROJECT_PATH)/sdkconfig | $(BOOTLOADER_BUILD_DIR)

View file

@ -148,7 +148,9 @@ bool secure_boot_generate_bootloader_digest(void) {
/* reuse the secure boot IV generation function to generate
the key, as this generator uses the hardware RNG. */
uint32_t buf[32];
ets_secure_boot_start();
ets_secure_boot_rd_iv(buf);
ets_secure_boot_finish();
for (int i = 0; i < 8; i++) {
ESP_LOGV(TAG, "EFUSE_BLK2_WDATA%d_REG = 0x%08x", i, buf[i]);
REG_WRITE(EFUSE_BLK2_WDATA0_REG + 4*i, buf[i]);

View file

@ -11,23 +11,34 @@ PYTHON ?= $(call dequote,$(CONFIG_PYTHON))
# two commands that can be used from other components
# to invoke esptool.py (with or without serial port args)
#
# NB: esptool.py lives in the sdk/bin directory not the component directory
ESPTOOLPY_SRC := $(COMPONENT_PATH)/esptool/esptool.py
ESPTOOLPY := $(PYTHON) $(ESPTOOLPY_SRC) --chip esp32
ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD)
# Supporting esptool command line tools
ESPEFUSEPY := $(PYTHON) $(COMPONENT_PATH)/esptool/espefuse.py
ESPSECUREPY := $(PYTHON) $(COMPONENT_PATH)/esptool/espsecure.py
ESPTOOL_FLASH_OPTIONS := --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) --flash_size $(ESPFLASHSIZE)
# the no-stub argument is temporary until esptool.py fully supports compressed uploads
ESPTOOL_ELF2IMAGE_OPTIONS :=
ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
ESPTOOL_ELF2IMAGE_OPTIONS += "--set-secure-boot-flag"
endif
ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) $(ESPTOOL_FLASH_OPTIONS)
ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN)
$(APP_BIN): $(APP_ELF) $(ESPTOOLPY_SRC)
$(Q) $(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) -o $@ $<
$(Q) $(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) $(ESPTOOL_ELF2IMAGE_OPTIONS) -o $@ $<
flash: all_binaries $(ESPTOOLPY_SRC)
@echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(CONFIG_APP_OFFSET))..."
ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
@echo "(Secure boot enabled, so bootloader not flashed automatically. See 'make bootloader' output)"
endif
$(Q) $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS)
app-flash: $(APP_BIN) $(ESPTOOLPY_SRC)

@ -1 +1 @@
Subproject commit 5c6962e894e0a118c9a4b5760876433493449260
Subproject commit 95dae1651e5aea1adb2b6018b23f65a305f67387

View file

@ -11,13 +11,13 @@
#
.PHONY: build-components menuconfig defconfig all build clean all_binaries
all: all_binaries # other components will add dependencies to 'all_binaries'
@echo "To flash all build output, run 'make flash' or:"
@echo $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS)
# (the reason all_binaries is used instead of 'all' is so that the flash target
# can build everything without triggering the per-component "to flash..."
# output targets.)
all: all_binaries
# see below for recipe of 'all' target
#
# # other components will add dependencies to 'all_binaries'. The
# reason all_binaries is used instead of 'all' is so that the flash
# target can build everything without triggering the per-component "to
# flash..." output targets.)
help:
@echo "Welcome to Espressif IDF build system. Some useful make targets:"
@ -135,6 +135,15 @@ export PROJECT_PATH
#Include functionality common to both project & component
-include $(IDF_PATH)/make/common.mk
all:
ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
@echo "(Secure boot enabled, so bootloader not flashed automatically. See 'make bootloader' output)"
@echo "To flash app & partition table, run 'make flash' or:"
else
@echo "To flash all build output, run 'make flash' or:"
endif
@echo $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS)
# Set default LDFLAGS
LDFLAGS ?= -nostdlib \