secure boot v2: esp32: Prevent read disabling additional efuses

Also reduce the number of eFuse write cycles during first boot when
Secure Boot and/or Flash Encryption are enabled.
This commit is contained in:
Angus Gratton
2020-03-20 13:55:15 +11:00
committed by Angus Gratton
parent f96d28172b
commit cf8dd62fc4
4 changed files with 73 additions and 25 deletions

View File

@ -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 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. 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 config SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
bool "Leave UART bootloader encryption enabled" bool "Leave UART bootloader encryption enabled"
depends on SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT depends on SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT

View File

@ -73,6 +73,10 @@ esp_err_t esp_flash_encrypt_check_and_update(void)
static esp_err_t initialise_flash_encryption(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); 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) { 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); 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) { && REG_READ(EFUSE_BLK1_RDATA7_REG) == 0) {
ESP_LOGI(TAG, "Generating new flash encryption key..."); ESP_LOGI(TAG, "Generating new flash encryption key...");
esp_efuse_write_random_key(EFUSE_BLK1_WDATA0_REG); 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..."); ESP_LOGI(TAG, "Read & write protecting new key...");
REG_WRITE(EFUSE_BLK0_WDATA0_REG, EFUSE_WR_DIS_BLK1 | EFUSE_RD_DIS_BLK1); new_wdata0 |= EFUSE_WR_DIS_BLK1 | EFUSE_RD_DIS_BLK1;
esp_efuse_burn_new_values();
} else { } else {
if(!(efuse_key_read_protected && efuse_key_write_protected)) { 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! operation does nothing. Please note this is not recommended!
*/ */
ESP_LOGI(TAG, "Setting CRYPT_CONFIG efuse to 0xF"); ESP_LOGI(TAG, "Setting CRYPT_CONFIG efuse to 0xF");
REG_WRITE(EFUSE_BLK0_WDATA5_REG, EFUSE_FLASH_CRYPT_CONFIG_M); new_wdata5 |= EFUSE_FLASH_CRYPT_CONFIG_M;
esp_efuse_burn_new_values();
uint32_t new_wdata6 = 0;
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC #ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
ESP_LOGI(TAG, "Disable UART bootloader encryption..."); ESP_LOGI(TAG, "Disable UART bootloader encryption...");
new_wdata6 |= EFUSE_DISABLE_DL_ENCRYPT; new_wdata6 |= EFUSE_DISABLE_DL_ENCRYPT;
#else #else
ESP_LOGW(TAG, "Not disabling UART bootloader encryption"); ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
#endif #endif
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC #ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC
ESP_LOGI(TAG, "Disable UART bootloader decryption..."); ESP_LOGI(TAG, "Disable UART bootloader decryption...");
new_wdata6 |= EFUSE_DISABLE_DL_DECRYPT; new_wdata6 |= EFUSE_DISABLE_DL_DECRYPT;
#else #else
ESP_LOGW(TAG, "Not disabling UART bootloader decryption - SECURITY COMPROMISED"); ESP_LOGW(TAG, "Not disabling UART bootloader decryption - SECURITY COMPROMISED");
#endif #endif
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE #ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
ESP_LOGI(TAG, "Disable UART bootloader MMU cache..."); ESP_LOGI(TAG, "Disable UART bootloader MMU cache...");
new_wdata6 |= EFUSE_DISABLE_DL_CACHE; new_wdata6 |= EFUSE_DISABLE_DL_CACHE;
#else #else
ESP_LOGW(TAG, "Not disabling UART bootloader MMU cache - SECURITY COMPROMISED"); ESP_LOGW(TAG, "Not disabling UART bootloader MMU cache - SECURITY COMPROMISED");
#endif #endif
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG #ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable JTAG..."); ESP_LOGI(TAG, "Disable JTAG...");
new_wdata6 |= EFUSE_RD_DISABLE_JTAG; new_wdata6 |= EFUSE_RD_DISABLE_JTAG;
#else #else
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED"); ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
#endif #endif
#ifndef CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC #ifndef CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC
ESP_LOGI(TAG, "Disable ROM BASIC interpreter fallback..."); ESP_LOGI(TAG, "Disable ROM BASIC interpreter fallback...");
new_wdata6 |= EFUSE_RD_CONSOLE_DEBUG_DISABLE; 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"); ESP_LOGW(TAG, "Not disabling ROM BASIC fallback - SECURITY COMPROMISED");
#endif #endif
if (new_wdata6 != 0) { #if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
REG_WRITE(EFUSE_BLK0_WDATA6_REG, new_wdata6); // This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
esp_efuse_burn_new_values(); // 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; return ESP_OK;
} }

View File

@ -39,11 +39,6 @@
/* The following API implementations are used only when called /* The following API implementations are used only when called
* from the bootloader code. * 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 #ifdef CONFIG_SECURE_BOOT_V1_ENABLED
static const char *TAG = "secure_boot_v1"; 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) { && REG_READ(EFUSE_BLK2_RDATA7_REG) == 0) {
ESP_LOGI(TAG, "Generating new secure boot key..."); ESP_LOGI(TAG, "Generating new secure boot key...");
esp_efuse_write_random_key(EFUSE_BLK2_WDATA0_REG); esp_efuse_write_random_key(EFUSE_BLK2_WDATA0_REG);
burn_efuses(); esp_efuse_burn_new_values();
} else { } else {
ESP_LOGW(TAG, "Using pre-loaded secure boot key in EFUSE block 2"); 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) esp_err_t esp_secure_boot_permanently_enable(void)
{ {
uint32_t new_wdata0 = 0;
uint32_t new_wdata6 = 0;
if (esp_secure_boot_enabled()) { if (esp_secure_boot_enabled()) {
ESP_LOGI(TAG, "bootloader secure boot is already enabled, continuing.."); ESP_LOGI(TAG, "bootloader secure boot is already enabled, continuing..");
return ESP_OK; return ESP_OK;
@ -174,8 +172,7 @@ esp_err_t esp_secure_boot_permanently_enable(void)
if (efuse_key_read_protected == false if (efuse_key_read_protected == false
&& efuse_key_write_protected == false) { && efuse_key_write_protected == false) {
ESP_LOGI(TAG, "Read & write protecting new key..."); ESP_LOGI(TAG, "Read & write protecting new key...");
REG_WRITE(EFUSE_BLK0_WDATA0_REG, EFUSE_WR_DIS_BLK2 | EFUSE_RD_DIS_BLK2); new_wdata0 = EFUSE_WR_DIS_BLK2 | EFUSE_RD_DIS_BLK2;
burn_efuses();
efuse_key_read_protected = true; efuse_key_read_protected = true;
efuse_key_write_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_LOGI(TAG, "blowing secure boot efuse...");
ESP_LOGD(TAG, "before updating, EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG)); 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 #ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable 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"); ESP_LOGW(TAG, "Not disabling ROM BASIC fallback - SECURITY COMPROMISED");
#endif #endif
REG_WRITE(EFUSE_BLK0_WDATA0_REG, new_wdata0);
REG_WRITE(EFUSE_BLK0_WDATA6_REG, new_wdata6); REG_WRITE(EFUSE_BLK0_WDATA6_REG, new_wdata6);
burn_efuses(); esp_efuse_burn_new_values();
uint32_t after = REG_READ(EFUSE_BLK0_RDATA6_REG); 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_RDATA6 %x", after);
if (after & EFUSE_RD_ABS_DONE_0) { 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) 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_LOGI(TAG, "enabling secure boot v2...");
esp_err_t ret; esp_err_t ret;
if (esp_secure_boot_enabled()) { 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; return ESP_ERR_NOT_SUPPORTED;
} }
/* Verify the bootloader */ /* Verify the bootloader */
esp_image_metadata_t bootloader_data = { 0 }; esp_image_metadata_t bootloader_data = { 0 };
ret = esp_image_verify_bootloader_data(&bootloader_data); ret = esp_image_verify_bootloader_data(&bootloader_data);
if (ret != ESP_OK) { 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..."); 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_write_protected = true;
efuse_key_read_protected = false; efuse_key_read_protected = false;
} else { } 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_LOGI(TAG, "blowing secure boot efuse...");
ESP_LOGD(TAG, "before updating, EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG)); 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 #ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable 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"); ESP_LOGW(TAG, "Not disabling ROM BASIC fallback - SECURITY COMPROMISED");
#endif #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); REG_WRITE(EFUSE_BLK0_WDATA6_REG, new_wdata6);
burn_efuses(); esp_efuse_burn_new_values();
uint32_t after = REG_READ(EFUSE_BLK0_RDATA6_REG); 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) { if (after & EFUSE_RD_ABS_DONE_1) {
ESP_LOGI(TAG, "secure boot v2 is now enabled."); ESP_LOGI(TAG, "secure boot v2 is now enabled.");
return ESP_OK; return ESP_OK;

View File

@ -164,6 +164,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). 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: .. _secure-boot-v2-generate-key:
Generating Secure Boot Signing Key Generating Secure Boot Signing Key