Merge branch 'feature/esp_tee_flash_prot_spi1' into 'master'

feat(esp_tee): Add support for flash memory isolation and protection (SPI1)

Closes IDF-10481, IDF-10083, and IDF-8915

See merge request espressif/esp-idf!36454
This commit is contained in:
Mahavir Jain 2025-02-12 18:35:49 +08:00
commit 870a1846b1
48 changed files with 1241 additions and 245 deletions

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -752,6 +752,15 @@ esp_err_t IRAM_ATTR bootloader_flash_unlock_default(void)
esp_err_t __attribute__((weak, alias("bootloader_flash_unlock_default"))) bootloader_flash_unlock(void);
#if CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1 && !NON_OS_BUILD
extern uint32_t bootloader_flash_execute_command_common(
uint8_t command,
uint32_t addr_len, uint32_t address,
uint8_t dummy_len,
uint8_t mosi_len, uint32_t mosi_data,
uint8_t miso_len);
#else
IRAM_ATTR uint32_t bootloader_flash_execute_command_common(
uint8_t command,
uint32_t addr_len, uint32_t address,
@ -804,6 +813,7 @@ IRAM_ATTR uint32_t bootloader_flash_execute_command_common(
}
return ret;
}
#endif
uint32_t IRAM_ATTR bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)
{

View File

@ -1,5 +1,5 @@
idf_build_get_property(esp_tee_build ESP_TEE_BUILD)
idf_build_get_property(custom_secure_service_tbl CUSTOM_SECURE_SERVICE_TBL)
idf_build_get_property(custom_secure_service_yaml CUSTOM_SECURE_SERVICE_YAML)
idf_build_get_property(custom_secure_service_dir CUSTOM_SECURE_SERVICE_COMPONENT_DIR)
idf_build_get_property(custom_secure_service_component CUSTOM_SECURE_SERVICE_COMPONENT)
idf_build_get_property(target IDF_TARGET)
@ -82,33 +82,37 @@ else()
endif()
endif()
set(secure_service_tbl_parser_py
${COMPONENT_DIR}/scripts/secure_service_tbl_parser.py ${CMAKE_CURRENT_BINARY_DIR}/secure_service.tbl
set(secure_service_yml
${COMPONENT_DIR}/scripts/${IDF_TARGET}/sec_srv_tbl_default.yml ${custom_secure_service_yaml}
)
set(secure_service_gen_headers
${CONFIG_DIR}/secure_service_num.h ${CONFIG_DIR}/secure_service_dec.h
${CONFIG_DIR}/secure_service_int.h ${CONFIG_DIR}/secure_service_ext.h
set(secure_service_yml_parser_py
${COMPONENT_DIR}/scripts/secure_service_yml_parser.py
)
if(CONFIG_SECURE_ENABLE_TEE AND NOT esp_tee_build)
# Default secure service API families: flash_protection_spi0, flash_protection_spi1,
# interrupt_handling, hal, crypto, efuse, secure_storage, ota, attestation
set(exclude_srv)
if(NOT CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1)
list(APPEND exclude_srv "flash_protection_spi1")
endif()
if(NOT CONFIG_SECURE_TEE_ATTESTATION)
list(APPEND exclude_srv "attestation")
endif()
execute_process(
COMMAND cat ${COMPONENT_DIR}/scripts/${target}/secure_service.tbl ${custom_secure_service_tbl}
OUTPUT_FILE secure_service.tbl
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND python ${secure_service_yml_parser_py}
"--sec_srv" ${secure_service_yml}
"--exclude" ${exclude_srv}
WORKING_DIRECTORY ${CONFIG_DIR}
)
execute_process(
COMMAND python ${secure_service_tbl_parser_py} ${secure_service_gen_headers}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
set_property(DIRECTORY ${COMPONENT_DIR} APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES ${secure_service_gen_headers}
)
execute_process(
COMMAND python ${secure_service_tbl_parser_py} "--wrap"
COMMAND python ${secure_service_yml_parser_py}
"--sec_srv" ${secure_service_yml}
"--exclude" ${exclude_srv} "--wrap"
OUTPUT_VARIABLE wrap_list
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
OUTPUT_STRIP_TRAILING_WHITESPACE

View File

@ -110,6 +110,35 @@ menu "ESP-TEE (Trusted Execution Environment)"
endmenu
config SECURE_TEE_EXT_FLASH_MEMPROT_SPI1
bool "Memprot: Isolate TEE flash regions over SPI1"
depends on SECURE_ENABLE_TEE
default n
help
This configuration restricts access to TEE-reserved regions in external flash
by making them inaccessible to the REE via the SPI1 interface (physical addresses).
With this enabled, all SPI flash read, write, or erase operations over SPI1 will
be routed through service calls to the TEE, introducing additional performance
overhead.
When Flash Encryption (SECURE_FLASH_ENC_ENABLED) is enabled, the REE can still
access TEE-related flash partitions over SPI1, but read operations will return
encrypted data contents. This prevents attackers from inferring the TEE contents
with direct reads.
Additionally, with Secure Boot enabled (SECURE_BOOT_V2_ENABLED), any unauthorized
modifications to the TEE firmware will be detected during boot, causing signature
verification to fail. Thus, these options provide a level of protection suitable for
most applications. However, while the TEE firmware integrity is protected, other TEE
partitions (Secure Storage, TEE OTA data) can be manipulated through direct writes.
Enable this option only when complete isolation of all TEE flash regions is required,
even with the associated performance tradeoffs.
Note: All accesses to the TEE partitions over SPI0 (i.e. the MMU) are blocked
unconditionally.
config SECURE_TEE_DEBUG_MODE
bool "Enable Debug Mode"
default y

View File

@ -0,0 +1,283 @@
secure_services:
- family: misc
entries:
- id: 0
type: custom
function: invalid_secure_service
args: 0
# ID: 1-4 (4) - External memory (Flash) protection [SPI0]
- family: flash_protection_spi0
entries:
- id: 1
type: IDF
function: mmu_hal_map_region
args: 6
- id: 2
type: IDF
function: mmu_hal_unmap_region
args: 3
- id: 3
type: IDF
function: mmu_hal_vaddr_to_paddr
args: 4
- id: 4
type: IDF
function: mmu_hal_paddr_to_vaddr
args: 5
# ID: 5-21 (17) - External memory (Flash) protection [SPI1]
- family: flash_protection_spi1
entries:
- id: 5
type: IDF
function: spi_flash_hal_check_status
args: 1
- id: 6
type: IDF
function: spi_flash_hal_common_command
args: 2
- id: 7
type: IDF
function: spi_flash_hal_device_config
args: 1
- id: 8
type: IDF
function: spi_flash_hal_erase_block
args: 2
- id: 9
type: IDF
function: spi_flash_hal_erase_chip
args: 1
- id: 10
type: IDF
function: spi_flash_hal_erase_sector
args: 2
- id: 11
type: IDF
function: spi_flash_hal_program_page
args: 4
- id: 12
type: IDF
function: spi_flash_hal_read
args: 4
- id: 13
type: IDF
function: spi_flash_hal_resume
args: 1
- id: 14
type: IDF
function: spi_flash_hal_set_write_protect
args: 2
- id: 15
type: IDF
function: spi_flash_hal_setup_read_suspend
args: 2
- id: 16
type: IDF
function: spi_flash_hal_supports_direct_read
args: 2
- id: 17
type: IDF
function: spi_flash_hal_supports_direct_write
args: 2
- id: 18
type: IDF
function: spi_flash_hal_suspend
args: 1
- id: 19
type: IDF
function: bootloader_flash_execute_command_common
args: 7
- id: 20
type: IDF
function: memspi_host_flush_cache
args: 3
- id: 21
type: IDF
function: spi_flash_chip_generic_config_host_io_mode
args: 2
# ID: 30-53 (24) - Interrupt Handling
- family: interrupt_handling
entries:
- id: 30
type: IDF
function: esp_rom_route_intr_matrix
args: 3
- id: 31
type: IDF
function: rv_utils_intr_enable
args: 1
- id: 32
type: IDF
function: rv_utils_intr_disable
args: 1
- id: 33
type: IDF
function: rv_utils_intr_set_priority
args: 2
- id: 34
type: IDF
function: rv_utils_intr_set_type
args: 2
- id: 35
type: IDF
function: rv_utils_intr_set_threshold
args: 1
- id: 36
type: IDF
function: rv_utils_intr_edge_ack
args: 1
- id: 37
type: IDF
function: rv_utils_intr_global_enable
args: 0
# ID: 54-85 (32) - HAL
- family: hal
entries:
- id: 54
type: IDF
function: efuse_hal_chip_revision
args: 0
- id: 55
type: IDF
function: efuse_hal_get_chip_ver_pkg
args: 1
- id: 56
type: IDF
function: efuse_hal_get_disable_wafer_version_major
args: 0
- id: 57
type: IDF
function: efuse_hal_get_mac
args: 1
- id: 58
type: IDF
function: wdt_hal_init
args: 4
- id: 59
type: IDF
function: wdt_hal_deinit
args: 1
# ID: 86-133 (48) - Crypto
- family: crypto
entries:
- id: 86
type: IDF
function: esp_aes_intr_alloc
args: 0
- id: 87
type: IDF
function: esp_aes_crypt_cbc
args: 6
- id: 88
type: IDF
function: esp_aes_crypt_cfb8
args: 6
- id: 89
type: IDF
function: esp_aes_crypt_cfb128
args: 7
- id: 90
type: IDF
function: esp_aes_crypt_ctr
args: 7
- id: 91
type: IDF
function: esp_aes_crypt_ecb
args: 4
- id: 92
type: IDF
function: esp_aes_crypt_ofb
args: 6
- id: 93
type: IDF
function: esp_sha
args: 4
- id: 94
type: IDF
function: esp_sha_block
args: 3
- id: 95
type: IDF
function: esp_sha_dma
args: 6
- id: 96
type: IDF
function: esp_sha_read_digest_state
args: 2
- id: 97
type: IDF
function: esp_sha_write_digest_state
args: 2
# ID: 134-149 (16) - eFuse
- family: efuse
entries:
- id: 134
type: IDF
function: esp_efuse_check_secure_version
args: 1
- id: 135
type: IDF
function: esp_efuse_read_field_blob
args: 3
- id: 136
type: IDF
function: esp_flash_encryption_enabled
args: 0
# ID: 150-169 (20) - Reserved for future use
- family: attestation
entries:
- id: 170
type: custom
function: esp_tee_att_generate_token
args: 6
# ID: 175-194 (20) - Secure Storage
- family: secure_storage
entries:
- id: 175
type: custom
function: esp_tee_sec_storage_init
args: 0
- id: 176
type: custom
function: esp_tee_sec_storage_gen_key
args: 2
- id: 177
type: custom
function: esp_tee_sec_storage_get_signature
args: 4
- id: 178
type: custom
function: esp_tee_sec_storage_get_pubkey
args: 2
- id: 179
type: custom
function: esp_tee_sec_storage_encrypt
args: 8
- id: 180
type: custom
function: esp_tee_sec_storage_decrypt
args: 8
- id: 181
type: custom
function: esp_tee_sec_storage_is_slot_empty
args: 1
- id: 182
type: custom
function: esp_tee_sec_storage_clear_slot
args: 1
# ID: 195-199 (5) - OTA
- family: ota
entries:
- id: 195
type: custom
function: esp_tee_ota_begin
args: 0
- id: 196
type: custom
function: esp_tee_ota_write
args: 3
- id: 197
type: custom
function: esp_tee_ota_end
args: 0
# ID: 200+ - User-defined

View File

@ -1,57 +0,0 @@
# SS no. API type Function Args
0 custom invalid_secure_service 0
# ID: 1-47 (47) - External memory (Flash) protection
1 IDF mmu_hal_map_region 6
2 IDF mmu_hal_unmap_region 3
3 IDF mmu_hal_vaddr_to_paddr 4
4 IDF mmu_hal_paddr_to_vaddr 5
# Services before the ID 48 will be placed in the internal memory table,
# while the rest will be placed in the external memory table.
# ID: 48-71 (24) - Interrupt Handling
48 IDF esp_rom_route_intr_matrix 3
49 IDF rv_utils_intr_enable 1
50 IDF rv_utils_intr_disable 1
51 IDF rv_utils_intr_set_priority 2
52 IDF rv_utils_intr_set_type 2
53 IDF rv_utils_intr_set_threshold 1
54 IDF rv_utils_intr_edge_ack 1
55 IDF rv_utils_intr_global_enable 0
# ID: 72-119 (48) - HAL
72 IDF efuse_hal_chip_revision 0
73 IDF efuse_hal_get_chip_ver_pkg 1
74 IDF efuse_hal_get_disable_wafer_version_major 0
75 IDF efuse_hal_get_mac 1
76 IDF wdt_hal_init 4
77 IDF wdt_hal_deinit 1
# ID: 120-167 (48) - Crypto
120 IDF esp_aes_intr_alloc 0
121 IDF esp_aes_crypt_cbc 6
122 IDF esp_aes_crypt_cfb8 6
123 IDF esp_aes_crypt_cfb128 7
124 IDF esp_aes_crypt_ctr 7
125 IDF esp_aes_crypt_ecb 4
126 IDF esp_aes_crypt_ofb 6
127 IDF esp_sha 4
128 IDF esp_sha_dma 6
129 IDF esp_sha_read_digest_state 2
130 IDF esp_sha_write_digest_state 2
131 IDF esp_sha_block 3
# ID: 168-183 (16) - eFuse
168 IDF esp_efuse_check_secure_version 1
169 IDF esp_efuse_read_field_blob 3
170 IDF esp_flash_encryption_enabled 0
# ID: 184-249 (66) - Reserved for future use
# ID: 270-293 (24) - Secure Storage
270 custom esp_tee_sec_storage_init 0
271 custom esp_tee_sec_storage_gen_key 2
272 custom esp_tee_sec_storage_get_signature 4
273 custom esp_tee_sec_storage_get_pubkey 2
274 custom esp_tee_sec_storage_encrypt 8
275 custom esp_tee_sec_storage_decrypt 8
276 custom esp_tee_sec_storage_is_slot_empty 1
277 custom esp_tee_sec_storage_clear_slot 1
# ID: 294-299 (6) - OTA
294 custom esp_tee_ota_begin 0
295 custom esp_tee_ota_write 3
296 custom esp_tee_ota_end 0
# ID: 300+ - User-defined

View File

@ -1,25 +1,37 @@
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import argparse
import re
from typing import List
from typing import Set
from typing import Tuple
SEC_SRV_TABLE_SPLIT_ID = 48
import yaml
SEC_SRV_TABLE_SPLIT_ID = 30
OUTPUT_HEADERS = [
'secure_service_num.h',
'secure_service_dec.h',
'secure_service_int.h',
'secure_service_ext.h',
]
def parse_services(secure_service_tbl: str) -> List[Tuple[int, str, int]]:
def parse_services(yml_files: List[str], excluded_fam: Set[str]) -> List[Tuple[int, str, int]]:
services, service_ids = [], set()
pattern = re.compile(r'^([0-9A-Fa-fXx]+)\s+\S+\s+(\S+)\s+(\d+)')
with open(secure_service_tbl, 'r') as f:
for line in f:
if match := pattern.match(line):
service_id = int(match.group(1), 0)
if service_id in service_ids:
raise ValueError(f'Duplicate service call ID found: 0x{service_id:X}')
service_ids.add(service_id)
services.append((service_id, match.group(2), int(match.group(3))))
for yml_file in yml_files:
with open(yml_file, 'r') as f:
data = yaml.safe_load(f)
for family in data.get('secure_services', []):
family_name = family.get('family', '')
if family_name in excluded_fam:
continue
for entry in family.get('entries', []):
service_id = entry['id']
if service_id in service_ids:
raise ValueError(f'Duplicate service call ID found: 0x{service_id:X}')
service_ids.add(service_id)
services.append((service_id, entry['function'], entry['args']))
return sorted(services, key=lambda x: x[0])
@ -83,30 +95,36 @@ def generate_table_split(services: List[Tuple[int, str, int]], output_file_1: st
f2.write(header + body_2)
def generate_wrap_list(secure_service_tbl: str) -> None:
pattern = re.compile(r'^[0-9A-Fa-fXx]+\s+IDF\s+(\S+)\s+\d+')
with open(secure_service_tbl, 'r') as f:
wrap_list = [f'-Wl,--wrap={match.group(1)}' for line in f if (match := pattern.match(line))]
def generate_wrap_list(yml_files: List[str], excluded_fam: Set[str]) -> None:
wrap_list: list[str] = []
for yml_file in yml_files:
with open(yml_file, 'r') as f:
data = yaml.safe_load(f)
wrap_list.extend(
f'-Wl,--wrap={entry["function"]}'
for family in data.get('secure_services', [])
for entry in family.get('entries', [])
if entry['type'] == 'IDF' and family.get('family', '') not in excluded_fam
)
print(' '.join(wrap_list), end='')
def main() -> None:
parser = argparse.ArgumentParser(description='Generate secure service outputs')
parser = argparse.ArgumentParser(description='Generate secure service outputs from YAML table')
parser.add_argument('--wrap', action='store_true', help='Generate linker wrap options')
parser.add_argument('secure_service_tbl', type=str, help='Path to secure service table file')
parser.add_argument('output_files', nargs='*', help='Output files: [secure_service_num.h, secure_service_dec.h, secure_service_1.h, secure_service_2.h]')
parser.add_argument('-s', '--sec_srv', nargs='+', required=True, help='Secure service table(s) in YAML')
parser.add_argument('--exclude', nargs='*', default=[], help='List of API families to exclude from the output')
args = parser.parse_args()
excluded_fam = set(args.exclude)
if args.wrap:
generate_wrap_list(args.secure_service_tbl)
generate_wrap_list(args.sec_srv, excluded_fam)
else:
if len(args.output_files) != 4:
parser.error('Missing output header files!')
services = parse_services(args.secure_service_tbl)
generate_num_header(services, args.output_files[0])
generate_dec_header(services, args.output_files[1])
generate_table_split(services, args.output_files[2], args.output_files[3])
services = parse_services(args.sec_srv, excluded_fam)
generate_num_header(services, OUTPUT_HEADERS[0])
generate_dec_header(services, OUTPUT_HEADERS[1])
generate_table_split(services, OUTPUT_HEADERS[2], OUTPUT_HEADERS[3])
if __name__ == '__main__':

View File

@ -13,6 +13,8 @@
#include "hal/sha_hal.h"
#include "hal/mmu_types.h"
#include "hal/wdt_hal.h"
#include "hal/spi_flash_types.h"
#include "esp_flash.h"
#include "soc/soc_caps.h"
@ -247,3 +249,101 @@ bool IRAM_ATTR __wrap_mmu_hal_paddr_to_vaddr(uint32_t mmu_id, uint32_t paddr, mm
{
return esp_tee_service_call(6, SS_MMU_HAL_PADDR_TO_VADDR, mmu_id, paddr, target, type, out_vaddr);
}
#if CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1
/* ---------------------------------------------- SPI Flash HAL ------------------------------------------------- */
uint32_t IRAM_ATTR __wrap_spi_flash_hal_check_status(spi_flash_host_inst_t *host)
{
return esp_tee_service_call(2, SS_SPI_FLASH_HAL_CHECK_STATUS, host);
}
esp_err_t IRAM_ATTR __wrap_spi_flash_hal_common_command(spi_flash_host_inst_t *host, spi_flash_trans_t *trans)
{
return esp_tee_service_call(3, SS_SPI_FLASH_HAL_COMMON_COMMAND, host, trans);
}
esp_err_t IRAM_ATTR __wrap_spi_flash_hal_device_config(spi_flash_host_inst_t *host)
{
return esp_tee_service_call(2, SS_SPI_FLASH_HAL_DEVICE_CONFIG, host);
}
void IRAM_ATTR __wrap_spi_flash_hal_erase_block(spi_flash_host_inst_t *host, uint32_t start_address)
{
esp_tee_service_call(3, SS_SPI_FLASH_HAL_ERASE_BLOCK, host, start_address);
}
void IRAM_ATTR __wrap_spi_flash_hal_erase_chip(spi_flash_host_inst_t *host)
{
esp_tee_service_call(2, SS_SPI_FLASH_HAL_ERASE_CHIP, host);
}
void IRAM_ATTR __wrap_spi_flash_hal_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address)
{
esp_tee_service_call(3, SS_SPI_FLASH_HAL_ERASE_SECTOR, host, start_address);
}
void IRAM_ATTR __wrap_spi_flash_hal_program_page(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length)
{
esp_tee_service_call(5, SS_SPI_FLASH_HAL_PROGRAM_PAGE, host, buffer, address, length);
}
esp_err_t IRAM_ATTR __wrap_spi_flash_hal_read(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len)
{
return esp_tee_service_call(5, SS_SPI_FLASH_HAL_READ, host, buffer, address, read_len);
}
void IRAM_ATTR __wrap_spi_flash_hal_resume(spi_flash_host_inst_t *host)
{
esp_tee_service_call(2, SS_SPI_FLASH_HAL_RESUME, host);
}
esp_err_t IRAM_ATTR __wrap_spi_flash_hal_set_write_protect(spi_flash_host_inst_t *host, bool wp)
{
return esp_tee_service_call(3, SS_SPI_FLASH_HAL_SET_WRITE_PROTECT, host, wp);
}
esp_err_t IRAM_ATTR __wrap_spi_flash_hal_setup_read_suspend(spi_flash_host_inst_t *host, const spi_flash_sus_cmd_conf *sus_conf)
{
return esp_tee_service_call(6, SS_SPI_FLASH_HAL_SETUP_READ_SUSPEND, host, sus_conf);
}
bool IRAM_ATTR __wrap_spi_flash_hal_supports_direct_read(spi_flash_host_inst_t *host, const void *p)
{
return esp_tee_service_call(3, SS_SPI_FLASH_HAL_SUPPORTS_DIRECT_READ, host, p);
}
bool IRAM_ATTR __wrap_spi_flash_hal_supports_direct_write(spi_flash_host_inst_t *host, const void *p)
{
return esp_tee_service_call(3, SS_SPI_FLASH_HAL_SUPPORTS_DIRECT_WRITE, host, p);
}
void IRAM_ATTR __wrap_spi_flash_hal_suspend(spi_flash_host_inst_t *host)
{
esp_tee_service_call(2, SS_SPI_FLASH_HAL_SUSPEND, host);
}
/* ---------------------------------------------- SPI Flash Extras ------------------------------------------------- */
uint32_t IRAM_ATTR __wrap_bootloader_flash_execute_command_common(
uint8_t command,
uint32_t addr_len, uint32_t address,
uint8_t dummy_len,
uint8_t mosi_len, uint32_t mosi_data,
uint8_t miso_len)
{
return esp_tee_service_call(8, SS_BOOTLOADER_FLASH_EXECUTE_COMMAND_COMMON,
command, addr_len, address, dummy_len, mosi_len,
mosi_data, miso_len);
}
esp_err_t IRAM_ATTR __wrap_memspi_host_flush_cache(spi_flash_host_inst_t *host, uint32_t addr, uint32_t size)
{
return esp_tee_service_call(4, SS_MEMSPI_HOST_FLUSH_CACHE, host, addr, size);
}
esp_err_t IRAM_ATTR __wrap_spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip, uint32_t flags)
{
return esp_tee_service_call(3, SS_SPI_FLASH_CHIP_GENERIC_CONFIG_HOST_IO_MODE, chip, flags);
}
#endif

View File

@ -1,5 +0,0 @@
# This file must be manually included in the project's top level CMakeLists.txt before project()
# This ensures that the variables are set before TEE starts building
# Append secure service table consisting of secure services
idf_build_set_property(CUSTOM_SECURE_SERVICE_TBL ${CMAKE_CURRENT_LIST_DIR}/esp_tee_att.tbl APPEND)

View File

@ -1,2 +0,0 @@
# SS no. API type Function Args
250 custom esp_tee_att_generate_token 6

View File

@ -54,6 +54,10 @@ list(APPEND srcs "${hal_dir}/apm_hal.c"
"${hal_dir}/brownout_hal.c"
"${hal_dir}/wdt_hal_iram.c")
if(CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1)
list(APPEND srcs "${hal_dir}/spi_flash_hal.c")
endif()
# TLSF implementation for heap
list(APPEND include "${heap_dir}/include"
"${heap_dir}/tlsf"

View File

@ -11,7 +11,6 @@
#include "esp_flash.h"
#include "esp_flash_encrypt.h"
#include "esp_rom_efuse.h"
#include "esp_fault.h"
#include "hal/efuse_hal.h"
#include "hal/mmu_types.h"
@ -19,6 +18,11 @@
#include "hal/wdt_hal.h"
#include "hal/sha_hal.h"
#include "hal/spi_flash_hal.h"
#include "hal/spi_flash_types.h"
#include "spi_flash_chip_generic.h"
#include "memspi_host_driver.h"
#include "soc/soc_caps.h"
#include "aes/esp_aes.h"
#include "sha/sha_core.h"
@ -34,6 +38,8 @@
#include "esp_tee_ota_ops.h"
#include "esp_attestation.h"
static __attribute__((unused)) const char *TAG = "esp_tee_sec_srv";
void _ss_invalid_secure_service(void)
{
assert(0);
@ -449,7 +455,7 @@ void _ss_mmu_hal_map_region(uint32_t mmu_id, mmu_target_t mem_type, uint32_t vad
if (vaddr_chk || paddr_chk) {
return;
}
ESP_FAULT_ASSERT(!vaddr_chk && !vaddr_chk);
ESP_FAULT_ASSERT(!vaddr_chk && !paddr_chk);
mmu_hal_map_region(mmu_id, mem_type, vaddr, paddr, len, out_len);
}
@ -484,3 +490,151 @@ bool _ss_mmu_hal_paddr_to_vaddr(uint32_t mmu_id, uint32_t paddr, mmu_target_t ta
ESP_FAULT_ASSERT(!paddr_chk);
return mmu_hal_paddr_to_vaddr(mmu_id, paddr, target, type, out_vaddr);
}
#if CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1
/* ---------------------------------------------- SPI Flash HAL ------------------------------------------------- */
uint32_t _ss_spi_flash_hal_check_status(spi_flash_host_inst_t *host)
{
return spi_flash_hal_check_status(host);
}
esp_err_t _ss_spi_flash_hal_common_command(spi_flash_host_inst_t *host, spi_flash_trans_t *trans)
{
return spi_flash_hal_common_command(host, trans);
}
esp_err_t _ss_spi_flash_hal_device_config(spi_flash_host_inst_t *host)
{
return spi_flash_hal_device_config(host);
}
void _ss_spi_flash_hal_erase_block(spi_flash_host_inst_t *host, uint32_t start_address)
{
bool paddr_chk = esp_tee_flash_check_paddr_in_tee_region(start_address);
if (paddr_chk) {
ESP_LOGD(TAG, "[%s] Illegal flash access at 0x%08x", __func__, start_address);
return;
}
ESP_FAULT_ASSERT(!paddr_chk);
spi_flash_hal_erase_block(host, start_address);
}
void _ss_spi_flash_hal_erase_chip(spi_flash_host_inst_t *host)
{
spi_flash_hal_erase_chip(host);
}
void _ss_spi_flash_hal_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address)
{
bool paddr_chk = esp_tee_flash_check_paddr_in_tee_region(start_address);
if (paddr_chk) {
ESP_LOGD(TAG, "[%s] Illegal flash access at 0x%08x", __func__, start_address);
return;
}
ESP_FAULT_ASSERT(!paddr_chk);
spi_flash_hal_erase_sector(host, start_address);
}
void _ss_spi_flash_hal_program_page(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length)
{
bool paddr_chk = esp_tee_flash_check_paddr_in_tee_region(address);
if (paddr_chk) {
ESP_LOGD(TAG, "[%s] Illegal flash access at 0x%08x", __func__, address);
return;
}
bool buf_addr_chk = ((esp_tee_ptr_in_ree((void *)buffer) && esp_tee_ptr_in_ree((void *)(buffer + length))));
if (!buf_addr_chk) {
return;
}
ESP_FAULT_ASSERT(!paddr_chk && buf_addr_chk);
spi_flash_hal_program_page(host, buffer, address, length);
}
esp_err_t _ss_spi_flash_hal_read(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len)
{
bool paddr_chk = esp_tee_flash_check_paddr_in_tee_region(address);
if (paddr_chk) {
ESP_LOGD(TAG, "[%s] Illegal flash access at 0x%08x", __func__, address);
return ESP_FAIL;
}
bool buf_addr_chk = ((esp_tee_ptr_in_ree((void *)buffer) && esp_tee_ptr_in_ree((void *)(buffer + read_len))));
if (!buf_addr_chk) {
return ESP_FAIL;
}
ESP_FAULT_ASSERT(!paddr_chk && buf_addr_chk);
return spi_flash_hal_read(host, buffer, address, read_len);
}
void _ss_spi_flash_hal_resume(spi_flash_host_inst_t *host)
{
spi_flash_hal_resume(host);
}
esp_err_t _ss_spi_flash_hal_set_write_protect(spi_flash_host_inst_t *host, bool wp)
{
return spi_flash_hal_set_write_protect(host, wp);
}
esp_err_t _ss_spi_flash_hal_setup_read_suspend(spi_flash_host_inst_t *host, const spi_flash_sus_cmd_conf *sus_conf)
{
return spi_flash_hal_setup_read_suspend(host, sus_conf);
}
bool _ss_spi_flash_hal_supports_direct_read(spi_flash_host_inst_t *host, const void *p)
{
return spi_flash_hal_supports_direct_read(host, p);
}
bool _ss_spi_flash_hal_supports_direct_write(spi_flash_host_inst_t *host, const void *p)
{
return spi_flash_hal_supports_direct_write(host, p);
}
void _ss_spi_flash_hal_suspend(spi_flash_host_inst_t *host)
{
spi_flash_hal_suspend(host);
}
/* ---------------------------------------------- SPI Flash Extras ------------------------------------------------- */
extern uint32_t bootloader_flash_execute_command_common(uint8_t command, uint32_t addr_len, uint32_t address,
uint8_t dummy_len, uint8_t mosi_len, uint32_t mosi_data,
uint8_t miso_len);
uint32_t _ss_bootloader_flash_execute_command_common(
uint8_t command,
uint32_t addr_len, uint32_t address,
uint8_t dummy_len,
uint8_t mosi_len, uint32_t mosi_data,
uint8_t miso_len)
{
bool paddr_chk = esp_tee_flash_check_paddr_in_tee_region(address);
if (paddr_chk) {
ESP_LOGD(TAG, "[%s] Illegal flash access at 0x%08x", __func__, address);
return ESP_FAIL;
}
ESP_FAULT_ASSERT(!paddr_chk);
return bootloader_flash_execute_command_common(command, addr_len, address, dummy_len,
mosi_len, mosi_data, miso_len);
}
esp_err_t _ss_memspi_host_flush_cache(spi_flash_host_inst_t *host, uint32_t addr, uint32_t size)
{
bool paddr_chk = esp_tee_flash_check_paddr_in_tee_region(addr);
if (paddr_chk) {
return ESP_FAIL;
}
ESP_FAULT_ASSERT(!paddr_chk);
return memspi_host_flush_cache(host, addr, size);
}
esp_err_t _ss_spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip, uint32_t flags)
{
return spi_flash_chip_generic_config_host_io_mode(chip, flags);
}
#endif

View File

@ -104,6 +104,8 @@ SECTIONS
_rodata_start = ABSOLUTE(.);
*libtee_flash_mgr.a:*(.rodata .srodata .rodata.* .srodata.*)
*libbootloader_support.a:bootloader_flash.*(.rodata .srodata .rodata.* .srodata.*)
*libmain.a:esp_secure_services.c.*(.rodata .srodata .rodata.* .srodata.*)
*libmain.a:esp_secure_dispatcher.c.*(.rodata .srodata .rodata.* .srodata.*)
*libmain.a:panic_helper_riscv.*(.rodata .srodata .rodata.* .srodata.*)
*libmain.a:esp_tee_apm_intr.c.*(.rodata .srodata .rodata.* .srodata.*)
_rodata_end = ABSOLUTE(.);

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -35,6 +35,14 @@ static const char *TAG = "esp_tee_apm_prot_cfg";
#endif
#endif
/* NOTE: Flash protection over the SPI1 controller */
#define HP_APM_SPI1_REG_START DR_REG_SPI1_BASE
#if CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1
#define HP_APM_SPI1_REG_END DR_REG_I2C_EXT_BASE
#else
#define HP_APM_SPI1_REG_END HP_APM_SPI1_REG_START
#endif
/*----------------------- HP APM range and filter configuration -----------------------*/
/* HP_APM: REE0 mode accessible regions */
@ -56,52 +64,61 @@ apm_ctrl_region_config_data_t hp_apm_pms_data[] = {
.regn_pms = 0x6,
.filter_enable = 1,
},
/* Region 2: Peripherals [MMU - Interrupt Matrix] (RW) */
/* Protected: Interrupt Matrix */
/* Region 2: Peripherals [MMU - SPI1] (RW) */
/* Protected: SPI1 */
{
.regn_num = 2,
.regn_start_addr = SPI_MEM_MMU_POWER_CTRL_REG(0),
.regn_end_addr = (HP_APM_SPI1_REG_START - 0x4),
.regn_pms = 0x6,
.filter_enable = 1,
},
/* Region 3: Peripherals [SPI1 - Interrupt Matrix] (RW) */
/* Protected: Interrupt Matrix */
{
.regn_num = 3,
.regn_start_addr = HP_APM_SPI1_REG_END,
.regn_end_addr = (DR_REG_INTMTX_BASE - 0x4),
.regn_pms = 0x6,
.filter_enable = 1,
},
/* Region 3: Peripherals [H/W Lock - AES] (RW) */
/* Region 4: Peripherals [H/W Lock - AES] (RW) */
/* Protected: AES, SHA */
{
.regn_num = 3,
.regn_num = 4,
.regn_start_addr = DR_REG_ATOMIC_BASE,
.regn_end_addr = (DR_REG_AES_BASE - 0x4),
.regn_pms = 0x6,
.filter_enable = 1,
},
/* Region 4: Peripherals [RSA - TEE Controller & APM] (RW) */
/* Region 5: Peripherals [RSA - TEE Controller & APM] (RW) */
/* Protected: APM, TEE Controller */
{
.regn_num = 4,
.regn_num = 5,
.regn_start_addr = DR_REG_RSA_BASE,
.regn_end_addr = (DR_REG_TEE_BASE - 0x4),
.regn_pms = 0x6,
.filter_enable = 1,
},
/* Region 5: Peripherals [Miscellaneous - PMU] (RW) */
/* Region 6: Peripherals [Miscellaneous - PMU] (RW) */
{
.regn_num = 5,
.regn_num = 6,
.regn_start_addr = DR_REG_MISC_BASE,
.regn_end_addr = (DR_REG_PMU_BASE - 0x04),
.regn_pms = 0x6,
.filter_enable = 1,
},
/* Region 6: Peripherals [DEBUG - PWDET] (RW) */
/* Region 7: Peripherals [DEBUG - PWDET] (RW) */
{
.regn_num = 6,
.regn_num = 7,
.regn_start_addr = DR_REG_OPT_DEBUG_BASE,
.regn_end_addr = 0x600D0000,
.regn_pms = 0x6,
.filter_enable = 1,
},
/* Region 7: REE SRAM region (RW) */
/* Region 8: REE SRAM region (RW) */
{
.regn_num = 7,
.regn_num = 8,
.regn_start_addr = SOC_NS_IRAM_START,
.regn_end_addr = SOC_IRAM_HIGH,
.regn_pms = 0x6,
@ -147,9 +164,9 @@ apm_ctrl_secure_mode_config_t hp_apm_sec_mode_data = {
/* HP_APM: TEE mode accessible regions */
apm_ctrl_region_config_data_t hp_apm_pms_data_tee[] = {
/* Region 8: Entire memory region (RWX)*/
/* Region 9: Entire memory region (RWX)*/
{
.regn_num = 8,
.regn_num = 9,
.regn_start_addr = 0x0,
.regn_end_addr = ~0x0,
.regn_pms = 0x7,

View File

@ -2,19 +2,6 @@
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
# (Not part of the boilerplate)
# This example uses extra components for the following -
# 1. common functions such as Wi-Fi and Ethernet connection.
# 2. managing TEE OTA updates
# 3. dumping TEE attestation info
# 4. TEE Secure storage
list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/components/esp_tee/subproject/components/tee_ota_ops
$ENV{IDF_PATH}/components/esp_tee/subproject/components/tee_attestation
$ENV{IDF_PATH}/components/esp_tee/subproject/components/tee_sec_storage)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
# Including the attestation service calls
include($ENV{IDF_PATH}/components/esp_tee/subproject/components/tee_attestation/esp_tee_att.cmake)
project(tee_cli)

View File

@ -0,0 +1,7 @@
dependencies:
tee_attestation:
path: ${IDF_PATH}/components/esp_tee/subproject/components/tee_attestation
tee_ota_ops:
path: ${IDF_PATH}/components/esp_tee/subproject/components/tee_ota_ops
tee_sec_storage:
path: ${IDF_PATH}/components/esp_tee/subproject/components/tee_sec_storage

View File

@ -2,6 +2,9 @@
CONFIG_SECURE_ENABLE_TEE=y
CONFIG_SECURE_TEE_IRAM_SIZE=0x9000
# Enabling flash protection over SPI1
CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1=y
# Custom partition table
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_PARTITION_TABLE_TWO_OTA_TEE=y

View File

@ -1,19 +1,9 @@
#This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16)
# This example uses extra components for the following -
# 1. Test framework related.
# 2. Managing TEE OTA updates
# 3. TEE Secure Storage
# 4. TEE Entity Attestation
list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/tools/unit-test-app/components
$ENV{IDF_PATH}/components/esp_tee/subproject/components/tee_ota_ops
$ENV{IDF_PATH}/components/esp_tee/subproject/components/tee_sec_storage
$ENV{IDF_PATH}/components/esp_tee/subproject/components/tee_attestation)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
# For registering the test-specific and attestation secure services
include(${CMAKE_CURRENT_LIST_DIR}/components/test_sec_srv/test_tee_project.cmake)
include($ENV{IDF_PATH}/components/esp_tee/subproject/components/tee_attestation/esp_tee_att.cmake)
project(esp_tee_test)

View File

@ -0,0 +1,71 @@
secure_services:
- family: test
entries:
- id: 200
type: custom
function: esp_tee_service_add
args: 2
- id: 201
type: custom
function: esp_tee_service_sub
args: 2
- id: 202
type: custom
function: esp_tee_service_mul
args: 2
- id: 203
type: custom
function: esp_tee_service_div
args: 2
- id: 204
type: custom
function: esp_tee_test_timer_init
args: 1
- id: 205
type: custom
function: esp_tee_secure_int_test
args: 0
- id: 206
type: custom
function: esp_tee_non_secure_int_test
args: 1
- id: 207
type: custom
function: esp_tee_test_int_count
args: 1
- id: 208
type: custom
function: esp_tee_test_resv_reg1_write_violation
args: 0
- id: 209
type: custom
function: esp_tee_test_resv_reg1_exec_violation
args: 0
- id: 210
type: custom
function: esp_tee_test_iram_reg1_write_violation
args: 0
- id: 211
type: custom
function: esp_tee_test_iram_reg2_write_violation
args: 0
- id: 212
type: custom
function: esp_tee_test_dram_reg1_exec_violation
args: 0
- id: 213
type: custom
function: esp_tee_test_dram_reg2_exec_violation
args: 0
- id: 214
type: custom
function: esp_tee_test_illegal_instruction
args: 0
- id: 215
type: custom
function: dummy_secure_service
args: 0
- id: 216
type: custom
function: add_in_loop
args: 3

View File

@ -1,18 +0,0 @@
# SS no. API type Function Args
300 custom esp_tee_service_add 2
301 custom esp_tee_service_sub 2
302 custom esp_tee_service_mul 2
303 custom esp_tee_service_div 2
304 custom esp_tee_test_timer_init 1
305 custom esp_tee_secure_int_test 0
306 custom esp_tee_non_secure_int_test 1
307 custom esp_tee_test_int_count 1
308 custom esp_tee_test_resv_reg1_write_violation 0
309 custom esp_tee_test_resv_reg1_exec_violation 0
310 custom esp_tee_test_iram_reg1_write_violation 0
311 custom esp_tee_test_iram_reg2_write_violation 0
312 custom esp_tee_test_dram_reg1_exec_violation 0
313 custom esp_tee_test_dram_reg2_exec_violation 0
314 custom esp_tee_test_illegal_instruction 0
315 custom dummy_secure_service 0
316 custom add_in_loop 3

View File

@ -1,11 +1,11 @@
# tee_project.cmake file must be manually included in the project's top level CMakeLists.txt before project()
# This file must be manually included in the project's top level CMakeLists.txt before project()
# This ensures that the variables are set before TEE starts building
get_filename_component(directory "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE DIRECTORY)
get_filename_component(name ${CMAKE_CURRENT_LIST_DIR} NAME)
# Append secure service table consisting of secure services
idf_build_set_property(CUSTOM_SECURE_SERVICE_TBL ${CMAKE_CURRENT_LIST_DIR}/test.tbl APPEND)
idf_build_set_property(CUSTOM_SECURE_SERVICE_YAML ${CMAKE_CURRENT_LIST_DIR}/sec_srv_tbl_test.yml APPEND)
# Append the directory of this component which is used by esp_tee component as
# EXTRA_COMPONENT_DIRS

View File

@ -1,2 +1,10 @@
dependencies:
ccomp_timer: "^1.0.0"
tee_attestation:
path: ${IDF_PATH}/components/esp_tee/subproject/components/tee_attestation
tee_ota_ops:
path: ${IDF_PATH}/components/esp_tee/subproject/components/tee_ota_ops
tee_sec_storage:
path: ${IDF_PATH}/components/esp_tee/subproject/components/tee_sec_storage
test_utils:
path: ${IDF_PATH}/tools/unit-test-app/components/test_utils

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -21,8 +21,11 @@
#include "secure_service_num.h"
#include "unity.h"
#include "ccomp_timer.h"
#define BOOT_COUNT_NAMESPACE "boot_count"
#define TEST_PART_LABEL "custom"
#define TEST_BUF_SZ 256
static const char *TAG = "test_esp_tee_flash_prot";
@ -106,6 +109,66 @@ TEST_CASE_MULTIPLE_STAGES("Test REE-TEE isolation: Flash - SPI0 (esp_partition_m
test_initial_boot, test_esp_partition_mmap_api, test_esp_partition_mmap_api,
test_esp_partition_mmap_api, test_esp_partition_mmap_api);
#if CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1
static void test_esp_partition_api_r(const esp_partition_t *part)
{
TEST_ASSERT_NOT_NULL(part);
uint8_t buf_r[128];
memset(buf_r, 0x00, sizeof(buf_r));
TEST_ESP_ERR(ESP_FAIL, esp_partition_read(part, 0x00, buf_r, sizeof(buf_r)));
}
static void test_esp_partition_api_w(const esp_partition_t *part)
{
TEST_ASSERT_NOT_NULL(part);
uint8_t buf_w[128];
memset(buf_w, 0xA5, sizeof(buf_w));
TEST_ESP_OK(esp_partition_write(part, 0x00, buf_w, sizeof(buf_w)));
}
static void test_esp_partition_api_e(const esp_partition_t *part)
{
TEST_ASSERT_NOT_NULL(part);
TEST_ESP_OK(esp_partition_erase_range(part, 0x00, SPI_FLASH_SEC_SIZE));
}
static void test_esp_partition_api(void)
{
uint8_t boot_count = get_boot_count_from_nvs();
boot_count++;
set_boot_count_in_nvs(boot_count);
const esp_partition_t *part = NULL;
switch (boot_count) {
case 2:
part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_TEE_0, NULL);
test_esp_partition_api_r(part);
break;
case 3:
part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_TEE_1, NULL);
test_esp_partition_api_w(part);
break;
case 4:
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_TEE_SEC_STORAGE, NULL);
test_esp_partition_api_w(part);
break;
case 5:
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_TEE_OTA, NULL);
test_esp_partition_api_e(part);
break;
default:
TEST_FAIL_MESSAGE("Unexpected stage");
break;
}
esp_restart();
}
TEST_CASE_MULTIPLE_STAGES("Test REE-TEE isolation: Flash - SPI1 (esp_partition)", "[flash_prot][timeout=60]",
test_initial_boot, test_esp_partition_api, test_esp_partition_api,
test_esp_partition_api, test_esp_partition_api);
#endif
/* ---------------------------------------------- API family 2: spi_flash ------------------------------------------------- */
static void test_spi_flash_mmap_api(void)
@ -149,3 +212,172 @@ static void test_spi_flash_mmap_api(void)
TEST_CASE_MULTIPLE_STAGES("Test REE-TEE isolation: Flash - SPI0 (spi_flash_mmap)", "[flash_prot][timeout=60]",
test_initial_boot, test_spi_flash_mmap_api, test_spi_flash_mmap_api,
test_spi_flash_mmap_api);
/* ---------------------------------------------- API family 3: esp_flash ------------------------------------------------- */
#if CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1
static void test_esp_flash_api_r(uint32_t paddr)
{
uint8_t buf_r[128];
memset(buf_r, 0x00, sizeof(buf_r));
TEST_ESP_ERR(ESP_FAIL, esp_flash_read(NULL, buf_r, paddr, sizeof(buf_r)));
}
static void test_esp_flash_api_w(uint32_t paddr)
{
uint8_t buf_w[128];
memset(buf_w, 0xA5, sizeof(buf_w));
TEST_ESP_OK(esp_flash_write(NULL, buf_w, paddr, sizeof(buf_w)));
}
static void test_esp_flash_api_e(uint32_t paddr)
{
TEST_ESP_OK(esp_flash_erase_region(NULL, paddr, SPI_FLASH_SEC_SIZE));
}
static void test_esp_flash_api(void)
{
uint8_t boot_count = get_boot_count_from_nvs();
boot_count++;
set_boot_count_in_nvs(boot_count);
const esp_partition_t *part = NULL;
switch (boot_count) {
case 2:
part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_TEE_0, NULL);
TEST_ASSERT_NOT_NULL(part);
test_esp_flash_api_w(part->address);
break;
case 3:
part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_TEE_1, NULL);
TEST_ASSERT_NOT_NULL(part);
test_esp_flash_api_r(part->address);
break;
case 4:
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_TEE_SEC_STORAGE, NULL);
TEST_ASSERT_NOT_NULL(part);
test_esp_flash_api_e(part->address);
break;
case 5:
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_TEE_OTA, NULL);
TEST_ASSERT_NOT_NULL(part);
test_esp_flash_api_w(part->address);
break;
default:
TEST_FAIL_MESSAGE("Unexpected stage");
break;
}
esp_restart();
}
TEST_CASE_MULTIPLE_STAGES("Test REE-TEE isolation: Flash - SPI1 (esp_flash)", "[flash_prot][timeout=60]",
test_initial_boot, test_esp_flash_api, test_esp_flash_api, test_esp_flash_api,
test_esp_flash_api);
/* ---------------------------------------------- API family 4: esp_rom ------------------------------------------------- */
static IRAM_ATTR void test_esp_rom_spiflash_api_r(uint32_t paddr)
{
uint32_t buf_r[32];
memset(buf_r, 0x00, sizeof(buf_r));
esp_rom_spiflash_result_t rc = esp_rom_spiflash_read(paddr, buf_r, sizeof(buf_r));
TEST_ASSERT_EQUAL_HEX(ESP_ROM_SPIFLASH_RESULT_OK, rc);
ESP_LOG_BUFFER_HEXDUMP(TAG, buf_r, sizeof(buf_r), ESP_LOG_INFO);
}
static IRAM_ATTR void test_esp_rom_spiflash_api_w(uint32_t paddr)
{
uint32_t buf_w[32];
memset(buf_w, 0xA5, sizeof(buf_w));
spi_flash_disable_interrupts_caches_and_other_cpu();
esp_rom_spiflash_result_t rc = esp_rom_spiflash_write(paddr, buf_w, sizeof(buf_w));
spi_flash_enable_interrupts_caches_and_other_cpu();
TEST_ASSERT_EQUAL_HEX(ESP_ROM_SPIFLASH_RESULT_OK, rc);
}
static IRAM_ATTR void test_esp_rom_spiflash_api_e(uint32_t paddr)
{
spi_flash_disable_interrupts_caches_and_other_cpu();
esp_rom_spiflash_result_t rc = esp_rom_spiflash_erase_area(paddr, SPI_FLASH_SEC_SIZE);
spi_flash_enable_interrupts_caches_and_other_cpu();
TEST_ASSERT_EQUAL_HEX(ESP_ROM_SPIFLASH_RESULT_OK, rc);
}
static void test_esp_rom_spiflash_api(void)
{
uint8_t boot_count = get_boot_count_from_nvs();
boot_count++;
set_boot_count_in_nvs(boot_count);
const esp_partition_t *part = NULL;
switch (boot_count) {
case 2:
part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_TEE_0, NULL);
TEST_ASSERT_NOT_NULL(part);
test_esp_rom_spiflash_api_r(part->address);
TEST_FAIL_MESSAGE("System fault should have been generated");
break;
case 3:
part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_TEE_1, NULL);
TEST_ASSERT_NOT_NULL(part);
test_esp_rom_spiflash_api_w(part->address);
TEST_FAIL_MESSAGE("System fault should have been generated");
break;
case 4:
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_TEE_SEC_STORAGE, NULL);
TEST_ASSERT_NOT_NULL(part);
test_esp_rom_spiflash_api_e(part->address);
TEST_FAIL_MESSAGE("System fault should have been generated");
break;
case 5:
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_TEE_OTA, NULL);
TEST_ASSERT_NOT_NULL(part);
test_esp_rom_spiflash_api_w(part->address);
TEST_FAIL_MESSAGE("System fault should have been generated");
break;
default:
TEST_FAIL_MESSAGE("Unexpected stage");
break;
}
}
TEST_CASE_MULTIPLE_STAGES("Test REE-TEE isolation: Flash - SPI1 (esp_rom_spiflash)", "[flash_prot][timeout=60]",
test_initial_boot, test_esp_rom_spiflash_api, test_esp_rom_spiflash_api,
test_esp_rom_spiflash_api, test_esp_rom_spiflash_api);
#endif
TEST_CASE("Test TEE flash read/write performance", "[flash_prot]")
{
const esp_partition_t *part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, TEST_PART_LABEL);
TEST_ASSERT_NOT_NULL(part);
TEST_ESP_OK(esp_partition_erase_range(part, 0x00, part->size));
TEST_ASSERT_TRUE((part->size % TEST_BUF_SZ) == 0);
ESP_LOGI(TAG, "R/W operations over a %luKB partition in %luB chunks...", part->size / 1024, TEST_BUF_SZ);
uint8_t buf_w[TEST_BUF_SZ];
memset(buf_w, 0xA5, sizeof(buf_w));
float write_usec, read_usec;
ccomp_timer_start();
for (size_t offs = 0; offs < part->size; offs += TEST_BUF_SZ) {
TEST_ESP_OK(esp_partition_write(part, offs, buf_w, TEST_BUF_SZ));
}
write_usec = ccomp_timer_stop();
ESP_LOGI(TAG, "[Time taken] Write: %.2fus", write_usec);
uint8_t buf_r[TEST_BUF_SZ] = {};
ccomp_timer_start();
for (size_t offs = 0; offs < part->size; offs += TEST_BUF_SZ) {
TEST_ESP_OK(esp_partition_read(part, offs, buf_r, TEST_BUF_SZ));
}
read_usec = ccomp_timer_stop();
TEST_ASSERT_EQUAL_HEX8_ARRAY(buf_w, buf_r, TEST_BUF_SZ);
ESP_LOGI(TAG, "[Time taken] Read: %.2fus", read_usec);
}

View File

@ -4,3 +4,4 @@ tee, app, tee_0, , 192K,
secure_storage, data, tee_sec_stg, , 64K,
factory, app, factory, , 512K,
nvs, data, nvs, , 24K,
custom, data, , , 1M

1 # ESP-IDF Partition Table
4 secure_storage, data, tee_sec_stg, , 64K,
5 factory, app, factory, , 512K,
6 nvs, data, nvs, , 24K,
7 custom, data, , , 1M

View File

@ -8,3 +8,4 @@ ota_0, app, ota_0, , 512K,
ota_1, app, ota_1, , 512K,
otadata, data, ota, , 8K,
nvs, data, nvs, , 24K,
custom, data, , , 1M

1 # ESP-IDF Partition Table
8 ota_1, app, ota_1, , 512K,
9 otadata, data, ota, , 8K,
10 nvs, data, nvs, , 24K,
11 custom, data, , , 1M

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
from enum import Enum
from typing import Any
@ -15,6 +15,11 @@ CONFIGS_OTA = [
pytest.param('ota', marks=[pytest.mark.esp32c6])
]
CONFIGS_ALL = [
pytest.param('default', marks=[pytest.mark.esp32c6]),
pytest.param('ota', marks=[pytest.mark.esp32c6])
]
TEE_VIOLATION_TEST_EXC_RSN: Dict[str, Any] = {
'esp32c6': {
('Reserved', 'W1'): 'Store access fault',
@ -42,6 +47,8 @@ REE_ISOLATION_TEST_EXC_RSN: Dict[str, Any] = {
TEE_APM_VIOLATION_EXC_CHK = ['AES', 'eFuse', 'MMU']
TEST_PARTITION_LABEL = 'test'
# ---------------- TEE default tests ----------------
@ -52,14 +59,14 @@ def test_esp_tee(dut: IdfDut) -> None:
@pytest.mark.generic
@pytest.mark.parametrize('config', CONFIGS_DEFAULT, indirect=True)
@pytest.mark.parametrize('config', CONFIGS_ALL, indirect=True)
def test_esp_tee_crypto_aes(dut: IdfDut) -> None:
dut.run_all_single_board_cases(group='aes')
dut.run_all_single_board_cases(group='aes-gcm')
@pytest.mark.generic
@pytest.mark.parametrize('config', CONFIGS_DEFAULT, indirect=True)
@pytest.mark.parametrize('config', CONFIGS_ALL, indirect=True)
def test_esp_tee_crypto_sha(dut: IdfDut) -> None:
dut.run_all_single_board_cases(group='mbedtls')
dut.run_all_single_board_cases(group='hw_crypto')
@ -67,7 +74,7 @@ def test_esp_tee_crypto_sha(dut: IdfDut) -> None:
# NOTE: Stress testing the AES performance case for interrupt-related edge-cases
@pytest.mark.generic
@pytest.mark.parametrize('config', CONFIGS_DEFAULT, indirect=True)
@pytest.mark.parametrize('config', CONFIGS_ALL, indirect=True)
def test_esp_tee_aes_perf(dut: IdfDut) -> None:
# start test
for i in range(24):
@ -134,17 +141,56 @@ def test_esp_tee_isolation_checks(dut: IdfDut) -> None:
raise RuntimeError('Incorrect exception received!')
dut.expect('Exception origin: U-mode')
# ---------------- TEE Flash Protection Tests ----------------
class TeeFlashAccessApi(Enum):
ESP_PARTITION_MMAP = 1
SPI_FLASH_MMAP = 2
ESP_PARTITION = 3
ESP_FLASH = 4
ESP_ROM_SPIFLASH = 5
def check_panic_or_reset(dut: IdfDut) -> None:
try:
exc = dut.expect(r"Core ([01]) panic\'ed \(([^)]+)\)", timeout=5).group(2).decode()
if exc not in {'Cache error', 'Authority exception'}:
raise RuntimeError('Flash operation incorrect exception')
except Exception:
rst_rsn = dut.expect(r'rst:(0x[0-9A-Fa-f]+) \(([^)]+)\)', timeout=5).group(2).decode()
# Fault assert check produces this reset reason
if rst_rsn != 'LP_SW_HPSYS':
raise RuntimeError('Flash operation incorrect reset reason')
def run_multiple_stages(dut: IdfDut, test_case_num: int, stages: int, api: TeeFlashAccessApi) -> None:
exp_seq = {
TeeFlashAccessApi.ESP_PARTITION: ['read', 'program_page', 'program_page', 'erase_sector'],
TeeFlashAccessApi.ESP_FLASH: ['program_page', 'read', 'erase_sector', 'program_page']
}
def run_multiple_stages(dut: IdfDut, test_case_num: int, stages: int) -> None:
for stage in range(1, stages + 1):
dut.write(str(test_case_num))
dut.expect(r'\s+\((\d+)\)\s+"([^"]+)"\r?\n', timeout=30)
dut.write(str(stage))
if 1 < stage <= stages:
rst_rsn = dut.expect(r"Core ([01]) panic\'ed \(([^)]+)\)", timeout=30).group(2).decode()
if rst_rsn != 'Cache error':
raise RuntimeError('Incorrect reset reason observed after TEE image failure!')
if api in exp_seq:
try:
match = dut.expect(r'\[_ss_spi_flash_hal_(\w+)\] Illegal flash access at \s*(0x[0-9a-fA-F]+)', timeout=5)
fault_api = match.group(1).decode()
if fault_api != exp_seq[api][stage - 2]:
raise RuntimeError('Flash operation address check failed')
except Exception:
# NOTE: The esp_partition_read API handles both decrypted
# and plaintext reads. When flash encryption is enabled,
# it uses the MMU HAL instead of the SPI flash HAL.
exc = dut.expect(r"Core ([01]) panic\'ed \(([^)]+)\)", timeout=5).group(2).decode()
if exc != 'Cache error':
raise RuntimeError('Flash operation incorrect exception')
else:
check_panic_or_reset(dut)
if stage != stages:
dut.expect_exact('Press ENTER to see the list of tests.')
@ -160,8 +206,8 @@ def test_esp_tee_flash_prot_esp_partition_mmap(dut: IdfDut) -> None:
# start test
extra_data = dut.parse_test_menu()
for test_case in extra_data:
if test_case.name == 'Test REE-TEE isolation: Flash - SPI1 (esp_partition_mmap)':
run_multiple_stages(dut, test_case.index, len(test_case.subcases))
if test_case.name == 'Test REE-TEE isolation: Flash - SPI0 (esp_partition_mmap)':
run_multiple_stages(dut, test_case.index, len(test_case.subcases), TeeFlashAccessApi.ESP_PARTITION_MMAP)
else:
continue
@ -177,7 +223,55 @@ def test_esp_tee_flash_prot_spi_flash_mmap(dut: IdfDut) -> None:
extra_data = dut.parse_test_menu()
for test_case in extra_data:
if test_case.name == 'Test REE-TEE isolation: Flash - SPI0 (spi_flash_mmap)':
run_multiple_stages(dut, test_case.index, len(test_case.subcases))
run_multiple_stages(dut, test_case.index, len(test_case.subcases), TeeFlashAccessApi.SPI_FLASH_MMAP)
else:
continue
@pytest.mark.generic
@pytest.mark.parametrize('config', CONFIGS_OTA, indirect=True)
@pytest.mark.parametrize('skip_autoflash', ['y'], indirect=True)
def test_esp_tee_flash_prot_esp_rom_spiflash(dut: IdfDut) -> None:
# Flash the bootloader, TEE and REE firmware
dut.serial.custom_flash()
# start test
extra_data = dut.parse_test_menu()
for test_case in extra_data:
if test_case.name == 'Test REE-TEE isolation: Flash - SPI1 (esp_rom_spiflash)':
run_multiple_stages(dut, test_case.index, len(test_case.subcases), TeeFlashAccessApi.ESP_ROM_SPIFLASH)
else:
continue
@pytest.mark.generic
@pytest.mark.parametrize('config', CONFIGS_OTA, indirect=True)
@pytest.mark.parametrize('skip_autoflash', ['y'], indirect=True)
def test_esp_tee_flash_prot_esp_partition(dut: IdfDut) -> None:
# Flash the bootloader, TEE and REE firmware
dut.serial.custom_flash()
# start test
extra_data = dut.parse_test_menu()
for test_case in extra_data:
if test_case.name == 'Test REE-TEE isolation: Flash - SPI1 (esp_partition)':
run_multiple_stages(dut, test_case.index, len(test_case.subcases), TeeFlashAccessApi.ESP_PARTITION)
else:
continue
@pytest.mark.generic
@pytest.mark.parametrize('config', CONFIGS_OTA, indirect=True)
@pytest.mark.parametrize('skip_autoflash', ['y'], indirect=True)
def test_esp_tee_flash_prot_esp_flash(dut: IdfDut) -> None:
# Flash the bootloader, TEE and REE firmware
dut.serial.custom_flash()
# start test
extra_data = dut.parse_test_menu()
for test_case in extra_data:
if test_case.name == 'Test REE-TEE isolation: Flash - SPI1 (esp_flash)':
run_multiple_stages(dut, test_case.index, len(test_case.subcases), TeeFlashAccessApi.ESP_FLASH)
else:
continue

View File

@ -9,3 +9,6 @@ CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG=y
# secure storage key slot for attestation
CONFIG_SECURE_TEE_ATT_KEY_SLOT_ID=14
# Enabling flash protection over SPI1
CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1=y

View File

@ -425,6 +425,7 @@ esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_u
return (timeout_us > 0) ? ESP_OK : ESP_ERR_TIMEOUT;
}
#if !CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1
esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip, uint32_t flags)
{
uint32_t dummy_cyclelen_base;
@ -483,6 +484,7 @@ esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip, uint32_t
return chip->host->driver->configure_host_io_mode(chip->host, read_command, addr_bitlen, dummy_cyclelen_base, read_mode);
}
#endif
esp_err_t spi_flash_chip_generic_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t* out_io_mode)
{

View File

@ -100,10 +100,6 @@ External Memory (Flash)
Designated partitions in the external flash are reserved for the TEE, serving various purposes, including TEE code execution via XIP, secure storage, and OTA data. The PMS safeguards these partitions from unauthorized access, with the APM module protecting the MMU and SPI1 controller registers, and the PMP securing the cache.
.. note::
Flash memory protection is under development and will be introduced in the next revision of ESP-TEE.
.. figure:: ../../../_static/esp_tee/{IDF_TARGET_PATH_NAME}/esp_tee_flash_layout.png
:align: center
:scale: 80%
@ -112,6 +108,53 @@ Designated partitions in the external flash are reserved for the TEE, serving va
ESP-TEE: Flash Memory Map for {IDF_TARGET_NAME}
.. _tee-flash-prot-scope:
**Flash Protection - Virtual and Physical Access**
The key interfaces for flash memory protection are the cache connected to SPI0, which provides virtual access to flash memory, and the SPI1 controller, which provides physical access. By default, the cache and the MMU registers are secured by the PMS, preventing virtual access to the TEE-related flash partitions from the REE.
When :doc:`Flash Encryption <../flash-encryption>` is enabled, the REE can still access TEE flash regions via SPI1, but read operations will return encrypted data. Since neither the REE nor TEE has direct access to the flash encryption key, this prevents attackers from inferring TEE contents through direct reads.
Additionally with :ref:`Secure Boot <secure_boot-guide>` enabled, any unauthorized modifications to the TEE firmware will be detected during boot, causing signature verification to fail. Thus, the combination of Flash Encryption and Secure Boot provides a robust level of protection suitable for most applications.
However, do note that while the TEE firmware integrity is protected, other TEE partitions (e.g., :doc:`Secure Storage <tee-sec-storage>`, :ref:`TEE OTA data <tee-ota-data-partition>`) can be modified through direct writes.
For stronger isolation, you can enable :ref:`CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1`, which completely blocks access to all TEE flash regions via SPI1 for the REE. With this setting, all SPI flash read, write, and erase operations are routed through service calls to the TEE. While this option provides enhanced security, it introduces some performance overhead.
The table below shows the rough time taken to read and write to a 1MB partition in 256B chunks with :doc:`../../api-reference/storage/partition`, highlighting the impact of ESP-TEE and the :ref:`CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1` configuration.
.. list-table:: Flash Protection: Performance Impact
:header-rows: 1
* - Case
- Read (ms)
- Read Δ (ms)
- Read Δ (%)
- Write (ms)
- Write Δ (ms)
- Write Δ (%)
* - ESP-TEE disabled
- 262.01
- -
- -
- 3394.23
- -
- -
* - ESP-TEE enabled
- 279.86
- +17.85
- +6.81%
- 3415.64
- +21.41
- +0.63%
* - ESP-TEE + SPI1 protected
- 359.73
- +97.72
- +37.33%
- 3778.65
- +384.42
- +11.32%
Peripherals
~~~~~~~~~~~
@ -286,31 +329,43 @@ To extend the ESP-TEE framework with custom service calls, follow the steps outl
1. Create a Custom Service Call Table
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Define a component for defining custom service calls and create a ``.tbl`` file within the component.
Define a component for defining custom service calls and create a ``.yml`` file within the component.
.. code-block:: bash
touch <path/to/tbl/file>/custom_srvcall.tbl
touch <path/to/yml/file>/custom_srvcall.yml
Add your custom service call entries to the ``.tbl`` file in the following format:
Add your custom service call entries to the ``.yml`` file in the following format:
.. code-block:: none
.. code-block:: yaml
<service_call_number> custom <function_name> <arguments_count>
secure_services:
- family: <api_family>
entries:
- id: <service_call_number>
type: custom
function: <function_name>
args: <arguments_count>
**Example Entry**
.. code-block:: none
.. code-block:: yaml
# SS no. API type Function Args
201 custom custom_sec_srv_op 1
secure_services:
- family: example
entries:
- id: 300
type: custom
function: example_sec_serv_aes_op
args: 5
- ``201``: Unique service call number
- ``300``: Unique service call number
- ``custom``: Custom service call type
- ``custom_sec_srv_op``: Function name
- ``1``: Number of arguments
- ``example_sec_serv_aes_op``: Function name
- ``5``: Number of arguments
Ensure that the custom service call numbers does not conflict with the :component_file:`default service call table<esp_tee/scripts/{IDF_TARGET_PATH_NAME}/secure_service.tbl>`. The ESP-TEE framework parses the custom service call table along with the default table to generate relevant header files used in applications.
Ensure that the custom service call numbers does not conflict with the :component_file:`default service call table<esp_tee/scripts/{IDF_TARGET_PATH_NAME}/sec_srv_tbl_default.yml>`. The ESP-TEE framework parses the custom service call table along with the default table to generate relevant header files used in applications.
2. Define the Service Call Implementation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -327,7 +382,7 @@ Define the function corresponding to the custom service call in the TEE. This fu
return 0;
}
The function name should have the prefix ``_ss_`` before the name and must match the name specified in the ``.tbl`` file.
The function name should have the prefix ``_ss_`` before the name and must match the name specified in the ``.yml`` file.
For reference, all default service call functions are defined in the :component_file:`file<esp_tee/subproject/main/core/esp_secure_services.c>`.
@ -342,7 +397,7 @@ Define a CMake file (e.g., ``custom_sec_srv.cmake``) in the component that defin
.. code-block:: cmake
idf_build_set_property(CUSTOM_SECURE_SERVICE_TBL ${CMAKE_CURRENT_LIST_DIR}/custom_srvcall.tbl APPEND)
idf_build_set_property(CUSTOM_SECURE_SERVICE_YAML ${CMAKE_CURRENT_LIST_DIR}/custom_srvcall.yml APPEND)
#. Set the custom component directory and name so that the ``esp_tee`` subproject can use it

View File

@ -255,8 +255,6 @@ API Reference
.. note::
- To use the TEE Attestation APIs into your project, ensure the :component:`tee_attestation <esp_tee/subproject/components/tee_attestation>` component is included by setting ``EXTRA_COMPONENT_DIRS`` in your project's ``CMakeLists.txt`` file, as shown in the :example:`tee_attestation <security/tee/tee_attestation>` example. For more information, refer to the :ref:`optional_project_variable` section from the :doc:`Build System </api-guides/build-system>` documentation.
- Additionally, the component-specific :component_file:`CMake <esp_tee/subproject/components/tee_attestation/esp_tee_att.cmake>` file needs to be included in the top-level ``CMakeLists.txt`` of your project before calling the ``project()`` command to integrate the corresponding service calls into the project.
To use the TEE Attestation APIs in your project, ensure that the :component:`tee_attestation <esp_tee/subproject/components/tee_attestation>` component is listed as a local dependency in the component manager manifest file `idf_component.yml <https://docs.espressif.com/projects/idf-component-manager/en/latest/reference/manifest_file.html>`_. Refer to the :example:`tee_attestation <security/tee/tee_attestation>` example for guidance.
.. include-build-file:: inc/esp_tee_attestation.inc

View File

@ -74,6 +74,6 @@ API Reference
.. note::
To use the TEE OTA APIs into your project, ensure the :component:`tee_ota_ops <esp_tee/subproject/components/tee_ota_ops>` component is included by setting ``EXTRA_COMPONENT_DIRS`` in your project's ``CMakeLists.txt`` file, as shown in the :example:`tee_secure_ota <security/tee/tee_secure_ota>` example. For more information, refer to the :ref:`optional_project_variable` section from the :doc:`Build System </api-guides/build-system>` documentation.
To use the TEE OTA APIs in your project, ensure that the :component:`tee_ota_ops <esp_tee/subproject/components/tee_ota_ops>` component is listed as a local dependency in the component manager manifest file `idf_component.yml <https://docs.espressif.com/projects/idf-component-manager/en/latest/reference/manifest_file.html>`_. Refer to the :example:`tee_secure_ota <security/tee/tee_secure_ota>` example for guidance.
.. include-build-file:: inc/esp_tee_ota_ops.inc

