efuse: Add ESP32 V3 'disable Download Mode' functionality

This commit is contained in:
Angus Gratton 2020-04-25 16:36:53 +10:00
parent 363589e849
commit 5a4091a2c0
9 changed files with 125 additions and 31 deletions

View File

@ -535,5 +535,23 @@ 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 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.
endmenu # Security features

View File

@ -121,6 +121,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();

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

@ -335,6 +335,23 @@ void esp_efuse_disable_basic_rom_console(void);
*/
esp_err_t esp_efuse_apply_34_encoding(const uint8_t *in_bytes, uint32_t *out_words, size_t in_bytes_len);
/* @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);
/* @brief Write random data to efuse key block write registers
*
* @note Caller is responsible for ensuring efuse

View File

@ -115,6 +115,33 @@ esp_err_t esp_efuse_apply_34_encoding(const uint8_t *in_bytes, uint32_t *out_wor
return ESP_OK;
}
esp_err_t esp_efuse_disable_rom_download_mode(void)
{
uint8_t dl_dis = 0;
uint8_t wr_dis_flash_crypt_cnt = 0;
#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
esp_efuse_read_field_blob(ESP_EFUSE_UART_DOWNLOAD_DIS, &dl_dis, 1);
if (dl_dis) {
return ESP_OK;
}
/* WR_DIS_FLASH_CRYPT_CNT also covers UART_DOWNLOAD_DIS on ESP32 */
esp_efuse_read_field_blob(ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT, &wr_dis_flash_crypt_cnt, 1);
if(wr_dis_flash_crypt_cnt) {
return ESP_ERR_INVALID_STATE;
}
dl_dis = 1;
return esp_efuse_write_field_blob(ESP_EFUSE_UART_DOWNLOAD_DIS, &dl_dis, 1);
}
void esp_efuse_write_random_key(uint32_t blk_wdata0_reg)
{
uint32_t buf[8];

View File

@ -350,6 +350,14 @@ void start_cpu0_default(void)
#if CONFIG_ESP32_BROWNOUT_DET
esp_brownout_init();
#endif
#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();
esp_vfs_dev_uart_register();
esp_reent_init(_GLOBAL_REENT);

View File

@ -377,6 +377,17 @@ Once the flash encryption is enabled in Release mode the bootloader will write p
For subsequent plaintext update in field OTA scheme should be used. Please refer :doc:`OTA <../api-reference/system/ota>` for further details.
. _flash-encrypt-best-practices:
Best Practices
^^^^^^^^^^^^^^
When using Flash Encryption in production:
- 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.
- 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.
- Enable :doc:`Secure Boot <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
^^^^^^^^^^^^^^^^^
Once flash encryption is enabled and if the ``FLASH_CRYPT_CNT`` eFuse value has an odd number of bits set then all the partitions (which are marked with encryption flag) are expected to contain encrypted ciphertext. Below are three typical failure cases if the ESP32 is loaded with plaintext data:
@ -569,16 +580,12 @@ Reset the ESP32 and flash encryption should be disabled, the bootloader will boo
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 protects firmware against unauthorised readout and modification. It is important to understand the limitations of the flash encryption feature:
- 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).
- 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.
- 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>`.
.. _flash-encryption-and-secure-boot: