Secure Storage
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 Non-Volatile Storage Library partition format and uses the HMAC peripheral-based XTS-AES encryption scheme, as detailed here. The AES encryption keys are derived from an HMAC key programmed in eFuse with the purpose esp_efuse_purpose_t::ESP_EFUSE_KEY_PURPOSE_HMAC_UP
. Please note that the TEE Secure storage does not support the 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.
Additionally, the secure storage provides interfaces for performing the following cryptographic services from the TEE using securely stored key material:
Message signing and public key retrieval using the
ecdsa_secp256r1
andecdsa_secp192r1
algorithmsAuthenticated encryption and decryption using the
aes256_gcm
algorithm
Note
As per the current implementation, the TEE Secure Storage partition must have the label secure_storage
.
Internals
Each data object consisting of the type, associated metadata flags (e.g., WRITE_ONCE
), and the actual payload is encapsulated in a structured format and stored as a variable-length NVS blob in the secure storage partition.
Note
As per the current implementation, all data objects in the TEE Secure Storage are to be stored in the tee_sec_stg_ns
namespace.
Currently, TEE secure storage supports storing the following cryptographic keys:
ecdsa_secp256r1
andecdsa_secp192r1
curve key-pairs, including private and public key components
aes256
keys, including the key and initialization vector (IV)
All assets related to TEE secure storage are protected by the APM peripheral and are inaccessible to the REE application. Any direct access attempts will result in a system fault. Future updates are planned to add support for additional key types and general-purpose data storage.
The TEE Secure Storage feature supports two modes for determining how the NVS encryption keys are derived (see 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 CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID.
Note
The valid range for CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID is from
0
(hmac_key_id_t::HMAC_KEY0
) to5
(hmac_key_id_t::HMAC_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 HMAC key into the required eFuse block:
# Generate a random 32-byte HMAC key openssl rand -out hmac_key_file.bin 32 # Program the HMAC key into the eFuse block idf.py -p PORT efuse-burn-key <BLOCK_KEY0-5> hmac_key_file.bin HMAC_UP
Tools
The NVS Partition Generator Utility tool can be used to generate binary images compatible with the NVS format for use with TEE Secure Storage. Since TEE Secure Storage stores data objects using a custom structured format, an additional step is required to convert input data into this format prior to image generation and encryption.
To support this process, the esp_tee_sec_stg_keygen.py script is provided for generating secure key blobs corresponding to the various supported cryptographic algorithms. These key blobs are then referenced in the input CSV file (format described here) and passed to the NVS Partition Generator utility to produce an encrypted images suitable for TEE Secure Storage.
Refer the detailed steps given here on generating key blobs and encrypted NVS partition images for TEE Secure Storage.
Application Example
The tee_secure_storage example demonstrates how to generate ECDSA key pairs and AES-256 keys in the TEE secure storage and use them for signing messages and encrypting/decrypting data.
API Reference
Note
To use the TEE Secure Storage APIs in your project, ensure that the tee_sec_storage component is listed as a local dependency in the component manager manifest file idf_component.yml. Refer to the tee_secure_storage example for guidance.
Header File
Functions
-
esp_err_t esp_tee_sec_storage_clear_key(const char *key_id)
Clear a key from secure storage.
- Parameters:
key_id -- Key identifier string
- Returns:
esp_err_t ESP_OK on success, appropriate error code otherwise.
-
esp_err_t esp_tee_sec_storage_gen_key(const esp_tee_sec_storage_key_cfg_t *cfg)
Generate a unique key and store it in the secure storage.
- Parameters:
cfg -- Pointer to the key configuration
- Returns:
esp_err_t ESP_OK on success, appropriate error code otherwise.
-
esp_err_t 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)
Generate and return the signature for the specified message digest using the key pair located in the secure storage.
- Parameters:
cfg -- [in] Pointer to the key configuration
hash -- [in] Message digest
hlen -- [in] Digest length
out_sign -- [out] Output context holding the signature
- Returns:
esp_err_t ESP_OK on success, appropriate error code otherwise.
-
esp_err_t 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)
Return the public key from secure storage.
- Parameters:
cfg -- [in] Pointer to the key configuration
out_pubkey -- [out] Output context holding the public key
- Returns:
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 *tag, size_t tag_len, uint8_t *output)
Perform encryption using AES256-GCM with the key from secure storage.
- Parameters:
ctx -- [in] Pointer to the AEAD operation context
tag -- [out] Pointer to the authentication tag buffer
tag_len -- [in] Length of the authentication tag
output -- [out] Pointer to the output data buffer
- Returns:
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 *tag, size_t tag_len, uint8_t *output)
Perform decryption using AES256-GCM with the key from secure storage.
- Parameters:
ctx -- [in] Pointer to the AEAD operation context
tag -- [in] Pointer to the authentication tag buffer
tag_len -- [in] Length of the authentication tag
output -- [out] Pointer to the output data buffer
- Returns:
esp_err_t ESP_OK on success, appropriate error code otherwise.
Structures
-
struct esp_tee_sec_storage_key_cfg_t
Configuration structure for key generation/import.
Public Members
-
const char *id
Unique identifier for the key
-
esp_tee_sec_storage_type_t type
Type of key (AES256, ECDSA_SECP256R1, etc.)
-
uint32_t flags
Key flags (e.g. WRITE_ONCE)
-
const char *id
-
struct esp_tee_sec_storage_aead_ctx_t
Context structure for AES-GCM AEAD encryption/decryption operations.
-
struct esp_tee_sec_storage_ecdsa_pubkey_t
Structure holding the X and Y components of the ECDSA public key.
-
struct esp_tee_sec_storage_ecdsa_sign_t
Structure holding the R and S components of the ECDSA signature.
Macros
-
MAX_ECDSA_SUPPORTED_KEY_LEN
Maximum supported size for the ECDSA key
-
MAX_AES_SUPPORTED_KEY_LEN
Maximum supported size for the AES key
-
SEC_STORAGE_FLAG_NONE
No flags
-
SEC_STORAGE_FLAG_WRITE_ONCE
Data can only be written once