From 506c8cd964a43048e43bd193e1ff4a7b039fab8b Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 25 Nov 2016 14:09:26 +1100 Subject: [PATCH] secure boot & flash encryption: Rework configuration options Add UART bootloader disable options for flash encryption --- components/bootloader/Kconfig.projbuild | 137 +++++++++++++----- components/bootloader/Makefile.projbuild | 5 +- .../bootloader/src/main/bootloader_start.c | 8 +- components/bootloader_support/component.mk | 2 +- .../bootloader_support/src/flash_encrypt.c | 34 ++++- .../bootloader_support/src/secure_boot.c | 22 ++- components/esptool_py/Makefile.projbuild | 4 +- make/project.mk | 2 +- 8 files changed, 156 insertions(+), 58 deletions(-) diff --git a/components/bootloader/Kconfig.projbuild b/components/bootloader/Kconfig.projbuild index 3070b36ae2..270369b2c6 100644 --- a/components/bootloader/Kconfig.projbuild +++ b/components/bootloader/Kconfig.projbuild @@ -34,21 +34,22 @@ endmenu menu "Security features" -choice SECURE_BOOTLOADER - bool "Secure bootloader" - default SECURE_BOOTLOADER_DISABLED +config SECURE_BOOT_ENABLED + bool "Enable secure boot in bootloader" + default N help - Build a bootloader with the secure boot flag enabled. + Build a bootloader which enables secure boot on first boot. - 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. + Once enabled, secure boot will not boot a modified bootloader. The bootloader will only load a partition table or boot an app if the data has a verified digital signature. + + When enabling secure boot, JTAG and ROM BASIC Interpreter are permanently disabled by default. See docs/security/secure-boot.rst for details. -config SECURE_BOOTLOADER_DISABLED - bool "Disabled" +choice SECURE_BOOTLOADER_MODE + bool "Secure bootloader mode" + depends on SECURE_BOOT_ENABLED + default SECURE_BOOTLOADER_ONE_TIME_FLASH config SECURE_BOOTLOADER_ONE_TIME_FLASH bool "One-time flash" @@ -70,10 +71,10 @@ endchoice config SECURE_BOOT_SIGNING_KEY string "Secure boot signing key" - depends on SECURE_BOOTLOADER_ENABLED + depends on SECURE_BOOT_ENABLED default secure_boot_signing_key.pem help - Path to the key file used to sign partition tables and app images for secure boot. + Path to the key file used to sign partition tables and app images for secure boot. Once secure boot is enabled, bootloader will only boot if partition table and app image are signed. Key file is an ECDSA private key (NIST256p curve) in PEM format. @@ -84,44 +85,106 @@ config SECURE_BOOT_SIGNING_KEY See docs/security/secure-boot.rst for details. -config SECURE_BOOT_DISABLE_JTAG - bool "First boot: Permanently disable JTAG" - depends on SECURE_BOOTLOADER_ENABLED - default Y +config SECURE_BOOT_INSECURE + bool "Allow potentially insecure options" + depends on SECURE_BOOT_ENABLED + default N + help + You can disable some of the default protections offered by secure boot, in order to enable testing or a custom combination of security features. + + Only enable these options if you are very sure. + + Refer to docs/security/secure-boot.rst and docs/security/flash-encryption.rst for details. + +config FLASH_ENCRYPTION_ENABLED + bool "Enable flash encryption on boot" + default N + help + If this option is set, flash contents will be encrypted by the bootloader on first boot. + + Note: After first boot, the system will be permanently encrypted. + See docs/securityflash-encryption.rst for details. + +config FLASH_ENCRYPTION_INSECURE + bool "Allow potentially insecure options" + depends on FLASH_ENCRYPTION_ENABLED + default N + help + You can disable some of the default protections offered by flash encryption, in order to enable testing or a custom combination of security features. + + Only enable these options if you are very sure. + + Refer to docs/security/secure-boot.rst and docs/security/flash-encryption.rst for details. + +menu "Potentially insecure options" + visible if FLASH_ENCRYPTION_INSECURE || SECURE_BOOT_INSECURE + +# NOTE: Options in this menu NEED to have SECURE_BOOT_INSECURE +# and/or FLASH_ENCRYPTION_INSECURE in "depends on", as the menu +# itself doesn't enable/disable its children (if it's not set, +# it's possible for the insecure menu to be disabled but the insecure option +# to remain on which is very bad.) + +config SECURE_BOOT_ALLOW_ROM_BASIC + bool "Leave ROM BASIC Interpreter available on reset" + depends on SECURE_BOOT_INSECURE + default N help - Bootloader permanently disable JTAG (across entire chip) when enabling secure boot. This happens on first boot of the bootloader. + If not set (default), bootloader permanently disables ROM BASIC (on UART console) as a fallback if the bootloader image becomes invalid. This happens on first boot. - It is recommended this option remains set for production environments. + Only set this option in testing environments. -config SECURE_BOOT_DISABLE_ROM_BASIC - bool "First boot: Permanently disable ROM BASIC fallback" - depends on SECURE_BOOTLOADER_ENABLED - default Y +config SECURE_BOOT_ALLOW_JTAG + bool "Allow JTAG Debugging" + depends on SECURE_BOOT_INSECURE || FLASH_ENCRYPTION_INSECURE + default N help - Bootloader permanently disables ROM BASIC (on UART console) as a fallback if the bootloader image becomes invalid. This happens on first boot. + If not set (default), the bootloader will permanently disable JTAG (across entire chip) on first boot when either secure boot or flash encryption is enabled. - It is recommended this option remains set in production environments. + Setting this option leaves JTAG on for debugging, which negates all protections of flash encryption and some of the protections of secure boot. + + Only set this option in testing environments. + + +config FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_ENCRYPT + bool "Leave UART bootloader encryption enabled" + depends on FLASH_ENCRYPTION_INSECURE + default N + help + If not set (default), the bootloader will permanently disable UART bootloader encryption access on first boot. If set, the UART bootloader will still be able to access hardware encryption. + + It is recommended to only set this option in testing environments. + +config FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_DECRYPT + bool "Leave UART bootloader decryption enabled" + depends on FLASH_ENCRYPTION_INSECURE + default N + help + If not set (default), the bootloader will permanently disable UART bootloader decryption access on first boot. If set, the UART bootloader will still be able to access hardware decryption. + + Only set this option in testing environments. Setting this option allows complete bypass of flash encryption. + +config FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_CACHE + bool "Leave UART bootloader flash cache enabled" + depends on FLASH_ENCRYPTION_INSECURE + default N + help + If not set (default), the bootloader will permanently disable UART bootloader flash cache access on first boot. If set, the UART bootloader will still be able to access the flash cache. + + Only set this option in testing environments. config SECURE_BOOT_TEST_MODE - bool "Test mode: don't actually enable secure boot" - depends on SECURE_BOOTLOADER_ENABLED + bool "Secure boot test mode: don't permanently set any efuses" + depends on SECURE_BOOT_INSECURE default N help If this option is set, all permanent secure boot changes (via Efuse) are disabled. - This option is for testing purposes only - it effectively completely disables secure boot protection. + Log output will state changes which would be applied, but they will not be. -config SECURE_BOOTLOADER_ENABLED - bool - default SECURE_BOOTLOADER_ONE_TIME_FLASH || SECURE_BOOTLOADER_REFLASHABLE + This option is for testing purposes only - it completely disables secure boot protection. -config FLASH_ENCRYPTION_ENABLED - bool "Enable flash encryption on boot" - help - If this option is set, flash contents will be encrypted by the bootloader on first boot. - - Note: After first boot, the system will be permanently encrypted. - See docs/securityflash-encryption.rst for details. +endmenu # potentially insecure endmenu \ No newline at end of file diff --git a/components/bootloader/Makefile.projbuild b/components/bootloader/Makefile.projbuild index 27c5857c3d..3f83803ad5 100644 --- a/components/bootloader/Makefile.projbuild +++ b/components/bootloader/Makefile.projbuild @@ -32,7 +32,7 @@ $(BOOTLOADER_BIN): $(SDKCONFIG_MAKEFILE) clean: bootloader-clean -ifdef CONFIG_SECURE_BOOTLOADER_DISABLED +ifndef CONFIG_SECURE_BOOT_ENABLED # If secure boot disabled, bootloader flashing is integrated # with 'make flash' and no warnings are printed. @@ -90,7 +90,10 @@ bootloader: @exit 1 endif +ifndef CONFIG_SECURE_BOOT_ENABLED +# don't build bootloader by default is secure boot is enabled all_binaries: $(BOOTLOADER_BIN) +endif bootloader-clean: $(BOOTLOADER_MAKE) app-clean diff --git a/components/bootloader/src/main/bootloader_start.c b/components/bootloader/src/main/bootloader_start.c index c1fa2a8135..80b37db40c 100644 --- a/components/bootloader/src/main/bootloader_start.c +++ b/components/bootloader/src/main/bootloader_start.c @@ -118,7 +118,7 @@ bool load_partition_table(bootloader_state_t* bs) ESP_LOGI(TAG, "Partition Table:"); ESP_LOGI(TAG, "## Label Usage Type ST Offset Length"); -#ifdef CONFIG_SECURE_BOOTLOADER_ENABLED +#ifdef CONFIG_SECURE_BOOT_ENABLED if(esp_secure_boot_enabled()) { ESP_LOGI(TAG, "Verifying partition table signature..."); esp_err_t err = esp_secure_boot_verify_signature(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN); @@ -226,7 +226,7 @@ static bool ota_select_valid(const esp_ota_select_entry_t *s) void bootloader_main() { ESP_LOGI(TAG, "Espressif ESP32 2nd stage bootloader v. %s", BOOT_VERSION); -#if defined(CONFIG_SECURE_BOOTLOADER_ENABLED) || defined(CONFIG_FLASH_ENCRYPTION_ENABLED) +#if defined(CONFIG_SECURE_BOOT_ENABLED) || defined(CONFIG_FLASH_ENCRYPTION_ENABLED) esp_err_t err; #endif esp_image_header_t fhdr; @@ -322,7 +322,7 @@ void bootloader_main() return; } -#ifdef CONFIG_SECURE_BOOTLOADER_ENABLED +#ifdef CONFIG_SECURE_BOOT_ENABLED /* Generate secure digest from this bootloader to protect future modifications */ ESP_LOGI(TAG, "Checking secure boot..."); @@ -374,7 +374,7 @@ static void unpack_load_app(const esp_partition_pos_t* partition) return; } -#ifdef CONFIG_SECURE_BOOTLOADER_ENABLED +#ifdef CONFIG_SECURE_BOOT_ENABLED if (esp_secure_boot_enabled()) { ESP_LOGI(TAG, "Verifying app signature @ 0x%x (length 0x%x)", partition->offset, image_length); err = esp_secure_boot_verify_signature(partition->offset, image_length); diff --git a/components/bootloader_support/component.mk b/components/bootloader_support/component.mk index a7e5b849dc..c3ece6dca9 100755 --- a/components/bootloader_support/component.mk +++ b/components/bootloader_support/component.mk @@ -12,7 +12,7 @@ COMPONENT_SRCDIRS := src # # Secure boot signing key support # -ifdef CONFIG_SECURE_BOOTLOADER_ENABLED +ifdef CONFIG_SECURE_BOOT_ENABLED # this path is created relative to the component build directory SECURE_BOOT_VERIFICATION_KEY := $(abspath signature_verification_key.bin) diff --git a/components/bootloader_support/src/flash_encrypt.c b/components/bootloader_support/src/flash_encrypt.c index 49979237cc..8b9ca60cd1 100644 --- a/components/bootloader_support/src/flash_encrypt.c +++ b/components/bootloader_support/src/flash_encrypt.c @@ -114,11 +114,37 @@ static esp_err_t initialise_flash_encryption(void) REG_WRITE(EFUSE_BLK0_WDATA5_REG, EFUSE_FLASH_CRYPT_CONFIG_M); esp_efuse_burn_new_values(); -#ifndef CONFIG_FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_WRITE - ESP_LOGI(TAG, "Disable UART bootloader write..."); - //REG_WRITE(EFUSE_BLK0_ - + uint32_t new_wdata6 = 0; +#ifndef CONFIG_FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_ENCRYPT + ESP_LOGI(TAG, "Disable UART bootloader encryption..."); + new_wdata6 |= EFUSE_DISABLE_DL_ENCRYPT; +#else + ESP_LOGW(TAG, "Not disabling UART bootloader encryption"); #endif +#ifndef CONFIG_FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_DECRYPT + ESP_LOGI(TAG, "Disable UART bootloader decryption..."); + new_wdata6 |= EFUSE_DISABLE_DL_DECRYPT; +#else + ESP_LOGW(TAG, "Not disabling UART bootloader decryption - SECURITY COMPROMISED"); +#endif +#ifndef CONFIG_FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_CACHE + ESP_LOGI(TAG, "Disable UART bootloader MMU cache..."); + new_wdata6 |= EFUSE_DISABLE_DL_CACHE; +#else + ESP_LOGW(TAG, "Not disabling UART bootloader MMU cache - SECURITY COMPROMISED"); +#endif +#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG + ESP_LOGI(TAG, "Disable JTAG..."); + new_wdata6 |= EFUSE_RD_DISABLE_JTAG; +#else + ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED"); +#endif + + if (new_wdata6 != 0) { + REG_WRITE(EFUSE_BLK0_WDATA6_REG, new_wdata6); + esp_efuse_burn_new_values(); + } + return ESP_OK; } diff --git a/components/bootloader_support/src/secure_boot.c b/components/bootloader_support/src/secure_boot.c index e5b5e94745..0230e85ad5 100644 --- a/components/bootloader_support/src/secure_boot.c +++ b/components/bootloader_support/src/secure_boot.c @@ -96,7 +96,7 @@ static bool secure_boot_generate(uint32_t image_len){ static inline void burn_efuses() { #ifdef CONFIG_SECURE_BOOT_TEST_MODE - ESP_LOGE(TAG, "SECURE BOOT TEST MODE. Not really burning any efuses!"); + ESP_LOGE(TAG, "SECURE BOOT TEST MODE. Not really burning any efuses! NOT SECURE"); #else esp_efuse_burn_new_values(); #endif @@ -156,6 +156,7 @@ esp_err_t esp_secure_boot_permanently_enable(void) { } ESP_LOGI(TAG, "Digest generation complete."); +#ifndef CONFIG_SECURE_BOOT_TEST_MODE if (!efuse_key_read_protected) { ESP_LOGE(TAG, "Pre-loaded key is not read protected. Refusing to blow secure boot efuse."); return ESP_ERR_INVALID_STATE; @@ -164,21 +165,26 @@ esp_err_t esp_secure_boot_permanently_enable(void) { ESP_LOGE(TAG, "Pre-loaded key is not write protected. Refusing to blow secure boot efuse."); return ESP_ERR_INVALID_STATE; } +#endif ESP_LOGI(TAG, "blowing secure boot efuse..."); ESP_LOGD(TAG, "before updating, EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG)); uint32_t new_wdata6 = EFUSE_RD_ABS_DONE_0; - #ifdef CONFIG_SECURE_BOOT_DISABLE_JTAG - ESP_LOGI(TAG, "disabling JTAG..."); +#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG + ESP_LOGI(TAG, "Disable JTAG..."); new_wdata6 |= EFUSE_RD_DISABLE_JTAG; - #endif +#else + ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED"); +#endif - #ifdef CONFIG_SECURE_BOOT_DISABLE_ROM_BASIC - ESP_LOGI(TAG, "disabling UART bootloader..."); - new_wdata6 |= EFUSE_RD_CONSOLE_DEBUG_DISABLE_S; - #endif +#ifndef CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC + ESP_LOGI(TAG, "Disable ROM BASIC interpreter fallback..."); + new_wdata6 |= EFUSE_RD_CONSOLE_DEBUG_DISABLE; +#else + ESP_LOGW(TAG, "Not disabling ROM BASIC fallback - SECURITY COMPROMISED"); +#endif REG_WRITE(EFUSE_BLK0_WDATA6_REG, new_wdata6); burn_efuses(); diff --git a/components/esptool_py/Makefile.projbuild b/components/esptool_py/Makefile.projbuild index acbada7244..4930ded38d 100644 --- a/components/esptool_py/Makefile.projbuild +++ b/components/esptool_py/Makefile.projbuild @@ -28,7 +28,7 @@ ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_CO ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN) -ifdef CONFIG_SECURE_BOOTLOADER_ENABLED +ifdef CONFIG_SECURE_BOOT_ENABLED ifndef IS_BOOTLOADER_BUILD # for secure boot, add a signing step to get from unsiged app to signed app APP_BIN_UNSIGNED := $(APP_BIN:.bin=-unsigned.bin) @@ -45,7 +45,7 @@ $(APP_BIN_UNSIGNED): $(APP_ELF) $(ESPTOOLPY_SRC) flash: all_binaries $(ESPTOOLPY_SRC) @echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(CONFIG_APP_OFFSET))..." -ifdef CONFIG_SECURE_BOOTLOADER_ENABLED +ifdef CONFIG_SECURE_BOOT_ENABLED @echo "(Secure boot enabled, so bootloader not flashed automatically. See 'make bootloader' output)" endif $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS) diff --git a/make/project.mk b/make/project.mk index 181152f118..d4ecea3b79 100644 --- a/make/project.mk +++ b/make/project.mk @@ -139,7 +139,7 @@ export COMPONENT_INCLUDES include $(IDF_PATH)/make/common.mk all: -ifdef CONFIG_SECURE_BOOTLOADER_ENABLED +ifdef CONFIG_SECURE_BOOT_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