View File

@ -67,10 +67,6 @@ The TEE Secure Storage feature supports two modes (:ref:`CONFIG_SECURE_TEE_SEC_S
All the assets pertaining to the TEE secure storage are protected by the APM peripheral and thus, are inaccessible to the REE application. Any attempt to directly access them would result in a system fault.
.. note::
Flash memory protection is currently not implemented - it will be added soon in the next revision of the ESP-TEE framework.
.. note::
- Currently, the TEE secure storage supports the storage of two types of cryptographic keys:
@ -112,6 +108,6 @@ API Reference
.. note::
To use the TEE Secure Storage APIs into your project, ensure the :component:`tee_sec_storage <esp_tee/subproject/components/tee_sec_storage>` component is included by setting ``EXTRA_COMPONENT_DIRS`` in your project's ``CMakeLists.txt`` file, as shown in the :example:`tee_secure_storage <security/tee/tee_secure_storage>` example. For more information, refer to the :ref:`optional_project_variable` section from the :doc:`Build System </api-guides/build-system>` documentation.
To use the TEE Secure Storage APIs in your project, ensure that the :component:`tee_sec_storage <esp_tee/subproject/components/tee_sec_storage>` component is listed as a local dependency in the component manager manifest file `idf_component.yml <https://docs.espressif.com/projects/idf-component-manager/en/latest/reference/manifest_file.html>`_. Refer to the :example:`tee_secure_storage <security/tee/tee_secure_storage>` example for guidance.
.. include-build-file:: inc/esp_tee_sec_storage.inc

View File

@ -71,10 +71,6 @@ Memory Allocation
ESP-TEE divides the memory into separate regions for the TEE and REE, allocating part of the internal SRAM and external flash memory to the TEE. This separation safeguards sensitive data and operations within the TEE, preventing unauthorized access from the REE.
.. note::
Flash memory protection is under development and will be introduced in the next revision of ESP-TEE.
.. _tee-internal-memory:
Internal Memory (SRAM)
@ -105,10 +101,14 @@ Example partition table is given below: ::
nvs, data, nvs, 0x150000, 24K,
phy_init, data, phy, 0x156000, 4K,
.. note::
.. important::
The partition following the last TEE-related partition must be aligned to the configured MMU page size. This alignment is required to prevent secure boot verification failures when validating the user application (REE) image.
.. note::
For more details on the default policy and scope of flash memory protection with ESP-TEE, refer to the :ref:`Flash Protection - Virtual and Physical Access <tee-flash-prot-scope>` section from the advanced guide.
.. _tee-secure-services:
Secure Services
@ -120,7 +120,7 @@ All features that the TEE exposes to the REE are implemented as secure services.
Since multitasking is not currently supported in the TEE, secure service calls are serialized, and subsequent calls remain pending until the current service completes.
For {IDF_TARGET_NAME}, a list of secure services can be found at this :component_file:`table<esp_tee/scripts/{IDF_TARGET_PATH_NAME}/secure_service.tbl>`. Following are the types of secure services.
For {IDF_TARGET_NAME}, a list of secure services can be found at this :component_file:`table<esp_tee/scripts/{IDF_TARGET_PATH_NAME}/sec_srv_tbl_default.yml>`. Following are the types of secure services.
- **Core secure services**: Built-in services within the TEE firmware that provide routine functionalities to the REE, such as interrupt configuration and eFuse access.

View File

@ -2,14 +2,8 @@
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
# (Not part of the boilerplate)
# This example uses extra components for the following -
# 1. Printing TEE attestation info
list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/components/esp_tee/subproject/components/tee_attestation)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
# Including the attestation service calls
include($ENV{IDF_PATH}/components/esp_tee/subproject/components/tee_attestation/esp_tee_att.cmake)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
idf_build_set_property(MINIMAL_BUILD ON)
project(tee_attestation)

