From cdabee59ef6e333f719d768fe1fddae6c208e00c Mon Sep 17 00:00:00 2001 From: Sagar Bijwe Date: Tue, 7 Aug 2018 17:29:11 +0530 Subject: [PATCH 1/2] docs: Added more wordings to capture secure boot and flash encryption dependency. --- .../bootloader_support/include/esp_flash_encrypt.h | 10 ++++++++++ components/bootloader_support/src/flash_encrypt.c | 10 ++++++++++ docs/security/flash-encryption.rst | 13 ++++++++++++- docs/security/secure-boot.rst | 8 +++++++- 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/components/bootloader_support/include/esp_flash_encrypt.h b/components/bootloader_support/include/esp_flash_encrypt.h index ba370644a4..2f4679b2a4 100644 --- a/components/bootloader_support/include/esp_flash_encrypt.h +++ b/components/bootloader_support/include/esp_flash_encrypt.h @@ -99,4 +99,14 @@ esp_err_t esp_flash_encrypt_check_and_update(void); */ esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length); +/** @brief Write protect FLASH_CRYPT_CNT + * + * Intended to be called as a part of boot process if flash encryption + * is enabled but secure boot is not used. This should protect against + * serial re-flashing of an unauthorised code in absence of secure boot. + * + * @return + */ +void esp_flash_write_protect_crypt_cnt(); + #endif diff --git a/components/bootloader_support/src/flash_encrypt.c b/components/bootloader_support/src/flash_encrypt.c index 7a4cfcb835..40ec7b8596 100644 --- a/components/bootloader_support/src/flash_encrypt.c +++ b/components/bootloader_support/src/flash_encrypt.c @@ -342,3 +342,13 @@ esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length) ESP_LOGE(TAG, "flash operation failed: 0x%x", err); return err; } + +void esp_flash_write_protect_crypt_cnt() +{ + uint32_t efuse_blk0 = REG_READ(EFUSE_BLK0_RDATA0_REG); + bool flash_crypt_wr_dis = efuse_blk0 & EFUSE_WR_DIS_FLASH_CRYPT_CNT; + if(!flash_crypt_wr_dis) { + REG_WRITE(EFUSE_BLK0_WDATA0_REG, EFUSE_WR_DIS_FLASH_CRYPT_CNT); + esp_efuse_burn_new_values(); + } +} diff --git a/docs/security/flash-encryption.rst b/docs/security/flash-encryption.rst index 433578a467..8471ce29d9 100644 --- a/docs/security/flash-encryption.rst +++ b/docs/security/flash-encryption.rst @@ -3,7 +3,7 @@ Flash Encryption Flash Encryption is a feature for encrypting the contents of the ESP32's attached SPI flash. When flash encryption is enabled, physical readout of the SPI flash is not sufficient to recover most flash contents. -Flash Encryption is separate from the :doc:`Secure Boot ` feature, and you can use flash encryption without enabling secure boot. However we recommend using both features together for a secure environment. +Flash Encryption is separate from the :doc:`Secure Boot ` feature, and you can use flash encryption without enabling secure boot. However we recommend using both features together for a secure environment. In absence of secure boot, additional configuration needs to be performed to ensure effectiveness of flash encryption. See :ref:`flash-encryption-without-secure-boot` for more details. **IMPORTANT: Enabling flash encryption limits your options for further updates of your ESP32. Make sure to read this document (including :ref:`flash-encryption-limitations`) and understand the implications of enabling flash encryption.** @@ -270,6 +270,17 @@ Flash Encryption prevents plaintext readout of the encrypted flash, to protect f - Flash encryption alone may not prevent an attacker from modifying the firmware of the device. To prevent unauthorised firmware from runningon the device, use flash encryption in combination with :doc:`Secure Boot `. +.. _flash-encryption-without-secure-boot: + +Using Flash Encryption without Secure Boot +------------------------------------------ + +If flash encryption is used without secure boot, it is possible to load unauthorised code using serial re-flashing. See :ref:`updating-encrypted-flash-serial` for details. This unauthorised code can then read all encrypted partitions (in decrypted form) making flash-encryption ineffective. This can be avoided by write-protecting :ref:`FLASH_CRYPT_CNT` and thereby disallowing serial re-flashing. :ref:`FLASH_CRYPT_CNT` can be write-protected using command:: + + espefuse.py --port PORT write_protect_efuse FLASH_CRYPT_CNT + +Alternatively, the app can call :func:`esp_flash_write_protect_crypt_cnt` during its startup process. + .. _flash-encryption-advanced-features: Flash Encryption Advanced Features diff --git a/docs/security/secure-boot.rst b/docs/security/secure-boot.rst index dcd6d4b60e..0030cabbce 100644 --- a/docs/security/secure-boot.rst +++ b/docs/security/secure-boot.rst @@ -3,7 +3,7 @@ Secure Boot Secure Boot is a feature for ensuring only your code can run on the chip. Data loaded from flash is verified on each reset. -Secure Boot is separate from the :doc:`Flash Encryption ` feature, and you can use secure boot without encrypting the flash contents. However we recommend using both features together for a secure environment. +Secure Boot is separate from the :doc:`Flash Encryption ` feature, and you can use secure boot without encrypting the flash contents. However we recommend using both features together for a secure environment. See :ref:`secure-boot-and-flash-encr` for more details. .. important:: @@ -235,3 +235,9 @@ Keyfile is the 32 byte raw secure boot key for the device. To flash this digest esptool.py write_flash 0x0 bootloader-digest.bin +.. _secure-boot-and-flash-encr: + +Secure Boot & Flash Encryption +------------------------------ + +If secure boot is used without :doc:`Flash Encryption `, it is possible to launch "time-of-check to time-of-use" attack, where flash contents are swapped after the image is verified and running. Therefore, it is recommended to use both the features together. From 8df3c666db10a1b9ecd0080944d86a2ca2804e59 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 12 Jun 2019 11:03:42 +1000 Subject: [PATCH 2/2] flash encryption: Add config option to disable any plaintext reflashes Enabled by default when Secure Boot is on, so Flash Encryption protection is always available in case of a Secure Boot bypass. --- components/bootloader/Kconfig.projbuild | 18 ++++++++++ .../include/esp_flash_encrypt.h | 5 +-- .../bootloader_support/src/flash_encrypt.c | 8 +++++ components/esp32/cpu_start.c | 6 ++++ docs/security/flash-encryption.rst | 33 ++++++++++--------- 5 files changed, 53 insertions(+), 17 deletions(-) diff --git a/components/bootloader/Kconfig.projbuild b/components/bootloader/Kconfig.projbuild index 18989dc089..72427ffc7e 100644 --- a/components/bootloader/Kconfig.projbuild +++ b/components/bootloader/Kconfig.projbuild @@ -251,4 +251,22 @@ config SECURE_BOOT_TEST_MODE endmenu # Potentially Insecure + + config FLASH_ENCRYPTION_DISABLE_PLAINTEXT + bool "Disable serial reflashing of plaintext firmware" + depends on FLASH_ENCRYPTION_ENABLED + default y if SECURE_BOOT_ENABLED + default n if !SECURE_BOOT_ENABLED + help + If this option is enabled, flash encryption is permanently enabled after first boot by write-protecting + the FLASH_CRYPT_CNT efuse. This is the recommended configuration for a secure production system. + + If this option is disabled, FLASH_CRYPT_CNT is left writeable and up to 4 plaintext re-flashes are allowed. + An attacker with physical access will be able to read out encrypted flash contents until all plaintext + re-flashes have been used up. + + If this option is disabled and hardware Secure Boot is enabled, Secure Boot must be configured in + Reflashable mode so that a new Secure Boot digest can be flashed at the same time as plaintext firmware. + This combination is not secure and should not be used for a production system. + endmenu # Security features diff --git a/components/bootloader_support/include/esp_flash_encrypt.h b/components/bootloader_support/include/esp_flash_encrypt.h index 2f4679b2a4..8acc75b0d6 100644 --- a/components/bootloader_support/include/esp_flash_encrypt.h +++ b/components/bootloader_support/include/esp_flash_encrypt.h @@ -102,8 +102,9 @@ esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length); /** @brief Write protect FLASH_CRYPT_CNT * * Intended to be called as a part of boot process if flash encryption - * is enabled but secure boot is not used. This should protect against - * serial re-flashing of an unauthorised code in absence of secure boot. + * should be permanently enabled. This should protect against serial + * re-flashing of an unauthorised code in absence of secure boot or if + * secure boot protection is bypassed. * * @return */ diff --git a/components/bootloader_support/src/flash_encrypt.c b/components/bootloader_support/src/flash_encrypt.c index 40ec7b8596..2526cd3a66 100644 --- a/components/bootloader_support/src/flash_encrypt.c +++ b/components/bootloader_support/src/flash_encrypt.c @@ -210,6 +210,14 @@ static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_cry uint32_t new_flash_crypt_cnt = flash_crypt_cnt + (1 << (ffs_inv - 1)); ESP_LOGD(TAG, "FLASH_CRYPT_CNT 0x%x -> 0x%x", flash_crypt_cnt, new_flash_crypt_cnt); REG_SET_FIELD(EFUSE_BLK0_WDATA0_REG, EFUSE_FLASH_CRYPT_CNT, new_flash_crypt_cnt); + +#ifdef CONFIG_FLASH_ENCRYPTION_DISABLE_PLAINTEXT + ESP_LOGI(TAG, "Write protecting FLASH_CRYPT_CNT efuse..."); + REG_SET_BIT(EFUSE_BLK0_WDATA0_REG, EFUSE_WR_DIS_FLASH_CRYPT_CNT); +#else + ESP_LOGW(TAG, "Not disabling FLASH_CRYPT_CNT - plaintext flashing is still possible"); +#endif + esp_efuse_burn_new_values(); ESP_LOGI(TAG, "Flash encryption completed"); diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index c702cde82f..5218608195 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -67,6 +67,7 @@ #include "esp_clk_internal.h" #include "esp_timer.h" #include "esp_pm.h" +#include "esp_flash_encrypt.h" #include "pm_impl.h" #include "trax.h" @@ -301,6 +302,11 @@ void start_cpu0_default(void) #endif #if CONFIG_DISABLE_BASIC_ROM_CONSOLE esp_efuse_disable_basic_rom_console(); +#endif +#ifdef CONFIG_FLASH_ENCRYPTION_DISABLE_PLAINTEXT + if (esp_flash_encryption_enabled()) { + esp_flash_write_protect_crypt_cnt(); + } #endif rtc_gpio_force_hold_dis_all(); esp_vfs_dev_uart_register(); diff --git a/docs/security/flash-encryption.rst b/docs/security/flash-encryption.rst index 8471ce29d9..b59b5265e3 100644 --- a/docs/security/flash-encryption.rst +++ b/docs/security/flash-encryption.rst @@ -3,7 +3,9 @@ Flash Encryption Flash Encryption is a feature for encrypting the contents of the ESP32's attached SPI flash. When flash encryption is enabled, physical readout of the SPI flash is not sufficient to recover most flash contents. -Flash Encryption is separate from the :doc:`Secure Boot ` feature, and you can use flash encryption without enabling secure boot. However we recommend using both features together for a secure environment. In absence of secure boot, additional configuration needs to be performed to ensure effectiveness of flash encryption. See :ref:`flash-encryption-without-secure-boot` for more details. +Flash Encryption is separate from the :doc:`Secure Boot ` feature, and you can use flash encryption without enabling secure boot. However, **for a secure environment both should be used simultaneously**. In absence of secure boot, additional configuration needs to be performed to ensure effectiveness of flash encryption. See :ref:`flash-encryption-without-secure-boot` for more details. + +When using any non-default configuration in production, additional steps may also be needed to ensure effectiveness of flash encryption. See :ref:`securing-flash-encryption` for more details. **IMPORTANT: Enabling flash encryption limits your options for further updates of your ESP32. Make sure to read this document (including :ref:`flash-encryption-limitations`) and understand the implications of enabling flash encryption.** @@ -164,15 +166,7 @@ Serial Re-Flashing Procedure - Reset the device and it will re-encrypt plaintext partitions, then burn the :ref:`FLASH_CRYPT_CNT` again to re-enable encryption. - -Disabling Serial Updates -~~~~~~~~~~~~~~~~~~~~~~~~ - -To prevent further plaintext updates via serial, use espefuse.py to write protect the :ref:`FLASH_CRYPT_CNT` after flash encryption has been enabled (ie after first boot is complete):: - - espefuse.py --port PORT write_protect_efuse FLASH_CRYPT_CNT - -This prevents any further modifications to disable or re-enable flash encryption. +To prevent any further serial updates, see :ref:`securing-flash-encryption`. .. _pregenerated-flash-encryption-key: @@ -260,7 +254,7 @@ Limitations of Flash Encryption Flash Encryption prevents plaintext readout of the encrypted flash, to protect firmware against unauthorised readout and modification. It is important to understand the limitations of the flash encryption system: -- Flash encryption is only as strong as the key. For this reason, we recommend keys are generated on the device during first boot (default behaviour). If generating keys off-device (see :ref:`pregenerated-flash-encryption-key`), ensure proper procedure is followed. +- Flash encryption is only as strong as the key. For this reason, we recommend keys are generated on the device during first boot (default behavior). If generating keys off-device (see :ref:`pregenerated-flash-encryption-key`), ensure proper procedure is followed. - Not all data is stored encrypted. If storing data on flash, check if the method you are using (library, API, etc.) supports flash encryption. @@ -271,15 +265,24 @@ Flash Encryption prevents plaintext readout of the encrypted flash, to protect f - Flash encryption alone may not prevent an attacker from modifying the firmware of the device. To prevent unauthorised firmware from runningon the device, use flash encryption in combination with :doc:`Secure Boot `. .. _flash-encryption-without-secure-boot: +.. _securing-flash-encryption: -Using Flash Encryption without Secure Boot ------------------------------------------- +Securing Flash Encryption +------------------------- -If flash encryption is used without secure boot, it is possible to load unauthorised code using serial re-flashing. See :ref:`updating-encrypted-flash-serial` for details. This unauthorised code can then read all encrypted partitions (in decrypted form) making flash-encryption ineffective. This can be avoided by write-protecting :ref:`FLASH_CRYPT_CNT` and thereby disallowing serial re-flashing. :ref:`FLASH_CRYPT_CNT` can be write-protected using command:: +In a production setting it's important to ensure that flash encryption cannot be temporarily disabled. + +This is because if the :doc:`secure-boot` feature is not enabled, or if Secure Boot is somehow bypassed by an attacker, then unauthorised code can be written to flash in plaintext. This code can then re-enable encryption and access encrypted data, making flash encryption ineffective. + +This problem must be avoided by write-protecting :ref:`FLASH_CRYPT_CNT` and thereby keeping flash encryption permanently enabled. + +The simplest way to do this is to enable the configuration option ``CONFIG_FLASH_ENCRYPTION_DISABLE_PLAINTEXT`` (enabled by default if Secure Boot is enabled). This option causes :ref:`FLASH_CRYPT_CNT` to be write protected during initial app startup, or during first boot when the bootloader enables flash encryption. This includes if an app with this option is OTA updated. + +Alternatively, :ref:`FLASH_CRYPT_CNT` can be write-protected using the serial bootloader:: espefuse.py --port PORT write_protect_efuse FLASH_CRYPT_CNT -Alternatively, the app can call :func:`esp_flash_write_protect_crypt_cnt` during its startup process. +A third option with more flexibility: the app can call :func:`esp_flash_write_protect_crypt_cnt` at a convenient time during its startup or provisioning process, or set the ``FLASH_ENCRYPTION_DISABLE_PLAINTEXT`` config option for this to happen automatically. .. _flash-encryption-advanced-features: