Merge branch 'fix/fix_esp_tee_iv_length_check_v6.0' into 'release/v6.0'

feat(esp_tee): ESP-TEE Security Audit fixes (v6.0)

See merge request espressif/esp-idf!50851
This commit is contained in:
Jiang Jiang Jian
2026-07-22 10:37:48 +08:00
20 changed files with 261 additions and 62 deletions
@@ -426,8 +426,8 @@ void bootloader_munmap(const void *mapping)
mmu_hal_unmap_all();
#else
cache_hal_suspend(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
mmu_hal_unmap_region(0, FLASH_MMAP_VADDR, current_mapped_size);
cache_hal_invalidate_addr(FLASH_MMAP_VADDR, current_mapped_size);
mmu_hal_unmap_region(0, FLASH_MMAP_VADDR, current_mapped_size);
cache_hal_resume(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
#endif
#endif
+1 -1
View File
@@ -9,7 +9,7 @@ idf_build_get_property(target IDF_TARGET)
# ESP-TEE is currently supported only on the ESP32-C6, H2, C5 and C61 SoCs
set(SUPPORTED_TARGETS "esp32c6" "esp32h2" "esp32c5" "esp32c61")
if(NOT target IN_LIST SUPPORTED_TARGETS)
message(STATUS "ESP-TEE is currently supported only on the ${SUPPORTED_TARGETS} SoCs")
# ESP-TEE Kconfig is gated on the supported targets; nothing to register elsewhere.
return()
endif()
@@ -57,6 +57,14 @@ extern "C" {
#error "CONFIG_SECURE_TEE_DROM_SIZE must be a multiple of SOC_MMU_PAGE_SIZE"
#endif
/* With HAL assertions disabled (level 0), a failed HAL_ASSERT() expands to
* __builtin_unreachable(): the compiler then optimizes assuming the asserted
* preconditions always hold, turning any unvalidated HAL input into undefined
* behavior. The TEE must never be built this way. */
#if CONFIG_SECURE_ENABLE_TEE && (CONFIG_HAL_DEFAULT_ASSERTION_LEVEL < 1)
#error "ESP-TEE requires HAL assertions (CONFIG_HAL_DEFAULT_ASSERTION_LEVEL >= 1)"
#endif
/* TEE Secure Storage partition label and NVS namespace */
#define ESP_TEE_SEC_STG_PART_LABEL "secure_storage"
#define ESP_TEE_SEC_STG_NVS_NAMESPACE "tee_sec_stg_ns"
@@ -18,6 +18,8 @@ options:
-o, --output OUTPUT output binary file name
-i, --input INPUT input key file (.pem for ecdsa, .bin for aes)
--write-once make key persistent - cannot be modified or deleted once written
--tee-only mark key as owned exclusively by the TEE - the REE cannot use, generate or clear it
-h, --help Show this message and exit
```
### ECDSA Keys
@@ -31,7 +33,7 @@ python esp_tee_sec_stg_keygen.py -k ecdsa_p384 -o ecdsa_p384_k0.bin
```bash
openssl ecparam -name prime256v1 -genkey -noout -out ecdsa_p256.pem
python esp_tee_sec_stg_keygen.py -k ecdsa_p256 -o ecdsa_p256_k1.bin -i ecdsa_p256.pem --write-once
python esp_tee_sec_stg_keygen.py -k ecdsa_p256 -o ecdsa_p256_k1.bin -i ecdsa_p256.pem --write-once --tee-only
```
### AES-256 Key
@@ -31,6 +31,7 @@ class KeyType(Enum):
class Flags(IntFlag):
NONE = 0x00000000
WRITE_ONCE = 0x00000001
TEE_ONLY = 0x00000002
# === Key Generators ===
@@ -112,6 +113,11 @@ def parse_args() -> argparse.Namespace:
action='store_true',
help='make key persistent - cannot be modified or deleted once written',
)
parser.add_argument(
'--tee-only',
action='store_true',
help='mark key as owned exclusively by the TEE - the REE cannot use, generate or clear it',
)
return parser.parse_args()
@@ -122,12 +128,16 @@ def main() -> None:
flags = Flags.NONE
if args.write_once:
flags |= Flags.WRITE_ONCE
if args.tee_only:
flags |= Flags.TEE_ONLY
print(f'[+] Generating key of type: {key_type.name} (value: {key_type.value})')
if args.input:
print(f'[+] Using user-provided key file: {args.input}')
if args.write_once:
print('[+] WRITE_ONCE flag is set')
if args.tee_only:
print('[+] TEE_ONLY flag is set')
key_data = generate_key_data(key_type, flags, args.input)
@@ -42,6 +42,8 @@ static esp_err_t gen_ecdsa_keypair_secp256r1(esp_att_ecdsa_keypair_t *keypair)
esp_tee_sec_storage_key_cfg_t key_cfg = {
.id = (const char *)(ESP_ATT_TK_KEY_ID),
.type = ESP_SEC_STG_KEY_ECDSA_SECP256R1,
/* The attestation key must never be usable from the REE */
.flags = SEC_STORAGE_FLAG_TEE_ONLY,
};
esp_err_t err = esp_tee_sec_storage_gen_key(&key_cfg);
@@ -16,15 +16,18 @@ extern "C" {
#include "esp_err.h"
#include "esp_bit_defs.h"
#if SOC_ECDSA_SUPPORT_CURVE_P384
#include "sdkconfig.h"
#if CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP384R1_SIGN
#define MAX_ECDSA_SUPPORTED_KEY_LEN 48 /*!< Maximum supported size for the ECDSA key (SECP384R1) */
#else
#define MAX_ECDSA_SUPPORTED_KEY_LEN 32 /*!< Maximum supported size for the ECDSA key (SECP256R1) */
#endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */
#endif /* CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP384R1_SIGN */
#define MAX_AES_SUPPORTED_KEY_LEN 32 /*!< Maximum supported size for the AES key */
#define SEC_STORAGE_FLAG_NONE 0 /*!< No flags */
#define SEC_STORAGE_FLAG_WRITE_ONCE BIT(0) /*!< Data can only be written once */
#define SEC_STORAGE_FLAG_TEE_ONLY BIT(1) /*!< Key is owned exclusively by the TEE */
/**
* @brief Enum to represent the type of key stored in the secure storage
@@ -97,6 +100,21 @@ typedef struct {
* @return esp_err_t ESP_OK on success, appropriate error code otherwise.
*/
esp_err_t esp_tee_sec_storage_init(void);
/**
* @brief Check whether a key ID is owned exclusively by the TEE
*
* A key is TEE-owned if either:
* - it refers to the reserved TEE attestation key
* (`CONFIG_SECURE_TEE_ATT_KEY_STR_ID`); this also blocks the REE from
* "squatting" the ID before the TEE creates the key, or
* - the stored key carries the ::SEC_STORAGE_FLAG_TEE_ONLY flag.
*
* @param key_id NULL-terminated key identifier string (may be NULL)
*
* @return true if the key is TEE-owned (REE access must be denied), false otherwise
*/
bool esp_tee_sec_storage_is_key_tee_owned(const char *key_id);
#endif
/**
@@ -145,11 +163,13 @@ esp_err_t esp_tee_sec_storage_ecdsa_get_pubkey(const esp_tee_sec_storage_key_cfg
*
* @param[in] ctx Pointer to the AEAD operation context
* @param[out] iv Pointer to the output buffer for the generated initialization vector
* @param[in] iv_len Length of the initialization vector buffer
* @param[in] iv_len Length of the initialization vector buffer; must be exactly 12 bytes (96-bit IV, per NIST SP 800-38D)
* @param[out] tag Pointer to the authentication tag buffer
* @param[in] tag_len Length of the authentication tag
* @param[in] tag_len Length of the authentication tag; must be 12 to 16 bytes (96- to 128-bit tag, per NIST SP 800-38D)
* @param[out] output Pointer to the output data buffer
*
* @note Non-standard @p iv_len / @p tag_len values are rejected with ESP_ERR_INVALID_SIZE.
*
* @return esp_err_t ESP_OK on success, appropriate error code otherwise.
*/
esp_err_t esp_tee_sec_storage_aead_encrypt(const esp_tee_sec_storage_aead_ctx_t *ctx, uint8_t *iv, size_t iv_len, uint8_t *tag, size_t tag_len, uint8_t *output);
@@ -159,11 +179,13 @@ esp_err_t esp_tee_sec_storage_aead_encrypt(const esp_tee_sec_storage_aead_ctx_t
*
* @param[in] ctx Pointer to the AEAD operation context
* @param[in] iv Pointer to the initialization vector used during encryption
* @param[in] iv_len Length of the initialization vector
* @param[in] iv_len Length of the initialization vector; must be exactly 12 bytes (96-bit IV, per NIST SP 800-38D)
* @param[in] tag Pointer to the authentication tag buffer
* @param[in] tag_len Length of the authentication tag
* @param[in] tag_len Length of the authentication tag; must be 12 to 16 bytes (96- to 128-bit tag, per NIST SP 800-38D)
* @param[out] output Pointer to the output data buffer
*
* @note Non-standard @p iv_len / @p tag_len values are rejected with ESP_ERR_INVALID_SIZE.
*
* @return esp_err_t ESP_OK on success, appropriate error code otherwise.
*/
esp_err_t esp_tee_sec_storage_aead_decrypt(const esp_tee_sec_storage_aead_ctx_t *ctx, const uint8_t *iv, size_t iv_len, const uint8_t *tag, size_t tag_len, uint8_t *output);
@@ -37,6 +37,8 @@
#define AES256_KEY_LEN 32
#define AES256_KEY_BITS (AES256_KEY_LEN * 8)
#define AES256_GCM_IV_LEN 12
#define AES256_GCM_TAG_LEN_MIN 12 /* NIST SP800-38D general-use minimum (96-bit tag) */
#define AES256_GCM_TAG_LEN_MAX 16 /* full GCM tag (128-bit) */
#define ECDSA_SECP384R1_KEY_LEN 48
#define ECDSA_SECP256R1_KEY_LEN 32
@@ -285,6 +287,29 @@ static esp_err_t secure_storage_read(const char *key_id, void *data, size_t *len
return nvs_get_blob(tee_nvs_hdl, key_id, data, len);
}
bool esp_tee_sec_storage_is_key_tee_owned(const char *key_id)
{
if (key_id == NULL) {
return false;
}
bool is_att_key = false, is_tee_only = false;
esp_err_t err = ESP_FAIL;
#if CONFIG_SECURE_TEE_ATTESTATION
is_att_key = (strncmp(key_id, CONFIG_SECURE_TEE_ATT_KEY_STR_ID, NVS_KEY_NAME_MAX_SIZE) == 0);
#endif
sec_stg_key_t keyctx = {};
size_t keyctx_len = sizeof(keyctx);
err = secure_storage_read(key_id, (void *)&keyctx, &keyctx_len);
is_tee_only = (err == ESP_OK) && ((keyctx.flags & SEC_STORAGE_FLAG_TEE_ONLY) != 0);
mbedtls_platform_zeroize(&keyctx, sizeof(keyctx));
return (is_att_key || is_tee_only);
}
/* ---------------------------------------------- Interface APIs ------------------------------------------------- */
esp_err_t esp_tee_sec_storage_init(void)
@@ -658,8 +683,16 @@ static esp_err_t tee_sec_storage_crypt_common(const char *key_id, const uint8_t
return ESP_ERR_INVALID_ARG;
}
if (len == 0 || tag_len == 0 || iv_len == 0) {
ESP_LOGE(TAG, "Invalid input/tag/iv length");
if (len == 0) {
ESP_LOGE(TAG, "Invalid input length");
return ESP_ERR_INVALID_SIZE;
}
/* Enforce standard AES-GCM parameters */
if (iv_len != AES256_GCM_IV_LEN ||
tag_len < AES256_GCM_TAG_LEN_MIN || tag_len > AES256_GCM_TAG_LEN_MAX) {
ESP_LOGE(TAG, "Non-standard GCM iv_len(%u)/tag_len(%u) rejected",
(unsigned)iv_len, (unsigned)tag_len);
return ESP_ERR_INVALID_SIZE;
}
@@ -6,6 +6,7 @@
#include <assert.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "esp_rom_tlsf.h"
#include "esp_rom_sys.h"
#include "tlsf_block_functions.h"
@@ -63,6 +64,9 @@ esp_err_t esp_tee_heap_init(void *start_ptr, size_t size)
return ESP_ERR_INVALID_SIZE;
}
/* Zeroize the entire region before registering it as the TEE heap*/
memset(start_ptr, 0, size);
#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
void *heap = tlsf_create_with_pool(start_ptr + sizeof(heap_t), usable_size);
size_t overhead = tlsf_size();
@@ -227,7 +231,7 @@ void esp_tee_heap_dump_info(void)
/* Definitions for functions from the heap component, used in files shared with ESP-IDF */
void *heap_caps_malloc(size_t alignment, size_t size, uint32_t caps)
void *heap_caps_malloc(size_t size, uint32_t caps)
{
(void) caps;
return esp_tee_heap_malloc(size);
@@ -592,17 +592,24 @@ int _ss_esp_tee_ota_end(void)
*/
esp_err_t _ss_esp_tee_sec_storage_clear_key(const char *key_id)
{
bool valid_arg = !esp_tee_sec_storage_is_key_tee_owned(key_id);
if (!valid_arg) {
return ESP_ERR_INVALID_ARG;
}
ESP_FAULT_ASSERT(valid_arg);
return esp_tee_sec_storage_clear_key(key_id);
}
esp_err_t _ss_esp_tee_sec_storage_gen_key(const esp_tee_sec_storage_key_cfg_t *cfg)
{
bool valid_addr = esp_tee_buf_in_ree(cfg, sizeof(esp_tee_sec_storage_key_cfg_t));
if (!valid_addr) {
bool valid_arg = esp_tee_buf_in_ree(cfg, sizeof(esp_tee_sec_storage_key_cfg_t)) &&
!(cfg->flags & SEC_STORAGE_FLAG_TEE_ONLY) &&
!esp_tee_sec_storage_is_key_tee_owned(cfg->id);
if (!valid_arg) {
return ESP_ERR_INVALID_ARG;
}
ESP_FAULT_ASSERT(valid_addr);
ESP_FAULT_ASSERT(valid_arg);
return esp_tee_sec_storage_gen_key(cfg);
}
@@ -8,6 +8,7 @@
#include "esp_err.h"
#include "esp_log.h"
#include "esp_macros.h"
#include "esp_fault.h"
#include "hal/mmu_types.h"
@@ -38,6 +39,9 @@
static __attribute__((unused)) const char *TAG = "esp_tee_sec_srv_iram";
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
#define ALIGN_DOWN(num, align) ((num) & ~((align) - 1))
/* ---------------------------------------------- Interrupts ------------------------------------------------- */
#if SOC_INT_CLIC_SUPPORTED
@@ -191,67 +195,69 @@ void _ss_wdt_hal_deinit(wdt_hal_context_t *hal)
*/
esp_err_t _ss_esp_tee_sec_storage_ecdsa_sign(const esp_tee_sec_storage_key_cfg_t *cfg, const uint8_t *hash, size_t hlen, esp_tee_sec_storage_ecdsa_sign_t *out_sign)
{
bool valid_addr = (esp_tee_buf_in_ree(cfg, sizeof(esp_tee_sec_storage_key_cfg_t)) &&
esp_tee_buf_in_ree(hash, hlen) &&
esp_tee_buf_in_ree(out_sign, sizeof(esp_tee_sec_storage_ecdsa_sign_t)));
if (!valid_addr) {
bool valid_arg = (esp_tee_buf_in_ree(cfg, sizeof(esp_tee_sec_storage_key_cfg_t)) &&
esp_tee_buf_in_ree(hash, hlen) &&
esp_tee_buf_in_ree(out_sign, sizeof(esp_tee_sec_storage_ecdsa_sign_t)) &&
!esp_tee_sec_storage_is_key_tee_owned(cfg->id));
if (!valid_arg) {
return ESP_ERR_INVALID_ARG;
}
ESP_FAULT_ASSERT(valid_addr);
ESP_FAULT_ASSERT(valid_arg);
return esp_tee_sec_storage_ecdsa_sign(cfg, hash, hlen, out_sign);
}
esp_err_t _ss_esp_tee_sec_storage_ecdsa_get_pubkey(const esp_tee_sec_storage_key_cfg_t *cfg, esp_tee_sec_storage_ecdsa_pubkey_t *out_pubkey)
{
bool valid_addr = (esp_tee_buf_in_ree(cfg, sizeof(esp_tee_sec_storage_key_cfg_t)) &&
esp_tee_buf_in_ree(out_pubkey, sizeof(esp_tee_sec_storage_ecdsa_pubkey_t)));
if (!valid_addr) {
bool valid_arg = (esp_tee_buf_in_ree(cfg, sizeof(esp_tee_sec_storage_key_cfg_t)) &&
esp_tee_buf_in_ree(out_pubkey, sizeof(esp_tee_sec_storage_ecdsa_pubkey_t)) &&
!esp_tee_sec_storage_is_key_tee_owned(cfg->id));
if (!valid_arg) {
return ESP_ERR_INVALID_ARG;
}
ESP_FAULT_ASSERT(valid_addr);
ESP_FAULT_ASSERT(valid_arg);
return esp_tee_sec_storage_ecdsa_get_pubkey(cfg, out_pubkey);
}
esp_err_t _ss_esp_tee_sec_storage_aead_encrypt(const esp_tee_sec_storage_aead_ctx_t *ctx, uint8_t *iv, size_t iv_len, uint8_t *tag, size_t tag_len, uint8_t *output)
{
bool valid_addr = (esp_tee_buf_in_ree(ctx, sizeof(esp_tee_sec_storage_aead_ctx_t)) &&
esp_tee_buf_in_ree(ctx->input, ctx->input_len) &&
esp_tee_buf_in_ree(iv, iv_len) &&
esp_tee_buf_in_ree(tag, tag_len) &&
esp_tee_buf_in_ree(output, ctx->input_len));
bool valid_arg = (esp_tee_buf_in_ree(ctx, sizeof(esp_tee_sec_storage_aead_ctx_t)) &&
esp_tee_buf_in_ree(ctx->input, ctx->input_len) &&
esp_tee_buf_in_ree(iv, iv_len) &&
esp_tee_buf_in_ree(tag, tag_len) &&
esp_tee_buf_in_ree(output, ctx->input_len) &&
!esp_tee_sec_storage_is_key_tee_owned(ctx->key_id));
if (ctx->aad_len != 0) {
valid_addr &= esp_tee_buf_in_ree(ctx->aad, ctx->aad_len);
valid_arg &= esp_tee_buf_in_ree(ctx->aad, ctx->aad_len);
}
if (!valid_addr) {
if (!valid_arg) {
return ESP_ERR_INVALID_ARG;
}
ESP_FAULT_ASSERT(valid_addr);
ESP_FAULT_ASSERT(valid_arg);
return esp_tee_sec_storage_aead_encrypt(ctx, iv, iv_len, tag, tag_len, output);
}
esp_err_t _ss_esp_tee_sec_storage_aead_decrypt(const esp_tee_sec_storage_aead_ctx_t *ctx, const uint8_t *iv, size_t iv_len, const uint8_t *tag, size_t tag_len, uint8_t *output)
{
bool valid_addr = (esp_tee_buf_in_ree(ctx, sizeof(esp_tee_sec_storage_aead_ctx_t)) &&
esp_tee_buf_in_ree(ctx->input, ctx->input_len) &&
esp_tee_buf_in_ree(iv, iv_len) &&
esp_tee_buf_in_ree(tag, tag_len) &&
esp_tee_buf_in_ree(output, ctx->input_len));
bool valid_arg = (esp_tee_buf_in_ree(ctx, sizeof(esp_tee_sec_storage_aead_ctx_t)) &&
esp_tee_buf_in_ree(ctx->input, ctx->input_len) &&
esp_tee_buf_in_ree(iv, iv_len) &&
esp_tee_buf_in_ree(tag, tag_len) &&
esp_tee_buf_in_ree(output, ctx->input_len) &&
!esp_tee_sec_storage_is_key_tee_owned(ctx->key_id));
if (ctx->aad_len != 0) {
valid_addr &= esp_tee_buf_in_ree(ctx->aad, ctx->aad_len);
valid_arg &= esp_tee_buf_in_ree(ctx->aad, ctx->aad_len);
}
if (!valid_addr) {
if (!valid_arg) {
return ESP_ERR_INVALID_ARG;
}
ESP_FAULT_ASSERT(valid_addr);
ESP_FAULT_ASSERT(valid_arg);
return esp_tee_sec_storage_aead_decrypt(ctx, iv, iv_len, tag, tag_len, output);
}
@@ -274,11 +280,32 @@ esp_err_t _ss_esp_tee_sec_storage_ecdsa_sign_pbkdf2(const esp_tee_sec_storage_pb
/* ---------------------------------------------- MMU HAL ------------------------------------------------- */
static bool tee_ree_ext_vaddr_ok(uint32_t mmu_id, uint32_t vaddr, uint32_t len)
{
uint32_t page = mmu_hal_pages_to_bytes(mmu_id, 1);
uint32_t map_len = ALIGN_UP(len, page);
return (len != 0 && map_len >= len && (vaddr % page == 0) &&
mmu_hal_check_valid_ext_vaddr_region(mmu_id, vaddr, map_len,
MMU_VADDR_DATA | MMU_VADDR_INSTRUCTION) &&
!esp_tee_flash_check_vrange_in_tee_region(vaddr, map_len));
}
static bool tee_ree_ext_paddr_ok(uint32_t mmu_id, uint32_t paddr, uint32_t len)
{
uint32_t page = mmu_hal_pages_to_bytes(mmu_id, 1);
uint32_t map_len = ALIGN_UP(len, page);
return (len != 0 && map_len >= len && (paddr % page == 0) &&
mmu_hal_check_valid_paddr_region(mmu_id, paddr, map_len) &&
!esp_tee_flash_check_prange_in_tee_region(paddr, map_len));
}
void _ss_mmu_hal_map_region(uint32_t mmu_id, mmu_target_t mem_type, uint32_t vaddr,
uint32_t paddr, uint32_t len, uint32_t *out_len)
{
bool valid_addr = (!esp_tee_flash_check_vrange_in_tee_region(vaddr, len) &&
!esp_tee_flash_check_prange_in_tee_region(paddr, len) &&
bool valid_addr = (tee_ree_ext_vaddr_ok(mmu_id, vaddr, len) &&
tee_ree_ext_paddr_ok(mmu_id, paddr, len) &&
esp_tee_buf_in_ree(out_len, sizeof(uint32_t)));
if (!valid_addr) {
@@ -292,20 +319,21 @@ void _ss_mmu_hal_map_region(uint32_t mmu_id, mmu_target_t mem_type, uint32_t vad
void _ss_mmu_hal_unmap_region(uint32_t mmu_id, uint32_t vaddr, uint32_t len)
{
bool vaddr_chk = esp_tee_flash_check_vrange_in_tee_region(vaddr, len);
bool valid_addr = tee_ree_ext_vaddr_ok(mmu_id, vaddr, len);
if (vaddr_chk) {
if (!valid_addr) {
ESP_LOGD(TAG, "[%s] Illegal flash access at 0x%08x", __func__, vaddr);
return;
}
ESP_FAULT_ASSERT(!vaddr_chk);
ESP_FAULT_ASSERT(valid_addr);
mmu_hal_unmap_region(mmu_id, vaddr, len);
}
bool _ss_mmu_hal_vaddr_to_paddr(uint32_t mmu_id, uint32_t vaddr, uint32_t *out_paddr, mmu_target_t *out_target)
{
bool valid_addr = (!esp_tee_flash_check_vaddr_in_tee_region(vaddr) &&
uint32_t page = mmu_hal_pages_to_bytes(mmu_id, 1);
bool valid_addr = (tee_ree_ext_vaddr_ok(mmu_id, ALIGN_DOWN(vaddr, page), 1) &&
esp_tee_buf_in_ree(out_paddr, sizeof(uint32_t)) &&
esp_tee_buf_in_ree(out_target, sizeof(mmu_target_t)));
@@ -319,7 +347,8 @@ bool _ss_mmu_hal_vaddr_to_paddr(uint32_t mmu_id, uint32_t vaddr, uint32_t *out_p
bool _ss_mmu_hal_paddr_to_vaddr(uint32_t mmu_id, uint32_t paddr, mmu_target_t target, mmu_vaddr_t type, uint32_t *out_vaddr)
{
bool valid_addr = (!esp_tee_flash_check_paddr_in_tee_region(paddr) &&
bool valid_addr = (mmu_hal_check_valid_paddr_region(mmu_id, paddr, 1) &&
!esp_tee_flash_check_paddr_in_tee_region(paddr) &&
esp_tee_buf_in_ree(out_vaddr, sizeof(uint32_t)));
if (!valid_addr) {
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -26,6 +26,9 @@
/* TEE symbols */
extern uint32_t _tee_stack;
extern uint32_t _tee_stack_bottom;
extern uint32_t _tee_intr_stack;
extern uint32_t _tee_intr_stack_bottom;
extern uint32_t _tee_bss_start;
extern uint32_t _tee_bss_end;
extern uint32_t _tee_s_intr_handler;
@@ -119,6 +122,9 @@ void __attribute__((noreturn)) esp_tee_init(uint32_t ree_entry_addr, uint32_t re
{
/* Clear BSS */
memset(&_tee_bss_start, 0, (&_tee_bss_end - &_tee_bss_start) * sizeof(_tee_bss_start));
/* Clear the TEE stack and interrupt stack */
memset(&_tee_stack_bottom, 0, (&_tee_stack - &_tee_stack_bottom) * sizeof(_tee_stack_bottom));
memset(&_tee_intr_stack_bottom, 0, (&_tee_intr_stack - &_tee_intr_stack_bottom) * sizeof(_tee_intr_stack_bottom));
static uint32_t btld_sp;
@@ -203,7 +203,7 @@ static int tee_sec_stg_gen_key(int argc, char **argv)
err = esp_tee_sec_storage_clear_key(cfg.id);
if (err != ESP_OK && err != ESP_ERR_NOT_FOUND) {
ESP_LOGE(TAG, "Failed to clear key %d!", cfg.id);
ESP_LOGE(TAG, "Failed to clear key %s!", cfg.id);
goto exit;
}
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import hashlib
import http.server
@@ -134,10 +134,6 @@ def test_tee_cli_attestation(dut: Dut) -> None:
dut.expect('ESP-TEE: Secure services demonstration', timeout=30)
time.sleep(1)
att_key_id = dut.app.sdkconfig.get('SECURE_TEE_ATT_KEY_STR_ID')
dut.write(f'tee_sec_stg_gen_key {att_key_id} 1')
dut.expect(r'Generated ECDSA_SECP256R1 key with ID (\S+)', timeout=30)
# Get the Entity Attestation token from TEE and verify its signature
dut.write('tee_att_info')
dut.expect(r'Attestation token - Length: (\d+)', timeout=30)
@@ -418,6 +418,7 @@ class TEESerial(IdfSerial):
'type': 'ecdsa_p256',
'input': 'ecdsa_p256_key.pem',
'write_once': True,
'tee_only': True,
'b64': (
'LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlNU1VpUktHaVZjSTIvbUZFekI3eXRIOVJj'
'd0wyUThkNDhONHNFUHFYc0RvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSkYxYXRZQUxrdnB4cCt4N3c1dmVPQ1Vj'
@@ -493,6 +494,7 @@ class TEESerial(IdfSerial):
[sys.executable, ESP_TEE_SEC_STG_KEYGEN, '-k', entry['type'], '-o', str(tmp_dir / f'{entry["key"]}.bin')]
+ (['-i', entry['input']] if entry['input'] else [])
+ (['--write-once'] if entry['write_once'] else [])
+ (['--tee-only'] if entry.get('tee_only') else [])
for entry in self.KEY_DEFS
]
@@ -365,6 +365,38 @@ TEST_CASE("Test TEE Secure Storage - Null Pointer and Zero Length", "[sec_storag
TEST_ESP_OK(esp_tee_sec_storage_clear_key(key_cfg.id));
}
#if CONFIG_SECURE_TEE_ATTESTATION
TEST_CASE("Test TEE Secure Storage - Attestation key is not REE-accessible", "[sec_storage]")
{
const char *att_key_id = CONFIG_SECURE_TEE_ATT_KEY_STR_ID;
esp_tee_sec_storage_key_cfg_t key_cfg = {
.id = att_key_id,
.type = ESP_SEC_STG_KEY_ECDSA_SECP256R1
};
uint8_t digest[SHA256_DIGEST_SZ];
esp_fill_random(digest, sizeof(digest));
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_gen_key(&key_cfg));
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_clear_key(att_key_id));
esp_tee_sec_storage_ecdsa_sign_t sign = {};
esp_tee_sec_storage_ecdsa_pubkey_t pubkey = {};
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_ecdsa_sign(&key_cfg, digest, sizeof(digest), &sign));
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_ecdsa_get_pubkey(&key_cfg, &pubkey));
uint8_t data[31], tag[12], iv[12];
esp_tee_sec_storage_aead_ctx_t aead_ctx = {
.key_id = att_key_id,
.input = data,
.input_len = sizeof(data),
};
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_aead_encrypt(&aead_ctx, iv, sizeof(iv), tag, sizeof(tag), data));
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_aead_decrypt(&aead_ctx, iv, sizeof(iv), tag, sizeof(tag), data));
}
#endif
TEST_CASE("Test TEE Secure Storage - Verify data encryption", "[sec_storage_encr]")
{
ESP_LOGI(TAG, "Populating NVS-based TEE Secure Storage; encrypted with XTS-AES-512");
@@ -423,6 +455,22 @@ TEST_CASE("Test TEE Secure Storage - WRITE_ONCE keys", "[sec_storage]")
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, esp_tee_sec_storage_clear_key(key_cfg.id));
}
TEST_CASE("Test TEE Secure Storage - TEE_ONLY keys", "[sec_storage]")
{
const char *key_id = "key_id_tee_only";
esp_tee_sec_storage_key_cfg_t key_cfg = {
.id = key_id,
.type = ESP_SEC_STG_KEY_ECDSA_SECP256R1,
.flags = SEC_STORAGE_FLAG_TEE_ONLY,
};
esp_err_t err = esp_tee_sec_storage_clear_key(key_cfg.id);
TEST_ASSERT_TRUE(err == ESP_OK || err == ESP_ERR_NOT_FOUND);
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_gen_key(&key_cfg));
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, esp_tee_sec_storage_clear_key(key_cfg.id));
}
static void test_aead_encrypt_decrypt(const char *key_id, const uint8_t *input, size_t len)
{
uint8_t *ciphertext = heap_caps_malloc(len, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
@@ -524,10 +572,19 @@ TEST_CASE("Test TEE Secure Storage - Host-generated keys", "[sec_storage_host_ke
size_t token_len = 0;
TEST_ESP_OK(psa_initial_attest_get_token(auth_challenge, challenge_size, token_buf, token_buf_size, &token_len));
free(token_buf);
const char *attest_key_id = "attest_key";
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, esp_tee_sec_storage_clear_key(attest_key_id));
#endif /* CONFIG_SECURE_TEE_ATTESTATION */
const char *attest_key_id = "attest_key";
esp_tee_sec_storage_key_cfg_t attest_cfg = {
.id = attest_key_id,
.type = ESP_SEC_STG_KEY_ECDSA_SECP256R1,
};
esp_tee_sec_storage_ecdsa_sign_t attest_sign = {0};
esp_tee_sec_storage_ecdsa_pubkey_t attest_pubkey = {0};
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_ecdsa_sign(&attest_cfg, digest_buf, SHA256_DIGEST_SZ, &attest_sign));
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_ecdsa_get_pubkey(&attest_cfg, &attest_pubkey));
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_clear_key(attest_key_id));
}
#if CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN
+12
View File
@@ -149,6 +149,18 @@ bool mmu_hal_paddr_to_vaddr(uint32_t mmu_id, uint32_t paddr, mmu_target_t target
*/
bool mmu_hal_check_valid_ext_vaddr_region(uint32_t mmu_id, uint32_t vaddr_start, uint32_t len, mmu_vaddr_t type);
/**
* Check if the paddr region is valid
*
* @param mmu_id MMU ID
* @param paddr_start start of the physical address
* @param len length, in bytes
*
* @return
* True for valid
*/
bool mmu_hal_check_valid_paddr_region(uint32_t mmu_id, uint32_t paddr_start, uint32_t len);
#if SOC_MMU_PER_EXT_MEM_TARGET
/**
* Get MMU ID from MMU target
+5
View File
@@ -197,6 +197,11 @@ bool mmu_hal_check_valid_ext_vaddr_region(uint32_t mmu_id, uint32_t vaddr_start,
return mmu_ll_check_valid_ext_vaddr_region(mmu_id, vaddr_start, len, type);
}
bool mmu_hal_check_valid_paddr_region(uint32_t mmu_id, uint32_t paddr_start, uint32_t len)
{
return mmu_ll_check_valid_paddr_region(mmu_id, paddr_start, len);
}
#if SOC_MMU_PER_EXT_MEM_TARGET
uint32_t mmu_hal_get_id_from_target(mmu_target_t target)
{