diff --git a/components/esp_tee/test_apps/tee_cli_app/README.md b/components/esp_tee/test_apps/tee_cli_app/README.md index cc2ad5bfb2..67ae90d8f1 100644 --- a/components/esp_tee/test_apps/tee_cli_app/README.md +++ b/components/esp_tee/test_apps/tee_cli_app/README.md @@ -17,20 +17,35 @@ This example can be executed on any development board with a Espressif SOC chip - Configure the secure storage key ID for generating/fetching the ECDSA keypair for attestation token signing at `ESP-TEE (Trusted Execution Environment) → Secure Services → Attestation: Secure Storage key ID for EAT signing`. -Configure the Secure Storage mode for determining how the NVS XTS encryption keys are derived at `ESP-TEE (Trusted Execution Environment) → Secure Services → Secure Storage: Mode` +Configure the Secure Storage mode for determining how the NVS XTS-AES encryption keys are derived at `ESP-TEE (Trusted Execution Environment) → Secure Services → Secure Storage: Mode` - **Development** Mode: Encryption keys are embedded in the ESP-TEE firmware (identical across all instances). - - **Release** Mode: Encryption keys are derived via the HMAC peripheral using a key stored in eFuse. - - Set the eFuse key ID storing the HMAC key at `ESP-TEE (Trusted Execution Environment) → Secure Services → Secure Storage: eFuse HMAC key ID for storage encryption keys`. - - Snippet for burning the secure storage key in eFuse is given below. + - **Release** Mode: Encryption keys are derived using a key stored in eFuse, specified by `CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID`. + - Set the eFuse key ID at `ESP-TEE (Trusted Execution Environment) → Secure Services → Secure Storage: eFuse HMAC key ID for storage encryption keys`. + - Before running the application, users must program the required key into the configured eFuse block - refer to the instructions below. - ```shell - # Generate a random 32-byte HMAC key - openssl rand -out hmac_key_file.bin 32 - # Programming the HMAC key (256-bit) in eFuse - # Here, BLOCK_KEYx is a free eFuse key-block between BLOCK_KEY0 and BLOCK_KEY5 - espefuse -p PORT burn-key BLOCK_KEYx hmac_key_file.bin HMAC_UP - ``` +**For targets without HMAC peripheral (ESP32-C61):** + +```shell +# Generate a random 32-byte key +openssl rand -out hmac_key_file.bin 32 +# Program the USER purpose key (256-bit) in eFuse +# Here, BLOCK_KEYx is a free eFuse key-block between BLOCK_KEY0 and BLOCK_KEY5 +espefuse -p PORT burn-key --no-read-protect BLOCK_KEYx hmac_key_file.bin USER +``` + +> [!IMPORTANT] +> When programming the key into eFuse for targets without HMAC peripheral, ensure that it is **NOT** marked as read-protected (use the `--no-read-protect` flag). If the key is read-protected, the TEE will be unable to access it. However, this does not weaken security: the APM peripheral already blocks software access to the key, and any illegal read or write attempt from the REE triggers a fault. + +**For targets with HMAC peripheral:** + +```shell +# Generate a random 32-byte HMAC key +openssl rand -out hmac_key_file.bin 32 +# Program the HMAC key (256-bit) in eFuse +# Here, BLOCK_KEYx is a free eFuse key-block between BLOCK_KEY0 and BLOCK_KEY5 +espefuse -p PORT burn-key BLOCK_KEYx hmac_key_file.bin HMAC_UP +``` ### Build and Flash diff --git a/docs/conf_common.py b/docs/conf_common.py index b6feb4a241..48f608f56f 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -309,7 +309,7 @@ ESP32C61_DOCS = [ 'api-guides/phy.rst', 'api-reference/peripherals/sd_pullup_requirements.rst', 'api-guides/RF_calibration.rst', -] +] + ESP_TEE_DOCS ESP32C6_DOCS = [ 'api-guides/RF_calibration.rst', diff --git a/docs/doxygen/Doxyfile_esp32c61 b/docs/doxygen/Doxyfile_esp32c61 index 74f603a122..674784e580 100644 --- a/docs/doxygen/Doxyfile_esp32c61 +++ b/docs/doxygen/Doxyfile_esp32c61 @@ -5,3 +5,7 @@ INPUT += \ $(PROJECT_PATH)/components/bt/include/esp32c6/include/esp_bt_vs.h \ $(PROJECT_PATH)/components/esp_phy/include/esp_phy_init.h \ $(PROJECT_PATH)/components/esp_phy/include/esp_phy_cert_test.h \ + $(PROJECT_PATH)/components/esp_tee/include/esp_tee.h \ + $(PROJECT_PATH)/components/esp_tee/subproject/components/tee_sec_storage/include/esp_tee_sec_storage.h \ + $(PROJECT_PATH)/components/esp_tee/subproject/components/tee_attestation/esp_tee_attestation.h \ + $(PROJECT_PATH)/components/esp_tee/subproject/components/tee_ota_ops/include/esp_tee_ota_ops.h \ diff --git a/docs/en/security/index.rst b/docs/en/security/index.rst index 9a108e9302..96529124c1 100644 --- a/docs/en/security/index.rst +++ b/docs/en/security/index.rst @@ -10,6 +10,6 @@ Security Guides flash-encryption :esp32: secure-boot-v1 secure-boot-v2 - :esp32c6 or esp32c5: tee/index + :esp32c6 or esp32c5 or esp32c61: tee/index security-features-enablement-workflows vulnerabilities diff --git a/docs/en/security/tee/tee-sec-storage.rst b/docs/en/security/tee/tee-sec-storage.rst index 22c37b11f8..c3c0e88055 100644 --- a/docs/en/security/tee/tee-sec-storage.rst +++ b/docs/en/security/tee/tee-sec-storage.rst @@ -5,12 +5,18 @@ Overview -------- The TEE Secure Storage service provides persistent storage for securely storing sensitive data, such as cryptographic keys, cloud credentials, or other general-purpose information. It uses a dedicated flash partition of type ``data`` and subtype ``nvs``. The TEE ensures both confidentiality and integrity of the stored data. -TEE Secure Storage adopts the :doc:`../../api-reference/storage/nvs_flash` partition format and uses the HMAC peripheral-based XTS-AES encryption scheme, as detailed :ref:`here `. The AES encryption keys are derived from an HMAC key programmed in eFuse with the purpose :cpp:enumerator:`esp_efuse_purpose_t::ESP_EFUSE_KEY_PURPOSE_HMAC_UP`. Please note that the TEE Secure storage does not support the :ref:`NVS Flash Encryption-based scheme `. +.. only:: SOC_HMAC_SUPPORTED + + TEE Secure Storage adopts the :doc:`../../api-reference/storage/nvs_flash` partition format and uses the HMAC peripheral-based XTS-AES encryption scheme, as detailed :ref:`here `. The AES encryption keys are derived from an HMAC key programmed in eFuse with the purpose :cpp:enumerator:`esp_efuse_purpose_t::ESP_EFUSE_KEY_PURPOSE_HMAC_UP`. Please note that the TEE Secure storage does not support the :ref:`NVS Flash Encryption-based scheme `. + +.. only:: not SOC_HMAC_SUPPORTED + + TEE Secure Storage adopts the :doc:`../../api-reference/storage/nvs_flash` partition format and uses the HMAC-based XTS-AES encryption scheme. There is, however, an important difference in how the HMAC step is handled. Since {IDF_TARGET_NAME} lacks a hardware HMAC peripheral, the HMAC computation is carried out in software with assistance from the SHA peripheral.The AES encryption keys are derived from an eFuse key with the purpose :cpp:enumerator:`esp_efuse_purpose_t::ESP_EFUSE_KEY_PURPOSE_USER`. Please note that the TEE Secure storage does not support the :ref:`NVS Flash Encryption-based scheme `. .. important:: - One eFuse block is required to store the HMAC key used for deriving the NVS encryption keys. This key is exclusive to the TEE and **CANNOT** be used by the REE for any purpose. - - The HMAC key must be programmed into eFuse before firmware execution, as TEE Secure Storage does not support generating it on-device. If no valid key with the required purpose is found in the configured eFuse block, an error will be raised at runtime. + - The required key must be programmed into eFuse before firmware execution, as TEE Secure Storage does not support generating it on-device. If no valid key with the required purpose is found in the configured eFuse block, an error will be raised at runtime. Additionally, the secure storage provides interfaces for performing the following cryptographic services from the TEE using securely stored key material: @@ -21,12 +27,14 @@ Additionally, the secure storage provides interfaces for performing the followin As per the current implementation, the TEE Secure Storage partition **must** have the label ``secure_storage``. -TEE secure storage also supports ECDSA signing with keys derived via PBKDF2 (Password-Based Key Derivation Function 2), using an HMAC key programmed in eFuse along with a user-provided salt. This mechanism enables ECDSA signing on both P-256 and P-192 curves without requiring storage of the actual private keys. The eFuse HMAC key ID for the PBKDF2 operations is specified via the :ref:`CONFIG_SECURE_TEE_PBKDF2_EFUSE_HMAC_KEY_ID` option. +.. only:: SOC_HMAC_SUPPORTED -.. important:: + TEE secure storage also supports ECDSA signing with keys derived via PBKDF2 (Password-Based Key Derivation Function 2), using an HMAC key programmed in eFuse along with a user-provided salt. This mechanism enables ECDSA signing on both P-256 and P-192 curves without requiring storage of the actual private keys. The eFuse HMAC key ID for the PBKDF2 operations is specified via the :ref:`CONFIG_SECURE_TEE_PBKDF2_EFUSE_HMAC_KEY_ID` option. - - The eFuse HMAC key ID used for PBKDF2-based signing **CANNOT** be the same as the one used for deriving TEE secure storage encryption keys (i.e., :ref:`CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID`). - - This eFuse ID is also exclusive to the TEE and **CANNOT** be used by the REE for any purpose. + .. important:: + + - The eFuse HMAC key ID used for PBKDF2-based signing **CANNOT** be the same as the one used for deriving TEE secure storage encryption keys (i.e., :ref:`CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID`). + - This eFuse ID is also exclusive to the TEE and **CANNOT** be used by the REE for any purpose. Internals --------- @@ -47,7 +55,9 @@ All assets related to TEE secure storage are protected by the APM peripheral and The TEE Secure Storage feature supports two modes for determining how the NVS encryption keys are derived (see :ref:`CONFIG_SECURE_TEE_SEC_STG_MODE`): - **Development** Mode: Encryption keys are embedded (constant for all instances) in the ESP-TEE firmware. - - **Release** Mode: Encryption keys are derived via the HMAC peripheral using a key stored in eFuse, specified by :ref:`CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID`. + - **Release** Mode: Encryption keys are derived via the HMAC peripheral (or software-based HMAC implementation) using a key stored in eFuse, specified by :ref:`CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID`. + +.. only:: SOC_HMAC_SUPPORTED .. note:: @@ -61,7 +71,28 @@ The TEE Secure Storage feature supports two modes for determining how the NVS en openssl rand -out hmac_key_file.bin 32 # Program the HMAC key into the eFuse block - idf.py -p PORT efuse-burn-key hmac_key_file.bin HMAC_UP + espefuse -p PORT burn-key hmac_key_file.bin HMAC_UP + +.. only:: not SOC_HMAC_SUPPORTED + + .. note:: + + - The valid range for :ref:`CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID` is from ``0`` (:cpp:enumerator:`esp_efuse_block_t::EFUSE_BLK_KEY0`) to ``5`` (:cpp:enumerator:`esp_efuse_block_t::EFUSE_BLK_KEY5`). By default, this config is set to ``-1`` and must be configured before building the TEE application. + + - The following commands can be used to generate and program the USER purpose key into the required eFuse block: + + :: + + # Generate a random 32-byte key + openssl rand -out hmac_key_file.bin 32 + + # Program the USER purpose key into the eFuse block + espefuse -p PORT burn-key --no-read-protect hmac_key_file.bin USER + + .. warning:: + + - When programming the key into eFuse, ensure that it is **NOT** marked as read-protected (use the ``--no-read-protect`` flag). If the key is read-protected, the TEE will be unable to access it. + - However, this does not weaken security: the APM peripheral already blocks software access to the key, and any illegal read or write attempt from the REE triggers a fault. Tools ----- diff --git a/docs/zh_CN/security/index.rst b/docs/zh_CN/security/index.rst index da5da3dd41..556270dc27 100644 --- a/docs/zh_CN/security/index.rst +++ b/docs/zh_CN/security/index.rst @@ -10,6 +10,6 @@ flash-encryption :esp32: secure-boot-v1 secure-boot-v2 - :esp32c6 or esp32c5: tee/index + :esp32c6 or esp32c5 or esp32c61: tee/index security-features-enablement-workflows vulnerabilities diff --git a/examples/security/.build-test-rules.yml b/examples/security/.build-test-rules.yml index 64d0781791..9b097ea8fd 100644 --- a/examples/security/.build-test-rules.yml +++ b/examples/security/.build-test-rules.yml @@ -38,7 +38,7 @@ examples/security/security_features_app: examples/security/tee/tee_attestation: disable: - - if: IDF_TARGET not in ["esp32c6"] + - if: IDF_TARGET not in ["esp32c6", "esp32c61"] depends_components: - esp_tee depends_filepatterns: @@ -46,7 +46,7 @@ examples/security/tee/tee_attestation: examples/security/tee/tee_basic: disable: - - if: IDF_TARGET not in ["esp32c6"] + - if: IDF_TARGET not in ["esp32c6", "esp32c61"] depends_components: - esp_tee depends_filepatterns: @@ -54,7 +54,7 @@ examples/security/tee/tee_basic: examples/security/tee/tee_secure_ota: disable: - - if: IDF_TARGET not in ["esp32c6"] + - if: IDF_TARGET not in ["esp32c6", "esp32c61"] depends_components: - esp_tee depends_filepatterns: @@ -62,7 +62,7 @@ examples/security/tee/tee_secure_ota: examples/security/tee/tee_secure_storage: disable: - - if: IDF_TARGET not in ["esp32c6"] + - if: IDF_TARGET not in ["esp32c6", "esp32c61"] depends_components: - esp_tee depends_filepatterns: diff --git a/examples/security/tee/tee_attestation/README.md b/examples/security/tee/tee_attestation/README.md index 8718725475..4f8ee89a3b 100644 --- a/examples/security/tee/tee_attestation/README.md +++ b/examples/security/tee/tee_attestation/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C6 | -| ----------------- | -------- | +| Supported Targets | ESP32-C6 | ESP32-C61 | +| ----------------- | -------- | --------- | # TEE: Attestation example diff --git a/examples/security/tee/tee_attestation/pytest_tee_attestation.py b/examples/security/tee/tee_attestation/pytest_tee_attestation.py index debb2431ae..8dc9e2d123 100644 --- a/examples/security/tee/tee_attestation/pytest_tee_attestation.py +++ b/examples/security/tee/tee_attestation/pytest_tee_attestation.py @@ -46,7 +46,7 @@ def verify_att_token_signature(att_tk: str) -> Any: @pytest.mark.generic -@idf_parametrize('target', ['esp32c6'], indirect=['target']) +@idf_parametrize('target', ['supported_targets'], indirect=['target']) def test_example_tee_attestation(dut: Dut) -> None: # Erase the TEE secure_storage partition dut.serial.erase_partition('secure_storage') diff --git a/examples/security/tee/tee_basic/README.md b/examples/security/tee/tee_basic/README.md index 894ba5e4fc..4b8b7e8a31 100644 --- a/examples/security/tee/tee_basic/README.md +++ b/examples/security/tee/tee_basic/README.md @@ -1,12 +1,12 @@ -| Supported Targets | ESP32-C6 | -| ----------------- | -------- | +| Supported Targets | ESP32-C6 | ESP32-C61 | +| ----------------- | -------- | --------- | # Basic TEE example ## Overview - This example illustrates the ESP-TEE (Trusted Execution Environment) framework to encrypt/decrypt data using AES within a secure environment. -- The non-secure world i.e. the Rich Execution Environment (REE) raises a request for AES operation in TEE through the secure service call interface. The TEE performs encrypts/decrypts the given buffer with the AES-256-CBC mode using the key protected by TEE. If the operation is successful, the result of the AES operation is returned in the output buffer provided in the secure service call by the REE. +- The non-secure world i.e. the Rich Execution Environment (REE) raises a request for AES operation in TEE through the secure service call interface. The TEE performs encrypts/decrypts the given buffer with the AES-256-GCM mode using the key protected by TEE. If the operation is successful, the result of the AES operation is returned in the output buffer provided in the secure service call by the REE. - This example also demonstrates how to add custom service calls to TEE. You can refer to `components/example_service` for more information - see the structure below. ``` @@ -43,15 +43,15 @@ See the Getting Started Guide for full steps to configure and use ESP-IDF to bui ### Example Output ```log -I (315) main_task: Calling app_main() -I (315) example_tee_basic: AES-256-CBC operations in TEE -TEE: Secure service call for AES-256-CBC operation -TEE: In PROTECTED M-mode -I (325) example_tee_basic: AES encryption successful! -I (325) example_tee_basic: Cipher text - -I (325) example_tee_basic: ee 04 9b ee 95 6f 25 04 1e 8c e4 4e 8e 4e 7a d3 -TEE: Secure service call for AES-256-CBC operation -TEE: In PROTECTED M-mode -I (345) example_tee_basic: AES decryption successful! -I (345) main_task: Returned from app_main() +I (353) main_task: Calling app_main() +I (353) example_tee_basic: AES-256-GCM operations in TEE +I (364) example_tee_service: Secure service call: PROTECTED M-mode +I (370) example_tee_service: AES-256-GCM encryption +I (373) ciphertext: 23 32 a6 1f ff 27 15 d7 35 70 db f5 e3 0c 13 41 +I (373) ciphertext: eb 80 d7 2c 9c f5 68 5a b4 2c 43 b0 64 68 13 36 +I (383) tag: f8 85 ab 3b 47 a6 65 0d 0a 42 bd 3d +I (391) example_tee_service: Secure service call: PROTECTED M-mode +I (397) example_tee_service: AES-256-GCM decryption +I (393) example_tee_basic: AES-GCM decryption successful! +I (403) main_task: Returned from app_main() ``` diff --git a/examples/security/tee/tee_basic/components/example_secure_service/CMakeLists.txt b/examples/security/tee/tee_basic/components/example_secure_service/CMakeLists.txt index 4007e34517..58deeca4de 100644 --- a/examples/security/tee/tee_basic/components/example_secure_service/CMakeLists.txt +++ b/examples/security/tee/tee_basic/components/example_secure_service/CMakeLists.txt @@ -2,10 +2,13 @@ cmake_minimum_required(VERSION 3.22) idf_build_get_property(esp_tee_build ESP_TEE_BUILD) -if(NOT esp_tee_build) - return() +set(srcs) +set(include_dirs include) + +if(esp_tee_build) + list(APPEND srcs "example_service.c") endif() -idf_component_register(SRCS "example_service.c" - INCLUDE_DIRS include +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS ${include_dirs} PRIV_REQUIRES main) diff --git a/examples/security/tee/tee_basic/components/example_secure_service/example_service.c b/examples/security/tee/tee_basic/components/example_secure_service/example_service.c index 0be518e82a..ba8b738da6 100644 --- a/examples/security/tee/tee_basic/components/example_secure_service/example_service.c +++ b/examples/security/tee/tee_basic/components/example_secure_service/example_service.c @@ -1,39 +1,95 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ +#include #include "esp_cpu.h" #include "esp_err.h" -#include "esp_rom_sys.h" +#include "esp_log.h" -#include "hal/aes_hal.h" -#include "aes/esp_aes.h" +#include "mbedtls/gcm.h" #include "esp_tee.h" #include "secure_service_num.h" +#include "example_service.h" -/* Fixed key */ -static const uint8_t key[AES_256_KEY_BYTES] = {[0 ... 31] = 0xA5}; +#define AES256_KEY_LEN 32 +#define AES256_KEY_BITS (AES256_KEY_LEN * 8) +#define AES256_NONCE_LEN 12 -esp_err_t _ss_example_sec_serv_aes_op(int mode, size_t length, unsigned char iv[16], const unsigned char *input, unsigned char *output) +static const char *TAG = "tee_secure_service"; + +/* Fixed key (only for example purposes) */ +static const uint8_t key[AES256_KEY_LEN] = {[0 ... AES256_KEY_LEN - 1] = 0xA5}; + +/* Fixed nonce (only for example purposes) */ +static const uint8_t nonce[AES256_NONCE_LEN] = {[0 ... AES256_NONCE_LEN - 1] = 0x5A}; + +static esp_err_t aes_gcm_crypt_common(example_aes_gcm_ctx_t *ctx, uint8_t *tag, size_t tag_len, + uint8_t *output, bool is_encrypt) { - if (length == 0 || iv == NULL || input == NULL || output == NULL) { - return ESP_ERR_INVALID_ARG; - } - if (esp_cpu_get_curr_privilege_level() != ESP_CPU_S_MODE) { - esp_rom_printf("Operation executing from illegal privilege level!\n"); + ESP_LOGE(TAG, "Operation executing from illegal privilege level!"); return ESP_ERR_INVALID_STATE; } - esp_rom_printf("TEE: Secure service call for AES-256-CBC operation\n"); - esp_rom_printf("TEE: In PROTECTED M-mode\n"); + if (ctx == NULL || ctx->input == NULL || output == NULL || tag == NULL) { + return ESP_ERR_INVALID_ARG; + } - esp_aes_context ctx = {}; - ctx.key_bytes = AES_256_KEY_BYTES; - ctx.key_in_hardware = 0; - memcpy(ctx.key, key, ctx.key_bytes); + if (ctx->input_len == 0 || tag_len == 0) { + return ESP_ERR_INVALID_ARG; + } - return (esp_err_t)esp_aes_crypt_cbc(&ctx, mode, length, iv, input, output); + ESP_LOGI(TAG, "Secure service call: PROTECTED M-mode"); + ESP_LOGI(TAG, "AES-256-GCM %s", is_encrypt ? "encryption" : "decryption"); + + mbedtls_gcm_context gcm; + mbedtls_gcm_init(&gcm); + + esp_err_t err = ESP_FAIL; + + int ret = mbedtls_gcm_setkey(&gcm, MBEDTLS_CIPHER_ID_AES, key, AES256_KEY_BITS); + if (ret != 0) { + ESP_LOGE(TAG, "Error in setting key: %d", ret); + goto cleanup; + } + + if (is_encrypt) { + ret = mbedtls_gcm_crypt_and_tag(&gcm, MBEDTLS_GCM_ENCRYPT, ctx->input_len, + nonce, AES256_NONCE_LEN, + ctx->aad, ctx->aad_len, + ctx->input, output, + tag_len, tag); + if (ret != 0) { + ESP_LOGE(TAG, "Error in encrypting data: %d", ret); + goto cleanup; + } + } else { + ret = mbedtls_gcm_auth_decrypt(&gcm, ctx->input_len, + nonce, AES256_NONCE_LEN, + ctx->aad, ctx->aad_len, + tag, tag_len, + ctx->input, output); + if (ret != 0) { + ESP_LOGE(TAG, "Error in decrypting data: %d", ret); + goto cleanup; + } + } + err = ESP_OK; + +cleanup: + mbedtls_gcm_free(&gcm); + return err; +} + +esp_err_t _ss_example_sec_serv_aes_gcm_encrypt(example_aes_gcm_ctx_t *ctx, uint8_t *tag, size_t tag_len, uint8_t *output) +{ + return aes_gcm_crypt_common(ctx, tag, tag_len, output, true); +} + +esp_err_t _ss_example_sec_serv_aes_gcm_decrypt(example_aes_gcm_ctx_t *ctx, const uint8_t *tag, size_t tag_len, uint8_t *output) +{ + return aes_gcm_crypt_common(ctx, (uint8_t *)tag, tag_len, output, false); } diff --git a/examples/security/tee/tee_basic/components/example_secure_service/include/example_service.h b/examples/security/tee/tee_basic/components/example_secure_service/include/example_service.h index 6ea9efa37f..f13267e0fa 100644 --- a/examples/security/tee/tee_basic/components/example_secure_service/include/example_service.h +++ b/examples/security/tee/tee_basic/components/example_secure_service/include/example_service.h @@ -1,20 +1,18 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ #include "esp_err.h" -/** - * @brief Perform AES-256-CBC encryption/decryption operation in TEE - * - * @param mode ESP_AES_ENCRYPT (1) for encryption, ESP_AES_DECRYPT (0) for decryption - * @param length Length of input data in bytes - * @param iv Initialization vector (16 bytes) - * @param input Input buffer containing plaintext (for encryption) or ciphertext (for decryption) - * @param output Output buffer for ciphertext (for encryption) or plaintext (for decryption) - * - * @return esp_err_t ESP_OK on success, appropriate error code on failure - */ -esp_err_t example_sec_serv_aes_op(int mode, size_t length, unsigned char iv[16], const unsigned char *input, unsigned char *output); +typedef struct { + const uint8_t *aad; /*!< Additional authenticated data */ + size_t aad_len; /*!< Length of additional authenticated data */ + const uint8_t *input; /*!< Input data buffer */ + size_t input_len; /*!< Length of input data */ +} example_aes_gcm_ctx_t; + +esp_err_t example_sec_serv_aes_gcm_encrypt(example_aes_gcm_ctx_t *ctx, uint8_t *tag, size_t tag_len, uint8_t *output); + +esp_err_t example_sec_serv_aes_gcm_decrypt(example_aes_gcm_ctx_t *ctx, const uint8_t *tag, size_t tag_len, uint8_t *output); 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 index 8b55150673..3ecc846124 100644 --- 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 @@ -3,5 +3,9 @@ secure_services: entries: - id: 200 type: custom - function: example_sec_serv_aes_op - args: 5 + function: example_sec_serv_aes_gcm_encrypt + args: 4 + - id: 201 + type: custom + function: example_sec_serv_aes_gcm_decrypt + args: 4 diff --git a/examples/security/tee/tee_basic/main/CMakeLists.txt b/examples/security/tee/tee_basic/main/CMakeLists.txt index c9e36bfd72..962b2a0326 100644 --- a/examples/security/tee/tee_basic/main/CMakeLists.txt +++ b/examples/security/tee/tee_basic/main/CMakeLists.txt @@ -1,3 +1,3 @@ idf_component_register(SRCS "tee_main.c" - INCLUDE_DIRS "" - PRIV_REQUIRES esp_tee mbedtls) + INCLUDE_DIRS "" + PRIV_REQUIRES esp_tee mbedtls example_secure_service) diff --git a/examples/security/tee/tee_basic/main/tee_main.c b/examples/security/tee/tee_basic/main/tee_main.c index 6d30288a84..e050320b9e 100644 --- a/examples/security/tee/tee_basic/main/tee_main.c +++ b/examples/security/tee/tee_basic/main/tee_main.c @@ -1,6 +1,6 @@ /* ESP-TEE (Trusted Execution Environment) Example * - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -10,55 +10,72 @@ #include "esp_log.h" #include "esp_err.h" -#include "aes/esp_aes.h" +#include "esp_random.h" #include "esp_tee.h" #include "secure_service_num.h" +#include "example_service.h" -#define BUF_SZ (16) +#define EXAMPLE_BUF_SZ (32) +#define AES256_GCM_TAG_LEN (12) +#define AES256_GCM_AAD_LEN (16) static const char *TAG = "example_tee_basic"; -static const uint8_t expected_cipher[] = { - 0xee, 0x04, 0x9b, 0xee, 0x95, 0x6f, 0x25, 0x04, - 0x1e, 0x8c, 0xe4, 0x4e, 0x8e, 0x4e, 0x7a, 0xd3 -}; - -static const uint8_t nonce[IV_BYTES] = {[0 ... IV_BYTES - 1] = 0xFF}; - /* * Example workflow: - * 1. The REE initiates an AES operation request via the secure service call interface - * 2. The TEE receives the request and performs encryption/decryption using AES-256-CBC mode - * 3. The TEE uses a protected key that is only accessible within the secure environment - * 4. The encrypted/decrypted result is returned to the non-secure world through an output buffer - * provided in the secure service call + * 1. The REE generates random plaintext and AAD (Additional Authenticated Data) + * 2. The REE initiates an AES-256-GCM encryption request and provides output buffers + * for ciphertext and authentication tag + * 3. The TEE receives the request and performs encryption using a protected key and + * nonce that are only accessible within the secure environment + * 4. The encrypted ciphertext and authentication tag are returned to the REE + * 5. The REE initiates a decryption request with the ciphertext and authentication tag + * 6. The TEE performs authenticated decryption, verifying the tag and returning the plaintext + * 7. The REE verifies that the decrypted data matches the original plaintext */ void app_main(void) { - ESP_LOGI(TAG, "AES-256-CBC operations in TEE"); + ESP_LOGI(TAG, "AES-256-GCM operations in TEE"); - uint8_t plain_text[BUF_SZ] = {[0 ... BUF_SZ - 1] = 0x3A}; - uint8_t cipher_text[BUF_SZ] = {0}; - uint8_t decrypted_text[BUF_SZ] = {0}; - uint8_t iv[IV_BYTES] = {0}; + uint8_t plain_text[EXAMPLE_BUF_SZ]; + uint8_t cipher_text[EXAMPLE_BUF_SZ] = {0}; + uint8_t decrypted_text[EXAMPLE_BUF_SZ] = {0}; + uint8_t tag[AES256_GCM_TAG_LEN] = {0}; + uint8_t aad_buf[AES256_GCM_AAD_LEN]; - memcpy(iv, nonce, sizeof(iv)); - uint32_t ret = esp_tee_service_call(6, SS_EXAMPLE_SEC_SERV_AES_OP, ESP_AES_ENCRYPT, sizeof(plain_text), iv, plain_text, cipher_text); - if (ret != ESP_OK || memcmp(cipher_text, expected_cipher, sizeof(expected_cipher))) { - ESP_LOGE(TAG, "Failed to encrypt data!"); + /* Generate random plaintext and AAD */ + esp_fill_random(plain_text, sizeof(EXAMPLE_BUF_SZ)); + esp_fill_random(aad_buf, AES256_GCM_AAD_LEN); + + /* Encryption operation */ + example_aes_gcm_ctx_t enc_ctx = { + .aad = aad_buf, + .aad_len = sizeof(aad_buf), + .input = plain_text, + .input_len = sizeof(plain_text), + }; + + uint32_t ret = esp_tee_service_call(5, SS_EXAMPLE_SEC_SERV_AES_GCM_ENCRYPT, &enc_ctx, tag, AES256_GCM_TAG_LEN, cipher_text); + ESP_ERROR_CHECK((esp_err_t)ret); + + ESP_LOG_BUFFER_HEX_LEVEL("ciphertext", cipher_text, sizeof(cipher_text), ESP_LOG_INFO); + ESP_LOG_BUFFER_HEX_LEVEL("tag", tag, AES256_GCM_TAG_LEN, ESP_LOG_INFO); + + /* Decryption operation */ + example_aes_gcm_ctx_t dec_ctx = { + .aad = aad_buf, + .aad_len = sizeof(aad_buf), + .input = cipher_text, + .input_len = sizeof(cipher_text), + }; + + ret = esp_tee_service_call(5, SS_EXAMPLE_SEC_SERV_AES_GCM_DECRYPT, &dec_ctx, tag, AES256_GCM_TAG_LEN, decrypted_text); + ESP_ERROR_CHECK((esp_err_t)ret); + + if (memcmp(decrypted_text, plain_text, sizeof(plain_text)) != 0) { + ESP_LOGE(TAG, "Decrypted data mismatch!"); } else { - ESP_LOGI(TAG, "AES encryption successful!"); - } - - ESP_LOGI(TAG, "Cipher text -"); - ESP_LOG_BUFFER_HEX_LEVEL(TAG, cipher_text, sizeof(cipher_text), ESP_LOG_INFO); - - memcpy(iv, nonce, sizeof(iv)); - ret = esp_tee_service_call(6, SS_EXAMPLE_SEC_SERV_AES_OP, ESP_AES_DECRYPT, sizeof(cipher_text), iv, cipher_text, decrypted_text); - if (ret != ESP_OK || memcmp(decrypted_text, plain_text, sizeof(plain_text))) { - ESP_LOGE(TAG, "Failed to decrypt data!"); - } else { - ESP_LOGI(TAG, "AES decryption successful!"); + ESP_LOGI(TAG, "AES-GCM decryption successful!"); } } diff --git a/examples/security/tee/tee_basic/pytest_tee_basic.py b/examples/security/tee/tee_basic/pytest_tee_basic.py index d4f858164f..fdc466118e 100644 --- a/examples/security/tee/tee_basic/pytest_tee_basic.py +++ b/examples/security/tee/tee_basic/pytest_tee_basic.py @@ -9,7 +9,7 @@ from pytest_embedded_idf.utils import idf_parametrize @pytest.mark.generic -@idf_parametrize('target', ['esp32c6'], indirect=['target']) +@idf_parametrize('target', ['supported_targets'], indirect=['target']) def test_example_tee_basic(dut: Dut) -> None: # Logging example binary details binary_files = [ @@ -19,11 +19,12 @@ def test_example_tee_basic(dut: Dut) -> None: for file_name, log_label in binary_files: binary_file = os.path.join(dut.app.binary_path, file_name) bin_size = os.path.getsize(binary_file) - logging.info('{}: {}KB'.format(log_label, bin_size // 1024)) + logging.info(f'{log_label}: {bin_size // 1024}KB') # Start test - dut.expect('AES-256-CBC operations in TEE', timeout=30) - dut.expect('TEE: In PROTECTED M-mode', timeout=30) - dut.expect('AES encryption successful!', timeout=30) - dut.expect('ee 04 9b ee 95 6f 25 04 1e 8c e4 4e 8e 4e 7a d3', timeout=30) - dut.expect('AES decryption successful!', timeout=30) + dut.expect('AES-256-GCM operations in TEE', timeout=10) + dut.expect('Secure service call: PROTECTED M-mode', timeout=10) + dut.expect('AES-256-GCM encryption', timeout=10) + dut.expect('Secure service call: PROTECTED M-mode', timeout=10) + dut.expect('AES-256-GCM decryption', timeout=10) + dut.expect('Returned from app_main()', timeout=10) diff --git a/examples/security/tee/tee_basic/sdkconfig.defaults b/examples/security/tee/tee_basic/sdkconfig.defaults index 4c3a898568..214076f76e 100644 --- a/examples/security/tee/tee_basic/sdkconfig.defaults +++ b/examples/security/tee/tee_basic/sdkconfig.defaults @@ -1,5 +1,6 @@ # Enabling TEE CONFIG_SECURE_ENABLE_TEE=y +CONFIG_SECURE_TEE_LOG_LEVEL_INFO=y CONFIG_PARTITION_TABLE_SINGLE_APP_TEE=y CONFIG_SECURE_TEE_ATTESTATION=n CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN=n diff --git a/examples/security/tee/tee_secure_ota/README.md b/examples/security/tee/tee_secure_ota/README.md index 220f4c7d43..1601febb53 100644 --- a/examples/security/tee/tee_secure_ota/README.md +++ b/examples/security/tee/tee_secure_ota/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C6 | -| ----------------- | -------- | +| Supported Targets | ESP32-C6 | ESP32-C61 | +| ----------------- | -------- | --------- | # TEE: Secure OTA example diff --git a/examples/security/tee/tee_secure_ota/pytest_tee_secure_ota.py b/examples/security/tee/tee_secure_ota/pytest_tee_secure_ota.py index c8d7aba606..3f29d3f254 100644 --- a/examples/security/tee/tee_secure_ota/pytest_tee_secure_ota.py +++ b/examples/security/tee/tee_secure_ota/pytest_tee_secure_ota.py @@ -32,7 +32,7 @@ def start_https_server(ota_image_dir: str, server_ip: str, server_port: int) -> @pytest.mark.wifi_high_traffic -@idf_parametrize('target', ['esp32c6'], indirect=['target']) +@idf_parametrize('target', ['supported_targets'], indirect=['target']) def test_examples_tee_secure_ota_example(dut: Dut) -> None: """ This is a positive test case, which downloads complete binary file multiple number of times. diff --git a/examples/security/tee/tee_secure_storage/README.md b/examples/security/tee/tee_secure_storage/README.md index 0b3255d0c6..f44ed6dd82 100644 --- a/examples/security/tee/tee_secure_storage/README.md +++ b/examples/security/tee/tee_secure_storage/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C6 | -| ----------------- | -------- | +| Supported Targets | ESP32-C6 | ESP32-C61 | +| ----------------- | -------- | --------- | # TEE: Secure Storage example @@ -31,22 +31,37 @@ Open the project configuration menu (`idf.py menuconfig`). - Configure the secure storage example key ID at `Example Configuration → TEE: Secure Storage Key ID`. -TEE Secure Storage follows the NVS partition format and uses an AES-XTS encryption scheme derived via the HMAC peripheral. It supports two key derivation modes, configurable via `CONFIG_SECURE_TEE_SEC_STG_MODE`: +TEE Secure Storage follows the NVS partition format and uses an XTS-AES encryption scheme derived via the HMAC peripheral or software-based HMAC implementation. It supports two key derivation modes, configurable via `CONFIG_SECURE_TEE_SEC_STG_MODE`: - **Development** Mode: Encryption keys are embedded in the ESP-TEE firmware (identical across all instances). - - **Release** Mode: Encryption keys are derived via the HMAC peripheral using a key stored in eFuse, specified by `CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID`. + - **Release** Mode: Encryption keys are derived using a key stored in eFuse, specified by `CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID`. -#### Configure the eFuse key ID storing the HMAC key +#### Configure the eFuse key ID for storage encryption - Navigate to `ESP-TEE (Trusted Execution Environment) → Secure Services → Secure Storage: Mode` and enable the `Release` mode configuration. -- Set the eFuse key ID storing the HMAC key at `ESP-TEE (Trusted Execution Environment) → Secure Services → Secure Storage: eFuse HMAC key ID for storage encryption keys`. +- Set the eFuse key ID storing the HMAC/USER key at `ESP-TEE (Trusted Execution Environment) → Secure Services → Secure Storage: eFuse HMAC key ID for storage encryption keys`. -**Note:** Before running the example, users must program the HMAC key into the configured eFuse block - refer to the snippet below. The TEE checks whether the specified eFuse block is empty or already programmed with a key. If the block is empty, an error will be returned; otherwise, the pre-programmed key will be used. +**Note:** Before running the example, users must program the required key into the configured eFuse block - refer to the snippet below. The TEE checks whether the specified eFuse block is empty or already programmed with a key. If the block is empty, an error will be returned; otherwise, the pre-programmed key will be used. + +**For targets without HMAC peripheral (ESP32-C61):** + +```shell +# Generate a random 32-byte key +openssl rand -out hmac_key_file.bin 32 +# Program the USER purpose key (256-bit) in eFuse +# Here, BLOCK_KEYx is a free eFuse key-block between BLOCK_KEY0 and BLOCK_KEY5 +espefuse -p PORT burn-key --no-read-protect BLOCK_KEYx hmac_key_file.bin USER +``` + +> [!IMPORTANT] +> When programming the key into eFuse for targets without HMAC peripheral, ensure that it is **NOT** marked as read-protected (use the `--no-read-protect` flag). If the key is read-protected, the TEE will be unable to access it. However, this does not weaken security: the APM peripheral already blocks software access to the key, and any illegal read or write attempt from the REE triggers a fault. + +**For targets with HMAC peripheral:** ```shell # Generate a random 32-byte HMAC key openssl rand -out hmac_key_file.bin 32 -# Programming the HMAC key (256-bit) in eFuse +# Program the HMAC key (256-bit) in eFuse # Here, BLOCK_KEYx is a free eFuse key-block between BLOCK_KEY0 and BLOCK_KEY5 espefuse -p PORT burn-key BLOCK_KEYx hmac_key_file.bin HMAC_UP ``` diff --git a/examples/security/tee/tee_secure_storage/pytest_tee_secure_storage.py b/examples/security/tee/tee_secure_storage/pytest_tee_secure_storage.py index 3e6c4c34ae..5fa0107ab6 100644 --- a/examples/security/tee/tee_secure_storage/pytest_tee_secure_storage.py +++ b/examples/security/tee/tee_secure_storage/pytest_tee_secure_storage.py @@ -6,7 +6,7 @@ from pytest_embedded_idf.utils import idf_parametrize @pytest.mark.generic -@idf_parametrize('target', ['esp32c6'], indirect=['target']) +@idf_parametrize('target', ['supported_targets'], indirect=['target']) def test_example_tee_secure_storage(dut: Dut) -> None: # Start test dut.expect('TEE Secure Storage', timeout=30)