mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-31 19:24:33 +02:00
refactor(esp_tee): Update TEE secure storage examples and test-apps
This commit is contained in:
95
components/esp_tee/scripts/esp_tee_sec_stg_keygen/README.md
Normal file
95
components/esp_tee/scripts/esp_tee_sec_stg_keygen/README.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# TEE Secure Storage: Image Generation
|
||||
|
||||
|
||||
## A. Generate Secure Key Blobs
|
||||
|
||||
### `esp_tee_sec_stg_keygen` tool
|
||||
|
||||
```
|
||||
$ python esp_tee_sec_stg_keygen.py --help
|
||||
usage: esp_tee_sec_stg_keygen.py [-h] -k {aes256,ecdsa_p256,ecdsa_p192} -o OUTPUT [-i INPUT] [--write-once]
|
||||
|
||||
Generate or import a cryptographic key structure for secure storage
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
-k, --key-type {aes256,ecdsa_p256,ecdsa_p192}
|
||||
key type to be processed
|
||||
-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
|
||||
```
|
||||
|
||||
### ECDSA Keys
|
||||
|
||||
```bash
|
||||
python esp_tee_sec_stg_keygen.py -k ecdsa_p256 -o ecdsa_p256_k0.bin
|
||||
python esp_tee_sec_stg_keygen.py -k ecdsa_p192 -o ecdsa_p192_k0.bin
|
||||
```
|
||||
|
||||
#### With custom PEM:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
### AES-256 Key
|
||||
|
||||
```bash
|
||||
python esp_tee_sec_stg_keygen.py -k aes256 -o aes256_gcm_k0.bin --write-once
|
||||
```
|
||||
|
||||
#### With custom key and IV
|
||||
|
||||
```bash
|
||||
# Generate 32 bytes AES key
|
||||
openssl rand 32 > aes_key.bin
|
||||
|
||||
# Generate 12 bytes IV (optional)
|
||||
openssl rand 12 >> aes_key.bin
|
||||
|
||||
# Generate AES key blob using custom key + IV
|
||||
python esp_tee_sec_stg_keygen.py -k aes256 -o aes256_gcm_k1.bin -i aes_key.bin
|
||||
```
|
||||
|
||||
## B. NVS Partition Image Generation
|
||||
|
||||
### Create the TEE Secure Storage CSV
|
||||
|
||||
Prepare a CSV file that defines the data to be used as input for the NVS Partition Generator utility.
|
||||
|
||||
```csv
|
||||
key,type,encoding,value
|
||||
tee_sec_stg_ns,namespace,,
|
||||
aes256_key0,file,binary,aes256_gcm_k0.bin
|
||||
p256_key0,file,binary,ecdsa_p256_k0.bin
|
||||
p192_key0,file,binary,ecdsa_p192_k0.bin
|
||||
attest_key0,file,binary,ecdsa_p256_k1.bin
|
||||
```
|
||||
> [!IMPORTANT]
|
||||
> As per the current implementation, all data objects in the TEE Secure Storage are to be stored in the `tee_sec_stg_ns` namespace.
|
||||
|
||||
### Generate NVS Encryption Keys
|
||||
|
||||
```bash
|
||||
python nvs_partition_gen.py generate-key --key_protect_hmac --kp_hmac_inputkey hmac_key.bin --keyfile nvs_keys.bin
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> `hmac_key.bin` must match the HMAC key programmed into the eFuse block specified by `CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID`.
|
||||
|
||||
### Generate encrypted NVS partition
|
||||
|
||||
```bash
|
||||
python nvs_partition_gen.py encrypt tee_sec_stg_val.csv tee_sec_stg_nvs.bin 0x8000 --inputkey nvs_keys.bin
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Replace `0x8000` with the actual size of the TEE Secure Storage partition as configured in your project's partition table.
|
||||
|
||||
## (Optional) Decrypt for Verification
|
||||
|
||||
```bash
|
||||
python nvs_partition_gen.py decrypt tee_sec_stg_nvs.bin nvs_keys.bin tee_sec_stg_nvs_decr.bin
|
||||
```
|
@@ -0,0 +1,156 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import struct
|
||||
from enum import Enum
|
||||
from enum import IntFlag
|
||||
from typing import Any
|
||||
from typing import Optional
|
||||
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import ec
|
||||
|
||||
# === Constants ===
|
||||
SEC_STG_KEY_DATA_SZ = 256
|
||||
AES_KEY_LEN = 32
|
||||
AES_DEFAULT_IV_LEN = 16
|
||||
AES_GCM_IV_LEN = 12
|
||||
ECDSA_P256_LEN = 32
|
||||
ECDSA_P192_LEN = 24
|
||||
|
||||
|
||||
# === Key Type Enum ===
|
||||
class KeyType(Enum):
|
||||
AES256 = 0
|
||||
ECDSA_P256 = 1
|
||||
ECDSA_P192 = 2
|
||||
|
||||
|
||||
# === Bitwise Flags Enum ===
|
||||
class Flags(IntFlag):
|
||||
NONE = 0x00000000
|
||||
WRITE_ONCE = 0x00000001
|
||||
|
||||
|
||||
# === Key Generators ===
|
||||
|
||||
|
||||
def generate_aes256_key(flags: Flags, key_file: Optional[str] = None) -> bytes:
|
||||
if key_file:
|
||||
with open(key_file, 'rb') as f:
|
||||
key_data = f.read()
|
||||
|
||||
if len(key_data) < AES_KEY_LEN:
|
||||
raise ValueError('AES key file must be at least 32 bytes long')
|
||||
|
||||
key = key_data[:AES_KEY_LEN]
|
||||
iv_data = key_data[AES_KEY_LEN:]
|
||||
|
||||
iv_len = len(iv_data)
|
||||
if iv_len == 0:
|
||||
iv = os.urandom(AES_DEFAULT_IV_LEN)
|
||||
elif iv_len == AES_GCM_IV_LEN:
|
||||
iv = iv_data + b'\x00' * (AES_DEFAULT_IV_LEN - AES_GCM_IV_LEN)
|
||||
elif iv_len == AES_DEFAULT_IV_LEN:
|
||||
iv = iv_data
|
||||
else:
|
||||
raise ValueError('IV length must be exactly 12 or 16 bytes, or omitted to generate one')
|
||||
else:
|
||||
key = os.urandom(AES_KEY_LEN)
|
||||
iv = os.urandom(AES_DEFAULT_IV_LEN)
|
||||
|
||||
packed = struct.pack('<II32s16s', KeyType.AES256.value, flags.value, key, iv)
|
||||
return packed + b'\x00' * (SEC_STG_KEY_DATA_SZ - len(packed))
|
||||
|
||||
|
||||
def generate_ecdsa_key(
|
||||
curve: ec.EllipticCurve, key_type_enum: KeyType, key_len: int, flags: Flags, pem_file: Optional[str] = None
|
||||
) -> bytes:
|
||||
if pem_file:
|
||||
with open(pem_file, 'rb') as f:
|
||||
private_key = serialization.load_pem_private_key(f.read(), password=None, backend=default_backend())
|
||||
if not isinstance(private_key, ec.EllipticCurvePrivateKey):
|
||||
raise ValueError('Provided PEM does not contain an EC private key')
|
||||
else:
|
||||
private_key = ec.generate_private_key(curve, default_backend())
|
||||
|
||||
priv = private_key.private_numbers().private_value.to_bytes(key_len, 'big')
|
||||
pub = private_key.public_key().public_numbers()
|
||||
x = pub.x.to_bytes(key_len, 'big')
|
||||
y = pub.y.to_bytes(key_len, 'big')
|
||||
|
||||
packed = struct.pack(f'<II{key_len}s{key_len}s{key_len}s', key_type_enum.value, flags.value, priv, x, y)
|
||||
return packed + b'\x00' * (SEC_STG_KEY_DATA_SZ - len(packed))
|
||||
|
||||
|
||||
def generate_key_data(key_type: KeyType, flags: Flags, input_file: Optional[str]) -> bytes:
|
||||
if key_type == KeyType.AES256:
|
||||
return generate_aes256_key(flags, input_file)
|
||||
elif key_type == KeyType.ECDSA_P256:
|
||||
return generate_ecdsa_key(ec.SECP256R1(), key_type, ECDSA_P256_LEN, flags, input_file)
|
||||
elif key_type == KeyType.ECDSA_P192:
|
||||
return generate_ecdsa_key(ec.SECP192R1(), key_type, ECDSA_P192_LEN, flags, input_file)
|
||||
else:
|
||||
raise ValueError(f'Unsupported key type: {key_type}')
|
||||
|
||||
|
||||
# === CLI ===
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description='Generate or import a cryptographic key structure for secure storage')
|
||||
parser.add_argument(
|
||||
'-k',
|
||||
'--key-type',
|
||||
type=str,
|
||||
choices=[e.name.lower() for e in KeyType],
|
||||
required=True,
|
||||
help='key type to be processed',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-o',
|
||||
'--output',
|
||||
required=True,
|
||||
help='output binary file name',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-i',
|
||||
'--input',
|
||||
help='input key file (.pem for ecdsa, .bin for aes)',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--write-once',
|
||||
action='store_true',
|
||||
help='make key persistent - cannot be modified or deleted once written',
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args: Any = parse_args()
|
||||
|
||||
key_type = KeyType[args.key_type.upper()]
|
||||
flags = Flags.NONE
|
||||
if args.write_once:
|
||||
flags |= Flags.WRITE_ONCE
|
||||
|
||||
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')
|
||||
|
||||
key_data = generate_key_data(key_type, flags, args.input)
|
||||
|
||||
with open(args.output, 'wb') as f:
|
||||
f.write(key_data)
|
||||
|
||||
print(f'[✓] Key written to {args.output}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@@ -78,31 +78,33 @@ get_msg_sha256 "<msg>"
|
||||
Get the SHA256 digest for the given message
|
||||
"<msg>" Message for SHA256 digest calculation
|
||||
|
||||
tee_sec_stg_gen_key <slot_id> <key_type>
|
||||
Generate and store a new key of the specified type in the given TEE secure
|
||||
storage slot
|
||||
<slot_id> TEE Secure storage slot for storing the key
|
||||
<key_type> Key type (0: ECDSA_SECP256R1, 1: AES256)
|
||||
tee_sec_stg_gen_key <key_id> <key_type>
|
||||
Generate and store a new key of the specified type with the given ID
|
||||
<key_id> TEE Secure storage key ID
|
||||
<key_type> Key type (0: AES256, 1: ECDSA_SECP256R1)
|
||||
|
||||
tee_sec_stg_sign <slot_id> <msg_sha256>
|
||||
Sign a message using the ECDSA keypair stored in the given slot ID and verify
|
||||
the signature
|
||||
<slot_id> TEE Secure storage slot storing the ecdsa-secp256r1 keypair
|
||||
tee_sec_stg_sign <key_id> <msg_sha256>
|
||||
Sign a message using the ECDSA keypair stored with the given key ID and
|
||||
verify the signature
|
||||
<key_id> TEE Secure storage key ID
|
||||
<msg_sha256> SHA256 digest of the message to be signed and verified
|
||||
|
||||
tee_sec_stg_encrypt <slot_id> <plaintext>
|
||||
Encrypt data using AES-GCM with a key from secure storage
|
||||
<slot_id> TEE Secure storage slot storing the AES key
|
||||
tee_sec_stg_encrypt <key_id> <plaintext>
|
||||
Encrypt data using AES-GCM key with the given ID from secure storage
|
||||
<key_id> TEE Secure storage key ID
|
||||
<plaintext> Plaintext to be encrypted
|
||||
|
||||
tee_sec_stg_decrypt <slot_id> <ciphertext> <tag>
|
||||
Decrypt data using AES-GCM with a key from secure storage
|
||||
<slot_id> TEE Secure storage slot storing the AES key
|
||||
tee_sec_stg_decrypt <key_id> <ciphertext> <tag>
|
||||
Decrypt data using AES-GCM key with the given ID from secure storage
|
||||
<key_id> TEE Secure storage key ID
|
||||
<ciphertext> Ciphertext to be decrypted
|
||||
<tag> AES-GCM authentication tag
|
||||
|
||||
help
|
||||
Print the list of registered commands
|
||||
help [<string>] [-v <0|1>]
|
||||
Print the summary of all registered commands if no arguments are given,
|
||||
otherwise print summary of given command.
|
||||
<string> Name of command
|
||||
-v, --verbose=<0|1> If specified, list console commands with given verbose level
|
||||
```
|
||||
|
||||
## Secure Services
|
||||
@@ -110,7 +112,7 @@ help
|
||||
### Attestation
|
||||
|
||||
- The `tee_att_info` command provided by the attestation service generates and dumps an Entity Attestation Token (EAT) signed by the TEE.
|
||||
- The token is signed using the ECDSA key (`secp256r1` curve) stored in the configured slot ID of the TEE Secure Storage.
|
||||
- The token is signed using the ECDSA key (`secp256r1` curve) stored in the TEE Secure Storage with the configured key ID.
|
||||
|
||||
<details>
|
||||
<summary><b>Sample output:</b> <i>tee_att_info</i></summary>
|
||||
@@ -128,22 +130,22 @@ I (8180) tee_attest: Attestation token - Data:
|
||||
### Secure Storage
|
||||
|
||||
- The TEE secure storage service provides the following commands:
|
||||
- `tee_sec_stg_gen_key`: Generate and store a new key (ECDSA or AES) in a specified TEE secure storage slot
|
||||
- `tee_sec_stg_sign`: Sign a message using an ECDSA `secp256r1` key pair stored in a specified slot and verify the signature
|
||||
- `tee_sec_stg_encrypt`: Encrypt data with AES256-GCM using the key from the specified slot and outputs the ciphertext and tag
|
||||
- `tee_sec_stg_decrypt`: Decrypt ciphertext using key from the specified slot and tag for integrity verification
|
||||
- `tee_sec_stg_gen_key`: Generate and store a new key (ECDSA or AES) in the TEE secure storage with the specified ID
|
||||
- `tee_sec_stg_sign`: Sign a message using an ECDSA `secp256r1` key pair with the specified ID and verify the signature
|
||||
- `tee_sec_stg_encrypt`: Encrypt data with AES256-GCM using the key with the specified ID and outputs the ciphertext and tag
|
||||
- `tee_sec_stg_decrypt`: Decrypt ciphertext using key with the specified ID and tag for integrity verification
|
||||
- The `get_msg_sha256` command computes the SHA256 hash of a given message, which can be used as input for the `tee_sec_stg_sign` command.
|
||||
|
||||
<details>
|
||||
<summary><b>Sample output:</b> <i>tee_sec_stg_gen_key + get_msg_sha256 + tee_sec_stg_sign</i></summary>
|
||||
|
||||
```log
|
||||
esp32c6> tee_sec_stg_gen_key 7 0
|
||||
I (2964) tee_sec_stg: Generated ECDSA_SECP256R1 key in slot 7
|
||||
esp32c6> tee_sec_stg_gen_key ecdsa_p256_k0 1
|
||||
I (2964) tee_sec_stg: Generated ECDSA_SECP256R1 key with ID ecdsa_p256_k0
|
||||
esp32c6> get_msg_sha256 "hello world"
|
||||
I (3984) tee_sec_stg: Message digest (SHA256) -
|
||||
b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
|
||||
esp32c6> tee_sec_stg_sign 7 b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
|
||||
esp32c6> tee_sec_stg_sign ecdsa_p256_k0 b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
|
||||
I (5384) tee_sec_stg: Generated signature -
|
||||
944684f6ddcf4c268ac6b65e34ccb8d95bd2849567a87867101bc1f09208f0885d935d7b3ba9d46014f28e4c7c988d68c775431fcb2cb2d4ca5c6862db771088
|
||||
I (6404) tee_sec_stg: Public key (Uncompressed) -
|
||||
@@ -157,14 +159,14 @@ I (6444) tee_sec_stg: Signature verified successfully!
|
||||
<summary><b>Sample output:</b> <i>tee_sec_stg_gen_key + tee_sec_stg_encrypt + tee_sec_stg_decrypt</i></summary>
|
||||
|
||||
```log
|
||||
esp32c6> tee_sec_stg_gen_key 8 1
|
||||
I (2784) tee_sec_stg: Generated AES256 key in slot 8
|
||||
esp32c6> tee_sec_stg_encrypt 8 b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
|
||||
esp32c6> tee_sec_stg_gen_key aes256_k0 0
|
||||
I (2784) tee_sec_stg: Generated AES256 key with ID key0
|
||||
esp32c6> tee_sec_stg_encrypt aes256_k0 b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
|
||||
I (3084) tee_sec_stg: Ciphertext -
|
||||
58054310a96d48c2dccdf2e34005aa63b40817723d3ec3d597ab362efea084c1
|
||||
I (3594) tee_sec_stg: Tag -
|
||||
caeedb43e08dc3b4e35a58b2412908cc
|
||||
esp32c6> tee_sec_stg_decrypt 8 58054310a96d48c2dccdf2e34005aa63b40817723d3ec3d597ab362efea084c1 caeedb43e08dc3b4e35a58b2412908cc
|
||||
esp32c6> tee_sec_stg_decrypt aes256_k0 58054310a96d48c2dccdf2e34005aa63b40817723d3ec3d597ab362efea084c1 caeedb43e08dc3b4e35a58b2412908cc
|
||||
I (4314) tee_sec_stg: Decrypted plaintext -
|
||||
b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
|
||||
```
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "esp_tee_sec_storage.h"
|
||||
#include "example_tee_srv.h"
|
||||
|
||||
#define PROMPT_STR CONFIG_IDF_TARGET
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -79,7 +79,7 @@ static esp_err_t hexbuf_to_hexstr(const void *hexbuf, size_t hexbuf_sz, char *he
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t verify_ecdsa_secp256r1_sign(const uint8_t *digest, size_t len, const esp_tee_sec_storage_pubkey_t *pubkey, const esp_tee_sec_storage_sign_t *sign)
|
||||
static esp_err_t verify_ecdsa_secp256r1_sign(const uint8_t *digest, size_t len, const esp_tee_sec_storage_ecdsa_pubkey_t *pubkey, const esp_tee_sec_storage_ecdsa_sign_t *sign)
|
||||
{
|
||||
if (pubkey == NULL || digest == NULL || sign == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
@@ -197,7 +197,7 @@ void register_cmd_msg_sha256(void)
|
||||
}
|
||||
|
||||
static struct {
|
||||
struct arg_int *slot_id;
|
||||
struct arg_str *key_str_id;
|
||||
struct arg_int *key_type;
|
||||
struct arg_end *end;
|
||||
} tee_sec_stg_gen_key_args;
|
||||
@@ -211,29 +211,27 @@ static int tee_sec_stg_gen_key(int argc, char **argv)
|
||||
}
|
||||
|
||||
esp_err_t err = ESP_FAIL;
|
||||
uint16_t slot_id = (uint16_t)tee_sec_stg_gen_key_args.slot_id->ival[0];
|
||||
esp_tee_sec_storage_type_t key_type = (esp_tee_sec_storage_type_t)tee_sec_stg_gen_key_args.key_type->ival[0];
|
||||
|
||||
err = esp_tee_sec_storage_init();
|
||||
if (err != ESP_OK) {
|
||||
esp_tee_sec_storage_key_cfg_t cfg = {
|
||||
.id = (const char *)tee_sec_stg_gen_key_args.key_str_id->sval[0],
|
||||
.type = (esp_tee_sec_storage_type_t)tee_sec_stg_gen_key_args.key_type->ival[0]
|
||||
};
|
||||
|
||||
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);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = esp_tee_sec_storage_clear_slot(slot_id);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to clear slot %d!", slot_id);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = esp_tee_sec_storage_gen_key(slot_id, key_type);
|
||||
err = esp_tee_sec_storage_gen_key(&cfg);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to generate key!");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Generated %s key in slot %d",
|
||||
(key_type == ESP_SEC_STG_KEY_ECDSA_SECP256R1) ? "ECDSA_SECP256R1" : "AES256",
|
||||
slot_id);
|
||||
ESP_LOGI(TAG, "Generated %s key with ID %s",
|
||||
(cfg.type == ESP_SEC_STG_KEY_ECDSA_SECP256R1) ? "ECDSA_SECP256R1" : "AES256",
|
||||
cfg.id);
|
||||
|
||||
exit:
|
||||
return err;
|
||||
@@ -241,13 +239,13 @@ exit:
|
||||
|
||||
void register_srv_sec_stg_gen_key(void)
|
||||
{
|
||||
tee_sec_stg_gen_key_args.slot_id = arg_int1(NULL, NULL, "<slot_id>", "TEE Secure storage slot for storing the key");
|
||||
tee_sec_stg_gen_key_args.key_type = arg_int1(NULL, NULL, "<key_type>", "Key type (0: ECDSA_SECP256R1, 1: AES256)");
|
||||
tee_sec_stg_gen_key_args.key_str_id = arg_str1(NULL, NULL, "<key_id>", "TEE Secure storage key ID");
|
||||
tee_sec_stg_gen_key_args.key_type = arg_int1(NULL, NULL, "<key_type>", "Key type (0: AES256, 1: ECDSA_SECP256R1)");
|
||||
tee_sec_stg_gen_key_args.end = arg_end(2);
|
||||
|
||||
const esp_console_cmd_t tee_sec_stg = {
|
||||
.command = "tee_sec_stg_gen_key",
|
||||
.help = "Generate and store a new key of the specified type in the given TEE secure storage slot",
|
||||
.help = "Generate and store a new key of the specified type with the given ID",
|
||||
.hint = NULL,
|
||||
.func = &tee_sec_stg_gen_key,
|
||||
.argtable = &tee_sec_stg_gen_key_args,
|
||||
@@ -257,7 +255,7 @@ void register_srv_sec_stg_gen_key(void)
|
||||
}
|
||||
|
||||
static struct {
|
||||
struct arg_int *slot_id;
|
||||
struct arg_str *key_str_id;
|
||||
struct arg_str *msg_sha256;
|
||||
struct arg_end *end;
|
||||
} tee_sec_stg_sign_args;
|
||||
@@ -280,16 +278,13 @@ static int tee_sec_stg_sign(int argc, char **argv)
|
||||
uint8_t digest[SHA256_DIGEST_SZ] = {};
|
||||
hexstr_to_hexbuf(msg_sha256, msg_sha256_len, digest, sizeof(digest));
|
||||
|
||||
esp_err_t err = ESP_FAIL;
|
||||
uint16_t slot_id = (uint16_t)tee_sec_stg_sign_args.slot_id->ival[0];
|
||||
esp_tee_sec_storage_key_cfg_t cfg = {
|
||||
.id = (const char *)tee_sec_stg_sign_args.key_str_id->sval[0],
|
||||
.type = ESP_SEC_STG_KEY_ECDSA_SECP256R1
|
||||
};
|
||||
|
||||
err = esp_tee_sec_storage_init();
|
||||
if (err != ESP_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
esp_tee_sec_storage_sign_t sign = {};
|
||||
err = esp_tee_sec_storage_get_signature(slot_id, ESP_SEC_STG_KEY_ECDSA_SECP256R1, digest, sizeof(digest), &sign);
|
||||
esp_tee_sec_storage_ecdsa_sign_t sign = {};
|
||||
esp_err_t err = esp_tee_sec_storage_ecdsa_sign(&cfg, digest, sizeof(digest), &sign);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to generate signature!");
|
||||
goto exit;
|
||||
@@ -306,8 +301,8 @@ static int tee_sec_stg_sign(int argc, char **argv)
|
||||
ESP_LOGI(TAG, "Generated signature -\n%s", sign_hexstr);
|
||||
free(sign_hexstr);
|
||||
|
||||
esp_tee_sec_storage_pubkey_t pubkey = {};
|
||||
err = esp_tee_sec_storage_get_pubkey(slot_id, ESP_SEC_STG_KEY_ECDSA_SECP256R1, &pubkey);
|
||||
esp_tee_sec_storage_ecdsa_pubkey_t pubkey = {};
|
||||
err = esp_tee_sec_storage_ecdsa_get_pubkey(&cfg, &pubkey);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to fetch public-key!");
|
||||
goto exit;
|
||||
@@ -338,13 +333,13 @@ exit:
|
||||
|
||||
void register_srv_sec_stg_sign(void)
|
||||
{
|
||||
tee_sec_stg_sign_args.slot_id = arg_int1(NULL, NULL, "<slot_id>", "TEE Secure storage slot storing the ecdsa-secp256r1 keypair");
|
||||
tee_sec_stg_sign_args.key_str_id = arg_str1(NULL, NULL, "<key_id>", "TEE Secure storage key ID");
|
||||
tee_sec_stg_sign_args.msg_sha256 = arg_str1(NULL, NULL, "<msg_sha256>", "SHA256 digest of the message to be signed and verified");
|
||||
tee_sec_stg_sign_args.end = arg_end(2);
|
||||
|
||||
const esp_console_cmd_t tee_sec_stg = {
|
||||
.command = "tee_sec_stg_sign",
|
||||
.help = "Sign a message using the ECDSA keypair stored in the given slot ID and verify the signature",
|
||||
.help = "Sign a message using the ECDSA keypair stored with the given key ID and verify the signature",
|
||||
.hint = NULL,
|
||||
.func = &tee_sec_stg_sign,
|
||||
.argtable = &tee_sec_stg_sign_args,
|
||||
@@ -354,7 +349,7 @@ void register_srv_sec_stg_sign(void)
|
||||
}
|
||||
|
||||
static struct {
|
||||
struct arg_int *slot_id;
|
||||
struct arg_str *key_str_id;
|
||||
struct arg_str *plaintext;
|
||||
struct arg_end *end;
|
||||
} tee_sec_stg_encrypt_args;
|
||||
@@ -369,7 +364,7 @@ static int tee_sec_stg_encrypt(int argc, char **argv)
|
||||
|
||||
esp_err_t err = ESP_FAIL;
|
||||
uint8_t tag[AES256_GCM_TAG_LEN];
|
||||
uint16_t slot_id = (uint16_t)tee_sec_stg_encrypt_args.slot_id->ival[0];
|
||||
const char *key_id = (const char *)tee_sec_stg_encrypt_args.key_str_id->sval[0];
|
||||
|
||||
const char *plaintext = tee_sec_stg_encrypt_args.plaintext->sval[0];
|
||||
size_t plaintext_len = strnlen(plaintext, MAX_AES_PLAINTEXT_LEN);
|
||||
@@ -399,13 +394,13 @@ static int tee_sec_stg_encrypt(int argc, char **argv)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = esp_tee_sec_storage_init();
|
||||
if (err != ESP_OK) {
|
||||
goto exit;
|
||||
}
|
||||
esp_tee_sec_storage_aead_ctx_t ctx = {
|
||||
.key_id = key_id,
|
||||
.input = (uint8_t *)plaintext_buf,
|
||||
.input_len = plaintext_buf_len
|
||||
};
|
||||
|
||||
err = esp_tee_sec_storage_encrypt(slot_id, (uint8_t *)plaintext_buf, plaintext_buf_len,
|
||||
NULL, 0, tag, sizeof(tag), ciphertext_buf);
|
||||
err = esp_tee_sec_storage_aead_encrypt(&ctx, tag, sizeof(tag), ciphertext_buf);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to encrypt data: %s", esp_err_to_name(err));
|
||||
goto exit;
|
||||
@@ -434,13 +429,13 @@ exit:
|
||||
|
||||
void register_srv_sec_stg_encrypt(void)
|
||||
{
|
||||
tee_sec_stg_encrypt_args.slot_id = arg_int1(NULL, NULL, "<slot_id>", "TEE Secure storage slot storing the AES key");
|
||||
tee_sec_stg_encrypt_args.key_str_id = arg_str1(NULL, NULL, "<key_id>", "TEE Secure storage key ID");
|
||||
tee_sec_stg_encrypt_args.plaintext = arg_str1(NULL, NULL, "<plaintext>", "Plaintext to be encrypted");
|
||||
tee_sec_stg_encrypt_args.end = arg_end(2);
|
||||
|
||||
const esp_console_cmd_t tee_sec_stg = {
|
||||
.command = "tee_sec_stg_encrypt",
|
||||
.help = "Encrypt data using AES-GCM with a key from secure storage",
|
||||
.help = "Encrypt data using AES-GCM key with the given ID from secure storage",
|
||||
.hint = NULL,
|
||||
.func = &tee_sec_stg_encrypt,
|
||||
.argtable = &tee_sec_stg_encrypt_args,
|
||||
@@ -450,7 +445,7 @@ void register_srv_sec_stg_encrypt(void)
|
||||
}
|
||||
|
||||
static struct {
|
||||
struct arg_int *slot_id;
|
||||
struct arg_str *key_str_id;
|
||||
struct arg_str *ciphertext;
|
||||
struct arg_str *tag;
|
||||
struct arg_end *end;
|
||||
@@ -465,7 +460,7 @@ static int tee_sec_stg_decrypt(int argc, char **argv)
|
||||
}
|
||||
|
||||
esp_err_t err = ESP_FAIL;
|
||||
uint16_t slot_id = (uint16_t)tee_sec_stg_decrypt_args.slot_id->ival[0];
|
||||
const char *key_id = (const char *)tee_sec_stg_decrypt_args.key_str_id->sval[0];
|
||||
|
||||
const char *tag_hexstr = tee_sec_stg_decrypt_args.tag->sval[0];
|
||||
uint8_t tag[AES256_GCM_TAG_LEN];
|
||||
@@ -499,13 +494,13 @@ static int tee_sec_stg_decrypt(int argc, char **argv)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = esp_tee_sec_storage_init();
|
||||
if (err != ESP_OK) {
|
||||
goto exit;
|
||||
}
|
||||
esp_tee_sec_storage_aead_ctx_t ctx = {
|
||||
.key_id = key_id,
|
||||
.input = (uint8_t *)ciphertext_buf,
|
||||
.input_len = ciphertext_buf_len
|
||||
};
|
||||
|
||||
err = esp_tee_sec_storage_decrypt(slot_id, ciphertext_buf, ciphertext_buf_len,
|
||||
NULL, 0, tag, sizeof(tag), plaintext_buf);
|
||||
err = esp_tee_sec_storage_aead_decrypt(&ctx, tag, sizeof(tag), plaintext_buf);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to decrypt data: %s", esp_err_to_name(err));
|
||||
goto exit;
|
||||
@@ -530,14 +525,14 @@ exit:
|
||||
|
||||
void register_srv_sec_stg_decrypt(void)
|
||||
{
|
||||
tee_sec_stg_decrypt_args.slot_id = arg_int1(NULL, NULL, "<slot_id>", "TEE Secure storage slot storing the AES key");
|
||||
tee_sec_stg_decrypt_args.key_str_id = arg_str1(NULL, NULL, "<key_id>", "TEE Secure storage key ID");
|
||||
tee_sec_stg_decrypt_args.ciphertext = arg_str1(NULL, NULL, "<ciphertext>", "Ciphertext to be decrypted");
|
||||
tee_sec_stg_decrypt_args.tag = arg_str1(NULL, NULL, "<tag>", "AES-GCM authentication tag");
|
||||
tee_sec_stg_decrypt_args.end = arg_end(3);
|
||||
|
||||
const esp_console_cmd_t tee_sec_stg = {
|
||||
.command = "tee_sec_stg_decrypt",
|
||||
.help = "Decrypt data using AES-GCM with a key from secure storage",
|
||||
.help = "Decrypt data using AES-GCM key with the given ID from secure storage",
|
||||
.hint = NULL,
|
||||
.func = &tee_sec_stg_decrypt,
|
||||
.argtable = &tee_sec_stg_decrypt_args,
|
||||
|
@@ -53,13 +53,14 @@ def test_tee_cli_secure_storage(dut: Dut) -> None:
|
||||
time.sleep(1)
|
||||
|
||||
# Test out the TEE secure storage workflow - Message signing and verification
|
||||
iterations = 3
|
||||
sec_stg_slots = {0: 0, 1: 14, 2: 7}
|
||||
for i in range(iterations):
|
||||
dut.write(f'tee_sec_stg_gen_key {sec_stg_slots.get(i)} 0')
|
||||
dut.expect(r'Generated ECDSA_SECP256R1 key in slot (\d+)', timeout=30)
|
||||
sec_stg_key_ids = {0: 'key0', 1: 'key1', 2: 'key2'}
|
||||
iterations = len(sec_stg_key_ids)
|
||||
|
||||
dut.write(f'tee_sec_stg_sign {sec_stg_slots.get(i)} {test_msg_hash}')
|
||||
for i in range(iterations):
|
||||
dut.write(f'tee_sec_stg_gen_key {sec_stg_key_ids.get(i)} 1')
|
||||
dut.expect(r'Generated ECDSA_SECP256R1 key with ID (\S+)', timeout=30)
|
||||
|
||||
dut.write(f'tee_sec_stg_sign {sec_stg_key_ids.get(i)} {test_msg_hash}')
|
||||
test_msg_sign = dut.expect(r'Generated signature -\s*([0-9a-fA-F]{128})', timeout=30)[1].decode()
|
||||
test_msg_pubkey = dut.expect(r'Public key \(Uncompressed\) -\s*([0-9a-fA-F]{130})', timeout=30)[1].decode()
|
||||
dut.expect('Signature verified successfully', timeout=30)
|
||||
@@ -69,16 +70,15 @@ def test_tee_cli_secure_storage(dut: Dut) -> None:
|
||||
time.sleep(1)
|
||||
|
||||
# Test out the TEE secure storage workflow - Encryption and decryption
|
||||
sec_stg_slots = {0: 1, 1: 14, 2: 9}
|
||||
for i in range(iterations):
|
||||
dut.write(f'tee_sec_stg_gen_key {sec_stg_slots.get(i)} 1')
|
||||
dut.expect(r'Generated AES256 key in slot (\d+)', timeout=30)
|
||||
dut.write(f'tee_sec_stg_gen_key {sec_stg_key_ids.get(i)} 0')
|
||||
dut.expect(r'Generated AES256 key with ID (\S+)', timeout=30)
|
||||
|
||||
dut.write(f'tee_sec_stg_encrypt {sec_stg_slots.get(i)} {test_msg_hash}')
|
||||
dut.write(f'tee_sec_stg_encrypt {sec_stg_key_ids.get(i)} {test_msg_hash}')
|
||||
test_msg_cipher = dut.expect(r'Ciphertext -\s*([0-9a-fA-F]{64})', timeout=30)[1].decode()
|
||||
test_msg_tag = dut.expect(r'Tag -\s*([0-9a-fA-F]{32})', timeout=30)[1].decode()
|
||||
|
||||
dut.write(f'tee_sec_stg_decrypt {sec_stg_slots.get(i)} {test_msg_cipher} {test_msg_tag}')
|
||||
dut.write(f'tee_sec_stg_decrypt {sec_stg_key_ids.get(i)} {test_msg_cipher} {test_msg_tag}')
|
||||
test_msg_decipher = dut.expect(r'Decrypted plaintext -\s*([0-9a-fA-F]{64})', timeout=30)[1].decode()
|
||||
|
||||
assert test_msg_decipher == test_msg_hash
|
||||
@@ -133,9 +133,9 @@ def test_tee_cli_attestation(dut: Dut) -> None:
|
||||
dut.expect('ESP-TEE: Secure services demonstration', timeout=30)
|
||||
time.sleep(1)
|
||||
|
||||
att_key_slot = dut.app.sdkconfig.get('SECURE_TEE_ATT_KEY_SLOT_ID')
|
||||
dut.write(f'tee_sec_stg_gen_key {att_key_slot} 0')
|
||||
dut.expect(r'Generated ECDSA_SECP256R1 key in slot (\d+)', timeout=30)
|
||||
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')
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# Minimal TEE configuration
|
||||
CONFIG_SECURE_TEE_SEC_STG_MODE_RELEASE=y
|
||||
CONFIG_SECURE_TEE_SEC_STG_KEY_EFUSE_BLK=9
|
||||
CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID=5
|
||||
|
||||
# Reducing TEE DRAM and STACK sizes
|
||||
# 21KB
|
||||
|
@@ -12,4 +12,4 @@ CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=y
|
||||
|
||||
# TEE Secure Storage: Release mode
|
||||
CONFIG_SECURE_TEE_SEC_STG_MODE_RELEASE=y
|
||||
CONFIG_SECURE_TEE_SEC_STG_KEY_EFUSE_BLK=9
|
||||
CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID=5
|
||||
|
@@ -42,7 +42,7 @@ uint32_t _ss_add_in_loop(uint32_t a, uint32_t b, uint32_t iter)
|
||||
for (int i = 0; i < iter; i++) {
|
||||
a += b;
|
||||
esp_rom_delay_us(1000000);
|
||||
ESP_LOGD(TAG, "[mode: %d] val: %d", esp_cpu_get_curr_privilege_level(), a);
|
||||
esp_rom_printf("[mode: %d] val: %d\n", esp_cpu_get_curr_privilege_level(), a);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
@@ -1,9 +1,17 @@
|
||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# pylint: disable=W0621 # redefined-outer-name
|
||||
import base64
|
||||
import csv
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from typing import Dict
|
||||
from typing import List
|
||||
|
||||
import espsecure
|
||||
import esptool
|
||||
@@ -13,6 +21,7 @@ from _pytest.monkeypatch import MonkeyPatch
|
||||
from pytest_embedded_idf.serial import IdfSerial
|
||||
from pytest_embedded_serial_esp.serial import EspSerial
|
||||
|
||||
# fmt: off
|
||||
esp_tee_empty_bin = {
|
||||
'esp32c6': [
|
||||
0xE9, 0x04, 0x02, 0x10, 0x00, 0x00, 0x80, 0x40, 0xEE, 0x00, 0x00, 0x00,
|
||||
@@ -56,6 +65,7 @@ esp_tee_empty_bin = {
|
||||
0xFC, 0x74, 0xB2, 0xB9, 0x34, 0x72, 0xC3, 0x00
|
||||
]
|
||||
}
|
||||
# fmt: on
|
||||
|
||||
|
||||
# This is a custom IdfSerial class to support custom functionality
|
||||
@@ -70,10 +80,12 @@ class TEESerial(IdfSerial):
|
||||
@EspSerial.use_esptool()
|
||||
def bootloader_force_flash_if_req(self) -> None:
|
||||
# Forcefully flash the bootloader only if security features are enabled
|
||||
if any((
|
||||
self.app.sdkconfig.get('SECURE_BOOT', True),
|
||||
self.app.sdkconfig.get('SECURE_FLASH_ENC_ENABLED', True),
|
||||
)):
|
||||
if any(
|
||||
(
|
||||
self.app.sdkconfig.get('SECURE_BOOT', True),
|
||||
self.app.sdkconfig.get('SECURE_FLASH_ENC_ENABLED', True),
|
||||
)
|
||||
):
|
||||
offs = int(self.app.sdkconfig.get('BOOTLOADER_OFFSET_IN_FLASH', 0))
|
||||
bootloader_path = os.path.join(self.app.binary_path, 'bootloader', 'bootloader.bin')
|
||||
encrypt = '--encrypt' if self.app.sdkconfig.get('SECURE_FLASH_ENC_ENABLED') else ''
|
||||
@@ -81,7 +93,7 @@ class TEESerial(IdfSerial):
|
||||
|
||||
esptool.main(
|
||||
f'--no-stub write_flash {offs} {bootloader_path} --force {encrypt} --flash_size {flash_size}'.split(),
|
||||
esp=self.esp
|
||||
esp=self.esp,
|
||||
)
|
||||
|
||||
@EspSerial.use_esptool()
|
||||
@@ -97,20 +109,30 @@ class TEESerial(IdfSerial):
|
||||
temp_file.flush()
|
||||
|
||||
esptool.main(
|
||||
f'--no-stub write_flash {offs} {temp_file.name} --flash_size {flash_size}'.split(),
|
||||
esp=self.esp
|
||||
f'--no-stub write_flash {offs} {temp_file.name} --flash_size {flash_size}'.split(), esp=self.esp
|
||||
)
|
||||
else:
|
||||
self.erase_partition(partition)
|
||||
|
||||
@EspSerial.use_esptool()
|
||||
def copy_test_tee_img(self, partition: str, is_rollback: bool = False) -> None:
|
||||
def custom_write_partition(self, partition: str, bin_path: str, encrypt: bool = False) -> None:
|
||||
offs = self.app.partition_table[partition]['offset']
|
||||
no_stub = '--no-stub' if self.app.sdkconfig.get('SECURE_ENABLE_SECURE_ROM_DL_MODE') else ''
|
||||
encrypt = '--encrypt' if self.app.sdkconfig.get('SECURE_FLASH_ENC_ENABLED') else ''
|
||||
flash_size = self._get_flash_size()
|
||||
flash_file = bin_path
|
||||
|
||||
args = f'{no_stub} write_flash {offs} {flash_file}'.split()
|
||||
|
||||
if encrypt:
|
||||
args.append('--encrypt')
|
||||
args += f'--flash_size {flash_size}'.split()
|
||||
|
||||
esptool.main(args, esp=self.esp)
|
||||
|
||||
@EspSerial.use_esptool()
|
||||
def copy_test_tee_img(self, partition: str, is_rollback: bool = False) -> None:
|
||||
flash_file = os.path.join(self.app.binary_path, 'esp_tee', 'esp_tee.bin')
|
||||
encrypt = self.app.sdkconfig.get('SECURE_FLASH_ENC_ENABLED', False)
|
||||
|
||||
if is_rollback:
|
||||
datafile = 'esp_tee_empty.bin'
|
||||
@@ -125,22 +147,27 @@ class TEESerial(IdfSerial):
|
||||
|
||||
if self.app.sdkconfig.get('SECURE_BOOT'):
|
||||
keyfile = self.app.sdkconfig.get('SECURE_BOOT_SIGNING_KEY')
|
||||
# Signing the image with espsecure
|
||||
espsecure.main(
|
||||
f'sign_data --version 2 --append_signatures --keyfile {keyfile} --output {datafile_signed} {datafile}'.split()
|
||||
[
|
||||
'sign_data',
|
||||
'--version',
|
||||
'2',
|
||||
'--append_signatures',
|
||||
'--keyfile',
|
||||
keyfile,
|
||||
'--output',
|
||||
datafile_signed,
|
||||
datafile,
|
||||
]
|
||||
)
|
||||
flash_file = datafile_signed
|
||||
|
||||
esptool.main(
|
||||
f'{no_stub} write_flash {offs} {flash_file} {encrypt} --flash_size {flash_size}'.split(),
|
||||
esp=self.esp
|
||||
)
|
||||
self.custom_write_partition(partition, flash_file, encrypt=encrypt)
|
||||
|
||||
if is_rollback:
|
||||
if os.path.exists(datafile):
|
||||
os.remove(datafile)
|
||||
if os.path.exists(datafile_signed):
|
||||
os.remove(datafile_signed)
|
||||
for file in [datafile, datafile_signed]:
|
||||
if os.path.exists(file):
|
||||
os.remove(file)
|
||||
|
||||
@EspSerial.use_esptool()
|
||||
def custom_flash(self) -> None:
|
||||
@@ -165,6 +192,114 @@ class TEESerial(IdfSerial):
|
||||
self.flash()
|
||||
self.custom_erase_partition('secure_storage')
|
||||
|
||||
KEY_DEFS: List[Dict[str, Any]] = [
|
||||
{'key': 'aes256_key0', 'type': 'aes256', 'input': None, 'write_once': True},
|
||||
{
|
||||
'key': 'aes256_key1',
|
||||
'type': 'aes256',
|
||||
'input': 'aes256_key.bin',
|
||||
'write_once': False,
|
||||
'b64': 'qZxftt2T8mOpLxALIfsDqI65srqPxrJtCVnDU8wrKXbFCJekDRzXqINlU5s=',
|
||||
},
|
||||
{'key': 'p256_key0', 'type': 'ecdsa_p256', 'input': None, 'write_once': False},
|
||||
{
|
||||
'key': 'attest_key',
|
||||
'type': 'ecdsa_p256',
|
||||
'input': 'ecdsa_p256_key.pem',
|
||||
'write_once': True,
|
||||
'b64': (
|
||||
'LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlNU1VpUktHaVZjSTIvbUZFekI3eXRIOVJj'
|
||||
'd0wyUThkNDhONHNFUHFYc0RvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSkYxYXRZQUxrdnB4cCt4N3c1dmVPQ1Vj'
|
||||
'RUhFRTY5azkvcFB5eFdTbEZkbW5wMnBmbVJpZwp5NnRTMDNaM2tnN2hYcitTQmNLbmRCV2RlZW81Vm9XV29nPT0K'
|
||||
'LS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo='
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
NVS_KEYS_B64 = 'MzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzPMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzA=='
|
||||
|
||||
TMP_DIR = Path('tmp')
|
||||
NVS_KEYS_PATH = TMP_DIR / 'nvs_keys.bin'
|
||||
NVS_CSV_PATH = TMP_DIR / 'tee_sec_stg_val.csv'
|
||||
NVS_BIN_PATH = TMP_DIR / 'tee_sec_stg_nvs.bin'
|
||||
|
||||
def run_command(self, command: List[str]) -> None:
|
||||
try:
|
||||
subprocess.check_call(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
except subprocess.CalledProcessError:
|
||||
print(f'Command failed: {" ".join(command)}')
|
||||
raise
|
||||
|
||||
def write_keys_to_file(self, b64_data: str, path: Path) -> None:
|
||||
path.write_bytes(base64.b64decode(b64_data))
|
||||
|
||||
def create_tee_sec_stg_csv(self, tmp_dir: Path) -> Path:
|
||||
csv_path = self.NVS_CSV_PATH
|
||||
rows: List[List[str]] = [
|
||||
['key', 'type', 'encoding', 'value'],
|
||||
['tee_sec_stg_ns', 'namespace', '', ''],
|
||||
]
|
||||
rows += [[entry['key'], 'file', 'binary', str(tmp_dir / f'{entry["key"]}.bin')] for entry in self.KEY_DEFS]
|
||||
with csv_path.open('w', newline='') as f:
|
||||
csv.writer(f).writerows(rows)
|
||||
return csv_path
|
||||
|
||||
def custom_flash_with_host_gen_sec_stg_img(self) -> None:
|
||||
tmp_dir = self.TMP_DIR
|
||||
tmp_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for entry in self.KEY_DEFS:
|
||||
if entry['input']:
|
||||
input_path = tmp_dir / entry['input']
|
||||
self.write_keys_to_file(entry['b64'], input_path)
|
||||
entry['input'] = str(input_path)
|
||||
self.write_keys_to_file(self.NVS_KEYS_B64, self.NVS_KEYS_PATH)
|
||||
|
||||
idf_path = Path(os.environ['IDF_PATH'])
|
||||
ESP_TEE_SEC_STG_KEYGEN = os.path.join(
|
||||
idf_path, 'components', 'esp_tee', 'scripts', 'esp_tee_sec_stg_keygen', 'esp_tee_sec_stg_keygen.py'
|
||||
)
|
||||
NVS_PARTITION_GEN = os.path.join(
|
||||
idf_path, 'components', 'nvs_flash', 'nvs_partition_generator', 'nvs_partition_gen.py'
|
||||
)
|
||||
|
||||
cmds = [
|
||||
[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 [])
|
||||
for entry in self.KEY_DEFS
|
||||
]
|
||||
|
||||
csv_path = self.create_tee_sec_stg_csv(tmp_dir)
|
||||
nvs_bin = self.NVS_BIN_PATH
|
||||
nvs_keys = self.NVS_KEYS_PATH
|
||||
size = self.app.partition_table['secure_storage']['size']
|
||||
|
||||
cmds.append(
|
||||
[
|
||||
sys.executable,
|
||||
NVS_PARTITION_GEN,
|
||||
'encrypt',
|
||||
str(csv_path),
|
||||
str(nvs_bin),
|
||||
str(size),
|
||||
'--inputkey',
|
||||
str(nvs_keys),
|
||||
]
|
||||
)
|
||||
|
||||
try:
|
||||
for cmd in cmds:
|
||||
self.run_command(cmd)
|
||||
|
||||
self.bootloader_force_flash_if_req()
|
||||
self.flash()
|
||||
self.custom_erase_partition('secure_storage')
|
||||
self.custom_write_partition('secure_storage', nvs_bin)
|
||||
|
||||
finally:
|
||||
shutil.rmtree(tmp_dir)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def monkeypatch_module(request: FixtureRequest) -> MonkeyPatch:
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -29,14 +29,14 @@
|
||||
#define ECDSA_SECP256R1_KEY_LEN (32)
|
||||
|
||||
#define ESP_ATT_TK_BUF_SIZE (1792)
|
||||
#define ESP_ATT_TK_PSA_CERT_REF ("0716053550477-10100")
|
||||
#define ESP_ATT_TK_PSA_CERT_REF ("0632793520245-10010")
|
||||
|
||||
#define ESP_ATT_TK_NONCE (0xABCD1234)
|
||||
#define ESP_ATT_TK_CLIENT_ID (0x0FACADE0)
|
||||
|
||||
static const char *TAG = "test_esp_tee_att";
|
||||
|
||||
extern int verify_ecdsa_sign(const uint8_t *digest, size_t len, const esp_tee_sec_storage_pubkey_t *pubkey, const esp_tee_sec_storage_sign_t *sign, bool is_crv_p192);
|
||||
extern int verify_ecdsa_sign(const uint8_t *digest, size_t len, const esp_tee_sec_storage_ecdsa_pubkey_t *pubkey, const esp_tee_sec_storage_ecdsa_sign_t *sign, bool is_crv_p192);
|
||||
|
||||
static uint8_t hexchar_to_byte(char hex)
|
||||
{
|
||||
@@ -72,7 +72,7 @@ static void hexstr_to_bytes(const char *hex_str, uint8_t **hex_buf, size_t *buf_
|
||||
}
|
||||
}
|
||||
|
||||
static int decompress_ecdsa_pubkey(const mbedtls_ecp_group *grp, const unsigned char *input, size_t ilen, esp_tee_sec_storage_pubkey_t *pubkey)
|
||||
static int decompress_ecdsa_pubkey(const mbedtls_ecp_group *grp, const unsigned char *input, size_t ilen, esp_tee_sec_storage_ecdsa_pubkey_t *pubkey)
|
||||
{
|
||||
int ret = -1;
|
||||
mbedtls_mpi r, x, n;
|
||||
@@ -186,7 +186,7 @@ static void prehash_token_data(const char *token_json, uint8_t *digest, size_t l
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void fetch_pubkey(const char *token_json, esp_tee_sec_storage_pubkey_t *pubkey_ctx)
|
||||
static void fetch_pubkey(const char *token_json, esp_tee_sec_storage_ecdsa_pubkey_t *pubkey_ctx)
|
||||
{
|
||||
TEST_ASSERT_NOT_NULL(token_json);
|
||||
TEST_ASSERT_NOT_NULL(pubkey_ctx);
|
||||
@@ -218,7 +218,7 @@ static void fetch_pubkey(const char *token_json, esp_tee_sec_storage_pubkey_t *p
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void fetch_signature(const char *token_json, esp_tee_sec_storage_sign_t *sign_ctx)
|
||||
static void fetch_signature(const char *token_json, esp_tee_sec_storage_ecdsa_sign_t *sign_ctx)
|
||||
{
|
||||
TEST_ASSERT_NOT_NULL(token_json);
|
||||
TEST_ASSERT_NOT_NULL(sign_ctx);
|
||||
@@ -267,11 +267,11 @@ TEST_CASE("Test TEE Attestation - Generate and verify the EAT", "[attestation]")
|
||||
prehash_token_data((const char *)token_buf, digest, sizeof(digest));
|
||||
|
||||
// Fetching and decompressing the public key
|
||||
esp_tee_sec_storage_pubkey_t pubkey_ctx = {};
|
||||
esp_tee_sec_storage_ecdsa_pubkey_t pubkey_ctx = {};
|
||||
fetch_pubkey((const char *)token_buf, &pubkey_ctx);
|
||||
|
||||
// Fetching the signature components
|
||||
esp_tee_sec_storage_sign_t sign_ctx = {};
|
||||
esp_tee_sec_storage_ecdsa_sign_t sign_ctx = {};
|
||||
fetch_signature((const char *)token_buf, &sign_ctx);
|
||||
|
||||
// Verifying the generated token
|
||||
|
@@ -27,6 +27,8 @@
|
||||
#define TEST_PART_LABEL "custom"
|
||||
#define TEST_BUF_SZ 256
|
||||
|
||||
#define ESP_TEE_SEC_STG_PART_LABEL "secure_storage"
|
||||
|
||||
static const char *TAG = "test_esp_tee_flash_prot";
|
||||
|
||||
static void set_boot_count_in_nvs(uint8_t boot_count)
|
||||
@@ -93,7 +95,7 @@ static void test_esp_partition_mmap_api(void)
|
||||
TEST_FAIL_MESSAGE("System fault should have been generated");
|
||||
break;
|
||||
case 5:
|
||||
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_TEE_SEC_STORAGE, NULL);
|
||||
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, ESP_TEE_SEC_STG_PART_LABEL);
|
||||
TEST_ASSERT_NOT_NULL(part);
|
||||
TEST_ESP_OK(esp_partition_mmap(part, 0, part->size, ESP_PARTITION_MMAP_DATA, &outptr, &out_handle));
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, outptr, 0x20, ESP_LOG_INFO);
|
||||
@@ -149,7 +151,7 @@ static void test_esp_partition_api(void)
|
||||
test_esp_partition_api_w(part);
|
||||
break;
|
||||
case 4:
|
||||
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_TEE_SEC_STORAGE, NULL);
|
||||
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, ESP_TEE_SEC_STG_PART_LABEL);
|
||||
test_esp_partition_api_w(part);
|
||||
break;
|
||||
case 5:
|
||||
@@ -255,7 +257,7 @@ static void test_esp_flash_api(void)
|
||||
test_esp_flash_api_r(part->address);
|
||||
break;
|
||||
case 4:
|
||||
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_TEE_SEC_STORAGE, NULL);
|
||||
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, ESP_TEE_SEC_STG_PART_LABEL);
|
||||
TEST_ASSERT_NOT_NULL(part);
|
||||
test_esp_flash_api_e(part->address);
|
||||
break;
|
||||
@@ -327,7 +329,7 @@ static void test_esp_rom_spiflash_api(void)
|
||||
TEST_FAIL_MESSAGE("System fault should have been generated");
|
||||
break;
|
||||
case 4:
|
||||
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_TEE_SEC_STORAGE, NULL);
|
||||
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, ESP_TEE_SEC_STG_PART_LABEL);
|
||||
TEST_ASSERT_NOT_NULL(part);
|
||||
test_esp_rom_spiflash_api_e(part->address);
|
||||
TEST_FAIL_MESSAGE("System fault should have been generated");
|
||||
|
@@ -30,7 +30,7 @@ extern uint32_t _instruction_reserved_start;
|
||||
|
||||
#if CONFIG_SECURE_TEE_SEC_STG_MODE_RELEASE
|
||||
#define TEST_APM_EFUSE_PROT_REG \
|
||||
(EFUSE_RD_KEY0_DATA0_REG + (((CONFIG_SECURE_TEE_SEC_STG_KEY_EFUSE_BLK) - 4) * 0x20))
|
||||
(EFUSE_RD_KEY0_DATA0_REG + (CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID * 0x20))
|
||||
#else
|
||||
#define TEST_APM_EFUSE_PROT_REG EFUSE_RD_KEY5_DATA0_REG
|
||||
#endif
|
||||
|
@@ -17,9 +17,12 @@
|
||||
#include "esp_tee.h"
|
||||
#include "esp_tee_sec_storage.h"
|
||||
#include "secure_service_num.h"
|
||||
#if CONFIG_SECURE_TEE_ATTESTATION
|
||||
#include "esp_tee_attestation.h"
|
||||
#endif
|
||||
|
||||
#include "esp_random.h"
|
||||
|
||||
#include "nvs.h"
|
||||
#include "unity.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
@@ -31,9 +34,14 @@
|
||||
#define ECDSA_SECP256R1_KEY_LEN (32)
|
||||
#define ECDSA_SECP192R1_KEY_LEN (24)
|
||||
|
||||
#define ESP_ATT_TK_BUF_SIZE (1792)
|
||||
#define ESP_ATT_TK_PSA_CERT_REF ("0632793520245-10010")
|
||||
|
||||
#define MAX_SEC_STG_ITER (16)
|
||||
|
||||
static const char *TAG = "test_esp_tee_sec_storage";
|
||||
|
||||
int verify_ecdsa_sign(const uint8_t *digest, size_t len, const esp_tee_sec_storage_pubkey_t *pubkey, const esp_tee_sec_storage_sign_t *sign, bool is_crv_p192)
|
||||
int verify_ecdsa_sign(const uint8_t *digest, size_t len, const esp_tee_sec_storage_ecdsa_pubkey_t *pubkey, const esp_tee_sec_storage_ecdsa_sign_t *sign, bool is_crv_p192)
|
||||
{
|
||||
#if !CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP192R1_SIGN
|
||||
TEST_ASSERT_FALSE(is_crv_p192);
|
||||
@@ -73,7 +81,7 @@ int verify_ecdsa_sign(const uint8_t *digest, size_t len, const esp_tee_sec_stora
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST_CASE("Test TEE Secure Storage - Sign-verify (ecdsa_secp256r1) with all key-slot IDs", "[secure_storage]")
|
||||
TEST_CASE("Test TEE Secure Storage - Sign-verify (ecdsa_secp256r1)", "[sec_storage]")
|
||||
{
|
||||
const size_t buf_sz = 16 * 1024 + 6; // NOTE: Not an exact multiple of SHA block size
|
||||
unsigned char *message = heap_caps_malloc(buf_sz, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
@@ -85,27 +93,34 @@ TEST_CASE("Test TEE Secure Storage - Sign-verify (ecdsa_secp256r1) with all key-
|
||||
TEST_ASSERT_MBEDTLS_OK(mbedtls_sha256(message, buf_sz, msg_digest, false));
|
||||
free(message);
|
||||
|
||||
TEST_ESP_OK(esp_tee_sec_storage_init());
|
||||
esp_tee_sec_storage_key_cfg_t key_cfg = {
|
||||
.type = ESP_SEC_STG_KEY_ECDSA_SECP256R1
|
||||
};
|
||||
|
||||
for (uint16_t slot_id = 0; slot_id <= MAX_SEC_STG_SLOT_ID; slot_id++) {
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_slot(slot_id));
|
||||
TEST_ESP_OK(esp_tee_sec_storage_gen_key(slot_id, ESP_SEC_STG_KEY_ECDSA_SECP256R1));
|
||||
for (unsigned int i = 0; i < MAX_SEC_STG_ITER; i++) {
|
||||
char key_id[32];
|
||||
int ret = snprintf(key_id, sizeof(key_id), "ecdsa_key_%u", i);
|
||||
TEST_ASSERT_TRUE(ret > 0 && ret < sizeof(key_id));
|
||||
|
||||
esp_tee_sec_storage_sign_t sign = {};
|
||||
TEST_ESP_OK(esp_tee_sec_storage_get_signature(slot_id, ESP_SEC_STG_KEY_ECDSA_SECP256R1, msg_digest, sizeof(msg_digest), &sign));
|
||||
key_cfg.id = key_id;
|
||||
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_OK(esp_tee_sec_storage_gen_key(&key_cfg));
|
||||
|
||||
esp_tee_sec_storage_pubkey_t pubkey = {};
|
||||
TEST_ESP_OK(esp_tee_sec_storage_get_pubkey(slot_id, ESP_SEC_STG_KEY_ECDSA_SECP256R1, &pubkey));
|
||||
esp_tee_sec_storage_ecdsa_sign_t sign = {};
|
||||
TEST_ESP_OK(esp_tee_sec_storage_ecdsa_sign(&key_cfg, msg_digest, sizeof(msg_digest), &sign));
|
||||
|
||||
esp_tee_sec_storage_ecdsa_pubkey_t pubkey = {};
|
||||
TEST_ESP_OK(esp_tee_sec_storage_ecdsa_get_pubkey(&key_cfg, &pubkey));
|
||||
|
||||
TEST_ESP_OK(verify_ecdsa_sign(msg_digest, sizeof(msg_digest), &pubkey, &sign, false));
|
||||
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_slot(slot_id));
|
||||
TEST_ASSERT_TRUE(esp_tee_sec_storage_is_slot_empty(slot_id));
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_key(key_cfg.id));
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP192R1_SIGN
|
||||
TEST_CASE("Test TEE Secure Storage - Sign-verify (ecdsa_secp192r1) with all key-slot IDs", "[secure_storage]")
|
||||
TEST_CASE("Test TEE Secure Storage - Sign-verify (ecdsa_secp192r1)", "[sec_storage]")
|
||||
{
|
||||
const size_t buf_sz = 16 * 1024 + 6; // NOTE: Not an exact multiple of SHA block size
|
||||
unsigned char *message = heap_caps_malloc(buf_sz, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
@@ -117,27 +132,34 @@ TEST_CASE("Test TEE Secure Storage - Sign-verify (ecdsa_secp192r1) with all key-
|
||||
TEST_ASSERT_MBEDTLS_OK(mbedtls_sha256(message, buf_sz, msg_digest, false));
|
||||
free(message);
|
||||
|
||||
TEST_ESP_OK(esp_tee_sec_storage_init());
|
||||
esp_tee_sec_storage_key_cfg_t key_cfg = {
|
||||
.type = ESP_SEC_STG_KEY_ECDSA_SECP192R1
|
||||
};
|
||||
|
||||
for (uint16_t slot_id = 0; slot_id <= MAX_SEC_STG_SLOT_ID; slot_id++) {
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_slot(slot_id));
|
||||
TEST_ESP_OK(esp_tee_sec_storage_gen_key(slot_id, ESP_SEC_STG_KEY_ECDSA_SECP192R1));
|
||||
for (unsigned int i = 0; i < MAX_SEC_STG_ITER; i++) {
|
||||
char key_id[32];
|
||||
int ret = snprintf(key_id, sizeof(key_id), "ecdsa_key_%u", i);
|
||||
TEST_ASSERT_TRUE(ret > 0 && ret < sizeof(key_id));
|
||||
|
||||
esp_tee_sec_storage_sign_t sign = {};
|
||||
TEST_ESP_OK(esp_tee_sec_storage_get_signature(slot_id, ESP_SEC_STG_KEY_ECDSA_SECP192R1, msg_digest, sizeof(msg_digest), &sign));
|
||||
key_cfg.id = key_id;
|
||||
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_OK(esp_tee_sec_storage_gen_key(&key_cfg));
|
||||
|
||||
esp_tee_sec_storage_pubkey_t pubkey = {};
|
||||
TEST_ESP_OK(esp_tee_sec_storage_get_pubkey(slot_id, ESP_SEC_STG_KEY_ECDSA_SECP192R1, &pubkey));
|
||||
esp_tee_sec_storage_ecdsa_sign_t sign = {};
|
||||
TEST_ESP_OK(esp_tee_sec_storage_ecdsa_sign(&key_cfg, msg_digest, sizeof(msg_digest), &sign));
|
||||
|
||||
esp_tee_sec_storage_ecdsa_pubkey_t pubkey = {};
|
||||
TEST_ESP_OK(esp_tee_sec_storage_ecdsa_get_pubkey(&key_cfg, &pubkey));
|
||||
|
||||
TEST_ESP_OK(verify_ecdsa_sign(msg_digest, sizeof(msg_digest), &pubkey, &sign, true));
|
||||
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_slot(slot_id));
|
||||
TEST_ASSERT_TRUE(esp_tee_sec_storage_is_slot_empty(slot_id));
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_key(key_cfg.id));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("Test TEE Secure Storage - Encrypt-decrypt (aes256_gcm) with all key-slot IDs", "[secure_storage]")
|
||||
TEST_CASE("Test TEE Secure Storage - Encrypt-decrypt (aes256_gcm)", "[sec_storage]")
|
||||
{
|
||||
const uint8_t SZ = 100;
|
||||
uint8_t *plaintext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
@@ -154,21 +176,37 @@ TEST_CASE("Test TEE Secure Storage - Encrypt-decrypt (aes256_gcm) with all key-s
|
||||
uint8_t aad[16];
|
||||
memset(aad, 0xA5, sizeof(aad));
|
||||
|
||||
TEST_ESP_OK(esp_tee_sec_storage_init());
|
||||
esp_tee_sec_storage_key_cfg_t key_cfg = {
|
||||
.type = ESP_SEC_STG_KEY_AES256
|
||||
};
|
||||
|
||||
for (uint16_t slot_id = 0; slot_id <= MAX_SEC_STG_SLOT_ID; slot_id++) {
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_slot(slot_id));
|
||||
TEST_ESP_OK(esp_tee_sec_storage_gen_key(slot_id, ESP_SEC_STG_KEY_AES256));
|
||||
for (unsigned int i = 0; i < MAX_SEC_STG_ITER; i++) {
|
||||
char test_key_id[32];
|
||||
int ret = snprintf(test_key_id, sizeof(test_key_id), "aes_key_%u", i);
|
||||
TEST_ASSERT_TRUE(ret > 0 && ret < sizeof(test_key_id));
|
||||
|
||||
TEST_ESP_OK(esp_tee_sec_storage_encrypt(slot_id, plaintext, SZ, aad, sizeof(aad),
|
||||
tag, sizeof(tag), ciphertext));
|
||||
TEST_ESP_OK(esp_tee_sec_storage_decrypt(slot_id, ciphertext, SZ, aad, sizeof(aad),
|
||||
tag, sizeof(tag), decryptedtext));
|
||||
key_cfg.id = test_key_id;
|
||||
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_OK(esp_tee_sec_storage_gen_key(&key_cfg));
|
||||
|
||||
esp_tee_sec_storage_aead_ctx_t aead_ctx = {
|
||||
.key_id = test_key_id,
|
||||
.aad = aad,
|
||||
.aad_len = sizeof(aad),
|
||||
};
|
||||
|
||||
aead_ctx.input = plaintext;
|
||||
aead_ctx.input_len = SZ;
|
||||
TEST_ESP_OK(esp_tee_sec_storage_aead_encrypt(&aead_ctx, tag, sizeof(tag), ciphertext));
|
||||
|
||||
aead_ctx.input = ciphertext;
|
||||
aead_ctx.input_len = SZ;
|
||||
TEST_ESP_OK(esp_tee_sec_storage_aead_decrypt(&aead_ctx, tag, sizeof(tag), decryptedtext));
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ);
|
||||
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_slot(slot_id));
|
||||
TEST_ASSERT_TRUE(esp_tee_sec_storage_is_slot_empty(slot_id));
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_key(key_cfg.id));
|
||||
}
|
||||
|
||||
free(plaintext);
|
||||
@@ -176,7 +214,7 @@ TEST_CASE("Test TEE Secure Storage - Encrypt-decrypt (aes256_gcm) with all key-s
|
||||
free(decryptedtext);
|
||||
}
|
||||
|
||||
TEST_CASE("Test TEE Secure Storage - Operations with invalid/non-existent keys", "[secure_storage]")
|
||||
TEST_CASE("Test TEE Secure Storage - Operations with invalid/non-existent keys", "[sec_storage]")
|
||||
{
|
||||
// Setup for ECDSA
|
||||
const uint8_t SZ = 100;
|
||||
@@ -187,6 +225,12 @@ TEST_CASE("Test TEE Secure Storage - Operations with invalid/non-existent keys",
|
||||
TEST_ASSERT_MBEDTLS_OK(mbedtls_sha256(message, SZ, msg_digest, false));
|
||||
free(message);
|
||||
|
||||
const char *key_id = "key_id_misc";
|
||||
esp_tee_sec_storage_key_cfg_t key_cfg = {
|
||||
.id = key_id,
|
||||
.type = ESP_SEC_STG_KEY_ECDSA_SECP256R1
|
||||
};
|
||||
|
||||
// Setup for AES
|
||||
uint8_t *plaintext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
TEST_ASSERT_NOT_NULL(plaintext);
|
||||
@@ -197,127 +241,195 @@ TEST_CASE("Test TEE Secure Storage - Operations with invalid/non-existent keys",
|
||||
uint8_t aad[16];
|
||||
memset(aad, 0xA5, sizeof(aad));
|
||||
|
||||
TEST_ESP_OK(esp_tee_sec_storage_init());
|
||||
esp_tee_sec_storage_aead_ctx_t aead_ctx = {
|
||||
.key_id = key_id,
|
||||
.aad = aad,
|
||||
.aad_len = sizeof(aad),
|
||||
.input = plaintext,
|
||||
.input_len = SZ
|
||||
};
|
||||
|
||||
// Test ECDSA key with AES operation
|
||||
const uint16_t slot_id = 7;
|
||||
ESP_LOGI(TAG, "Slot ID: %u - Trying AES operation with ECDSA key...", slot_id);
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_slot(slot_id));
|
||||
ESP_LOGI(TAG, "Key ID: %s - Trying AES operation with ECDSA key...", key_cfg.id);
|
||||
esp_err_t err = esp_tee_sec_storage_clear_key(key_cfg.id);
|
||||
ESP_LOGW(TAG, "err: %x", err);
|
||||
TEST_ASSERT_TRUE(err == ESP_OK || err == ESP_ERR_NOT_FOUND);
|
||||
TEST_ESP_OK(esp_tee_sec_storage_gen_key(&key_cfg));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, esp_tee_sec_storage_aead_encrypt(&aead_ctx, tag, sizeof(tag), ciphertext));
|
||||
|
||||
esp_tee_sec_storage_type_t key_type = ESP_SEC_STG_KEY_ECDSA_SECP256R1;
|
||||
TEST_ESP_OK(esp_tee_sec_storage_gen_key(slot_id, key_type));
|
||||
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, esp_tee_sec_storage_encrypt(slot_id, plaintext, SZ, aad, sizeof(aad),
|
||||
tag, sizeof(tag), ciphertext));
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_key(key_cfg.id));
|
||||
|
||||
// Test AES key with ECDSA operation
|
||||
ESP_LOGI(TAG, "Slot ID: %u - Trying ECDSA operation with AES key...", slot_id);
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_slot(slot_id));
|
||||
TEST_ESP_OK(esp_tee_sec_storage_gen_key(slot_id, ESP_SEC_STG_KEY_AES256));
|
||||
ESP_LOGI(TAG, "Key ID: %s - Trying ECDSA operation with AES key...", key_cfg.id);
|
||||
TEST_ASSERT_TRUE(err == ESP_OK || err == ESP_ERR_NOT_FOUND);
|
||||
key_cfg.type = ESP_SEC_STG_KEY_AES256;
|
||||
TEST_ESP_OK(esp_tee_sec_storage_gen_key(&key_cfg));
|
||||
|
||||
esp_tee_sec_storage_sign_t sign = {};
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, esp_tee_sec_storage_get_signature(slot_id, key_type, msg_digest, sizeof(msg_digest), &sign));
|
||||
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_slot(slot_id));
|
||||
TEST_ASSERT_TRUE(esp_tee_sec_storage_is_slot_empty(slot_id));
|
||||
esp_tee_sec_storage_ecdsa_sign_t sign = {};
|
||||
TEST_ESP_ERR(ESP_FAIL, esp_tee_sec_storage_ecdsa_sign(&key_cfg, msg_digest, sizeof(msg_digest), &sign));
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_key(key_cfg.id));
|
||||
|
||||
// Test with non-existent data
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, esp_tee_sec_storage_encrypt(slot_id, plaintext, SZ, aad, sizeof(aad),
|
||||
tag, sizeof(tag), ciphertext));
|
||||
TEST_ESP_ERR(ESP_ERR_NVS_NOT_FOUND, esp_tee_sec_storage_aead_encrypt(&aead_ctx, tag, sizeof(tag), ciphertext));
|
||||
|
||||
free(plaintext);
|
||||
free(ciphertext);
|
||||
}
|
||||
|
||||
TEST_CASE("Test TEE Secure Storage - Invalid key-slot IDs", "[secure_storage]")
|
||||
TEST_CASE("Test TEE Secure Storage - Null Pointer and Zero Length", "[sec_storage]")
|
||||
{
|
||||
TEST_ESP_OK(esp_tee_sec_storage_init());
|
||||
|
||||
uint16_t slot_id = MAX_SEC_STG_SLOT_ID + 1;
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_gen_key(slot_id, ESP_SEC_STG_KEY_ECDSA_SECP256R1));
|
||||
|
||||
slot_id = MIN_SEC_STG_SLOT_ID - 1;
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_gen_key(slot_id, ESP_SEC_STG_KEY_AES256));
|
||||
}
|
||||
|
||||
TEST_CASE("Test TEE Secure Storage - Exhaust all key-slots", "[secure_storage]")
|
||||
{
|
||||
TEST_ESP_OK(esp_tee_sec_storage_init());
|
||||
|
||||
esp_err_t err = ESP_FAIL;
|
||||
uint16_t slot_id = MIN_SEC_STG_SLOT_ID;
|
||||
|
||||
while (1) {
|
||||
esp_tee_sec_storage_clear_slot(slot_id);
|
||||
err = esp_tee_sec_storage_gen_key(slot_id, ESP_SEC_STG_KEY_AES256);
|
||||
if (err != ESP_OK) {
|
||||
break;
|
||||
}
|
||||
TEST_ASSERT_FALSE(esp_tee_sec_storage_is_slot_empty(slot_id));
|
||||
slot_id++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err);
|
||||
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, esp_tee_sec_storage_gen_key(MAX_SEC_STG_SLOT_ID, ESP_SEC_STG_KEY_AES256));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, esp_tee_sec_storage_gen_key(MIN_SEC_STG_SLOT_ID, ESP_SEC_STG_KEY_AES256));
|
||||
|
||||
uint16_t mid_slot = (MIN_SEC_STG_SLOT_ID + MAX_SEC_STG_SLOT_ID) / 2;
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, esp_tee_sec_storage_gen_key(mid_slot, ESP_SEC_STG_KEY_AES256));
|
||||
}
|
||||
|
||||
TEST_CASE("Test TEE Secure Storage - Null Pointer and Zero Length", "[secure_storage]")
|
||||
{
|
||||
TEST_ESP_OK(esp_tee_sec_storage_init());
|
||||
|
||||
const uint16_t slot_id = 7;
|
||||
const char *key_id = "key_id_misc";
|
||||
uint8_t data[31], tag[12];
|
||||
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_slot(slot_id));
|
||||
TEST_ESP_OK(esp_tee_sec_storage_gen_key(slot_id, ESP_SEC_STG_KEY_AES256));
|
||||
esp_tee_sec_storage_key_cfg_t key_cfg = {
|
||||
.id = key_id,
|
||||
.type = ESP_SEC_STG_KEY_AES256
|
||||
};
|
||||
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_encrypt(slot_id, NULL, sizeof(data), NULL, 0, tag, sizeof(tag), data));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_SIZE, esp_tee_sec_storage_encrypt(slot_id, data, 0, NULL, 0, tag, sizeof(tag), data));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_encrypt(slot_id, data, sizeof(data), NULL, 0, NULL, sizeof(tag), data));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_SIZE, esp_tee_sec_storage_encrypt(slot_id, data, sizeof(data), NULL, 0, tag, 0, data));
|
||||
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_OK(esp_tee_sec_storage_gen_key(&key_cfg));
|
||||
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_decrypt(slot_id, NULL, sizeof(data), NULL, 0, tag, sizeof(tag), data));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_SIZE, esp_tee_sec_storage_decrypt(slot_id, data, 0, NULL, 0, tag, sizeof(tag), data));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_decrypt(slot_id, data, sizeof(data), NULL, 0, NULL, sizeof(tag), data));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_SIZE, esp_tee_sec_storage_decrypt(slot_id, data, sizeof(data), NULL, 0, tag, 0, data));
|
||||
esp_tee_sec_storage_aead_ctx_t aead_ctx = {
|
||||
.key_id = key_cfg.id,
|
||||
.input = data,
|
||||
.input_len = sizeof(data),
|
||||
};
|
||||
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_slot(slot_id));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_aead_encrypt(&aead_ctx, NULL, sizeof(tag), data));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_SIZE, esp_tee_sec_storage_aead_encrypt(&aead_ctx, tag, 0, data));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_aead_decrypt(&aead_ctx, NULL, sizeof(tag), data));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_SIZE, esp_tee_sec_storage_aead_decrypt(&aead_ctx, tag, 0, data));
|
||||
|
||||
esp_tee_sec_storage_type_t key_type = ESP_SEC_STG_KEY_ECDSA_SECP256R1;
|
||||
TEST_ESP_OK(esp_tee_sec_storage_gen_key(slot_id, key_type));
|
||||
aead_ctx.input = NULL;
|
||||
aead_ctx.input_len = sizeof(data);
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_aead_encrypt(&aead_ctx, tag, sizeof(tag), data));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_aead_decrypt(&aead_ctx, tag, sizeof(tag), data));
|
||||
|
||||
esp_tee_sec_storage_sign_t sign = {};
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_get_signature(slot_id, key_type, NULL, sizeof(data), &sign));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_SIZE, esp_tee_sec_storage_get_signature(slot_id, key_type, data, 0, &sign));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_get_signature(slot_id, key_type, data, sizeof(data), NULL));
|
||||
aead_ctx.input = data;
|
||||
aead_ctx.input_len = 0;
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_SIZE, esp_tee_sec_storage_aead_encrypt(&aead_ctx, tag, sizeof(tag), data));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_SIZE, esp_tee_sec_storage_aead_decrypt(&aead_ctx, tag, sizeof(tag), data));
|
||||
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_get_pubkey(slot_id, key_type, NULL));
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_key(key_id));
|
||||
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_slot(slot_id));
|
||||
key_cfg.type = ESP_SEC_STG_KEY_ECDSA_SECP256R1;
|
||||
err = esp_tee_sec_storage_clear_key(key_cfg.id);
|
||||
TEST_ASSERT_TRUE(err == ESP_OK || err == ESP_ERR_NOT_FOUND);
|
||||
TEST_ESP_OK(esp_tee_sec_storage_gen_key(&key_cfg));
|
||||
|
||||
esp_tee_sec_storage_ecdsa_sign_t sign = {};
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_ecdsa_sign(&key_cfg, NULL, sizeof(data), &sign));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_ecdsa_sign(&key_cfg, data, 0, &sign));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_ecdsa_sign(&key_cfg, data, sizeof(data), NULL));
|
||||
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_tee_sec_storage_ecdsa_get_pubkey(&key_cfg, NULL));
|
||||
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_key(key_cfg.id));
|
||||
}
|
||||
|
||||
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C6)
|
||||
TEST_CASE("Test TEE Secure Storage - Corruption from non-secure world", "[secure_storage_neg]")
|
||||
TEST_CASE("Test TEE Secure Storage - WRITE_ONCE keys", "[sec_storage]")
|
||||
{
|
||||
const esp_partition_t *tee_sec_stg = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_TEE_SEC_STORAGE, NULL);
|
||||
TEST_ASSERT_NOT_NULL(tee_sec_stg);
|
||||
const char *key_id = "key_id_test_wo";
|
||||
|
||||
uint8_t buf_w[128];
|
||||
memset(buf_w, 0xA5, sizeof(buf_w));
|
||||
TEST_ESP_OK(esp_partition_write(tee_sec_stg, 0x00, buf_w, sizeof(buf_w)));
|
||||
esp_tee_sec_storage_key_cfg_t key_cfg = {
|
||||
.id = key_id,
|
||||
.type = ESP_SEC_STG_KEY_AES256,
|
||||
.flags = SEC_STORAGE_FLAG_WRITE_ONCE,
|
||||
};
|
||||
|
||||
uint8_t buf_r[128];
|
||||
memset(buf_r, 0x00, sizeof(buf_r));
|
||||
TEST_ESP_OK(esp_partition_read(tee_sec_stg, 0x00, buf_r, sizeof(buf_r)));
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, buf_r, sizeof(buf_r), ESP_LOG_INFO);
|
||||
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_FAIL_MESSAGE("APM violation interrupt should have been generated");
|
||||
TEST_ESP_OK(esp_tee_sec_storage_gen_key(&key_cfg));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, esp_tee_sec_storage_gen_key(&key_cfg));
|
||||
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, 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);
|
||||
TEST_ASSERT_NOT_NULL(ciphertext);
|
||||
uint8_t *decrypted = heap_caps_malloc(len, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
TEST_ASSERT_NOT_NULL(decrypted);
|
||||
|
||||
uint8_t tag[12];
|
||||
uint8_t aad[16];
|
||||
esp_fill_random(aad, sizeof(aad));
|
||||
|
||||
esp_tee_sec_storage_aead_ctx_t ctx = {
|
||||
.key_id = key_id,
|
||||
.aad = aad,
|
||||
.aad_len = sizeof(aad),
|
||||
};
|
||||
|
||||
ctx.input = input;
|
||||
ctx.input_len = len;
|
||||
TEST_ESP_OK(esp_tee_sec_storage_aead_encrypt(&ctx, tag, sizeof(tag), ciphertext));
|
||||
|
||||
ctx.input = ciphertext;
|
||||
ctx.input_len = len;
|
||||
TEST_ESP_OK(esp_tee_sec_storage_aead_decrypt(&ctx, tag, sizeof(tag), decrypted));
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(input, decrypted, len);
|
||||
|
||||
free(ciphertext);
|
||||
free(decrypted);
|
||||
}
|
||||
|
||||
TEST_CASE("Test TEE Secure Storage - Host-generated keys", "[sec_storage_host_keygen]")
|
||||
{
|
||||
const char *aes_key_id0 = "aes256_key0";
|
||||
const char *aes_key_id1 = "aes256_key1";
|
||||
const char *ecdsa_key_id0 = "p256_key0";
|
||||
const char *attest_key_id = "attest_key";
|
||||
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, esp_tee_sec_storage_clear_key(aes_key_id0));
|
||||
|
||||
const size_t SZ = 100;
|
||||
uint8_t *plaintext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
TEST_ASSERT_NOT_NULL(plaintext);
|
||||
esp_fill_random(plaintext, SZ);
|
||||
|
||||
test_aead_encrypt_decrypt(aes_key_id0, plaintext, SZ);
|
||||
test_aead_encrypt_decrypt(aes_key_id1, plaintext, SZ);
|
||||
|
||||
free(plaintext);
|
||||
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_key(aes_key_id1));
|
||||
|
||||
uint8_t msg_digest[SHA256_DIGEST_SZ];
|
||||
esp_fill_random(msg_digest, sizeof(msg_digest));
|
||||
|
||||
esp_tee_sec_storage_key_cfg_t key_cfg = {
|
||||
.id = ecdsa_key_id0,
|
||||
.type = ESP_SEC_STG_KEY_ECDSA_SECP256R1,
|
||||
};
|
||||
|
||||
esp_tee_sec_storage_ecdsa_sign_t sign = {};
|
||||
TEST_ESP_OK(esp_tee_sec_storage_ecdsa_sign(&key_cfg, msg_digest, sizeof(msg_digest), &sign));
|
||||
|
||||
esp_tee_sec_storage_ecdsa_pubkey_t pubkey = {};
|
||||
TEST_ESP_OK(esp_tee_sec_storage_ecdsa_get_pubkey(&key_cfg, &pubkey));
|
||||
|
||||
TEST_ESP_OK(verify_ecdsa_sign(msg_digest, sizeof(msg_digest), &pubkey, &sign, false));
|
||||
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_key(ecdsa_key_id0));
|
||||
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, esp_tee_sec_storage_clear_key(attest_key_id));
|
||||
|
||||
#if CONFIG_SECURE_TEE_ATTESTATION
|
||||
uint8_t *token_buf = heap_caps_calloc(ESP_ATT_TK_BUF_SIZE, sizeof(uint8_t), MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
TEST_ASSERT_NOT_NULL(token_buf);
|
||||
|
||||
uint32_t token_len = 0;
|
||||
TEST_ESP_OK(esp_tee_att_generate_token(0xA1B2C3D4, 0x0FACADE0, (const char *)ESP_ATT_TK_PSA_CERT_REF,
|
||||
token_buf, ESP_ATT_TK_BUF_SIZE, &token_len));
|
||||
|
||||
free(token_buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN
|
||||
static const uint8_t sha[] = {
|
||||
@@ -327,11 +439,8 @@ static const uint8_t sha[] = {
|
||||
0x91, 0xbe, 0x58, 0x10, 0xfe, 0x80, 0x65, 0x6e
|
||||
};
|
||||
|
||||
static void test_ecdsa_sign(mbedtls_ecp_group_id gid, const uint8_t *hash, int slot_id)
|
||||
static void test_ecdsa_sign(mbedtls_ecp_group_id gid)
|
||||
{
|
||||
TEST_ESP_OK(esp_tee_sec_storage_init());
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_slot(slot_id));
|
||||
|
||||
bool is_crv_p192 = false;
|
||||
esp_tee_sec_storage_type_t key_type = ESP_SEC_STG_KEY_ECDSA_SECP256R1;
|
||||
size_t key_len = ECDSA_SECP256R1_KEY_LEN;
|
||||
@@ -342,10 +451,20 @@ static void test_ecdsa_sign(mbedtls_ecp_group_id gid, const uint8_t *hash, int s
|
||||
key_len = ECDSA_SECP192R1_KEY_LEN;
|
||||
}
|
||||
|
||||
TEST_ESP_OK(esp_tee_sec_storage_gen_key(slot_id, key_type));
|
||||
const char *key_id = "ecdsa_k0";
|
||||
|
||||
esp_tee_sec_storage_pubkey_t pubkey = {};
|
||||
TEST_ESP_OK(esp_tee_sec_storage_get_pubkey(slot_id, key_type, &pubkey));
|
||||
esp_tee_sec_storage_key_cfg_t key_cfg = {
|
||||
.id = key_id,
|
||||
.type = key_type
|
||||
};
|
||||
|
||||
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_OK(esp_tee_sec_storage_gen_key(&key_cfg));
|
||||
|
||||
esp_tee_sec_storage_ecdsa_pubkey_t pubkey = {};
|
||||
TEST_ESP_OK(esp_tee_sec_storage_ecdsa_get_pubkey(&key_cfg, &pubkey));
|
||||
|
||||
mbedtls_mpi r, s;
|
||||
mbedtls_mpi_init(&r);
|
||||
@@ -360,7 +479,7 @@ static void test_ecdsa_sign(mbedtls_ecp_group_id gid, const uint8_t *hash, int s
|
||||
|
||||
esp_ecdsa_pk_conf_t conf = {
|
||||
.grp_id = gid,
|
||||
.tee_slot_id = slot_id,
|
||||
.tee_key_id = key_id,
|
||||
.load_pubkey = true,
|
||||
.use_tee_sec_stg_key = true,
|
||||
};
|
||||
@@ -371,7 +490,7 @@ static void test_ecdsa_sign(mbedtls_ecp_group_id gid, const uint8_t *hash, int s
|
||||
|
||||
TEST_ASSERT_MBEDTLS_OK(mbedtls_ecdsa_sign(&ecdsa_context.MBEDTLS_PRIVATE(grp), &r, &s, &key_mpi, sha, SHA256_DIGEST_SZ, NULL, NULL));
|
||||
|
||||
esp_tee_sec_storage_sign_t sign = {};
|
||||
esp_tee_sec_storage_ecdsa_sign_t sign = {};
|
||||
TEST_ASSERT_MBEDTLS_OK(mbedtls_mpi_write_binary(&r, sign.sign_r, key_len));
|
||||
TEST_ASSERT_MBEDTLS_OK(mbedtls_mpi_write_binary(&s, sign.sign_s, key_len));
|
||||
|
||||
@@ -381,13 +500,15 @@ static void test_ecdsa_sign(mbedtls_ecp_group_id gid, const uint8_t *hash, int s
|
||||
mbedtls_ecdsa_free(&ecdsa_context);
|
||||
mbedtls_mpi_free(&r);
|
||||
mbedtls_mpi_free(&s);
|
||||
|
||||
TEST_ESP_OK(esp_tee_sec_storage_clear_key(key_cfg.id));
|
||||
}
|
||||
|
||||
TEST_CASE("Test TEE Secure Storage - mbedtls ECDSA signing", "[mbedtls]")
|
||||
{
|
||||
test_ecdsa_sign(MBEDTLS_ECP_DP_SECP256R1, sha, MIN_SEC_STG_SLOT_ID);
|
||||
test_ecdsa_sign(MBEDTLS_ECP_DP_SECP256R1);
|
||||
#if CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP192R1_SIGN
|
||||
test_ecdsa_sign(MBEDTLS_ECP_DP_SECP192R1, sha, MAX_SEC_STG_SLOT_ID);
|
||||
test_ecdsa_sign(MBEDTLS_ECP_DP_SECP192R1);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
@@ -1,7 +0,0 @@
|
||||
# ESP-IDF Partition Table
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
tee, app, tee_0, , 192K,
|
||||
secure_storage, data, tee_sec_stg, , 64K,
|
||||
factory, app, factory, , 512K,
|
||||
nvs, data, nvs, , 24K,
|
||||
custom, data, , , 1M
|
|
@@ -3,7 +3,7 @@
|
||||
tee_0, app, tee_0, , 192K,
|
||||
tee_1, app, tee_1, , 192K,
|
||||
tee_otadata, data, tee_ota, , 8K,
|
||||
secure_storage, data, tee_sec_stg, , 56K,
|
||||
secure_storage, data, nvs, , 56K,
|
||||
ota_0, app, ota_0, , 512K,
|
||||
ota_1, app, ota_1, , 512K,
|
||||
otadata, data, ota, , 8K,
|
||||
|
|
@@ -442,7 +442,18 @@ def test_esp_tee_secure_storage(dut: IdfDut) -> None:
|
||||
# Flash image and erase the secure_storage partition
|
||||
dut.serial.custom_flash_with_empty_sec_stg()
|
||||
|
||||
dut.run_all_single_board_cases(group='secure_storage')
|
||||
dut.run_all_single_board_cases(group='sec_storage')
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('config', ['ota'], indirect=['config'])
|
||||
@idf_parametrize('skip_autoflash', ['y'], indirect=['skip_autoflash'])
|
||||
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
|
||||
def test_esp_tee_secure_storage_with_host_img(dut: IdfDut) -> None:
|
||||
# Flash image and write the secure_storage partition with host-generated keys
|
||||
dut.serial.custom_flash_with_host_gen_sec_stg_img()
|
||||
|
||||
dut.run_all_single_board_cases(group='sec_storage_host_keygen')
|
||||
|
||||
|
||||
# ---------------- TEE Attestation tests ----------------
|
||||
|
@@ -0,0 +1,5 @@
|
||||
# Decreasing Bootloader log verbosity
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
|
||||
|
||||
# Disabling ATTESTATION
|
||||
CONFIG_SECURE_TEE_ATTESTATION=n
|
||||
|
@@ -7,10 +7,8 @@ CONFIG_SECURE_ENABLE_TEE=y
|
||||
CONFIG_SECURE_TEE_DEBUG_MODE=y
|
||||
CONFIG_SECURE_TEE_TEST_MODE=y
|
||||
|
||||
# Custom partition table
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
# Setting partition table
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_TEE=y
|
||||
|
||||
# TEE IRAM size
|
||||
CONFIG_SECURE_TEE_IRAM_SIZE=0x8400
|
||||
|
@@ -1,11 +1,10 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_TEE_SEC_STG_SLOT_ID
|
||||
int "TEE: Secure Storage keypair slot ID"
|
||||
default 0
|
||||
range 0 15
|
||||
config EXAMPLE_TEE_SEC_STG_KEY_STR_ID
|
||||
string "TEE: Secure Storage Key ID"
|
||||
default "key_id_0"
|
||||
help
|
||||
This configuration sets the slot ID from the TEE secure storage
|
||||
This configuration sets the key string identifier from the TEE secure storage
|
||||
storing the ECDSA keypair for executing sign/verify operations
|
||||
from the TEE side
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* TEE Secure Storage 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
|
||||
*/
|
||||
@@ -21,20 +21,21 @@
|
||||
|
||||
#include "esp_tee_sec_storage.h"
|
||||
#include "secure_service_num.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define SHA256_DIGEST_SZ (32)
|
||||
#define ECDSA_SECP256R1_KEY_LEN (32)
|
||||
#define AES256_GCM_TAG_LEN (16)
|
||||
#define AES256_GCM_AAD_LEN (16)
|
||||
|
||||
#define KEY_SLOT_ID (CONFIG_EXAMPLE_TEE_SEC_STG_SLOT_ID)
|
||||
#define KEY_STR_ID (CONFIG_EXAMPLE_TEE_SEC_STG_KEY_STR_ID)
|
||||
#define MAX_AES_PLAINTEXT_LEN (128)
|
||||
|
||||
static const char *message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
|
||||
|
||||
static const char *TAG = "example_tee_sec_stg";
|
||||
|
||||
static esp_err_t verify_ecdsa_secp256r1_sign(const uint8_t *digest, size_t len, const esp_tee_sec_storage_pubkey_t *pubkey, const esp_tee_sec_storage_sign_t *sign)
|
||||
static esp_err_t verify_ecdsa_secp256r1_sign(const uint8_t *digest, size_t len, const esp_tee_sec_storage_ecdsa_pubkey_t *pubkey, const esp_tee_sec_storage_ecdsa_sign_t *sign)
|
||||
{
|
||||
if (pubkey == NULL || digest == NULL || sign == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
@@ -112,20 +113,25 @@ static void example_tee_sec_stg_sign_verify(void *pvParameter)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_tee_sec_storage_clear_slot(KEY_SLOT_ID);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to clear slot %d!", KEY_SLOT_ID);
|
||||
esp_tee_sec_storage_key_cfg_t cfg = {
|
||||
.id = (const char *)(KEY_STR_ID),
|
||||
.type = ESP_SEC_STG_KEY_ECDSA_SECP256R1
|
||||
};
|
||||
|
||||
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);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = esp_tee_sec_storage_gen_key(KEY_SLOT_ID, ESP_SEC_STG_KEY_ECDSA_SECP256R1);
|
||||
err = esp_tee_sec_storage_gen_key(&cfg);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to generate keypair!");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
esp_tee_sec_storage_sign_t sign = {};
|
||||
err = esp_tee_sec_storage_get_signature(KEY_SLOT_ID, ESP_SEC_STG_KEY_ECDSA_SECP256R1, msg_digest, sizeof(msg_digest), &sign);
|
||||
esp_tee_sec_storage_ecdsa_sign_t sign = {};
|
||||
err = esp_tee_sec_storage_ecdsa_sign(&cfg, msg_digest, sizeof(msg_digest), &sign);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to generate signature!");
|
||||
goto exit;
|
||||
@@ -133,8 +139,8 @@ static void example_tee_sec_stg_sign_verify(void *pvParameter)
|
||||
|
||||
ESP_LOG_BUFFER_HEX("Signature", &sign, sizeof(sign));
|
||||
|
||||
esp_tee_sec_storage_pubkey_t pubkey = {};
|
||||
err = esp_tee_sec_storage_get_pubkey(KEY_SLOT_ID, ESP_SEC_STG_KEY_ECDSA_SECP256R1, &pubkey);
|
||||
esp_tee_sec_storage_ecdsa_pubkey_t pubkey = {};
|
||||
err = esp_tee_sec_storage_ecdsa_get_pubkey(&cfg, &pubkey);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to fetch public-key!");
|
||||
goto exit;
|
||||
@@ -175,19 +181,32 @@ static void example_tee_sec_stg_encrypt_decrypt(void *pvParameter)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = esp_tee_sec_storage_clear_slot(KEY_SLOT_ID);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to clear slot %d!", KEY_SLOT_ID);
|
||||
esp_tee_sec_storage_key_cfg_t cfg = {
|
||||
.id = (const char *)(KEY_STR_ID),
|
||||
.type = ESP_SEC_STG_KEY_AES256
|
||||
};
|
||||
|
||||
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);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = esp_tee_sec_storage_gen_key(KEY_SLOT_ID, ESP_SEC_STG_KEY_AES256);
|
||||
err = esp_tee_sec_storage_gen_key(&cfg);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to generate key!");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = esp_tee_sec_storage_encrypt(KEY_SLOT_ID, (uint8_t *)plaintext, plaintext_len, aad_buf, sizeof(aad_buf), tag, sizeof(tag), ciphertext);
|
||||
esp_tee_sec_storage_aead_ctx_t ctx = {
|
||||
.key_id = cfg.id,
|
||||
.aad = aad_buf,
|
||||
.aad_len = sizeof(aad_buf),
|
||||
};
|
||||
|
||||
ctx.input = (const uint8_t *)plaintext;
|
||||
ctx.input_len = plaintext_len;
|
||||
err = esp_tee_sec_storage_aead_encrypt(&ctx, tag, sizeof(tag), ciphertext);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to encrypt data!");
|
||||
goto exit;
|
||||
@@ -195,7 +214,9 @@ static void example_tee_sec_stg_encrypt_decrypt(void *pvParameter)
|
||||
|
||||
ESP_LOG_BUFFER_HEX("Encrypted data", ciphertext, plaintext_len);
|
||||
|
||||
err = esp_tee_sec_storage_decrypt(KEY_SLOT_ID, (uint8_t *)ciphertext, plaintext_len, aad_buf, sizeof(aad_buf), tag, sizeof(tag), ciphertext);
|
||||
ctx.input = (const uint8_t *)ciphertext;
|
||||
ctx.input_len = plaintext_len;
|
||||
err = esp_tee_sec_storage_aead_decrypt(&ctx, tag, sizeof(tag), ciphertext);
|
||||
if (err != ESP_OK || memcmp(ciphertext, plaintext, plaintext_len) != 0) {
|
||||
ESP_LOGE(TAG, "Encryption verification failed!");
|
||||
err = ESP_FAIL;
|
||||
@@ -216,8 +237,6 @@ void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "TEE Secure Storage");
|
||||
|
||||
ESP_ERROR_CHECK(esp_tee_sec_storage_init());
|
||||
|
||||
xTaskCreate(example_tee_sec_stg_sign_verify, "tee_sec_stg_sign_verify", 4096, (void *)message, 5, NULL);
|
||||
xTaskCreate(example_tee_sec_stg_encrypt_decrypt, "tee_sec_stg_encrypt_decrypt", 4096, (void *)message, 5, NULL);
|
||||
}
|
||||
|
Reference in New Issue
Block a user