efuse: Add 'disable Download Mode' & ESP32-S2 'Secure Download Mode' functionality

This commit is contained in:
Angus Gratton 2020-04-25 16:36:53 +10:00 committed by Angus Gratton
parent 48d9c14c28
commit f64ae4fa99
11 changed files with 195 additions and 45 deletions

View file

@ -587,6 +587,7 @@ menu "Security features"
config SECURE_FLASH_ENCRYPTION_MODE_RELEASE
bool "Release"
select SECURE_ENABLE_SECURE_ROM_DL_MODE
endchoice
@ -698,5 +699,48 @@ menu "Security features"
the wrong device. The device needs to have flash encryption already enabled using espefuse.py.
endmenu # Potentially Insecure
config SECURE_DISABLE_ROM_DL_MODE
bool "Permanently disable ROM Download Mode"
depends on !IDF_TARGET_ESP32 || ESP32_REV_MIN_3
default n
help
If set, during startup the app will burn an eFuse bit to permanently disable the UART ROM
Download Mode. This prevents any future use of esptool.py, espefuse.py and similar tools.
Once disabled, if the SoC is booted with strapping pins set for ROM Download Mode
then an error is printed instead.
It is recommended to enable this option in any production application where Flash
Encryption and/or Secure Boot is enabled and access to Download Mode is not required.
It is also possible to permanently disable Download Mode by calling
esp_efuse_disable_rom_download_mode() at runtime.
config SECURE_ENABLE_SECURE_ROM_DL_MODE
bool "Permanently switch to ROM UART Secure Download mode"
depends on IDF_TARGET_ESP32S2 && !SECURE_DISABLE_ROM_DL_MODE
help
If set, during startup the app will burn an eFuse bit to permanently switch the UART ROM
Download Mode into a separate Secure Download mode. This option can only work if
Download Mode is not already disabled by eFuse.
Secure Download mode limits the use of Download Mode functions to simple flash read,
write and erase operations, plus a command to return a summary of currently enabled
security features.
Secure Download mode is not compatible with the esptool.py flasher stub feature,
espefuse.py, read/writing memory or registers, encrypted download, or any other
features that interact with unsupported Download Mode commands.
Secure Download mode should be enabled in any application where Flash Encryption
and/or Secure Boot is enabled. Disabling this option does not immediately cancel
the benefits of the security features, but it increases the potential "attack
surface" for an attacker to try and bypass them with a successful physical attack.
It is also possible to enable secure download mode at runtime by calling
esp_efuse_enable_rom_secure_download_mode()
endmenu # Security features

View file

@ -128,6 +128,10 @@ esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length);
* is enabled but secure boot is not used. This should protect against
* serial re-flashing of an unauthorised code in absence of secure boot.
*
* @note On ESP32 V3 only, write protecting FLASH_CRYPT_CNT will also prevent
* disabling UART Download Mode. If both are wanted, call
* esp_efuse_disable_rom_download_mode() before calling this function.
*
*/
void esp_flash_write_protect_crypt_cnt(void);

View file

