espressif: ESP32, ESP32S2 and ESP32C3 native flash encryption
Native flash encryption was added as option for Espressif chips and
added to the initialization process before MCUboot workflow.
Signed-off-by: Almir Okato <almir.okato@espressif.com>
diff --git a/boot/espressif/bootloader.conf b/boot/espressif/bootloader.conf
index c4b833a..f350262 100644
--- a/boot/espressif/bootloader.conf
+++ b/boot/espressif/bootloader.conf
@@ -31,6 +31,15 @@
# CONFIG_SECURE_BOOT_V2_ENABLED=1
# CONFIG_SECURE_BOOT_SUPPORTS_RSA=1
+# Hardware Flash Encryption related options
+# CONFIG_SECURE_FLASH_ENC_ENABLED=1
+# CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=1
+# CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC=1
+# CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=1
+# CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=1
+# CONFIG_SECURE_BOOT_ALLOW_JTAG=1
+# CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC=1
+
# Options for enabling eFuse emulation in Flash
# CONFIG_EFUSE_VIRTUAL=1
# CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH=1
diff --git a/boot/espressif/hal/CMakeLists.txt b/boot/espressif/hal/CMakeLists.txt
index 8e879a6..742e140 100644
--- a/boot/espressif/hal/CMakeLists.txt
+++ b/boot/espressif/hal/CMakeLists.txt
@@ -56,6 +56,7 @@
set(hal_srcs
${src_dir}/bootloader_wdt.c
${src_dir}/secure_boot.c
+ ${src_dir}/flash_encrypt.c
${src_dir}/${MCUBOOT_TARGET}/bootloader_init.c
${esp_idf_dir}/components/hal/mpu_hal.c
${esp_idf_dir}/components/bootloader_support/src/bootloader_common_loader.c
@@ -67,11 +68,13 @@
${esp_idf_dir}/components/bootloader_support/src/bootloader_panic.c
${esp_idf_dir}/components/bootloader_support/src/bootloader_mem.c
${esp_idf_dir}/components/bootloader_support/src/bootloader_random.c
+ ${esp_idf_dir}/components/bootloader_support/src/bootloader_random_${MCUBOOT_TARGET}.c
${esp_idf_dir}/components/bootloader_support/src/bootloader_utility.c
${esp_idf_dir}/components/bootloader_support/src/esp_image_format.c
${esp_idf_dir}/components/bootloader_support/src/secure_boot_v2/secure_boot_signatures_bootloader.c
${esp_idf_dir}/components/bootloader_support/src/${MCUBOOT_TARGET}/bootloader_sha.c
${esp_idf_dir}/components/bootloader_support/src/${MCUBOOT_TARGET}/secure_boot_secure_features.c
+ ${esp_idf_dir}/components/bootloader_support/src/${MCUBOOT_TARGET}/flash_encryption_secure_features.c
${esp_idf_dir}/components/spi_flash/${MCUBOOT_TARGET}/spi_flash_rom_patch.c
${esp_idf_dir}/components/esp_hw_support/esp_clk.c
${esp_idf_dir}/components/esp_hw_support/port/${MCUBOOT_TARGET}/rtc_init.c
diff --git a/boot/espressif/hal/include/esp32/sdkconfig.h b/boot/espressif/hal/include/esp32/sdkconfig.h
index cb7d4e7..6e76b63 100644
--- a/boot/espressif/hal/include/esp32/sdkconfig.h
+++ b/boot/espressif/hal/include/esp32/sdkconfig.h
@@ -16,7 +16,7 @@
#define CONFIG_BOOTLOADER_WDT_TIME_MS 9000
#define CONFIG_ESP_CONSOLE_UART_BAUDRATE 115200
#define CONFIG_BOOTLOADER_OFFSET_IN_FLASH 0x1000
-#define CONFIG_PARTITION_TABLE_OFFSET 0xE000
-#define CONFIG_EFUSE_VIRTUAL_OFFSET 0xE000
+#define CONFIG_PARTITION_TABLE_OFFSET 0x10000
+#define CONFIG_EFUSE_VIRTUAL_OFFSET 0x250000
#define CONFIG_EFUSE_VIRTUAL_SIZE 0x2000
#define CONFIG_EFUSE_MAX_BLK_LEN 192
diff --git a/boot/espressif/hal/include/esp32c3/sdkconfig.h b/boot/espressif/hal/include/esp32c3/sdkconfig.h
index f657725..f091a13 100644
--- a/boot/espressif/hal/include/esp32c3/sdkconfig.h
+++ b/boot/espressif/hal/include/esp32c3/sdkconfig.h
@@ -14,7 +14,7 @@
#define CONFIG_BOOTLOADER_WDT_TIME_MS 9000
#define CONFIG_ESP_CONSOLE_UART_BAUDRATE 115200
#define CONFIG_BOOTLOADER_OFFSET_IN_FLASH 0x0000
-#define CONFIG_PARTITION_TABLE_OFFSET 0xE000
-#define CONFIG_EFUSE_VIRTUAL_OFFSET 0xE000
+#define CONFIG_PARTITION_TABLE_OFFSET 0x10000
+#define CONFIG_EFUSE_VIRTUAL_OFFSET 0x250000
#define CONFIG_EFUSE_VIRTUAL_SIZE 0x2000
#define CONFIG_EFUSE_MAX_BLK_LEN 256
diff --git a/boot/espressif/hal/include/esp32s2/sdkconfig.h b/boot/espressif/hal/include/esp32s2/sdkconfig.h
index 84601c8..ed61b9b 100644
--- a/boot/espressif/hal/include/esp32s2/sdkconfig.h
+++ b/boot/espressif/hal/include/esp32s2/sdkconfig.h
@@ -14,7 +14,7 @@
#define CONFIG_BOOTLOADER_WDT_TIME_MS 9000
#define CONFIG_ESP_CONSOLE_UART_BAUDRATE 115200
#define CONFIG_BOOTLOADER_OFFSET_IN_FLASH 0x1000
-#define CONFIG_PARTITION_TABLE_OFFSET 0xE000
-#define CONFIG_EFUSE_VIRTUAL_OFFSET 0xE000
+#define CONFIG_PARTITION_TABLE_OFFSET 0x10000
+#define CONFIG_EFUSE_VIRTUAL_OFFSET 0x250000
#define CONFIG_EFUSE_VIRTUAL_SIZE 0x2000
#define CONFIG_EFUSE_MAX_BLK_LEN 256
diff --git a/boot/espressif/hal/include/esp_mcuboot_image.h b/boot/espressif/hal/include/esp_mcuboot_image.h
new file mode 100644
index 0000000..baccf08
--- /dev/null
+++ b/boot/espressif/hal/include/esp_mcuboot_image.h
@@ -0,0 +1,26 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+/* Magic is derived from sha256sum of the string "espmcuboot"
+ * The application header magic must match this number
+ */
+#define ESP_LOAD_HEADER_MAGIC 0xace637d3
+
+/* Load header that should be a part of application image
+ * for MCUboot-Espressif port booting.
+ */
+typedef struct esp_image_load_header {
+ uint32_t header_magic; /* Magic for load header */
+ uint32_t entry_addr; /* Application entry address */
+ uint32_t iram_dest_addr; /* Destination address(VMA) for IRAM region */
+ uint32_t iram_flash_offset; /* Flash offset(LMA) for start of IRAM region */
+ uint32_t iram_size; /* Size of IRAM region */
+ uint32_t dram_dest_addr; /* Destination address(VMA) for DRAM region */
+ uint32_t dram_flash_offset; /* Flash offset(LMA) for start of DRAM region */
+ uint32_t dram_size; /* Size of DRAM region */
+} esp_image_load_header_t;
diff --git a/boot/espressif/hal/include/mcuboot_config/mcuboot_config.h b/boot/espressif/hal/include/mcuboot_config/mcuboot_config.h
index aada8e3..abbbd97 100644
--- a/boot/espressif/hal/include/mcuboot_config/mcuboot_config.h
+++ b/boot/espressif/hal/include/mcuboot_config/mcuboot_config.h
@@ -8,19 +8,6 @@
#define __MCUBOOT_CONFIG_H__
/*
- * Template configuration file for MCUboot.
- *
- * When porting MCUboot to a new target, copy it somewhere that your
- * include path can find it as mcuboot_config/mcuboot_config.h, and
- * make adjustments to suit your platform.
- *
- * For examples, see:
- *
- * boot/zephyr/include/mcuboot_config/mcuboot_config.h
- * boot/mynewt/mcuboot_config/include/mcuboot_config/mcuboot_config.h
- */
-
-/*
* Signature types
*
* You must choose exactly one signature type - check bootloader.conf
@@ -41,6 +28,11 @@
#elif defined(CONFIG_ESP_SIGN_ED25519)
#define MCUBOOT_SIGN_ED25519
#endif
+
+#if defined(CONFIG_SECURE_FLASH_ENC_ENABLED)
+#define MCUBOOT_BOOT_MAX_ALIGN 32
+#endif
+
/*
* Upgrade mode
*
@@ -132,6 +124,7 @@
* MCUBOOT_LOG_ERR > MCUBOOT_LOG_WRN > MCUBOOT_LOG_INF > MCUBOOT_LOG_DBG
*/
#define MCUBOOT_HAVE_LOGGING 1
+/* #define MCUBOOT_LOG_LEVEL MCUBOOT_LOG_LEVEL_INFO */
/*
* Assertions
diff --git a/boot/espressif/hal/include/mcuboot_config/mcuboot_logging.h b/boot/espressif/hal/include/mcuboot_config/mcuboot_logging.h
index f6a16a2..130f30f 100644
--- a/boot/espressif/hal/include/mcuboot_config/mcuboot_logging.h
+++ b/boot/espressif/hal/include/mcuboot_config/mcuboot_logging.h
@@ -7,6 +7,7 @@
#pragma once
#include "sdkconfig.h"
+#include "mcuboot_config.h"
extern int ets_printf(const char *fmt, ...);
diff --git a/boot/espressif/hal/src/flash_encrypt.c b/boot/espressif/hal/src/flash_encrypt.c
new file mode 100644
index 0000000..143571b
--- /dev/null
+++ b/boot/espressif/hal/src/flash_encrypt.c
@@ -0,0 +1,351 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <strings.h>
+#include "bootloader_flash_priv.h"
+#include "bootloader_random.h"
+#include "esp_image_format.h"
+#include "esp_flash_encrypt.h"
+#include "esp_flash_partitions.h"
+#include "esp_secure_boot.h"
+#include "esp_efuse.h"
+#include "esp_efuse_table.h"
+#include "esp_log.h"
+#include "hal/wdt_hal.h"
+
+#include "esp_mcuboot_image.h"
+
+#if CONFIG_IDF_TARGET_ESP32
+#define CRYPT_CNT ESP_EFUSE_FLASH_CRYPT_CNT
+#define WR_DIS_CRYPT_CNT ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT
+#else
+#define CRYPT_CNT ESP_EFUSE_SPI_BOOT_CRYPT_CNT
+#define WR_DIS_CRYPT_CNT ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT
+#endif
+
+/* This file implements FLASH ENCRYPTION related APIs to perform
+ * various operations such as programming necessary flash encryption
+ * eFuses, detect whether flash encryption is enabled (by reading eFuse)
+ * and if required encrypt the partitions in flash memory
+ */
+
+static const char *TAG = "flash_encrypt";
+
+/* Static functions for stages of flash encryption */
+static esp_err_t initialise_flash_encryption(void);
+static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_crypt_wr_dis) __attribute__((unused));
+static esp_err_t encrypt_bootloader(void);
+static esp_err_t encrypt_primary_slot(void);
+
+esp_err_t esp_flash_encrypt_check_and_update(void)
+{
+ size_t flash_crypt_cnt = 0;
+ esp_efuse_read_field_cnt(CRYPT_CNT, &flash_crypt_cnt);
+ bool flash_crypt_wr_dis = esp_efuse_read_field_bit(WR_DIS_CRYPT_CNT);
+
+ ESP_LOGV(TAG, "CRYPT_CNT %d, write protection %d", flash_crypt_cnt, flash_crypt_wr_dis);
+
+ if (flash_crypt_cnt % 2 == 1) {
+ /* Flash is already encrypted */
+ int left = (CRYPT_CNT[0]->bit_count - flash_crypt_cnt) / 2;
+ if (flash_crypt_wr_dis) {
+ left = 0; /* can't update FLASH_CRYPT_CNT, no more flashes */
+ }
+ ESP_LOGI(TAG, "flash encryption is enabled (%d plaintext flashes left)", left);
+ return ESP_OK;
+ } else {
+#ifndef CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED
+ /* Flash is not encrypted, so encrypt it! */
+ return encrypt_flash_contents(flash_crypt_cnt, flash_crypt_wr_dis);
+#else
+ ESP_LOGE(TAG, "flash encryption is not enabled, and SECURE_FLASH_REQUIRE_ALREADY_ENABLED "
+ "is set, refusing to boot.");
+ return ESP_ERR_INVALID_STATE;
+#endif // CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED
+ }
+}
+
+static esp_err_t check_and_generate_encryption_keys(void)
+{
+ size_t key_size = 32;
+#ifdef CONFIG_IDF_TARGET_ESP32
+ enum { BLOCKS_NEEDED = 1 };
+ esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = {
+ ESP_EFUSE_KEY_PURPOSE_FLASH_ENCRYPTION,
+ };
+ esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK_ENCRYPT_FLASH);
+ if (coding_scheme != EFUSE_CODING_SCHEME_NONE && coding_scheme != EFUSE_CODING_SCHEME_3_4) {
+ ESP_LOGE(TAG, "Unknown/unsupported CODING_SCHEME value 0x%x", coding_scheme);
+ return ESP_ERR_NOT_SUPPORTED;
+ }
+ if (coding_scheme == EFUSE_CODING_SCHEME_3_4) {
+ key_size = 24;
+ }
+#else
+#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_AES256
+ enum { BLOCKS_NEEDED = 2 };
+ esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = {
+ ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1,
+ ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2,
+ };
+ if (esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY, NULL)) {
+ ESP_LOGE(TAG, "XTS_AES_128_KEY is already in use, XTS_AES_256_KEY_1/2 can not be used");
+ return ESP_ERR_INVALID_STATE;
+ }
+#else
+ enum { BLOCKS_NEEDED = 1 };
+ esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = {
+ ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY,
+ };
+#endif // CONFIG_SECURE_FLASH_ENCRYPTION_AES256
+#endif // CONFIG_IDF_TARGET_ESP32
+
+ /* Initialize all efuse block entries to invalid (max) value */
+ esp_efuse_block_t blocks[BLOCKS_NEEDED] = {[0 ... BLOCKS_NEEDED-1] = EFUSE_BLK_KEY_MAX};
+ bool has_key = true;
+ for (unsigned i = 0; i < BLOCKS_NEEDED; i++) {
+ bool tmp_has_key = esp_efuse_find_purpose(purposes[i], &blocks[i]);
+ if (tmp_has_key) { // For ESP32: esp_efuse_find_purpose() always returns True, need to check whether the key block is used or not.
+ tmp_has_key &= !esp_efuse_key_block_unused(blocks[i]);
+ }
+ if (i == 1 && tmp_has_key != has_key) {
+ ESP_LOGE(TAG, "Invalid efuse key blocks: Both AES-256 key blocks must be set.");
+ return ESP_ERR_INVALID_STATE;
+ }
+ has_key &= tmp_has_key;
+ }
+
+ if (!has_key) {
+ /* Generate key */
+ uint8_t keys[BLOCKS_NEEDED][32] = { 0 };
+ ESP_LOGI(TAG, "Generating new flash encryption key...");
+ for (unsigned i = 0; i < BLOCKS_NEEDED; ++i) {
+ bootloader_fill_random(keys[i], key_size);
+ }
+ ESP_LOGD(TAG, "Key generation complete");
+
+ esp_err_t err = esp_efuse_write_keys(purposes, keys, BLOCKS_NEEDED);
+ if (err != ESP_OK) {
+ if (err == ESP_ERR_NOT_ENOUGH_UNUSED_KEY_BLOCKS) {
+ ESP_LOGE(TAG, "Not enough free efuse key blocks (need %d) to continue", BLOCKS_NEEDED);
+ } else {
+ ESP_LOGE(TAG, "Failed to write efuse block with purpose (err=0x%x). Can't continue.", err);
+ }
+ return err;
+ }
+ } else {
+ for (unsigned i = 0; i < BLOCKS_NEEDED; i++) {
+ if (!esp_efuse_get_key_dis_write(blocks[i])
+ || !esp_efuse_get_key_dis_read(blocks[i])
+ || !esp_efuse_get_keypurpose_dis_write(blocks[i])) { // For ESP32: no keypurpose, it returns always True.
+ ESP_LOGE(TAG, "Invalid key state, check read&write protection for key and keypurpose(if exists)");
+ return ESP_ERR_INVALID_STATE;
+ }
+ }
+ ESP_LOGI(TAG, "Using pre-loaded flash encryption key in efuse");
+ }
+ return ESP_OK;
+}
+
+static esp_err_t initialise_flash_encryption(void)
+{
+ esp_efuse_batch_write_begin(); /* Batch all efuse writes at the end of this function */
+
+ /* Before first flash encryption pass, need to initialise key & crypto config */
+ esp_err_t err = check_and_generate_encryption_keys();
+ if (err != ESP_OK) {
+ esp_efuse_batch_write_cancel();
+ return err;
+ }
+
+ err = esp_flash_encryption_enable_secure_features();
+ if (err != ESP_OK) {
+ esp_efuse_batch_write_cancel();
+ return err;
+ }
+
+ err = esp_efuse_batch_write_commit();
+ if (err != ESP_OK) {
+ ESP_LOGE(TAG, "Error programming security eFuses (err=0x%x).", err);
+ return err;
+ }
+
+ return ESP_OK;
+}
+
+/* Encrypt all flash data that should be encrypted */
+static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_crypt_wr_dis)
+{
+ esp_err_t err;
+
+ /* If all flash_crypt_cnt bits are burned or write-disabled, the
+ device can't re-encrypt itself. */
+ if (flash_crypt_wr_dis || flash_crypt_cnt == CRYPT_CNT[0]->bit_count) {
+ ESP_LOGE(TAG, "Cannot re-encrypt data CRYPT_CNT %d write disabled %d", flash_crypt_cnt, flash_crypt_wr_dis);
+ return ESP_FAIL;
+ }
+
+ if (flash_crypt_cnt == 0) {
+ /* Very first flash of encrypted data: generate keys, etc. */
+ err = initialise_flash_encryption();
+ if (err != ESP_OK) {
+ return err;
+ }
+ }
+
+ err = encrypt_bootloader();
+ if (err != ESP_OK) {
+ return err;
+ }
+
+ /* If the primary slot executable application is not encrypted,
+ * then encrypt it
+ */
+ err = encrypt_primary_slot();
+ if (err != ESP_OK) {
+ return err;
+ }
+
+ /* Unconditionally encrypts remaining regions
+ * This will need changes when implementing multi-slot support
+ */
+ ESP_LOGI(TAG, "Encrypting remaining flash...");
+ uint32_t region_addr = CONFIG_ESP_APPLICATION_SECONDARY_START_ADDRESS;
+ size_t region_size = CONFIG_ESP_APPLICATION_SIZE;
+ err = esp_flash_encrypt_region(region_addr, region_size);
+ if (err != ESP_OK) {
+ return err;
+ }
+ region_addr = CONFIG_ESP_SCRATCH_OFFSET;
+ region_size = CONFIG_ESP_SCRATCH_SIZE;
+ err = esp_flash_encrypt_region(region_addr, region_size);
+ if (err != ESP_OK) {
+ return err;
+ }
+
+#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
+ // Go straight to max, permanently enabled
+ ESP_LOGI(TAG, "Setting CRYPT_CNT for permanent encryption");
+ size_t new_flash_crypt_cnt = CRYPT_CNT[0]->bit_count - flash_crypt_cnt;
+#else
+ /* Set least significant 0-bit in flash_crypt_cnt */
+ size_t new_flash_crypt_cnt = 1;
+#endif
+ ESP_LOGD(TAG, "CRYPT_CNT %d -> %d", flash_crypt_cnt, new_flash_crypt_cnt);
+ err = esp_efuse_write_field_cnt(CRYPT_CNT, new_flash_crypt_cnt);
+
+ ESP_LOGI(TAG, "Flash encryption completed");
+
+ return ESP_OK;
+}
+
+static esp_err_t encrypt_bootloader(void)
+{
+ esp_err_t err;
+ uint32_t image_length;
+ /* Check for plaintext bootloader (verification will fail if it's already encrypted) */
+ if (esp_image_verify_bootloader(&image_length) == ESP_OK) {
+ ESP_LOGI(TAG, "Encrypting bootloader...");
+
+ err = esp_flash_encrypt_region(ESP_BOOTLOADER_OFFSET, CONFIG_ESP_BOOTLOADER_SIZE);
+ if (err != ESP_OK) {
+ ESP_LOGE(TAG, "Failed to encrypt bootloader in place: 0x%x", err);
+ return err;
+ }
+ ESP_LOGI(TAG, "Bootloader encrypted successfully");
+ } else {
+ ESP_LOGW(TAG, "No valid bootloader was found");
+ return ESP_ERR_NOT_FOUND;
+ }
+
+ return ESP_OK;
+}
+
+static esp_err_t verify_img_header(uint32_t addr, const esp_image_load_header_t *image, bool silent)
+{
+ esp_err_t err = ESP_OK;
+
+ if (image->header_magic != ESP_LOAD_HEADER_MAGIC) {
+ if (!silent) {
+ ESP_LOGE(TAG, "image at 0x%x has invalid magic byte",
+ addr);
+ }
+ err = ESP_ERR_IMAGE_INVALID;
+ }
+
+ return err;
+}
+
+static esp_err_t encrypt_primary_slot(void)
+{
+ esp_err_t err;
+
+ esp_image_load_header_t img_header;
+
+ /* Check if the slot is plaintext or encrypted, 0x20 offset is for skipping
+ * MCUboot header
+ */
+ err = bootloader_flash_read(CONFIG_ESP_APPLICATION_PRIMARY_START_ADDRESS + 0x20,
+ &img_header, sizeof(esp_image_load_header_t), true);
+ if (err != ESP_OK) {
+ ESP_LOGE(TAG, "Failed to read slot img header");
+ return err;
+ } else {
+ err = verify_img_header(CONFIG_ESP_APPLICATION_PRIMARY_START_ADDRESS,
+ &img_header, true);
+ }
+
+ if (err == ESP_OK) {
+ ESP_LOGI(TAG, "Encrypting primary slot...");
+
+ err = esp_flash_encrypt_region(CONFIG_ESP_APPLICATION_PRIMARY_START_ADDRESS,
+ CONFIG_ESP_APPLICATION_SIZE);
+ if (err != ESP_OK) {
+ ESP_LOGE(TAG, "Failed to encrypt slot in place: 0x%x", err);
+ return err;
+ }
+ } else {
+ ESP_LOGW(TAG, "Slot already encrypted or no valid image was found");
+ }
+
+ return ESP_OK;
+}
+
+esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length)
+{
+ esp_err_t err;
+ uint32_t buf[FLASH_SECTOR_SIZE / sizeof(uint32_t)];
+
+ if (src_addr % FLASH_SECTOR_SIZE != 0) {
+ ESP_LOGE(TAG, "esp_flash_encrypt_region bad src_addr 0x%x", src_addr);
+ return ESP_FAIL;
+ }
+
+ wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL};
+ for (size_t i = 0; i < data_length; i += FLASH_SECTOR_SIZE) {
+ wdt_hal_write_protect_disable(&rtc_wdt_ctx);
+ wdt_hal_feed(&rtc_wdt_ctx);
+ wdt_hal_write_protect_enable(&rtc_wdt_ctx);
+ uint32_t sec_start = i + src_addr;
+ err = bootloader_flash_read(sec_start, buf, FLASH_SECTOR_SIZE, true);
+ if (err != ESP_OK) {
+ goto flash_failed;
+ }
+ err = bootloader_flash_erase_sector(sec_start / FLASH_SECTOR_SIZE);
+ if (err != ESP_OK) {
+ goto flash_failed;
+ }
+ err = bootloader_flash_write(sec_start, buf, FLASH_SECTOR_SIZE, true);
+ if (err != ESP_OK) {
+ goto flash_failed;
+ }
+ }
+ return ESP_OK;
+
+flash_failed:
+ ESP_LOGE(TAG, "flash operation failed: 0x%x", err);
+ return err;
+}
diff --git a/boot/espressif/main.c b/boot/espressif/main.c
index bd1d04d..083efc5 100644
--- a/boot/espressif/main.c
+++ b/boot/espressif/main.c
@@ -10,6 +10,8 @@
#include <bootutil/image.h>
#include "bootloader_init.h"
+#include "bootloader_utility.h"
+#include "bootloader_random.h"
#if defined(CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH) || defined(CONFIG_SECURE_BOOT)
#include "esp_efuse.h"
@@ -17,6 +19,9 @@
#ifdef CONFIG_SECURE_BOOT
#include "esp_secure_boot.h"
#endif
+#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
+#include "esp_flash_encrypt.h"
+#endif
#include "esp_loader.h"
#include "os/os_malloc.h"
@@ -37,12 +42,31 @@
{
bootloader_init();
+ BOOT_LOG_INF("Enabling RNG early entropy source...");
+ bootloader_random_enable();
+
+ /* Rough steps for a first boot when Secure Boot and/or Flash Encryption are still disabled on device:
+ * Secure Boot:
+ * 1) Calculate the SHA-256 hash digest of the public key and write to EFUSE.
+ * 2) Validate the application images and prepare the booting process.
+ * 3) Burn EFUSE to enable Secure Boot V2 (ABS_DONE_0).
+ * Flash Encryption:
+ * 4) Generate Flash Encryption key and write to EFUSE.
+ * 5) Encrypt flash in-place including bootloader, image primary/secondary slot and scratch.
+ * 6) Burn EFUSE to enable Flash Encryption.
+ * 7) Reset system to ensure Flash Encryption cache resets properly.
+ */
+
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
BOOT_LOG_WRN("eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
esp_efuse_init_virtual_mode_in_flash(CONFIG_EFUSE_VIRTUAL_OFFSET, CONFIG_EFUSE_VIRTUAL_SIZE);
#endif
#ifdef CONFIG_SECURE_BOOT
+ /* Steps 1 (see above for full description):
+ * 1) Compute digest of the public key.
+ */
+
BOOT_LOG_INF("enabling secure boot v2...");
bool sb_hw_enabled = esp_secure_boot_enabled();
@@ -66,8 +90,13 @@
os_heap_init();
struct boot_rsp rsp;
+
fih_int fih_rc = FIH_FAILURE;
+ /* Step 2 (see above for full description):
+ * 2) MCUboot validates the application images and prepares the booting process.
+ */
+
FIH_CALL(boot_go, fih_rc, &rsp);
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
@@ -79,6 +108,10 @@
}
#ifdef CONFIG_SECURE_BOOT
+ /* Step 3 (see above for full description):
+ * 3) Burn EFUSE to enable Secure Boot V2.
+ */
+
if (!sb_hw_enabled) {
BOOT_LOG_INF("blowing secure boot efuse...");
esp_err_t err;
@@ -103,6 +136,35 @@
}
#endif
+#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
+ /* Step 4, 5 & 6 (see above for full description):
+ * 4) Generate Flash Encryption key and write to EFUSE.
+ * 5) Encrypt flash in-place including bootloader, image primary/secondary slot and scratch.
+ * 6) Burn EFUSE to enable flash encryption
+ */
+
+ int rc;
+
+ BOOT_LOG_INF("Checking flash encryption...");
+ bool flash_encryption_enabled = esp_flash_encryption_enabled();
+ rc = esp_flash_encrypt_check_and_update();
+ if (rc != ESP_OK) {
+ BOOT_LOG_ERR("Flash encryption check failed (%d).", rc);
+ FIH_PANIC;
+ }
+
+ /* Step 7 (see above for full description):
+ * 7) Reset system to ensure flash encryption cache resets properly.
+ */
+ if (!flash_encryption_enabled && esp_flash_encryption_enabled()) {
+ BOOT_LOG_INF("Resetting with flash encryption enabled...");
+ bootloader_reset();
+ }
+#endif
+
+ BOOT_LOG_INF("Disabling RNG early entropy source...");
+ bootloader_random_disable();
+
do_boot(&rsp);
while(1);
diff --git a/boot/espressif/port/esp32/ld/bootloader.ld b/boot/espressif/port/esp32/ld/bootloader.ld
index 8249181..9933bd3 100644
--- a/boot/espressif/port/esp32/ld/bootloader.ld
+++ b/boot/espressif/port/esp32/ld/bootloader.ld
@@ -12,9 +12,9 @@
MEMORY
{
- iram_seg (RWX) : org = 0x40093000, len = 0x9000
- iram_loader_seg (RWX) : org = 0x4009C000, len = 0x4000
- dram_seg (RW) : org = 0x3FFF5000, len = 0x8000
+ iram_seg (RWX) : org = 0x40093000, len = 0x8800
+ iram_loader_seg (RWX) : org = 0x4009B800, len = 0x4800
+ dram_seg (RW) : org = 0x3FFF5000, len = 0x8900
}
/* Default entry point: */
diff --git a/boot/espressif/port/esp32c3/ld/bootloader.ld b/boot/espressif/port/esp32c3/ld/bootloader.ld
index 61dd412..c627cb9 100644
--- a/boot/espressif/port/esp32c3/ld/bootloader.ld
+++ b/boot/espressif/port/esp32c3/ld/bootloader.ld
@@ -14,7 +14,7 @@
{
iram_seg (RWX) : org = 0x403C8000, len = 0x8000
iram_loader_seg (RWX) : org = 0x403D0000, len = 0x4800
- dram_seg (RW) : org = 0x3FCD5000, len = 0x8800
+ dram_seg (RW) : org = 0x3FCD5000, len = 0x8C00
}
/* Default entry point: */
diff --git a/boot/espressif/port/esp32s2/ld/bootloader.ld b/boot/espressif/port/esp32s2/ld/bootloader.ld
index d01e7a5..3521894 100644
--- a/boot/espressif/port/esp32s2/ld/bootloader.ld
+++ b/boot/espressif/port/esp32s2/ld/bootloader.ld
@@ -9,12 +9,12 @@
* The main purpose is to make sure the bootloader can load into main memory
* without overwriting itself.
*/
-
+
MEMORY
{
iram_seg (RWX) : org = 0x40048000, len = 0x8000
iram_loader_seg (RWX) : org = 0x40050000, len = 0x5000
- dram_seg (RW) : org = 0x3FFE5000, len = 0x8000
+ dram_seg (RW) : org = 0x3FFE5000, len = 0x8E00
}
/* Default entry point: */
diff --git a/boot/espressif/port/esp_loader.c b/boot/espressif/port/esp_loader.c
index 9e6aef6..f2f7d87 100644
--- a/boot/espressif/port/esp_loader.c
+++ b/boot/espressif/port/esp_loader.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd.
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -10,6 +10,7 @@
#include <bootutil/fault_injection_hardening.h>
#include "bootloader_flash_priv.h"
+#include "esp_flash_encrypt.h"
#include "soc/soc_memory_layout.h"
#if CONFIG_IDF_TARGET_ESP32
@@ -20,24 +21,10 @@
#include "esp32c3/rom/uart.h"
#endif
+#include "esp_mcuboot_image.h"
#include "esp_loader.h"
#include "flash_map_backend/flash_map_backend.h"
-#define ESP_LOAD_HEADER_MAGIC 0xace637d3 /* Magic is derived from sha256sum of espmcuboot */
-
-/*
- * Load header that should be a part of application image.
- */
-typedef struct image_load_header {
- uint32_t header_magic; /* Magic for load header */
- uint32_t entry_addr; /* Application entry address */
- uint32_t iram_dest_addr; /* Destination address(VMA) for IRAM region */
- uint32_t iram_flash_offset; /* Flash offset(LMA) for start of IRAM region */
- uint32_t iram_size; /* Size of IRAM region */
- uint32_t dram_dest_addr; /* Destination address(VMA) for DRAM region */
- uint32_t dram_flash_offset; /* Flash offset(LMA) for start of DRAM region */
- uint32_t dram_size; /* Size of DRAM region */
-} image_load_header_t;
static int load_segment(const struct flash_area *fap, uint32_t data_addr, uint32_t data_len, uint32_t load_addr)
{
@@ -57,16 +44,15 @@
int area_id;
int rc;
- image_load_header_t load_header = {0};
-
area_id = flash_area_id_from_image_slot(slot);
rc = flash_area_open(area_id, &fap);
if (rc != 0) {
BOOT_LOG_ERR("%s: flash_area_open failed with %d", __func__, rc);
}
- const uint32_t *data = (const uint32_t *)bootloader_mmap((fap->fa_off + hdr_offset), sizeof(image_load_header_t));
- memcpy((void *)&load_header, data, sizeof(image_load_header_t));
+ const uint32_t *data = (const uint32_t *)bootloader_mmap((fap->fa_off + hdr_offset), sizeof(esp_image_load_header_t));
+ esp_image_load_header_t load_header = {0};
+ memcpy((void *)&load_header, data, sizeof(esp_image_load_header_t));
bootloader_munmap(data);
if (load_header.header_magic != ESP_LOAD_HEADER_MAGIC) {
diff --git a/boot/espressif/port/esp_mcuboot.c b/boot/espressif/port/esp_mcuboot.c
index 4dd03b9..5cda2ae 100644
--- a/boot/espressif/port/esp_mcuboot.c
+++ b/boot/espressif/port/esp_mcuboot.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd.
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -11,8 +11,10 @@
#include <bootutil/bootutil.h>
#include <bootutil/bootutil_log.h>
+#include "sdkconfig.h"
#include "esp_err.h"
#include "bootloader_flash_priv.h"
+#include "esp_flash_encrypt.h"
#include "flash_map_backend/flash_map_backend.h"
#include "sysflash/sysflash.h"
@@ -45,7 +47,7 @@
_Static_assert(IS_ALIGNED(FLASH_BUFFER_SIZE, 4), "Buffer size for SPI Flash operations must be 4-byte aligned.");
-#define BOOTLOADER_START_ADDRESS 0x1000
+#define BOOTLOADER_START_ADDRESS CONFIG_BOOTLOADER_OFFSET_IN_FLASH
#define BOOTLOADER_SIZE CONFIG_ESP_BOOTLOADER_SIZE
#define APPLICATION_PRIMARY_START_ADDRESS CONFIG_ESP_APPLICATION_PRIMARY_START_ADDRESS
#define APPLICATION_SECONDARY_START_ADDRESS CONFIG_ESP_APPLICATION_SECONDARY_START_ADDRESS
@@ -196,10 +198,12 @@
return -1;
}
+ bool flash_encryption_enabled = esp_flash_encryption_enabled();
+
const uint32_t start_addr = fa->fa_off + off;
BOOT_LOG_DBG("%s: Addr: 0x%08x Length: %d", __func__, (int)start_addr, (int)len);
- if (bootloader_flash_write(start_addr, (void *)src, len, false) != ESP_OK) {
+ if (bootloader_flash_write(start_addr, (void *)src, len, flash_encryption_enabled) != ESP_OK) {
BOOT_LOG_ERR("%s: Flash write failed", __func__);
return -1;
}
@@ -241,7 +245,18 @@
uint32_t flash_area_align(const struct flash_area *area)
{
- return 4;
+ static size_t align = 0;
+
+ if (align == 0) {
+ bool flash_encryption_enabled = esp_flash_encryption_enabled();
+
+ if (flash_encryption_enabled) {
+ align = 32;
+ } else {
+ align = 4;
+ }
+ }
+ return align;
}
uint8_t flash_area_erased_val(const struct flash_area *area)
diff --git a/boot/espressif/secureboot-sign-ec256.conf b/boot/espressif/secureboot-sign-ec256.conf
index cbd588d..98894fa 100644
--- a/boot/espressif/secureboot-sign-ec256.conf
+++ b/boot/espressif/secureboot-sign-ec256.conf
@@ -2,11 +2,19 @@
#
# SPDX-License-Identifier: Apache-2.0
+# ATTENTION:
+# This configuration file targets the building for CI environment and contains
+# a set of definitions to resemble a bootloader image for RELEASE environment.
+# Running the generated firmware image may result in irreversible operations
+# to the chip!
+
CONFIG_SECURE_SIGNED_ON_BOOT=1
CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME=1
CONFIG_SECURE_BOOT=1
CONFIG_SECURE_BOOT_V2_ENABLED=1
CONFIG_SECURE_BOOT_SUPPORTS_RSA=1
+CONFIG_SECURE_FLASH_ENC_ENABLED=1
+CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=1
CONFIG_ESP_SIGN_KEY_FILE=root-ec-p256.pem
CONFIG_ESP_USE_TINYCRYPT=1
CONFIG_ESP_SIGN_EC256=1
diff --git a/boot/espressif/secureboot-sign-ed25519.conf b/boot/espressif/secureboot-sign-ed25519.conf
index a086fb6..67e6dcd 100644
--- a/boot/espressif/secureboot-sign-ed25519.conf
+++ b/boot/espressif/secureboot-sign-ed25519.conf
@@ -2,11 +2,19 @@
#
# SPDX-License-Identifier: Apache-2.0
+# ATTENTION:
+# This configuration file targets the building for CI environment and contains
+# a set of definitions to resemble a bootloader image for RELEASE environment.
+# Running the generated firmware image may result in irreversible operations
+# to the chip!
+
CONFIG_SECURE_SIGNED_ON_BOOT=1
CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME=1
CONFIG_SECURE_BOOT=1
CONFIG_SECURE_BOOT_V2_ENABLED=1
CONFIG_SECURE_BOOT_SUPPORTS_RSA=1
+CONFIG_SECURE_FLASH_ENC_ENABLED=1
+CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=1
CONFIG_ESP_SIGN_KEY_FILE=root-ed25519.pem
CONFIG_ESP_USE_TINYCRYPT=1
CONFIG_ESP_SIGN_ED25519=1
diff --git a/boot/espressif/secureboot-sign-rsa2048.conf b/boot/espressif/secureboot-sign-rsa2048.conf
index a0f5464..e5888f7 100644
--- a/boot/espressif/secureboot-sign-rsa2048.conf
+++ b/boot/espressif/secureboot-sign-rsa2048.conf
@@ -2,11 +2,19 @@
#
# SPDX-License-Identifier: Apache-2.0
+# ATTENTION:
+# This configuration file targets the building for CI environment and contains
+# a set of definitions to resemble a bootloader image for RELEASE environment.
+# Running the generated firmware image may result in irreversible operations
+# to the chip!
+
CONFIG_SECURE_SIGNED_ON_BOOT=1
CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME=1
CONFIG_SECURE_BOOT=1
CONFIG_SECURE_BOOT_V2_ENABLED=1
CONFIG_SECURE_BOOT_SUPPORTS_RSA=1
+CONFIG_SECURE_FLASH_ENC_ENABLED=1
+CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=1
CONFIG_ESP_SIGN_KEY_FILE=root-rsa-2048.pem
CONFIG_ESP_USE_MBEDTLS=1
CONFIG_ESP_SIGN_RSA=1
diff --git a/boot/espressif/secureboot-sign-rsa3072.conf b/boot/espressif/secureboot-sign-rsa3072.conf
index 0aa6be7..66825e0 100644
--- a/boot/espressif/secureboot-sign-rsa3072.conf
+++ b/boot/espressif/secureboot-sign-rsa3072.conf
@@ -2,11 +2,19 @@
#
# SPDX-License-Identifier: Apache-2.0
+# ATTENTION:
+# This configuration file targets the building for CI environment and contains
+# a set of definitions to resemble a bootloader image for RELEASE environment.
+# Running the generated firmware image may result in irreversible operations
+# to the chip!
+
CONFIG_SECURE_SIGNED_ON_BOOT=1
CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME=1
CONFIG_SECURE_BOOT=1
CONFIG_SECURE_BOOT_V2_ENABLED=1
CONFIG_SECURE_BOOT_SUPPORTS_RSA=1
+CONFIG_SECURE_FLASH_ENC_ENABLED=1
+CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=1
CONFIG_ESP_SIGN_KEY_FILE=root-rsa-3072.pem
CONFIG_ESP_USE_MBEDTLS=1
CONFIG_ESP_SIGN_RSA=1