ESP-IDF 中的 ESP-TEE 高级主题:架构剖析、安全服务调用与自定义扩展实战
ESP-IDF 中的 ESP-TEE 高级主题架构剖析、安全服务调用与自定义扩展实战【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idfESP-TEETrusted Execution Environment是 ESP-IDF 在 RISC-V 芯片上提供的可信执行环境框架它通过 RISC-V 特权级M/U 模式、PMP/PMA 以及 Espressif 自研的 APM 外设把系统划分为高特权 TEE 与低特权 REE 两个隔离的执行域。本文基于 docs/en/security/tee/tee-advanced.rst 展开深入讲解 ESP-TEE 的详细架构、内存与 Flash 隔离机制、中断处理模型、安全服务Secure Service调用约定并给出新增自定义安全服务的完整实操步骤与单元测试方法帮助开发者在当前仓库中构建、扩展并验证自己的 TEE 安全方案。详细架构M 模式与 U 模式的双世界隔离ESP-TEE 框架在目标芯片上同时利用了 RISC-V 架构的固有特性与 Espressif 专有硬件外设共同保证系统隔离并提供安全执行环境RISC-V CPU 固有特性MachineM与 UserU两种特权级PMPPhysical Memory Protection物理内存保护PMAPhysical Memory Attributes物理内存属性Espressif 专有硬件APMAccess Permission Management访问权限管理外设通过这些组件的组合芯片可以将硬件资源内部内存、外部内存与外设和软件资源划分为两种模式高特权的M 模式TEE与低特权的U 模式REE。CPU 可以在两种模式之间切换TEE 运行在更高特权的 M 模式REE 运行在较低特权的 U 模式。启动流程启用 ESP-TEE 后标准应用启动流程会发生轻微变化复位后第二阶段引导加载程序second stage bootloader从启动设备同时加载TEE 镜像与应用镜像随后将控制权移交给 TEE。TEE 负责配置内存、中断与外设访问权限然后切换到 U 模式下的 REE 执行应用镜像。隔离之硬件基础RISC-V 特权级在 RISC-V 架构中每个硬件线程hart工作于特定的特权级该特权级定义在一个或多个控制状态寄存器CSR的模式字段中。特权级是软件栈内部不同组件之间的保护屏障——任何试图执行当前特权模式不允许的操作或访问受保护资源的行为都会触发异常。M 模式拥有最高特权运行在 M 模式的代码通常被视作固有可信代码因为它拥有对机器实现的底层访问能力。PMP 与 PMA 检查器ESP-TEE 利用 RISC-V 的 PMP 与 PMA 检查器管理 TEE/REE 上下文中对系统内存内部 SRAM 与外部 Flash的访问PMP允许 M 模式软件为指定内存区域配置访问权限读、写、执行。该机制按系统预定义策略强制实施 TEE 与 REE 之间的资源隔离保证安全访问控制。PMAPMAC通过提供额外的权限检查增强安全性包括可配置的内存类型以及为指定内存区域定制属性。APM 访问权限管理APM 模块是芯片级硬件外设用于在系统内存与外设两个层面强制 TEE 与 REE 之间的隔离。它由两个主要组件构成各自拥有独立寄存器TEE 控制器TEE 相关寄存器用于配置每个主设备如 HP CPU或作为主设备访问内存的 DMA的安全模式APM 控制器APM 相关寄存器用于指定每种安全模式的访问权限与访问地址范围。APM 在 PMP/PMA 机制力所不及之处增强了系统隔离PMP/PMA 的表项数量有限且无法约束低功耗核或其他主设备如 GDMA的访问。需要注意的是对于目标芯片APM 与 PMP 共同扮演权限控制PMSPermission Control的角色。隔离之实体划分内部内存SRAMHP SRAM 顶部的一段区域被预留给 TEE用于 TEE 代码执行与运行时数据存储包括栈和堆。SRAM 内所有内存区域的权限均由 TEE 通过 PMP 配置管理。REE 内存通过 PMP 划分为 IRAM代码段读/执行与 DRAM数据段读/写而 TEE 内存同样划分为 IRAM 与 DRAM但其划分由PMA强制执行。在 Kconfig 中TEE 的内存区域尺寸可通过以下配置项调整见 components/esp_tee/Kconfig.projbuild配置项说明默认值取值范围SECURE_TEE_IRAM_SIZETEE 模块 IRAM 区域大小0x80000x5000~0xF000需 256 字节对齐SECURE_TEE_DRAM_SIZETEE 模块 DRAM 区域大小0x50000x3000~0x7000需 256 字节对齐SECURE_TEE_STACK_SIZETEE 栈大小从 TEE DRAM 区域分配0x1000启用 Secure Boot 时/0xc000x800~0x1000需 16 字节对齐SECURE_TEE_INTR_STACK_SIZETEE 中断栈大小从 TEE DRAM 区域分配0x4000x400~0x800需 16 字节对齐SECURE_TEE_IROM_SIZETEE 外部 Flash 指令段大小0x20000需为 MMU 页大小的整数倍SECURE_TEE_DROM_SIZETEE 外部 Flash 数据段大小0x10000需为 MMU 页大小的整数倍外部内存Flash外部 Flash 中保留指定分区给 TEE用途包括通过 XIP 执行 TEE 代码、安全存储Secure Storage以及 OTA 数据。PMS 保护这些分区免受未授权访问APM 模块保护 MMU 与 SPI1 控制器寄存器PMP 保护 cache。Flash 保护虚拟访问与物理访问Flash 保护的关键接口有两个连接 SPI0 的cache提供对 Flash 的虚拟访问与SPI1 控制器提供物理访问。默认情况下cache 与 MMU 寄存器受 PMS 保护阻止 REE 对 TEE 相关 Flash 分区进行虚拟访问。启用Flash 加密后REE 仍可通过 SPI1 访问 TEE Flash 区域但读操作返回的是加密数据。由于 REE 与 TEE 都无法直接访问 Flash 加密密钥攻击者无法通过直接读取推断 TEE 内容。启用Secure Boot后对 TEE 固件的任何未授权修改都会在启动时被检测到导致签名校验失败。因此Flash 加密 Secure Boot的组合能为大多数应用提供足够强的保护。需要注意TEE 固件完整性虽然受保护但其他 TEE 分区如 Secure Storage、TEE OTA 数据仍可能通过直接写入被篡改。如需更强隔离可启用CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1该选项完全阻断 REE 通过 SPI1 访问所有 TEE Flash 区域此时所有 SPI Flash 读、写、擦除操作都通过服务调用service call路由到 TEE 执行。该选项带来更高安全性但会引入一定性能开销。该配置在 Kconfig 中的默认值为n其帮助文本明确说明启用后所有经 SPI1 的 SPI Flash 操作都会产生额外的性能开销并提示仅在需要完全隔离全部 TEE Flash 区域即使付出性能代价时才启用同时 SPI0即 MMU路径对 TEE 分区的访问是无条件阻断的。下表给出了使用 Partition API 以 256B 分块读写 1MB 分区的大致耗时展示了 ESP-TEE 与CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1配置对性能的影响场景读 (ms)读 Δ (ms)读 Δ (%)写 (ms)写 Δ (ms)写 Δ (%)关闭 ESP-TEE262.01--3394.23--启用 ESP-TEE279.8617.856.81%3415.6421.410.63%ESP-TEE SPI1 保护359.7397.7237.33%3778.65384.4211.32%外设以下外设通过 APM 模块保护仅 TEE 可访问REE 对这些外设的任何直接访问都会触发异常。选择保护这些外设是因为来自 REE 的访问可能危及系统安全或干扰安全存储、认证attestation等安全服务APM 外设中断控制器Interrupt ControllereFuse 控制器欠压检测器Brownout Detector超级看门狗定时器SWDTAES 加速器芯片支持时SHA 加速器芯片支持时ECC 加速器芯片支持时HMAC 模块芯片支持时数字签名模块芯片支持时注意以下外设将在未来版本中纳入保护MPI 加速器RSA、ECDSA 加速器芯片支持时。固件与系统初始化TEE 固件主要从内部安全 SRAM 加载执行由于 SRAM 容量有限部分 TEE 固件存储在专用的外部 Flash 分区中执行该分区受保护REE 无法访问。该固件负责安全配置系统确保内部/外部内存与外设的隔离与保护。TEE 负责 SoC 资源的安全初始化包括设置 TEE 向量表、指定的安全中断以及委托给 REE 的中断配置 TEE 与 REE 的隔离边界为内部内存I/DRAM与外部内存Flash配置 RISC-V PMP/PMA为外设AES、SHA、eFuse、MMU 等配置 APM注册 TEE 堆。在 esp_tee_init.c 中可以看到 TEE 初始化时的关键校验逻辑TEE 会检查esp_tee_app_config结构中的magic_word是否为ESP_TEE_APP_CFG_MAGIC0x3348AAED并校验 API 主版本号与二进制是否匹配不匹配即进入ESP_INFINITE_LOOP()由看门狗复位系统。该配置结构esp_tee_config_t定义于 esp_tee.h内嵌在 REE 应用镜像的 IRAM 段中包含安全中断处理函数指针、REE 入口地址、REE 中断处理函数指针以及 REE 的 IRAM/IROM/DRAM 边界等字段TEE 在切换到 REE 前读取并更新该结构随后将其写保护。中断处理模型TEE 与 REE 各自拥有独立的向量表并有一个专用于安全中断的中断引脚。TEE 中断的优先级始终高于 REE 中断。TEE 固件提供了注册安全中断外设特定中断处理函数的 API。根据中断发生时的状态中断可能在当前执行环境的向量表中被处理也可能触发特权切换、移交到另一环境的向量表处理。共有四种可能场景场景说明在 TEE 中操作时发生 TEE 中断在 TEE 的 M 模式异常处理程序中捕获在 REE 中操作时发生 REE 中断在 REE 的 U 模式异常处理程序中捕获在 REE 中操作时发生 TEE 中断在 TEE 的 M 模式异常处理程序中捕获处理完毕后返回 REE在 TEE 中操作时发生 REE 中断在 TEE 的 M 模式异常处理程序中捕获跳转到 REE 的 U 模式异常处理程序处理完毕后返回 TEE当中断在另一执行环境中处理完毕后执行流程会返回最初触发中断的环境。以REE 中发生 TEE 中断为例其序列为REE 软件执行 → 触发 TEE 中断跳转到 M 模式异常处理程序→ 保存 U 模式上下文、切换到 M 模式中断栈 → 执行服务例程 → 恢复 U 模式上下文mret指令→ 返回 REE 继续执行。安全服务Secure Services执行流程安全服务调用接口允许 REE 应用请求受信任TEE的操作并触发安全服务分发器secure service dispatcher。分发器是 TEE 的入口点负责解析输入参数、识别要调用的服务并将请求转发给对应的服务处理函数。安全服务完成后分发器处理返回过程并启动特权切换将控制权恢复给 REE 中原始调用的位置——特权级的切换是安全服务分发器前后处理例程的一部分。在 esp_secure_dispatcher.c 中可以看到分发器esp_tee_service_dispatcher的实现它首先校验参数个数上限ESP_TEE_MAX_INPUT_ARG即 10 个通过find_service_by_id在内部内存服务表tee_sec_srv_tbl_int_mem与外部内存服务表tee_sec_srv_tbl_ext_mem中查找服务 ID校验实参个数与表中记录的nargs一致后通过内联汇编将前 8 个参数装载到a0-a7寄存器多于 8 个的参数压栈再jalr调用目标函数。服务表本身在 esp_secure_service_table.c 中通过包含生成的secure_service_int.h/secure_service_ext.h头文件完成初始化。完整的安全服务调用序列为REE 软件执行 → 发起安全服务调用ecall指令跳转到 M 模式异常处理程序→ 保存 U 模式上下文、切换到 M 模式栈、禁用 U 模式中断委托→ 执行安全服务 → 恢复 U 模式上下文、重新启用 U 模式中断委托mret指令→ 返回 REE 继续执行。调用约定安全服务调用接口 APIesp_tee_service_call的调用约定如下参数类型说明arg0uint8_t输入传给安全服务的输入参数个数arg1tee_secure_service_t输入安全服务 IDarg2-arg9uint32_t输入传给安全服务的参数valuint32_t输出安全服务的返回值IRAM 安全变体esp_tee_service_call_with_noniram_intr_disabled会在切换执行环境之前挂起调度器并禁用所有非 IRAM 驻留中断。这在通过 SPI1 总线访问 Flash此时 Flash cache 可能被禁用等操作中至关重要可防止多个实体并发访问 Flash。该 API 在 esp_tee.h 中声明uint32_t esp_tee_service_call(int argc, ...)仅对非 TEE 构建!ESP_TEE_BUILD暴露。默认服务表默认安全服务表按家族family分组定义在各芯片目录下的 YAML 文件中例如 components/esp_tee/scripts/esp32c6/sec_srv_tbl_default.yml。以 ESP32-C6 为例主要包括miscID 0invalid_secure_serviceflash_protection_spi0ID 1-4MMU 映射/解映射、虚实地址转换mmu_hal_map_region等flash_protection_spi1ID 5-21SPI Flash HAL 层的状态查询、通用命令、擦除、编程、读写、挂起/恢复、写保护等interrupt_handlingID 30-37中断矩阵路由、使能/禁用、优先级/类型/阈值设置等halID 54-55看门狗 HAL 初始化/反初始化cryptoID 86-111AES 各模式加解密、SHA、HMAC、数字签名DS、ECC 点乘与点验证、时钟使能等attestationID 170-171PSA 初始认证 token 获取secure_storageID 175-181密钥生成/清除、ECDSA 签名与公钥获取、AEAD 加解密等otaID 195-197TEE OTA 的 begin/write/endID 200用户自定义区域所有默认服务调用函数定义在 esp_secure_services.c 中。REE 侧则通过 esp_secure_service_wrapper.c 中的__wrap_*包装函数完成对服务 ID 的封装调用——例如__wrap_esp_aes_crypt_ecb内部调用esp_tee_service_call(5, SS_ESP_AES_CRYPT_ECB, ...)部分加密操作还会在调用前后获取/释放对应的加密锁如esp_crypto_sha_aes_lock_acquire/release。注意SPI1 Flash 保护相关包装函数仅在CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1使能时编译而认证相关包装函数在CONFIG_SECURE_TEE_ATTESTATION使能时编译。添加自定义安全服务扩展 ESP-TEE 框架以支持自定义服务调用需要完成以下三个步骤。第一步创建自定义服务调用表定义一个用于声明自定义服务调用的组件并在组件内创建.yml文件touch path/to/yml/file/custom_srvcall.yml按以下格式向.yml文件添加自定义服务调用条目secure_services: - family: api_family entries: - id: service_call_number type: custom function: function_name args: arguments_count示例条目secure_services: - family: example entries: - id: 300 type: custom function: example_sec_serv_aes_op args: 5字段含义300唯一的服务调用编号custom自定义服务调用类型example_sec_serv_aes_op函数名5参数个数。必须确保自定义服务调用编号与默认服务调用表不冲突默认表已为ID 200预留用户自定义区域。ESP-TEE 框架会同时解析自定义服务调用表与默认表生成应用所需的头文件。第二步定义服务调用实现在 TEE 中定义与自定义服务调用对应的函数该函数在 REE 以对应编号发起服务调用时执行。示例实现int _ss_custom_sec_srv_op(void *arg) { // Perform the intended task return 0; }函数名必须以_ss_前缀开头并且必须与.yml文件中指定的名称一致。第三步构建系统改动自定义组件级在定义自定义服务调用的组件中创建 CMake 文件例如custom_sec_srv.cmake并添加以下配置。将服务调用表追加到默认表idf_build_set_property(CUSTOM_SECURE_SERVICE_YAML ${CMAKE_CURRENT_LIST_DIR}/custom_srvcall.yml APPEND)设置自定义组件目录与名称使esp_tee子项目可以使用它get_filename_component(directory ${CMAKE_CURRENT_LIST_DIR}/.. ABSOLUTE DIRECTORY) idf_build_set_property(CUSTOM_SECURE_SERVICE_COMPONENT_DIR ${directory} APPEND) get_filename_component(name ${CMAKE_CURRENT_LIST_DIR} NAME) idf_build_set_property(CUSTOM_SECURE_SERVICE_COMPONENT ${name} APPEND)定义自定义组件的CMakeLists.txtidf_build_get_property(esp_tee_build ESP_TEE_BUILD) if(esp_tee_build) ## Headers, sources and dependent components for the TEE-build else() ## Headers, sources and dependent components for the REE-build endif() idf_component_register(...)项目级修改项目顶层CMakeLists.txt在调用project()命令之前包含custom_sec_srv.cmake文件include(path/to/component/custom_sec_srv.cmake) project(your_project_name)更多细节可参考tee_basic示例examples/security/tee/tee_basic。该示例组件 example_secure_service 中即包含了完整的参考实现其 sec_srv_tbl_example.yml 定义了两个自定义服务ID 200/201 的 AES-GCM 加解密tee_project.cmake 展示了上述三条构建属性的实际写法并注释说明该文件必须在项目顶层CMakeLists.txt中、project()之前手动 include以确保变量在 TEE 开始构建前设置完毕。单元测试ESP-TEE 框架使用 ESP-IDF 的 pytest 框架在目标芯片上执行专用单元测试。测试应用覆盖以下模块位于components目录下的esp_tee/test_apps具体为 components/esp_tee/test_apps安全服务调用接口中断与异常处理特权违例加密操作TEE OTA 更新安全存储认证Attestation要运行 TEE 测试套件假设已配置好 ESP-IDF 环境例如为某目标芯片执行 TEE 测试套件并使用所有可用的sdkconfig文件可执行以下步骤$ cd components/esp_tee/test_apps/tee_test_fw $ idf.py build $ pytest --target target测试应用目录下提供了多种 CI 配置如sdkconfig.ci.tee_default、sdkconfig.ci.tee_ota、sdkconfig.ci.tee_fuzzing以及pytest_esp_tee_ut.py等 pytest 入口脚本便于针对不同安全特性组合执行验证。小结ESP-TEE 通过 RISC-V M/U 特权级、PMP/PMA 与 APM 外设的协同在单芯片上构建了可验证的隔离边界内部 SRAM 顶部预留 TEE 区域、外部 Flash 保留 TEE 分区并由 PMS 保护、关键外设仅对 TEE 开放。安全服务分发器以ecall为入口完成 REE→TEE→REE 的特权切换配合默认服务表与__wrap_*包装机制使 REE 可以安全调用 Flash、中断、密码学等受保护能力。开发者只需遵循YAML 声明 →_ss_前缀实现 → CMake 注册三步流程即可扩展自定义安全服务并可通过tee_test_fw测试框架对新增服务进行完整验证。对于追求更强 Flash 隔离的场景CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1提供了以性能换取完全隔离的取舍方案读操作 37.33%、写操作 11.32% 的实测开销可供工程评估参考。【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →