efuse(esp32): Deprecate esp_efuse_burn_new_values() & esp_efuse_write_random_key()

These functions were used only for esp32 in secure_boot and flash encryption.
Use idf efuse APIs instead of efuse regs.
This commit is contained in:
Konstantin Kondrashov
2021-06-17 07:21:36 +08:00
committed by Angus Gratton
parent eca878b37f
commit f339b3fc96
86 changed files with 2785 additions and 2825 deletions

View File

@@ -31,6 +31,12 @@
#include "esp32c3/rom/spi_flash.h"
#endif
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
#define ENCRYPTION_IS_VIRTUAL 1
#else
#define ENCRYPTION_IS_VIRTUAL 0
#endif
#ifndef BOOTLOADER_BUILD
/* Normal app version maps to esp_spi_flash.h operations...
@@ -80,7 +86,7 @@ esp_err_t bootloader_flash_read(size_t src, void *dest, size_t size, bool allow_
esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool write_encrypted)
{
if (write_encrypted) {
if (write_encrypted && !ENCRYPTION_IS_VIRTUAL) {
#if CONFIG_IDF_TARGET_ESP32
return spi_flash_write_encrypted(dest_addr, src, size);
#else
@@ -395,7 +401,7 @@ esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool
return err;
}
if (write_encrypted) {
if (write_encrypted && !ENCRYPTION_IS_VIRTUAL) {
return spi_to_esp_err(esp_rom_spiflash_write_encrypted(dest_addr, src, size));
} else {
return spi_to_esp_err(esp_rom_spiflash_write(dest_addr, src, size));

View File

@@ -186,8 +186,8 @@ bool bootloader_utility_load_partition_table(bootloader_state_t *bs)
break;
case PART_SUBTYPE_DATA_EFUSE_EM:
partition_usage = "efuse";
#ifdef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE
esp_efuse_init(partition->pos.offset, partition->pos.size);
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
esp_efuse_init_virtual_mode_in_flash(partition->pos.offset, partition->pos.size);
#endif
break;
default:

View File

@@ -34,6 +34,7 @@
#include "esp_rom_sys.h"
#include "esp32/rom/spi_flash.h"
#include "esp32/rom/rtc.h"
#include "esp_efuse.h"
static const char *TAG = "boot.esp32";
@@ -364,6 +365,13 @@ esp_err_t bootloader_init(void)
#endif
// clear bss section
bootloader_clear_bss_section();
// init eFuse virtual mode (read eFuses to RAM)
#ifdef CONFIG_EFUSE_VIRTUAL
ESP_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
esp_efuse_init_virtual_mode_in_ram();
#endif
#endif
// bootst up vddsdio
bootloader_common_vddsdio_configure();
// reset MMU

View File

@@ -1,376 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <strings.h>
#include "bootloader_flash_priv.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_log.h"
#include "esp32/rom/secure_boot.h"
#include "hal/wdt_hal.h"
#include "esp32/rom/cache.h"
#include "esp32/rom/spi_flash.h" /* TODO: Remove this */
/* 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_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions);
static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition);
esp_err_t esp_flash_encrypt_check_and_update(void)
{
uint32_t efuse_blk0 = REG_READ(EFUSE_BLK0_RDATA0_REG);
ESP_LOGV(TAG, "efuse_blk0 raw value %08x", efuse_blk0);
uint32_t flash_crypt_cnt = (efuse_blk0 & EFUSE_RD_FLASH_CRYPT_CNT_M) >> EFUSE_RD_FLASH_CRYPT_CNT_S;
bool flash_crypt_wr_dis = efuse_blk0 & EFUSE_WR_DIS_FLASH_CRYPT_CNT;
ESP_LOGV(TAG, "efuse FLASH_CRYPT_CNT 0x%x WR_DIS_FLASH_CRYPT_CNT 0x%x", flash_crypt_cnt, flash_crypt_wr_dis);
if (__builtin_parity(flash_crypt_cnt) == 1) {
/* Flash is already encrypted */
int left = (7 - __builtin_popcount(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 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);
return ESP_ERR_NOT_SUPPORTED;
}
/* Before first flash encryption pass, need to initialise key & crypto config */
/* Generate key */
uint32_t dis_reg = REG_READ(EFUSE_BLK0_RDATA0_REG);
bool efuse_key_read_protected = dis_reg & EFUSE_RD_DIS_BLK1;
bool efuse_key_write_protected = dis_reg & EFUSE_WR_DIS_BLK1;
if (efuse_key_read_protected == false
&& efuse_key_write_protected == false
&& REG_READ(EFUSE_BLK1_RDATA0_REG) == 0
&& REG_READ(EFUSE_BLK1_RDATA1_REG) == 0
&& REG_READ(EFUSE_BLK1_RDATA2_REG) == 0
&& REG_READ(EFUSE_BLK1_RDATA3_REG) == 0
&& REG_READ(EFUSE_BLK1_RDATA4_REG) == 0
&& REG_READ(EFUSE_BLK1_RDATA5_REG) == 0
&& REG_READ(EFUSE_BLK1_RDATA6_REG) == 0
&& REG_READ(EFUSE_BLK1_RDATA7_REG) == 0) {
ESP_LOGI(TAG, "Generating new flash encryption key...");
esp_efuse_write_random_key(EFUSE_BLK1_WDATA0_REG);
// defer efuse programming step to the end
ESP_LOGI(TAG, "Read & write protecting new key...");
new_wdata0 |= EFUSE_WR_DIS_BLK1 | EFUSE_RD_DIS_BLK1;
} else {
if(!(efuse_key_read_protected && efuse_key_write_protected)) {
ESP_LOGE(TAG, "Flash encryption key has to be either unset or both read and write protected");
return ESP_ERR_INVALID_STATE;
}
ESP_LOGW(TAG, "Using pre-loaded flash encryption key in EFUSE block 1");
}
/* CRYPT_CONFIG determines which bits of the AES block key are XORed
with bits from the flash address, to provide the key tweak.
CRYPT_CONFIG == 0 is effectively AES ECB mode (NOT SUPPORTED)
For now this is hardcoded to XOR all 256 bits of the key.
If you need to override it, you can pre-burn this efuse to the
desired value and then write-protect it, in which case this
operation does nothing. Please note this is not recommended!
*/
ESP_LOGI(TAG, "Setting CRYPT_CONFIG efuse to 0xF");
new_wdata5 |= EFUSE_FLASH_CRYPT_CONFIG_M;
#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;
#else
ESP_LOGW(TAG, "Not disabling ROM BASIC fallback - SECURITY COMPROMISED");
#endif
#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;
}
/* 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;
esp_partition_info_t partition_table[ESP_PARTITION_TABLE_MAX_ENTRIES];
int num_partitions;
/* If the last flash_crypt_cnt bit is burned or write-disabled, the
device can't re-encrypt itself. */
if (flash_crypt_wr_dis || flash_crypt_cnt == 0xFF) {
ESP_LOGE(TAG, "Cannot re-encrypt data (FLASH_CRYPT_CNT 0x%02x 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;
}
err = encrypt_and_load_partition_table(partition_table, &num_partitions);
if (err != ESP_OK) {
return err;
}
/* Now iterate the just-loaded partition table, looking for entries to encrypt
*/
/* Go through each partition and encrypt if necessary */
for (int i = 0; i < num_partitions; i++) {
err = encrypt_partition(i, &partition_table[i]);
if (err != ESP_OK) {
return err;
}
}
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) */
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);
REG_WRITE(EFUSE_BLK0_WDATA0_REG, wdata0_reg);
esp_efuse_burn_new_values();
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_LOGD(TAG, "bootloader is plaintext. Encrypting...");
#if CONFIG_SECURE_BOOT_V2_ENABLED
/* The image length obtained from esp_image_verify_bootloader includes the sector boundary padding and the signature block lengths */
if (ESP_BOOTLOADER_OFFSET + image_length > ESP_PARTITION_TABLE_OFFSET) {
ESP_LOGE(TAG, "Bootloader is too large to fit Secure Boot V2 signature sector and partition table (configured offset 0x%x)", ESP_PARTITION_TABLE_OFFSET);
return ESP_ERR_INVALID_STATE;
}
#endif // CONFIG_SECURE_BOOT_V2_ENABLED
err = esp_flash_encrypt_region(ESP_BOOTLOADER_OFFSET, image_length);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt bootloader in place: 0x%x", err);
return err;
}
#ifdef CONFIG_SECURE_BOOT_V1_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");
}
return ESP_OK;
}
static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions)
{
esp_err_t err;
/* Check for plaintext partition table */
err = bootloader_flash_read(ESP_PARTITION_TABLE_OFFSET, partition_table, ESP_PARTITION_TABLE_MAX_LEN, false);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to read partition table data");
return err;
}
if (esp_partition_table_verify(partition_table, false, num_partitions) == ESP_OK) {
ESP_LOGD(TAG, "partition table is plaintext. Encrypting...");
esp_err_t err = esp_flash_encrypt_region(ESP_PARTITION_TABLE_OFFSET,
FLASH_SECTOR_SIZE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt partition table in place. %x", err);
return err;
}
}
else {
ESP_LOGE(TAG, "Failed to read partition table data - not plaintext?");
return ESP_ERR_INVALID_STATE;
}
/* Valid partition table loded */
return ESP_OK;
}
static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition)
{
esp_err_t err;
bool should_encrypt = (partition->flags & PART_FLAG_ENCRYPTED);
if (partition->type == PART_TYPE_APP) {
/* check if the partition holds a valid unencrypted app */
esp_image_metadata_t data_ignored;
err = esp_image_verify(ESP_IMAGE_VERIFY,
&partition->pos,
&data_ignored);
should_encrypt = (err == ESP_OK);
} else if ((partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_OTA)
|| (partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_NVS_KEYS)) {
/* check if we have ota data partition and the partition should be encrypted unconditionally */
should_encrypt = true;
}
if (!should_encrypt) {
return ESP_OK;
}
else {
/* should_encrypt */
ESP_LOGI(TAG, "Encrypting partition %d at offset 0x%x...", index, partition->pos.offset);
err = esp_flash_encrypt_region(partition->pos.offset, partition->pos.size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt partition %d", index);
}
return err;
}
}
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, false);
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;
}

View File