View File

@ -8,9 +8,7 @@
#include <errno.h>
#include "esp_system.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_console.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

View File

@ -0,0 +1,3 @@
dependencies:
tee_attestation:
path: ${IDF_PATH}/components/esp_tee/subproject/components/tee_attestation

View File

@ -4,7 +4,9 @@ cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
# Including the example service calls
# For registering custom secure services for the example
include(${CMAKE_CURRENT_LIST_DIR}/components/example_secure_service/tee_project.cmake)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
idf_build_set_property(MINIMAL_BUILD ON)
project(tee_basic)

View File

@ -13,7 +13,7 @@
└── example_secure_service # Component parent directory
├── CMakeLists.txt
├── example_service.c # Custom secure service APIs
├── example.tbl # Custom secure service table, which is appended to the default one provided by TEE
├── sec_srv_tbl_example.yml # Custom secure service table, which is parsed alongwith the default one provided by TEE
├── include
│   └── example_service.h
└── tee_project.cmake # To be manually included in the project's top level CMakeLists.txt before project(...)

View File

@ -1,2 +0,0 @@
# SS no. API type Function Args
300 custom example_sec_serv_aes_op 5

View File

@ -0,0 +1,7 @@
secure_services:
- family: example
entries:
- id: 200
type: custom
function: example_sec_serv_aes_op
args: 5

