feat(esp_tee): Support for ESP-TEE - bootloader_support component

This commit is contained in:
Laukik Hase
2024-11-06 17:57:18 +05:30
parent f254f93594
commit 54c3f1bae4
10 changed files with 833 additions and 27 deletions
@@ -52,6 +52,10 @@
#include "esp_efuse.h"
#include "esp_fault.h"
#if CONFIG_SECURE_ENABLE_TEE
#include "bootloader_utility_tee.h"
#endif
static const char *TAG = "boot";
/* Reduce literal size for some generic string literals */
@@ -69,6 +73,21 @@ static void set_cache_and_start_app(uint32_t drom_addr,
uint32_t irom_size,
const esp_image_metadata_t *data);
#if CONFIG_SECURE_ENABLE_TEE
/* NOTE: Required by other sources for secure boot routine */
esp_image_metadata_t tee_data;
static uint8_t tee_boot_part = UINT8_MAX;
static void unpack_load_tee_app(const esp_image_metadata_t *data);
static void set_cache_and_load_tee_app(uint32_t drom_addr,
uint32_t drom_load_addr,
uint32_t drom_size,
uint32_t irom_addr,
uint32_t irom_load_addr,
uint32_t irom_size,
const esp_image_metadata_t *data);
#endif
esp_err_t bootloader_common_read_otadata(const esp_partition_pos_t *ota_info, esp_ota_select_entry_t *two_otadata)
{
const esp_ota_select_entry_t *ota_select_map;
@@ -162,6 +181,13 @@ bool bootloader_utility_load_partition_table(bootloader_state_t *bs)
bs->test = partition->pos;
partition_usage = "test app";
break;
#if CONFIG_SECURE_ENABLE_TEE
case PART_SUBTYPE_TEE_0: /* TEE binary */
case PART_SUBTYPE_TEE_1:
bs->tee[partition->subtype & 0x01] = partition->pos;
partition_usage = "TEE app";
break;
#endif
default:
/* OTA binary */
if ((partition->subtype & ~PART_SUBTYPE_OTA_MASK) == PART_SUBTYPE_OTA_FLAG) {
@@ -195,6 +221,15 @@ bool bootloader_utility_load_partition_table(bootloader_state_t *bs)
esp_efuse_init_virtual_mode_in_flash(partition->pos.offset, partition->pos.size);
#endif
break;
#if CONFIG_SECURE_ENABLE_TEE
case PART_SUBTYPE_DATA_TEE_OTA: /* TEE ota data */
bs->tee_ota_info = partition->pos;
partition_usage = "TEE OTA data";
break;
case PART_SUBTYPE_DATA_TEE_SEC_STORAGE: /* TEE secure storage */
partition_usage = "TEE secure storage";
break;
#endif
default:
partition_usage = "Unknown data";
break;
@@ -518,6 +553,29 @@ void bootloader_utility_load_boot_image_from_deep_sleep(void)
}
#endif
#if CONFIG_SECURE_ENABLE_TEE
void bootloader_utility_load_tee_image(const bootloader_state_t *bs)
{
esp_err_t err = ESP_FAIL;
uint8_t tee_active_part = bootloader_utility_tee_get_boot_partition(&bs->tee_ota_info);
if (tee_active_part != PART_SUBTYPE_TEE_0 && tee_active_part != PART_SUBTYPE_TEE_1) {
ESP_LOGE(TAG, "Failed to find valid TEE app");
bootloader_reset();
}
uint8_t tee_part_idx = tee_active_part & 0x01;
const esp_partition_pos_t *tee_active_part_pos = &bs->tee[tee_part_idx];
err = bootloader_load_image(tee_active_part_pos, &tee_data);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to load TEE app");
bootloader_reset();
}
tee_boot_part = tee_part_idx;
ESP_LOGI(TAG, "Loaded TEE app from partition at offset 0x%"PRIx32, tee_active_part_pos->offset);
}
#endif
#define TRY_LOG_FORMAT "Trying partition index %d offs 0x%"PRIx32" size 0x%"PRIx32
void bootloader_utility_load_boot_image(const bootloader_state_t *bs, int start_index)
@@ -856,6 +914,127 @@ static bool s_flash_seg_needs_map(uint32_t vaddr)
#endif
}
/* TODO: [IDF-11689] Unify the TEE-specific app loading implementation with
* the existing app loading implementation.
*/
#if CONFIG_SECURE_ENABLE_TEE
static void unpack_load_tee_app(const esp_image_metadata_t *data)
{
/**
* note:
* On chips with shared D/I external vaddr, we don't divide them into either D or I,
* as essentially they are the same.
* We integrate all the hardware difference into this `unpack_load_app` function.
*/
uint32_t rom_addr[2] = {};
uint32_t rom_load_addr[2] = {};
uint32_t rom_size[2] = {};
int rom_index = 0; //shall not exceed 2
// Find DROM & IROM addresses, to configure MMU mappings
for (int i = 0; i < data->image.segment_count; i++) {
const esp_image_segment_header_t *header = &data->segments[i];
const uint32_t addr = header->load_addr;
//`SOC_DROM_LOW` and `SOC_DROM_HIGH` are the same as `SOC_IROM_LOW` and `SOC_IROM_HIGH`, reasons are in above `note`
if ((addr >= SOC_DROM_LOW && addr < SOC_DROM_HIGH)
#if SOC_MMU_PER_EXT_MEM_TARGET
|| (addr >= SOC_EXTRAM_LOW && addr < SOC_EXTRAM_HIGH)
#endif
) {
/**
* D/I are shared, but there should not be a third segment on flash/psram
*/
assert(rom_index < 2);
rom_addr[rom_index] = data->segment_data[i];
rom_load_addr[rom_index] = header->load_addr;
rom_size[rom_index] = header->data_len;
rom_index++;
}
}
assert(rom_index == 2);
ESP_EARLY_LOGD(TAG, "calling set_cache_and_start_tee_app");
set_cache_and_load_tee_app(rom_addr[0],
rom_load_addr[0],
rom_size[0],
rom_addr[1],
rom_load_addr[1],
rom_size[1],
data);
}
static void set_cache_and_load_tee_app(
uint32_t drom_addr,
uint32_t drom_load_addr,
uint32_t drom_size,
uint32_t irom_addr,
uint32_t irom_load_addr,
uint32_t irom_size,
const esp_image_metadata_t *data)
{
uint32_t drom_load_addr_aligned = 0, drom_addr_aligned = 0;
uint32_t irom_load_addr_aligned = 0, irom_addr_aligned = 0;
uint32_t actual_mapped_len = 0;
const uint32_t mmu_page_size = data->mmu_page_size;
#if SOC_MMU_PAGE_SIZE_CONFIGURABLE
// re-configure MMU page size
mmu_ll_set_page_size(0, mmu_page_size);
#endif //SOC_MMU_PAGE_SIZE_CONFIGURABLE
if (drom_addr != 0) {
drom_load_addr_aligned = drom_load_addr & MMU_FLASH_MASK_FROM_VAL(mmu_page_size);
drom_addr_aligned = drom_addr & MMU_FLASH_MASK_FROM_VAL(mmu_page_size);
ESP_EARLY_LOGV(TAG, "TEE rodata starts from paddr=0x%08x, vaddr=0x%08x, size=0x%x", drom_addr, drom_load_addr, drom_size);
//The addr is aligned, so we add the mask off length to the size, to make sure the corresponding buses are enabled.
if (s_flash_seg_needs_map(drom_load_addr_aligned)) {
mmu_hal_map_region(0, MMU_TARGET_FLASH0, drom_load_addr_aligned, drom_addr_aligned, drom_size, &actual_mapped_len);
ESP_EARLY_LOGV(TAG, "after mapping rodata, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", drom_addr_aligned, drom_load_addr_aligned, actual_mapped_len);
}
//we use the MMU_LL_END_DROM_ENTRY_ID mmu entry as a map page for app to find the boot partition
mmu_hal_map_region(0, MMU_TARGET_FLASH0, MMU_DROM_END_ENTRY_VADDR_FROM_VAL(mmu_page_size), drom_addr_aligned, mmu_page_size, &actual_mapped_len);
ESP_EARLY_LOGV(TAG, "mapped one page of the rodata, from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", drom_addr_aligned, drom_load_addr_aligned, actual_mapped_len);
}
if (irom_addr != 0) {
irom_load_addr_aligned = irom_load_addr & MMU_FLASH_MASK_FROM_VAL(mmu_page_size);
irom_addr_aligned = irom_addr & MMU_FLASH_MASK_FROM_VAL(mmu_page_size);
ESP_EARLY_LOGV(TAG, "TEE text starts from paddr=0x%08x, vaddr=0x%08x, size=0x%x", irom_addr, irom_load_addr, irom_size);
//The addr is aligned, so we add the mask off length to the size, to make sure the corresponding buses are enabled.
irom_size = (irom_load_addr - irom_load_addr_aligned) + irom_size;
if (s_flash_seg_needs_map(irom_load_addr_aligned)) {
mmu_hal_map_region(0, MMU_TARGET_FLASH0, irom_load_addr_aligned, irom_addr_aligned, irom_size, &actual_mapped_len);
ESP_EARLY_LOGV(TAG, "after mapping text, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", irom_addr_aligned, irom_load_addr_aligned, actual_mapped_len);
}
}
if (drom_load_addr_aligned != 0) {
cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(0, drom_load_addr_aligned, drom_size);
cache_ll_l1_enable_bus(0, bus_mask);
}
if (irom_load_addr_aligned != 0) {
cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(0, irom_load_addr_aligned, irom_size);
cache_ll_l1_enable_bus(0, bus_mask);
}
#if !CONFIG_FREERTOS_UNICORE
if (drom_load_addr_aligned != 0) {
cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(1, drom_load_addr_aligned, drom_size);
cache_ll_l1_enable_bus(1, bus_mask);
}
if (irom_load_addr_aligned != 0) {
cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(1, irom_load_addr_aligned, irom_size);
cache_ll_l1_enable_bus(1, bus_mask);
}
#endif
}
#endif // CONFIG_SECURE_ENABLE_TEE
static void set_cache_and_start_app(
uint32_t drom_addr,
uint32_t drom_load_addr,
@@ -943,6 +1122,11 @@ static void set_cache_and_start_app(
cache_ll_l1_enable_bus(1, bus_mask);
#endif
#if CONFIG_SECURE_ENABLE_TEE
//----------------------Unpacking and loading the TEE app----------------
unpack_load_tee_app(&tee_data);
#endif
//----------------------Enable Cache----------------
#if CONFIG_IDF_TARGET_ESP32
// Application will need to do Cache_Flush(1) and Cache_Read_Enable(1)
@@ -953,12 +1137,26 @@ static void set_cache_and_start_app(
ESP_LOGD(TAG, "start: 0x%08"PRIx32, entry_addr);
bootloader_atexit();
#if CONFIG_SECURE_ENABLE_TEE
ESP_LOGI(TAG, "Current privilege level - %d", esp_cpu_get_curr_privilege_level());
/* NOTE: TEE Initialization and REE Switch
* This call will not return back. After TEE initialization,
* it will switch to the REE and execute the user application.
*/
typedef void (*esp_tee_init_t)(uint32_t, uint32_t, uint8_t) __attribute__((noreturn));
esp_tee_init_t esp_tee_init = ((esp_tee_init_t) tee_data.image.entry_addr);
ESP_LOGI(TAG, "Starting TEE: Entry point - 0x%"PRIx32, (uint32_t)esp_tee_init);
(*esp_tee_init)(entry_addr, drom_addr, tee_boot_part);
#else
typedef void (*entry_t)(void) __attribute__((noreturn));
entry_t entry = ((entry_t) entry_addr);
// TODO: we have used quite a bit of stack at this point.
// use "movsp" instruction to reset stack back to where ROM stack starts.
(*entry)();
#endif
}
void bootloader_reset(void)
@@ -0,0 +1,260 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdint.h>
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_rom_sys.h"
#include "esp_rom_crc.h"
#include "hal/efuse_hal.h"
#include "esp_image_format.h"
#include "bootloader_config.h"
#include "bootloader_flash_priv.h"
#include "bootloader_utility.h"
#include "bootloader_utility_tee.h"
#include "esp_tee_ota_utils.h"
#include "sdkconfig.h"
static const char *TAG = "boot_tee";
static esp_err_t write_tee_otadata_sector(esp_tee_ota_select_entry_t *tee_otadata, uint32_t offset)
{
if (tee_otadata == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t err = bootloader_flash_erase_sector(offset / FLASH_SECTOR_SIZE);
if (err == ESP_OK) {
bool write_encrypted = false;
#if !CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
write_encrypted = efuse_hal_flash_encryption_enabled();
#endif
err = bootloader_flash_write(offset, tee_otadata, sizeof(esp_tee_ota_select_entry_t), write_encrypted);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to write otadata sector, 0x%x", err);
}
}
return err;
}
static esp_err_t read_tee_otadata(const esp_partition_pos_t *tee_ota_info, esp_tee_ota_select_entry_t *two_otadata)
{
if (tee_ota_info == NULL || two_otadata == NULL || tee_ota_info->offset == 0) {
return ESP_ERR_INVALID_ARG;
}
if (tee_ota_info->size < 2 * FLASH_SECTOR_SIZE) {
return ESP_ERR_INVALID_SIZE;
}
ESP_LOGV(TAG, "TEE OTA data offset 0x%"PRIx32, tee_ota_info->offset);
const esp_tee_ota_select_entry_t *ota_select_map = bootloader_mmap(tee_ota_info->offset, tee_ota_info->size);
if (!ota_select_map) {
ESP_LOGE(TAG, "bootloader_mmap(0x%"PRIx32", 0x%"PRIx32") failed", tee_ota_info->offset, tee_ota_info->size);
return ESP_FAIL;
}
memcpy(&two_otadata[0], (uint8_t *)ota_select_map, sizeof(esp_tee_ota_select_entry_t));
memcpy(&two_otadata[1], (uint8_t *)ota_select_map + FLASH_SECTOR_SIZE, sizeof(esp_tee_ota_select_entry_t));
bootloader_munmap(ota_select_map);
return ESP_OK;
}
static esp_err_t write_tee_otadata(esp_tee_ota_select_entry_t *tee_otadata, const esp_partition_pos_t *tee_ota_info)
{
esp_err_t err = write_tee_otadata_sector(tee_otadata, tee_ota_info->offset);
if (err == ESP_OK) {
err = write_tee_otadata_sector(tee_otadata, tee_ota_info->offset + FLASH_SECTOR_SIZE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to update otadata sector, 0x%x", err);
}
}
return err;
}
static esp_err_t get_valid_tee_otadata(const esp_partition_pos_t *tee_ota_info, esp_tee_ota_select_entry_t *tee_otadata)
{
esp_tee_ota_select_entry_t two_otadata[2] = {0};
if (read_tee_otadata(tee_ota_info, two_otadata) != ESP_OK) {
return ESP_ERR_NOT_FOUND;
}
esp_tee_ota_select_entry_t blank_otadata;
memset(&blank_otadata, 0xff, sizeof(esp_tee_ota_select_entry_t));
// Check if the contents of both the otadata sectors match
bool sectors_match = (memcmp(&two_otadata[0], &two_otadata[1], sizeof(esp_tee_ota_select_entry_t)) == 0);
if (sectors_match) {
if (memcmp(&two_otadata[0], &blank_otadata, sizeof(esp_tee_ota_select_entry_t)) != 0) {
uint32_t crc = esp_rom_crc32_le(0, (uint8_t const *)two_otadata, (sizeof(esp_tee_ota_select_entry_t) - sizeof(uint32_t)));
if (two_otadata[0].magic != TEE_OTADATA_MAGIC || crc != two_otadata[0].crc) {
ESP_LOGE(TAG, "TEE otadata[0] magic or CRC verification failed");
return ESP_FAIL;
}
}
memcpy(tee_otadata, &two_otadata[0], sizeof(esp_tee_ota_select_entry_t));
ESP_LOGV(TAG, "Both tee_otadata sectors are the same");
} else {
uint32_t crc_otadata0 = esp_rom_crc32_le(0, (uint8_t const *)&two_otadata[0], (sizeof(esp_tee_ota_select_entry_t) - sizeof(uint32_t)));
uint32_t crc_otadata1 = esp_rom_crc32_le(0, (uint8_t const *)&two_otadata[1], (sizeof(esp_tee_ota_select_entry_t) - sizeof(uint32_t)));
if (crc_otadata0 == two_otadata[0].crc) {
ESP_LOGV(TAG, "Second tee_otadata sector is invalid - copying contents from first sector");
// Copy contents of first tee_otadata sector into second
write_tee_otadata_sector(&two_otadata[0], tee_ota_info->offset + FLASH_SECTOR_SIZE);
memcpy(tee_otadata, &two_otadata[0], sizeof(esp_tee_ota_select_entry_t));
} else if (crc_otadata1 == two_otadata[1].crc) {
ESP_LOGV(TAG, "First tee_otadata sector is invalid - copying contents from second sector");
// Copy contents of second tee_otadata sector into first
write_tee_otadata_sector(&two_otadata[1], tee_ota_info->offset);
memcpy(tee_otadata, &two_otadata[1], sizeof(esp_tee_ota_select_entry_t));
} else {
ESP_LOGE(TAG, "Both tee_otadata sectors are invalid!");
abort();
}
}
return ESP_OK;
}
static esp_err_t update_tee_otadata(const esp_partition_pos_t *tee_ota_info, uint8_t boot_partition, uint8_t ota_state)
{
esp_tee_ota_select_entry_t otadata = {
.magic = TEE_OTADATA_MAGIC,
.boot_partition = boot_partition,
.ota_state = ota_state,
};
otadata.crc = esp_rom_crc32_le(0, (uint8_t const *)&otadata, (sizeof(esp_tee_ota_select_entry_t) - sizeof(uint32_t)));
return write_tee_otadata(&otadata, tee_ota_info);
}
int bootloader_utility_tee_get_boot_partition(const esp_partition_pos_t *tee_ota_info)
{
esp_tee_ota_select_entry_t otadata = {}, blank_otadata;
const int default_tee_app_slot = PART_SUBTYPE_TEE_0;
esp_err_t err = get_valid_tee_otadata(tee_ota_info, &otadata);
if (err == ESP_ERR_NOT_FOUND) {
ESP_LOGV(TAG, "otadata partition not found, booting from first partition");
return default_tee_app_slot;
}
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to get valid otadata, 0x%x", err);
return -1;
}
memset(&blank_otadata, 0xff, sizeof(esp_tee_ota_select_entry_t));
if (!memcmp(&blank_otadata, &otadata, sizeof(esp_tee_ota_select_entry_t))) {
ESP_LOGV(TAG, "otadata partition empty, booting from first partition");
/* NOTE: The first TEE partition will always be valid as it is flashed manually */
if (update_tee_otadata(tee_ota_info, default_tee_app_slot, ESP_TEE_OTA_IMG_VALID) != ESP_OK) {
ESP_LOGW(TAG, "Failed to setup TEE otadata as per the first partition!");
}
return default_tee_app_slot;
}
int boot_partition = 0;
#if BOOTLOADER_BUILD
switch(otadata.ota_state) {
case ESP_TEE_OTA_IMG_NEW:
ESP_LOGD(TAG, "TEE otadata - Current image state: NEW");
boot_partition = otadata.boot_partition;
if (update_tee_otadata(tee_ota_info, otadata.boot_partition, ESP_TEE_OTA_IMG_PENDING_VERIFY) != ESP_OK) {
return -1;
}
break;
case ESP_TEE_OTA_IMG_UNDEFINED:
case ESP_TEE_OTA_IMG_PENDING_VERIFY:
ESP_LOGD(TAG, "TEE otadata - Current image state: PENDING_VERIFY/UNDEFINED");
boot_partition = (otadata.boot_partition == PART_SUBTYPE_TEE_0) ? PART_SUBTYPE_TEE_1 : PART_SUBTYPE_TEE_0;
if (update_tee_otadata(tee_ota_info, boot_partition, ESP_TEE_OTA_IMG_INVALID) != ESP_OK) {
return -1;
}
break;
case ESP_TEE_OTA_IMG_INVALID:
ESP_LOGD(TAG, "TEE otadata - Current image state: INVALID");
bootloader_reset();
break;
case ESP_TEE_OTA_IMG_VALID:
ESP_LOGD(TAG, "TEE otadata - Current image state: VALID");
boot_partition = otadata.boot_partition;
break;
break;
default:
break;
}
#else
boot_partition = otadata.boot_partition;
#endif
return boot_partition;
}
esp_err_t bootloader_utility_tee_set_boot_partition(const esp_partition_pos_t *tee_ota_info, const esp_partition_info_t *tee_try_part)
{
if (tee_ota_info == NULL || tee_try_part == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (tee_try_part->subtype != PART_SUBTYPE_TEE_0 && tee_try_part->subtype != PART_SUBTYPE_TEE_1) {
return ESP_ERR_INVALID_ARG;
}
esp_image_metadata_t data = {};
if (esp_image_verify(ESP_IMAGE_VERIFY, &tee_try_part->pos, &data) != ESP_OK) {
return ESP_ERR_IMAGE_INVALID;
}
return update_tee_otadata(tee_ota_info, tee_try_part->subtype, ESP_TEE_OTA_IMG_NEW);
}
int bootloader_utility_tee_get_next_update_partition(const esp_partition_pos_t *tee_ota_info)
{
esp_tee_ota_select_entry_t otadata = {}, blank_otadata;
const int default_tee_next_app_slot = PART_SUBTYPE_TEE_1;
esp_err_t err = get_valid_tee_otadata(tee_ota_info, &otadata);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to get valid otadata, 0x%x", err);
return -1;
}
memset(&blank_otadata, 0xff, sizeof(esp_tee_ota_select_entry_t));
if (!memcmp(&blank_otadata, &otadata, sizeof(esp_tee_ota_select_entry_t))) {
return default_tee_next_app_slot;
}
return (otadata.boot_partition == PART_SUBTYPE_TEE_0) ? PART_SUBTYPE_TEE_1 : PART_SUBTYPE_TEE_0;
}
esp_err_t bootloader_utility_tee_mark_app_valid_and_cancel_rollback(const esp_partition_pos_t *tee_ota_info)
{
esp_tee_ota_select_entry_t two_otadata[2];
esp_err_t err = read_tee_otadata(tee_ota_info, two_otadata);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to fetch TEE otadata!");
return err;
}
if (two_otadata[0].ota_state == ESP_TEE_OTA_IMG_VALID) {
ESP_LOGD(TAG, "TEE otadata - Current image already has been marked VALID");
return ESP_ERR_INVALID_STATE;
}
int tee_app_slot = bootloader_utility_tee_get_boot_partition(tee_ota_info);
return update_tee_otadata(tee_ota_info, (uint8_t)tee_app_slot, ESP_TEE_OTA_IMG_VALID);
}
@@ -23,6 +23,10 @@
#ifdef CONFIG_SECURE_BOOT_V2_ENABLED
#if CONFIG_SECURE_ENABLE_TEE
extern esp_image_metadata_t tee_data;
#endif
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
static const char *TAG = "secure_boot_v2";
@@ -268,6 +272,28 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
ESP_LOGW(TAG, "App has %d signature blocks but bootloader only has %d. Some keys missing from bootloader?", app_key_digests.num_digests, boot_key_digests.num_digests);
}
#if CONFIG_SECURE_ENABLE_TEE
/* Generate the TEE public key digests */
bool tee_match = false;
esp_image_sig_public_key_digests_t tee_key_digests = {0};
ret = s_calculate_image_public_key_digests(tee_data.start_addr, tee_data.image_len - SIG_BLOCK_PADDING, &tee_key_digests);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "TEE signature block is invalid.");
return ret;
}
if (tee_key_digests.num_digests == 0) {
ESP_LOGE(TAG, "No valid TEE signature blocks found.");
return ESP_FAIL;
}
ESP_LOGI(TAG, "%d signature block(s) found appended to the tee.", tee_key_digests.num_digests);
if (tee_key_digests.num_digests > boot_key_digests.num_digests) {
ESP_LOGW(TAG, "TEE has %d signature blocks but bootloader only has %d. Some keys missing from bootloader?", tee_key_digests.num_digests, boot_key_digests.num_digests);
}
#endif
/* 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;
@@ -285,6 +311,18 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
match = true;
}
}
#if CONFIG_SECURE_ENABLE_TEE
if (!match) {
continue;
}
for (unsigned j = 0; j < tee_key_digests.num_digests; j++) {
if (!memcmp(boot_key_digests.key_digests[i], tee_key_digests.key_digests[j], ESP_SECURE_BOOT_DIGEST_LEN)) {
ESP_LOGI(TAG, "TEE key(%d) matches with bootloader key(%d).", j, i);
tee_match = true;
}
}
#endif
}
if (match == false) {
@@ -292,6 +330,13 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
return ESP_FAIL;
}
#if CONFIG_SECURE_ENABLE_TEE
if (tee_match == false) {
ESP_LOGE(TAG, "No TEE key digest matches the bootloader key digest.");
return ESP_FAIL;
}
#endif
#if SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
/* Revoke the empty signature blocks */
if (boot_key_digests.num_digests < SECURE_BOOT_NUM_BLOCKS) {