diff --git a/components/esp_tee/scripts/esp_tee_sec_stg_keygen/README.md b/components/esp_tee/scripts/esp_tee_sec_stg_keygen/README.md index 3e949fab7b2..9bb50b6a1ff 100644 --- a/components/esp_tee/scripts/esp_tee_sec_stg_keygen/README.md +++ b/components/esp_tee/scripts/esp_tee_sec_stg_keygen/README.md @@ -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 diff --git a/components/esp_tee/scripts/esp_tee_sec_stg_keygen/esp_tee_sec_stg_keygen.py b/components/esp_tee/scripts/esp_tee_sec_stg_keygen/esp_tee_sec_stg_keygen.py index 49b3836a437..87781547572 100644 --- a/components/esp_tee/scripts/esp_tee_sec_stg_keygen/esp_tee_sec_stg_keygen.py +++ b/components/esp_tee/scripts/esp_tee_sec_stg_keygen/esp_tee_sec_stg_keygen.py @@ -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) diff --git a/components/esp_tee/subproject/components/attestation/esp_att_utils_crypto.c b/components/esp_tee/subproject/components/attestation/esp_att_utils_crypto.c index 6ac7557f2ab..7a5bd54f1ec 100644 --- a/components/esp_tee/subproject/components/attestation/esp_att_utils_crypto.c +++ b/components/esp_tee/subproject/components/attestation/esp_att_utils_crypto.c @@ -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); diff --git a/components/esp_tee/subproject/components/tee_sec_storage/include/esp_tee_sec_storage.h b/components/esp_tee/subproject/components/tee_sec_storage/include/esp_tee_sec_storage.h index b801289a486..61d6ea9a3f3 100644 --- a/components/esp_tee/subproject/components/tee_sec_storage/include/esp_tee_sec_storage.h +++ b/components/esp_tee/subproject/components/tee_sec_storage/include/esp_tee_sec_storage.h @@ -16,6 +16,8 @@ extern "C" { #include "esp_err.h" #include "esp_bit_defs.h" +#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 @@ -25,6 +27,7 @@ extern "C" { #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 /** diff --git a/components/esp_tee/subproject/components/tee_sec_storage/tee_sec_storage.c b/components/esp_tee/subproject/components/tee_sec_storage/tee_sec_storage.c index 8dfe49cd39c..f4b61fe1800 100644 --- a/components/esp_tee/subproject/components/tee_sec_storage/tee_sec_storage.c +++ b/components/esp_tee/subproject/components/tee_sec_storage/tee_sec_storage.c @@ -287,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) 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 b56b0c7c28c..2a335938407 100644 --- a/components/esp_tee/subproject/main/core/esp_secure_services.c +++ b/components/esp_tee/subproject/main/core/esp_secure_services.c @@ -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); } diff --git a/components/esp_tee/subproject/main/core/esp_secure_services_iram.c b/components/esp_tee/subproject/main/core/esp_secure_services_iram.c index d4350fe77e7..cf7d56e98b6 100644 --- a/components/esp_tee/subproject/main/core/esp_secure_services_iram.c +++ b/components/esp_tee/subproject/main/core/esp_secure_services_iram.c @@ -195,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); } diff --git a/components/esp_tee/test_apps/tee_cli_app/main/tee_srv_sec_str.c b/components/esp_tee/test_apps/tee_cli_app/main/tee_srv_sec_str.c index 7aaa2edeb13..de49b5ff24b 100644 --- a/components/esp_tee/test_apps/tee_cli_app/main/tee_srv_sec_str.c +++ b/components/esp_tee/test_apps/tee_cli_app/main/tee_srv_sec_str.c @@ -204,7 +204,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; } diff --git a/components/esp_tee/test_apps/tee_cli_app/pytest_tee_cli.py b/components/esp_tee/test_apps/tee_cli_app/pytest_tee_cli.py index 2acdcc3bf30..226bc637091 100644 --- a/components/esp_tee/test_apps/tee_cli_app/pytest_tee_cli.py +++ b/components/esp_tee/test_apps/tee_cli_app/pytest_tee_cli.py @@ -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 @@ -135,10 +135,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) diff --git a/components/esp_tee/test_apps/tee_cli_app/sdkconfig.ci.minimal_tee b/components/esp_tee/test_apps/tee_cli_app/sdkconfig.ci.minimal_tee index eb2f53d45c5..2cff4b58aa5 100644 --- a/components/esp_tee/test_apps/tee_cli_app/sdkconfig.ci.minimal_tee +++ b/components/esp_tee/test_apps/tee_cli_app/sdkconfig.ci.minimal_tee @@ -5,8 +5,8 @@ CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID=5 # Reducing TEE I/DRAM sizes # 24KB CONFIG_SECURE_TEE_IRAM_SIZE=0x6000 -# 16KB -CONFIG_SECURE_TEE_DRAM_SIZE=0x4000 +# 17KB +CONFIG_SECURE_TEE_DRAM_SIZE=0x4400 # Disable TEE logs (also disable all panic logs) CONFIG_SECURE_TEE_DEBUG_MODE=n diff --git a/components/esp_tee/test_apps/tee_cli_app/sdkconfig.ci.release b/components/esp_tee/test_apps/tee_cli_app/sdkconfig.ci.release index f4c39acfebb..b6b8fd811d3 100644 --- a/components/esp_tee/test_apps/tee_cli_app/sdkconfig.ci.release +++ b/components/esp_tee/test_apps/tee_cli_app/sdkconfig.ci.release @@ -2,8 +2,8 @@ # builds across various configurations - and is not intended for production use. # Reducing TEE IRAM size -# 30KB -CONFIG_SECURE_TEE_IRAM_SIZE=0x7800 +# 31KB +CONFIG_SECURE_TEE_IRAM_SIZE=0x7C00 # TEE Secure Storage: Release mode CONFIG_SECURE_TEE_SEC_STG_MODE_RELEASE=y diff --git a/components/esp_tee/test_apps/tee_test_fw/conftest.py b/components/esp_tee/test_apps/tee_test_fw/conftest.py index b025bc4db43..585c739e042 100644 --- a/components/esp_tee/test_apps/tee_test_fw/conftest.py +++ b/components/esp_tee/test_apps/tee_test_fw/conftest.py @@ -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 ] diff --git a/components/esp_tee/test_apps/tee_test_fw/main/test_esp_tee_sec_stg.c b/components/esp_tee/test_apps/tee_test_fw/main/test_esp_tee_sec_stg.c index c5ea5f79781..55dd7ff4b7e 100644 --- a/components/esp_tee/test_apps/tee_test_fw/main/test_esp_tee_sec_stg.c +++ b/components/esp_tee/test_apps/tee_test_fw/main/test_esp_tee_sec_stg.c @@ -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 diff --git a/docs/en/security/tee/tee-attestation.rst b/docs/en/security/tee/tee-attestation.rst index 2d45bcf9a18..02cca2b9125 100644 --- a/docs/en/security/tee/tee-attestation.rst +++ b/docs/en/security/tee/tee-attestation.rst @@ -14,6 +14,10 @@ To ensure security, the EAT is cryptographically protected. The remote relying p - Support for Attestation can be toggled using the option :ref:`CONFIG_SECURE_TEE_ATTESTATION` (enabled by default). + - The attestation signing key (identified by :ref:`CONFIG_SECURE_TEE_ATT_KEY_STR_ID`) is owned exclusively by the TEE. When the TEE generates this key, it is marked with the ``SEC_STORAGE_FLAG_TEE_ONLY`` flag, and the REE is denied any access to it through the secure service interface - it cannot use the key for signing, regenerate it, or clear it. This ensures that the attestation evidence can only ever be signed from within the TEE. + + - In addition, the reserved key ID is treated as TEE-owned even before the key exists, which prevents the REE from "squatting" the ID with a key of its own before the TEE provisions it. If the key is pre-provisioned as part of an NVS image (see :doc:`Secure Storage `), it **must** be generated with the ``--tee-only`` flag of the :component_file:`esp_tee_sec_stg_keygen.py` tool. + Attestation Flow ---------------- 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 aebdf0e1c2b..e24433cf933 100644 --- a/examples/security/tee/tee_secure_storage/main/tee_main.c +++ b/examples/security/tee/tee_secure_storage/main/tee_main.c @@ -93,7 +93,7 @@ static void example_tee_sec_stg_sign_verify(void *pvParameter) esp_err_t 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; } @@ -186,7 +186,7 @@ static void example_tee_sec_stg_encrypt_decrypt(void *pvParameter) 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; }