View File

@ -1,11 +1,11 @@
# tee_project.cmake file must be manually included in the project's top level CMakeLists.txt before project()
# This file must be manually included in the project's top level CMakeLists.txt before project()
# This ensures that the variables are set before TEE starts building
get_filename_component(directory "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE DIRECTORY)
get_filename_component(name ${CMAKE_CURRENT_LIST_DIR} NAME)
# Append secure service table consisting of secure services
idf_build_set_property(CUSTOM_SECURE_SERVICE_TBL ${CMAKE_CURRENT_LIST_DIR}/example.tbl APPEND)
idf_build_set_property(CUSTOM_SECURE_SERVICE_YAML ${CMAKE_CURRENT_LIST_DIR}/sec_srv_tbl_example.yml APPEND)
# Append the directory of this component which is used by esp_tee component as
# EXTRA_COMPONENT_DIRS

View File

@ -1,2 +1,3 @@
idf_component_register(SRCS "tee_main.c"
INCLUDE_DIRS "")
INCLUDE_DIRS ""
PRIV_REQUIRES esp_tee mbedtls)

View File

@ -2,12 +2,8 @@
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
# (Not part of the boilerplate)
# This example uses extra components for the following -
# 1. common functions such as Wi-Fi and Ethernet connection.
# 2. managing TEE OTA updates
list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common
$ENV{IDF_PATH}/components/esp_tee/subproject/components/tee_ota_ops)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
idf_build_set_property(MINIMAL_BUILD ON)
project(tee_secure_ota)