@@ -0,0 +1,83 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <strings.h>
#include "esp_flash_encrypt.h"
#include "esp_secure_boot.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp_log.h"
#include "sdkconfig.h"
static __attribute__((unused)) const char *TAG = "flash_encrypt";
esp_err_t esp_flash_encryption_enable_secure_features(void)
{
/* CRYPT_CONFIG determines which bits of the AES block key are XORed
with bits from the flash address, to provide the key tweak.
CRYPT_CONFIG == 0 is effectively AES ECB mode (NOT SUPPORTED)
For now this is hardcoded to XOR all 256 bits of the key.
If you need to override it, you can pre-burn this efuse to the
desired value and then write-protect it, in which case this
operation does nothing. Please note this is not recommended!
*/
ESP_LOGI(TAG, "Setting CRYPT_CONFIG efuse to 0xF");
uint32_t crypt_config = 0;
esp_efuse_read_field_blob(ESP_EFUSE_ENCRYPT_CONFIG, &crypt_config, 4);
if (crypt_config == 0) {
crypt_config = EFUSE_FLASH_CRYPT_CONFIG;
esp_efuse_write_field_blob(ESP_EFUSE_ENCRYPT_CONFIG, &crypt_config, 4);
} else if (crypt_config != EFUSE_FLASH_CRYPT_CONFIG) {
ESP_LOGE(TAG, "EFUSE_ENCRYPT_CONFIG should be set 0xF but it is 0x%x", crypt_config);
}
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
esp_efuse_write_field_bit(ESP_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...");
esp_efuse_write_field_bit(ESP_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...");
esp_efuse_write_field_bit(ESP_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...");
esp_efuse_write_field_bit(ESP_EFUSE_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...");
esp_efuse_write_field_bit(ESP_EFUSE_CONSOLE_DEBUG_DISABLE);
#else
ESP_LOGW(TAG, "Not disabling ROM BASIC fallback - SECURITY COMPROMISED");
#endif
#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
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_EFUSE_RD_DISABLE);
#endif
return ESP_OK;
}

View File

@@ -1,470 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_attr.h"
#include "esp_types.h"
#include "esp_log.h"
#include "esp32/rom/cache.h"
#include "soc/efuse_periph.h"
#include "soc/rtc_periph.h"
#include "bootloader_sha.h"
#include "bootloader_utility.h"
#include "sdkconfig.h"
#include "bootloader_flash_priv.h"
#include "bootloader_random.h"
#include "esp_image_format.h"
#include "esp_secure_boot.h"
#include "esp_flash_encrypt.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
/* The following API implementations are used only when called
* from the bootloader code.
*/
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
static const char *TAG = "secure_boot_v1";
/**
* @function : secure_boot_generate
* @description: generate boot digest (aka "abstract") & iv
*
* @inputs: image_len - length of image to calculate digest for
*/
static bool secure_boot_generate(uint32_t image_len){
esp_err_t err;
esp_secure_boot_iv_digest_t digest;
const uint32_t *image;
/* hardware secure boot engine only takes full blocks, so round up the
image length. The additional data should all be 0xFF (or the appended SHA, if it falls in the same block).
*/
if (image_len % sizeof(digest.iv) != 0) {
image_len = (image_len / sizeof(digest.iv) + 1) * sizeof(digest.iv);
}
ets_secure_boot_start();
ets_secure_boot_rd_iv((uint32_t *)digest.iv);
ets_secure_boot_hash(NULL);
/* iv stored in sec 0 */
err = bootloader_flash_erase_sector(0);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "SPI erase failed: 0x%x", err);
return false;
}
/* generate digest from image contents */
image = bootloader_mmap(ESP_BOOTLOADER_OFFSET, image_len);
if (!image) {
ESP_LOGE(TAG, "bootloader_mmap(0x1000, 0x%x) failed", image_len);
return false;
}
for (size_t i = 0; i < image_len; i+= sizeof(digest.iv)) {
ets_secure_boot_hash(&image[i/sizeof(uint32_t)]);
}
bootloader_munmap(image);
ets_secure_boot_obtain();
ets_secure_boot_rd_abstract((uint32_t *)digest.digest);
ets_secure_boot_finish();
ESP_LOGD(TAG, "write iv+digest to flash");
err = bootloader_flash_write(FLASH_OFFS_SECURE_BOOT_IV_DIGEST, &digest,
sizeof(digest), esp_flash_encryption_enabled());
if (err != ESP_OK) {
ESP_LOGE(TAG, "SPI write failed: 0x%x", err);
return false;
}
Cache_Read_Enable(0);
return true;
}
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."
" No need to generate digest. continuing..");
return ESP_OK;
}
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);
return ESP_ERR_NOT_SUPPORTED;
}
/* Verify the bootloader */
esp_image_metadata_t bootloader_data = { 0 };
err = esp_image_verify_bootloader_data(&bootloader_data);
if (err != ESP_OK) {
ESP_LOGE(TAG, "bootloader image appears invalid! error %d", err);
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;
if (efuse_key_read_protected == false
&& efuse_key_write_protected == false
&& REG_READ(EFUSE_BLK2_RDATA0_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA1_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA2_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA3_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA4_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA5_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA6_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA7_REG) == 0) {
ESP_LOGI(TAG, "Generating new secure boot key...");
esp_efuse_write_random_key(EFUSE_BLK2_WDATA0_REG);
esp_efuse_burn_new_values();
} 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) {
/* Secure boot digest doesn't cover the hash */
image_len -= ESP_IMAGE_HASH_LEN;
}
if (false == secure_boot_generate(image_len)){
ESP_LOGE(TAG, "secure boot generation failed");
return ESP_FAIL;
}
ESP_LOGI(TAG, "Digest generation complete.");
return ESP_OK;
}
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;
}
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...");
new_wdata0 = EFUSE_WR_DIS_BLK2 | EFUSE_RD_DIS_BLK2;
efuse_key_read_protected = true;
efuse_key_write_protected = true;
}
if (!efuse_key_read_protected) {
ESP_LOGE(TAG, "Pre-loaded key is not read protected. Refusing to blow secure boot efuse.");
return ESP_ERR_INVALID_STATE;
}
if (!efuse_key_write_protected) {
ESP_LOGE(TAG, "Pre-loaded key is not write protected. Refusing to blow secure boot efuse.");
return ESP_ERR_INVALID_STATE;
}
ESP_LOGI(TAG, "blowing secure boot efuse...");
ESP_LOGD(TAG, "before updating, EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG));
new_wdata6 |= EFUSE_RD_ABS_DONE_0;
#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;
#else
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);
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) {
ESP_LOGI(TAG, "secure boot is now enabled for bootloader image");
return ESP_OK;
} else {
ESP_LOGE(TAG, "secure boot not enabled for bootloader image, EFUSE_RD_ABS_DONE_0 is probably write protected!");
return ESP_ERR_INVALID_STATE;
}
}
#elif CONFIG_SECURE_BOOT_V2_ENABLED
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
static const char *TAG = "secure_boot_v2";
static esp_err_t validate_signature_block(const ets_secure_boot_signature_t *sig_block, uint8_t *digest)
{
uint32_t crc = esp_rom_crc32_le(0, (uint8_t *)sig_block, CRC_SIGN_BLOCK_LEN);
if (sig_block->block[0].magic_byte == ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC
&& sig_block->block[0].block_crc == crc
&& !memcmp(digest, sig_block->block[0].image_digest, ESP_SECURE_BOOT_DIGEST_LEN)) {
ESP_LOGI(TAG, "valid signature block found");
return ESP_OK;
}
return ESP_FAIL;
}
static esp_err_t secure_boot_v2_digest_generate(uint32_t flash_offset, uint32_t flash_size, uint8_t *public_key_digest)
{
esp_err_t ret = ESP_FAIL;
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
size_t sig_block_addr = flash_offset + ALIGN_UP(flash_size, FLASH_SECTOR_SIZE);
ret = bootloader_sha256_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "error generating image digest, %d", ret);
return ret;
}
ESP_LOGD(TAG, "reading signature block");
const ets_secure_boot_signature_t *sig_block = bootloader_mmap(sig_block_addr, sizeof(ets_secure_boot_signature_t));
if (sig_block == NULL) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", sig_block_addr, sizeof(ets_secure_boot_signature_t));
return ret;
}
/* Validating Signature block */
ret = validate_signature_block(sig_block, image_digest);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "signature block (address 0x%x) validation failed %d", sig_block_addr, ret);
goto done;
}
/* Verifying Signature block */
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
/* Generating the SHA of the public key components in the signature block */
bootloader_sha256_handle_t sig_block_sha;
sig_block_sha = bootloader_sha256_start();
bootloader_sha256_data(sig_block_sha, &sig_block->block[0].key, sizeof(sig_block->block[0].key));
bootloader_sha256_finish(sig_block_sha, public_key_digest);
secure_boot_v2_status_t error;
error = ets_secure_boot_verify_signature(sig_block, image_digest, public_key_digest, verified_digest);
if (error != SBV2_SUCCESS) {
ESP_LOGE(TAG, "secure boot v2 verification failed %d", error);
ret = ESP_FAIL;
goto done;
} else {
ret = ESP_OK;
}
done:
bootloader_munmap(sig_block);
return ret;
}
esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *image_data)
{
ESP_LOGI(TAG, "enabling secure boot v2...");
esp_err_t ret;
if (esp_secure_boot_enabled()) {
ESP_LOGI(TAG, "secure boot v2 is already enabled. Continuing..");
return ESP_OK;
}
ret = esp_efuse_batch_write_begin();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Error batch programming security eFuses.");
return ret;
}
uint32_t coding_scheme = REG_GET_FIELD(EFUSE_BLK0_RDATA6_REG, EFUSE_CODING_SCHEME);
if (coding_scheme != EFUSE_CODING_SCHEME_VAL_NONE) {
ESP_LOGE(TAG, "No coding schemes are supported in secure boot v2.(Detected scheme: 0x%x)", coding_scheme);
return ESP_ERR_NOT_SUPPORTED;
}
/* Verify the bootloader */
esp_image_metadata_t bootloader_data = { 0 };
ret = esp_image_verify_bootloader_data(&bootloader_data);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "bootloader image appears invalid! error %d", ret);
return ret;
}
uint8_t boot_pub_key_digest[ESP_SECURE_BOOT_DIGEST_LEN];
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;
uint32_t efuse_blk2_r0, efuse_blk2_r1, efuse_blk2_r2, efuse_blk2_r3, efuse_blk2_r4, efuse_blk2_r5, efuse_blk2_r6, efuse_blk2_r7;
efuse_blk2_r0 = REG_READ(EFUSE_BLK2_RDATA0_REG);
efuse_blk2_r1 = REG_READ(EFUSE_BLK2_RDATA1_REG);
efuse_blk2_r2 = REG_READ(EFUSE_BLK2_RDATA2_REG);
efuse_blk2_r3 = REG_READ(EFUSE_BLK2_RDATA3_REG);
efuse_blk2_r4 = REG_READ(EFUSE_BLK2_RDATA4_REG);
efuse_blk2_r5 = REG_READ(EFUSE_BLK2_RDATA5_REG);
efuse_blk2_r6 = REG_READ(EFUSE_BLK2_RDATA6_REG);
efuse_blk2_r7 = REG_READ(EFUSE_BLK2_RDATA7_REG);
if (efuse_key_read_protected == true) {
ESP_LOGE(TAG, "Secure Boot v2 digest(BLK2) read protected, aborting....");
return ESP_FAIL;
}
if (efuse_key_write_protected == false
&& efuse_blk2_r0 == 0 && efuse_blk2_r1 == 0
&& efuse_blk2_r2 == 0 && efuse_blk2_r3 == 0
&& efuse_blk2_r4 == 0 && efuse_blk2_r5 == 0
&& efuse_blk2_r6 == 0 && efuse_blk2_r7 == 0) {
/* Verifies the signature block appended to the image matches with the signature block of the app to be loaded */
ret = secure_boot_v2_digest_generate(bootloader_data.start_addr, bootloader_data.image_len - SIG_BLOCK_PADDING, boot_pub_key_digest);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Public key digest generation failed");
return ret;
}
ESP_LOGI(TAG, "Burning public key hash to efuse.");
ret = esp_efuse_write_block(EFUSE_BLK2, boot_pub_key_digest, 0, (ESP_SECURE_BOOT_DIGEST_LEN * 8));
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Writing public key hash to efuse failed.");
return ret;
}
} else {
uint32_t efuse_blk2_digest[8];
efuse_blk2_digest[0] = efuse_blk2_r0;
efuse_blk2_digest[1] = efuse_blk2_r1;
efuse_blk2_digest[2] = efuse_blk2_r2;
efuse_blk2_digest[3] = efuse_blk2_r3;
efuse_blk2_digest[4] = efuse_blk2_r4;
efuse_blk2_digest[5] = efuse_blk2_r5;
efuse_blk2_digest[6] = efuse_blk2_r6;
efuse_blk2_digest[7] = efuse_blk2_r7;
memcpy(boot_pub_key_digest, efuse_blk2_digest, ESP_SECURE_BOOT_DIGEST_LEN);
ESP_LOGW(TAG, "Using pre-loaded secure boot v2 public key digest in EFUSE block 2");
}
if (efuse_key_write_protected == false) {
ESP_LOGI(TAG, "Write protecting public key digest...");
ret = esp_efuse_set_write_protect(EFUSE_BLK2);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Write protecting public key digest...failed.");
return ret;
}
efuse_key_write_protected = true;
}
uint8_t app_pub_key_digest[ESP_SECURE_BOOT_DIGEST_LEN];
ret = secure_boot_v2_digest_generate(image_data->start_addr, image_data->image_len - SIG_BLOCK_PADDING, app_pub_key_digest);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Application signature block is invalid.");
return ret;
}
/* Confirming if the public key in the bootloader's signature block matches with the one in the application's signature block */
if (memcmp(boot_pub_key_digest, app_pub_key_digest, ESP_SECURE_BOOT_DIGEST_LEN) != 0) {
ESP_LOGE(TAG, "Application not signed with a valid private key.");
return ESP_FAIL;
}
if (efuse_key_read_protected) {
ESP_LOGE(TAG, "Efuse BLK2 (public key digest) is read protected. Refusing to blow secure boot efuse.");
return ESP_ERR_INVALID_STATE;
}
if (!efuse_key_write_protected) {
ESP_LOGE(TAG, "Efuse BLK2 (public key digest) is not write protected. Refusing to blow secure boot efuse.");
return ESP_ERR_INVALID_STATE;
}
ESP_LOGI(TAG, "blowing secure boot efuse...");
ESP_LOGD(TAG, "before updating, EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG));
ret = esp_efuse_write_field_bit(ESP_EFUSE_ABS_DONE_1);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Blowing secure boot efuse...failed.");
return ret;
}
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable JTAG...");
ret = esp_efuse_write_field_bit(ESP_EFUSE_DISABLE_JTAG);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Disable JTAG...failed.");
return ret;
}
#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...");
ret = esp_efuse_write_field_bit(ESP_EFUSE_CONSOLE_DEBUG_DISABLE);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Disable ROM BASIC interpreter fallback...failed.");
return ret;
}
#else
ESP_LOGW(TAG, "Not disabling ROM BASIC fallback - SECURITY COMPROMISED");
#endif
#ifdef CONFIG_SECURE_DISABLE_ROM_DL_MODE
ESP_LOGI(TAG, "Disable ROM Download mode...");
ret = esp_efuse_disable_rom_download_mode();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Could not disable ROM Download mode...");
return ESP_FAIL;
}
#else
ESP_LOGW(TAG, "Not disabling ROM Download mode - 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...");
ret = esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_EFUSE_RD_DISABLE);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Prevent read disabling of additional efuses...failed.");
return ret;
}
}
#else
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
#endif
ret = esp_efuse_batch_write_commit();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Error programming security eFuses.");
return ret;
}
uint32_t after = REG_READ(EFUSE_BLK0_RDATA6_REG);
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;
} else {
ESP_LOGE(TAG, " secure boot v2 not enabled, EFUSE_RD_ABS_DONE_1 is probably write protected!");
return ESP_ERR_INVALID_STATE;
}
}
#endif // CONFIG_SECURE_BOOT_V2_ENABLED

View File

@@ -0,0 +1,107 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <strings.h>
#include "esp_flash_encrypt.h"
#include "esp_secure_boot.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp_log.h"
#include "sdkconfig.h"
static __attribute__((unused)) const char *TAG = "secure_boot";
esp_err_t esp_secure_boot_enable_secure_features(void)
{
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
ESP_LOGI(TAG, "Read & write protecting new key...");
esp_efuse_write_field_bit(ESP_EFUSE_RD_DIS_BLK2);
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_BLK2);
esp_efuse_write_field_bit(ESP_EFUSE_ABS_DONE_0);
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable JTAG...");
esp_efuse_write_field_bit(ESP_EFUSE_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...");
esp_efuse_write_field_bit(ESP_EFUSE_CONSOLE_DEBUG_DISABLE);
#else
ESP_LOGW(TAG, "Not disabling ROM BASIC fallback - SECURITY COMPROMISED");
#endif
#endif // CONFIG_SECURE_BOOT_V1_ENABLED
#ifdef CONFIG_SECURE_BOOT_V2_ENABLED
esp_err_t err;
err = esp_efuse_write_field_bit(ESP_EFUSE_ABS_DONE_1);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Blowing secure boot efuse...failed.");
return err;
}
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable JTAG...");
err = esp_efuse_write_field_bit(ESP_EFUSE_DISABLE_JTAG);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Disable JTAG...failed.");
return err;
}
#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...");
err = esp_efuse_write_field_bit(ESP_EFUSE_CONSOLE_DEBUG_DISABLE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Disable ROM BASIC interpreter fallback...failed.");
return err;
}
#else
ESP_LOGW(TAG, "Not disabling ROM BASIC fallback - SECURITY COMPROMISED");
#endif
#ifdef CONFIG_SECURE_DISABLE_ROM_DL_MODE
ESP_LOGI(TAG, "Disable ROM Download mode...");
err = esp_efuse_disable_rom_download_mode();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Could not disable ROM Download mode...");
return err;
}
#else
ESP_LOGW(TAG, "Not disabling ROM Download mode - 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...");
err = esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_EFUSE_RD_DISABLE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Prevent read disabling of additional efuses...failed.");
return err;
}
}
#else
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
#endif
#endif // CONFIG_SECURE_BOOT_V2_ENABLED
return ESP_OK;
}

View File

@@ -37,6 +37,7 @@
#include "regi2c_ctrl.h"
#include "bootloader_console.h"
#include "bootloader_flash_priv.h"
#include "esp_efuse.h"
static const char *TAG = "boot.esp32c3";
@@ -294,6 +295,13 @@ esp_err_t bootloader_init(void)
assert(&_data_start <= &_data_end);
// clear bss section
bootloader_clear_bss_section();
// init eFuse virtual mode (read eFuses to RAM)
#ifdef CONFIG_EFUSE_VIRTUAL
ESP_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
esp_efuse_init_virtual_mode_in_ram();
#endif
#endif
// reset MMU
bootloader_reset_mmu();
// config clock

View File

@@ -0,0 +1,44 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <strings.h>
#include "esp_flash_encrypt.h"
#include "esp_secure_boot.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp_log.h"
#include "sdkconfig.h"
static __attribute__((unused)) const char *TAG = "flash_encrypt";
esp_err_t esp_flash_encryption_enable_secure_features(void)
{
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
#else
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
#endif
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
ESP_LOGI(TAG, "Disable UART bootloader cache...");
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE);
#else
ESP_LOGW(TAG, "Not disabling UART bootloader cache - SECURITY COMPROMISED");
#endif
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable JTAG...");
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
#else
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
#endif
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
return ESP_OK;
}

View File

@@ -1,289 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_log.h"
#include "esp_secure_boot.h"
#include "soc/efuse_reg.h"
#include "bootloader_flash_priv.h"
#include "bootloader_sha.h"
#include "bootloader_utility.h"
#include "esp_rom_crc.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp32c3/rom/efuse.h"
#include "esp32c3/rom/secure_boot.h"
static const char *TAG = "secure_boot_v2";
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
/* A signature block is valid when it has correct magic byte, crc and image digest. */
static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *block, int block_num, const uint8_t *image_digest)
{
uint32_t crc = esp_rom_crc32_le(0, (uint8_t *)block, CRC_SIGN_BLOCK_LEN);
if (block->magic_byte != ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC) {
// All signature blocks have been parsed, no new signature block present.
ESP_LOGD(TAG, "Signature block(%d) invalid/absent.", block_num);
return ESP_FAIL;
}
if (block->block_crc != crc) {
ESP_LOGE(TAG, "Magic byte correct but incorrect crc.");
return ESP_FAIL;
}
if (memcmp(image_digest, block->image_digest, ESP_SECURE_BOOT_DIGEST_LEN)) {
ESP_LOGE(TAG, "Magic byte & CRC correct but incorrect image digest.");
return ESP_FAIL;
} else {
ESP_LOGD(TAG, "valid signature block(%d) found", block_num);
return ESP_OK;
}
return ESP_FAIL;
}
/* Generates the public key digests of the valid public keys in an image's
signature block, verifies each signature, and stores the key digests in the
public_key_digests structure.
@param flash_offset Image offset in flash
@param flash_size Image size in flash (not including signature block)
@param[out] public_key_digests Pointer to structure to hold the key digests for valid sig blocks
Note that this function doesn't read any eFuses, so it doesn't know if the
keys are ultimately trusted by the hardware or not
@return - ESP_OK if no signatures failed to verify, or if no valid signature blocks are found at all.
- ESP_FAIL if there's a valid signature block that doesn't verify using the included public key (unexpected!)
*/
static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uint32_t flash_size, esp_image_sig_public_key_digests_t *public_key_digests)
{
esp_err_t ret;
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
uint8_t __attribute__((aligned(4))) key_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
size_t sig_block_addr = flash_offset + ALIGN_UP(flash_size, FLASH_SECTOR_SIZE);
ESP_LOGD(TAG, "calculating public key digests for sig blocks of image offset 0x%x (sig block offset 0x%x)", flash_offset, sig_block_addr);
bzero(public_key_digests, sizeof(esp_image_sig_public_key_digests_t));
ret = bootloader_sha256_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "error generating image digest, %d", ret);
return ret;
}
ESP_LOGD(TAG, "reading signatures");
const ets_secure_boot_signature_t *signatures = bootloader_mmap(sig_block_addr, sizeof(ets_secure_boot_signature_t));
if (signatures == NULL) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", sig_block_addr, sizeof(ets_secure_boot_signature_t));
return ESP_FAIL;
}
for (int i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
const ets_secure_boot_sig_block_t *block = &signatures->block[i];
ret = validate_signature_block(block, i, image_digest);
if (ret != ESP_OK) {
ret = ESP_OK; // past the last valid signature block
break;
}
/* Generating the SHA of the public key components in the signature block */
bootloader_sha256_handle_t sig_block_sha;
sig_block_sha = bootloader_sha256_start();
bootloader_sha256_data(sig_block_sha, &block->key, sizeof(block->key));
bootloader_sha256_finish(sig_block_sha, key_digest);
// Check we can verify the image using this signature and this key
uint8_t temp_verified_digest[ESP_SECURE_BOOT_DIGEST_LEN];
bool verified = ets_rsa_pss_verify(&block->key, block->signature, image_digest, temp_verified_digest);
if (!verified) {
/* We don't expect this: the signature blocks before we enable secure boot should all be verifiable or invalid,
so this is a fatal error
*/
ret = ESP_FAIL;
ESP_LOGE(TAG, "Secure boot key (%d) verification failed.", i);
break;
}
ESP_LOGD(TAG, "Signature block (%d) is verified", i);
/* Copy the key digest to the buffer provided by the caller */
memcpy((void *)public_key_digests->key_digests[i], key_digest, ESP_SECURE_BOOT_DIGEST_LEN);
public_key_digests->num_digests++;
}
if (ret == ESP_OK && public_key_digests->num_digests > 0) {
ESP_LOGI(TAG, "Digests successfully calculated, %d valid signatures (image offset 0x%x)",
public_key_digests->num_digests, flash_offset);
}
bootloader_munmap(signatures);
return ret;
}
static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t *image_data)
{
esp_err_t ret;
/* Verify the bootloader */
esp_image_metadata_t bootloader_data = { 0 };
ret = esp_image_verify_bootloader_data(&bootloader_data);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "bootloader image appears invalid! error %d", ret);
return ret;
}
/* Check if secure boot digests are present */
bool has_secure_boot_digest = esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0, NULL);
has_secure_boot_digest |= esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1, NULL);
has_secure_boot_digest |= esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2, NULL);
ESP_LOGI(TAG, "Secure boot digests %s", has_secure_boot_digest ? "already present":"absent, generating..");
if (!has_secure_boot_digest) {
esp_image_sig_public_key_digests_t boot_key_digests = {0};
esp_image_sig_public_key_digests_t app_key_digests = {0};
/* Generate the bootloader public key digests */
ret = s_calculate_image_public_key_digests(bootloader_data.start_addr, bootloader_data.image_len - SIG_BLOCK_PADDING, &boot_key_digests);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Bootloader signature block is invalid");
return ret;
}
if (boot_key_digests.num_digests == 0) {
ESP_LOGE(TAG, "No valid bootloader signature blocks found.");
return ESP_FAIL;
}
ESP_LOGI(TAG, "%d signature block(s) found appended to the bootloader.", boot_key_digests.num_digests);
esp_efuse_purpose_t secure_boot_key_purpose[SECURE_BOOT_NUM_BLOCKS] = {
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0,
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1,
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2,
};
ret = esp_efuse_write_keys(secure_boot_key_purpose, boot_key_digests.key_digests, boot_key_digests.num_digests);
if (ret) {
if (ret == ESP_ERR_NOT_ENOUGH_UNUSED_KEY_BLOCKS) {
ESP_LOGE(TAG, "Bootloader signatures(%d) more than available key slots.", boot_key_digests.num_digests);
} else {
ESP_LOGE(TAG, "Failed to write efuse block with purpose (err=0x%x). Can't continue.", ret);
}
return ret;
}
/* Generate the application public key digests */
ret = s_calculate_image_public_key_digests(image_data->start_addr, image_data->image_len - SIG_BLOCK_PADDING, &app_key_digests);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "App signature block is invalid.");
return ret;
}
if (app_key_digests.num_digests == 0) {
ESP_LOGE(TAG, "No valid applications signature blocks found.");
return ESP_FAIL;
}
ESP_LOGI(TAG, "%d signature block(s) found appended to the app.", app_key_digests.num_digests);
if (app_key_digests.num_digests > boot_key_digests.num_digests) {
ESP_LOGW(TAG, "App has %d signature blocks but bootloader only has %d. Some keys missing from bootloader?");
}
/* Confirm if at least one public key from the application matches a public key in the bootloader
(Also, ensure if that public revoke bit is not set for the matched key) */
bool match = false;
for (int i = 0; i < boot_key_digests.num_digests; i++) {
if (esp_efuse_get_digest_revoke(i)) {
ESP_LOGI(TAG, "Key block(%d) has been revoked.", i);
continue; // skip if the key block is revoked
}
for (int j = 0; j < app_key_digests.num_digests; j++) {
if (!memcmp(boot_key_digests.key_digests[i], app_key_digests.key_digests[j], ESP_SECURE_BOOT_DIGEST_LEN)) {
ESP_LOGI(TAG, "Application key(%d) matches with bootloader key(%d).", j, i);
match = true;
}
}
}
if (match == false) {
ESP_LOGE(TAG, "No application key digest matches the bootloader key digest.");
return ESP_FAIL;
}
/* Revoke the empty signature blocks */
if (boot_key_digests.num_digests < SECURE_BOOT_NUM_BLOCKS) {
/* The revocation index can be 0, 1, 2. Bootloader count can be 1,2,3. */
for (uint8_t i = boot_key_digests.num_digests; i < SECURE_BOOT_NUM_BLOCKS; i++) {
ESP_LOGI(TAG, "Revoking empty key digest slot (%d)...", i);
esp_efuse_set_digest_revoke(i);
}
}
}
return ESP_OK;
}
esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *image_data)
{
ESP_LOGI(TAG, "enabling secure boot v2...");
if (esp_secure_boot_enabled()) {
ESP_LOGI(TAG, "secure boot v2 is already enabled, continuing..");
return ESP_OK;
}
esp_efuse_batch_write_begin(); /* Batch all efuse writes at the end of this function */
esp_err_t key_state = check_and_generate_secure_boot_keys(image_data);
if (key_state != ESP_OK) {
esp_efuse_batch_write_cancel();
return key_state;
}
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
ESP_LOGI(TAG, "Enabling Security download mode...");
esp_efuse_write_field_bit(ESP_EFUSE_ENABLE_SECURITY_DOWNLOAD);
#else
ESP_LOGW(TAG, "Not enabling Security download mode - SECURITY COMPROMISED");
#endif
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
esp_efuse_write_field_bit(ESP_EFUSE_SOFT_DIS_JTAG);
#else
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
#endif
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
#endif
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
esp_err_t err = esp_efuse_batch_write_commit();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error programming security eFuses (err=0x%x).", err);
return err;
}
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
assert(ets_efuse_secure_boot_aggressive_revoke_enabled());
#endif
assert(esp_rom_efuse_is_secure_boot_enabled());
ESP_LOGI(TAG, "Secure boot permanently enabled");
return ESP_OK;
}

View File

@@ -0,0 +1,44 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <strings.h>
#include "esp_flash_encrypt.h"
#include "esp_secure_boot.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp_log.h"
#include "sdkconfig.h"
static __attribute__((unused)) const char *TAG = "secure_boot";
esp_err_t esp_secure_boot_enable_secure_features(void)
{
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
ESP_LOGI(TAG, "Enabling Security download mode...");
esp_efuse_write_field_bit(ESP_EFUSE_ENABLE_SECURITY_DOWNLOAD);
#else
ESP_LOGW(TAG, "Not enabling Security download mode - SECURITY COMPROMISED");
#endif
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
esp_efuse_write_field_bit(ESP_EFUSE_SOFT_DIS_JTAG);
#else
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
#endif
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
#endif
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
return ESP_OK;
}

View File

@@ -36,6 +36,7 @@
#include "soc/rtc.h"
#include "soc/spi_periph.h"
#include <string.h>
#include "esp_efuse.h"
static const char *TAG = "boot.esp32s2";
void IRAM_ATTR bootloader_configure_spi_pins(int drv)
@@ -292,6 +293,13 @@ esp_err_t bootloader_init(void)
#endif
// clear bss section
bootloader_clear_bss_section();
// init eFuse virtual mode (read eFuses to RAM)
#ifdef CONFIG_EFUSE_VIRTUAL
ESP_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
esp_efuse_init_virtual_mode_in_ram();
#endif
#endif
// reset MMU
bootloader_reset_mmu();
// config clock

View File

@@ -1,370 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-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 "bootloader_utility.h"
#include "esp_image_format.h"
#include "esp_flash_encrypt.h"
#include "esp_flash_partitions.h"
#include "esp_secure_boot.h"
#include "esp_log.h"
#include "esp32s2/rom/secure_boot.h"
#include "esp32s2/rom/cache.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "hal/wdt_hal.h"
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_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions);
static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition);
esp_err_t esp_flash_encrypt_check_and_update(void)
{
uint8_t flash_crypt_wr_dis = 0;
uint32_t flash_crypt_cnt = 0;
esp_efuse_read_field_blob(ESP_EFUSE_SPI_BOOT_CRYPT_CNT, &flash_crypt_cnt, 3);
esp_efuse_read_field_blob(ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT, &flash_crypt_wr_dis, 1);
ESP_LOGV(TAG, "SPI_BOOT_CRYPT_CNT 0x%x", flash_crypt_cnt);
ESP_LOGV(TAG, "EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT 0x%x", flash_crypt_wr_dis);
_Static_assert(EFUSE_SPI_BOOT_CRYPT_CNT == 0x7, "assuming CRYPT_CNT is only 3 bits wide");
if (__builtin_parity(flash_crypt_cnt) == 1) {
/* Flash is already encrypted */
int left = (flash_crypt_cnt == 1) ? 1 : 0;
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)
{
esp_efuse_block_t aes_128_key_block;
esp_efuse_block_t aes_256_key_block_1;
esp_efuse_block_t aes_256_key_block_2;
bool has_aes128 = esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY, &aes_128_key_block);
bool has_aes256_1 = esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1, &aes_256_key_block_1);
bool has_aes256_2 = esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2, &aes_256_key_block_2);
bool has_key = has_aes128 || (has_aes256_1 && has_aes256_2);
bool dis_write = false;
bool dis_read = false;
// If there are keys set, they must be write and read protected!
if(has_key && has_aes128) {
dis_write = esp_efuse_get_key_dis_write(aes_128_key_block);
dis_read = esp_efuse_get_key_dis_read(aes_128_key_block);
} else if (has_key && has_aes256_1 && has_aes256_2) {
dis_write = esp_efuse_get_key_dis_write(aes_256_key_block_1) && esp_efuse_get_key_dis_write(aes_256_key_block_2);
dis_read = esp_efuse_get_key_dis_read(aes_256_key_block_1) && esp_efuse_get_key_dis_read(aes_256_key_block_2);
}
if (!has_key && (has_aes256_1 || has_aes256_2)) {
ESP_LOGE(TAG, "Invalid efuse key blocks: Both AES-256 key blocks must be set.");
return ESP_ERR_INVALID_STATE;
}
if(has_key && (!dis_read || !dis_write)) {
ESP_LOGE(TAG, "Invalid key state, a key was set but not read and write protected.");
return ESP_ERR_INVALID_STATE;
}
if(!has_key && !dis_write && !dis_read) {
ESP_LOGI(TAG, "Generating new flash encryption key...");
#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,
};
#else
enum { BLOCKS_NEEDED = 1 };
esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = {
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY,
};
#endif
uint8_t keys[BLOCKS_NEEDED][32] = { 0 };
for (int i = 0; i < BLOCKS_NEEDED; ++i) {
bootloader_fill_random(keys[i], 32);
}
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;
}
ESP_LOGD(TAG, "Key generation complete");
return ESP_OK;
} else {
ESP_LOGI(TAG, "Using pre-existing 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 */
esp_err_t key_state = check_and_generate_encryption_keys();
if (key_state != ESP_OK) {
esp_efuse_batch_write_cancel();
return key_state;
}
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
#else
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
#endif
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
ESP_LOGI(TAG, "Disable UART bootloader cache...");
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_DCACHE);
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE);
#else
ESP_LOGW(TAG, "Not disabling UART bootloader cache - SECURITY COMPROMISED");
#endif
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable JTAG...");
esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
#else
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
#endif
esp_efuse_write_field_bit(ESP_EFUSE_DIS_BOOT_REMAP);
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
esp_err_t err = esp_efuse_batch_write_commit();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error programming security eFuses (err=0x%x).", err);
}
return err;
}
/* Encrypt all flash data that should be encrypted */
static esp_err_t encrypt_flash_contents(uint32_t spi_boot_crypt_cnt, bool flash_crypt_wr_dis)
{
esp_err_t err;
esp_partition_info_t partition_table[ESP_PARTITION_TABLE_MAX_ENTRIES];
int num_partitions;
/* If the last spi_boot_crypt_cnt bit is burned or write-disabled, the
device can't re-encrypt itself. */
if (flash_crypt_wr_dis || spi_boot_crypt_cnt == EFUSE_SPI_BOOT_CRYPT_CNT) {
ESP_LOGE(TAG, "Cannot re-encrypt data SPI_BOOT_CRYPT_CNT 0x%02x write disabled %d", spi_boot_crypt_cnt, flash_crypt_wr_dis);
return ESP_FAIL;
}
if (spi_boot_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;
}
err = encrypt_and_load_partition_table(partition_table, &num_partitions);
if (err != ESP_OK) {
return err;
}
/* Now iterate the just-loaded partition table, looking for entries to encrypt */
for (int i = 0; i < num_partitions; i++) {
err = encrypt_partition(i, &partition_table[i]);
if (err != ESP_OK) {
return err;
}
}
ESP_LOGD(TAG, "All flash regions checked for encryption pass");
/* Set least significant 0-bit in spi_boot_crypt_cnt */
int ffs_inv = __builtin_ffs((~spi_boot_crypt_cnt) & 0x7);
/* ffs_inv shouldn't be zero, as zero implies spi_boot_crypt_cnt == 0xFF */
uint32_t new_spi_boot_crypt_cnt = (1 << (ffs_inv - 1));
ESP_LOGD(TAG, "SPI_BOOT_CRYPT_CNT 0x%x -> 0x%x", spi_boot_crypt_cnt, new_spi_boot_crypt_cnt + spi_boot_crypt_cnt);
esp_efuse_write_field_blob(ESP_EFUSE_SPI_BOOT_CRYPT_CNT, &new_spi_boot_crypt_cnt, 3);
#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
//Secure SPI boot cnt after its update if needed.
const uint32_t spi_boot_cnt_wr_dis = 1;
ESP_LOGI(TAG, "Write protecting SPI_CRYPT_CNT eFuse");
esp_efuse_write_field_blob(ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT, &spi_boot_cnt_wr_dis, 1);
#endif
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_LOGD(TAG, "bootloader is plaintext. Encrypting...");
#if CONFIG_SECURE_BOOT_V2_ENABLED
/* The image length obtained from esp_image_verify_bootloader includes the sector boundary padding and the signature block lengths */
if (ESP_BOOTLOADER_OFFSET + image_length > ESP_PARTITION_TABLE_OFFSET) {
ESP_LOGE(TAG, "Bootloader is too large to fit Secure Boot V2 signature sector and partition table (configured offset 0x%x)", ESP_PARTITION_TABLE_OFFSET);
return ESP_ERR_INVALID_SIZE;
}
#endif // CONFIG_SECURE_BOOT_V2_ENABLED
err = esp_flash_encrypt_region(ESP_BOOTLOADER_OFFSET, image_length);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt bootloader in place: 0x%x", err);
return err;
}
ESP_LOGI(TAG, "bootloader encrypted successfully");
return err;
}
else {
ESP_LOGW(TAG, "no valid bootloader was found");
return ESP_ERR_NOT_FOUND;
}
}
static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions)
{
esp_err_t err;
/* Check for plaintext partition table */
err = bootloader_flash_read(ESP_PARTITION_TABLE_OFFSET, partition_table, ESP_PARTITION_TABLE_MAX_LEN, false);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to read partition table data");
return err;
}
if (esp_partition_table_verify(partition_table, false, num_partitions) == ESP_OK) {
ESP_LOGD(TAG, "partition table is plaintext. Encrypting...");
esp_err_t err = esp_flash_encrypt_region(ESP_PARTITION_TABLE_OFFSET,
FLASH_SECTOR_SIZE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt partition table in place. %x", err);
return err;
}
}
else {
ESP_LOGE(TAG, "Failed to read partition table data - not plaintext?");
return ESP_ERR_INVALID_STATE;
}
/* Valid partition table loded */
ESP_LOGI(TAG, "partition table encrypted and loaded successfully");
return ESP_OK;
}
static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition)
{
esp_err_t err;
bool should_encrypt = (partition->flags & PART_FLAG_ENCRYPTED);
if (partition->type == PART_TYPE_APP) {
/* check if the partition holds a valid unencrypted app */
esp_image_metadata_t data_ignored;
err = esp_image_verify(ESP_IMAGE_VERIFY,
&partition->pos,
&data_ignored);
should_encrypt = (err == ESP_OK);
} else if (partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_OTA) {
/* check if we have ota data partition and the partition should be encrypted unconditionally */
should_encrypt = true;
}
if (!should_encrypt) {
return ESP_OK;
}
else {
/* should_encrypt */
ESP_LOGI(TAG, "Encrypting partition %d at offset 0x%x (length 0x%x)...", index, partition->pos.offset, partition->pos.size);
err = esp_flash_encrypt_region(partition->pos.offset, partition->pos.size);
ESP_LOGI(TAG, "Done encrypting");
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt partition %d", index);
}
return err;
}
}
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, false);
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;
}

View File

@@ -0,0 +1,45 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <strings.h>
#include "esp_flash_encrypt.h"
#include "esp_secure_boot.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp_log.h"
#include "sdkconfig.h"
static __attribute__((unused)) const char *TAG = "flash_encrypt";
esp_err_t esp_flash_encryption_enable_secure_features(void)
{
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
#else
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
#endif
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
ESP_LOGI(TAG, "Disable UART bootloader cache...");
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_DCACHE);
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE);
#else
ESP_LOGW(TAG, "Not disabling UART bootloader cache - SECURITY COMPROMISED");
#endif
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable JTAG...");
esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
#else
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
#endif
esp_efuse_write_field_bit(ESP_EFUSE_DIS_BOOT_REMAP);
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
return ESP_OK;
}

View File

@@ -0,0 +1,44 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <strings.h>
#include "esp_flash_encrypt.h"
#include "esp_secure_boot.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp_log.h"
#include "sdkconfig.h"
static __attribute__((unused)) const char *TAG = "secure_boot";
esp_err_t esp_secure_boot_enable_secure_features(void)
{
esp_efuse_write_field_bit(ESP_EFUSE_DIS_BOOT_REMAP);
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
ESP_LOGI(TAG, "Enabling Security download mode...");
esp_efuse_write_field_bit(ESP_EFUSE_ENABLE_SECURITY_DOWNLOAD);
#else
ESP_LOGW(TAG, "Not enabling Security download mode - SECURITY COMPROMISED");
#endif
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
esp_efuse_write_field_bit(ESP_EFUSE_SOFT_DIS_JTAG);
#else
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
#endif
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
#endif
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
return ESP_OK;
}

View File

@@ -34,6 +34,7 @@
#include "bootloader_mem.h"
#include "bootloader_console.h"
#include "bootloader_flash_priv.h"
#include "esp_efuse.h"
static const char *TAG = "boot.esp32s3";
@@ -302,6 +303,13 @@ esp_err_t bootloader_init(void)
#endif
// clear bss section
bootloader_clear_bss_section();
// init eFuse virtual mode (read eFuses to RAM)
#ifdef CONFIG_EFUSE_VIRTUAL
ESP_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
esp_efuse_init_virtual_mode_in_ram();
#endif
#endif
// reset MMU
bootloader_reset_mmu();
// config clock

View File

@@ -1,368 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-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 "bootloader_utility.h"
#include "esp_image_format.h"
#include "esp_flash_encrypt.h"
#include "esp_flash_partitions.h"
#include "esp_secure_boot.h"
#include "esp_log.h"
#include "esp32s3/rom/secure_boot.h"
#include "esp32s3/rom/cache.h"
#include "esp32s3/rom/efuse.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "hal/wdt_hal.h"
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_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions);
static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition);
esp_err_t esp_flash_encrypt_check_and_update(void)
{
uint8_t flash_crypt_wr_dis = 0;
uint32_t flash_crypt_cnt = 0;
esp_efuse_read_field_blob(ESP_EFUSE_SPI_BOOT_CRYPT_CNT, &flash_crypt_cnt, 3);
esp_efuse_read_field_blob(ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT, &flash_crypt_wr_dis, 1);
ESP_LOGV(TAG, "SPI_BOOT_CRYPT_CNT 0x%x", flash_crypt_cnt);
ESP_LOGV(TAG, "EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT 0x%x", flash_crypt_wr_dis);
if (__builtin_parity(flash_crypt_cnt) == 1) {
/* Flash is already encrypted */
int left = (flash_crypt_cnt == 1) ? 1 : 0;
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)
{
esp_efuse_block_t aes_128_key_block;
esp_efuse_block_t aes_256_key_block_1;
esp_efuse_block_t aes_256_key_block_2;
bool has_aes128 = esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY, &aes_128_key_block);
bool has_aes256_1 = esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1, &aes_256_key_block_1);
bool has_aes256_2 = esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2, &aes_256_key_block_2);
bool has_key = has_aes128 || (has_aes256_1 && has_aes256_2);
bool dis_write = false;
bool dis_read = false;
// If there are keys set, they must be write and read protected!
if(has_key && has_aes128) {
dis_write = esp_efuse_get_key_dis_write(aes_128_key_block);
dis_read = esp_efuse_get_key_dis_read(aes_128_key_block);
} else if (has_key && has_aes256_1 && has_aes256_2) {
dis_write = esp_efuse_get_key_dis_write(aes_256_key_block_1) && esp_efuse_get_key_dis_write(aes_256_key_block_2);
dis_read = esp_efuse_get_key_dis_read(aes_256_key_block_1) && esp_efuse_get_key_dis_read(aes_256_key_block_2);
}
if (!has_key && (has_aes256_1 || has_aes256_2)) {
ESP_LOGE(TAG, "Invalid efuse key blocks: Both AES-256 key blocks must be set.");
return ESP_ERR_INVALID_STATE;
}
if(has_key && (!dis_read || !dis_write)) {
ESP_LOGE(TAG, "Invalid key state, a key was set but not read and write protected.");
return ESP_ERR_INVALID_STATE;
}
if(!has_key && !dis_write && !dis_read) {
ESP_LOGI(TAG, "Generating new flash encryption key...");
#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,
};
#else
enum { BLOCKS_NEEDED = 1 };
esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = {
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY,
};
#endif
uint8_t keys[BLOCKS_NEEDED][32] = { 0 };
for (int i = 0; i < BLOCKS_NEEDED; ++i) {
bootloader_fill_random(keys[i], 32);
}
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;
}
ESP_LOGD(TAG, "Key generation complete");
return ESP_OK;
} else {
ESP_LOGI(TAG, "Using pre-existing 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 */
esp_err_t key_state = check_and_generate_encryption_keys();
if (key_state != ESP_OK) {
esp_efuse_batch_write_cancel();
return key_state;
}
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
#else
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
#endif
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
ESP_LOGI(TAG, "Disable UART bootloader cache...");
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_DCACHE);
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE);
#else
ESP_LOGW(TAG, "Not disabling UART bootloader cache - SECURITY COMPROMISED");
#endif
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable JTAG...");
esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
#else
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
#endif
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
esp_err_t err = esp_efuse_batch_write_commit();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error programming security eFuses (err=0x%x).", err);
}
return err;
}
/* Encrypt all flash data that should be encrypted */
static esp_err_t encrypt_flash_contents(uint32_t spi_boot_crypt_cnt, bool flash_crypt_wr_dis)
{
esp_err_t err;
esp_partition_info_t partition_table[ESP_PARTITION_TABLE_MAX_ENTRIES];
int num_partitions;
/* If the last spi_boot_crypt_cnt bit is burned or write-disabled, the
device can't re-encrypt itself. */
if (flash_crypt_wr_dis) {
ESP_LOGE(TAG, "Cannot re-encrypt data SPI_BOOT_CRYPT_CNT 0x%02x write disabled %d", spi_boot_crypt_cnt, flash_crypt_wr_dis);
return ESP_FAIL;
}
if (spi_boot_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;
}
err = encrypt_and_load_partition_table(partition_table, &num_partitions);
if (err != ESP_OK) {
return err;
}
/* Now iterate the just-loaded partition table, looking for entries to encrypt */
for (int i = 0; i < num_partitions; i++) {
err = encrypt_partition(i, &partition_table[i]);
if (err != ESP_OK) {
return err;
}
}
ESP_LOGD(TAG, "All flash regions checked for encryption pass");
/* Set least significant 0-bit in spi_boot_crypt_cnt */
int ffs_inv = __builtin_ffs((~spi_boot_crypt_cnt) & 0x7);
/* ffs_inv shouldn't be zero, as zero implies spi_boot_crypt_cnt == 0xFF */
uint32_t new_spi_boot_crypt_cnt = (1 << (ffs_inv - 1));
ESP_LOGD(TAG, "SPI_BOOT_CRYPT_CNT 0x%x -> 0x%x", spi_boot_crypt_cnt, new_spi_boot_crypt_cnt + spi_boot_crypt_cnt);
esp_efuse_write_field_blob(ESP_EFUSE_SPI_BOOT_CRYPT_CNT, &new_spi_boot_crypt_cnt, 3);
#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
//Secure SPI boot cnt after its update if needed.
const uint32_t spi_boot_cnt_wr_dis = 1;
ESP_LOGI(TAG, "Write protecting SPI_CRYPT_CNT eFuse");
esp_efuse_write_field_blob(ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT, &spi_boot_cnt_wr_dis, 1);
#endif
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_LOGD(TAG, "bootloader is plaintext. Encrypting...");
#if CONFIG_SECURE_BOOT_V2_ENABLED
/* The image length obtained from esp_image_verify_bootloader includes the sector boundary padding and the signature block lengths */
if (ESP_BOOTLOADER_OFFSET + image_length > ESP_PARTITION_TABLE_OFFSET) {
ESP_LOGE(TAG, "Bootloader is too large to fit Secure Boot V2 signature sector and partition table (configured offset 0x%x)", ESP_PARTITION_TABLE_OFFSET);
return ESP_ERR_INVALID_SIZE;
}
#endif // CONFIG_SECURE_BOOT_V2_ENABLED
err = esp_flash_encrypt_region(ESP_BOOTLOADER_OFFSET, image_length);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt bootloader in place: 0x%x", err);
return err;
}
ESP_LOGI(TAG, "bootloader encrypted successfully");
return err;
}
else {
ESP_LOGW(TAG, "no valid bootloader was found");
return ESP_ERR_NOT_FOUND;
}
}
static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions)
{
esp_err_t err;
/* Check for plaintext partition table */
err = bootloader_flash_read(ESP_PARTITION_TABLE_OFFSET, partition_table, ESP_PARTITION_TABLE_MAX_LEN, false);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to read partition table data");
return err;
}
if (esp_partition_table_verify(partition_table, false, num_partitions) == ESP_OK) {
ESP_LOGD(TAG, "partition table is plaintext. Encrypting...");
esp_err_t err = esp_flash_encrypt_region(ESP_PARTITION_TABLE_OFFSET,
FLASH_SECTOR_SIZE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt partition table in place. %x", err);
return err;
}
}
else {
ESP_LOGE(TAG, "Failed to read partition table data - not plaintext?");
return ESP_ERR_INVALID_STATE;
}
/* Valid partition table loded */
ESP_LOGI(TAG, "partition table encrypted and loaded successfully");
return ESP_OK;
}
static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition)
{
esp_err_t err;
bool should_encrypt = (partition->flags & PART_FLAG_ENCRYPTED);
if (partition->type == PART_TYPE_APP) {
/* check if the partition holds a valid unencrypted app */
esp_image_metadata_t data_ignored;
err = esp_image_verify(ESP_IMAGE_VERIFY,
&partition->pos,
&data_ignored);
should_encrypt = (err == ESP_OK);
} else if (partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_OTA) {
/* check if we have ota data partition and the partition should be encrypted unconditionally */
should_encrypt = true;
}
if (!should_encrypt) {
return ESP_OK;
}
else {
/* should_encrypt */
ESP_LOGI(TAG, "Encrypting partition %d at offset 0x%x (length 0x%x)...", index, partition->pos.offset, partition->pos.size);
err = esp_flash_encrypt_region(partition->pos.offset, partition->pos.size);
ESP_LOGI(TAG, "Done encrypting");
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt partition %d", index);
}
return err;
}
}
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, false);
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;
}

View File

@@ -0,0 +1,44 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <strings.h>
#include "esp_flash_encrypt.h"
#include "esp_secure_boot.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp_log.h"
#include "sdkconfig.h"
static __attribute__((unused)) const char *TAG = "flash_encrypt";
esp_err_t esp_flash_encryption_enable_secure_features(void)
{
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
#else
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
#endif
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
ESP_LOGI(TAG, "Disable UART bootloader cache...");
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_DCACHE);
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE);
#else
ESP_LOGW(TAG, "Not disabling UART bootloader cache - SECURITY COMPROMISED");
#endif
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable JTAG...");
esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
#else
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
#endif
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
return ESP_OK;
}

View File

@@ -1,290 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_log.h"
#include "esp_secure_boot.h"
#include "soc/efuse_reg.h"
#include "bootloader_flash_priv.h"
#include "bootloader_sha.h"
#include "bootloader_utility.h"
#include "esp_rom_crc.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp32s3/rom/efuse.h"
#include "esp32s3/rom/secure_boot.h"
static const char *TAG = "secure_boot_v2";
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
/* A signature block is valid when it has correct magic byte, crc and image digest. */
static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *block, int block_num, const uint8_t *image_digest)
{
uint32_t crc = esp_rom_crc32_le(0, (uint8_t *)block, CRC_SIGN_BLOCK_LEN);
if (block->magic_byte != ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC) {
// All signature blocks have been parsed, no new signature block present.
ESP_LOGD(TAG, "Signature block(%d) invalid/absent.", block_num);
return ESP_FAIL;
}
if (block->block_crc != crc) {
ESP_LOGE(TAG, "Magic byte correct but incorrect crc.");
return ESP_FAIL;
}
if (memcmp(image_digest, block->image_digest, ESP_SECURE_BOOT_DIGEST_LEN)) {
ESP_LOGE(TAG, "Magic byte & CRC correct but incorrect image digest.");
return ESP_FAIL;
} else {
ESP_LOGD(TAG, "valid signature block(%d) found", block_num);
return ESP_OK;
}
return ESP_FAIL;
}
/* Generates the public key digests of the valid public keys in an image's
signature block, verifies each signature, and stores the key digests in the
public_key_digests structure.
@param flash_offset Image offset in flash
@param flash_size Image size in flash (not including signature block)
@param[out] public_key_digests Pointer to structure to hold the key digests for valid sig blocks
Note that this function doesn't read any eFuses, so it doesn't know if the
keys are ultimately trusted by the hardware or not
@return - ESP_OK if no signatures failed to verify, or if no valid signature blocks are found at all.
- ESP_FAIL if there's a valid signature block that doesn't verify using the included public key (unexpected!)
*/
static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uint32_t flash_size, esp_image_sig_public_key_digests_t *public_key_digests)
{
esp_err_t ret;
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
uint8_t __attribute__((aligned(4))) key_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
size_t sig_block_addr = flash_offset + ALIGN_UP(flash_size, FLASH_SECTOR_SIZE);
ESP_LOGD(TAG, "calculating public key digests for sig blocks of image offset 0x%x (sig block offset 0x%x)", flash_offset, sig_block_addr);
bzero(public_key_digests, sizeof(esp_image_sig_public_key_digests_t));
ret = bootloader_sha256_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "error generating image digest, %d", ret);
return ret;
}
ESP_LOGD(TAG, "reading signatures");
const ets_secure_boot_signature_t *signatures = bootloader_mmap(sig_block_addr, sizeof(ets_secure_boot_signature_t));
if (signatures == NULL) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", sig_block_addr, sizeof(ets_secure_boot_signature_t));
return ESP_FAIL;
}
for (int i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
const ets_secure_boot_sig_block_t *block = &signatures->block[i];
ret = validate_signature_block(block, i, image_digest);
if (ret != ESP_OK) {
ret = ESP_OK; // past the last valid signature block
break;
}
/* Generating the SHA of the public key components in the signature block */
bootloader_sha256_handle_t sig_block_sha;
sig_block_sha = bootloader_sha256_start();
bootloader_sha256_data(sig_block_sha, &block->key, sizeof(block->key));
bootloader_sha256_finish(sig_block_sha, key_digest);
// Check we can verify the image using this signature and this key
uint8_t temp_verified_digest[ESP_SECURE_BOOT_DIGEST_LEN];
bool verified = ets_rsa_pss_verify(&block->key, block->signature, image_digest, temp_verified_digest);
if (!verified) {
/* We don't expect this: the signature blocks before we enable secure boot should all be verifiable or invalid,
so this is a fatal error
*/
ret = ESP_FAIL;
ESP_LOGE(TAG, "Secure boot key (%d) verification failed.", i);
break;
}
ESP_LOGD(TAG, "Signature block (%d) is verified", i);
/* Copy the key digest to the buffer provided by the caller */
memcpy((void *)public_key_digests->key_digests[i], key_digest, ESP_SECURE_BOOT_DIGEST_LEN);
public_key_digests->num_digests++;
}
if (ret == ESP_OK && public_key_digests->num_digests > 0) {
ESP_LOGI(TAG, "Digests successfully calculated, %d valid signatures (image offset 0x%x)",
public_key_digests->num_digests, flash_offset);
}
bootloader_munmap(signatures);
return ret;
}
static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t *image_data)
{
esp_err_t ret;
/* Verify the bootloader */
esp_image_metadata_t bootloader_data = { 0 };
ret = esp_image_verify_bootloader_data(&bootloader_data);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "bootloader image appears invalid! error %d", ret);
return ret;
}
/* Check if secure boot digests are present */
bool has_secure_boot_digest = esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0, NULL);
has_secure_boot_digest |= esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1, NULL);
has_secure_boot_digest |= esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2, NULL);
ESP_LOGI(TAG, "Secure boot digests %s", has_secure_boot_digest ? "already present":"absent, generating..");
if (!has_secure_boot_digest) {
esp_image_sig_public_key_digests_t boot_key_digests = {0};
esp_image_sig_public_key_digests_t app_key_digests = {0};
/* Generate the bootloader public key digests */
ret = s_calculate_image_public_key_digests(bootloader_data.start_addr, bootloader_data.image_len - SIG_BLOCK_PADDING, &boot_key_digests);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Bootloader signature block is invalid");
return ret;
}
if (boot_key_digests.num_digests == 0) {
ESP_LOGE(TAG, "No valid bootloader signature blocks found.");
return ESP_FAIL;
}
ESP_LOGI(TAG, "%d signature block(s) found appended to the bootloader.", boot_key_digests.num_digests);
esp_efuse_purpose_t secure_boot_key_purpose[SECURE_BOOT_NUM_BLOCKS] = {
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0,
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1,
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2,
};
ret = esp_efuse_write_keys(secure_boot_key_purpose, boot_key_digests.key_digests, boot_key_digests.num_digests);
if (ret) {
if (ret == ESP_ERR_NOT_ENOUGH_UNUSED_KEY_BLOCKS) {
ESP_LOGE(TAG, "Bootloader signatures(%d) more than available key slots.", boot_key_digests.num_digests);
} else {
ESP_LOGE(TAG, "Failed to write efuse block with purpose (err=0x%x). Can't continue.", ret);
}
return ret;
}
/* Generate the application public key digests */
ret = s_calculate_image_public_key_digests(image_data->start_addr, image_data->image_len - SIG_BLOCK_PADDING, &app_key_digests);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "App signature block is invalid.");
return ret;
}
if (app_key_digests.num_digests == 0) {
ESP_LOGE(TAG, "No valid applications signature blocks found.");
return ESP_FAIL;
}
ESP_LOGI(TAG, "%d signature block(s) found appended to the app.", app_key_digests.num_digests);
if (app_key_digests.num_digests > boot_key_digests.num_digests) {
ESP_LOGW(TAG, "App has %d signature blocks but bootloader only has %d. Some keys missing from bootloader?");
}
/* Confirm if at least one public key from the application matches a public key in the bootloader
(Also, ensure if that public revoke bit is not set for the matched key) */
bool match = false;
for (int i = 0; i < boot_key_digests.num_digests; i++) {
if (esp_efuse_get_digest_revoke(i)) {
ESP_LOGI(TAG, "Key block(%d) has been revoked.", i);
continue; // skip if the key block is revoked
}
for (int j = 0; j < app_key_digests.num_digests; j++) {
if (!memcmp(boot_key_digests.key_digests[i], app_key_digests.key_digests[j], ESP_SECURE_BOOT_DIGEST_LEN)) {
ESP_LOGI(TAG, "Application key(%d) matches with bootloader key(%d).", j, i);
match = true;
}
}
}
if (match == false) {
ESP_LOGE(TAG, "No application key digest matches the bootloader key digest.");
return ESP_FAIL;
}
/* Revoke the empty signature blocks */
if (boot_key_digests.num_digests < SECURE_BOOT_NUM_BLOCKS) {
/* The revocation index can be 0, 1, 2. Bootloader count can be 1,2,3. */
for (uint8_t i = boot_key_digests.num_digests; i < SECURE_BOOT_NUM_BLOCKS; i++) {
ESP_LOGI(TAG, "Revoking empty key digest slot (%d)...", i);
esp_efuse_set_digest_revoke(i);
}
}
}
return ESP_OK;
}
esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *image_data)
{
ESP_LOGI(TAG, "enabling secure boot v2...");
if (esp_secure_boot_enabled()) {
ESP_LOGI(TAG, "secure boot v2 is already enabled, continuing..");
return ESP_OK;
}
esp_efuse_batch_write_begin(); /* Batch all efuse writes at the end of this function */
esp_err_t key_state = check_and_generate_secure_boot_keys(image_data);
if (key_state != ESP_OK) {
esp_efuse_batch_write_cancel();
return key_state;
}
__attribute__((unused)) static const uint8_t enable = 1;
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
ESP_LOGI(TAG, "Enabling Security download mode...");
esp_efuse_write_field_bit(ESP_EFUSE_ENABLE_SECURITY_DOWNLOAD);
#else
ESP_LOGW(TAG, "Not enabling Security download mode - SECURITY COMPROMISED");
#endif
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
esp_efuse_write_field_bit(ESP_EFUSE_SOFT_DIS_JTAG);
#else
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
#endif
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
#endif
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
esp_err_t err = esp_efuse_batch_write_commit();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error programming security eFuses (err=0x%x).", err);
return err;
}
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
assert(ets_efuse_secure_boot_aggressive_revoke_enabled());
#endif
assert(esp_rom_efuse_is_secure_boot_enabled());
ESP_LOGI(TAG, "Secure boot permanently enabled");
return ESP_OK;
}

View File

@@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <strings.h>
#include "esp_flash_encrypt.h"
#include "esp_secure_boot.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp_log.h"
#include "sdkconfig.h"
static __attribute__((unused)) const char *TAG = "secure_boot";
esp_err_t esp_secure_boot_enable_secure_features(void)
{
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
ESP_LOGI(TAG, "Enabling Security download mode...");
esp_efuse_write_field_bit(ESP_EFUSE_ENABLE_SECURITY_DOWNLOAD);
#else
ESP_LOGW(TAG, "Not enabling Security download mode - SECURITY COMPROMISED");
#endif
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
esp_efuse_write_field_bit(ESP_EFUSE_SOFT_DIS_JTAG);
#else
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
#endif
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
#endif
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
return ESP_OK;
}

View File

