Merge branch 'bugfix/flash_encryption_disable_plaintext_v4.0' into 'release/v4.0'
flash encryption: Always disable plaintext reflashes in Release mode (v4.0) See merge request espressif/esp-idf!6070
This commit is contained in:
commit
5a351af83f
7 changed files with 103 additions and 25 deletions
|
@ -40,6 +40,7 @@ SECTIONS
|
|||
*(.iram1 .iram1.*) /* catch stray IRAM_ATTR */
|
||||
*liblog.a:(.literal .text .literal.* .text.*)
|
||||
*libgcc.a:(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_clock.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_common.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_flash.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_random.*(.literal .text .literal.* .text.*)
|
||||
|
@ -53,6 +54,7 @@ SECTIONS
|
|||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libsoc.a:rtc_wdt.*(.literal .text .literal.* .text.*)
|
||||
*libsoc.a:rtc_clk.*(.literal .text .literal.* .text.*)
|
||||
*libefuse.a:*.*(.literal .text .literal.* .text.*)
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
|
|
|
@ -133,6 +133,21 @@ void esp_flash_write_protect_crypt_cnt();
|
|||
*/
|
||||
esp_flash_enc_mode_t esp_get_flash_encryption_mode();
|
||||
|
||||
|
||||
/** @brief Check the flash encryption mode during startup
|
||||
*
|
||||
* @note This function is called automatically during app startup,
|
||||
* it doesn't need to be called from the app.
|
||||
*
|
||||
* Verifies the flash encryption config during startup:
|
||||
*
|
||||
* - Correct any insecure flash encryption settings if hardware
|
||||
* Secure Boot is enabled.
|
||||
* - Log warnings if the efuse config doesn't match the project
|
||||
* config in any way
|
||||
*/
|
||||
void esp_flash_encryption_init_checks(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -58,3 +58,12 @@ void bootloader_clock_configure()
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
|
||||
int esp_clk_apb_freq(void)
|
||||
{
|
||||
return rtc_clk_apb_freq_get();
|
||||
}
|
||||
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
|
|
@ -13,9 +13,51 @@
|
|||
// limitations under the License.
|
||||
|
||||
#include <strings.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_secure_boot.h"
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
static const char *TAG = "flash_encrypt";
|
||||
|
||||
void esp_flash_encryption_init_checks()
|
||||
{
|
||||
esp_flash_enc_mode_t mode;
|
||||
|
||||
// First check is: if Release mode flash encryption & secure boot are enabled then
|
||||
// FLASH_CRYPT_CNT *must* be write protected. This will have happened automatically
|
||||
// if bootloader is IDF V4.0 or newer but may not have happened for previous ESP-IDF bootloaders.
|
||||
#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLED
|
||||
if (esp_secure_boot_enabled() && esp_flash_encryption_enabled()) {
|
||||
uint8_t flash_crypt_cnt_wr_dis = 0;
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT, &flash_crypt_cnt_wr_dis, 1);
|
||||
if (!flash_crypt_cnt_wr_dis) {
|
||||
ESP_EARLY_LOGE(TAG, "Flash encryption & Secure Boot together requires FLASH_CRYPT_CNT efuse to be write protected. Fixing now...");
|
||||
esp_flash_write_protect_crypt_cnt();
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_SECURE_BOOT_ENABLED
|
||||
#endif // CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
|
||||
|
||||
// Second check is to print a warning or error if the current running flash encryption mode
|
||||
// doesn't match the expectation from project config (due to mismatched bootloader and app, probably)
|
||||
mode = esp_get_flash_encryption_mode();
|
||||
if (mode == ESP_FLASH_ENC_MODE_DEVELOPMENT) {
|
||||
#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
|
||||
ESP_EARLY_LOGE(TAG, "Flash encryption settings error: app is configured for RELEASE but efuses are set for DEVELOPMENT");
|
||||
ESP_EARLY_LOGE(TAG, "Mismatch found in security options in bootloader menuconfig and efuse settings. Device is not secure.");
|
||||
#else
|
||||
ESP_EARLY_LOGW(TAG, "Flash encryption mode is DEVELOPMENT (not secure)");
|
||||
#endif
|
||||
} else if (mode == ESP_FLASH_ENC_MODE_RELEASE) {
|
||||
ESP_EARLY_LOGI(TAG, "Flash encryption mode is RELEASE");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void esp_flash_write_protect_crypt_cnt()
|
||||
{
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "esp_efuse_utility.h"
|
||||
|
||||
#include "soc/efuse_periph.h"
|
||||
#include "esp32/clk.h"
|
||||
#include "esp_log.h"
|
||||
#include "assert.h"
|
||||
#include "sdkconfig.h"
|
||||
|
@ -209,6 +210,25 @@ void esp_efuse_utility_burn_efuses(void)
|
|||
}
|
||||
}
|
||||
#else
|
||||
// Update Efuse timing configuration
|
||||
uint32_t apb_freq_mhz = esp_clk_apb_freq() / 1000000;
|
||||
uint32_t clk_sel0, clk_sel1, dac_clk_div;
|
||||
if (apb_freq_mhz <= 26) {
|
||||
clk_sel0 = 250;
|
||||
clk_sel1 = 255;
|
||||
dac_clk_div = 52;
|
||||
} else if (apb_freq_mhz <= 40) {
|
||||
clk_sel0 = 160;
|
||||
clk_sel1 = 255;
|
||||
dac_clk_div = 80;
|
||||
} else {
|
||||
clk_sel0 = 80;
|
||||
clk_sel1 = 128;
|
||||
dac_clk_div = 100;
|
||||
}
|
||||
REG_SET_FIELD(EFUSE_DAC_CONF_REG, EFUSE_DAC_CLK_DIV, dac_clk_div);
|
||||
REG_SET_FIELD(EFUSE_CLK_REG, EFUSE_CLK_SEL0, clk_sel0);
|
||||
REG_SET_FIELD(EFUSE_CLK_REG, EFUSE_CLK_SEL1, clk_sel1);
|
||||
// Permanently update values written to the efuse write registers
|
||||
REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_WRITE);
|
||||
REG_WRITE(EFUSE_CMD_REG, EFUSE_CMD_PGM);
|
||||
|
|
|
@ -205,18 +205,9 @@ void IRAM_ATTR call_start_cpu0()
|
|||
}
|
||||
ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1);
|
||||
|
||||
esp_flash_enc_mode_t mode;
|
||||
mode = esp_get_flash_encryption_mode();
|
||||
if (mode == ESP_FLASH_ENC_MODE_DEVELOPMENT) {
|
||||
#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
|
||||
ESP_EARLY_LOGE(TAG, "Flash encryption settings error: mode should be RELEASE but is actually DEVELOPMENT");
|
||||
ESP_EARLY_LOGE(TAG, "Mismatch found in security options in menuconfig and efuse settings");
|
||||
#else
|
||||
ESP_EARLY_LOGW(TAG, "Flash encryption mode is DEVELOPMENT");
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
esp_flash_encryption_init_checks();
|
||||
#endif
|
||||
} else if (mode == ESP_FLASH_ENC_MODE_RELEASE) {
|
||||
ESP_EARLY_LOGI(TAG, "Flash encryption mode is RELEASE");
|
||||
}
|
||||
|
||||
//Flush and enable icache for APP CPU
|
||||
Cache_Flush(1);
|
||||
|
|
|
@ -22,7 +22,10 @@ With flash encryption enabled, following kinds of flash data are encrypted by de
|
|||
- Secure boot bootloader digest (if secure boot is enabled)
|
||||
- Any partition marked with the "encrypted" flag in the partition table
|
||||
|
||||
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.
|
||||
|
||||
.. important::
|
||||
For production use, flash encryption should be enabled in the "Release" mode only.
|
||||
|
||||
.. important::
|
||||
Enabling flash encryption limits the options for further updates of the ESP32. Make sure to read this document (including :ref:`flash-encryption-limitations`) and understand the implications of enabling flash encryption.
|
||||
|
@ -31,7 +34,7 @@ Flash encryption is separate from the :doc:`Secure Boot <secure-boot>` feature,
|
|||
|
||||
eFuse Used During Flash Encryption Process
|
||||
-------------------------------------------
|
||||
The flash encryption operation is controlled by various eFuses available on ESP32. Below is the list of eFuse and their description:
|
||||
The flash encryption operation is controlled by various eFuses available on ESP32. Below is the list of eFuse and their description:
|
||||
|
||||
::
|
||||
|
||||
|
@ -300,6 +303,8 @@ Using Host Generated Flash Encryption Key
|
|||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
It is possible to pregenerate the flash encryption key on the host computer and burn it into the ESP32's eFuse key block. This allows data to be pre-encrypted on the host and flashed to the ESP32 without needing a plaintext flash update. This feature allows encrypted flashing in both :ref:`flash_enc_development_mode` and :ref:`flash_enc_release_mode` modes.
|
||||
|
||||
.. note:: This option is not recommended for production unless a separate key is generated for each individual device.
|
||||
|
||||
- Ensure you have a ESP32 device with default flash encryption eFuse settings as shown in :ref:`flash-encryption-efuse`.
|
||||
|
||||
- Generate a random key with espsecure.py::
|
||||
|
@ -321,7 +326,6 @@ It is possible to pregenerate the flash encryption key on the host computer and
|
|||
- Update to the partition table offset may be required since after enabling flash encryption the size of bootloader is increased. See :ref:`secure-boot-bootloader-size`
|
||||
|
||||
- Save the configuration and exit.
|
||||
|
||||
|
||||
Build and flash the complete image including: bootloader, partition table and app. These partitions are initially written to the flash unencrypted
|
||||
|
||||
|
@ -375,7 +379,7 @@ For subsequent plaintext update in field OTA scheme should be used. Please refer
|
|||
|
||||
Possible Failures
|
||||
^^^^^^^^^^^^^^^^^
|
||||
Once the flash encryption is enabled and if the ``FLASH_CRYPT_CNT`` eFuse value has 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:
|
||||
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:
|
||||
|
||||
1. In case the bootloader partition is re-updated with plaintext bootloader image the ROM loader will fail to load the bootloader and following type of failure will be displayed:
|
||||
|
||||
|
@ -406,6 +410,8 @@ Once the flash encryption is enabled and if the ``FLASH_CRYPT_CNT`` eFuse value
|
|||
ets_main.c 371
|
||||
ets Jun 8 2016 00:22:57
|
||||
|
||||
.. note:: This error also appears in the flash contents is erased or corrupted.
|
||||
|
||||
2. In case the bootloader is encrypted but partition table is re-updated with plaintext partition table image the bootloader will fail to read the partition table and following type of failure will be displayed:
|
||||
|
||||
::
|
||||
|
@ -547,7 +553,7 @@ Disabling Flash Encryption
|
|||
|
||||
If you've accidentally enabled flash encryption for some reason, the next flash of plaintext data will soft-brick the ESP32 (the device will reboot continuously, printing the error ``flash read err, 1000``).
|
||||
|
||||
You can disable flash encryption again by writing ``FLASH_CRYPT_CNT`` eFuse (only in Development mode):
|
||||
If flash encryption is enabled in Development mode, you can disable flash encryption again by writing ``FLASH_CRYPT_CNT`` eFuse. This can only be done three times per chip.
|
||||
|
||||
- First, open :ref:`project-configuration-menu` and disable :ref:`Enable flash encryption boot <CONFIG_SECURE_FLASH_ENC_ENABLED>` under "Security Features".
|
||||
- Exit menuconfig and save the new configuration.
|
||||
|
@ -565,13 +571,13 @@ 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, 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 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 identical content. 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).
|
||||
- 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>`.
|
||||
|
||||
|
@ -586,13 +592,6 @@ It is recommended to use flash encryption and secure boot together. However, if
|
|||
- :ref:`Plaintext serial flash updates <updating-encrypted-flash-serial>` are only possible if the :ref:`Reflashable <CONFIG_SECURE_BOOTLOADER_MODE>` Secure Boot mode is selected and a Secure Boot key was pre-generated and burned to the ESP32 (refer to :ref:`Secure Boot <secure-boot-reflashable>` docs.). In this configuration, ``idf.py bootloader`` will produce a pre-digested bootloader and secure boot digest file for flashing at offset 0x0. When following the plaintext serial reflashing steps it is necessary to re-flash this file before flashing other plaintext data.
|
||||
- :ref:`Reflashing via Pregenerated Flash Encryption Key <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:
|
||||
|
||||
Using Flash Encryption Without Secure Boot
|
||||
------------------------------------------
|
||||
|
||||
Even though flash encryption and secure boot can be used independently it is strongly recommended to use flash encryption ALONG with secure boot to achieve strong security.
|
||||
|
||||
.. _flash-encryption-advanced-features:
|
||||
|
||||
Flash Encryption Advanced Features
|
||||
|
|
Loading…
Reference in a new issue