Merge branch 'bugfix/flash_encryption_disable_plaintext_v3.0' into 'release/v3.0'
flash encryption: Add config option to disable any plaintext reflashes (3.0) See merge request espressif/esp-idf!6050
This commit is contained in:
commit
76a240d758
6 changed files with 85 additions and 12 deletions
|
@ -251,4 +251,22 @@ config SECURE_BOOT_TEST_MODE
|
||||||
|
|
||||||
|
|
||||||
endmenu # Potentially Insecure
|
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
|
endmenu # Security features
|
||||||
|
|
|
@ -99,4 +99,15 @@ 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);
|
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
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
void esp_flash_write_protect_crypt_cnt();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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));
|
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);
|
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);
|
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_efuse_burn_new_values();
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Flash encryption completed");
|
ESP_LOGI(TAG, "Flash encryption completed");
|
||||||
|
@ -342,3 +350,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);
|
ESP_LOGE(TAG, "flash operation failed: 0x%x", err);
|
||||||
return 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@
|
||||||
#include "esp_clk_internal.h"
|
#include "esp_clk_internal.h"
|
||||||
#include "esp_timer.h"
|
#include "esp_timer.h"
|
||||||
#include "esp_pm.h"
|
#include "esp_pm.h"
|
||||||
|
#include "esp_flash_encrypt.h"
|
||||||
#include "pm_impl.h"
|
#include "pm_impl.h"
|
||||||
#include "trax.h"
|
#include "trax.h"
|
||||||
|
|
||||||
|
@ -301,6 +302,11 @@ void start_cpu0_default(void)
|
||||||
#endif
|
#endif
|
||||||
#if CONFIG_DISABLE_BASIC_ROM_CONSOLE
|
#if CONFIG_DISABLE_BASIC_ROM_CONSOLE
|
||||||
esp_efuse_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
|
#endif
|
||||||
rtc_gpio_force_hold_dis_all();
|
rtc_gpio_force_hold_dis_all();
|
||||||
esp_vfs_dev_uart_register();
|
esp_vfs_dev_uart_register();
|
||||||
|
|
|
@ -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 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 <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 <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.**
|
**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.
|
- Reset the device and it will re-encrypt plaintext partitions, then burn the :ref:`FLASH_CRYPT_CNT` again to re-enable encryption.
|
||||||
|
|
||||||
|
To prevent any further serial updates, see :ref:`securing-flash-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.
|
|
||||||
|
|
||||||
.. _pregenerated-flash-encryption-key:
|
.. _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 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.
|
- Not all data is stored encrypted. If storing data on flash, check if the method you are using (library, API, etc.) supports flash encryption.
|
||||||
|
|
||||||
|
@ -270,6 +264,26 @@ 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 <secure-boot>`.
|
- 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 <secure-boot>`.
|
||||||
|
|
||||||
|
.. _flash-encryption-without-secure-boot:
|
||||||
|
.. _securing-flash-encryption:
|
||||||
|
|
||||||
|
Securing Flash Encryption
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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:
|
.. _flash-encryption-advanced-features:
|
||||||
|
|
||||||
Flash Encryption Advanced Features
|
Flash Encryption Advanced Features
|
||||||
|
|
|
@ -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 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 <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 <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::
|
.. 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
|
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 <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.
|
||||||
|
|
Loading…
Reference in a new issue