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.
This commit is contained in:
parent
d1f40c15ac
commit
ec331b3979
4 changed files with 67 additions and 15 deletions
|
@ -426,4 +426,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
|
||||
|
|
|
@ -205,6 +205,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");
|
||||
|
|
|
@ -69,6 +69,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"
|
||||
#include "bootloader_common.h"
|
||||
|
@ -329,6 +330,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();
|
||||
|
|
|
@ -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 <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.
|
||||
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**.
|
||||
|
||||
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.
|
||||
|
@ -37,6 +39,23 @@ Background
|
|||
|
||||
- If flash encryption may be enabled, the programmer must take certain precautions when writing code that :ref:`uses encrypted flash <using-encrypted-flash>`.
|
||||
|
||||
.. _storing-encrypted-data:
|
||||
|
||||
Storing Encrypted Data
|
||||
----------------------
|
||||
|
||||
Aside from encrypting the firmware binary, the app may need to store some sensitive data in an encrypted form. For example, in a filesystem or NVS data partition.
|
||||
|
||||
The recommended way to do this is to use :ref:`nvs_encryption` .
|
||||
|
||||
Alternatively, it is possible to use the :doc:`Wear Levelling feature </api-reference/storage/wear-levelling>` with an encrypted partition, if the "encrypted" flag is set on the partition. This allows, for example, a FATFS partition to be stored encrypted in flash.
|
||||
|
||||
The following are **not suitable** and will store data where an attacker with physical access can read it out:
|
||||
|
||||
- Custom efuse fields (these can be write protected against modification but not read protected if the app needs to read them)
|
||||
- SPIFFS (SPIFFS is optimized for the read and write behavior of NOR flash, so it's not possible to encrypt this filesystem)
|
||||
|
||||
|
||||
.. _flash-encryption-initialisation:
|
||||
|
||||
Flash Encryption Initialisation
|
||||
|
@ -172,15 +191,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:
|
||||
|
||||
|
@ -269,7 +280,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.
|
||||
|
||||
|
@ -291,15 +302,24 @@ It is recommended to use flash encryption and secure boot together. However, if
|
|||
- :ref:`pregenerated-flash-encryption-key` is still possible, provided the bootloader is not reflashed. Reflashing the bootloader requires the same :ref:`Reflashable <CONFIG_SECURE_BOOTLOADER_MODE>` option to be enabled in the Secure Boot config.
|
||||
|
||||
.. _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 :ref:`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.
|
||||
|
||||
.. _flash-encryption-advanced-features:
|
||||
|
||||
|
|
Loading…
Reference in a new issue