View File

@ -1,2 +1,4 @@
idf_component_register(SRCS "cmd_ota.c" "app_main.c"
INCLUDE_DIRS ".")
INCLUDE_DIRS "."
PRIV_REQUIRES app_update console esp_driver_uart esp_event esp_http_client
esp_https_ota esp_netif esp_wifi mbedtls nvs_flash)

View File

@ -0,0 +1,5 @@
dependencies:
tee_ota_ops:
path: ${IDF_PATH}/components/esp_tee/subproject/components/tee_ota_ops
protocol_examples_common:
path: ${IDF_PATH}/examples/common_components/protocol_examples_common

View File

@ -2,8 +2,8 @@
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/components/esp_tee/subproject/components/tee_sec_storage)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
idf_build_set_property(MINIMAL_BUILD ON)
project(tee_secure_storage)

View File

@ -1,2 +1,3 @@
idf_component_register(SRCS "tee_main.c"
INCLUDE_DIRS "")
INCLUDE_DIRS ""
PRIV_REQUIRES mbedtls)

View File

@ -0,0 +1,3 @@
dependencies:
tee_sec_storage:
path: ${IDF_PATH}/components/esp_tee/subproject/components/tee_sec_storage

View File

@ -19,7 +19,6 @@
#include "mbedtls/ecdsa.h"
#include "mbedtls/sha256.h"
#include "esp_tee.h"
#include "esp_tee_sec_storage.h"
#include "secure_service_num.h"