From 8f117c7f4c7c4cab339fb13d73ecfac8a0297020 Mon Sep 17 00:00:00 2001 From: Laukik Hase Date: Wed, 8 Jan 2025 15:04:30 +0530 Subject: [PATCH 1/4] refactor(esp_tee): Add local components in TEE examples via `idf_component.yml` --- .../esp_tee/test_apps/tee_cli_app/CMakeLists.txt | 12 +----------- .../test_apps/tee_cli_app/main/idf_component.yml | 7 +++++++ .../esp_tee/test_apps/tee_test_fw/CMakeLists.txt | 11 +---------- .../components/test_sec_srv/test_tee_project.cmake | 2 +- .../test_apps/tee_test_fw/main/idf_component.yml | 8 ++++++++ docs/en/security/tee/tee-attestation.rst | 2 +- docs/en/security/tee/tee-ota.rst | 2 +- docs/en/security/tee/tee-sec-storage.rst | 2 +- examples/security/tee/tee_attestation/CMakeLists.txt | 9 +++------ .../security/tee/tee_attestation/main/app_main.c | 2 -- .../tee/tee_attestation/main/idf_component.yml | 3 +++ examples/security/tee/tee_basic/CMakeLists.txt | 4 +++- examples/security/tee/tee_basic/main/CMakeLists.txt | 3 ++- examples/security/tee/tee_secure_ota/CMakeLists.txt | 10 +++------- .../security/tee/tee_secure_ota/main/CMakeLists.txt | 4 +++- .../tee/tee_secure_ota/main/idf_component.yml | 5 +++++ .../security/tee/tee_secure_storage/CMakeLists.txt | 4 ++-- .../tee/tee_secure_storage/main/CMakeLists.txt | 3 ++- .../tee/tee_secure_storage/main/idf_component.yml | 3 +++ .../security/tee/tee_secure_storage/main/tee_main.c | 1 - 20 files changed, 50 insertions(+), 47 deletions(-) create mode 100644 components/esp_tee/test_apps/tee_cli_app/main/idf_component.yml create mode 100644 examples/security/tee/tee_attestation/main/idf_component.yml create mode 100644 examples/security/tee/tee_secure_ota/main/idf_component.yml create mode 100644 examples/security/tee/tee_secure_storage/main/idf_component.yml diff --git a/components/esp_tee/test_apps/tee_cli_app/CMakeLists.txt b/components/esp_tee/test_apps/tee_cli_app/CMakeLists.txt index a87732fdbb..25d05f1b65 100644 --- a/components/esp_tee/test_apps/tee_cli_app/CMakeLists.txt +++ b/components/esp_tee/test_apps/tee_cli_app/CMakeLists.txt @@ -2,19 +2,9 @@ # 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 +# For registering the attestation secure service include($ENV{IDF_PATH}/components/esp_tee/subproject/components/tee_attestation/esp_tee_att.cmake) project(tee_cli) diff --git a/components/esp_tee/test_apps/tee_cli_app/main/idf_component.yml b/components/esp_tee/test_apps/tee_cli_app/main/idf_component.yml new file mode 100644 index 0000000000..2aea218675 --- /dev/null +++ b/components/esp_tee/test_apps/tee_cli_app/main/idf_component.yml @@ -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 diff --git a/components/esp_tee/test_apps/tee_test_fw/CMakeLists.txt b/components/esp_tee/test_apps/tee_test_fw/CMakeLists.txt index 87cacafa2e..2a92d2d729 100644 --- a/components/esp_tee/test_apps/tee_test_fw/CMakeLists.txt +++ b/components/esp_tee/test_apps/tee_test_fw/CMakeLists.txt @@ -1,18 +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) diff --git a/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/test_tee_project.cmake b/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/test_tee_project.cmake index 8be3ba76b3..d4a389ad76 100644 --- a/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/test_tee_project.cmake +++ b/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/test_tee_project.cmake @@ -1,4 +1,4 @@ -# 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) diff --git a/components/esp_tee/test_apps/tee_test_fw/main/idf_component.yml b/components/esp_tee/test_apps/tee_test_fw/main/idf_component.yml index 2ae836a935..7b62e998be 100644 --- a/components/esp_tee/test_apps/tee_test_fw/main/idf_component.yml +++ b/components/esp_tee/test_apps/tee_test_fw/main/idf_component.yml @@ -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 diff --git a/docs/en/security/tee/tee-attestation.rst b/docs/en/security/tee/tee-attestation.rst index 4d57274d92..c57eec865d 100644 --- a/docs/en/security/tee/tee-attestation.rst +++ b/docs/en/security/tee/tee-attestation.rst @@ -255,7 +255,7 @@ API Reference .. note:: - - To use the TEE Attestation APIs into your project, ensure the :component:`tee_attestation ` component is included by setting ``EXTRA_COMPONENT_DIRS`` in your project's ``CMakeLists.txt`` file, as shown in the :example:`tee_attestation ` example. For more information, refer to the :ref:`optional_project_variable` section from the :doc:`Build System ` documentation. + - To use the TEE Attestation APIs in your project, ensure that the :component:`tee_attestation ` component is listed as a local dependency in the component manager manifest file `idf_component.yml `_. Refer to the :example:`tee_attestation ` example for guidance. - Additionally, the component-specific :component_file:`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. diff --git a/docs/en/security/tee/tee-ota.rst b/docs/en/security/tee/tee-ota.rst index c1bbb00479..264b9c4be2 100644 --- a/docs/en/security/tee/tee-ota.rst +++ b/docs/en/security/tee/tee-ota.rst @@ -74,6 +74,6 @@ API Reference .. note:: - To use the TEE OTA APIs into your project, ensure the :component:`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 ` example. For more information, refer to the :ref:`optional_project_variable` section from the :doc:`Build System ` documentation. + To use the TEE OTA APIs in your project, ensure that the :component:`tee_ota_ops ` component is listed as a local dependency in the component manager manifest file `idf_component.yml `_. Refer to the :example:`tee_secure_ota ` example for guidance. .. include-build-file:: inc/esp_tee_ota_ops.inc diff --git a/docs/en/security/tee/tee-sec-storage.rst b/docs/en/security/tee/tee-sec-storage.rst index 7a4354dcf1..a5d36118af 100644 --- a/docs/en/security/tee/tee-sec-storage.rst +++ b/docs/en/security/tee/tee-sec-storage.rst @@ -112,6 +112,6 @@ API Reference .. note:: - To use the TEE Secure Storage APIs into your project, ensure the :component:`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 ` example. For more information, refer to the :ref:`optional_project_variable` section from the :doc:`Build System ` documentation. + To use the TEE Secure Storage APIs in your project, ensure that the :component:`tee_sec_storage ` component is listed as a local dependency in the component manager manifest file `idf_component.yml `_. Refer to the :example:`tee_secure_storage ` example for guidance. .. include-build-file:: inc/esp_tee_sec_storage.inc diff --git a/examples/security/tee/tee_attestation/CMakeLists.txt b/examples/security/tee/tee_attestation/CMakeLists.txt index 2bd98f78a4..115dffc941 100644 --- a/examples/security/tee/tee_attestation/CMakeLists.txt +++ b/examples/security/tee/tee_attestation/CMakeLists.txt @@ -2,14 +2,11 @@ # 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 +# For registering the attestation secure service 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) diff --git a/examples/security/tee/tee_attestation/main/app_main.c b/examples/security/tee/tee_attestation/main/app_main.c index 90c7c1872b..e3b2800cf4 100644 --- a/examples/security/tee/tee_attestation/main/app_main.c +++ b/examples/security/tee/tee_attestation/main/app_main.c @@ -8,9 +8,7 @@ #include #include "esp_system.h" -#include "esp_event.h" #include "esp_log.h" -#include "esp_console.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" diff --git a/examples/security/tee/tee_attestation/main/idf_component.yml b/examples/security/tee/tee_attestation/main/idf_component.yml new file mode 100644 index 0000000000..ffc1a7d072 --- /dev/null +++ b/examples/security/tee/tee_attestation/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + tee_attestation: + path: ${IDF_PATH}/components/esp_tee/subproject/components/tee_attestation diff --git a/examples/security/tee/tee_basic/CMakeLists.txt b/examples/security/tee/tee_basic/CMakeLists.txt index 12a1e84ce9..432e9c39ac 100644 --- a/examples/security/tee/tee_basic/CMakeLists.txt +++ b/examples/security/tee/tee_basic/CMakeLists.txt @@ -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) diff --git a/examples/security/tee/tee_basic/main/CMakeLists.txt b/examples/security/tee/tee_basic/main/CMakeLists.txt index 6746047f5f..c9e36bfd72 100644 --- a/examples/security/tee/tee_basic/main/CMakeLists.txt +++ b/examples/security/tee/tee_basic/main/CMakeLists.txt @@ -1,2 +1,3 @@ idf_component_register(SRCS "tee_main.c" - INCLUDE_DIRS "") + INCLUDE_DIRS "" + PRIV_REQUIRES esp_tee mbedtls) diff --git a/examples/security/tee/tee_secure_ota/CMakeLists.txt b/examples/security/tee/tee_secure_ota/CMakeLists.txt index 7559f4d7da..b686c24817 100644 --- a/examples/security/tee/tee_secure_ota/CMakeLists.txt +++ b/examples/security/tee/tee_secure_ota/CMakeLists.txt @@ -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) diff --git a/examples/security/tee/tee_secure_ota/main/CMakeLists.txt b/examples/security/tee/tee_secure_ota/main/CMakeLists.txt index 371fba8ba5..e052c95102 100644 --- a/examples/security/tee/tee_secure_ota/main/CMakeLists.txt +++ b/examples/security/tee/tee_secure_ota/main/CMakeLists.txt @@ -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) diff --git a/examples/security/tee/tee_secure_ota/main/idf_component.yml b/examples/security/tee/tee_secure_ota/main/idf_component.yml new file mode 100644 index 0000000000..3d5ae02d6c --- /dev/null +++ b/examples/security/tee/tee_secure_ota/main/idf_component.yml @@ -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 diff --git a/examples/security/tee/tee_secure_storage/CMakeLists.txt b/examples/security/tee/tee_secure_storage/CMakeLists.txt index 9842c6bb84..55c182e782 100644 --- a/examples/security/tee/tee_secure_storage/CMakeLists.txt +++ b/examples/security/tee/tee_secure_storage/CMakeLists.txt @@ -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) diff --git a/examples/security/tee/tee_secure_storage/main/CMakeLists.txt b/examples/security/tee/tee_secure_storage/main/CMakeLists.txt index 6746047f5f..3b865c8632 100644 --- a/examples/security/tee/tee_secure_storage/main/CMakeLists.txt +++ b/examples/security/tee/tee_secure_storage/main/CMakeLists.txt @@ -1,2 +1,3 @@ idf_component_register(SRCS "tee_main.c" - INCLUDE_DIRS "") + INCLUDE_DIRS "" + PRIV_REQUIRES mbedtls) diff --git a/examples/security/tee/tee_secure_storage/main/idf_component.yml b/examples/security/tee/tee_secure_storage/main/idf_component.yml new file mode 100644 index 0000000000..c4cb532a85 --- /dev/null +++ b/examples/security/tee/tee_secure_storage/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + tee_sec_storage: + path: ${IDF_PATH}/components/esp_tee/subproject/components/tee_sec_storage diff --git a/examples/security/tee/tee_secure_storage/main/tee_main.c b/examples/security/tee/tee_secure_storage/main/tee_main.c index 9bb73e22d3..21c96efdb6 100644 --- a/examples/security/tee/tee_secure_storage/main/tee_main.c +++ b/examples/security/tee/tee_secure_storage/main/tee_main.c @@ -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" From 37525c605dbca0264fd7c10dca188bbd9c34322a Mon Sep 17 00:00:00 2001 From: Laukik Hase Date: Tue, 28 Jan 2025 17:57:03 +0530 Subject: [PATCH 2/4] refactor(esp_tee): Migrate secure services list from TBL to YAML --- components/esp_tee/CMakeLists.txt | 38 ++-- .../scripts/esp32c6/sec_srv_tbl_default.yml | 212 ++++++++++++++++++ .../scripts/esp32c6/secure_service.tbl | 57 ----- ...parser.py => secure_service_yml_parser.py} | 70 +++--- .../tee_attestation/esp_tee_att.cmake | 5 - .../tee_attestation/esp_tee_att.tbl | 2 - .../test_apps/tee_cli_app/CMakeLists.txt | 3 - .../test_apps/tee_test_fw/CMakeLists.txt | 1 - .../test_sec_srv/sec_srv_tbl_test.yml | 71 ++++++ .../components/test_sec_srv/test.tbl | 18 -- .../test_sec_srv/test_tee_project.cmake | 2 +- docs/en/security/tee/tee-advanced.rst | 40 ++-- docs/en/security/tee/tee-attestation.rst | 4 +- docs/en/security/tee/tee.rst | 2 +- .../tee/tee_attestation/CMakeLists.txt | 3 - examples/security/tee/tee_basic/README.md | 2 +- .../example_secure_service/example.tbl | 2 - .../sec_srv_tbl_example.yml | 7 + .../example_secure_service/tee_project.cmake | 4 +- 19 files changed, 385 insertions(+), 158 deletions(-) create mode 100644 components/esp_tee/scripts/esp32c6/sec_srv_tbl_default.yml delete mode 100644 components/esp_tee/scripts/esp32c6/secure_service.tbl rename components/esp_tee/scripts/{secure_service_tbl_parser.py => secure_service_yml_parser.py} (55%) delete mode 100644 components/esp_tee/subproject/components/tee_attestation/esp_tee_att.cmake delete mode 100644 components/esp_tee/subproject/components/tee_attestation/esp_tee_att.tbl create mode 100644 components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/sec_srv_tbl_test.yml delete mode 100644 components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/test.tbl delete mode 100644 examples/security/tee/tee_basic/components/example_secure_service/example.tbl create mode 100644 examples/security/tee/tee_basic/components/example_secure_service/sec_srv_tbl_example.yml diff --git a/components/esp_tee/CMakeLists.txt b/components/esp_tee/CMakeLists.txt index 96e92e3567..ef69044eb7 100644 --- a/components/esp_tee/CMakeLists.txt +++ b/components/esp_tee/CMakeLists.txt @@ -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,33 @@ 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_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 diff --git a/components/esp_tee/scripts/esp32c6/sec_srv_tbl_default.yml b/components/esp_tee/scripts/esp32c6/sec_srv_tbl_default.yml new file mode 100644 index 0000000000..d15d125f3a --- /dev/null +++ b/components/esp_tee/scripts/esp32c6/sec_srv_tbl_default.yml @@ -0,0 +1,212 @@ +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: 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 diff --git a/components/esp_tee/scripts/esp32c6/secure_service.tbl b/components/esp_tee/scripts/esp32c6/secure_service.tbl deleted file mode 100644 index 51cd652035..0000000000 --- a/components/esp_tee/scripts/esp32c6/secure_service.tbl +++ /dev/null @@ -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 diff --git a/components/esp_tee/scripts/secure_service_tbl_parser.py b/components/esp_tee/scripts/secure_service_yml_parser.py similarity index 55% rename from components/esp_tee/scripts/secure_service_tbl_parser.py rename to components/esp_tee/scripts/secure_service_yml_parser.py index 94cb3f9c2c..8dc18e8aca 100644 --- a/components/esp_tee/scripts/secure_service_tbl_parser.py +++ b/components/esp_tee/scripts/secure_service_yml_parser.py @@ -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__': diff --git a/components/esp_tee/subproject/components/tee_attestation/esp_tee_att.cmake b/components/esp_tee/subproject/components/tee_attestation/esp_tee_att.cmake deleted file mode 100644 index b99f4aaf7f..0000000000 --- a/components/esp_tee/subproject/components/tee_attestation/esp_tee_att.cmake +++ /dev/null @@ -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) diff --git a/components/esp_tee/subproject/components/tee_attestation/esp_tee_att.tbl b/components/esp_tee/subproject/components/tee_attestation/esp_tee_att.tbl deleted file mode 100644 index 5541be8625..0000000000 --- a/components/esp_tee/subproject/components/tee_attestation/esp_tee_att.tbl +++ /dev/null @@ -1,2 +0,0 @@ -# SS no. API type Function Args -250 custom esp_tee_att_generate_token 6 diff --git a/components/esp_tee/test_apps/tee_cli_app/CMakeLists.txt b/components/esp_tee/test_apps/tee_cli_app/CMakeLists.txt index 25d05f1b65..721b1cfd91 100644 --- a/components/esp_tee/test_apps/tee_cli_app/CMakeLists.txt +++ b/components/esp_tee/test_apps/tee_cli_app/CMakeLists.txt @@ -4,7 +4,4 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -# For registering the attestation secure service -include($ENV{IDF_PATH}/components/esp_tee/subproject/components/tee_attestation/esp_tee_att.cmake) - project(tee_cli) diff --git a/components/esp_tee/test_apps/tee_test_fw/CMakeLists.txt b/components/esp_tee/test_apps/tee_test_fw/CMakeLists.txt index 2a92d2d729..0269fa8801 100644 --- a/components/esp_tee/test_apps/tee_test_fw/CMakeLists.txt +++ b/components/esp_tee/test_apps/tee_test_fw/CMakeLists.txt @@ -5,6 +5,5 @@ 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) diff --git a/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/sec_srv_tbl_test.yml b/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/sec_srv_tbl_test.yml new file mode 100644 index 0000000000..76ba15c605 --- /dev/null +++ b/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/sec_srv_tbl_test.yml @@ -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 diff --git a/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/test.tbl b/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/test.tbl deleted file mode 100644 index b93f500728..0000000000 --- a/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/test.tbl +++ /dev/null @@ -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 diff --git a/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/test_tee_project.cmake b/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/test_tee_project.cmake index d4a389ad76..29e6e3290c 100644 --- a/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/test_tee_project.cmake +++ b/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/test_tee_project.cmake @@ -5,7 +5,7 @@ get_filename_component(directory "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE DIRECTO 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 diff --git a/docs/en/security/tee/tee-advanced.rst b/docs/en/security/tee/tee-advanced.rst index c539e59389..24ca16191f 100644 --- a/docs/en/security/tee/tee-advanced.rst +++ b/docs/en/security/tee/tee-advanced.rst @@ -286,31 +286,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 /custom_srvcall.tbl + touch /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 - custom + secure_services: + - family: + entries: + - id: + type: custom + function: + args: **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`. 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`. 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 +339,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`. @@ -342,7 +354,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 diff --git a/docs/en/security/tee/tee-attestation.rst b/docs/en/security/tee/tee-attestation.rst index c57eec865d..780229f606 100644 --- a/docs/en/security/tee/tee-attestation.rst +++ b/docs/en/security/tee/tee-attestation.rst @@ -255,8 +255,6 @@ API Reference .. note:: - - To use the TEE Attestation APIs in your project, ensure that the :component:`tee_attestation ` component is listed as a local dependency in the component manager manifest file `idf_component.yml `_. Refer to the :example:`tee_attestation ` example for guidance. - - - Additionally, the component-specific :component_file:`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 ` component is listed as a local dependency in the component manager manifest file `idf_component.yml `_. Refer to the :example:`tee_attestation ` example for guidance. .. include-build-file:: inc/esp_tee_attestation.inc diff --git a/docs/en/security/tee/tee.rst b/docs/en/security/tee/tee.rst index d1c578f1b0..b8ea2ab93f 100644 --- a/docs/en/security/tee/tee.rst +++ b/docs/en/security/tee/tee.rst @@ -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`. Following are the types of secure services. +For {IDF_TARGET_NAME}, a list of secure services can be found at this :component_file:`table`. 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. diff --git a/examples/security/tee/tee_attestation/CMakeLists.txt b/examples/security/tee/tee_attestation/CMakeLists.txt index 115dffc941..f2683dfc68 100644 --- a/examples/security/tee/tee_attestation/CMakeLists.txt +++ b/examples/security/tee/tee_attestation/CMakeLists.txt @@ -4,9 +4,6 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -# For registering the attestation secure service -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) diff --git a/examples/security/tee/tee_basic/README.md b/examples/security/tee/tee_basic/README.md index e3bd576494..894ba5e4fc 100644 --- a/examples/security/tee/tee_basic/README.md +++ b/examples/security/tee/tee_basic/README.md @@ -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(...) diff --git a/examples/security/tee/tee_basic/components/example_secure_service/example.tbl b/examples/security/tee/tee_basic/components/example_secure_service/example.tbl deleted file mode 100644 index e801439ed5..0000000000 --- a/examples/security/tee/tee_basic/components/example_secure_service/example.tbl +++ /dev/null @@ -1,2 +0,0 @@ -# SS no. API type Function Args -300 custom example_sec_serv_aes_op 5 diff --git a/examples/security/tee/tee_basic/components/example_secure_service/sec_srv_tbl_example.yml b/examples/security/tee/tee_basic/components/example_secure_service/sec_srv_tbl_example.yml new file mode 100644 index 0000000000..8b55150673 --- /dev/null +++ b/examples/security/tee/tee_basic/components/example_secure_service/sec_srv_tbl_example.yml @@ -0,0 +1,7 @@ +secure_services: + - family: example + entries: + - id: 200 + type: custom + function: example_sec_serv_aes_op + args: 5 diff --git a/examples/security/tee/tee_basic/components/example_secure_service/tee_project.cmake b/examples/security/tee/tee_basic/components/example_secure_service/tee_project.cmake index 28ffbc57ec..f0340c19e1 100644 --- a/examples/security/tee/tee_basic/components/example_secure_service/tee_project.cmake +++ b/examples/security/tee/tee_basic/components/example_secure_service/tee_project.cmake @@ -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 From c23714f7755832e3750ac31b4b36598def5e48e4 Mon Sep 17 00:00:00 2001 From: Laukik Hase Date: Wed, 29 Jan 2025 12:16:27 +0530 Subject: [PATCH 3/4] feat(esp_tee): Add support for flash memory isolation and protection (SPI1) --- .../bootloader_flash/src/bootloader_flash.c | 12 +- components/esp_tee/CMakeLists.txt | 4 + components/esp_tee/Kconfig.projbuild | 29 ++++ .../scripts/esp32c6/sec_srv_tbl_default.yml | 71 ++++++++ .../esp_tee/src/esp_secure_service_wrapper.c | 100 +++++++++++ .../esp_tee/subproject/main/CMakeLists.txt | 4 + .../main/core/esp_secure_services.c | 158 +++++++++++++++++- .../subproject/main/ld/esp32c6/esp_tee.ld.in | 2 + .../main/soc/esp32c6/esp_tee_apm_prot_cfg.c | 47 ++++-- components/spi_flash/spi_flash_chip_generic.c | 2 + docs/en/security/tee/tee-advanced.rst | 51 +++++- docs/en/security/tee/tee-sec-storage.rst | 4 - docs/en/security/tee/tee.rst | 10 +- 13 files changed, 463 insertions(+), 31 deletions(-) diff --git a/components/bootloader_support/bootloader_flash/src/bootloader_flash.c b/components/bootloader_support/bootloader_flash/src/bootloader_flash.c index a486b64378..fddcc982d6 100644 --- a/components/bootloader_support/bootloader_flash/src/bootloader_flash.c +++ b/components/bootloader_support/bootloader_flash/src/bootloader_flash.c @@ -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) { diff --git a/components/esp_tee/CMakeLists.txt b/components/esp_tee/CMakeLists.txt index ef69044eb7..f49ac66730 100644 --- a/components/esp_tee/CMakeLists.txt +++ b/components/esp_tee/CMakeLists.txt @@ -94,6 +94,10 @@ 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() diff --git a/components/esp_tee/Kconfig.projbuild b/components/esp_tee/Kconfig.projbuild index 69886842bd..e01d157db5 100644 --- a/components/esp_tee/Kconfig.projbuild +++ b/components/esp_tee/Kconfig.projbuild @@ -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 diff --git a/components/esp_tee/scripts/esp32c6/sec_srv_tbl_default.yml b/components/esp_tee/scripts/esp32c6/sec_srv_tbl_default.yml index d15d125f3a..45a0837722 100644 --- a/components/esp_tee/scripts/esp32c6/sec_srv_tbl_default.yml +++ b/components/esp_tee/scripts/esp32c6/sec_srv_tbl_default.yml @@ -24,6 +24,77 @@ secure_services: 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: diff --git a/components/esp_tee/src/esp_secure_service_wrapper.c b/components/esp_tee/src/esp_secure_service_wrapper.c index 21abec2ba5..5c3e3232f8 100644 --- a/components/esp_tee/src/esp_secure_service_wrapper.c +++ b/components/esp_tee/src/esp_secure_service_wrapper.c @@ -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 diff --git a/components/esp_tee/subproject/main/CMakeLists.txt b/components/esp_tee/subproject/main/CMakeLists.txt index 752e4ecec8..4be567ca54 100644 --- a/components/esp_tee/subproject/main/CMakeLists.txt +++ b/components/esp_tee/subproject/main/CMakeLists.txt @@ -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" diff --git a/components/esp_tee/subproject/main/core/esp_secure_services.c b/components/esp_tee/subproject/main/core/esp_secure_services.c index 87c5275f4d..6c5fb5dc9b 100644 --- a/components/esp_tee/subproject/main/core/esp_secure_services.c +++ b/components/esp_tee/subproject/main/core/esp_secure_services.c @@ -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 diff --git a/components/esp_tee/subproject/main/ld/esp32c6/esp_tee.ld.in b/components/esp_tee/subproject/main/ld/esp32c6/esp_tee.ld.in index 48a8710655..b0e259c1e3 100644 --- a/components/esp_tee/subproject/main/ld/esp32c6/esp_tee.ld.in +++ b/components/esp_tee/subproject/main/ld/esp32c6/esp_tee.ld.in @@ -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(.); diff --git a/components/esp_tee/subproject/main/soc/esp32c6/esp_tee_apm_prot_cfg.c b/components/esp_tee/subproject/main/soc/esp32c6/esp_tee_apm_prot_cfg.c index a7d3a130eb..3c027c0693 100644 --- a/components/esp_tee/subproject/main/soc/esp32c6/esp_tee_apm_prot_cfg.c +++ b/components/esp_tee/subproject/main/soc/esp32c6/esp_tee_apm_prot_cfg.c @@ -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, diff --git a/components/spi_flash/spi_flash_chip_generic.c b/components/spi_flash/spi_flash_chip_generic.c index 287ac7e7b1..0680e743d2 100644 --- a/components/spi_flash/spi_flash_chip_generic.c +++ b/components/spi_flash/spi_flash_chip_generic.c @@ -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) { diff --git a/docs/en/security/tee/tee-advanced.rst b/docs/en/security/tee/tee-advanced.rst index 24ca16191f..20e8669654 100644 --- a/docs/en/security/tee/tee-advanced.rst +++ b/docs/en/security/tee/tee-advanced.rst @@ -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 ` 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 `, :ref:`TEE OTA data `) 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 ~~~~~~~~~~~ diff --git a/docs/en/security/tee/tee-sec-storage.rst b/docs/en/security/tee/tee-sec-storage.rst index a5d36118af..b72f0a8e7c 100644 --- a/docs/en/security/tee/tee-sec-storage.rst +++ b/docs/en/security/tee/tee-sec-storage.rst @@ -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: diff --git a/docs/en/security/tee/tee.rst b/docs/en/security/tee/tee.rst index b8ea2ab93f..bef9266346 100644 --- a/docs/en/security/tee/tee.rst +++ b/docs/en/security/tee/tee.rst @@ -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 ` section from the advanced guide. + .. _tee-secure-services: Secure Services From 7d49f696c1aeb9b8b4d7d99b8a67bbd2368aedbd Mon Sep 17 00:00:00 2001 From: Laukik Hase Date: Thu, 23 Jan 2025 11:47:19 +0530 Subject: [PATCH 4/4] ci(esp_tee): Add tests for verifying behaviour for illegal flash accesses (SPI1) --- .../test_apps/tee_cli_app/sdkconfig.defaults | 3 + .../main/test_esp_tee_flash_prot.c | 234 +++++++++++++++++- .../test_apps/tee_test_fw/partitions.csv | 1 + .../tee_test_fw/partitions_tee_ota.csv | 1 + .../tee_test_fw/pytest_esp_tee_ut.py | 116 ++++++++- .../test_apps/tee_test_fw/sdkconfig.ci.ota | 3 + 6 files changed, 346 insertions(+), 12 deletions(-) diff --git a/components/esp_tee/test_apps/tee_cli_app/sdkconfig.defaults b/components/esp_tee/test_apps/tee_cli_app/sdkconfig.defaults index f6cf613bd1..6235cf4cf7 100644 --- a/components/esp_tee/test_apps/tee_cli_app/sdkconfig.defaults +++ b/components/esp_tee/test_apps/tee_cli_app/sdkconfig.defaults @@ -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 diff --git a/components/esp_tee/test_apps/tee_test_fw/main/test_esp_tee_flash_prot.c b/components/esp_tee/test_apps/tee_test_fw/main/test_esp_tee_flash_prot.c index 3949878a36..ffd979db81 100644 --- a/components/esp_tee/test_apps/tee_test_fw/main/test_esp_tee_flash_prot.c +++ b/components/esp_tee/test_apps/tee_test_fw/main/test_esp_tee_flash_prot.c @@ -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); +} diff --git a/components/esp_tee/test_apps/tee_test_fw/partitions.csv b/components/esp_tee/test_apps/tee_test_fw/partitions.csv index e5f7bb21fd..d79624198b 100644 --- a/components/esp_tee/test_apps/tee_test_fw/partitions.csv +++ b/components/esp_tee/test_apps/tee_test_fw/partitions.csv @@ -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 diff --git a/components/esp_tee/test_apps/tee_test_fw/partitions_tee_ota.csv b/components/esp_tee/test_apps/tee_test_fw/partitions_tee_ota.csv index 7856d6bb34..6708e6401e 100644 --- a/components/esp_tee/test_apps/tee_test_fw/partitions_tee_ota.csv +++ b/components/esp_tee/test_apps/tee_test_fw/partitions_tee_ota.csv @@ -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 diff --git a/components/esp_tee/test_apps/tee_test_fw/pytest_esp_tee_ut.py b/components/esp_tee/test_apps/tee_test_fw/pytest_esp_tee_ut.py index 0d41fef279..6bbed77791 100644 --- a/components/esp_tee/test_apps/tee_test_fw/pytest_esp_tee_ut.py +++ b/components/esp_tee/test_apps/tee_test_fw/pytest_esp_tee_ut.py @@ -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 diff --git a/components/esp_tee/test_apps/tee_test_fw/sdkconfig.ci.ota b/components/esp_tee/test_apps/tee_test_fw/sdkconfig.ci.ota index f6984d573c..ba0a656949 100644 --- a/components/esp_tee/test_apps/tee_test_fw/sdkconfig.ci.ota +++ b/components/esp_tee/test_apps/tee_test_fw/sdkconfig.ci.ota @@ -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