mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
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:
parent
eca878b37f
commit
f339b3fc96
@ -893,7 +893,7 @@ esp_err_t esp_ota_revoke_secure_boot_public_key(esp_ota_secure_boot_public_key_i
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ets_secure_boot_revoke_public_key_digest(index);
|
||||
esp_efuse_set_digest_revoke(index);
|
||||
ESP_LOGI(TAG, "Revoked signature block %d.", index);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -267,10 +267,14 @@ menu "Bootloader config"
|
||||
bool "Emulate operations with efuse secure version(only test)"
|
||||
default n
|
||||
depends on BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
select EFUSE_VIRTUAL
|
||||
select EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
help
|
||||
This option allow emulate read/write operations with efuse secure version.
|
||||
It allow to test anti-rollback implemention without permanent write eFuse bits.
|
||||
In partition table should be exist this partition `emul_efuse, data, 5, , 0x2000`.
|
||||
This option allows to emulate read/write operations with all eFuses and efuse secure version.
|
||||
It allows to test anti-rollback implemention without permanent write eFuse bits.
|
||||
There should be an entry in partition table with following details: `emul_efuse, data, efuse, , 0x2000`.
|
||||
|
||||
This option enables: EFUSE_VIRTUAL and EFUSE_VIRTUAL_KEEP_IN_FLASH.
|
||||
|
||||
config BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP
|
||||
bool "Skip image validation when exiting deep sleep"
|
||||
|
@ -50,8 +50,10 @@ SECTIONS
|
||||
*libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_encryption_secure_features.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_secure_features.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures_bootloader.*(.literal .text .literal.* .text.*)
|
||||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
|
@ -38,8 +38,10 @@ SECTIONS
|
||||
*libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_encryption_secure_features.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_secure_features.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures_bootloader.*(.literal .text .literal.* .text.*)
|
||||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
|
@ -37,8 +37,10 @@ SECTIONS
|
||||
*libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_encryption_secure_features.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_secure_features.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures_bootloader.*(.literal .text .literal.* .text.*)
|
||||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
|
@ -38,8 +38,10 @@ SECTIONS
|
||||
*libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_encryption_secure_features.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_secure_features.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures_bootloader.*(.literal .text .literal.* .text.*)
|
||||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
|
@ -26,7 +26,6 @@ if(BOOTLOADER_BUILD)
|
||||
"src/bootloader_console_loader.c"
|
||||
"src/bootloader_panic.c"
|
||||
"src/${IDF_TARGET}/bootloader_sha.c"
|
||||
"src/${IDF_TARGET}/flash_encrypt.c"
|
||||
"src/${IDF_TARGET}/bootloader_${IDF_TARGET}.c"
|
||||
)
|
||||
list(APPEND priv_requires hal)
|
||||
@ -39,14 +38,27 @@ else()
|
||||
endif()
|
||||
|
||||
if(BOOTLOADER_BUILD)
|
||||
if(CONFIG_SECURE_FLASH_ENC_ENABLED)
|
||||
list(APPEND srcs "src/flash_encryption/flash_encrypt.c"
|
||||
"src/${IDF_TARGET}/flash_encryption_secure_features.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SECURE_SIGNED_ON_BOOT)
|
||||
if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
|
||||
list(APPEND srcs "src/secure_boot_v1/secure_boot_signatures_bootloader.c")
|
||||
endif()
|
||||
if(CONFIG_SECURE_BOOT_V1_ENABLED)
|
||||
list(APPEND srcs "src/secure_boot_v1/secure_boot.c"
|
||||
"src/${IDF_TARGET}/secure_boot_secure_features.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
|
||||
list(APPEND srcs "src/secure_boot_v2/secure_boot_signatures_bootloader.c")
|
||||
endif()
|
||||
if(CONFIG_SECURE_BOOT_V2_ENABLED)
|
||||
list(APPEND srcs "src/secure_boot_v2/secure_boot.c"
|
||||
"src/${IDF_TARGET}/secure_boot_secure_features.c")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
if(CONFIG_SECURE_SIGNED_ON_UPDATE)
|
||||
@ -60,11 +72,6 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CONFIG_SECURE_BOOT AND BOOTLOADER_BUILD)
|
||||
list(APPEND srcs
|
||||
"src/${IDF_TARGET}/secure_boot.c")
|
||||
endif()
|
||||
|
||||
set(requires soc) #unfortunately the header directly uses SOC registers
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
|
@ -15,6 +15,9 @@ ifndef IS_BOOTLOADER_BUILD
|
||||
COMPONENT_SRCDIRS += src/idf # idf sub-directory contains platform agnostic IDF versions
|
||||
else
|
||||
COMPONENT_SRCDIRS += src/$(IDF_TARGET) # one sub-dir per chip
|
||||
ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
COMPONENT_SRCDIRS += src/flash_encryption
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef IS_BOOTLOADER_BUILD
|
||||
@ -43,6 +46,23 @@ ifdef IS_BOOTLOADER_BUILD
|
||||
ifndef CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
COMPONENT_OBJEXCLUDE += src/secure_boot_v2/secure_boot_signatures_bootloader.o
|
||||
endif
|
||||
|
||||
ifndef CONFIG_SECURE_BOOT_V1_ENABLED
|
||||
COMPONENT_OBJEXCLUDE += src/secure_boot_v1/secure_boot.o
|
||||
endif
|
||||
|
||||
ifndef CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
COMPONENT_OBJEXCLUDE += src/secure_boot_v2/secure_boot.o
|
||||
endif
|
||||
|
||||
ifndef CONFIG_SECURE_BOOT
|
||||
COMPONENT_OBJEXCLUDE += src/${IDF_TARGET}/secure_boot_secure_features.o
|
||||
endif
|
||||
|
||||
ifndef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
COMPONENT_OBJEXCLUDE += src/${IDF_TARGET}/flash_encryption_secure_features.o
|
||||
endif
|
||||
|
||||
COMPONENT_OBJEXCLUDE += src/secure_boot_v1/secure_boot_signatures_app.o \
|
||||
src/secure_boot_v2/secure_boot_signatures_app.o
|
||||
else
|
||||
@ -53,13 +73,12 @@ else
|
||||
ifndef CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
COMPONENT_OBJEXCLUDE += src/secure_boot_v2/secure_boot_signatures_app.o
|
||||
endif
|
||||
COMPONENT_OBJEXCLUDE += src/secure_boot_v1/secure_boot_signatures_bootloader.o \
|
||||
src/secure_boot_v2/secure_boot_signatures_bootloader.o
|
||||
endif # IS_BOOTLOADER_BUILD
|
||||
|
||||
ifndef CONFIG_SECURE_BOOT
|
||||
COMPONENT_OBJEXCLUDE += src/$(IDF_TARGET)/secure_boot.o
|
||||
endif
|
||||
COMPONENT_OBJEXCLUDE += src/secure_boot_v1/secure_boot_signatures_bootloader.o \
|
||||
src/secure_boot_v1/secure_boot.o \
|
||||
src/secure_boot_v2/secure_boot_signatures_bootloader.o \
|
||||
src/secure_boot_v2/secure_boot.o
|
||||
endif # IS_BOOTLOADER_BUILD
|
||||
|
||||
#
|
||||
# Secure boot signing key support
|
||||
|
@ -14,6 +14,11 @@
|
||||
#include "soc/efuse_periph.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -43,9 +48,17 @@ static inline /** @cond */ IRAM_ATTR /** @endcond */ bool esp_flash_encryption_e
|
||||
{
|
||||
uint32_t flash_crypt_cnt = 0;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
flash_crypt_cnt = REG_GET_FIELD(EFUSE_BLK0_RDATA0_REG, EFUSE_RD_FLASH_CRYPT_CNT);
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
flash_crypt_cnt = REG_GET_FIELD(EFUSE_BLK0_RDATA0_REG, EFUSE_RD_FLASH_CRYPT_CNT);
|
||||
#else
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_FLASH_CRYPT_CNT, &flash_crypt_cnt, ESP_EFUSE_FLASH_CRYPT_CNT[0]->bit_count);
|
||||
#endif
|
||||
#else
|
||||
flash_crypt_cnt = REG_GET_FIELD(EFUSE_RD_REPEAT_DATA1_REG, EFUSE_SPI_BOOT_CRYPT_CNT);
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
flash_crypt_cnt = REG_GET_FIELD(EFUSE_RD_REPEAT_DATA1_REG, EFUSE_SPI_BOOT_CRYPT_CNT);
|
||||
#else
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_SPI_BOOT_CRYPT_CNT, &flash_crypt_cnt, ESP_EFUSE_SPI_BOOT_CRYPT_CNT[0]->bit_count);
|
||||
#endif
|
||||
#endif
|
||||
/* __builtin_parity is in flash, so we calculate parity inline */
|
||||
bool enabled = false;
|
||||
@ -151,6 +164,13 @@ esp_flash_enc_mode_t esp_get_flash_encryption_mode(void);
|
||||
*/
|
||||
void esp_flash_encryption_init_checks(void);
|
||||
|
||||
/** @brief Set all secure eFuse features related to flash encryption
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK - Successfully
|
||||
*/
|
||||
esp_err_t esp_flash_encryption_enable_secure_features(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -44,6 +44,11 @@ extern "C" {
|
||||
|
||||
#define ESP_SECURE_BOOT_DIGEST_LEN 32
|
||||
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#endif
|
||||
|
||||
/** @brief Is secure boot currently enabled in hardware?
|
||||
*
|
||||
* This means that the ROM bootloader code will only boot
|
||||
@ -55,12 +60,24 @@ static inline bool esp_secure_boot_enabled(void)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
|
||||
return REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_ABS_DONE_0;
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
return REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_ABS_DONE_0;
|
||||
#else
|
||||
return esp_efuse_read_field_bit(ESP_EFUSE_ABS_DONE_0);
|
||||
#endif
|
||||
#elif CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
return ets_use_secure_boot_v2();
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
return ets_use_secure_boot_v2();
|
||||
#else
|
||||
return esp_efuse_read_field_bit(ESP_EFUSE_ABS_DONE_1);
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
return esp_rom_efuse_is_secure_boot_enabled();
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
return esp_rom_efuse_is_secure_boot_enabled();
|
||||
#else
|
||||
return esp_efuse_read_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
#endif
|
||||
#endif
|
||||
return false; /* Secure Boot not enabled in menuconfig */
|
||||
}
|
||||
@ -263,6 +280,13 @@ esp_err_t esp_secure_boot_get_signature_blocks_for_running_app(bool digest_publi
|
||||
|
||||
#endif // !BOOTLOADER_BUILD && CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
|
||||
/** @brief Set all secure eFuse features related to secure_boot
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK - Successfully
|
||||
*/
|
||||
esp_err_t esp_secure_boot_enable_secure_features(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -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));
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
|
180
components/bootloader_support/src/secure_boot_v1/secure_boot.c
Normal file
180
components/bootloader_support/src/secure_boot_v1/secure_boot.c
Normal 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
|
@ -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
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -1,5 +1,10 @@
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
|
||||
if(CONFIG_EFUSE_VIRTUAL)
|
||||
message(STATUS "Efuse virtual mode is enabled. If Secure boot or Flash encryption is on"
|
||||
" it does not provide any security. FOR TESTING ONLY!")
|
||||
endif()
|
||||
|
||||
if(EXISTS "${COMPONENT_DIR}/${target}")
|
||||
include(${COMPONENT_DIR}/${target}/sources.cmake)
|
||||
spaces2list(EFUSE_SOC_SRCS)
|
||||
|
@ -18,9 +18,25 @@ menu "eFuse Bit Manager"
|
||||
bool "Simulate eFuse operations in RAM"
|
||||
default n
|
||||
help
|
||||
All read and writes operations are redirected to RAM instead of eFuse registers.
|
||||
If this option is set, all permanent changes (via eFuse) are disabled.
|
||||
Log output will state changes which would be applied, but they will not be.
|
||||
If "n" - No virtual mode. All eFuse operations are real and use eFuse registers.
|
||||
If "y" - The virtual mode is enabled and all eFuse operations (read and write) are redirected
|
||||
to RAM instead of eFuse registers, all permanent changes (via eFuse) are disabled.
|
||||
Log output will state changes that would be applied, but they will not be.
|
||||
|
||||
During startup, the eFuses are copied into RAM. This mode is useful for fast tests.
|
||||
|
||||
config EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
bool "Keep eFuses in flash"
|
||||
depends on EFUSE_VIRTUAL
|
||||
help
|
||||
In addition to the "Simulate eFuse operations in RAM" option, this option just adds
|
||||
a feature to keep eFuses after reboots in flash memory. To use this mode the partition_table
|
||||
should have the `efuse` partition. partition.csv: "efuse_em, data, efuse, , 0x2000,"
|
||||
|
||||
During startup, the eFuses are copied from flash or,
|
||||
in case if flash is empty, from real eFuse to RAM and then update flash.
|
||||
This mode is useful when need to keep changes after reboot
|
||||
(testing secure_boot and flash_encryption).
|
||||
|
||||
choice EFUSE_CODE_SCHEME_SELECTOR
|
||||
prompt "Coding Scheme Compatibility"
|
||||
|
@ -12,3 +12,7 @@ endif
|
||||
|
||||
COMPONENT_PRIV_INCLUDEDIRS := private_include $(TARGET)/private_include
|
||||
COMPONENT_ADD_INCLUDEDIRS := include $(TARGET)/include
|
||||
|
||||
ifdef CONFIG_EFUSE_VIRTUAL
|
||||
$(info eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!)
|
||||
endif
|
||||
|
@ -115,3 +115,9 @@ void esp_efuse_write_random_key(uint32_t blk_wdata0_reg)
|
||||
bzero(buf, sizeof(buf));
|
||||
bzero(raw, sizeof(raw));
|
||||
}
|
||||
|
||||
// Permanently update values written to the efuse write registers
|
||||
void esp_efuse_burn_new_values(void)
|
||||
{
|
||||
esp_efuse_utility_burn_efuses();
|
||||
}
|
||||
|
@ -98,6 +98,9 @@ void esp_efuse_utility_burn_efuses(void)
|
||||
virt_blocks[num_block][subblock++] |= REG_READ(addr_wr_block);
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_utility_write_efuses_to_flash();
|
||||
#endif
|
||||
#else
|
||||
esp_efuse_set_timing();
|
||||
// Permanently update values written to the efuse write registers
|
||||
|
@ -6,6 +6,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <esp_err.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -40,6 +43,71 @@ typedef enum {
|
||||
EFUSE_CODING_SCHEME_REPEAT = 2, /**< Repeat coding */
|
||||
} esp_efuse_coding_scheme_t;
|
||||
|
||||
/**
|
||||
* @brief Type of key purpose (virtual because ESP32 has only fixed purposes for blocks)
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_EFUSE_KEY_PURPOSE_USER = 0, /**< BLOCK3 */
|
||||
ESP_EFUSE_KEY_PURPOSE_SYSTEM = 1, /**< BLOCK0 */
|
||||
ESP_EFUSE_KEY_PURPOSE_FLASH_ENCRYPTION = 2, /**< BLOCK1 */
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_V2 = 3, /**< BLOCK2 */
|
||||
ESP_EFUSE_KEY_PURPOSE_MAX, /**< MAX PURPOSE*/
|
||||
} esp_efuse_purpose_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Permanently update values written to the efuse write registers
|
||||
*
|
||||
* After updating EFUSE_BLKx_WDATAx_REG registers with new values to
|
||||
* write, call this function to permanently write them to efuse.
|
||||
*
|
||||
* @note Setting bits in efuse is permanent, they cannot be unset.
|
||||
*
|
||||
* @note Due to this restriction you don't need to copy values to
|
||||
* Efuse write registers from the matching read registers, bits which
|
||||
* are set in the read register but unset in the matching write
|
||||
* register will be unchanged when new values are burned.
|
||||
*
|
||||
* @note This function is not threadsafe, if calling code updates
|
||||
* efuse values from multiple tasks then this is caller's
|
||||
* responsibility to serialise.
|
||||
*
|
||||
* @deprecated Use the batch mode instead of directly call the burn command.
|
||||
*
|
||||
* After burning new efuses, the read registers are updated to match
|
||||
* the new efuse values.
|
||||
*/
|
||||
void esp_efuse_burn_new_values(void) __attribute__ ((deprecated));
|
||||
|
||||
/* @brief Write random data to efuse key block write registers
|
||||
*
|
||||
* @note Caller is responsible for ensuring efuse
|
||||
* block is empty and not write protected, before calling.
|
||||
*
|
||||
* @note Behaviour depends on coding scheme: a 256-bit key is
|
||||
* generated and written for Coding Scheme "None", a 192-bit key
|
||||
* is generated, extended to 256-bits by the Coding Scheme,
|
||||
* and then writtten for 3/4 Coding Scheme.
|
||||
*
|
||||
* @note This function does not burn the new values, caller should
|
||||
* call esp_efuse_burn_new_values() when ready to do this.
|
||||
*
|
||||
* @deprecated Use the code below instead of this function:
|
||||
*
|
||||
* @code{c}
|
||||
* 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_BLK1, key, 0, key_size);
|
||||
* @endcode
|
||||
*
|
||||
* @param blk_wdata0_reg Address of the first data write register
|
||||
* in the block
|
||||
*/
|
||||
void esp_efuse_write_random_key(uint32_t blk_wdata0_reg) __attribute__ ((deprecated));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include "bootloader_random.h"
|
||||
#include "sys/param.h"
|
||||
|
||||
const static char *TAG = "efuse";
|
||||
static __attribute__((unused)) const char *TAG = "efuse";
|
||||
|
||||
// Contains functions that provide access to efuse fields which are often used in IDF.
|
||||
|
||||
@ -49,22 +49,6 @@ esp_err_t esp_efuse_set_rom_log_scheme(esp_efuse_rom_log_scheme_t log_scheme)
|
||||
}
|
||||
}
|
||||
|
||||
void esp_efuse_write_random_key(uint32_t blk_wdata0_reg)
|
||||
{
|
||||
uint32_t buf[8];
|
||||
uint8_t raw[24];
|
||||
|
||||
bootloader_fill_random(buf, sizeof(buf));
|
||||
|
||||
ESP_LOGV(TAG, "Writing random values to address 0x%08x", blk_wdata0_reg);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ESP_LOGV(TAG, "EFUSE_BLKx_WDATA%d_REG = 0x%08x", i, buf[i]);
|
||||
REG_WRITE(blk_wdata0_reg + 4 * i, buf[i]);
|
||||
}
|
||||
bzero(buf, sizeof(buf));
|
||||
bzero(raw, sizeof(raw));
|
||||
}
|
||||
|
||||
esp_err_t esp_efuse_disable_rom_download_mode(void)
|
||||
{
|
||||
return esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MODE);
|
||||
|
@ -85,6 +85,9 @@ void esp_efuse_utility_burn_efuses(void)
|
||||
virt_blocks[num_block][subblock++] |= REG_READ(addr_wr_block);
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_utility_write_efuses_to_flash();
|
||||
#endif
|
||||
#else
|
||||
if (esp_efuse_set_timing() != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Efuse fields are not burnt");
|
||||
|
@ -57,6 +57,23 @@ typedef enum {
|
||||
EFUSE_CODING_SCHEME_RS = 3, /**< Reed-Solomon coding */
|
||||
} esp_efuse_coding_scheme_t;
|
||||
|
||||
/**
|
||||
* @brief Type of key purpose
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_EFUSE_KEY_PURPOSE_USER = 0, /**< User purposes (software-only use) */
|
||||
ESP_EFUSE_KEY_PURPOSE_RESERVED = 1, /**< Reserved */
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY = 4, /**< XTS_AES_128_KEY (flash/PSRAM encryption) */
|
||||
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL = 5, /**< HMAC Downstream mode */
|
||||
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG = 6, /**< JTAG soft enable key (uses HMAC Downstream mode) */
|
||||
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE = 7, /**< Digital Signature peripheral key (uses HMAC Downstream mode) */
|
||||
ESP_EFUSE_KEY_PURPOSE_HMAC_UP = 8, /**< HMAC Upstream mode */
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0 = 9, /**< SECURE_BOOT_DIGEST0 (Secure Boot key digest) */
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1 = 10, /**< SECURE_BOOT_DIGEST1 (Secure Boot key digest) */
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2 = 11, /**< SECURE_BOOT_DIGEST2 (Secure Boot key digest) */
|
||||
ESP_EFUSE_KEY_PURPOSE_MAX, /**< MAX PURPOSE */
|
||||
} esp_efuse_purpose_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "bootloader_random.h"
|
||||
#include "sys/param.h"
|
||||
|
||||
const static char *TAG = "efuse";
|
||||
static __attribute__((unused)) const char *TAG = "efuse";
|
||||
|
||||
// Contains functions that provide access to efuse fields which are often used in IDF.
|
||||
|
||||
@ -37,22 +37,6 @@ uint32_t esp_efuse_get_pkg_ver(void)
|
||||
return pkg_ver;
|
||||
}
|
||||
|
||||
void esp_efuse_write_random_key(uint32_t blk_wdata0_reg)
|
||||
{
|
||||
uint32_t buf[8];
|
||||
uint8_t raw[24];
|
||||
|
||||
bootloader_fill_random(buf, sizeof(buf));
|
||||
|
||||
ESP_LOGV(TAG, "Writing random values to address 0x%08x", blk_wdata0_reg);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ESP_LOGV(TAG, "EFUSE_BLKx_WDATA%d_REG = 0x%08x", i, buf[i]);
|
||||
REG_WRITE(blk_wdata0_reg + 4 * i, buf[i]);
|
||||
}
|
||||
bzero(buf, sizeof(buf));
|
||||
bzero(raw, sizeof(raw));
|
||||
}
|
||||
|
||||
esp_err_t esp_efuse_disable_rom_download_mode(void)
|
||||
{
|
||||
return esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MODE);
|
||||
|
@ -78,6 +78,9 @@ void esp_efuse_utility_burn_efuses(void)
|
||||
virt_blocks[num_block][subblock++] |= REG_READ(addr_wr_block);
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_utility_write_efuses_to_flash();
|
||||
#endif
|
||||
#else
|
||||
if (esp_efuse_set_timing() != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Efuse fields are not burnt");
|
||||
|
@ -57,6 +57,25 @@ typedef enum {
|
||||
EFUSE_CODING_SCHEME_RS = 3, /**< Reed-Solomon coding */
|
||||
} esp_efuse_coding_scheme_t;
|
||||
|
||||
/**
|
||||
* @brief Type of key purpose
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_EFUSE_KEY_PURPOSE_USER = 0, /**< User purposes (software-only use) */
|
||||
ESP_EFUSE_KEY_PURPOSE_RESERVED = 1, /**< Reserved */
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1 = 2, /**< XTS_AES_256_KEY_1 (flash/PSRAM encryption) */
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2 = 3, /**< XTS_AES_256_KEY_2 (flash/PSRAM encryption) */
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY = 4, /**< XTS_AES_128_KEY (flash/PSRAM encryption) */
|
||||
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL = 5, /**< HMAC Downstream mode */
|
||||
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG = 6, /**< JTAG soft enable key (uses HMAC Downstream mode) */
|
||||
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE = 7, /**< Digital Signature peripheral key (uses HMAC Downstream mode) */
|
||||
ESP_EFUSE_KEY_PURPOSE_HMAC_UP = 8, /**< HMAC Upstream mode */
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0 = 9, /**< SECURE_BOOT_DIGEST0 (Secure Boot key digest) */
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1 = 10, /**< SECURE_BOOT_DIGEST1 (Secure Boot key digest) */
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2 = 11, /**< SECURE_BOOT_DIGEST2 (Secure Boot key digest) */
|
||||
ESP_EFUSE_KEY_PURPOSE_MAX, /**< MAX PURPOSE */
|
||||
} esp_efuse_purpose_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "bootloader_random.h"
|
||||
#include "sys/param.h"
|
||||
|
||||
const static char *TAG = "efuse";
|
||||
static __attribute__((unused)) const char *TAG = "efuse";
|
||||
|
||||
// Contains functions that provide access to efuse fields which are often used in IDF.
|
||||
|
||||
@ -37,22 +37,6 @@ uint32_t esp_efuse_get_pkg_ver(void)
|
||||
return pkg_ver;
|
||||
}
|
||||
|
||||
void esp_efuse_write_random_key(uint32_t blk_wdata0_reg)
|
||||
{
|
||||
uint32_t buf[8];
|
||||
uint8_t raw[24];
|
||||
|
||||
bootloader_fill_random(buf, sizeof(buf));
|
||||
|
||||
ESP_LOGV(TAG, "Writing random values to address 0x%08x", blk_wdata0_reg);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ESP_LOGV(TAG, "EFUSE_BLKx_WDATA%d_REG = 0x%08x", i, buf[i]);
|
||||
REG_WRITE(blk_wdata0_reg + 4 * i, buf[i]);
|
||||
}
|
||||
bzero(buf, sizeof(buf));
|
||||
bzero(raw, sizeof(raw));
|
||||
}
|
||||
|
||||
esp_err_t esp_efuse_disable_rom_download_mode(void)
|
||||
{
|
||||
return esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MODE);
|
||||
|
@ -78,6 +78,9 @@ void esp_efuse_utility_burn_efuses(void)
|
||||
virt_blocks[num_block][subblock++] |= REG_READ(addr_wr_block);
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_utility_write_efuses_to_flash();
|
||||
#endif
|
||||
#else
|
||||
if (esp_efuse_set_timing() != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Efuse fields are not burnt");
|
||||
|
@ -57,6 +57,25 @@ typedef enum {
|
||||
EFUSE_CODING_SCHEME_RS = 3, /**< Reed-Solomon coding */
|
||||
} esp_efuse_coding_scheme_t;
|
||||
|
||||
/**
|
||||
* @brief Type of key purpose
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_EFUSE_KEY_PURPOSE_USER = 0, /**< User purposes (software-only use) */
|
||||
ESP_EFUSE_KEY_PURPOSE_RESERVED = 1, /**< Reserved */
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1 = 2, /**< XTS_AES_256_KEY_1 (flash/PSRAM encryption) */
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2 = 3, /**< XTS_AES_256_KEY_2 (flash/PSRAM encryption) */
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY = 4, /**< XTS_AES_128_KEY (flash/PSRAM encryption) */
|
||||
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL = 5, /**< HMAC Downstream mode */
|
||||
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG = 6, /**< JTAG soft enable key (uses HMAC Downstream mode) */
|
||||
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE = 7, /**< Digital Signature peripheral key (uses HMAC Downstream mode) */
|
||||
ESP_EFUSE_KEY_PURPOSE_HMAC_UP = 8, /**< HMAC Upstream mode */
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0 = 9, /**< SECURE_BOOT_DIGEST0 (Secure Boot key digest) */
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1 = 10, /**< SECURE_BOOT_DIGEST1 (Secure Boot key digest) */
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2 = 11, /**< SECURE_BOOT_DIGEST2 (Secure Boot key digest) */
|
||||
ESP_EFUSE_KEY_PURPOSE_MAX, /**< MAX PURPOSE */
|
||||
} esp_efuse_purpose_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -17,6 +17,16 @@ extern "C" {
|
||||
#include "sdkconfig.h"
|
||||
#include_next "esp_efuse.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "esp32/rom/secure_boot.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/secure_boot.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/rom/secure_boot.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp32s3/rom/secure_boot.h"
|
||||
#endif
|
||||
|
||||
#define ESP_ERR_EFUSE 0x1600 /*!< Base error code for efuse api. */
|
||||
#define ESP_OK_EFUSE_CNT (ESP_ERR_EFUSE + 0x01) /*!< OK the required number of bits is set. */
|
||||
#define ESP_ERR_EFUSE_CNT_IS_FULL (ESP_ERR_EFUSE + 0x02) /*!< Error field is full. */
|
||||
@ -275,27 +285,6 @@ uint8_t esp_efuse_get_chip_ver(void);
|
||||
*/
|
||||
uint32_t esp_efuse_get_pkg_ver(void);
|
||||
|
||||
/**
|
||||
* @brief Permanently update values written to the efuse write registers
|
||||
*
|
||||
* After updating EFUSE_BLKx_WDATAx_REG registers with new values to
|
||||
* write, call this function to permanently write them to efuse.
|
||||
*
|
||||
* @note Setting bits in efuse is permanent, they cannot be unset.
|
||||
*
|
||||
* @note Due to this restriction you don't need to copy values to
|
||||
* Efuse write registers from the matching read registers, bits which
|
||||
* are set in the read register but unset in the matching write
|
||||
* register will be unchanged when new values are burned.
|
||||
*
|
||||
* @note This function is not threadsafe, if calling code updates
|
||||
* efuse values from multiple tasks then this is caller's
|
||||
* responsibility to serialise.
|
||||
*
|
||||
* After burning new efuses, the read registers are updated to match
|
||||
* the new efuse values.
|
||||
*/
|
||||
void esp_efuse_burn_new_values(void);
|
||||
|
||||
/**
|
||||
* @brief Reset efuse write registers
|
||||
@ -374,24 +363,6 @@ esp_err_t esp_efuse_set_rom_log_scheme(esp_efuse_rom_log_scheme_t log_scheme);
|
||||
esp_err_t esp_efuse_enable_rom_secure_download_mode(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Write random data to efuse key block write registers
|
||||
*
|
||||
* @note Caller is responsible for ensuring efuse
|
||||
* block is empty and not write protected, before calling.
|
||||
*
|
||||
* @note Behaviour depends on coding scheme: a 256-bit key is
|
||||
* generated and written for Coding Scheme "None", a 192-bit key
|
||||
* is generated, extended to 256-bits by the Coding Scheme,
|
||||
* and then writtten for 3/4 Coding Scheme.
|
||||
*
|
||||
* @note This function does not burn the new values, caller should
|
||||
* call esp_efuse_burn_new_values() when ready to do this.
|
||||
*
|
||||
* @param blk_wdata0_reg Address of the first data write register
|
||||
* in the block
|
||||
*/
|
||||
void esp_efuse_write_random_key(uint32_t blk_wdata0_reg);
|
||||
|
||||
/**
|
||||
* @brief Return secure_version from efuse field.
|
||||
@ -422,16 +393,28 @@ bool esp_efuse_check_secure_version(uint32_t secure_version);
|
||||
*/
|
||||
esp_err_t esp_efuse_update_secure_version(uint32_t secure_version);
|
||||
|
||||
#if defined(BOOTLOADER_BUILD) && defined(CONFIG_EFUSE_VIRTUAL) && !defined(CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH)
|
||||
/**
|
||||
* @brief Initializes eFuses API to keep eFuses in RAM.
|
||||
*
|
||||
* This function just copies all eFuses to RAM. IDF eFuse APIs perform all operators with RAM instead of real eFuse.
|
||||
* (Used only in bootloader).
|
||||
*/
|
||||
void esp_efuse_init_virtual_mode_in_ram(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
/**
|
||||
* @brief Initializes variables: offset and size to simulate the work of an eFuse.
|
||||
*
|
||||
* Note: To simulate the work of an eFuse need to set CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE option
|
||||
* Note: To simulate the work of an eFuse need to set CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH option
|
||||
* and to add in the partition.csv file a line `efuse_em, data, efuse, , 0x2000,`.
|
||||
*
|
||||
* @param[in] offset The starting address of the partition where the eFuse data will be located.
|
||||
* @param[in] size The size of the partition.
|
||||
*/
|
||||
void esp_efuse_init(uint32_t offset, uint32_t size);
|
||||
void esp_efuse_init_virtual_mode_in_flash(uint32_t offset, uint32_t size);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Set the batch mode of writing fields.
|
||||
@ -573,28 +556,44 @@ esp_err_t esp_efuse_set_key_dis_write(esp_efuse_block_t block);
|
||||
*/
|
||||
bool esp_efuse_key_block_unused(esp_efuse_block_t block);
|
||||
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32
|
||||
/**
|
||||
* @brief Find a key block with the particular purpose set.
|
||||
*
|
||||
* @param[in] purpose Purpose to search for.
|
||||
* @param[out] block Pointer in the range EFUSE_BLK_KEY0..EFUSE_BLK_KEY_MAX which will be set to the key block if found.
|
||||
* Can be NULL, if only need to test the key block exists.
|
||||
*
|
||||
* @return
|
||||
* - True: If found,
|
||||
* - False: If not found (value at block pointer is unchanged).
|
||||
*/
|
||||
bool esp_efuse_find_purpose(esp_efuse_purpose_t purpose, esp_efuse_block_t *block);
|
||||
|
||||
/**
|
||||
* @brief Type of key purpose
|
||||
* @brief Returns a write protection of the key purpose field for an efuse key block.
|
||||
*
|
||||
* @param[in] block A key block in the range EFUSE_BLK_KEY0..EFUSE_BLK_KEY_MAX
|
||||
*
|
||||
* @note For ESP32: no keypurpose, it returns always True.
|
||||
*
|
||||
* @return True: The key purpose is write protected.
|
||||
* False: The key purpose is writeable.
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_EFUSE_KEY_PURPOSE_USER = 0,
|
||||
ESP_EFUSE_KEY_PURPOSE_RESERVED = 1,
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1 = 2,
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2 = 3,
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY = 4,
|
||||
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL = 5,
|
||||
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG = 6,
|
||||
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE = 7,
|
||||
ESP_EFUSE_KEY_PURPOSE_HMAC_UP = 8,
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0 = 9,
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1 = 10,
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2 = 11,
|
||||
ESP_EFUSE_KEY_PURPOSE_MAX,
|
||||
} esp_efuse_purpose_t;
|
||||
bool esp_efuse_get_keypurpose_dis_write(esp_efuse_block_t block);
|
||||
|
||||
/**
|
||||
* @brief Returns the current purpose set for an efuse key block.
|
||||
*
|
||||
* @param[in] block A key block in the range EFUSE_BLK_KEY0..EFUSE_BLK_KEY_MAX
|
||||
*
|
||||
* @return
|
||||
* - Value: If Successful, it returns the value of the purpose related to the given key block.
|
||||
* - ESP_EFUSE_KEY_PURPOSE_MAX: Otherwise.
|
||||
*/
|
||||
esp_efuse_purpose_t esp_efuse_get_key_purpose(esp_efuse_block_t block);
|
||||
|
||||
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32
|
||||
/**
|
||||
* @brief Returns a pointer to a key purpose for an efuse key block.
|
||||
*
|
||||
@ -615,17 +614,6 @@ const esp_efuse_desc_t **esp_efuse_get_purpose_field(esp_efuse_block_t block);
|
||||
*/
|
||||
const esp_efuse_desc_t** esp_efuse_get_key(esp_efuse_block_t block);
|
||||
|
||||
/**
|
||||
* @brief Returns the current purpose set for an efuse key block.
|
||||
*
|
||||
* @param[in] block A key block in the range EFUSE_BLK_KEY0..EFUSE_BLK_KEY_MAX
|
||||
*
|
||||
* @return
|
||||
* - Value: If Successful, it returns the value of the purpose related to the given key block.
|
||||
* - ESP_EFUSE_KEY_PURPOSE_MAX: Otherwise.
|
||||
*/
|
||||
esp_efuse_purpose_t esp_efuse_get_key_purpose(esp_efuse_block_t block);
|
||||
|
||||
/**
|
||||
* @brief Sets a key purpose for an efuse key block.
|
||||
*
|
||||
@ -640,16 +628,6 @@ esp_efuse_purpose_t esp_efuse_get_key_purpose(esp_efuse_block_t block);
|
||||
*/
|
||||
esp_err_t esp_efuse_set_key_purpose(esp_efuse_block_t block, esp_efuse_purpose_t purpose);
|
||||
|
||||
/**
|
||||
* @brief Returns a write protection of the key purpose field for an efuse key block.
|
||||
*
|
||||
* @param[in] block A key block in the range EFUSE_BLK_KEY0..EFUSE_BLK_KEY_MAX
|
||||
*
|
||||
* @return True: The key purpose is write protected.
|
||||
* False: The key purpose is writeable.
|
||||
*/
|
||||
bool esp_efuse_get_keypurpose_dis_write(esp_efuse_block_t block);
|
||||
|
||||
/**
|
||||
* @brief Sets a write protection of the key purpose field for an efuse key block.
|
||||
*
|
||||
@ -663,19 +641,6 @@ bool esp_efuse_get_keypurpose_dis_write(esp_efuse_block_t block);
|
||||
*/
|
||||
esp_err_t esp_efuse_set_keypurpose_dis_write(esp_efuse_block_t block);
|
||||
|
||||
/**
|
||||
* @brief Find a key block with the particular purpose set.
|
||||
*
|
||||
* @param[in] purpose Purpose to search for.
|
||||
* @param[out] block Pointer in the range EFUSE_BLK_KEY0..EFUSE_BLK_KEY_MAX which will be set to the key block if found.
|
||||
* Can be NULL, if only need to test the key block exists.
|
||||
*
|
||||
* @return
|
||||
* - True: If found,
|
||||
* - False: If not found (value at block pointer is unchanged).
|
||||
*/
|
||||
bool esp_efuse_find_purpose(esp_efuse_purpose_t purpose, esp_efuse_block_t *block);
|
||||
|
||||
/**
|
||||
* @brief Search for an unused key block and return the first one found.
|
||||
*
|
||||
@ -737,6 +702,8 @@ bool esp_efuse_get_write_protect_of_digest_revoke(unsigned num_digest);
|
||||
*/
|
||||
esp_err_t esp_efuse_set_write_protect_of_digest_revoke(unsigned num_digest);
|
||||
|
||||
#endif // not CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
/**
|
||||
* @brief Program a block of key data to an efuse block
|
||||
*
|
||||
@ -773,9 +740,21 @@ esp_err_t esp_efuse_write_key(esp_efuse_block_t block, esp_efuse_purpose_t purpo
|
||||
* - ESP_ERR_EFUSE_REPEATED_PROG: Error repeated programming of programmed bits is strictly forbidden.
|
||||
* - ESP_ERR_CODING: Error range of data does not match the coding scheme.
|
||||
*/
|
||||
esp_err_t esp_efuse_write_keys(esp_efuse_purpose_t purposes[], uint8_t keys[][32], unsigned number_of_keys);
|
||||
esp_err_t esp_efuse_write_keys(const esp_efuse_purpose_t purposes[], uint8_t keys[][32], unsigned number_of_keys);
|
||||
|
||||
#endif // not CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
#if CONFIG_ESP32_REV_MIN_3 || !CONFIG_IDF_TARGET_ESP32
|
||||
/**
|
||||
* @brief Read key digests from efuse. Any revoked/missing digests will be marked as NULL
|
||||
*
|
||||
* @param[out] trusted_keys The number of digest in range 0..2
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Successful.
|
||||
* - ESP_FAIL: If trusted_keys is NULL or there is no valid digest.
|
||||
*/
|
||||
esp_err_t esp_secure_boot_read_key_digests(ets_secure_boot_key_digests_t *trusted_keys);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -17,6 +17,14 @@ extern "C" {
|
||||
#include "sdkconfig.h"
|
||||
#include_next "esp_efuse_utility.h"
|
||||
|
||||
#define ESP_EFUSE_CHK(ret) \
|
||||
do \
|
||||
{ \
|
||||
if( ( err = (ret) ) != ESP_OK ) \
|
||||
goto err_exit; \
|
||||
} while( 0 )
|
||||
|
||||
|
||||
/**
|
||||
* @brief Structure range address by blocks
|
||||
*/
|
||||
@ -139,6 +147,38 @@ esp_err_t esp_efuse_utility_apply_new_coding_scheme(void);
|
||||
*/
|
||||
void esp_efuse_utility_clear_program_registers(void);
|
||||
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
/**
|
||||
* @brief Writes eFuses to the efuse flash partition.
|
||||
*
|
||||
* Used only when CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH is set.
|
||||
*/
|
||||
void esp_efuse_utility_write_efuses_to_flash(void);
|
||||
|
||||
/**
|
||||
* @brief Loads efuses from efuse flash partition.
|
||||
*
|
||||
* Used only when CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH is set.
|
||||
*/
|
||||
bool esp_efuse_utility_load_efuses_from_flash(void);
|
||||
|
||||
/**
|
||||
* @brief Erase efuse flash partition.
|
||||
*
|
||||
* Used only when CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH is set.
|
||||
*/
|
||||
void esp_efuse_utility_erase_efuses_in_flash(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Return the address of a particular efuse block's first read register
|
||||
*
|
||||
* @param[in] block Index of efuse block to look up
|
||||
*
|
||||
* @return a numeric read register address of the first word in the block.
|
||||
*/
|
||||
uint32_t esp_efuse_utility_get_read_register_address(esp_efuse_block_t block);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -104,8 +104,7 @@ esp_err_t esp_efuse_set_key_dis_read(esp_efuse_block_t block)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
unsigned idx = block - EFUSE_BLK_KEY0;
|
||||
const uint8_t one = 1;
|
||||
return esp_efuse_write_field_blob(s_table[idx].key_rd_dis, &one, 1);
|
||||
return esp_efuse_write_field_bit(s_table[idx].key_rd_dis);
|
||||
}
|
||||
|
||||
bool esp_efuse_get_key_dis_write(esp_efuse_block_t block)
|
||||
@ -121,8 +120,7 @@ esp_err_t esp_efuse_set_key_dis_write(esp_efuse_block_t block)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
unsigned idx = block - EFUSE_BLK_KEY0;
|
||||
const uint8_t one = 1;
|
||||
return esp_efuse_write_field_blob(s_table[idx].key_wr_dis, &one, 1);
|
||||
return esp_efuse_write_field_bit(s_table[idx].key_wr_dis);
|
||||
}
|
||||
|
||||
bool esp_efuse_key_block_unused(esp_efuse_block_t block)
|
||||
@ -138,3 +136,110 @@ bool esp_efuse_key_block_unused(esp_efuse_block_t block)
|
||||
|
||||
return true; // Unused
|
||||
}
|
||||
|
||||
esp_efuse_purpose_t esp_efuse_get_key_purpose(esp_efuse_block_t block)
|
||||
{
|
||||
esp_efuse_purpose_t ret_purpose;
|
||||
if (block == EFUSE_BLK0) {
|
||||
ret_purpose = ESP_EFUSE_KEY_PURPOSE_SYSTEM;
|
||||
} else if (block == EFUSE_BLK_ENCRYPT_FLASH) {
|
||||
ret_purpose = ESP_EFUSE_KEY_PURPOSE_FLASH_ENCRYPTION;
|
||||
} else if (block == EFUSE_BLK_SECURE_BOOT) {
|
||||
ret_purpose = ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_V2;
|
||||
} else if (block == EFUSE_BLK3) {
|
||||
ret_purpose = ESP_EFUSE_KEY_PURPOSE_USER;
|
||||
} else {
|
||||
ret_purpose = ESP_EFUSE_KEY_PURPOSE_MAX;
|
||||
}
|
||||
return ret_purpose;
|
||||
}
|
||||
|
||||
bool esp_efuse_get_keypurpose_dis_write(esp_efuse_block_t block)
|
||||
{
|
||||
(void)block;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool esp_efuse_find_purpose(esp_efuse_purpose_t purpose, esp_efuse_block_t *block)
|
||||
{
|
||||
esp_efuse_block_t dummy;
|
||||
if (block == NULL) {
|
||||
block = &dummy;
|
||||
}
|
||||
|
||||
for (esp_efuse_block_t b = EFUSE_BLK_KEY0; b < EFUSE_BLK_KEY_MAX; b++) {
|
||||
if (esp_efuse_get_key_purpose(b) == purpose) {
|
||||
*block = b;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_err_t esp_efuse_write_key(esp_efuse_block_t block, esp_efuse_purpose_t purpose, const void *key, size_t key_size_bytes)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX || key_size_bytes > 32 || purpose >= ESP_EFUSE_KEY_PURPOSE_MAX
|
||||
|| esp_efuse_get_key_purpose(block) != purpose) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_efuse_batch_write_begin();
|
||||
|
||||
if (!esp_efuse_key_block_unused(block)) {
|
||||
err = ESP_ERR_INVALID_STATE;
|
||||
} else {
|
||||
ESP_EFUSE_CHK(esp_efuse_write_block(block, key, 0, key_size_bytes * 8));
|
||||
ESP_EFUSE_CHK(esp_efuse_set_key_dis_write(block));
|
||||
if (purpose == ESP_EFUSE_KEY_PURPOSE_FLASH_ENCRYPTION) {
|
||||
ESP_EFUSE_CHK(esp_efuse_set_key_dis_read(block));
|
||||
}
|
||||
return esp_efuse_batch_write_commit();
|
||||
}
|
||||
err_exit:
|
||||
esp_efuse_batch_write_cancel();
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_efuse_write_keys(const esp_efuse_purpose_t purposes[], uint8_t keys[][32], unsigned number_of_keys)
|
||||
{
|
||||
esp_err_t err = ESP_FAIL;
|
||||
if (number_of_keys == 0 || number_of_keys > (EFUSE_BLK_KEY_MAX - EFUSE_BLK_KEY0) || keys == NULL || purposes == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
size_t key_size = 32;
|
||||
esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK_KEY0);
|
||||
if (coding_scheme == EFUSE_CODING_SCHEME_3_4) {
|
||||
key_size = 24;
|
||||
}
|
||||
esp_efuse_purpose_t purpose = 0;
|
||||
esp_efuse_block_t block = EFUSE_BLK_KEY0;
|
||||
|
||||
esp_efuse_batch_write_begin();
|
||||
for (unsigned i_key = 0; (block < EFUSE_BLK_KEY_MAX) && (i_key < number_of_keys); block++) {
|
||||
purpose = purposes[i_key];
|
||||
if (esp_efuse_get_key_purpose(block) == purpose) {
|
||||
ESP_LOGI(TAG, "Writing EFUSE_BLK_KEY%d with purpose %d", block - EFUSE_BLK_KEY0, purpose);
|
||||
ESP_EFUSE_CHK(esp_efuse_write_key(block, purpose, keys[i_key], key_size));
|
||||
i_key++;
|
||||
}
|
||||
}
|
||||
return esp_efuse_batch_write_commit();
|
||||
err_exit:
|
||||
ESP_LOGE(TAG, "Failed to write EFUSE_BLK_KEY%d with purpose %d. Can't continue.", block - EFUSE_BLK_KEY0, purpose);
|
||||
esp_efuse_batch_write_cancel();
|
||||
return err;
|
||||
}
|
||||
|
||||
#if CONFIG_ESP32_REV_MIN_3
|
||||
esp_err_t esp_secure_boot_read_key_digests(ets_secure_boot_key_digests_t *trusted_keys)
|
||||
{
|
||||
if (trusted_keys == NULL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
trusted_keys->key_digests[0] = (const void *)esp_efuse_utility_get_read_register_address(EFUSE_BLK_SECURE_BOOT);
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif // CONFIG_ESP32_REV_MIN_3
|
||||
|
@ -27,6 +27,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
const esp_efuse_desc_t** revoke;
|
||||
const esp_efuse_desc_t** revoke_wr_dis;
|
||||
const esp_efuse_purpose_t digest_purpose;
|
||||
} esp_efuse_revokes_t;
|
||||
|
||||
const esp_efuse_keys_t s_table[EFUSE_BLK_KEY_MAX - EFUSE_BLK_KEY0] = {
|
||||
@ -42,19 +43,11 @@ const esp_efuse_keys_t s_table[EFUSE_BLK_KEY_MAX - EFUSE_BLK_KEY0] = {
|
||||
};
|
||||
|
||||
const esp_efuse_revokes_t s_revoke_table[] = {
|
||||
{ESP_EFUSE_SECURE_BOOT_KEY_REVOKE0, ESP_EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE0},
|
||||
{ESP_EFUSE_SECURE_BOOT_KEY_REVOKE1, ESP_EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE1},
|
||||
{ESP_EFUSE_SECURE_BOOT_KEY_REVOKE2, ESP_EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE2},
|
||||
{ESP_EFUSE_SECURE_BOOT_KEY_REVOKE0, ESP_EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE0, ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0},
|
||||
{ESP_EFUSE_SECURE_BOOT_KEY_REVOKE1, ESP_EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE1, ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1},
|
||||
{ESP_EFUSE_SECURE_BOOT_KEY_REVOKE2, ESP_EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE2, ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2},
|
||||
};
|
||||
|
||||
#define ESP_EFUSE_CHK(ret) \
|
||||
do \
|
||||
{ \
|
||||
if( ( err = (ret) ) != ESP_OK ) \
|
||||
goto err_exit; \
|
||||
} while( 0 )
|
||||
|
||||
|
||||
bool esp_efuse_block_is_empty(esp_efuse_block_t block)
|
||||
{
|
||||
const unsigned blk_len_bit = 256;
|
||||
@ -149,8 +142,7 @@ esp_err_t esp_efuse_set_key_dis_read(esp_efuse_block_t block)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
unsigned idx = block - EFUSE_BLK_KEY0;
|
||||
const uint8_t one = 1;
|
||||
return esp_efuse_write_field_blob(s_table[idx].key_rd_dis, &one, 1);
|
||||
return esp_efuse_write_field_bit(s_table[idx].key_rd_dis);
|
||||
}
|
||||
|
||||
bool esp_efuse_get_key_dis_write(esp_efuse_block_t block)
|
||||
@ -166,8 +158,7 @@ esp_err_t esp_efuse_set_key_dis_write(esp_efuse_block_t block)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
unsigned idx = block - EFUSE_BLK_KEY0;
|
||||
const uint8_t one = 1;
|
||||
return esp_efuse_write_field_blob(s_table[idx].key_wr_dis, &one, 1);
|
||||
return esp_efuse_write_field_bit(s_table[idx].key_wr_dis);
|
||||
}
|
||||
|
||||
esp_efuse_purpose_t esp_efuse_get_key_purpose(esp_efuse_block_t block)
|
||||
@ -206,8 +197,7 @@ esp_err_t esp_efuse_set_keypurpose_dis_write(esp_efuse_block_t block)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
unsigned idx = block - EFUSE_BLK_KEY0;
|
||||
const uint8_t one = 1;
|
||||
return esp_efuse_write_field_blob(s_table[idx].keypurpose_wr_dis, &one, 1);
|
||||
return esp_efuse_write_field_bit(s_table[idx].keypurpose_wr_dis);
|
||||
}
|
||||
|
||||
bool esp_efuse_find_purpose(esp_efuse_purpose_t purpose, esp_efuse_block_t *block)
|
||||
@ -231,7 +221,7 @@ esp_efuse_block_t esp_efuse_find_unused_key_block(void)
|
||||
{
|
||||
for (esp_efuse_block_t b = EFUSE_BLK_KEY0; b < EFUSE_BLK_KEY_MAX; b++) {
|
||||
if (esp_efuse_key_block_unused(b)) {
|
||||
return b;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
return EFUSE_BLK_KEY_MAX; // nothing
|
||||
@ -311,9 +301,11 @@ esp_err_t esp_efuse_write_key(esp_efuse_block_t block, esp_efuse_purpose_t purpo
|
||||
unsigned idx = block - EFUSE_BLK_KEY0;
|
||||
ESP_EFUSE_CHK(esp_efuse_write_field_blob(s_table[idx].key, key, key_size_bytes * 8));
|
||||
ESP_EFUSE_CHK(esp_efuse_set_key_dis_write(block));
|
||||
if (purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1 ||
|
||||
if (purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY ||
|
||||
#ifdef SOC_EFUSE_SUPPORT_XTS_AES_256_KEYS
|
||||
purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1 ||
|
||||
purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2 ||
|
||||
purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY ||
|
||||
#endif
|
||||
purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL ||
|
||||
purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG ||
|
||||
purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE ||
|
||||
@ -329,7 +321,7 @@ err_exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_efuse_write_keys(esp_efuse_purpose_t purposes[], uint8_t keys[][32], unsigned number_of_keys)
|
||||
esp_err_t esp_efuse_write_keys(const esp_efuse_purpose_t purposes[], uint8_t keys[][32], unsigned number_of_keys)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
if (number_of_keys == 0 || number_of_keys > (EFUSE_BLK_KEY_MAX - EFUSE_BLK_KEY0) || keys == NULL || purposes == NULL) {
|
||||
@ -361,3 +353,37 @@ err_exit:
|
||||
esp_efuse_batch_write_cancel();
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_read_key_digests(ets_secure_boot_key_digests_t *trusted_keys)
|
||||
{
|
||||
bool found = false;
|
||||
esp_efuse_block_t key_block;
|
||||
|
||||
if (trusted_keys == NULL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < MAX_KEY_DIGESTS; i++) {
|
||||
trusted_keys->key_digests[i] = NULL;
|
||||
if (esp_efuse_get_digest_revoke(i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Anti-FI check that this efuse really is not revoked
|
||||
assert(esp_efuse_get_digest_revoke(i) == 0);
|
||||
|
||||
if (!esp_efuse_find_purpose(s_revoke_table[i].digest_purpose, &key_block)) {
|
||||
continue;
|
||||
}
|
||||
trusted_keys->key_digests[i] = (const void *)esp_efuse_utility_get_read_register_address(key_block);
|
||||
found = found || (trusted_keys->key_digests[i] != NULL);
|
||||
}
|
||||
|
||||
trusted_keys->allow_key_revoke = false;
|
||||
|
||||
if (!found) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -19,11 +19,12 @@
|
||||
#include "sys/param.h"
|
||||
|
||||
static __attribute__((unused)) const char *TAG = "efuse";
|
||||
// Permanently update values written to the efuse write registers
|
||||
void esp_efuse_burn_new_values(void)
|
||||
{
|
||||
esp_efuse_utility_burn_efuses();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_APP_SEC_VER_SIZE_EFUSE_FIELD
|
||||
#define APP_SEC_VER_SIZE_EFUSE_FIELD CONFIG_BOOTLOADER_APP_SEC_VER_SIZE_EFUSE_FIELD
|
||||
#else
|
||||
#define APP_SEC_VER_SIZE_EFUSE_FIELD 16 // smallest possible size for all chips
|
||||
#endif
|
||||
|
||||
// Reset efuse write registers
|
||||
void esp_efuse_reset(void)
|
||||
@ -31,87 +32,14 @@ void esp_efuse_reset(void)
|
||||
esp_efuse_utility_reset();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE
|
||||
|
||||
#include "../include_bootloader/bootloader_flash_priv.h"
|
||||
#include "esp_flash_encrypt.h"
|
||||
|
||||
static uint32_t esp_efuse_flash_offset = 0;
|
||||
static uint32_t esp_efuse_flash_size = 0;
|
||||
|
||||
void esp_efuse_init(uint32_t offset, uint32_t size)
|
||||
{
|
||||
esp_efuse_flash_offset = offset;
|
||||
esp_efuse_flash_size = size;
|
||||
}
|
||||
|
||||
static uint32_t emulate_secure_version_read(void)
|
||||
{
|
||||
uint32_t secure_version;
|
||||
uint32_t offset = esp_efuse_flash_offset;
|
||||
if (offset == 0) {
|
||||
ESP_LOGE(TAG, "emulate secure_version can not be used");
|
||||
return 0;
|
||||
}
|
||||
const uint32_t *efuse_place_in_flash = bootloader_mmap(offset, esp_efuse_flash_size);
|
||||
if (!efuse_place_in_flash) {
|
||||
ESP_LOGE(TAG, "secure_version can not be read from (0x%x, 0x%x) flash", offset, esp_efuse_flash_size);
|
||||
return 0;
|
||||
}
|
||||
memcpy(&secure_version, efuse_place_in_flash, sizeof(uint32_t));
|
||||
bootloader_munmap(efuse_place_in_flash);
|
||||
secure_version = ~secure_version;
|
||||
ESP_LOGV(TAG, "Read 0x%08x secure_version from flash", secure_version);
|
||||
return secure_version;
|
||||
}
|
||||
|
||||
static void emulate_secure_version_write(uint32_t secure_version)
|
||||
{
|
||||
uint32_t secure_version_wr = ~secure_version;
|
||||
uint32_t offset = esp_efuse_flash_offset;
|
||||
if (offset == 0) {
|
||||
ESP_LOGE(TAG, "emulate secure_version can not be used");
|
||||
return;
|
||||
}
|
||||
esp_err_t err = bootloader_flash_write(offset, &secure_version_wr, sizeof(secure_version_wr), false);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "secure_version can not be written to flash. err = 0x%x", err);
|
||||
}
|
||||
ESP_LOGV(TAG, "Write 0x%08x secure_version into flash", secure_version);
|
||||
}
|
||||
#endif // CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE
|
||||
|
||||
uint32_t esp_efuse_read_secure_version(void)
|
||||
{
|
||||
#ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
uint32_t secure_version = 0;
|
||||
int size = esp_efuse_get_field_size(ESP_EFUSE_SECURE_VERSION);
|
||||
size = MIN(CONFIG_BOOTLOADER_APP_SEC_VER_SIZE_EFUSE_FIELD, size);
|
||||
#ifdef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE
|
||||
secure_version = emulate_secure_version_read();
|
||||
#else
|
||||
size_t size = MIN(APP_SEC_VER_SIZE_EFUSE_FIELD, esp_efuse_get_field_size(ESP_EFUSE_SECURE_VERSION));
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_SECURE_VERSION, &secure_version, size);
|
||||
#endif // CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE
|
||||
|
||||
return __builtin_popcount(secure_version & ((1ULL << size) - 1));
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
static void write_anti_rollback(uint32_t new_bits)
|
||||
{
|
||||
int size = esp_efuse_get_field_size(ESP_EFUSE_SECURE_VERSION);
|
||||
size = MIN(CONFIG_BOOTLOADER_APP_SEC_VER_SIZE_EFUSE_FIELD, size);
|
||||
#ifdef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE
|
||||
emulate_secure_version_write(new_bits);
|
||||
#else
|
||||
esp_efuse_write_field_blob(ESP_EFUSE_SECURE_VERSION, &new_bits, size);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
bool esp_efuse_check_secure_version(uint32_t secure_version)
|
||||
{
|
||||
uint32_t sec_ver_hw = esp_efuse_read_secure_version();
|
||||
@ -120,18 +48,16 @@ bool esp_efuse_check_secure_version(uint32_t secure_version)
|
||||
|
||||
esp_err_t esp_efuse_update_secure_version(uint32_t secure_version)
|
||||
{
|
||||
#ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
if (CONFIG_BOOTLOADER_APP_SEC_VER_SIZE_EFUSE_FIELD < secure_version) {
|
||||
ESP_LOGE(TAG, "Max secure version is %d. Given %d version can not be written.", CONFIG_BOOTLOADER_APP_SEC_VER_SIZE_EFUSE_FIELD, secure_version);
|
||||
size_t size = MIN(APP_SEC_VER_SIZE_EFUSE_FIELD, esp_efuse_get_field_size(ESP_EFUSE_SECURE_VERSION));
|
||||
if (size < secure_version) {
|
||||
ESP_LOGE(TAG, "Max secure version is %d. Given %d version can not be written.", size, secure_version);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
#ifndef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE
|
||||
esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(ESP_EFUSE_SECURE_VERSION_NUM_BLOCK);
|
||||
if (coding_scheme != EFUSE_CODING_SCHEME_NONE) {
|
||||
ESP_LOGE(TAG, "Anti rollback is not supported with any coding scheme.");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
#endif
|
||||
uint32_t sec_ver_hw = esp_efuse_read_secure_version();
|
||||
// If secure_version is the same as in eFuse field than it is ok just go out.
|
||||
if (sec_ver_hw < secure_version) {
|
||||
@ -139,12 +65,11 @@ esp_err_t esp_efuse_update_secure_version(uint32_t secure_version)
|
||||
uint32_t num_bit_app = (1ULL << secure_version) - 1;
|
||||
// Repeated programming of programmed bits is strictly forbidden
|
||||
uint32_t new_bits = num_bit_app - num_bit_hw; // get only new bits
|
||||
write_anti_rollback(new_bits);
|
||||
esp_efuse_write_field_blob(ESP_EFUSE_SECURE_VERSION, &new_bits, size);
|
||||
ESP_LOGI(TAG, "Anti-rollback is set. eFuse field is updated(%d).", secure_version);
|
||||
} else if (sec_ver_hw > secure_version) {
|
||||
ESP_LOGE(TAG, "Anti-rollback is not set. secure_version of app is lower that eFuse field(%d).", sec_ver_hw);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -18,9 +18,14 @@ static const char *TAG = "efuse";
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
uint32_t virt_blocks[EFUSE_BLK_MAX][COUNT_EFUSE_REG_PER_BLOCK];
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
/* Call the update function to seed virtual efuses during initialization */
|
||||
__attribute__((constructor)) void esp_efuse_utility_update_virt_blocks(void);
|
||||
#endif
|
||||
#endif // CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
#endif // NOT BOOTLOADER_BUILD
|
||||
|
||||
#endif // CONFIG_EFUSE_VIRTUAL
|
||||
|
||||
extern const esp_efuse_range_addr_t range_read_addr_blocks[];
|
||||
extern const esp_efuse_range_addr_t range_write_addr_blocks[];
|
||||
@ -149,20 +154,32 @@ void esp_efuse_utility_erase_virt_blocks(void)
|
||||
{
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
memset(virt_blocks, 0, sizeof(virt_blocks));
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_utility_write_efuses_to_flash();
|
||||
#endif
|
||||
#endif // CONFIG_EFUSE_VIRTUAL
|
||||
}
|
||||
|
||||
// Fills the virt_blocks array by values from efuse_Rdata.
|
||||
void esp_efuse_utility_update_virt_blocks(void)
|
||||
{
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
ESP_EARLY_LOGI(TAG, "Loading virtual efuse blocks from real efuses");
|
||||
for (int num_block = EFUSE_BLK0; num_block < EFUSE_BLK_MAX; num_block++) {
|
||||
int subblock = 0;
|
||||
for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4) {
|
||||
virt_blocks[num_block][subblock++] = REG_READ(addr_rd_block);
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
if (!esp_efuse_utility_load_efuses_from_flash()) {
|
||||
#else
|
||||
if (1) {
|
||||
#endif
|
||||
ESP_EARLY_LOGW(TAG, "Loading virtual efuse blocks from real efuses");
|
||||
for (int num_block = EFUSE_BLK0; num_block < EFUSE_BLK_MAX; num_block++) {
|
||||
int subblock = 0;
|
||||
for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4) {
|
||||
virt_blocks[num_block][subblock++] = REG_READ(addr_rd_block);
|
||||
}
|
||||
ESP_EARLY_LOGD(TAG, "virt_blocks[%d] is filled by EFUSE_BLOCK%d", num_block, num_block);
|
||||
}
|
||||
ESP_EARLY_LOGD(TAG, "virt_blocks[%d] is filled by EFUSE_BLOCK%d", num_block, num_block);
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_utility_write_efuses_to_flash();
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
ESP_EARLY_LOGI(TAG, "Emulate efuse is disabled");
|
||||
@ -170,31 +187,29 @@ void esp_efuse_utility_update_virt_blocks(void)
|
||||
}
|
||||
|
||||
// Prints efuse values for all registers.
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
void esp_efuse_utility_debug_dump_blocks(void)
|
||||
{
|
||||
printf("EFUSE_BLKx:\n");
|
||||
esp_rom_printf("EFUSE_BLKx:\n");
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
for (int num_block = EFUSE_BLK0; num_block < EFUSE_BLK_MAX; num_block++) {
|
||||
int num_reg = 0;
|
||||
printf("%d) ", num_block);
|
||||
esp_rom_printf("%d) ", num_block);
|
||||
for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4, num_reg++) {
|
||||
printf("0x%08x ", virt_blocks[num_block][num_reg]);
|
||||
esp_rom_printf("0x%08x ", virt_blocks[num_block][num_reg]);
|
||||
}
|
||||
printf("\n");
|
||||
esp_rom_printf("\n");
|
||||
}
|
||||
#else
|
||||
for (int num_block = EFUSE_BLK0; num_block < EFUSE_BLK_MAX; num_block++) {
|
||||
printf("%d) ", num_block);
|
||||
esp_rom_printf("%d) ", num_block);
|
||||
for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4) {
|
||||
printf("0x%08x ", REG_READ(addr_rd_block));
|
||||
esp_rom_printf("0x%08x ", REG_READ(addr_rd_block));
|
||||
}
|
||||
printf("\n");
|
||||
esp_rom_printf("\n");
|
||||
}
|
||||
#endif
|
||||
printf("\n");
|
||||
esp_rom_printf("\n");
|
||||
}
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
// returns the number of array elements for placing these bits in an array with the length of each element equal to size_of_base.
|
||||
int esp_efuse_utility_get_number_of_items(int bits, int size_of_base)
|
||||
@ -345,3 +360,94 @@ static bool check_range_of_bits(esp_efuse_block_t blk, int offset_in_bits, int s
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t esp_efuse_utility_get_read_register_address(esp_efuse_block_t block)
|
||||
{
|
||||
assert(block < EFUSE_BLK_MAX);
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
return (uint32_t)&virt_blocks[block][0];
|
||||
#else
|
||||
return range_read_addr_blocks[block].start;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if defined(BOOTLOADER_BUILD) && defined(CONFIG_EFUSE_VIRTUAL) && !defined(CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH)
|
||||
void esp_efuse_init_virtual_mode_in_ram(void)
|
||||
{
|
||||
esp_efuse_utility_update_virt_blocks();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
|
||||
#include "../include_bootloader/bootloader_flash_priv.h"
|
||||
|
||||
static uint32_t esp_efuse_flash_offset = 0;
|
||||
static uint32_t esp_efuse_flash_size = 0;
|
||||
|
||||
void esp_efuse_init_virtual_mode_in_flash(uint32_t offset, uint32_t size)
|
||||
{
|
||||
esp_efuse_flash_offset = offset;
|
||||
esp_efuse_flash_size = size;
|
||||
esp_efuse_utility_update_virt_blocks();
|
||||
esp_efuse_utility_debug_dump_blocks();
|
||||
}
|
||||
|
||||
void esp_efuse_utility_erase_efuses_in_flash(void)
|
||||
{
|
||||
if (esp_efuse_flash_offset == 0) {
|
||||
ESP_EARLY_LOGE(TAG, "no efuse partition in partition_table? (Flash is not updated)");
|
||||
abort();
|
||||
}
|
||||
esp_err_t err = bootloader_flash_erase_range(esp_efuse_flash_offset, esp_efuse_flash_size);
|
||||
if (err != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to erase flash. err = 0x%x", err);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
bool esp_efuse_utility_load_efuses_from_flash(void)
|
||||
{
|
||||
if (esp_efuse_flash_offset == 0) {
|
||||
ESP_EARLY_LOGE(TAG, "no efuse partition in partition_table? (Flash is not updated)");
|
||||
abort();
|
||||
}
|
||||
uint32_t efuses_in_flash[sizeof(virt_blocks)];
|
||||
|
||||
esp_err_t err = bootloader_flash_read(esp_efuse_flash_offset, &efuses_in_flash, sizeof(efuses_in_flash), true);
|
||||
if (err != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Can not read eFuse partition from flash (err=0x%x)", err);
|
||||
abort();
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < sizeof(virt_blocks); ++i) {
|
||||
if (efuses_in_flash[i] != 0xFFFFFFFF) {
|
||||
ESP_EARLY_LOGW(TAG, "Loading virtual efuse blocks from flash");
|
||||
memcpy(virt_blocks, efuses_in_flash, sizeof(virt_blocks));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void esp_efuse_utility_write_efuses_to_flash(void)
|
||||
{
|
||||
if (esp_efuse_flash_offset == 0) {
|
||||
ESP_EARLY_LOGE(TAG, "no efuse partition in partition_table? (Flash is not updated)");
|
||||
abort();
|
||||
}
|
||||
|
||||
esp_err_t err = bootloader_flash_erase_range(esp_efuse_flash_offset, esp_efuse_flash_size);
|
||||
if (err != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to erase flash. err = 0x%x", err);
|
||||
abort();
|
||||
}
|
||||
|
||||
err = bootloader_flash_write(esp_efuse_flash_offset, &virt_blocks, sizeof(virt_blocks), false);
|
||||
if (err != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "secure_version can not be written to flash. err = 0x%x", err);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
|
@ -61,9 +61,11 @@ static esp_err_t s_check_key(esp_efuse_block_t num_key, void* wr_key)
|
||||
#endif // not CONFIG_IDF_ENV_FPGA
|
||||
|
||||
TEST_ASSERT_TRUE(esp_efuse_get_key_dis_write(num_key));
|
||||
if (purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1 ||
|
||||
if (purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY ||
|
||||
#ifdef SOC_EFUSE_SUPPORT_XTS_AES_256_KEYS
|
||||
purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1 ||
|
||||
purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2 ||
|
||||
purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY ||
|
||||
#endif
|
||||
purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL ||
|
||||
purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG ||
|
||||
purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE ||
|
||||
@ -147,8 +149,13 @@ TEST_CASE("Test 1 esp_efuse_write_key for FPGA", "[efuse]")
|
||||
esp_efuse_purpose_t purpose [] = {
|
||||
ESP_EFUSE_KEY_PURPOSE_USER,
|
||||
ESP_EFUSE_KEY_PURPOSE_RESERVED,
|
||||
#ifdef SOC_EFUSE_SUPPORT_XTS_AES_256_KEYS
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1,
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2,
|
||||
#else
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY,
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY,
|
||||
#endif
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY,
|
||||
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL,
|
||||
};
|
||||
@ -210,10 +217,17 @@ TEST_CASE("Test esp_efuse_write_keys", "[efuse]")
|
||||
esp_efuse_block_t key_block = EFUSE_BLK_MAX;
|
||||
|
||||
enum { BLOCKS_NEEDED1 = 2 };
|
||||
#ifdef SOC_EFUSE_SUPPORT_XTS_AES_256_KEYS
|
||||
esp_efuse_purpose_t purpose1[BLOCKS_NEEDED1] = {
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1,
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2,
|
||||
};
|
||||
#else
|
||||
esp_efuse_purpose_t purpose1[BLOCKS_NEEDED1] = {
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY,
|
||||
ESP_EFUSE_KEY_PURPOSE_RESERVED
|
||||
};
|
||||
#endif
|
||||
uint8_t keys1[BLOCKS_NEEDED1][32] = {{0xEE}};
|
||||
|
||||
for (int num_key = 0; num_key < BLOCKS_NEEDED1; ++num_key) {
|
||||
|
@ -282,20 +282,6 @@ static void do_core_init(void)
|
||||
|
||||
esp_err_t err __attribute__((unused));
|
||||
|
||||
#if CONFIG_SECURE_DISABLE_ROM_DL_MODE
|
||||
err = esp_efuse_disable_rom_download_mode();
|
||||
assert(err == ESP_OK && "Failed to disable ROM download mode");
|
||||
#endif
|
||||
|
||||
#if CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
err = esp_efuse_enable_rom_secure_download_mode();
|
||||
assert(err == ESP_OK && "Failed to enable Secure Download mode");
|
||||
#endif
|
||||
|
||||
#if CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE
|
||||
esp_efuse_disable_basic_rom_console();
|
||||
#endif
|
||||
|
||||
// [refactor-todo] move this to secondary init
|
||||
#if CONFIG_APPTRACE_ENABLE
|
||||
err = esp_apptrace_init();
|
||||
@ -321,6 +307,30 @@ static void do_core_init(void)
|
||||
assert(flash_ret == ESP_OK);
|
||||
(void)flash_ret;
|
||||
|
||||
#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!");
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
const esp_partition_t *efuse_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM, NULL);
|
||||
if (efuse_partition) {
|
||||
esp_efuse_init_virtual_mode_in_flash(efuse_partition->address, efuse_partition->size);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if CONFIG_SECURE_DISABLE_ROM_DL_MODE
|
||||
err = esp_efuse_disable_rom_download_mode();
|
||||
assert(err == ESP_OK && "Failed to disable ROM download mode");
|
||||
#endif
|
||||
|
||||
#if CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
err = esp_efuse_enable_rom_secure_download_mode();
|
||||
assert(err == ESP_OK && "Failed to enable Secure Download mode");
|
||||
#endif
|
||||
|
||||
#if CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE
|
||||
esp_efuse_disable_basic_rom_console();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
esp_flash_encryption_init_checks();
|
||||
#endif
|
||||
@ -442,13 +452,6 @@ IRAM_ATTR ESP_SYSTEM_INIT_FN(init_components0, BIT(0))
|
||||
coex_pre_init();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE
|
||||
const esp_partition_t *efuse_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM, NULL);
|
||||
if (efuse_partition) {
|
||||
esp_efuse_init(efuse_partition->address, efuse_partition->size);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
|
||||
ESP_EARLY_LOGD(TAG, "Setting C++ exception workarounds.");
|
||||
_Unwind_SetNoFunctionContextInstall(1);
|
||||
|
@ -15,8 +15,9 @@
|
||||
#define SOC_USB_SERIAL_JTAG_SUPPORTED 1
|
||||
|
||||
/*-------------------------- COMMON CAPS ---------------------------------------*/
|
||||
#define SOC_SUPPORTS_SECURE_DL_MODE 1
|
||||
#define SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS 3
|
||||
#define SOC_SUPPORTS_SECURE_DL_MODE 1
|
||||
#define SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS 3
|
||||
#define SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS 1
|
||||
|
||||
|
||||
/*-------------------------- AES CAPS -----------------------------------------*/
|
||||
|
@ -53,7 +53,7 @@
|
||||
#define SOC_HMAC_SUPPORTED 1
|
||||
#define SOC_ASYNC_MEMCPY_SUPPORTED 1
|
||||
#define SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS 3
|
||||
|
||||
#define SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS 1
|
||||
#define SOC_CACHE_SUPPORT_WRAP 1
|
||||
|
||||
/*-------------------------- ADC CAPS ----------------------------------------*/
|
||||
|
@ -22,6 +22,7 @@
|
||||
#define SOC_ASYNC_MEMCPY_SUPPORTED 1
|
||||
#define SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS 3
|
||||
#define SOC_SDMMC_HOST_SUPPORTED 1
|
||||
#define SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS 1
|
||||
|
||||
|
||||
/*-------------------------- ADC CAPS ----------------------------------------*/
|
||||
|
@ -233,6 +233,16 @@ Access to the fields is via a pointer to the description structure. API function
|
||||
* :cpp:func:`esp_efuse_batch_write_begin` - set the batch mode of writing fields.
|
||||
* :cpp:func:`esp_efuse_batch_write_commit` - writes all prepared data for batch writing mode and reset the batch writing mode.
|
||||
* :cpp:func:`esp_efuse_batch_write_cancel` - reset the batch writing mode and prepared data.
|
||||
* :cpp:func:`esp_efuse_get_key_dis_read` - Returns a read protection for the key block.
|
||||
* :cpp:func:`esp_efuse_set_key_dis_read` - Sets a read protection for the key block.
|
||||
* :cpp:func:`esp_efuse_get_key_dis_write` - Returns a write protection for the key block.
|
||||
* :cpp:func:`esp_efuse_set_key_dis_write` - Sets a write protection for the key block.
|
||||
* :cpp:func:`esp_efuse_get_key_purpose` - Returns the current purpose set for an eFuse key block.
|
||||
* :cpp:func:`esp_efuse_write_key` - Programs a block of key data to an eFuse block
|
||||
* :cpp:func:`esp_efuse_write_keys` - Programs keys to unused eFuse blocks
|
||||
* :cpp:func:`esp_efuse_find_purpose` - Finds a key block with the particular purpose set.
|
||||
* :cpp:func:`esp_efuse_get_keypurpose_dis_write` - Returns a write protection of the key purpose field for an eFuse key block (for esp32 always true).
|
||||
* :cpp:func:`esp_efuse_key_block_unused` - Returns true if the key block is unused, false otherwise.
|
||||
|
||||
For frequently used fields, special functions are made, like this :cpp:func:`esp_efuse_get_chip_ver`, :cpp:func:`esp_efuse_get_pkg_ver`.
|
||||
|
||||
@ -251,24 +261,14 @@ For frequently used fields, special functions are made, like this :cpp:func:`esp
|
||||
|
||||
* :cpp:func:`esp_efuse_get_purpose_field` - Returns a pointer to a key purpose for an eFuse key block.
|
||||
* :cpp:func:`esp_efuse_get_key` - Returns a pointer to a key block.
|
||||
* :cpp:func:`esp_efuse_get_key_dis_read` - Returns a read protection for the key block.
|
||||
* :cpp:func:`esp_efuse_set_key_dis_read` - Sets a read protection for the key block.
|
||||
* :cpp:func:`esp_efuse_get_key_dis_write` - Returns a write protection for the key block.
|
||||
* :cpp:func:`esp_efuse_set_key_dis_write` - Sets a write protection for the key block.
|
||||
* :cpp:func:`esp_efuse_get_key_purpose` - Returns the current purpose set for an eFuse key block.
|
||||
* :cpp:func:`esp_efuse_set_key_purpose` - Sets a key purpose for an eFuse key block.
|
||||
* :cpp:func:`esp_efuse_get_keypurpose_dis_write` - Returns a write protection of the key purpose field for an eFuse key block.
|
||||
* :cpp:func:`esp_efuse_set_keypurpose_dis_write` - Sets a write protection of the key purpose field for an eFuse key block.
|
||||
* :cpp:func:`esp_efuse_find_purpose` - Finds a key block with the particular purpose set.
|
||||
* :cpp:func:`esp_efuse_find_unused_key_block` - Search for an unused key block and return the first one found.
|
||||
* :cpp:func:`esp_efuse_count_unused_key_blocks` - Returns the number of unused eFuse key blocks in the range EFUSE_BLK_KEY0..EFUSE_BLK_KEY_MAX
|
||||
* :cpp:func:`esp_efuse_key_block_unused` - Returns true if the key block is unused, false otherwise.
|
||||
* :cpp:func:`esp_efuse_get_digest_revoke` - Returns the status of the Secure Boot public key digest revocation bit.
|
||||
* :cpp:func:`esp_efuse_set_digest_revoke` - Sets the Secure Boot public key digest revocation bit.
|
||||
* :cpp:func:`esp_efuse_get_write_protect_of_digest_revoke` - Returns a write protection of the Secure Boot public key digest revocation bit.
|
||||
* :cpp:func:`esp_efuse_set_write_protect_of_digest_revoke` - Sets a write protection of the Secure Boot public key digest revocation bit.
|
||||
* :cpp:func:`esp_efuse_write_key` - Programs a block of key data to an eFuse block
|
||||
* :cpp:func:`esp_efuse_write_keys` - Programs keys to unused eFuse blocks
|
||||
|
||||
|
||||
How to add a new field
|
||||
@ -356,6 +356,10 @@ Virtual eFuses
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
The Kconfig option :ref:`CONFIG_EFUSE_VIRTUAL` will virtualize eFuse values inside the eFuse Manager, so writes are emulated and no eFuse values are permanently changed. This can be useful for debugging app and unit tests.
|
||||
During startup, the eFuses are copied to RAM. All eFuse operations (read and write) are performed with RAM instead of the real eFuse registers.
|
||||
|
||||
In addition to the :ref:`CONFIG_EFUSE_VIRTUAL` option there is :ref:`CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH` option that adds a feature to keep eFuses in flash memory. To use this mode the partition_table should have the `efuse` partition. partition.csv: ``"efuse_em, data, efuse, , 0x2000,"``.
|
||||
During startup, the eFuses are copied from flash or, in case if flash is empty, from real eFuse to RAM and then update flash. This option allows keeping eFuses after reboots (possible to test secure_boot and flash_encryption features with this option).
|
||||
|
||||
espefuse.py
|
||||
^^^^^^^^^^^
|
||||
|
@ -7,7 +7,7 @@ This example shows how to use the eFuse API. It demonstrates read and write oper
|
||||
The eFuse is a single bit of non-volatile memory with the restriction that once an eFuse bit is programmed to 1, it can not be reverted to 0.
|
||||
The eFuse fields can be useful to store: device types, serial numbers, some system variables, etc.
|
||||
|
||||
Note that the bits already written cannot be reset to the original state. For debugging purposes, the `CONFIG_EFUSE_VIRTUAL` option is provided. This option will block physical burning. All work happens with an array in RAM.
|
||||
Note that the bits already written cannot be reset to the original state. For debugging purposes, the `CONFIG_EFUSE_VIRTUAL` option is provided. This option will block physical burning. All work happens with an array in RAM. Use `CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH` to keep eFuse changes after reboots.
|
||||
In this example, all write operations are wrapped in `#ifdef CONFIG_EFUSE_VIRTUAL ... # endif` to prevent accidental burn while testing the features.
|
||||
|
||||
## How to use example
|
||||
|
@ -1,16 +1,32 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
import ttfw_idf
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32', 'esp32c3'])
|
||||
def test_examples_efuse(env, extra_data):
|
||||
def erase_field_on_emul_efuse(dut, bit_pos): # type: (ttfw_idf.TinyFW.Env, int) -> None
|
||||
emul_efuse_bin_path = os.path.join(dut.app.binary_path, 'emul_efuse.bin')
|
||||
dut.dump_flash(emul_efuse_bin_path, partition='emul_efuse')
|
||||
|
||||
nbytes, nbits = divmod(bit_pos, 8)
|
||||
with open(emul_efuse_bin_path, 'r+b') as f:
|
||||
f.seek(nbytes, 0)
|
||||
c = f.read(1)
|
||||
toggled = bytes([ord(c) ^ (1 << nbits)])
|
||||
f.seek(-1, 1) # or absolute: f.seek(nbytes, 0)
|
||||
f.write(toggled)
|
||||
|
||||
offs = dut.app.partition_table['emul_efuse']['offset']
|
||||
flash_files = [(offs, emul_efuse_bin_path)]
|
||||
dut.write_flash(flash_files)
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32', 'esp32c3'])
|
||||
def test_examples_efuse(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
|
||||
dut = env.get_dut('efuse', 'examples/system/efuse')
|
||||
dut.start_app()
|
||||
|
||||
dut.expect_all(re.compile(r'example: Coding Scheme (3/4)|(NONE)|(REPEAT)|(RS \(Reed-Solomon coding\))'),
|
||||
'example: read efuse fields',
|
||||
re.compile(r'example: 1. read MAC address: {}'.format(r':'.join((r'[0-9a-f]{2}',) * 6))),
|
||||
@ -34,5 +50,751 @@ def test_examples_efuse(env, extra_data):
|
||||
timeout=30)
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32', 'esp32s2', 'esp32c3'])
|
||||
def test_examples_efuse_with_virt_flash_enc(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
|
||||
dut = env.get_dut('efuse', 'examples/system/efuse', app_config_name='virt_flash_enc')
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut.app.binary_path, 'bootloader', 'bootloader.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
ttfw_idf.log_performance('{}_bootloader_{}_bin_size'.format(dut.app.target, dut.app.config_name), '{}KB'.format(bin_size // 1024))
|
||||
|
||||
print(' - Erase flash')
|
||||
dut.erase_flash()
|
||||
|
||||
print(' - Start app (flash partition_table and app)')
|
||||
dut.start_app_no_enc()
|
||||
dut.expect('Loading virtual efuse blocks from real efuses')
|
||||
dut.expect('Checking flash encryption...')
|
||||
dut.expect('Generating new flash encryption key...')
|
||||
if dut.TARGET == 'esp32':
|
||||
dut.expect('Writing EFUSE_BLK_KEY0 with purpose 2')
|
||||
dut.expect('Setting CRYPT_CONFIG efuse to 0xF')
|
||||
dut.expect('Not disabling UART bootloader encryption')
|
||||
dut.expect('Disable UART bootloader decryption...')
|
||||
dut.expect('Disable UART bootloader MMU cache...')
|
||||
dut.expect('Disable JTAG...')
|
||||
dut.expect('Disable ROM BASIC interpreter fallback...')
|
||||
else:
|
||||
dut.expect('Writing EFUSE_BLK_KEY0 with purpose 4')
|
||||
dut.expect('Not disabling UART bootloader encryption')
|
||||
dut.expect('Disable UART bootloader cache...')
|
||||
dut.expect('Disable JTAG...')
|
||||
dut.expect('bootloader encrypted successfully')
|
||||
dut.expect('partition table encrypted and loaded successfully')
|
||||
dut.expect('Flash encryption completed', timeout=90)
|
||||
dut.expect('Resetting with flash encryption enabled...')
|
||||
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Checking flash encryption...')
|
||||
if dut.TARGET == 'esp32':
|
||||
dut.expect('flash encryption is enabled (3 plaintext flashes left)')
|
||||
else:
|
||||
dut.expect('flash encryption is enabled (1 plaintext flashes left)')
|
||||
|
||||
dut.expect('Flash encryption mode is DEVELOPMENT (not secure)')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32s2'])
|
||||
def test_examples_efuse_with_virt_flash_enc_aes_256(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
|
||||
# Only ESP32-S2 has support AES-256 FLASH_ENCRYPTION key
|
||||
dut = env.get_dut('efuse', 'examples/system/efuse', app_config_name='virt_flash_enc_aes_256')
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut.app.binary_path, 'bootloader', 'bootloader.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
ttfw_idf.log_performance('{}_bootloader_{}_bin_size'.format(dut.app.target, dut.app.config_name), '{}KB'.format(bin_size // 1024))
|
||||
|
||||
print(' - Erase flash')
|
||||
dut.erase_flash()
|
||||
|
||||
print(' - Start app (flash partition_table and app)')
|
||||
dut.start_app_no_enc()
|
||||
dut.expect('Loading virtual efuse blocks from real efuses')
|
||||
dut.expect('Checking flash encryption...')
|
||||
dut.expect('Generating new flash encryption key...')
|
||||
|
||||
dut.expect('Writing EFUSE_BLK_KEY0 with purpose 2')
|
||||
dut.expect('Writing EFUSE_BLK_KEY1 with purpose 3')
|
||||
dut.expect('Not disabling UART bootloader encryption')
|
||||
dut.expect('Disable UART bootloader cache...')
|
||||
dut.expect('Disable JTAG...')
|
||||
|
||||
dut.expect('bootloader encrypted successfully')
|
||||
dut.expect('partition table encrypted and loaded successfully')
|
||||
dut.expect('Flash encryption completed', timeout=90)
|
||||
dut.expect('Resetting with flash encryption enabled...')
|
||||
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Checking flash encryption...')
|
||||
dut.expect('flash encryption is enabled (1 plaintext flashes left)')
|
||||
|
||||
dut.expect('Flash encryption mode is DEVELOPMENT (not secure)')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32', 'esp32s2', 'esp32c3'])
|
||||
def test_examples_efuse_with_virt_flash_enc_pre_loaded(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
|
||||
dut = env.get_dut('efuse', 'examples/system/efuse', app_config_name='virt_flash_enc')
|
||||
|
||||
print(' - Erase flash')
|
||||
dut.erase_flash()
|
||||
|
||||
print(' - Start app (flash partition_table and app)')
|
||||
dut.start_app_no_enc()
|
||||
dut.expect('Loading virtual efuse blocks from real efuses')
|
||||
dut.expect('Flash encryption completed', timeout=90)
|
||||
dut.expect('Resetting with flash encryption enabled...')
|
||||
|
||||
dut.expect('Flash encryption mode is DEVELOPMENT (not secure)')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
if dut.TARGET == 'esp32':
|
||||
print(' - Flash emul_efuse with pre-loaded efuses (FLASH_CRYPT_CNT 1 -> 0)')
|
||||
erase_field_on_emul_efuse(dut, 0 * 32 + 20)
|
||||
else:
|
||||
print(' - Flash emul_efuse with pre-loaded efuses (SPI_BOOT_CRYPT_CNT 1 -> 0)')
|
||||
erase_field_on_emul_efuse(dut, 2 * 32 + 18)
|
||||
|
||||
print(' - Start app (flash partition_table and app)')
|
||||
dut.start_app_no_enc()
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Checking flash encryption...')
|
||||
dut.expect('Using pre-loaded flash encryption key in efuse')
|
||||
if dut.TARGET == 'esp32':
|
||||
dut.expect('Setting CRYPT_CONFIG efuse to 0xF')
|
||||
dut.expect('Not disabling UART bootloader encryption')
|
||||
dut.expect('Disable UART bootloader decryption...')
|
||||
dut.expect('Disable UART bootloader MMU cache...')
|
||||
dut.expect('Disable JTAG...')
|
||||
dut.expect('Disable ROM BASIC interpreter fallback...')
|
||||
else:
|
||||
dut.expect('Not disabling UART bootloader encryption')
|
||||
dut.expect('Disable UART bootloader cache...')
|
||||
dut.expect('Disable JTAG...')
|
||||
dut.expect('bootloader encrypted successfully')
|
||||
dut.expect('partition table encrypted and loaded successfully')
|
||||
dut.expect('Flash encryption completed', timeout=90)
|
||||
dut.expect('Resetting with flash encryption enabled...')
|
||||
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Checking flash encryption...')
|
||||
if dut.TARGET == 'esp32':
|
||||
dut.expect('flash encryption is enabled (3 plaintext flashes left)')
|
||||
else:
|
||||
dut.expect('flash encryption is enabled (1 plaintext flashes left)')
|
||||
|
||||
dut.expect('Flash encryption mode is DEVELOPMENT (not secure)')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32', 'esp32s2', 'esp32c3'])
|
||||
def test_examples_efuse_with_virt_flash_enc_release(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
|
||||
dut = env.get_dut('efuse', 'examples/system/efuse', app_config_name='virt_flash_enc_release')
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut.app.binary_path, 'bootloader', 'bootloader.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
ttfw_idf.log_performance('{}_bootloader_{}_bin_size'.format(dut.app.target, dut.app.config_name), '{}KB'.format(bin_size // 1024))
|
||||
|
||||
print(' - Erase flash')
|
||||
dut.erase_flash()
|
||||
|
||||
print(' - Start app (flash partition_table and app)')
|
||||
dut.start_app_no_enc()
|
||||
dut.expect('Loading virtual efuse blocks from real efuses')
|
||||
dut.expect('Checking flash encryption...')
|
||||
dut.expect('Generating new flash encryption key...')
|
||||
if dut.TARGET == 'esp32':
|
||||
dut.expect('Writing EFUSE_BLK_KEY0 with purpose 2')
|
||||
dut.expect('Setting CRYPT_CONFIG efuse to 0xF')
|
||||
dut.expect('Disable UART bootloader encryption...')
|
||||
dut.expect('Disable UART bootloader decryption...')
|
||||
dut.expect('Disable UART bootloader MMU cache...')
|
||||
dut.expect('Disable JTAG...')
|
||||
dut.expect('Disable ROM BASIC interpreter fallback...')
|
||||
else:
|
||||
dut.expect('Writing EFUSE_BLK_KEY0 with purpose 4')
|
||||
dut.expect('Disable UART bootloader encryption')
|
||||
dut.expect('Disable UART bootloader cache...')
|
||||
dut.expect('Disable JTAG...')
|
||||
dut.expect('bootloader encrypted successfully')
|
||||
dut.expect('partition table encrypted and loaded successfully')
|
||||
dut.expect('Setting CRYPT_CNT for permanent encryption', timeout=90)
|
||||
dut.expect('Flash encryption completed')
|
||||
dut.expect('Resetting with flash encryption enabled...')
|
||||
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Checking flash encryption...')
|
||||
dut.expect('flash encryption is enabled (0 plaintext flashes left)')
|
||||
|
||||
dut.expect('Flash encryption mode is RELEASE')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32'])
|
||||
def test_examples_efuse_with_virt_secure_boot_v1(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
|
||||
# only for ESP32
|
||||
dut = env.get_dut('efuse', 'examples/system/efuse', app_config_name='virt_secure_boot_v1')
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut.app.binary_path, 'bootloader', 'bootloader.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
ttfw_idf.log_performance('{}_bootloader_{}_bin_size'.format(dut.app.target, dut.app.config_name), '{}KB'.format(bin_size // 1024))
|
||||
|
||||
print(' - Erase flash')
|
||||
dut.erase_flash()
|
||||
|
||||
print(' - Flash bootloader')
|
||||
dut.bootloader_flash()
|
||||
|
||||
print(' - Start app (flash partition_table and app)')
|
||||
dut.start_app()
|
||||
dut.expect('Loading virtual efuse blocks from real efuses')
|
||||
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v1: Generating new secure boot key...')
|
||||
dut.expect('secure_boot_v1: Generating secure boot digest...')
|
||||
dut.expect('secure_boot_v1: Digest generation complete')
|
||||
dut.expect('Checking secure boot...')
|
||||
|
||||
dut.expect('secure_boot_v1: blowing secure boot efuse...')
|
||||
dut.expect('Read & write protecting new key...')
|
||||
dut.expect('Disable JTAG...')
|
||||
dut.expect('Disable ROM BASIC interpreter fallback...')
|
||||
dut.expect('secure_boot_v1: secure boot is now enabled for bootloader image')
|
||||
|
||||
dut.expect('cpu_start: Pro cpu up')
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
dut.reset()
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v1: bootloader secure boot is already enabled. No need to generate digest. continuing..')
|
||||
dut.expect('boot: Checking secure boot...')
|
||||
dut.expect('secure_boot_v1: bootloader secure boot is already enabled, continuing..')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32'])
|
||||
def test_examples_efuse_with_virt_secure_boot_v1_pre_loaded(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
|
||||
# only for ESP32
|
||||
dut = env.get_dut('efuse', 'examples/system/efuse', app_config_name='virt_secure_boot_v1')
|
||||
|
||||
print(' - Erase flash')
|
||||
dut.erase_flash()
|
||||
|
||||
dut.bootloader_flash()
|
||||
dut.start_app()
|
||||
dut.expect('Loading virtual efuse blocks from real efuses')
|
||||
dut.expect('cpu_start: Pro cpu up')
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
print(' - Flash emul_efuse with pre-loaded efuses (ABS_DONE_0 1 -> 0)')
|
||||
erase_field_on_emul_efuse(dut, 6 * 32 + 4)
|
||||
|
||||
print(' - Start app (flash partition_table and app)')
|
||||
dut.start_app()
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v1: Using pre-loaded secure boot key in EFUSE block 2')
|
||||
dut.expect('secure_boot_v1: Generating secure boot digest...')
|
||||
dut.expect('secure_boot_v1: Digest generation complete')
|
||||
dut.expect('Checking secure boot...')
|
||||
|
||||
dut.expect('secure_boot_v1: blowing secure boot efuse...')
|
||||
dut.expect('Read & write protecting new key...')
|
||||
dut.expect('Disable JTAG...')
|
||||
dut.expect('Disable ROM BASIC interpreter fallback...')
|
||||
dut.expect('secure_boot_v1: secure boot is now enabled for bootloader image')
|
||||
|
||||
dut.expect('cpu_start: Pro cpu up')
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
dut.reset()
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v1: bootloader secure boot is already enabled. No need to generate digest. continuing..')
|
||||
dut.expect('Checking secure boot...')
|
||||
dut.expect('secure_boot_v1: bootloader secure boot is already enabled, continuing..')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_EthKitV12', target=['esp32'])
|
||||
def test_examples_efuse_with_virt_secure_boot_v2(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
|
||||
# only for ESP32 ECO3
|
||||
dut = env.get_dut('efuse', 'examples/system/efuse', app_config_name='virt_secure_boot_v2')
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut.app.binary_path, 'bootloader', 'bootloader.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
ttfw_idf.log_performance('{}_bootloader_{}_bin_size'.format(dut.app.target, dut.app.config_name), '{}KB'.format(bin_size // 1024))
|
||||
|
||||
print(' - Erase flash')
|
||||
dut.erase_flash()
|
||||
|
||||
print(' - Flash bootloader')
|
||||
dut.bootloader_flash()
|
||||
|
||||
print(' - Start app (flash partition_table and app)')
|
||||
dut.start_app()
|
||||
dut.expect('Loading virtual efuse blocks from real efuses')
|
||||
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Secure boot V2 is not enabled yet and eFuse digest keys are not set')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
|
||||
dut.expect('secure_boot_v2: enabling secure boot v2...')
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Secure boot V2 is not enabled yet and eFuse digest keys are not set')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
dut.expect('secure_boot_v2: Secure boot digests absent, generating..')
|
||||
dut.expect('secure_boot_v2: Digests successfully calculated, 1 valid signatures')
|
||||
dut.expect('secure_boot_v2: 1 signature block(s) found appended to the bootloader')
|
||||
|
||||
dut.expect('Writing EFUSE_BLK_KEY1 with purpose 3')
|
||||
dut.expect('secure_boot_v2: Digests successfully calculated, 1 valid signatures')
|
||||
dut.expect('secure_boot_v2: 1 signature block(s) found appended to the app')
|
||||
dut.expect('secure_boot_v2: Application key(0) matches with bootloader key(0)')
|
||||
|
||||
dut.expect('secure_boot_v2: blowing secure boot efuse...')
|
||||
dut.expect('Disable JTAG...')
|
||||
dut.expect('Disable ROM BASIC interpreter fallback...')
|
||||
dut.expect('Not disabling ROM Download mode - SECURITY COMPROMISED')
|
||||
dut.expect('Prevent read disabling of additional efuses...')
|
||||
dut.expect('secure_boot_v2: Secure boot permanently enabled')
|
||||
|
||||
dut.expect('cpu_start: Pro cpu up')
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
dut.reset()
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
dut.expect('secure_boot_v2: enabling secure boot v2...')
|
||||
dut.expect('secure_boot_v2: secure boot v2 is already enabled, continuing..')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_EthKitV12', target=['esp32'])
|
||||
def test_examples_efuse_with_virt_secure_boot_v2_pre_loaded(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
|
||||
# only for ESP32 ECO3
|
||||
dut = env.get_dut('efuse', 'examples/system/efuse', app_config_name='virt_secure_boot_v2')
|
||||
|
||||
print(' - Erase flash')
|
||||
dut.erase_flash()
|
||||
|
||||
print(' - Flash bootloader and app')
|
||||
dut.bootloader_flash()
|
||||
dut.start_app()
|
||||
dut.expect('Loading virtual efuse blocks from real efuses')
|
||||
dut.expect('cpu_start: Pro cpu up')
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
print(' - Flash emul_efuse with pre-loaded efuses (ABS_DONE_1 1 -> 0)')
|
||||
erase_field_on_emul_efuse(dut, 6 * 32 + 5)
|
||||
|
||||
print(' - Start app (flash partition_table and app)')
|
||||
dut.start_app()
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
|
||||
dut.expect('secure_boot_v2: enabling secure boot v2...')
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
dut.expect('secure_boot_v2: Secure boot digests already present')
|
||||
dut.expect('secure_boot_v2: Using pre-loaded public key digest in eFuse')
|
||||
dut.expect('secure_boot_v2: Digests successfully calculated, 1 valid signatures')
|
||||
dut.expect('secure_boot_v2: 1 signature block(s) found appended to the app')
|
||||
dut.expect('secure_boot_v2: Application key(0) matches with bootloader key(0)')
|
||||
|
||||
dut.expect('secure_boot_v2: blowing secure boot efuse...')
|
||||
dut.expect('Disable JTAG...')
|
||||
dut.expect('Disable ROM BASIC interpreter fallback...')
|
||||
dut.expect('Not disabling ROM Download mode - SECURITY COMPROMISED')
|
||||
dut.expect('Prevent read disabling of additional efuses...')
|
||||
dut.expect('secure_boot_v2: Secure boot permanently enabled')
|
||||
|
||||
dut.expect('cpu_start: Pro cpu up')
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
dut.reset()
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
dut.expect('secure_boot_v2: enabling secure boot v2...')
|
||||
dut.expect('secure_boot_v2: secure boot v2 is already enabled, continuing..')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32s2'])
|
||||
def test_examples_efuse_with_virt_secure_boot_v2_esp32xx(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
|
||||
dut = env.get_dut('efuse', 'examples/system/efuse', app_config_name='virt_secure_boot_v2')
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut.app.binary_path, 'bootloader', 'bootloader.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
ttfw_idf.log_performance('{}_bootloader_{}_bin_size'.format(dut.app.target, dut.app.config_name), '{}KB'.format(bin_size // 1024))
|
||||
|
||||
print(' - Erase flash')
|
||||
dut.erase_flash()
|
||||
|
||||
print(' - Flash bootloader')
|
||||
dut.bootloader_flash()
|
||||
|
||||
print(' - Start app (flash partition_table and app)')
|
||||
dut.start_app()
|
||||
dut.expect('Loading virtual efuse blocks from real efuses')
|
||||
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Secure boot V2 is not enabled yet and eFuse digest keys are not set')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
|
||||
dut.expect('secure_boot_v2: enabling secure boot v2...')
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Secure boot V2 is not enabled yet and eFuse digest keys are not set')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
dut.expect('secure_boot_v2: Secure boot digests absent, generating..')
|
||||
dut.expect('secure_boot_v2: Digests successfully calculated, 1 valid signatures')
|
||||
dut.expect('secure_boot_v2: 1 signature block(s) found appended to the bootloader')
|
||||
|
||||
dut.expect('Writing EFUSE_BLK_KEY0 with purpose 9')
|
||||
dut.expect('secure_boot_v2: Digests successfully calculated, 1 valid signatures')
|
||||
dut.expect('secure_boot_v2: 1 signature block(s) found appended to the app')
|
||||
dut.expect('secure_boot_v2: Application key(0) matches with bootloader key(0)')
|
||||
dut.expect('secure_boot_v2: Revoking empty key digest slot (1)...')
|
||||
dut.expect('secure_boot_v2: Revoking empty key digest slot (2)...')
|
||||
dut.expect('secure_boot_v2: blowing secure boot efuse...')
|
||||
dut.expect('Not enabling Security download mode - SECURITY COMPROMISED')
|
||||
dut.expect('Disable hardware & software JTAG...')
|
||||
dut.expect('secure_boot_v2: Secure boot permanently enabled')
|
||||
|
||||
dut.expect('cpu_start: Pro cpu up')
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
dut.reset()
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
dut.expect('secure_boot_v2: enabling secure boot v2...')
|
||||
dut.expect('secure_boot_v2: secure boot v2 is already enabled, continuing..')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32s2'])
|
||||
def test_examples_efuse_with_virt_secure_boot_v2_esp32xx_pre_loaded(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
|
||||
dut = env.get_dut('efuse', 'examples/system/efuse', app_config_name='virt_secure_boot_v2')
|
||||
|
||||
print(' - Erase flash')
|
||||
dut.erase_flash()
|
||||
|
||||
print(' - Flash bootloader and app')
|
||||
dut.bootloader_flash()
|
||||
dut.start_app()
|
||||
dut.expect('Loading virtual efuse blocks from real efuses')
|
||||
dut.expect('cpu_start: Pro cpu up')
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
print(' - Flash emul_efuse with pre-loaded efuses (SECURE_BOOT_EN 1 -> 0)')
|
||||
erase_field_on_emul_efuse(dut, 3 * 32 + 20)
|
||||
|
||||
print(' - Start app (flash partition_table and app)')
|
||||
dut.start_app()
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
dut.expect('secure_boot_v2: Secure boot digests already present')
|
||||
dut.expect('secure_boot_v2: Using pre-loaded public key digest in eFuse')
|
||||
dut.expect('secure_boot_v2: Digests successfully calculated, 1 valid signatures')
|
||||
dut.expect('secure_boot_v2: 1 signature block(s) found appended to the app')
|
||||
dut.expect('secure_boot_v2: Application key(0) matches with bootloader key(0)')
|
||||
dut.expect('secure_boot_v2: Revoking empty key digest slot (1)...')
|
||||
dut.expect('secure_boot_v2: Revoking empty key digest slot (2)...')
|
||||
|
||||
dut.expect('secure_boot_v2: blowing secure boot efuse...')
|
||||
dut.expect('Not enabling Security download mode - SECURITY COMPROMISED')
|
||||
dut.expect('Disable hardware & software JTAG...')
|
||||
dut.expect('secure_boot_v2: Secure boot permanently enabled')
|
||||
|
||||
dut.expect('cpu_start: Pro cpu up')
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
dut.reset()
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
dut.expect('secure_boot_v2: enabling secure boot v2...')
|
||||
dut.expect('secure_boot_v2: secure boot v2 is already enabled, continuing..')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32'])
|
||||
def test_examples_efuse_with_virt_sb_v1_and_fe(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
|
||||
dut = env.get_dut('efuse', 'examples/system/efuse', app_config_name='virt_sb_v1_and_fe')
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut.app.binary_path, 'bootloader', 'bootloader.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
ttfw_idf.log_performance('{}_bootloader_{}_bin_size'.format(dut.app.target, dut.app.config_name), '{}KB'.format(bin_size // 1024))
|
||||
|
||||
print(' - Erase flash')
|
||||
dut.erase_flash()
|
||||
|
||||
print(' - Flash bootloader')
|
||||
dut.bootloader_flash()
|
||||
|
||||
print(' - Start app (flash partition_table and app)')
|
||||
dut.start_app_no_enc()
|
||||
dut.expect('Loading virtual efuse blocks from real efuses')
|
||||
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v1: Generating new secure boot key...')
|
||||
dut.expect('secure_boot_v1: Generating secure boot digest...')
|
||||
dut.expect('secure_boot_v1: Digest generation complete')
|
||||
|
||||
dut.expect('Checking flash encryption...')
|
||||
dut.expect('flash_encrypt: Generating new flash encryption key...')
|
||||
dut.expect('Writing EFUSE_BLK_KEY0 with purpose 2')
|
||||
dut.expect('flash_encrypt: Setting CRYPT_CONFIG efuse to 0xF')
|
||||
dut.expect('flash_encrypt: Not disabling UART bootloader encryption')
|
||||
dut.expect('flash_encrypt: Disable UART bootloader decryption...')
|
||||
dut.expect('flash_encrypt: Disable UART bootloader MMU cache...')
|
||||
dut.expect('flash_encrypt: Disable JTAG...')
|
||||
dut.expect('flash_encrypt: Disable ROM BASIC interpreter fallback...')
|
||||
|
||||
dut.expect('flash_encrypt: bootloader encrypted successfully')
|
||||
dut.expect('flash_encrypt: partition table encrypted and loaded successfully')
|
||||
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('flash_encrypt: Flash encryption completed', timeout=90)
|
||||
|
||||
dut.expect('Checking secure boot...')
|
||||
dut.expect('secure_boot_v1: blowing secure boot efuse...')
|
||||
dut.expect('Read & write protecting new key...')
|
||||
dut.expect('Disable JTAG...')
|
||||
dut.expect('Disable ROM BASIC interpreter fallback...')
|
||||
dut.expect('secure_boot_v1: secure boot is now enabled for bootloader image')
|
||||
dut.expect('Resetting with flash encryption enabled...')
|
||||
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v1: bootloader secure boot is already enabled. No need to generate digest. continuing..')
|
||||
dut.expect('Checking flash encryption...')
|
||||
dut.expect('flash_encrypt: flash encryption is enabled (3 plaintext flashes left)')
|
||||
dut.expect('Checking secure boot...')
|
||||
dut.expect('secure_boot_v1: bootloader secure boot is already enabled, continuing..')
|
||||
|
||||
dut.expect('cpu_start: Pro cpu up')
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('flash_encrypt: Flash encryption mode is DEVELOPMENT (not secure)')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_EthKitV12', target=['esp32'])
|
||||
def test_examples_efuse_with_virt_sb_v2_and_fe(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
|
||||
# only for ESP32 ECO3
|
||||
dut = env.get_dut('efuse', 'examples/system/efuse', app_config_name='virt_sb_v2_and_fe')
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut.app.binary_path, 'bootloader', 'bootloader.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
ttfw_idf.log_performance('{}_bootloader_{}_bin_size'.format(dut.app.target, dut.app.config_name), '{}KB'.format(bin_size // 1024))
|
||||
|
||||
print(' - Erase flash')
|
||||
dut.erase_flash()
|
||||
|
||||
print(' - Flash bootloader')
|
||||
dut.bootloader_flash()
|
||||
|
||||
print(' - Start app (flash partition_table and app)')
|
||||
dut.start_app_no_enc()
|
||||
dut.expect('Loading virtual efuse blocks from real efuses')
|
||||
|
||||
dut.expect('secure_boot_v2: Secure boot V2 is not enabled yet and eFuse digest keys are not set')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
|
||||
dut.expect('secure_boot_v2: enabling secure boot v2...')
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Secure boot V2 is not enabled yet and eFuse digest keys are not set')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully')
|
||||
dut.expect('secure_boot_v2: Secure boot digests absent, generating..')
|
||||
dut.expect('secure_boot_v2: Digests successfully calculated, 1 valid signatures')
|
||||
dut.expect('secure_boot_v2: 1 signature block(s) found appended to the bootloader')
|
||||
|
||||
dut.expect('Writing EFUSE_BLK_KEY1 with purpose 3')
|
||||
dut.expect('secure_boot_v2: Digests successfully calculated, 1 valid signatures')
|
||||
dut.expect('secure_boot_v2: 1 signature block(s) found appended to the app')
|
||||
dut.expect('secure_boot_v2: Application key(0) matches with bootloader key(0)')
|
||||
|
||||
dut.expect('secure_boot_v2: blowing secure boot efuse...')
|
||||
dut.expect('Disable JTAG...')
|
||||
dut.expect('Disable ROM BASIC interpreter fallback...')
|
||||
dut.expect('Not disabling ROM Download mode - SECURITY COMPROMISED')
|
||||
dut.expect('secure_boot_v2: Secure boot permanently enabled')
|
||||
|
||||
dut.expect('Checking flash encryption...')
|
||||
dut.expect('flash_encrypt: Generating new flash encryption key...')
|
||||
dut.expect('Writing EFUSE_BLK_KEY0 with purpose 2')
|
||||
dut.expect('flash_encrypt: Setting CRYPT_CONFIG efuse to 0xF')
|
||||
dut.expect('flash_encrypt: Not disabling UART bootloader encryption')
|
||||
dut.expect('flash_encrypt: Disable UART bootloader decryption...')
|
||||
dut.expect('flash_encrypt: Disable UART bootloader MMU cache...')
|
||||
dut.expect('flash_encrypt: Disable JTAG...')
|
||||
dut.expect('flash_encrypt: Disable ROM BASIC interpreter fallback...')
|
||||
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
dut.expect('flash_encrypt: bootloader encrypted successfully')
|
||||
dut.expect('flash_encrypt: partition table encrypted and loaded successfully')
|
||||
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
dut.expect('flash_encrypt: Flash encryption completed', timeout=90)
|
||||
dut.expect('Resetting with flash encryption enabled...')
|
||||
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
dut.expect('secure_boot_v2: enabling secure boot v2...')
|
||||
dut.expect('secure_boot_v2: secure boot v2 is already enabled, continuing..')
|
||||
dut.expect('flash_encrypt: flash encryption is enabled (3 plaintext flashes left)')
|
||||
dut.expect('cpu_start: Pro cpu up')
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('flash_encrypt: Flash encryption mode is DEVELOPMENT (not secure)')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32s2'])
|
||||
def test_examples_efuse_with_virt_sb_v2_and_fe_esp32xx(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
|
||||
dut = env.get_dut('efuse', 'examples/system/efuse', app_config_name='virt_sb_v2_and_fe')
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut.app.binary_path, 'bootloader', 'bootloader.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
ttfw_idf.log_performance('{}_bootloader_{}_bin_size'.format(dut.app.target, dut.app.config_name), '{}KB'.format(bin_size // 1024))
|
||||
|
||||
print(' - Erase flash')
|
||||
dut.erase_flash()
|
||||
|
||||
print(' - Flash bootloader')
|
||||
dut.bootloader_flash()
|
||||
|
||||
print(' - Start app (flash partition_table and app)')
|
||||
dut.start_app_no_enc()
|
||||
dut.expect('Loading virtual efuse blocks from real efuses')
|
||||
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Secure boot V2 is not enabled yet and eFuse digest keys are not set')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
|
||||
dut.expect('secure_boot_v2: enabling secure boot v2...')
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Secure boot V2 is not enabled yet and eFuse digest keys are not set')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
dut.expect('secure_boot_v2: Secure boot digests absent, generating..')
|
||||
dut.expect('secure_boot_v2: Digests successfully calculated, 1 valid signatures')
|
||||
dut.expect('secure_boot_v2: 1 signature block(s) found appended to the bootloader')
|
||||
|
||||
dut.expect('Writing EFUSE_BLK_KEY0 with purpose 9')
|
||||
dut.expect('secure_boot_v2: Digests successfully calculated, 1 valid signatures')
|
||||
dut.expect('secure_boot_v2: 1 signature block(s) found appended to the app')
|
||||
dut.expect('secure_boot_v2: Application key(0) matches with bootloader key(0)')
|
||||
dut.expect('secure_boot_v2: Revoking empty key digest slot (1)...')
|
||||
dut.expect('secure_boot_v2: Revoking empty key digest slot (2)...')
|
||||
dut.expect('secure_boot_v2: blowing secure boot efuse...')
|
||||
dut.expect('Not enabling Security download mode - SECURITY COMPROMISED')
|
||||
dut.expect('Disable hardware & software JTAG...')
|
||||
dut.expect('secure_boot_v2: Secure boot permanently enabled')
|
||||
|
||||
dut.expect('Checking flash encryption...')
|
||||
dut.expect('flash_encrypt: Generating new flash encryption key...')
|
||||
dut.expect('Writing EFUSE_BLK_KEY1 with purpose 4')
|
||||
dut.expect('Not disabling UART bootloader encryption')
|
||||
dut.expect('Disable UART bootloader cache...')
|
||||
dut.expect('Disable JTAG...')
|
||||
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
dut.expect('flash_encrypt: bootloader encrypted successfully')
|
||||
dut.expect('flash_encrypt: partition table encrypted and loaded successfully')
|
||||
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
dut.expect('flash_encrypt: Flash encryption completed', timeout=90)
|
||||
dut.expect('Resetting with flash encryption enabled...')
|
||||
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('Verifying image signature...')
|
||||
dut.expect('secure_boot_v2: Verifying with RSA-PSS...')
|
||||
dut.expect('secure_boot_v2: Signature verified successfully!')
|
||||
dut.expect('secure_boot_v2: enabling secure boot v2...')
|
||||
dut.expect('secure_boot_v2: secure boot v2 is already enabled, continuing..')
|
||||
dut.expect('flash_encrypt: flash encryption is enabled (1 plaintext flashes left)')
|
||||
dut.expect('cpu_start: Pro cpu up')
|
||||
dut.expect('Loading virtual efuse blocks from flash')
|
||||
dut.expect('flash_encrypt: Flash encryption mode is DEVELOPMENT (not secure)')
|
||||
dut.expect('Start eFuse example')
|
||||
dut.expect('example: Done')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_efuse()
|
||||
test_examples_efuse_with_virt_flash_enc()
|
||||
test_examples_efuse_with_virt_flash_enc_pre_loaded()
|
||||
test_examples_efuse_with_virt_flash_enc_aes_256()
|
||||
test_examples_efuse_with_virt_flash_enc_release()
|
||||
test_examples_efuse_with_virt_secure_boot_v1()
|
||||
test_examples_efuse_with_virt_secure_boot_v1_pre_loaded()
|
||||
test_examples_efuse_with_virt_secure_boot_v2()
|
||||
test_examples_efuse_with_virt_secure_boot_v2_pre_loaded()
|
||||
test_examples_efuse_with_virt_secure_boot_v2_esp32xx()
|
||||
test_examples_efuse_with_virt_secure_boot_v2_esp32xx_pre_loaded()
|
||||
test_examples_efuse_with_virt_sb_v1_and_fe()
|
||||
test_examples_efuse_with_virt_sb_v2_and_fe()
|
||||
test_examples_efuse_with_virt_sb_v2_and_fe_esp32xx()
|
||||
|
@ -76,10 +76,9 @@ static void read_efuse_fields(device_desc_t *desc)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
static void write_efuse_fields(device_desc_t *desc, esp_efuse_coding_scheme_t coding_scheme)
|
||||
{
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
const esp_efuse_coding_scheme_t coding_scheme_for_batch_mode = EFUSE_CODING_SCHEME_3_4;
|
||||
#else
|
||||
@ -102,8 +101,8 @@ static void write_efuse_fields(device_desc_t *desc, esp_efuse_coding_scheme_t co
|
||||
if (coding_scheme == coding_scheme_for_batch_mode) {
|
||||
ESP_ERROR_CHECK(esp_efuse_batch_write_commit());
|
||||
}
|
||||
#endif // CONFIG_EFUSE_VIRTUAL
|
||||
}
|
||||
#endif // CONFIG_EFUSE_VIRTUAL
|
||||
|
||||
|
||||
static esp_efuse_coding_scheme_t get_coding_scheme(void)
|
||||
@ -130,7 +129,10 @@ static esp_efuse_coding_scheme_t get_coding_scheme(void)
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Start eFuse example");
|
||||
|
||||
esp_efuse_coding_scheme_t coding_scheme = get_coding_scheme();
|
||||
(void) coding_scheme;
|
||||
|
||||
device_desc_t device_desc = { 0 };
|
||||
read_efuse_fields(&device_desc);
|
||||
|
11
examples/system/efuse/sdkconfig.ci.virt_flash_enc
Normal file
11
examples/system/efuse/sdkconfig.ci.virt_flash_enc
Normal file
@ -0,0 +1,11 @@
|
||||
# FLASH_ENCRYPTION with EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xC000
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="test/partitions_efuse_emul.csv"
|
||||
|
||||
CONFIG_SECURE_FLASH_ENC_ENABLED=y
|
||||
|
||||
# IMPORTANT: ONLY VIRTUAL eFuse MODE!
|
||||
CONFIG_EFUSE_VIRTUAL=y
|
||||
CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH=y
|
15
examples/system/efuse/sdkconfig.ci.virt_flash_enc_aes_256
Normal file
15
examples/system/efuse/sdkconfig.ci.virt_flash_enc_aes_256
Normal file
@ -0,0 +1,15 @@
|
||||
# FLASH_ENCRYPTION with EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
|
||||
# FLASH_ENCRYPTION_AES256 is available only in ESP32-S2
|
||||
CONFIG_IDF_TARGET="esp32s2"
|
||||
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xC000
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="test/partitions_efuse_emul.csv"
|
||||
|
||||
CONFIG_SECURE_FLASH_ENC_ENABLED=y
|
||||
CONFIG_SECURE_FLASH_ENCRYPTION_AES256=y
|
||||
|
||||
# IMPORTANT: ONLY VIRTUAL eFuse MODE!
|
||||
CONFIG_EFUSE_VIRTUAL=y
|
||||
CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH=y
|
12
examples/system/efuse/sdkconfig.ci.virt_flash_enc_release
Normal file
12
examples/system/efuse/sdkconfig.ci.virt_flash_enc_release
Normal file
@ -0,0 +1,12 @@
|
||||
# FLASH_ENCRYPTION with EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xC000
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="test/partitions_efuse_emul.csv"
|
||||
|
||||
CONFIG_SECURE_FLASH_ENC_ENABLED=y
|
||||
CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=y
|
||||
|
||||
# IMPORTANT: ONLY VIRTUAL eFuse MODE!
|
||||
CONFIG_EFUSE_VIRTUAL=y
|
||||
CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH=y
|
18
examples/system/efuse/sdkconfig.ci.virt_sb_v1_and_fe
Normal file
18
examples/system/efuse/sdkconfig.ci.virt_sb_v1_and_fe
Normal file
@ -0,0 +1,18 @@
|
||||
# FLASH_ENCRYPTION & SECURE_BOOT_V1 with EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
|
||||
# SECURE_BOOT_V1 is available only in ESP32
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xD000
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="test/partitions_efuse_emul.csv"
|
||||
|
||||
CONFIG_SECURE_BOOT=y
|
||||
CONFIG_SECURE_BOOT_V1_ENABLED=y
|
||||
CONFIG_SECURE_BOOT_SIGNING_KEY="test/secure_boot_signing_key_ecdsa.pem"
|
||||
|
||||
CONFIG_SECURE_FLASH_ENC_ENABLED=y
|
||||
|
||||
# IMPORTANT: ONLY VIRTUAL eFuse MODE!
|
||||
CONFIG_EFUSE_VIRTUAL=y
|
||||
CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH=y
|
22
examples/system/efuse/sdkconfig.ci.virt_sb_v2_and_fe
Normal file
22
examples/system/efuse/sdkconfig.ci.virt_sb_v2_and_fe
Normal file
@ -0,0 +1,22 @@
|
||||
# FLASH_ENCRYPTION & SECURE_BOOT_V2 with EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
|
||||
# ESP32 supports SECURE_BOOT_V2 only in ECO3
|
||||
CONFIG_ESP32_REV_MIN_3=y
|
||||
CONFIG_ESP32_REV_MIN=3
|
||||
# ESP32C3 supports SECURE_BOOT_V2 only in ECO3
|
||||
CONFIG_ESP32C3_REV_MIN_3=y
|
||||
CONFIG_ESP32C3_REV_MIN=3
|
||||
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xD000
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="test/partitions_efuse_emul.csv"
|
||||
|
||||
CONFIG_SECURE_BOOT=y
|
||||
CONFIG_SECURE_BOOT_V2_ENABLED=y
|
||||
CONFIG_SECURE_BOOT_SIGNING_KEY="test/secure_boot_signing_key.pem"
|
||||
|
||||
CONFIG_SECURE_FLASH_ENC_ENABLED=y
|
||||
|
||||
# IMPORTANT: ONLY VIRTUAL eFuse MODE!
|
||||
CONFIG_EFUSE_VIRTUAL=y
|
||||
CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH=y
|
16
examples/system/efuse/sdkconfig.ci.virt_secure_boot_v1
Normal file
16
examples/system/efuse/sdkconfig.ci.virt_secure_boot_v1
Normal file
@ -0,0 +1,16 @@
|
||||
# SECURE_BOOT_V1 with EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
|
||||
# SECURE_BOOT_V1 is available only in ESP32
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xC000
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="test/partitions_efuse_emul.csv"
|
||||
|
||||
CONFIG_SECURE_BOOT=y
|
||||
CONFIG_SECURE_BOOT_V1_ENABLED=y
|
||||
CONFIG_SECURE_BOOT_SIGNING_KEY="test/secure_boot_signing_key_ecdsa.pem"
|
||||
|
||||
# IMPORTANT: ONLY VIRTUAL eFuse MODE!
|
||||
CONFIG_EFUSE_VIRTUAL=y
|
||||
CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH=y
|
21
examples/system/efuse/sdkconfig.ci.virt_secure_boot_v2
Normal file
21
examples/system/efuse/sdkconfig.ci.virt_secure_boot_v2
Normal file
@ -0,0 +1,21 @@
|
||||
# SECURE_BOOT_V2 with EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
|
||||
# ESP32 supports SECURE_BOOT_V2 only in ECO3
|
||||
CONFIG_ESP32_REV_MIN_3=y
|
||||
CONFIG_ESP32_REV_MIN=3
|
||||
# ESP32C3 supports SECURE_BOOT_V2 only in ECO3
|
||||
CONFIG_ESP32C3_REV_MIN_3=y
|
||||
CONFIG_ESP32C3_REV_MIN=3
|
||||
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xC000
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="test/partitions_efuse_emul.csv"
|
||||
|
||||
CONFIG_SECURE_BOOT=y
|
||||
CONFIG_SECURE_BOOT_V2_ENABLED=y
|
||||
CONFIG_SECURE_BOOT_SIGNING_KEY="test/secure_boot_signing_key.pem"
|
||||
CONFIG_SECURE_INSECURE_ALLOW_DL_MODE=y
|
||||
|
||||
# IMPORTANT: ONLY VIRTUAL eFuse MODE!
|
||||
CONFIG_EFUSE_VIRTUAL=y
|
||||
CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH=y
|
7
examples/system/efuse/test/partitions_efuse_emul.csv
Normal file
7
examples/system/efuse/test/partitions_efuse_emul.csv
Normal file
@ -0,0 +1,7 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, , 0x4000,
|
||||
phy_init, data, phy, , 0x1000,
|
||||
storage, data, 0xff, , 0x1000, encrypted
|
||||
nvs_key, data, nvs_keys, , 0x1000, encrypted,
|
||||
emul_efuse, data, efuse, , 0x2000,
|
||||
factory, app, factory, , 1M,
|
|
39
examples/system/efuse/test/secure_boot_signing_key.pem
Normal file
39
examples/system/efuse/test/secure_boot_signing_key.pem
Normal file
@ -0,0 +1,39 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIG4wIBAAKCAYEAzJUktQ+7wpPDfDGterxiMRx5w9n7PFaUSK3wnE+05ALsEF8F
|
||||
rUOC7/q0GutYYdWopdRM1FUKX2XVaryMViC+DHof42fEbpWYnfrCkYrDn8MLuMyK
|
||||
4uGunl8LUTIAZk3I3SZKJZy5FW9eb1XtkwfN1lAd6lEEGQKyoR6Bk/Rkisj0LP7R
|
||||
dyV9NKbJhxavZ1ohZXiXU5FW873iGdPIsloZoUK3QGRE1KRIH2woUGHATfXBCf5a
|
||||
+e41wJzz7YHl5tjyxAbJ9PET52N14G73WoZKHu3QPShALrZVfjsk1oYdFvNdOBDL
|
||||
uU0vpyKl7mJHno11gM0UM0s9PrMxk9ffdAqMyS8YeLEk2Xl3AwPv7m9oeGIdSD/P
|
||||
okcISYcm4YAl5veqIG3RlkfpWjf5G15UYyLbgmn4GOkgr6ksB/dCFOMi9V1LjPah
|
||||
32A7gxqTlapQza+wNs30SYBIXrFde4bNnhFhj4Cbt34ADefWm26KLiZEHFHFN30Z
|
||||
IownitXz3rT7rmzBAgMBAAECggGBAK6bBA88dGWnM4rF42gDbFK6GPqdCp3+zuQR
|
||||
AHCIXrzT+aInV3L/Ubt730eyYWZusleGEGSQiB/PjAxjC+teWpXPjXPK1o4DQ5Rh
|
||||
trn9EuVB1LlOaaMmNqCYQdJ0uH6YGL0WtuXPEvBGcvTXA8MfQACPtFiN+M9XzBlT
|
||||
LgiW51DEHhJhEWl9J5VOXGXdaKru893kxFLgkrPI9jZQ2NPPrlxB0qE0csKBy8R1
|
||||
zRp9s2FWRAFBg2gYdOwFiPLGkO8rbM+jhXM+IUV1GgVYdxAC6zS9AiIAWuACDEwp
|
||||
Pzg3d3/5uyOFK1xTIPl/cG8CZyPQL1v/mUx0MZFaB1R1CVeDuMoFVz2YSbEaAVFv
|
||||
QIcJGDN/WlJbt0jwj7/RJKKTx0ipFlUdNbodzdaSl3Yg4N+evzR1nS8DvLJpwl/e
|
||||
ybu40IbavwYXWVzirH3wRg+P/NDsHLU5xASAyUwf1minsmObILayEZgfTA6TbrKL
|
||||
fZbJCvy2/IuCM6iqKZwSvYy0bJdaAQKBwQDzDVa/M4/sJV0GEbwegeN6Xf+XKkl3
|
||||
Gosjd+vQgv/0X1gbdMc0Ej9eYSU5/GYIHxDzDRkYIxtIfwaze1gGeNRHycMCmVkl
|
||||
09DMi48jLGE7wzObPu6MtBCSAGHaS9zMTVCYDYtRlykPzG2/1QNrRUDNACnpzneK
|
||||
MkWObzFYTIup1zh+JaD56vLIDdL7qM9apmEkq4O6y1BBPnCgRYJy5EU3BDZxz9fP
|
||||
47JtCZ47uVguoh/NVYY5uibdvI5iJ4SA/VECgcEA13srpwJppfTTFPRWgD+g7PdU
|
||||
Yg+ENBWygiJuwgGv6DyD4k73pxiyshNo7jxsdOLeGFA8hI3dvd/Ei6uUsGnWPy/a
|
||||
OwuBcOZrJZjyawNSiC+mrCSP0LGQrC5VjmuE8IU1d2hFWyV/NzkSLaXJ52Zkg3ee
|
||||
sSepBHtWEYpwH929u5FTKDKhL0qRH8E1EsULSjmkTa+cVDYgx8+2mb3vHRdJdvt3
|
||||
FZU9erKyDb4II5GJhyNQo/cxBosDzj4yIMKM/dxxAoHAE1r1lIZjqLeU/927sGZB
|
||||
mkYQC5a3gP+hIvLy2YkFHw3Us2MKVhA58ack0shRy8XFkMVzQSPSkWRkQTjKWsGW
|
||||
jhz4JaXWnpeOoite+7sWBy9VVcCeOKBCTY4wPLUb4T0q9ODnPlkeUP7Doqow+oLq
|
||||
VSj1LYReqqe0OFKMiG6YFK9p9UnD1wMp0FqheZ8I3DwxsjziYaa9PmTdjTXb3JBn
|
||||
Hql8OHYHxqtoUxyX+EObTSNmCvELnl8/pxrT7+cbuzXxAoHAfmNYb1US8qxvQtMu
|
||||
CXtIwLUxYXMIcCRp17qqjFDBBM657Hu09uWdqqWH3nTCiKyo6EnntTgg38XoWqQB
|
||||
SphJejZvIkLVYYtFPYBAcFQ6jHampEGtuRLtcJCczjRyfUEk4yzdwWB1BccLyop7
|
||||
qqZ8PkBjbDV/BYnyKcexjH9bUjEjPWi08jAifyWsI54/yQGWRZrDbwFwqMJEsFif
|
||||
b8jA5nEIoDgxH07A8R6NV499wy4LlqDeuJ/BU69XZ6+1UxGBAoHAXfb9t5ivdf9N
|
||||
ZbZj61GcrDLyYGDTotucy8HPNMr5P3ZmBR/5UzClpCbWVSaziK3CKzR0zURLw0W7
|
||||
rF4CySTjuD9FHOFFWjjlkS4KwOyYiy8fuMMLg1RmsCS8H+0L3Pm25PmRQ9TLjEf4
|
||||
0uFWf7fG4GQiciqGcvfaFH3w//d0Q7PSvIMNlM1Gc7JS1Qn4HoDF2Ux6drNb6nJL
|
||||
l6tdXNMkUFHBMtaQy0l9D/ex5NZlAniePT3xfMrQf6m0rVAAaAY0
|
||||
-----END RSA PRIVATE KEY-----
|
@ -0,0 +1,5 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIOvP45grF4dSM2fWbOAp4W8PgFm30HIZqtNEK13O5hVHoAoGCCqGSM49
|
||||
AwEHoUQDQgAE1IL73BARrNpkHj1jG50eHoF2LERCwz1BfbshuAeLcsED5aT92Xgu
|
||||
gJvq45LN9p6eBi62ZZwr6Z2ZfX3YB3/8KA==
|
||||
-----END EC PRIVATE KEY-----
|
@ -3,6 +3,6 @@
|
||||
nvs, data, nvs, , 0x4000,
|
||||
otadata, data, ota, , 0x2000,
|
||||
phy_init, data, phy, , 0x1000,
|
||||
emul_efuse,data,efuse, , 0x2000,
|
||||
ota_0, app, ota_0, , 3584K,
|
||||
ota_1, app, ota_1, , 3584K,
|
||||
emul_efuse, data, 5, , 0x2000
|
||||
|
|
@ -461,6 +461,9 @@ def test_examples_protocol_advanced_https_ota_example_anti_rollback(env, extra_d
|
||||
4. Check working of anti_rollback feature
|
||||
"""
|
||||
dut1 = env.get_dut('advanced_https_ota_example', 'examples/system/ota/advanced_https_ota', dut_class=ttfw_idf.ESP32DUT, app_config_name='anti_rollback')
|
||||
Utility.console_log('Erasing the flash on the chip')
|
||||
# erase the flash
|
||||
dut1.erase_flash()
|
||||
server_port = 8001
|
||||
# Original binary file generated after compilation
|
||||
bin_name = 'advanced_https_ota.bin'
|
||||
|
@ -5,6 +5,7 @@ CONFIG_EXAMPLE_OTA_RECV_TIMEOUT=3000
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="anti_rollback_partition.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="anti_rollback_partition.csv"
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xd000
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE="16MB"
|
||||
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
|
||||
|
@ -125,7 +125,6 @@ examples/system/app_trace_to_host/example_test.py
|
||||
examples/system/base_mac_address/example_test.py
|
||||
examples/system/console/example_test.py
|
||||
examples/system/deep_sleep/example_test.py
|
||||
examples/system/efuse/example_test.py
|
||||
examples/system/esp_event/default_event_loop/example_test.py
|
||||
examples/system/esp_event/user_event_loops/example_test.py
|
||||
examples/system/esp_timer/example_test.py
|
||||
@ -192,7 +191,6 @@ tools/ci/python_packages/tiny_test_fw/bin/Runner.py
|
||||
tools/ci/python_packages/tiny_test_fw/bin/example.py
|
||||
tools/ci/python_packages/tiny_test_fw/docs/conf.py
|
||||
tools/ci/python_packages/ttfw_idf/DebugUtils.py
|
||||
tools/ci/python_packages/ttfw_idf/IDFApp.py
|
||||
tools/ci/python_packages/ttfw_idf/IDFAssignTest.py
|
||||
tools/ci/python_packages/ttfw_idf/IDFDUT.py
|
||||
tools/ci/python_packages/ttfw_idf/unity_test_parser.py
|
||||
@ -218,7 +216,6 @@ tools/esp_prov/transport/transport_console.py
|
||||
tools/esp_prov/transport/transport_http.py
|
||||
tools/esp_prov/utils/convenience.py
|
||||
tools/find_apps.py
|
||||
tools/find_build_apps/cmake.py
|
||||
tools/find_build_apps/common.py
|
||||
tools/find_build_apps/make.py
|
||||
tools/gdb_panic_server.py
|
||||
|
@ -30,8 +30,13 @@ try:
|
||||
except ImportError:
|
||||
gitlab_api = None
|
||||
|
||||
try:
|
||||
from typing import Any, Dict, List, Optional, Tuple, Type # noqa: F401
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
def parse_encrypted_flag(args, offs, binary):
|
||||
|
||||
def parse_encrypted_flag(args, offs, binary): # type: (Dict, str, str) -> Any
|
||||
# Find partition entries (e.g. the entries with an offset and a file)
|
||||
for _, entry in args.items():
|
||||
# If the current entry is a partition, we have to check whether it is
|
||||
@ -50,7 +55,7 @@ def parse_encrypted_flag(args, offs, binary):
|
||||
return None
|
||||
|
||||
|
||||
def parse_flash_settings(path, default_encryption=False):
|
||||
def parse_flash_settings(path, default_encryption=False): # type: (str, bool) -> Tuple[List[Tuple[str, str]], List[Tuple[str, str]], Dict, Any]
|
||||
file_name = os.path.basename(path)
|
||||
|
||||
# For compatibility reasons, this list contains all the files to be
|
||||
@ -104,6 +109,7 @@ def parse_flash_settings(path, default_encryption=False):
|
||||
|
||||
class Artifacts(object):
|
||||
def __init__(self, dest_root_path, artifact_index_file, app_path, config_name, target):
|
||||
# type: (str, str, str, str, str) -> None
|
||||
assert gitlab_api
|
||||
# at least one of app_path or config_name is not None. otherwise we can't match artifact
|
||||
assert app_path or config_name
|
||||
@ -115,7 +121,7 @@ class Artifacts(object):
|
||||
self.artifact_info = self._find_artifact(artifact_index, app_path, config_name, target)
|
||||
|
||||
@staticmethod
|
||||
def _find_artifact(artifact_index, app_path, config_name, target):
|
||||
def _find_artifact(artifact_index, app_path, config_name, target): # type: ignore
|
||||
for artifact_info in artifact_index:
|
||||
match_result = True
|
||||
if app_path:
|
||||
@ -133,13 +139,13 @@ class Artifacts(object):
|
||||
ret = None
|
||||
return ret
|
||||
|
||||
def _get_app_base_path(self):
|
||||
def _get_app_base_path(self): # type: () -> Any
|
||||
if self.artifact_info:
|
||||
return os.path.join(self.artifact_info['work_dir'], self.artifact_info['build_dir'])
|
||||
else:
|
||||
return None
|
||||
|
||||
def _get_flash_arg_file(self, base_path, job_id):
|
||||
def _get_flash_arg_file(self, base_path, job_id): # type: (str, str) -> str
|
||||
if self.artifact_info['build_system'] == 'cmake':
|
||||
flash_arg_file = os.path.join(base_path, 'flasher_args.json')
|
||||
else:
|
||||
@ -148,20 +154,24 @@ class Artifacts(object):
|
||||
self.gitlab_inst.download_artifact(job_id, [flash_arg_file], self.dest_root_path)
|
||||
return flash_arg_file
|
||||
|
||||
def _download_binary_files(self, base_path, job_id, flash_arg_file):
|
||||
def _download_binary_files(self, base_path, job_id, flash_arg_file): # type: (str, str, str) -> None
|
||||
# Let's ignore the second value returned (encrypt_files) as these
|
||||
# files also appear in the first list
|
||||
flash_files, _, _, app_name = parse_flash_settings(os.path.join(self.dest_root_path, flash_arg_file))
|
||||
artifact_files = [os.path.join(base_path, p[1]) for p in flash_files]
|
||||
artifact_files.append(os.path.join(base_path, app_name + '.elf'))
|
||||
|
||||
bootloader_path = os.path.join(base_path, 'bootloader', 'bootloader.bin')
|
||||
if bootloader_path not in artifact_files:
|
||||
artifact_files.append(bootloader_path)
|
||||
|
||||
self.gitlab_inst.download_artifact(job_id, artifact_files, self.dest_root_path)
|
||||
|
||||
def _download_sdkconfig_file(self, base_path, job_id):
|
||||
def _download_sdkconfig_file(self, base_path, job_id): # type: (str, str) -> None
|
||||
self.gitlab_inst.download_artifact(job_id, [os.path.join(os.path.dirname(base_path), 'sdkconfig')],
|
||||
self.dest_root_path)
|
||||
|
||||
def download_artifacts(self):
|
||||
def download_artifacts(self): # type: () -> Any
|
||||
if not self.artifact_info:
|
||||
return None
|
||||
base_path = self._get_app_base_path()
|
||||
@ -176,7 +186,7 @@ class Artifacts(object):
|
||||
self._download_sdkconfig_file(base_path, job_id)
|
||||
return base_path
|
||||
|
||||
def download_artifact_files(self, file_names):
|
||||
def download_artifact_files(self, file_names): # type: (List[str]) -> Any
|
||||
if self.artifact_info:
|
||||
base_path = os.path.join(self.artifact_info['work_dir'], self.artifact_info['build_dir'])
|
||||
job_id = self.artifact_info['ci_job_id']
|
||||
@ -196,14 +206,14 @@ class Artifacts(object):
|
||||
class UnitTestArtifacts(Artifacts):
|
||||
BUILDS_DIR_RE = re.compile(r'^builds/')
|
||||
|
||||
def _get_app_base_path(self):
|
||||
def _get_app_base_path(self): # type: () -> Any
|
||||
if self.artifact_info:
|
||||
output_dir = self.BUILDS_DIR_RE.sub('output/', self.artifact_info['build_dir'])
|
||||
return os.path.join(self.artifact_info['app_dir'], output_dir)
|
||||
else:
|
||||
return None
|
||||
|
||||
def _download_sdkconfig_file(self, base_path, job_id):
|
||||
def _download_sdkconfig_file(self, base_path, job_id): # type: (str, str) -> None
|
||||
self.gitlab_inst.download_artifact(job_id, [os.path.join(base_path, 'sdkconfig')], self.dest_root_path)
|
||||
|
||||
|
||||
@ -216,17 +226,17 @@ class IDFApp(App.BaseApp):
|
||||
IDF_DOWNLOAD_CONFIG_FILE = 'download.config'
|
||||
IDF_FLASH_ARGS_FILE = 'flasher_args.json'
|
||||
|
||||
def __init__(self, app_path, config_name=None, target=None, case_group=IDFCaseGroup, artifact_cls=Artifacts):
|
||||
def __init__(self, app_path, config_name=None, target=None, case_group=IDFCaseGroup, artifact_cls=Artifacts): # type: ignore
|
||||
super(IDFApp, self).__init__(app_path)
|
||||
self.app_path = app_path
|
||||
self.config_name = config_name
|
||||
self.target = target
|
||||
self.idf_path = self.get_sdk_path()
|
||||
self.app_path = app_path # type: (str)
|
||||
self.config_name = config_name # type: (str)
|
||||
self.target = target # type: (str)
|
||||
self.idf_path = self.get_sdk_path() # type: (str)
|
||||
self.case_group = case_group
|
||||
self.artifact_cls = artifact_cls
|
||||
self.binary_path = self.get_binary_path()
|
||||
self.elf_file = self._get_elf_file_path()
|
||||
self._elf_file_sha256 = None
|
||||
self._elf_file_sha256 = None # type: (Optional[str])
|
||||
assert os.path.exists(self.binary_path)
|
||||
if self.IDF_DOWNLOAD_CONFIG_FILE not in os.listdir(self.binary_path):
|
||||
if self.IDF_FLASH_ARGS_FILE not in os.listdir(self.binary_path):
|
||||
@ -243,7 +253,7 @@ class IDFApp(App.BaseApp):
|
||||
self.flash_files, self.encrypt_files, self.flash_settings = self._parse_flash_download_config()
|
||||
self.partition_table = self._parse_partition_table()
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self): # type: () -> str
|
||||
parts = ['app<{}>'.format(self.app_path)]
|
||||
if self.config_name:
|
||||
parts.append('config<{}>'.format(self.config_name))
|
||||
@ -258,7 +268,7 @@ class IDFApp(App.BaseApp):
|
||||
assert os.path.exists(idf_path)
|
||||
return idf_path
|
||||
|
||||
def _get_sdkconfig_paths(self):
|
||||
def _get_sdkconfig_paths(self): # type: () -> List[str]
|
||||
"""
|
||||
returns list of possible paths where sdkconfig could be found
|
||||
|
||||
@ -266,7 +276,7 @@ class IDFApp(App.BaseApp):
|
||||
"""
|
||||
return [os.path.join(self.binary_path, 'sdkconfig'), os.path.join(self.binary_path, '..', 'sdkconfig')]
|
||||
|
||||
def get_sdkconfig(self):
|
||||
def get_sdkconfig(self): # type: () -> Dict
|
||||
"""
|
||||
reads sdkconfig and returns a dictionary with all configured variables
|
||||
|
||||
@ -287,10 +297,10 @@ class IDFApp(App.BaseApp):
|
||||
return d
|
||||
|
||||
@abstractmethod
|
||||
def _try_get_binary_from_local_fs(self):
|
||||
def _try_get_binary_from_local_fs(self): # type: () -> Optional[str]
|
||||
pass
|
||||
|
||||
def get_binary_path(self):
|
||||
def get_binary_path(self): # type: () -> str
|
||||
path = self._try_get_binary_from_local_fs()
|
||||
if path:
|
||||
return path
|
||||
@ -309,7 +319,7 @@ class IDFApp(App.BaseApp):
|
||||
else:
|
||||
raise OSError('Failed to get binary for {}'.format(self))
|
||||
|
||||
def _get_elf_file_path(self):
|
||||
def _get_elf_file_path(self): # type: () -> str
|
||||
ret = ''
|
||||
file_names = os.listdir(self.binary_path)
|
||||
for fn in file_names:
|
||||
@ -317,12 +327,12 @@ class IDFApp(App.BaseApp):
|
||||
ret = os.path.join(self.binary_path, fn)
|
||||
return ret
|
||||
|
||||
def _int_offs_abs_paths(self, files_list):
|
||||
def _int_offs_abs_paths(self, files_list): # type: (List[tuple[str, str]]) -> List[Tuple[int, str]]
|
||||
return [(int(offs, 0),
|
||||
os.path.join(self.binary_path, file_path.strip()))
|
||||
for (offs, file_path) in files_list]
|
||||
|
||||
def _parse_flash_download_config(self):
|
||||
def _parse_flash_download_config(self): # type: () -> Tuple[List[tuple[int, str]], List[tuple[int, str]], Dict]
|
||||
"""
|
||||
Parse flash download config from build metadata files
|
||||
|
||||
@ -355,7 +365,7 @@ class IDFApp(App.BaseApp):
|
||||
|
||||
return self._int_offs_abs_paths(flash_files), self._int_offs_abs_paths(encrypt_files), flash_settings
|
||||
|
||||
def _parse_partition_table(self):
|
||||
def _parse_partition_table(self): # type: ignore
|
||||
"""
|
||||
Parse partition table contents based on app binaries
|
||||
|
||||
@ -422,7 +432,7 @@ class IDFApp(App.BaseApp):
|
||||
|
||||
return partition_table
|
||||
|
||||
def get_elf_sha256(self):
|
||||
def get_elf_sha256(self): # type: () -> Optional[str]
|
||||
if self._elf_file_sha256:
|
||||
return self._elf_file_sha256
|
||||
|
||||
@ -435,19 +445,20 @@ class IDFApp(App.BaseApp):
|
||||
|
||||
class Example(IDFApp):
|
||||
def __init__(self, app_path, config_name='default', target='esp32', case_group=ExampleGroup, artifacts_cls=Artifacts):
|
||||
# type: (str, str, str, Type[ExampleGroup], Type[Artifacts]) -> None
|
||||
if not config_name:
|
||||
config_name = 'default'
|
||||
if not target:
|
||||
target = 'esp32'
|
||||
super(Example, self).__init__(app_path, config_name, target, case_group, artifacts_cls)
|
||||
|
||||
def _get_sdkconfig_paths(self):
|
||||
def _get_sdkconfig_paths(self): # type: () -> List[str]
|
||||
"""
|
||||
overrides the parent method to provide exact path of sdkconfig for example tests
|
||||
"""
|
||||
return [os.path.join(self.binary_path, '..', 'sdkconfig')]
|
||||
|
||||
def _try_get_binary_from_local_fs(self):
|
||||
def _try_get_binary_from_local_fs(self): # type: () -> Optional[str]
|
||||
# build folder of example path
|
||||
path = os.path.join(self.idf_path, self.app_path, 'build')
|
||||
if os.path.exists(path):
|
||||
@ -466,17 +477,19 @@ class Example(IDFApp):
|
||||
return path
|
||||
else:
|
||||
return None
|
||||
return None
|
||||
|
||||
|
||||
class UT(IDFApp):
|
||||
def __init__(self, app_path, config_name='default', target='esp32', case_group=UnitTestGroup, artifacts_cls=UnitTestArtifacts):
|
||||
# type: (str, str, str, Type[UnitTestGroup], Type[UnitTestArtifacts]) -> None
|
||||
if not config_name:
|
||||
config_name = 'default'
|
||||
if not target:
|
||||
target = 'esp32'
|
||||
super(UT, self).__init__(app_path, config_name, target, case_group, artifacts_cls)
|
||||
|
||||
def _try_get_binary_from_local_fs(self):
|
||||
def _try_get_binary_from_local_fs(self): # type: () -> Optional[str]
|
||||
path = os.path.join(self.idf_path, self.app_path, 'build')
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
@ -497,16 +510,19 @@ class UT(IDFApp):
|
||||
|
||||
class TestApp(Example):
|
||||
def __init__(self, app_path, config_name='default', target='esp32', case_group=TestAppsGroup, artifacts_cls=Artifacts):
|
||||
# type: (str, str, str, Type[TestAppsGroup], Type[Artifacts]) -> None
|
||||
super(TestApp, self).__init__(app_path, config_name, target, case_group, artifacts_cls)
|
||||
|
||||
|
||||
class ComponentUTApp(TestApp):
|
||||
def __init__(self, app_path, config_name='default', target='esp32', case_group=ComponentUTGroup, artifacts_cls=Artifacts):
|
||||
# type: (str, str, str, Type[ComponentUTGroup], Type[Artifacts]) -> None
|
||||
super(ComponentUTApp, self).__init__(app_path, config_name, target, case_group, artifacts_cls)
|
||||
|
||||
|
||||
class LoadableElfTestApp(TestApp):
|
||||
def __init__(self, app_path, app_files, config_name='default', target='esp32', case_group=TestAppsGroup, artifacts_cls=Artifacts):
|
||||
# type: (str, List[str], str, str, Type[TestAppsGroup], Type[Artifacts]) -> None
|
||||
# add arg `app_files` for loadable elf test_app.
|
||||
# Such examples only build elf files, so it doesn't generate flasher_args.json.
|
||||
# So we can't get app files from config file. Test case should pass it to application.
|
||||
@ -524,12 +540,12 @@ class LoadableElfTestApp(TestApp):
|
||||
|
||||
|
||||
class SSC(IDFApp):
|
||||
def get_binary_path(self):
|
||||
def get_binary_path(self): # type: () -> str
|
||||
# TODO: to implement SSC get binary path
|
||||
return self.app_path
|
||||
|
||||
|
||||
class AT(IDFApp):
|
||||
def get_binary_path(self):
|
||||
def get_binary_path(self): # type: () -> str
|
||||
# TODO: to implement AT get binary path
|
||||
return self.app_path
|
||||
|
@ -29,7 +29,7 @@ import pexpect
|
||||
try:
|
||||
import Queue as _queue
|
||||
except ImportError:
|
||||
import queue as _queue
|
||||
import queue as _queue # type: ignore
|
||||
|
||||
from serial.tools import list_ports
|
||||
from tiny_test_fw import DUT, Utility
|
||||
@ -207,12 +207,11 @@ class IDFDUT(DUT.SerialDUT):
|
||||
if inst is not None:
|
||||
inst._port.close()
|
||||
|
||||
@_uses_esptool
|
||||
def _try_flash(self, esp, erase_nvs, baud_rate):
|
||||
def _try_flash(self, erase_nvs):
|
||||
"""
|
||||
Called by start_app() to try flashing at a particular baud rate.
|
||||
Called by start_app()
|
||||
|
||||
Structured this way so @_uses_esptool will reconnect each time
|
||||
:return: None
|
||||
"""
|
||||
flash_files = []
|
||||
encrypt_files = []
|
||||
@ -259,49 +258,51 @@ class IDFDUT(DUT.SerialDUT):
|
||||
else:
|
||||
encrypt_files.append((address, nvs_file))
|
||||
|
||||
# fake flasher args object, this is a hack until
|
||||
# esptool Python API is improved
|
||||
class FlashArgs(object):
|
||||
def __init__(self, attributes):
|
||||
for key, value in attributes.items():
|
||||
self.__setattr__(key, value)
|
||||
|
||||
# write_flash expects the parameter encrypt_files to be None and not
|
||||
# an empty list, so perform the check here
|
||||
flash_args = FlashArgs({
|
||||
'flash_size': self.app.flash_settings['flash_size'],
|
||||
'flash_mode': self.app.flash_settings['flash_mode'],
|
||||
'flash_freq': self.app.flash_settings['flash_freq'],
|
||||
'addr_filename': flash_files,
|
||||
'encrypt_files': encrypt_files or None,
|
||||
'no_stub': False,
|
||||
'compress': True,
|
||||
'verify': False,
|
||||
'encrypt': encrypt,
|
||||
'ignore_flash_encryption_efuse_setting': False,
|
||||
'erase_all': False,
|
||||
})
|
||||
|
||||
esp.change_baud(baud_rate)
|
||||
esptool.detect_flash_size(esp, flash_args)
|
||||
esptool.write_flash(esp, flash_args)
|
||||
self._write_flash(flash_files, encrypt_files, False, encrypt)
|
||||
finally:
|
||||
for (_, f) in flash_files:
|
||||
f.close()
|
||||
for (_, f) in encrypt_files:
|
||||
f.close()
|
||||
|
||||
def start_app(self, erase_nvs=ERASE_NVS):
|
||||
@_uses_esptool
|
||||
def _write_flash(self, esp, flash_files=None, encrypt_files=None, ignore_flash_encryption_efuse_setting=True, encrypt=False):
|
||||
"""
|
||||
download and start app.
|
||||
Try flashing at a particular baud rate.
|
||||
|
||||
:param: erase_nvs: whether erase NVS partition during flash
|
||||
Structured this way so @_uses_esptool will reconnect each time
|
||||
:return: None
|
||||
"""
|
||||
last_error = None
|
||||
for baud_rate in [921600, 115200]:
|
||||
try:
|
||||
self._try_flash(erase_nvs, baud_rate)
|
||||
# fake flasher args object, this is a hack until
|
||||
# esptool Python API is improved
|
||||
class FlashArgs(object):
|
||||
def __init__(self, attributes):
|
||||
for key, value in attributes.items():
|
||||
self.__setattr__(key, value)
|
||||
|
||||
# write_flash expects the parameter encrypt_files to be None and not
|
||||
# an empty list, so perform the check here
|
||||
flash_args = FlashArgs({
|
||||
'flash_size': self.app.flash_settings['flash_size'],
|
||||
'flash_mode': self.app.flash_settings['flash_mode'],
|
||||
'flash_freq': self.app.flash_settings['flash_freq'],
|
||||
'addr_filename': flash_files or None,
|
||||
'encrypt_files': encrypt_files or None,
|
||||
'no_stub': False,
|
||||
'compress': True,
|
||||
'verify': False,
|
||||
'encrypt': encrypt,
|
||||
'ignore_flash_encryption_efuse_setting': ignore_flash_encryption_efuse_setting,
|
||||
'erase_all': False,
|
||||
'after': 'no_reset',
|
||||
})
|
||||
|
||||
esp.change_baud(baud_rate)
|
||||
esptool.detect_flash_size(esp, flash_args)
|
||||
esptool.write_flash(esp, flash_args)
|
||||
break
|
||||
except RuntimeError as e:
|
||||
last_error = e
|
||||
@ -334,6 +335,58 @@ class IDFDUT(DUT.SerialDUT):
|
||||
sys.stdout = old_stdout
|
||||
return output
|
||||
|
||||
def start_app(self, erase_nvs=ERASE_NVS):
|
||||
"""
|
||||
download and start app.
|
||||
|
||||
:param: erase_nvs: whether erase NVS partition during flash
|
||||
:return: None
|
||||
"""
|
||||
self._try_flash(erase_nvs)
|
||||
|
||||
def start_app_no_enc(self):
|
||||
"""
|
||||
download and start app.
|
||||
|
||||
:param: erase_nvs: whether erase NVS partition during flash
|
||||
:return: None
|
||||
"""
|
||||
flash_files = self.app.flash_files + self.app.encrypt_files
|
||||
self.write_flash(flash_files)
|
||||
|
||||
def write_flash(self, flash_files=None, encrypt_files=None, ignore_flash_encryption_efuse_setting=True, encrypt=False):
|
||||
"""
|
||||
Flash files
|
||||
|
||||
:return: None
|
||||
"""
|
||||
flash_offs_files = []
|
||||
encrypt_offs_files = []
|
||||
try:
|
||||
if flash_files:
|
||||
flash_offs_files = [(offs, open(path, 'rb')) for (offs, path) in flash_files]
|
||||
|
||||
if encrypt_files:
|
||||
encrypt_offs_files = [(offs, open(path, 'rb')) for (offs, path) in encrypt_files]
|
||||
|
||||
self._write_flash(flash_offs_files, encrypt_offs_files, ignore_flash_encryption_efuse_setting, encrypt)
|
||||
finally:
|
||||
for (_, f) in flash_offs_files:
|
||||
f.close()
|
||||
for (_, f) in encrypt_offs_files:
|
||||
f.close()
|
||||
|
||||
def bootloader_flash(self):
|
||||
"""
|
||||
download bootloader.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
bootloader_path = os.path.join(self.app.binary_path, 'bootloader', 'bootloader.bin')
|
||||
offs = int(self.app.get_sdkconfig()['CONFIG_BOOTLOADER_OFFSET_IN_FLASH'], 0)
|
||||
flash_files = [(offs, bootloader_path)]
|
||||
self.write_flash(flash_files)
|
||||
|
||||
@_uses_esptool
|
||||
def reset(self, esp):
|
||||
"""
|
||||
@ -351,12 +404,9 @@ class IDFDUT(DUT.SerialDUT):
|
||||
:param partition: partition name to erase
|
||||
:return: None
|
||||
"""
|
||||
raise NotImplementedError() # TODO: implement this
|
||||
# address = self.app.partition_table[partition]["offset"]
|
||||
address = self.app.partition_table[partition]['offset']
|
||||
size = self.app.partition_table[partition]['size']
|
||||
# TODO can use esp.erase_region() instead of this, I think
|
||||
with open('.erase_partition.tmp', 'wb') as f:
|
||||
f.write(chr(0xFF) * size)
|
||||
esp.erase_region(address, size)
|
||||
|
||||
@_uses_esptool
|
||||
def erase_flash(self, esp):
|
||||
@ -515,9 +565,6 @@ class ESP32DUT(IDFDUT):
|
||||
def _get_rom(cls):
|
||||
return esptool.ESP32ROM
|
||||
|
||||
def erase_partition(self, esp, partition):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class ESP32S2DUT(IDFDUT):
|
||||
TARGET = 'esp32s2'
|
||||
@ -527,9 +574,6 @@ class ESP32S2DUT(IDFDUT):
|
||||
def _get_rom(cls):
|
||||
return esptool.ESP32S2ROM
|
||||
|
||||
def erase_partition(self, esp, partition):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class ESP32C3DUT(IDFDUT):
|
||||
TARGET = 'esp32c3'
|
||||
@ -539,9 +583,6 @@ class ESP32C3DUT(IDFDUT):
|
||||
def _get_rom(cls):
|
||||
return esptool.ESP32C3ROM
|
||||
|
||||
def erase_partition(self, esp, partition):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class ESP8266DUT(IDFDUT):
|
||||
TARGET = 'esp8266'
|
||||
@ -551,9 +592,6 @@ class ESP8266DUT(IDFDUT):
|
||||
def _get_rom(cls):
|
||||
return esptool.ESP8266ROM
|
||||
|
||||
def erase_partition(self, esp, partition):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
def get_target_by_rom_class(cls):
|
||||
for c in [ESP32DUT, ESP32S2DUT, ESP32C3DUT, ESP8266DUT, IDFQEMUDUT]:
|
||||
@ -652,5 +690,5 @@ class IDFQEMUDUT(IDFDUT):
|
||||
|
||||
|
||||
class ESP32QEMUDUT(IDFQEMUDUT):
|
||||
TARGET = 'esp32'
|
||||
TOOLCHAIN_PREFIX = 'xtensa-esp32-elf-'
|
||||
TARGET = 'esp32' # type: ignore
|
||||
TOOLCHAIN_PREFIX = 'xtensa-esp32-elf-' # type: ignore
|
||||
|
@ -6,6 +6,11 @@ import sys
|
||||
|
||||
from .common import BuildError, BuildItem, BuildSystem
|
||||
|
||||
try:
|
||||
from typing import Any, Optional
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
BUILD_SYSTEM_CMAKE = 'cmake'
|
||||
IDF_PY = os.path.join(os.environ['IDF_PATH'], 'tools', 'idf.py')
|
||||
|
||||
@ -38,6 +43,9 @@ class CMakeBuildSystem(BuildSystem):
|
||||
args.append('-DTESTS_ALL=1')
|
||||
if build_item.verbose:
|
||||
args.append('-v')
|
||||
if 'CONFIG_APP_BUILD_BOOTLOADER' in extra_cmakecache_items:
|
||||
# In case if secure_boot is enabled then for bootloader build need to add `bootloader` cmd
|
||||
args.append('bootloader')
|
||||
args.append('build')
|
||||
cmdline = format(' '.join(args))
|
||||
logging.info('Running {}'.format(cmdline))
|
||||
@ -70,7 +78,7 @@ class CMakeBuildSystem(BuildSystem):
|
||||
log_file.close()
|
||||
|
||||
@staticmethod
|
||||
def _read_cmakelists(app_path):
|
||||
def _read_cmakelists(app_path): # type: (str) -> Optional[str]
|
||||
cmakelists_path = os.path.join(app_path, 'CMakeLists.txt')
|
||||
if not os.path.exists(cmakelists_path):
|
||||
return None
|
||||
@ -78,7 +86,7 @@ class CMakeBuildSystem(BuildSystem):
|
||||
return cmakelists_file.read()
|
||||
|
||||
@staticmethod
|
||||
def is_app(path):
|
||||
def is_app(path): # type: (str) -> bool
|
||||
cmakelists_file_content = CMakeBuildSystem._read_cmakelists(path)
|
||||
if not cmakelists_file_content:
|
||||
return False
|
||||
@ -87,5 +95,5 @@ class CMakeBuildSystem(BuildSystem):
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def supported_targets(cls, app_path):
|
||||
def supported_targets(cls, app_path): # type: (str) -> Any
|
||||
return cls._supported_targets(app_path)
|
||||
|
@ -12,7 +12,7 @@ MAKE_PROJECT_LINE = r'include $(IDF_PATH)/make/project.mk'
|
||||
BUILD_SYSTEM_MAKE = 'make'
|
||||
|
||||
try:
|
||||
string_type = basestring
|
||||
string_type = basestring # type: ignore
|
||||
except NameError:
|
||||
string_type = str
|
||||
|
||||
@ -27,6 +27,8 @@ class MakeBuildSystem(BuildSystem):
|
||||
'make clean',
|
||||
'make defconfig',
|
||||
'make all',
|
||||
# In case if secure_boot is enabled then for bootloader build need to add `bootloader` cmd
|
||||
'make bootloader',
|
||||
'make print_flash_cmd',
|
||||
]
|
||||
|
||||
|
@ -3,4 +3,4 @@
|
||||
#
|
||||
# If you find yourself needing to edit this in the future, it's a sign the
|
||||
# bootloader is bloating out!
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xA000
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xC000
|
||||
|
@ -1,3 +1,3 @@
|
||||
CONFIG_SECURE_FLASH_ENC_ENABLED=y
|
||||
CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=y
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xA000
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xC000
|
||||
|
@ -1,3 +1,3 @@
|
||||
CONFIG_SECURE_FLASH_ENC_ENABLED=y
|
||||
CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=y
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xA000
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xC000
|
||||
|
Loading…
Reference in New Issue
Block a user