@ -17,7 +17,7 @@
#include <assert.h>
#include "esp_efuse_table.h"
// md5_digest_table 2e23344575b3d07f01ecb695294e9770
// md5_digest_table 11b691b6fa8546a3862a7a876be5f758
// This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY.
// If you want to change some fields, you need to change esp_efuse_table.csv file
// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.
@ -87,20 +87,24 @@ static const esp_efuse_desc_t DISABLE_DL_CACHE[] = {
{EFUSE_BLK0, 201, 1}, // Flash encrypt. Disable UART bootloader MMU cache. EFUSE_DISABLE_DL_CACHE.,
};
static const esp_efuse_desc_t DISABLE_JTAG[] = {
{EFUSE_BLK0, 198, 1}, // Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG.,
};
static const esp_efuse_desc_t CONSOLE_DEBUG_DISABLE[] = {
{EFUSE_BLK0, 194, 1}, // Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE.,
};
static const esp_efuse_desc_t FLASH_CRYPT_CNT[] = {
{EFUSE_BLK0, 20, 7}, // Flash encrypt. Flash encryption is enabled if this field has an odd number of bits set. EFUSE_FLASH_CRYPT_CNT.,
};
static const esp_efuse_desc_t DISABLE_JTAG[] = {
{EFUSE_BLK0, 198, 1}, // Disable JTAG. EFUSE_RD_DISABLE_JTAG.,
};
static const esp_efuse_desc_t CONSOLE_DEBUG_DISABLE[] = {
{EFUSE_BLK0, 194, 1}, // Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE.,
};
static const esp_efuse_desc_t UART_DOWNLOAD_DIS[] = {
{EFUSE_BLK0, 27, 1}, // Disable UART download mode. Valid for ESP32 V3 and newer,
};
static const esp_efuse_desc_t WR_DIS_FLASH_CRYPT_CNT[] = {
{EFUSE_BLK0, 2, 1}, // Flash encrypt. Write protection FLASH_CRYPT_CNT. EFUSE_WR_DIS_FLASH_CRYPT_CNT,
{EFUSE_BLK0, 2, 1}, // Flash encrypt. Write protection FLASH_CRYPT_CNT,
};
static const esp_efuse_desc_t WR_DIS_BLK1[] = {
@ -260,23 +264,28 @@ const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_CACHE[] = {
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_DISABLE_JTAG[] = {
&DISABLE_JTAG[0], // Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG.
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_CONSOLE_DEBUG_DISABLE[] = {
&CONSOLE_DEBUG_DISABLE[0], // Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE.
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_FLASH_CRYPT_CNT[] = {
&FLASH_CRYPT_CNT[0], // Flash encrypt. Flash encryption is enabled if this field has an odd number of bits set. EFUSE_FLASH_CRYPT_CNT.
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_DISABLE_JTAG[] = {
&DISABLE_JTAG[0], // Disable JTAG. EFUSE_RD_DISABLE_JTAG.
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_CONSOLE_DEBUG_DISABLE[] = {
&CONSOLE_DEBUG_DISABLE[0], // Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE.
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_UART_DOWNLOAD_DIS[] = {
&UART_DOWNLOAD_DIS[0], // Disable UART download mode. Valid for ESP32 V3 and newer
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT[] = {
&WR_DIS_FLASH_CRYPT_CNT[0], // Flash encrypt. Write protection FLASH_CRYPT_CNT. EFUSE_WR_DIS_FLASH_CRYPT_CNT
&WR_DIS_FLASH_CRYPT_CNT[0], // Flash encrypt. Write protection FLASH_CRYPT_CNT
NULL
};

View file

@ -39,13 +39,16 @@ ENCRYPT_CONFIG, EFUSE_BLK0, 188, 4, Flash encrypt. EFUSE_FLASH_C
DISABLE_DL_ENCRYPT, EFUSE_BLK0, 199, 1, Flash encrypt. Disable UART bootloader encryption. EFUSE_DISABLE_DL_ENCRYPT.
DISABLE_DL_DECRYPT, EFUSE_BLK0, 200, 1, Flash encrypt. Disable UART bootloader decryption. EFUSE_DISABLE_DL_DECRYPT.
DISABLE_DL_CACHE, EFUSE_BLK0, 201, 1, Flash encrypt. Disable UART bootloader MMU cache. EFUSE_DISABLE_DL_CACHE.
DISABLE_JTAG, EFUSE_BLK0, 198, 1, Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG.
CONSOLE_DEBUG_DISABLE, EFUSE_BLK0, 194, 1, Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE.
FLASH_CRYPT_CNT, EFUSE_BLK0, 20, 7, Flash encrypt. Flash encryption is enabled if this field has an odd number of bits set. EFUSE_FLASH_CRYPT_CNT.
# Misc Security #
DISABLE_JTAG, EFUSE_BLK0, 198, 1, Disable JTAG. EFUSE_RD_DISABLE_JTAG.
CONSOLE_DEBUG_DISABLE, EFUSE_BLK0, 194, 1, Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE.
UART_DOWNLOAD_DIS, EFUSE_BLK0, 27, 1, Disable UART download mode. Valid for ESP32 V3 and newer, only.
# Write protection #
####################
WR_DIS_FLASH_CRYPT_CNT, EFUSE_BLK0, 2, 1, Flash encrypt. Write protection FLASH_CRYPT_CNT. EFUSE_WR_DIS_FLASH_CRYPT_CNT
WR_DIS_FLASH_CRYPT_CNT, EFUSE_BLK0, 2, 1, Flash encrypt. Write protection FLASH_CRYPT_CNT, UART_DOWNLOAD_DIS. EFUSE_WR_DIS_FLASH_CRYPT_CNT
WR_DIS_BLK1, EFUSE_BLK0, 7, 1, Flash encrypt. Write protection encryption key. EFUSE_WR_DIS_BLK1
WR_DIS_BLK2, EFUSE_BLK0, 8, 1, Security boot. Write protection security key. EFUSE_WR_DIS_BLK2
WR_DIS_BLK3, EFUSE_BLK0, 9, 1, Write protection for EFUSE_BLK3. EFUSE_WR_DIS_BLK3

Can't render this file because it contains an unexpected character in line 7 and column 87.

View file

@ -17,7 +17,7 @@ extern "C" {
#endif
// md5_digest_table 2e23344575b3d07f01ecb695294e9770
// md5_digest_table 11b691b6fa8546a3862a7a876be5f758
// This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY.
// If you want to change some fields, you need to change esp_efuse_table.csv file
// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.
@ -36,9 +36,10 @@ extern const esp_efuse_desc_t* ESP_EFUSE_ENCRYPT_CONFIG[];
extern const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_ENCRYPT[];
extern const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_DECRYPT[];
extern const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_CACHE[];
extern const esp_efuse_desc_t* ESP_EFUSE_FLASH_CRYPT_CNT[];
extern const esp_efuse_desc_t* ESP_EFUSE_DISABLE_JTAG[];
extern const esp_efuse_desc_t* ESP_EFUSE_CONSOLE_DEBUG_DISABLE[];
extern const esp_efuse_desc_t* ESP_EFUSE_FLASH_CRYPT_CNT[];
extern const esp_efuse_desc_t* ESP_EFUSE_UART_DOWNLOAD_DIS[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK1[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK2[];

View file

@ -308,15 +308,48 @@ void esp_efuse_reset(void);
* By default, if booting from flash fails the ESP32 will boot a
* BASIC console in ROM.
*
* Call this function (from bootloader or app) to permanently
* disable the console on this chip.
*
* Call this function (from bootloader or app) to permanently disable the console on this chip.
*
*/
void esp_efuse_disable_basic_rom_console(void);
#endif
/* @brief Disable ROM Download Mode via eFuse
*
* Permanently disables the ROM Download Mode feature. Once disabled, if the SoC is booted with
* strapping pins set for ROM Download Mode then an error is printed instead.
*
* @note Not all SoCs support this option. An error will be returned if called on an ESP32
* with a silicon revision lower than 3, as these revisions do not support this option.
*
* @note If ROM Download Mode is already disabled, this function does nothing and returns success.
*
* @return
* - ESP_OK If the eFuse was successfully burned, or had already been burned.
* - ESP_ERR_NOT_SUPPORTED (ESP32 only) This SoC is not capable of disabling UART download mode
* - ESP_ERR_INVALID_STATE (ESP32 only) This eFuse is write protected and cannot be written
*/
esp_err_t esp_efuse_disable_rom_download_mode(void);
#ifdef CONFIG_IDF_TARGET_ESP32S2
/* @brief Switch ROM Download Mode to Secure Download mode via eFuse
*
* Permanently enables Secure Download mode. This mode limits the use of ROM Download Mode functions
* to simple flash read, write and erase operations, plus a command to return a summary of currently
* enabled security features.
*
* @note If Secure Download mode is already enabled, this function does nothing and returns success.
*
* @note Disabling the ROM Download Mode also disables Secure Download Mode.
*
* @return
* - ESP_OK If the eFuse was successfully burned, or had already been burned.
* - ESP_ERR_INVALID_STATE ROM Download Mode has been disabled via eFuse, so Secure Download mode is unavailable.
*/
esp_err_t esp_efuse_enable_rom_secure_download_mode(void);
#endif
/* @brief Write random data to efuse key block write registers
*
* @note Caller is responsible for ensuring efuse

View file

@ -70,14 +70,33 @@ uint32_t esp_efuse_get_pkg_ver(void)
// Disable BASIC ROM Console via efuse
void esp_efuse_disable_basic_rom_console(void)
{
uint8_t console_debug_disable = 0;
esp_efuse_read_field_blob(ESP_EFUSE_CONSOLE_DEBUG_DISABLE, &console_debug_disable, 1);
if (console_debug_disable == 0) {
if (!esp_efuse_read_field_bit(ESP_EFUSE_CONSOLE_DEBUG_DISABLE)) {
esp_efuse_write_field_cnt(ESP_EFUSE_CONSOLE_DEBUG_DISABLE, 1);
ESP_EARLY_LOGI(TAG, "Disable BASIC ROM Console fallback via efuse...");
}
}
esp_err_t esp_efuse_disable_rom_download_mode(void)
{
#ifndef CONFIG_ESP32_REV_MIN_3
/* Check if we support this revision at all */
if(esp_efuse_get_chip_ver() < 3) {
return ESP_ERR_NOT_SUPPORTED;
}
#endif
if (esp_efuse_read_field_bit(ESP_EFUSE_UART_DOWNLOAD_DIS)) {
return ESP_OK;
}
/* WR_DIS_FLASH_CRYPT_CNT also covers UART_DOWNLOAD_DIS on ESP32 */
if(esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT)) {
return ESP_ERR_INVALID_STATE;
}
return esp_efuse_write_field_bit(ESP_EFUSE_UART_DOWNLOAD_DIS);
}
void esp_efuse_write_random_key(uint32_t blk_wdata0_reg)
{
uint32_t buf[8];

View file

@ -60,3 +60,17 @@ void esp_efuse_write_random_key(uint32_t blk_wdata0_reg)
bzero(buf, sizeof(buf));
bzero(raw, sizeof(raw));
}
esp_err_t esp_efuse_disable_rom_download_mode(void)
{
return esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MODE);
}
esp_err_t esp_efuse_enable_rom_secure_download_mode(void)
{
if (esp_efuse_read_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MODE)) {
return ESP_ERR_INVALID_STATE;
}
return esp_efuse_write_field_bit(ESP_EFUSE_ENABLE_SECURITY_DOWNLOAD);
}

View file

@ -366,6 +366,10 @@ void start_cpu0_default(void)
#if CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE
esp_efuse_disable_basic_rom_console();
#endif
#if CONFIG_SECURE_DISABLE_ROM_DL_MODE
esp_efuse_disable_rom_download_mode();
#endif
rtc_gpio_force_hold_dis_all();
#ifdef CONFIG_VFS_SUPPORT_IO

View file

@ -292,6 +292,16 @@ void start_cpu0_default(void)
#if CONFIG_ESP32S2_BROWNOUT_DET
esp_brownout_init();
#endif
#if CONFIG_SECURE_DISABLE_ROM_DL_MODE
err = esp_efuse_disable_rom_download_mode();
assert(err == ESP_OK && "Failed to disable ROM download mode");
#endif
#if CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
err = esp_efuse_enable_rom_secure_download_mode();
assert(err == ESP_OK && "Failed to enable Secure Download mode");
#endif
rtc_gpio_force_hold_dis_all();
#ifdef CONFIG_VFS_SUPPORT_IO

View file

@ -484,6 +484,21 @@ Once the flash encryption is enabled in Release mode, the bootloader will write-
For subsequent plaintext field updates, use :ref:`OTA scheme <updating-encrypted-flash-ota>`.
. _flash-encrypt-best-practices:
Best Practices
^^^^^^^^^^^^^^
When using Flash Encryption in production:
.. list::
- Do not reuse the same flash encryption key between multiple devices. This means that an attacker who copies encrypted data from one device cannot transfer it to a second device.
:esp32: - When using ESP32 V3, if the UART ROM Download Mode is not needed for a production device then it should be disabled to provide an extra level of protection. Do this by calling :cpp:func:`esp_efuse_disable_rom_download_mode` during application startup. Alternatively, configure the project :ref:`CONFIG_ESP32_REV_MIN` level to 3 (targeting ESP32 V3 only) and enable :ref:`CONFIG_SECURE_DISABLE_ROM_DL_MODE`. The ability to disable ROM Download Mode is not available on earlier ESP32 versions.
:esp32s2: - The UART ROM Download Mode should be disabled entirely if it is not needed, or permanently set to "Secure Download Mode" otherwise. Secure Download Mode permanently limits the available commands to basic flash read and write only. The default behaviour is to set Secure Download Mode on first boot in Release mode. To disable Download Mode entirely, enable configuration option :ref:`CONFIG_SECURE_DISABLE_ROM_DL_MODE` or call :cpp:func:`esp_efuse_disable_rom_download_mode` at runtime.
:esp32: - Enable :doc:`Secure Boot <secure-boot-v2>` as an extra layer of protection, and to prevent an attacker from selectively corrupting any part of the flash before boot.
:esp32s2: - Enable Secure Boot as an extra layer of protection, and to prevent an attacker from selectively corrupting any part of the flash before boot.
Possible Failures
-----------------
@ -733,18 +748,12 @@ Limitations of Flash Encryption
Flash encryption protects firmware against unauthorised readout and modification. It is important to understand the limitations of the flash encryption feature:
.. list::
- **Flash encryption is only as strong as the key**. It is recommended to generate keys on the device during first boot (default behaviour). If generating keys on a host computer, ensure to follow a proper procedure and do not use the same key for produced devices.
- **Not all data is stored encrypted**. If storing data in flash memory, make sure that the method you are using (library, API, etc.) supports flash encryption.
:esp32: - **Flash encryption does not mask the high-level layout of flash**. This is because the same AES key is used for every pair of adjacent 16-byte AES blocks. If these blocks have identical content (such as empty or padding areas), these will produce matching pairs of encrypted blocks. It might allow an attacker to make high-level comparisons of firmware on encrypted devices, i.e., to tell if two devices are probably running the same firmware version.
:esp32: - **Flash encryption does not mask the high-level layout of flash**. Each pair of adjacent 16-byte AES blocks is encrypted with the same AES key. If these blocks have identical content (such as empty or padding areas), the result will be matching pairs of encrypted blocks. It might allow an attacker to make high-level comparisons of firmware on encrypted devices, i.e., to tell if two devices are probably running the same firmware version.
:esp32: - **An attacker can tell if a pair of adjacent 16-byte blocks (32 byte aligned) contains two identical 16-byte sequences** (the same reason as the previous bullet point). Keep this in mind if storing sensitive data in flash memory. While designing your flash storage, it is sufficient to use a counter byte or some other non-identical value every 16 bytes. :ref:`NVS Encryption <nvs_encryption>` deals with this and is suitable for many uses.
:esp32: - **Flash encryption alone may not prevent an attacker from modifying the firmware on the device**. To prevent unauthorized firmware from running on the device, use flash encryption in combination with :doc:`Secure Boot <secure-boot-v2>`.
- 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, ensure proper procedure is followed and don't share the same key between all production devices.
- Not all data is stored encrypted. If storing data on flash, check if the method you are using (library, API, etc.) supports flash encryption.
- Flash encryption does not prevent an attacker from understanding the high-level layout of the flash. This is because the same AES key is used for every pair of adjacent 16 byte AES blocks. When these adjacent 16 byte blocks contain identical content (such as empty or padding areas), these blocks will encrypt to produce matching pairs of encrypted blocks. This may allow an attacker to make high-level comparisons between encrypted devices (i.e. to tell if two devices are probably running the same firmware version).
:esp32: - For the same reason, an attacker can always tell when a pair of adjacent 16 byte blocks (32 byte aligned) contain two identical 16 byte sequences. Keep this in mind if storing sensitive data on the flash, design your flash storage so this doesn't happen (using a counter byte or some other non-identical value every 16 bytes is sufficient). :ref:`NVS Encryption <nvs_encryption>` deals with this and is suitable for many uses.
:esp32: - Flash encryption alone may not prevent an attacker from modifying the firmware of the device. To prevent unauthorised firmware from running on the device, use flash encryption in combination with :doc:`Secure Boot <secure-boot-v2>`.
:esp32s2: - Flash encryption alone may not prevent an attacker from modifying the firmware of the device. To prevent unauthorised firmware from running on the device, use flash encryption in combination with Secure Boot.
.. _flash-encryption-and-secure-boot:
@ -911,4 +920,4 @@ The following sections provide some reference information about the operation of
- The flash encryption key is stored in one or two ``KEYN`` eFuses and, by default, is protected from further writes or software readout.
- To see the full flash encryption algorithm implemented in Python, refer to the `_flash_encryption_operation()` function in the ``espsecure.py`` source code.
- To see the full flash encryption algorithm implemented in Python, refer to the `_flash_encryption_operation()` function in the ``espsecure.py`` source code.