Merge branch 'bugfix/enb_secboot_post_flash_enc' into 'master'

Enable secure boot only after encrypting flash

Closes IDF-234

See merge request idf/esp-idf!4709
This commit is contained in:
Angus Gratton 2019-04-12 13:33:50 +08:00
commit f2ce4fc81b
4 changed files with 145 additions and 33 deletions

View file

@ -46,6 +46,25 @@ static inline bool esp_secure_boot_enabled(void) {
return REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_ABS_DONE_0;
}
/** @brief Generate secure digest from bootloader image
*
* @important This function is intended to be called from bootloader code only.
*
* If secure boot is not yet enabled for bootloader, this will:
* 1) generate the secure boot key and burn it on EFUSE
* (without enabling R/W protection)
* 2) generate the digest from bootloader and save it
* to flash address 0x0
*
* If first boot gets interrupted after calling this function
* but before esp_secure_boot_permanently_enable() is called, then
* the key burned on EFUSE will not be regenerated, unless manually
* done using espefuse.py tool
*
* @return ESP_OK if secure boot digest is generated
* successfully or found to be already present
*/
esp_err_t esp_secure_boot_generate_digest(void);
/** @brief Enable secure boot if it is not already enabled.
*
@ -54,9 +73,13 @@ static inline bool esp_secure_boot_enabled(void) {
*
* @important This function is intended to be called from bootloader code only.
*
* @important This will enable r/w protection of secure boot key on EFUSE,
* therefore it is to be ensured that esp_secure_boot_generate_digest()
* is called before this
*
* If secure boot is not yet enabled for bootloader, this will
* generate the secure boot digest and enable secure boot by blowing
* the EFUSE_RD_ABS_DONE_0 efuse.
* 1) enable R/W protection of secure boot key on EFUSE
* 2) enable secure boot by blowing the EFUSE_RD_ABS_DONE_0 efuse.
*
* This function does not verify secure boot of the bootloader (the
* ROM bootloader does this.)
@ -64,7 +87,6 @@ static inline bool esp_secure_boot_enabled(void) {
* Will fail if efuses have been part-burned in a way that indicates
* secure boot should not or could not be correctly enabled.
*
*
* @return ESP_ERR_INVALID_STATE if efuse state doesn't allow
* secure boot to be enabled cleanly. ESP_OK if secure boot
* is enabled on this chip from now on.

View file

@ -478,24 +478,71 @@ void bootloader_utility_load_boot_image(const bootloader_state_t *bs, int start_
// Copy loaded segments to RAM, set up caches for mapped segments, and start application.
static void load_image(const esp_image_metadata_t* image_data)
{
/**
* Rough steps for a first boot, when encryption and secure boot are both disabled:
* 1) Generate secure boot key and write to EFUSE.
* 2) Write plaintext digest based on plaintext bootloader
* 3) Generate flash encryption key and write to EFUSE.
* 4) Encrypt flash in-place including bootloader, then digest,
* then app partitions and other encrypted partitions
* 5) Burn EFUSE to enable flash encryption (FLASH_CRYPT_CNT)
* 6) Burn EFUSE to enable secure boot (ABS_DONE_0)
*
* If power failure happens during Step 1, probably the next boot will continue from Step 2.
* There is some small chance that EFUSEs will be part-way through being written so will be
* somehow corrupted here. Thankfully this window of time is very small, but if that's the
* case, one has to use the espefuse tool to manually set the remaining bits and enable R/W
* protection. Once the relevant EFUSE bits are set and R/W protected, Step 1 will be skipped
* successfully on further reboots.
*
* If power failure happens during Step 2, Step 1 will be skipped and Step 2 repeated:
* the digest will get re-written on the next boot.
*
* If power failure happens during Step 3, it's possible that EFUSE was partially written
* with the generated flash encryption key, though the time window for that would again
* be very small. On reboot, Step 1 will be skipped and Step 2 repeated, though, Step 3
* may fail due to the above mentioned reason, in which case, one has to use the espefuse
* tool to manually set the remaining bits and enable R/W protection. Once the relevant EFUSE
* bits are set and R/W protected, Step 3 will be skipped successfully on further reboots.
*
* If power failure happens after start of 4 and before end of 5, the next boot will fail
* (bootloader header is encrypted and flash encryption isn't enabled yet, so it looks like
* noise to the ROM bootloader). The check in the ROM is pretty basic so if the first byte of
* ciphertext happens to be the magic byte E9 then it may try to boot, but it will definitely
* crash (no chance that the remaining ciphertext will look like a valid bootloader image).
* Only solution is to reflash with all plaintext and the whole process starts again: skips
* Step 1, repeats Step 2, skips Step 3, etc.
*
* If power failure happens after 5 but before 6, the device will reboot with flash
* encryption on and will regenerate an encrypted digest in Step 2. This should still
* be valid as the input data for the digest is read via flash cache (so will be decrypted)
* and the code in secure_boot_generate() tells bootloader_flash_write() to encrypt the data
* on write if flash encryption is enabled. Steps 3 - 5 are skipped (encryption already on),
* then Step 6 enables secure boot.
*/
#if defined(CONFIG_SECURE_BOOT_ENABLED) || defined(CONFIG_FLASH_ENCRYPTION_ENABLED)
esp_err_t err;
#endif
#ifdef CONFIG_SECURE_BOOT_ENABLED
/* Generate secure digest from this bootloader to protect future
modifications */
ESP_LOGI(TAG, "Checking secure boot...");
err = esp_secure_boot_permanently_enable();
/* Steps 1 & 2 (see above for full description):
* 1) Generate secure boot EFUSE key
* 2) Compute digest of plaintext bootloader
*/
err = esp_secure_boot_generate_digest();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Bootloader digest generation failed (%d). SECURE BOOT IS NOT ENABLED.", err);
/* Allow booting to continue, as the failure is probably
due to user-configured EFUSEs for testing...
*/
ESP_LOGE(TAG, "Bootloader digest generation for secure boot failed (%d).", err);
return;
}
#endif
#ifdef CONFIG_FLASH_ENCRYPTION_ENABLED
/* encrypt flash */
/* Steps 3, 4 & 5 (see above for full description):
* 3) Generate flash encryption EFUSE key
* 4) Encrypt flash contents
* 5) Burn EFUSE to enable flash encryption
*/
ESP_LOGI(TAG, "Checking flash encryption...");
bool flash_encryption_enabled = esp_flash_encryption_enabled();
err = esp_flash_encrypt_check_and_update();
@ -503,7 +550,23 @@ static void load_image(const esp_image_metadata_t* image_data)
ESP_LOGE(TAG, "Flash encryption check failed (%d).", err);
return;
}
#endif
#ifdef CONFIG_SECURE_BOOT_ENABLED
/* Step 6 (see above for full description):
* 6) Burn EFUSE to enable secure boot
*/
ESP_LOGI(TAG, "Checking secure boot...");
err = esp_secure_boot_permanently_enable();
if (err != ESP_OK) {
ESP_LOGE(TAG, "FAILED TO ENABLE SECURE BOOT (%d).", err);
/* Allow booting to continue, as the failure is probably
due to user-configured EFUSEs for testing...
*/
}
#endif
#ifdef CONFIG_FLASH_ENCRYPTION_ENABLED
if (!flash_encryption_enabled && esp_flash_encryption_enabled()) {
/* Flash encryption was just enabled for the first time,
so issue a system reset to ensure flash encryption

View file

@ -224,18 +224,18 @@ static esp_err_t encrypt_bootloader()
return err;
}
if (esp_secure_boot_enabled()) {
/* If secure boot is enabled and bootloader was plaintext, also
need to encrypt secure boot IV+digest.
*/
ESP_LOGD(TAG, "Encrypting secure bootloader IV & digest...");
err = esp_flash_encrypt_region(FLASH_OFFS_SECURE_BOOT_IV_DIGEST,
FLASH_SECTOR_SIZE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt bootloader IV & digest in place: 0x%x", err);
return err;
}
#ifdef CONFIG_SECURE_BOOT_ENABLED
/* If secure boot is enabled and bootloader was plaintext, also
* need to encrypt secure boot IV+digest.
*/
ESP_LOGD(TAG, "Encrypting secure bootloader IV & digest...");
err = esp_flash_encrypt_region(FLASH_OFFS_SECURE_BOOT_IV_DIGEST,
FLASH_SECTOR_SIZE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt bootloader IV & digest in place: 0x%x", err);
return err;
}
#endif
}
else {
ESP_LOGW(TAG, "no valid bootloader was found");

View file

@ -36,6 +36,12 @@
#include "esp_flash_encrypt.h"
#include "esp_efuse.h"
/* The following API implementations are used only when called
* from the bootloader code.
*/
#ifdef BOOTLOADER_BUILD
static const char* TAG = "secure_boot";
/**
@ -102,11 +108,12 @@ static inline void burn_efuses()
#endif
}
esp_err_t esp_secure_boot_permanently_enable(void) {
esp_err_t esp_secure_boot_generate_digest(void)
{
esp_err_t err;
if (esp_secure_boot_enabled())
{
ESP_LOGI(TAG, "bootloader secure boot is already enabled, continuing..");
if (esp_secure_boot_enabled()) {
ESP_LOGI(TAG, "bootloader secure boot is already enabled."
" No need to generate digest. continuing..");
return ESP_OK;
}
@ -124,6 +131,7 @@ esp_err_t esp_secure_boot_permanently_enable(void) {
return err;
}
/* Generate secure boot key and keep in EFUSE */
uint32_t dis_reg = REG_READ(EFUSE_BLK0_RDATA0_REG);
bool efuse_key_read_protected = dis_reg & EFUSE_RD_DIS_BLK2;
bool efuse_key_write_protected = dis_reg & EFUSE_WR_DIS_BLK2;
@ -140,16 +148,11 @@ esp_err_t esp_secure_boot_permanently_enable(void) {
ESP_LOGI(TAG, "Generating new secure boot key...");
esp_efuse_write_random_key(EFUSE_BLK2_WDATA0_REG);
burn_efuses();
ESP_LOGI(TAG, "Read & write protecting new key...");
REG_WRITE(EFUSE_BLK0_WDATA0_REG, EFUSE_WR_DIS_BLK2 | EFUSE_RD_DIS_BLK2);
burn_efuses();
efuse_key_read_protected = true;
efuse_key_write_protected = true;
} else {
ESP_LOGW(TAG, "Using pre-loaded secure boot key in EFUSE block 2");
}
/* Generate secure boot digest using programmed key in EFUSE */
ESP_LOGI(TAG, "Generating secure boot digest...");
uint32_t image_len = bootloader_data.image_len;
if(bootloader_data.image.hash_appended) {
@ -162,6 +165,28 @@ esp_err_t esp_secure_boot_permanently_enable(void) {
}
ESP_LOGI(TAG, "Digest generation complete.");
return ESP_OK;
}
esp_err_t esp_secure_boot_permanently_enable(void)
{
if (esp_secure_boot_enabled()) {
ESP_LOGI(TAG, "bootloader secure boot is already enabled, continuing..");
return ESP_OK;
}
uint32_t dis_reg = REG_READ(EFUSE_BLK0_RDATA0_REG);
bool efuse_key_read_protected = dis_reg & EFUSE_RD_DIS_BLK2;
bool efuse_key_write_protected = dis_reg & EFUSE_WR_DIS_BLK2;
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();
efuse_key_read_protected = true;
efuse_key_write_protected = true;
}
#ifndef CONFIG_SECURE_BOOT_TEST_MODE
if (!efuse_key_read_protected) {
ESP_LOGE(TAG, "Pre-loaded key is not read protected. Refusing to blow secure boot efuse.");
@ -208,3 +233,5 @@ esp_err_t esp_secure_boot_permanently_enable(void) {
return ESP_ERR_INVALID_STATE;
}
}
#endif // #ifdef BOOTLOADER_BUILD