feat(esp_tee): Added examples demonstrating the ESP-TEE framework
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/components/example_secure_service/tee_project.cmake)
|
||||
|
||||
project(tee_basic)
|
||||
@@ -0,0 +1,57 @@
|
||||
| Supported Targets | ESP32-C6 |
|
||||
| ----------------- | -------- |
|
||||
|
||||
# Basic TEE example
|
||||
|
||||
## Overview
|
||||
|
||||
- This example illustrates the ESP-TEE (Trusted Execution Environment) framework to encrypt/decrypt data using AES within a secure environment.
|
||||
- The non-secure world i.e. the Rich Execution Environment (REE) raises a request for AES operation in TEE through the secure service call interface. The TEE performs encrypts/decrypts the given buffer with the AES-256-CBC mode using the key protected by TEE. If the operation is successful, the result of the AES operation is returned in the output buffer provided in the secure service call by the REE.
|
||||
- This example also demonstrates how to add custom service calls to TEE. You can refer to `components/example_service` for more information - see the structure below.
|
||||
|
||||
```
|
||||
└── example_secure_service # Component parent directory
|
||||
├── CMakeLists.txt
|
||||
├── example_service.c # Custom secure service APIs
|
||||
├── example.tbl # Custom secure service table, which is appended to the default one provided by TEE
|
||||
├── include
|
||||
│ └── example_service.h
|
||||
└── tee_project.cmake # To be manually included in the project's top level CMakeLists.txt before project(...)
|
||||
# Processes the custom service table
|
||||
```
|
||||
|
||||
## How to use the example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example can be executed on any development board with a Espressif SOC chip supporting the TEE framework (see Supported Targets table above).
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Before building the example, be sure to set the correct chip target using idf.py set-target <chip_name>.
|
||||
|
||||
Build the project and flash it to the board, then run the monitor tool to view the serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type `Ctrl-]`.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
### Example Output
|
||||
|
||||
```log
|
||||
I (315) main_task: Calling app_main()
|
||||
I (315) example_tee_basic: AES-256-CBC operations in TEE
|
||||
TEE: Secure service call for AES-256-CBC operation
|
||||
TEE: In PROTECTED M-mode
|
||||
I (325) example_tee_basic: AES encryption successful!
|
||||
I (325) example_tee_basic: Cipher text -
|
||||
I (325) example_tee_basic: ee 04 9b ee 95 6f 25 04 1e 8c e4 4e 8e 4e 7a d3
|
||||
TEE: Secure service call for AES-256-CBC operation
|
||||
TEE: In PROTECTED M-mode
|
||||
I (345) example_tee_basic: AES decryption successful!
|
||||
I (345) main_task: Returned from app_main()
|
||||
```
|
||||
@@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
idf_build_get_property(esp_tee_build ESP_TEE_BUILD)
|
||||
|
||||
if(NOT esp_tee_build)
|
||||
return()
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "example_service.c"
|
||||
INCLUDE_DIRS include
|
||||
PRIV_REQUIRES main)
|
||||
@@ -0,0 +1,2 @@
|
||||
# SS no. API type Function Args
|
||||
201 custom example_sec_serv_aes_op 6
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "esp_cpu.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_rom_sys.h"
|
||||
|
||||
#include "hal/aes_hal.h"
|
||||
#include "aes/esp_aes.h"
|
||||
|
||||
#include "esp_tee.h"
|
||||
#include "secure_service_num.h"
|
||||
|
||||
/* Fixed key */
|
||||
static const uint8_t key[AES_256_KEY_BYTES] = {[0 ... 31] = 0xA5};
|
||||
|
||||
esp_err_t _ss_example_sec_serv_aes_op(int mode, size_t length, unsigned char iv[16], const unsigned char *input, unsigned char *output)
|
||||
{
|
||||
if (length == 0 || iv == NULL || input == NULL || output == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (esp_cpu_get_curr_privilege_level() != ESP_CPU_S_MODE) {
|
||||
esp_rom_printf("Operation executing from illegal privilege level!\n");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
esp_rom_printf("TEE: Secure service call for AES-256-CBC operation\n");
|
||||
esp_rom_printf("TEE: In PROTECTED M-mode\n");
|
||||
|
||||
esp_aes_context ctx = {};
|
||||
ctx.key_bytes = AES_256_KEY_BYTES;
|
||||
ctx.key_in_hardware = 0;
|
||||
memcpy(ctx.key, key, ctx.key_bytes);
|
||||
|
||||
return (esp_err_t)esp_aes_crypt_cbc(&ctx, mode, length, iv, input, output);
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Perform AES-256-CBC encryption/decryption operation in TEE
|
||||
*
|
||||
* @param mode ESP_AES_ENCRYPT (1) for encryption, ESP_AES_DECRYPT (0) for decryption
|
||||
* @param length Length of input data in bytes
|
||||
* @param iv Initialization vector (16 bytes)
|
||||
* @param input Input buffer containing plaintext (for encryption) or ciphertext (for decryption)
|
||||
* @param output Output buffer for ciphertext (for encryption) or plaintext (for decryption)
|
||||
*
|
||||
* @return esp_err_t ESP_OK on success, appropriate error code on failure
|
||||
*/
|
||||
esp_err_t example_sec_serv_aes_op(int mode, size_t length, unsigned char iv[16], const unsigned char *input, unsigned char *output);
|
||||
@@ -0,0 +1,15 @@
|
||||
# tee_project.cmake file must be manually included in the project's top level CMakeLists.txt before project()
|
||||
# This ensures that the variables are set before TEE starts building
|
||||
|
||||
get_filename_component(directory "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE DIRECTORY)
|
||||
get_filename_component(name ${CMAKE_CURRENT_LIST_DIR} NAME)
|
||||
|
||||
# Append secure service table consisting of secure services
|
||||
idf_build_set_property(CUSTOM_SECURE_SERVICE_TBL ${CMAKE_CURRENT_LIST_DIR}/example.tbl APPEND)
|
||||
|
||||
# Append the directory of this component which is used by esp_tee component as
|
||||
# EXTRA_COMPONENT_DIRS
|
||||
idf_build_set_property(CUSTOM_SECURE_SERVICE_COMPONENT_DIR ${directory} APPEND)
|
||||
|
||||
# Append the name of the component so that esp_tee can include it in its COMPONENTS list
|
||||
idf_build_set_property(CUSTOM_SECURE_SERVICE_COMPONENT ${name} APPEND)
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "tee_main.c"
|
||||
INCLUDE_DIRS "")
|
||||
@@ -0,0 +1,64 @@
|
||||
/* ESP-TEE (Trusted Execution Environment) Example
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "aes/esp_aes.h"
|
||||
|
||||
#include "esp_tee.h"
|
||||
#include "secure_service_num.h"
|
||||
|
||||
#define BUF_SZ (16)
|
||||
|
||||
static const char *TAG = "example_tee_basic";
|
||||
|
||||
static const uint8_t expected_cipher[] = {
|
||||
0xee, 0x04, 0x9b, 0xee, 0x95, 0x6f, 0x25, 0x04,
|
||||
0x1e, 0x8c, 0xe4, 0x4e, 0x8e, 0x4e, 0x7a, 0xd3
|
||||
};
|
||||
|
||||
static const uint8_t nonce[IV_BYTES] = {[0 ... IV_BYTES - 1] = 0xFF};
|
||||
|
||||
/*
|
||||
* Example workflow:
|
||||
* 1. The REE initiates an AES operation request via the secure service call interface
|
||||
* 2. The TEE receives the request and performs encryption/decryption using AES-256-CBC mode
|
||||
* 3. The TEE uses a protected key that is only accessible within the secure environment
|
||||
* 4. The encrypted/decrypted result is returned to the non-secure world through an output buffer
|
||||
* provided in the secure service call
|
||||
*/
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "AES-256-CBC operations in TEE");
|
||||
|
||||
uint8_t plain_text[BUF_SZ] = {[0 ... BUF_SZ - 1] = 0x3A};
|
||||
uint8_t cipher_text[BUF_SZ] = {0};
|
||||
uint8_t decrypted_text[BUF_SZ] = {0};
|
||||
uint8_t iv[IV_BYTES] = {0};
|
||||
|
||||
memcpy(iv, nonce, sizeof(iv));
|
||||
uint32_t ret = esp_tee_service_call(6, SS_EXAMPLE_SEC_SERV_AES_OP, ESP_AES_ENCRYPT, sizeof(plain_text), iv, plain_text, cipher_text);
|
||||
if (ret != ESP_OK || memcmp(cipher_text, expected_cipher, sizeof(expected_cipher))) {
|
||||
ESP_LOGE(TAG, "Failed to encrypt data!");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "AES encryption successful!");
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Cipher text -");
|
||||
ESP_LOG_BUFFER_HEX_LEVEL(TAG, cipher_text, sizeof(cipher_text), ESP_LOG_INFO);
|
||||
|
||||
memcpy(iv, nonce, sizeof(iv));
|
||||
ret = esp_tee_service_call(6, SS_EXAMPLE_SEC_SERV_AES_OP, ESP_AES_DECRYPT, sizeof(cipher_text), iv, cipher_text, decrypted_text);
|
||||
if (ret != ESP_OK || memcmp(decrypted_text, plain_text, sizeof(plain_text))) {
|
||||
ESP_LOGE(TAG, "Failed to decrypt data!");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "AES decryption successful!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import logging
|
||||
import os
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.esp32c6
|
||||
@pytest.mark.generic
|
||||
def test_example_tee_basic(dut: Dut) -> None:
|
||||
# Logging example binary details
|
||||
binary_files = [
|
||||
('tee_basic.bin', '[REE] tee_basic_bin_size'),
|
||||
('esp_tee/esp_tee.bin', '[TEE] tee_basic_bin_size'),
|
||||
]
|
||||
for file_name, log_label in binary_files:
|
||||
binary_file = os.path.join(dut.app.binary_path, file_name)
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
logging.info('{}: {}KB'.format(log_label, bin_size // 1024))
|
||||
|
||||
# Start test
|
||||
dut.expect('AES-256-CBC operations in TEE', timeout=30)
|
||||
dut.expect('TEE: In PROTECTED M-mode', timeout=30)
|
||||
dut.expect('AES encryption successful!', timeout=30)
|
||||
dut.expect('ee 04 9b ee 95 6f 25 04 1e 8c e4 4e 8e 4e 7a d3', timeout=30)
|
||||
dut.expect('AES decryption successful!', timeout=30)
|
||||
@@ -0,0 +1,3 @@
|
||||
# Enabling TEE
|
||||
CONFIG_SECURE_ENABLE_TEE=y
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_TEE=y
|
||||
Reference in New Issue
Block a user