@@ -7,40 +7,51 @@
#include <strings.h>
#include "bootloader_flash_priv.h"
#include "bootloader_random.h"
#include "bootloader_utility.h"
#include "esp_image_format.h"
#include "esp_flash_encrypt.h"
#include "esp_flash_partitions.h"
#include "esp_secure_boot.h"
#include "esp_log.h"
#include "esp32c3/rom/secure_boot.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp_log.h"
#include "hal/wdt_hal.h"
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
#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_flash_contents(size_t flash_crypt_cnt, bool flash_crypt_wr_dis) __attribute__((unused));
static esp_err_t encrypt_bootloader(void);
static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions);
static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition);
esp_err_t esp_flash_encrypt_check_and_update(void)
{
uint8_t flash_crypt_wr_dis = 0;
uint32_t flash_crypt_cnt = 0;
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_efuse_read_field_blob(ESP_EFUSE_SPI_BOOT_CRYPT_CNT, &flash_crypt_cnt, 3);
esp_efuse_read_field_blob(ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT, &flash_crypt_wr_dis, 1);
ESP_LOGV(TAG, "CRYPT_CNT %d, write protection %d", flash_crypt_cnt, flash_crypt_wr_dis);
ESP_LOGV(TAG, "SPI_BOOT_CRYPT_CNT 0x%x", flash_crypt_cnt);
ESP_LOGV(TAG, "EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT 0x%x", flash_crypt_wr_dis);
if (__builtin_parity(flash_crypt_cnt) == 1) {
if (flash_crypt_cnt % 2 == 1) {
/* Flash is already encrypted */
int left = (flash_crypt_cnt == 1) ? 1 : 0;
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 */
}
@@ -60,36 +71,61 @@ esp_err_t esp_flash_encrypt_check_and_update(void)
static esp_err_t check_and_generate_encryption_keys(void)
{
esp_efuse_block_t aes_128_key_block;
bool has_key = esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY, &aes_128_key_block);
bool dis_write = false;
bool dis_read = false;
// If there are keys set, they must be write and read protected!
if(has_key) {
dis_write = esp_efuse_get_key_dis_write(aes_128_key_block);
dis_read = esp_efuse_get_key_dis_read(aes_128_key_block);
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(has_key && (!dis_read || !dis_write)) {
ESP_LOGE(TAG, "Invalid key state, a key was set but not read and write protected.");
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
if(!has_key && !dis_write && !dis_read) {
ESP_LOGI(TAG, "Generating new flash encryption key...");
enum { BLOCKS_NEEDED = 1 };
esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = {
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY,
};
uint8_t keys[BLOCKS_NEEDED][32] = { 0 };
for (int i = 0; i < BLOCKS_NEEDED; ++i) {
bootloader_fill_random(keys[i], 32);
esp_efuse_block_t blocks[BLOCKS_NEEDED];
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) {
@@ -100,73 +136,61 @@ static esp_err_t check_and_generate_encryption_keys(void)
}
return err;
}
ESP_LOGD(TAG, "Key generation complete");
return ESP_OK;
} else {
ESP_LOGI(TAG, "Using pre-existing key in efuse");
return ESP_OK;
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 */
esp_err_t key_state = check_and_generate_encryption_keys();
if(key_state != ESP_OK) {
/* 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 key_state;
return err;
}
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
#else
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
#endif
err = esp_flash_encryption_enable_secure_features();
if (err != ESP_OK) {
esp_efuse_batch_write_cancel();
return err;
}
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
ESP_LOGI(TAG, "Disable UART bootloader cache...");
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE);
#else
ESP_LOGW(TAG, "Not disabling UART bootloader cache - SECURITY COMPROMISED");
#endif
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable JTAG...");
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
#else
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
#endif
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
esp_err_t err = esp_efuse_batch_write_commit();
err = esp_efuse_batch_write_commit();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error programming security eFuses (err=0x%x).", err);
return err;
}
return err;
return ESP_OK;
}
/* Encrypt all flash data that should be encrypted */
static esp_err_t encrypt_flash_contents(uint32_t spi_boot_crypt_cnt, bool flash_crypt_wr_dis)
static esp_err_t encrypt_flash_contents(size_t flash_crypt_cnt, bool flash_crypt_wr_dis)
{
esp_err_t err;
esp_partition_info_t partition_table[ESP_PARTITION_TABLE_MAX_ENTRIES];
int num_partitions;
/* If the last spi_boot_crypt_cnt bit is burned or write-disabled, the
/* If all flash_crypt_cnt bits are burned or write-disabled, the
device can't re-encrypt itself. */
if (flash_crypt_wr_dis || spi_boot_crypt_cnt == EFUSE_SPI_BOOT_CRYPT_CNT) {
ESP_LOGE(TAG, "Cannot re-encrypt data SPI_BOOT_CRYPT_CNT 0x%02x write disabled %d", spi_boot_crypt_cnt, flash_crypt_wr_dis);
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 (spi_boot_crypt_cnt == 0) {
if (flash_crypt_cnt == 0) {
/* Very first flash of encrypted data: generate keys, etc. */
err = initialise_flash_encryption();
if (err != ESP_OK) {
@@ -197,23 +221,20 @@ static esp_err_t encrypt_flash_contents(uint32_t spi_boot_crypt_cnt, bool flash_
ESP_LOGD(TAG, "All flash regions checked for encryption pass");
/* Set least significant 0-bit in spi_boot_crypt_cnt */
int ffs_inv = __builtin_ffs((~spi_boot_crypt_cnt) & 0x7);
/* ffs_inv shouldn't be zero, as zero implies spi_boot_crypt_cnt == 0xFF */
uint32_t new_spi_boot_crypt_cnt = (1 << (ffs_inv - 1));
ESP_LOGD(TAG, "SPI_BOOT_CRYPT_CNT 0x%x -> 0x%x", spi_boot_crypt_cnt, new_spi_boot_crypt_cnt + spi_boot_crypt_cnt);
esp_efuse_write_field_blob(ESP_EFUSE_SPI_BOOT_CRYPT_CNT, &new_spi_boot_crypt_cnt, 3);
#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
//Secure SPI boot cnt after its update if needed.
const uint32_t spi_boot_cnt_wr_dis = 1;
ESP_LOGI(TAG, "Write protecting SPI_CRYPT_CNT eFuse");
esp_efuse_write_field_blob(ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT, &spi_boot_cnt_wr_dis, 1);
// 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;
return err;
}
static esp_err_t encrypt_bootloader(void)
@@ -238,13 +259,23 @@ static esp_err_t encrypt_bootloader(void)
return err;
}
#ifdef CONFIG_SECURE_BOOT_V1_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
ESP_LOGI(TAG, "bootloader encrypted successfully");
return err;
}
else {
} else {
ESP_LOGW(TAG, "no valid bootloader was found");
return ESP_ERR_NOT_FOUND;
}
return ESP_OK;
}
static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions)
@@ -259,7 +290,7 @@ static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partitio
if (esp_partition_table_verify(partition_table, false, num_partitions) == ESP_OK) {
ESP_LOGD(TAG, "partition table is plaintext. Encrypting...");
esp_err_t err = esp_flash_encrypt_region(ESP_PARTITION_TABLE_OFFSET,
FLASH_SECTOR_SIZE);
FLASH_SECTOR_SIZE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt partition table in place. %x", err);
return err;
@@ -287,7 +318,8 @@ static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partit
&partition->pos,
&data_ignored);
should_encrypt = (err == ESP_OK);
} else if (partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_OTA) {
} else if ((partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_OTA)
|| (partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_NVS_KEYS)) {
/* check if we have ota data partition and the partition should be encrypted unconditionally */
should_encrypt = true;
}
@@ -323,7 +355,6 @@ esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length)
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, false);
if (err != ESP_OK) {
@@ -344,3 +375,5 @@ flash_failed:
ESP_LOGE(TAG, "flash operation failed: 0x%x", err);
return err;
}
#endif // CONFIG_SECURE_FLASH_ENC_ENABLED

View File

@@ -0,0 +1,180 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_attr.h"
#include "esp_types.h"
#include "esp_log.h"
#include "esp32/rom/cache.h"
#include "soc/rtc_periph.h"
#include "bootloader_utility.h"
#include "sdkconfig.h"
#include "bootloader_flash_priv.h"
#include "bootloader_random.h"
#include "esp_image_format.h"
#include "esp_secure_boot.h"
#include "esp_flash_encrypt.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
/* The following API implementations are used only when called
* from the bootloader code.
*/
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
static const char *TAG = "secure_boot_v1";
/**
* @function : secure_boot_generate
* @description: generate boot digest (aka "abstract") & iv
*
* @inputs: image_len - length of image to calculate digest for
*/
static bool secure_boot_generate(uint32_t image_len){
esp_err_t err;
esp_secure_boot_iv_digest_t digest;
const uint32_t *image;
/* hardware secure boot engine only takes full blocks, so round up the
image length. The additional data should all be 0xFF (or the appended SHA, if it falls in the same block).
*/
if (image_len % sizeof(digest.iv) != 0) {
image_len = (image_len / sizeof(digest.iv) + 1) * sizeof(digest.iv);
}
ets_secure_boot_start();
ets_secure_boot_rd_iv((uint32_t *)digest.iv);
ets_secure_boot_hash(NULL);
/* iv stored in sec 0 */
err = bootloader_flash_erase_sector(0);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "SPI erase failed: 0x%x", err);
return false;
}
/* generate digest from image contents */
image = bootloader_mmap(ESP_BOOTLOADER_OFFSET, image_len);
if (!image) {
ESP_LOGE(TAG, "bootloader_mmap(0x1000, 0x%x) failed", image_len);
return false;
}
for (size_t i = 0; i < image_len; i+= sizeof(digest.iv)) {
ets_secure_boot_hash(&image[i/sizeof(uint32_t)]);
}
bootloader_munmap(image);
ets_secure_boot_obtain();
ets_secure_boot_rd_abstract((uint32_t *)digest.digest);
ets_secure_boot_finish();
ESP_LOGD(TAG, "write iv+digest to flash");
err = bootloader_flash_write(FLASH_OFFS_SECURE_BOOT_IV_DIGEST, &digest,
sizeof(digest), esp_flash_encryption_enabled());
if (err != ESP_OK) {
ESP_LOGE(TAG, "SPI write failed: 0x%x", err);
return false;
}
Cache_Read_Enable(0);
return true;
}
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."
" No need to generate digest. continuing..");
return ESP_OK;
}
esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK_SECURE_BOOT);
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;
}
/* Verify the bootloader */
esp_image_metadata_t bootloader_data = { 0 };
err = esp_image_verify_bootloader_data(&bootloader_data);
if (err != ESP_OK) {
ESP_LOGE(TAG, "bootloader image appears invalid! error %d", err);
return err;
}
bool dis_write = esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_BLK2);
bool dis_read = esp_efuse_read_field_bit(ESP_EFUSE_RD_DIS_BLK2);
bool key_is_empty = esp_efuse_block_is_empty(EFUSE_BLK_SECURE_BOOT);
/* Generate secure boot key and keep in EFUSE */
if (!dis_read && !dis_write && key_is_empty) {
ESP_LOGI(TAG, "Generating new secure boot key...");
uint32_t key[8];
size_t key_size = 256;
if (coding_scheme == EFUSE_CODING_SCHEME_3_4) {
key_size = 192;
}
bootloader_fill_random(key, key_size / 8);
esp_efuse_write_block(EFUSE_BLK_SECURE_BOOT, key, 0, key_size);
} 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) {
/* Secure boot digest doesn't cover the hash */
image_len -= ESP_IMAGE_HASH_LEN;
}
if (false == secure_boot_generate(image_len)){
ESP_LOGE(TAG, "secure boot generation failed");
return ESP_FAIL;
}
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;
}
bool dis_read = esp_efuse_read_field_bit(ESP_EFUSE_RD_DIS_BLK2);
bool dis_write = esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_BLK2);
if (dis_read != dis_write) {
ESP_LOGE(TAG, "Pre-loaded key is not %s %s protected. Refusing to blow secure boot efuse.",
(!dis_read) ? "read,":" ",
(!dis_read) ? "write":" ");
return ESP_ERR_INVALID_STATE;
}
esp_efuse_batch_write_begin(); /* Batch all efuse writes at the end of this function */
ESP_LOGI(TAG, "blowing secure boot efuse...");
esp_err_t err = esp_secure_boot_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;
}
assert(esp_secure_boot_enabled());
ESP_LOGI(TAG, "secure boot is now enabled for bootloader image");
return ESP_OK;
}
#endif // CONFIG_SECURE_BOOT_V1_ENABLED

View File

@@ -3,36 +3,36 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <string.h>
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_secure_boot.h"
#include "soc/efuse_reg.h"
#include "bootloader_flash_priv.h"
#include "bootloader_sha.h"
#include "bootloader_utility.h"
#include "esp_rom_crc.h"
#include "esp_image_format.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp32s2/rom/efuse.h"
#include "esp32s2/rom/secure_boot.h"
/* The following API implementations are used only when called
* from the bootloader code.
*/
#ifdef CONFIG_SECURE_BOOT_V2_ENABLED
static const char *TAG = "secure_boot_v2";
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
static const char *TAG = "secure_boot_v2";
/* A signature block is valid when it has correct magic byte, crc and image digest. */
static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *block, int block_num, const uint8_t *image_digest)
{
uint32_t crc = esp_rom_crc32_le(0, (uint8_t *)block, CRC_SIGN_BLOCK_LEN);
if (block->magic_byte != ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC) {
// All signature blocks have been parsed, no new signature block present.
ESP_LOGD(TAG, "Signature block(%d) invalid/absent.", block_num);
return ESP_FAIL;
}
if (block->block_crc != crc) {
if (block->block_crc != esp_rom_crc32_le(0, (uint8_t *)block, CRC_SIGN_BLOCK_LEN)) {
ESP_LOGE(TAG, "Magic byte correct but incorrect crc.");
return ESP_FAIL;
}
@@ -43,7 +43,6 @@ static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *blo
ESP_LOGD(TAG, "valid signature block(%d) found", block_num);
return ESP_OK;
}
return ESP_FAIL;
}
@@ -79,14 +78,15 @@ static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uin
return ret;
}
ESP_LOGD(TAG, "reading signatures");
ESP_LOGD(TAG, "reading signature(s)");
const ets_secure_boot_signature_t *signatures = bootloader_mmap(sig_block_addr, sizeof(ets_secure_boot_signature_t));
if (signatures == NULL) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", sig_block_addr, sizeof(ets_secure_boot_signature_t));
return ESP_FAIL;
}
for (int i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
/* Validating Signature block */
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
const ets_secure_boot_sig_block_t *block = &signatures->block[i];
ret = validate_signature_block(block, i, image_digest);
@@ -131,6 +131,23 @@ static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uin
static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t *image_data)
{
esp_err_t ret;
#ifdef CONFIG_IDF_TARGET_ESP32
esp_efuse_purpose_t secure_boot_key_purpose[SECURE_BOOT_NUM_BLOCKS] = {
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_V2,
};
esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK_SECURE_BOOT);
if (coding_scheme != EFUSE_CODING_SCHEME_NONE) {
ESP_LOGE(TAG, "No coding schemes are supported in secure boot v2.(Detected scheme: 0x%x)", coding_scheme);
return ESP_ERR_NOT_SUPPORTED;
}
#else
esp_efuse_purpose_t secure_boot_key_purpose[SECURE_BOOT_NUM_BLOCKS] = {
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0,
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1,
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2,
};
#endif // CONFIG_IDF_TARGET_ESP32
/* Verify the bootloader */
esp_image_metadata_t bootloader_data = { 0 };
ret = esp_image_verify_bootloader_data(&bootloader_data);
@@ -140,15 +157,22 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
}
/* Check if secure boot digests are present */
bool has_secure_boot_digest = esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0, NULL);
has_secure_boot_digest |= esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1, NULL);
has_secure_boot_digest |= esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2, NULL);
esp_efuse_block_t blocks[SECURE_BOOT_NUM_BLOCKS];
bool has_secure_boot_digest = false;
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
blocks[i] = EFUSE_BLK_KEY_MAX;
bool tmp_has_key = esp_efuse_find_purpose(secure_boot_key_purpose[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]);
}
has_secure_boot_digest |= tmp_has_key;
}
esp_image_sig_public_key_digests_t boot_key_digests = {0};
esp_image_sig_public_key_digests_t app_key_digests = {0};
ESP_LOGI(TAG, "Secure boot digests %s", has_secure_boot_digest ? "already present":"absent, generating..");
if (!has_secure_boot_digest) {
esp_image_sig_public_key_digests_t boot_key_digests = {0};
esp_image_sig_public_key_digests_t app_key_digests = {0};
/* Generate the bootloader public key digests */
ret = s_calculate_image_public_key_digests(bootloader_data.start_addr, bootloader_data.image_len - SIG_BLOCK_PADDING, &boot_key_digests);
if (ret != ESP_OK) {
@@ -162,14 +186,9 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
}
ESP_LOGI(TAG, "%d signature block(s) found appended to the bootloader.", boot_key_digests.num_digests);
esp_efuse_purpose_t secure_boot_key_purpose[SECURE_BOOT_NUM_BLOCKS] = {
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0,
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1,
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2,
};
ESP_LOGI(TAG, "Burning public key hash to eFuse");
ret = esp_efuse_write_keys(secure_boot_key_purpose, boot_key_digests.key_digests, boot_key_digests.num_digests);
if (ret) {
if (ret != ESP_OK) {
if (ret == ESP_ERR_NOT_ENOUGH_UNUSED_KEY_BLOCKS) {
ESP_LOGE(TAG, "Bootloader signatures(%d) more than available key slots.", boot_key_digests.num_digests);
} else {
@@ -177,57 +196,88 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
}
return ret;
}
/* Generate the application public key digests */
ret = s_calculate_image_public_key_digests(image_data->start_addr, image_data->image_len - SIG_BLOCK_PADDING, &app_key_digests);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "App signature block is invalid.");
return ret;
}
if (app_key_digests.num_digests == 0) {
ESP_LOGE(TAG, "No valid applications signature blocks found.");
return ESP_FAIL;
}
ESP_LOGI(TAG, "%d signature block(s) found appended to the app.", app_key_digests.num_digests);
if (app_key_digests.num_digests > boot_key_digests.num_digests) {
ESP_LOGW(TAG, "App has %d signature blocks but bootloader only has %d. Some keys missing from bootloader?");
}
/* Confirm if at least one public key from the application matches a public key in the bootloader
(Also, ensure if that public revoke bit is not set for the matched key) */
bool match = false;
for (int i = 0; i < boot_key_digests.num_digests; i++) {
} else {
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
#if SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
if (esp_efuse_get_digest_revoke(i)) {
ESP_LOGI(TAG, "Key block(%d) has been revoked.", i);
continue; // skip if the key block is revoked
continue;
}
for (int j = 0; j < app_key_digests.num_digests; j++) {
if (!memcmp(boot_key_digests.key_digests[i], app_key_digests.key_digests[j], ESP_SECURE_BOOT_DIGEST_LEN)) {
ESP_LOGI(TAG, "Application key(%d) matches with bootloader key(%d).", j, i);
match = true;
}
#endif
if (esp_efuse_get_key_dis_read(blocks[i])) {
ESP_LOGE(TAG, "Key digest (BLK%d) read protected, aborting...", blocks[i]);
return ESP_FAIL;
}
if (esp_efuse_block_is_empty(blocks[i])) {
ESP_LOGE(TAG, "%d eFuse block is empty, aborting...", blocks[i]);
return ESP_FAIL;
}
esp_efuse_set_key_dis_write(blocks[i]);
ret = esp_efuse_read_block(blocks[i], boot_key_digests.key_digests[boot_key_digests.num_digests], 0,
sizeof(boot_key_digests.key_digests[0]) * 8);
if (ret) {
ESP_LOGE(TAG, "Error during reading %d eFuse block (err=0x%x)", blocks[i], ret);
return ret;
}
boot_key_digests.num_digests++;
}
if (match == false) {
ESP_LOGE(TAG, "No application key digest matches the bootloader key digest.");
if (boot_key_digests.num_digests == 0) {
ESP_LOGE(TAG, "No valid pre-loaded public key digest in eFuse");
return ESP_FAIL;
}
ESP_LOGW(TAG, "Using pre-loaded public key digest in eFuse");
}
/* Revoke the empty signature blocks */
if (boot_key_digests.num_digests < SECURE_BOOT_NUM_BLOCKS) {
/* The revocation index can be 0, 1, 2. Bootloader count can be 1,2,3. */
for (uint8_t i = boot_key_digests.num_digests; i < SECURE_BOOT_NUM_BLOCKS; i++) {
ESP_LOGI(TAG, "Revoking empty key digest slot (%d)...", i);
esp_efuse_set_digest_revoke(i);
/* Generate the application public key digests */
ret = s_calculate_image_public_key_digests(image_data->start_addr, image_data->image_len - SIG_BLOCK_PADDING, &app_key_digests);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Application signature block is invalid.");
return ret;
}
if (app_key_digests.num_digests == 0) {
ESP_LOGE(TAG, "No valid applications signature blocks found.");
return ESP_FAIL;
}
ESP_LOGI(TAG, "%d signature block(s) found appended to the app.", app_key_digests.num_digests);
if (app_key_digests.num_digests > boot_key_digests.num_digests) {
ESP_LOGW(TAG, "App has %d signature blocks but bootloader only has %d. Some keys missing from bootloader?");
}
/* Confirm if at least one public key from the application matches a public key in the bootloader
(Also, ensure if that public revoke bit is not set for the matched key) */
bool match = false;
for (unsigned i = 0; i < boot_key_digests.num_digests; i++) {
#if SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
if (esp_efuse_get_digest_revoke(i)) {
ESP_LOGI(TAG, "Key block(%d) has been revoked.", i);
continue; // skip if the key block is revoked
}
#endif // SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
for (unsigned j = 0; j < app_key_digests.num_digests; j++) {
if (!memcmp(boot_key_digests.key_digests[i], app_key_digests.key_digests[j], ESP_SECURE_BOOT_DIGEST_LEN)) {
ESP_LOGI(TAG, "Application key(%d) matches with bootloader key(%d).", j, i);
match = true;
}
}
}
if (match == false) {
ESP_LOGE(TAG, "No application key digest matches the bootloader key digest.");
return ESP_FAIL;
}
#if SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
/* Revoke the empty signature blocks */
if (boot_key_digests.num_digests < SECURE_BOOT_NUM_BLOCKS) {
/* The revocation index can be 0, 1, 2. Bootloader count can be 1,2,3. */
for (unsigned i = boot_key_digests.num_digests; i < SECURE_BOOT_NUM_BLOCKS; i++) {
ESP_LOGI(TAG, "Revoking empty key digest slot (%d)...", i);
esp_efuse_set_digest_revoke(i);
}
}
#endif // SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
return ESP_OK;
}
@@ -242,50 +292,34 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
esp_efuse_batch_write_begin(); /* Batch all efuse writes at the end of this function */
esp_err_t key_state = check_and_generate_secure_boot_keys(image_data);
if (key_state != ESP_OK) {
esp_err_t err;
err = check_and_generate_secure_boot_keys(image_data);
if (err != ESP_OK) {
esp_efuse_batch_write_cancel();
return key_state;
return err;
}
__attribute__((unused)) static const uint8_t enable = 1;
ESP_LOGI(TAG, "blowing secure boot efuse...");
err = esp_secure_boot_enable_secure_features();
if (err != ESP_OK) {
esp_efuse_batch_write_cancel();
return err;
}
esp_efuse_write_field_bit(ESP_EFUSE_DIS_BOOT_REMAP);
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
ESP_LOGI(TAG, "Enabling Security download mode...");
esp_efuse_write_field_bit(ESP_EFUSE_ENABLE_SECURITY_DOWNLOAD);
#else
ESP_LOGW(TAG, "Not enabling Security download mode - SECURITY COMPROMISED");
#endif
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
esp_efuse_write_field_bit(ESP_EFUSE_SOFT_DIS_JTAG);
#else
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
#endif
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
#endif
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
esp_err_t err = esp_efuse_batch_write_commit();
err = esp_efuse_batch_write_commit();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error programming security eFuses (err=0x%x).", err);
return err;
}
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
assert(ets_efuse_secure_boot_aggressive_revoke_enabled());
assert(esp_efuse_read_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE));
#endif
assert(esp_rom_efuse_is_secure_boot_enabled());
assert(esp_secure_boot_enabled());
ESP_LOGI(TAG, "Secure boot permanently enabled");
return ESP_OK;
}
#endif // CONFIG_SECURE_BOOT_V2_ENABLED

View File

@@ -20,6 +20,7 @@
#include <sys/param.h>
#include "esp_secure_boot.h"
#include "esp_ota_ops.h"
#include "esp_efuse.h"
// Secure boot V2 for app
@@ -100,10 +101,9 @@ static esp_err_t get_secure_boot_key_digests(esp_image_sig_public_key_digests_t
return esp_secure_boot_get_signature_blocks_for_running_app(true, public_key_digests);
#elif CONFIG_SECURE_BOOT_V2_ENABLED
ESP_LOGI(TAG, "Take trusted digest key(s) from eFuse block(s)");
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1
// Read key digests from efuse
ets_secure_boot_key_digests_t efuse_trusted;
if (ets_secure_boot_read_key_digests(&efuse_trusted) == ETS_OK) {
if (esp_secure_boot_read_key_digests(&efuse_trusted) == ESP_OK) {
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
if (efuse_trusted.key_digests[i] != NULL) {
memcpy(public_key_digests->key_digests[i], (uint8_t *)efuse_trusted.key_digests[i], ESP_SECURE_BOOT_DIGEST_LEN);
@@ -115,11 +115,6 @@ static esp_err_t get_secure_boot_key_digests(esp_image_sig_public_key_digests_t
return ESP_OK;
}
return ESP_ERR_NOT_FOUND;
#else
memcpy(public_key_digests->key_digests[0], (uint8_t *)EFUSE_BLK2_RDATA0_REG, ESP_SECURE_BOOT_DIGEST_LEN);
public_key_digests->num_digests = 1;
return ESP_OK;
#endif // SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS
#endif // CONFIG_SECURE_BOOT_V2_ENABLED
}

View File

@@ -13,6 +13,7 @@
#include "esp_log.h"
#include "esp_image_format.h"
#include "esp_secure_boot.h"
#include "esp_efuse.h"
// Secure boot V2 for bootloader.
@@ -64,49 +65,38 @@ static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *blo
static esp_err_t get_secure_boot_key_digests(esp_image_sig_public_key_digests_t *public_key_digests)
{
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1
// Read key digests from efuse
ets_secure_boot_key_digests_t trusted_keys;
ets_secure_boot_key_digests_t trusted_key_copies[2];
ETS_STATUS ets_ret;
memset(&trusted_keys, 0, sizeof(ets_secure_boot_key_digests_t));
memset(trusted_key_copies, 0, 2 * sizeof(ets_secure_boot_key_digests_t));
ets_ret = ets_secure_boot_read_key_digests(&trusted_keys);
esp_err_t err = esp_secure_boot_read_key_digests(&trusted_keys);
// Create the copies for FI checks (assuming result is ETS_OK, if it's not then it'll fail the fault check anyhow)
ets_secure_boot_read_key_digests(&trusted_key_copies[0]);
ets_secure_boot_read_key_digests(&trusted_key_copies[1]);
esp_secure_boot_read_key_digests(&trusted_key_copies[0]);
esp_secure_boot_read_key_digests(&trusted_key_copies[1]);
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[0], sizeof(ets_secure_boot_key_digests_t)) == 0);
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[1], sizeof(ets_secure_boot_key_digests_t)) == 0);
if (ets_ret == ETS_OK) {
if (err == ESP_OK) {
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
if (trusted_keys.key_digests[i] != NULL) {
memcpy(public_key_digests->key_digests[i], (uint8_t *)trusted_keys.key_digests[i], ESP_SECURE_BOOT_DIGEST_LEN);
public_key_digests->num_digests++;
}
}
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS == 1
if (esp_efuse_block_is_empty(EFUSE_BLK_SECURE_BOOT)) {
return ESP_ERR_NOT_FOUND;
}
#endif // SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS
if (public_key_digests->num_digests > 0) {
return ESP_OK;
}
}
return ESP_ERR_NOT_FOUND;
#else
bool all_zeroes = true;
uint32_t *reg = (uint32_t*)&public_key_digests->key_digests[0];
for (int i = 0; i < ESP_SECURE_BOOT_DIGEST_LEN / 4; i++) {
*(reg + i) = REG_READ(EFUSE_BLK2_RDATA0_REG + i * 4);
all_zeroes = all_zeroes && (*(reg + i) == 0);
}
if (all_zeroes) {
return ESP_ERR_NOT_FOUND;
}
public_key_digests->num_digests = 1;
return ESP_OK;
#endif // SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS
}
// if CONFIG_SECURE_BOOT_V2_ENABLED==y and key digests from eFuse are missing, then it is the first boot,