kopia lustrzana https://github.com/espressif/esp-idf
Merge branch 'bugfix/secure_boot_v2_wrdis' into 'master'
secure boot v2: esp32: Prevent read disabling additional efuses Closes IDF-1502 See merge request espressif/esp-idf!8045pull/5052/head
commit
9a5e4f9acb
|
@ -640,6 +640,18 @@ menu "Security features"
|
|||
image to this length. It is generally not recommended to set this option, unless you have a legacy
|
||||
partitioning scheme which doesn't support 64KB aligned partition lengths.
|
||||
|
||||
config SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
bool "Allow additional read protecting of efuses"
|
||||
depends on SECURE_BOOT_INSECURE && SECURE_BOOT_V2_ENABLED
|
||||
help
|
||||
If not set (default, recommended), on first boot the bootloader will burn the WR_DIS_RD_DIS
|
||||
efuse when Secure Boot is enabled. This prevents any more efuses from being read protected.
|
||||
|
||||
If this option is set, it will remain possible to write the EFUSE_RD_DIS efuse field after Secure
|
||||
Boot is enabled. This may allow an attacker to read-protect the BLK2 efuse holding the public
|
||||
key digest, causing an immediate denial of service and possibly allowing an additional fault
|
||||
injection attack to bypass the signature protection.
|
||||
|
||||
config SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
bool "Leave UART bootloader encryption enabled"
|
||||
depends on SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
|
||||
|
|
|
@ -73,6 +73,10 @@ esp_err_t esp_flash_encrypt_check_and_update(void)
|
|||
|
||||
static esp_err_t initialise_flash_encryption(void)
|
||||
{
|
||||
uint32_t new_wdata0 = 0;
|
||||
uint32_t new_wdata5 = 0;
|
||||
uint32_t new_wdata6 = 0;
|
||||
|
||||
uint32_t coding_scheme = REG_GET_FIELD(EFUSE_BLK0_RDATA6_REG, EFUSE_CODING_SCHEME);
|
||||
if (coding_scheme != EFUSE_CODING_SCHEME_VAL_NONE && coding_scheme != EFUSE_CODING_SCHEME_VAL_34) {
|
||||
ESP_LOGE(TAG, "Unknown/unsupported CODING_SCHEME value 0x%x", coding_scheme);
|
||||
|
@ -97,11 +101,10 @@ static esp_err_t initialise_flash_encryption(void)
|
|||
&& REG_READ(EFUSE_BLK1_RDATA7_REG) == 0) {
|
||||
ESP_LOGI(TAG, "Generating new flash encryption key...");
|
||||
esp_efuse_write_random_key(EFUSE_BLK1_WDATA0_REG);
|
||||
esp_efuse_burn_new_values();
|
||||
// defer efuse programming step to the end
|
||||
|
||||
ESP_LOGI(TAG, "Read & write protecting new key...");
|
||||
REG_WRITE(EFUSE_BLK0_WDATA0_REG, EFUSE_WR_DIS_BLK1 | EFUSE_RD_DIS_BLK1);
|
||||
esp_efuse_burn_new_values();
|
||||
new_wdata0 |= EFUSE_WR_DIS_BLK1 | EFUSE_RD_DIS_BLK1;
|
||||
} else {
|
||||
|
||||
if(!(efuse_key_read_protected && efuse_key_write_protected)) {
|
||||
|
@ -122,34 +125,36 @@ static esp_err_t initialise_flash_encryption(void)
|
|||
operation does nothing. Please note this is not recommended!
|
||||
*/
|
||||
ESP_LOGI(TAG, "Setting CRYPT_CONFIG efuse to 0xF");
|
||||
REG_WRITE(EFUSE_BLK0_WDATA5_REG, EFUSE_FLASH_CRYPT_CONFIG_M);
|
||||
esp_efuse_burn_new_values();
|
||||
new_wdata5 |= EFUSE_FLASH_CRYPT_CONFIG_M;
|
||||
|
||||
uint32_t new_wdata6 = 0;
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
|
||||
new_wdata6 |= EFUSE_DISABLE_DL_ENCRYPT;
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC
|
||||
ESP_LOGI(TAG, "Disable UART bootloader decryption...");
|
||||
new_wdata6 |= EFUSE_DISABLE_DL_DECRYPT;
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader decryption - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
|
||||
ESP_LOGI(TAG, "Disable UART bootloader MMU cache...");
|
||||
new_wdata6 |= EFUSE_DISABLE_DL_CACHE;
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader MMU cache - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
new_wdata6 |= EFUSE_RD_DISABLE_JTAG;
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC
|
||||
ESP_LOGI(TAG, "Disable ROM BASIC interpreter fallback...");
|
||||
new_wdata6 |= EFUSE_RD_CONSOLE_DEBUG_DISABLE;
|
||||
|
@ -157,10 +162,16 @@ static esp_err_t initialise_flash_encryption(void)
|
|||
ESP_LOGW(TAG, "Not disabling ROM BASIC fallback - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
if (new_wdata6 != 0) {
|
||||
REG_WRITE(EFUSE_BLK0_WDATA6_REG, new_wdata6);
|
||||
esp_efuse_burn_new_values();
|
||||
}
|
||||
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
|
||||
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
|
||||
// otherwise the Flash Encryption key cannot be read protected
|
||||
new_wdata0 |= EFUSE_WR_DIS_RD_DIS;
|
||||
#endif
|
||||
|
||||
REG_WRITE(EFUSE_BLK0_WDATA0_REG, new_wdata0);
|
||||
REG_WRITE(EFUSE_BLK0_WDATA5_REG, new_wdata5);
|
||||
REG_WRITE(EFUSE_BLK0_WDATA6_REG, new_wdata6);
|
||||
esp_efuse_burn_new_values();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -210,16 +221,19 @@ static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_cry
|
|||
|
||||
ESP_LOGD(TAG, "All flash regions checked for encryption pass");
|
||||
|
||||
uint32_t new_flash_crypt_cnt;
|
||||
#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
|
||||
// Go straight to max, permanently enabled
|
||||
ESP_LOGI(TAG, "Setting FLASH_CRYPT_CNT for permanent encryption");
|
||||
new_flash_crypt_cnt = EFUSE_FLASH_CRYPT_CNT;
|
||||
#else
|
||||
/* Set least significant 0-bit in flash_crypt_cnt */
|
||||
int ffs_inv = __builtin_ffs((~flash_crypt_cnt) & EFUSE_RD_FLASH_CRYPT_CNT);
|
||||
/* ffs_inv shouldn't be zero, as zero implies flash_crypt_cnt == EFUSE_RD_FLASH_CRYPT_CNT (0x7F) */
|
||||
uint32_t new_flash_crypt_cnt = flash_crypt_cnt + (1 << (ffs_inv - 1));
|
||||
new_flash_crypt_cnt = flash_crypt_cnt + (1 << (ffs_inv - 1));
|
||||
#endif
|
||||
ESP_LOGD(TAG, "FLASH_CRYPT_CNT 0x%x -> 0x%x", flash_crypt_cnt, new_flash_crypt_cnt);
|
||||
uint32_t wdata0_reg = ((new_flash_crypt_cnt & EFUSE_FLASH_CRYPT_CNT) << EFUSE_FLASH_CRYPT_CNT_S);
|
||||
#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
|
||||
ESP_LOGI(TAG, "Write protecting FLASH_CRYPT_CNT eFuse");
|
||||
wdata0_reg |= EFUSE_WR_DIS_FLASH_CRYPT_CNT;
|
||||
#endif
|
||||
|
||||
REG_WRITE(EFUSE_BLK0_WDATA0_REG, wdata0_reg);
|
||||
esp_efuse_burn_new_values();
|
||||
|
|
|
@ -39,11 +39,6 @@
|
|||
/* The following API implementations are used only when called
|
||||
* from the bootloader code.
|
||||
*/
|
||||
/* Burn values written to the efuse write registers */
|
||||
static inline void burn_efuses(void)
|
||||
{
|
||||
esp_efuse_burn_new_values();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
|
||||
static const char *TAG = "secure_boot_v1";
|
||||
|
@ -140,7 +135,7 @@ esp_err_t esp_secure_boot_generate_digest(void)
|
|||
&& REG_READ(EFUSE_BLK2_RDATA7_REG) == 0) {
|
||||
ESP_LOGI(TAG, "Generating new secure boot key...");
|
||||
esp_efuse_write_random_key(EFUSE_BLK2_WDATA0_REG);
|
||||
burn_efuses();
|
||||
esp_efuse_burn_new_values();
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Using pre-loaded secure boot key in EFUSE block 2");
|
||||
}
|
||||
|
@ -163,6 +158,9 @@ esp_err_t esp_secure_boot_generate_digest(void)
|
|||
|
||||
esp_err_t esp_secure_boot_permanently_enable(void)
|
||||
{
|
||||
uint32_t new_wdata0 = 0;
|
||||
uint32_t new_wdata6 = 0;
|
||||
|
||||
if (esp_secure_boot_enabled()) {
|
||||
ESP_LOGI(TAG, "bootloader secure boot is already enabled, continuing..");
|
||||
return ESP_OK;
|
||||
|
@ -174,8 +172,7 @@ esp_err_t esp_secure_boot_permanently_enable(void)
|
|||
if (efuse_key_read_protected == false
|
||||
&& efuse_key_write_protected == false) {
|
||||
ESP_LOGI(TAG, "Read & write protecting new key...");
|
||||
REG_WRITE(EFUSE_BLK0_WDATA0_REG, EFUSE_WR_DIS_BLK2 | EFUSE_RD_DIS_BLK2);
|
||||
burn_efuses();
|
||||
new_wdata0 = EFUSE_WR_DIS_BLK2 | EFUSE_RD_DIS_BLK2;
|
||||
efuse_key_read_protected = true;
|
||||
efuse_key_write_protected = true;
|
||||
}
|
||||
|
@ -192,7 +189,7 @@ esp_err_t esp_secure_boot_permanently_enable(void)
|
|||
ESP_LOGI(TAG, "blowing secure boot efuse...");
|
||||
ESP_LOGD(TAG, "before updating, EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG));
|
||||
|
||||
uint32_t new_wdata6 = EFUSE_RD_ABS_DONE_0;
|
||||
new_wdata6 |= EFUSE_RD_ABS_DONE_0;
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
|
@ -208,8 +205,9 @@ esp_err_t esp_secure_boot_permanently_enable(void)
|
|||
ESP_LOGW(TAG, "Not disabling ROM BASIC fallback - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
REG_WRITE(EFUSE_BLK0_WDATA0_REG, new_wdata0);
|
||||
REG_WRITE(EFUSE_BLK0_WDATA6_REG, new_wdata6);
|
||||
burn_efuses();
|
||||
esp_efuse_burn_new_values();
|
||||
uint32_t after = REG_READ(EFUSE_BLK0_RDATA6_REG);
|
||||
ESP_LOGD(TAG, "after updating, EFUSE_BLK0_RDATA6 %x", after);
|
||||
if (after & EFUSE_RD_ABS_DONE_0) {
|
||||
|
@ -293,6 +291,9 @@ done:
|
|||
|
||||
esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *image_data)
|
||||
{
|
||||
uint32_t new_wdata0 = 0;
|
||||
uint32_t new_wdata6 = 0;
|
||||
|
||||
ESP_LOGI(TAG, "enabling secure boot v2...");
|
||||
esp_err_t ret;
|
||||
if (esp_secure_boot_enabled()) {
|
||||
|
@ -306,7 +307,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
|
|||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Verify the bootloader */
|
||||
/* Verify the bootloader */
|
||||
esp_image_metadata_t bootloader_data = { 0 };
|
||||
ret = esp_image_verify_bootloader_data(&bootloader_data);
|
||||
if (ret != ESP_OK) {
|
||||
|
@ -343,7 +344,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
|
|||
}
|
||||
|
||||
ESP_LOGI(TAG, "Write protecting public key digest...");
|
||||
REG_WRITE(EFUSE_BLK0_WDATA0_REG, EFUSE_WR_DIS_BLK2);
|
||||
new_wdata0 |= EFUSE_WR_DIS_BLK2;
|
||||
efuse_key_write_protected = true;
|
||||
efuse_key_read_protected = false;
|
||||
} else {
|
||||
|
@ -375,7 +376,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
|
|||
ESP_LOGI(TAG, "blowing secure boot efuse...");
|
||||
ESP_LOGD(TAG, "before updating, EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG));
|
||||
|
||||
uint32_t new_wdata6 = EFUSE_RD_ABS_DONE_1;
|
||||
new_wdata6 |= EFUSE_RD_ABS_DONE_1;
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
|
@ -391,10 +392,27 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
|
|||
ESP_LOGW(TAG, "Not disabling ROM BASIC fallback - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
bool rd_dis_now = true;
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
|
||||
when Flash Encryption is being enabled */
|
||||
rd_dis_now = esp_flash_encryption_enabled();
|
||||
#endif
|
||||
if (rd_dis_now) {
|
||||
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
|
||||
new_wdata0 |= EFUSE_WR_DIS_RD_DIS;
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
REG_WRITE(EFUSE_BLK0_WDATA0_REG, new_wdata0);
|
||||
REG_WRITE(EFUSE_BLK0_WDATA6_REG, new_wdata6);
|
||||
burn_efuses();
|
||||
esp_efuse_burn_new_values();
|
||||
uint32_t after = REG_READ(EFUSE_BLK0_RDATA6_REG);
|
||||
ESP_LOGD(TAG, "after updating, EFUSE_BLK0_RDATA6 %x", after);
|
||||
ESP_LOGD(TAG, "after updating, EFUSE_BLK0_RDATA0 0x%08x EFUSE_BLK0_RDATA6 0x%08x",
|
||||
REG_READ(EFUSE_BLK0_RDATA0_REG), after);
|
||||
if (after & EFUSE_RD_ABS_DONE_1) {
|
||||
ESP_LOGI(TAG, "secure boot v2 is now enabled.");
|
||||
return ESP_OK;
|
||||
|
|
|
@ -110,15 +110,24 @@ An image is “verified” if the public key stored in any signature block is va
|
|||
Bootloader Size
|
||||
---------------
|
||||
|
||||
{IDF_TARGET_MAX_BOOTLOADER_SIZE:default = "64KB (0x10000 bytes)", esp32 = "48KB (0xC000 bytes)"}
|
||||
{IDF_TARGET_MAX_PARTITION_TABLE_OFFSET:default = "0x12000", esp32 = "0xE000"}
|
||||
.. Above is calculated as 0x1000 at start of flash + IDF_TARGET_MAX_BOOTLOADER_SIZE + 0x1000 signature sector
|
||||
|
||||
When secure boot is enabled the bootloader app binary ``bootloader.bin`` may exceed the default bootloader size limit. This is especially likely if flash encryption is enabled as well. The default size limit is 0x7000 (28672) bytes (partition table offset 0x8000 - bootloader offset 0x1000).
|
||||
|
||||
If the bootloader becomes too large, the ESP32 will fail to boot - errors will be logged about either invalid partition table or invalid bootloader checksum.
|
||||
If the bootloader becomes too large, the {IDF_TARGET_NAME} will fail to boot - errors will be logged about either invalid partition table or invalid bootloader checksum.
|
||||
|
||||
When Secure Boot V2 is enabled, there is also an absolute binary size limit of {IDF_TARGET_MAX_BOOTLOADER_SIZE} (excluding the 4KB signature), because the bootloader is first loaded into a fixed size buffer for verification.
|
||||
|
||||
Options to work around this are:
|
||||
|
||||
- Set :ref:`bootloader compiler optimization <CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION>` back to "Size" if it has been changed from this default value.
|
||||
- Reduce :ref:`bootloader log level <CONFIG_BOOTLOADER_LOG_LEVEL>`. Setting log level to Warning, Error or None all significantly reduce the final binary size (but may make it harder to debug).
|
||||
- Set :ref:`partition table offset <CONFIG_PARTITION_TABLE_OFFSET>` to a higher value than 0x8000, to place the partition table later in the flash. This increases the space available for the bootloader. If the :doc:`partition table </api-guides/partition-tables>` CSV file contains explicit partition offsets, they will need changing so no partition has an offset lower than ``CONFIG_PARTITION_TABLE_OFFSET + 0x1000``. (This includes the default partition CSV files supplied with ESP-IDF.)
|
||||
|
||||
Note that because of the absolute binary size limit, there is no benefit to moving the partition table any higher than offset {IDF_TARGET_MAX_PARTITION_TABLE_OFFSET}.
|
||||
|
||||
.. _efuse-usage:
|
||||
|
||||
eFuse usage
|
||||
|
@ -168,6 +177,13 @@ How To Enable Secure Boot V2
|
|||
|
||||
10. On subsequent boots, the secure boot hardware will verify the software bootloader has not changed and the software bootloader will verify the signed app image (using the validated public key portion of its appended signature block).
|
||||
|
||||
Restrictions after Secure Boot is enabled
|
||||
-----------------------------------------
|
||||
|
||||
- Any updated bootloader or app will need to be signed with a key matching the digest already stored in efuse.
|
||||
|
||||
- After Secure Boot is enabled, no further efuses can be read protected. (If :doc:`/security/flash-encryption` is enabled then the bootloader will ensure that any flash encryption key generated on first boot will already be read protected.) If :ref:`CONFIG_SECURE_BOOT_INSECURE` is enabled then this behaviour can be disabled, but this is not recommended.
|
||||
|
||||
.. _secure-boot-v2-generate-key:
|
||||
|
||||
Generating Secure Boot Signing Key
|
||||
|
|
Ładowanie…
Reference in New Issue