feat(esp_tee): Added examples demonstrating the ESP-TEE framework

This commit is contained in:
Laukik Hase
2024-11-12 17:03:54 +05:30
parent 909fd60d33
commit ad74c1c3c2
40 changed files with 1653 additions and 0 deletions
@@ -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)
+57
View File
@@ -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);
}
@@ -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