跳到主要内容

OP-TEE

本文档面向使用 MTT E300 BSP/SDK 的用户,介绍 OP-TEE 在 MTT E300 平台上的功能、架构和 TA 开发方法。读者应具备 Linux 开发环境、交叉编译和 BSP/SDK 使用基础。

1. 概述

OP-TEE(Open Portable Trusted Execution Environment)是运行在 ARM TrustZone Secure World 中的开源可信执行环境。MTT E300 平台基于 OP-TEE 为你提供以下安全能力:

  • 可信应用运行环境:在 Secure World 中承载 Trusted Application(TA),与 Normal World 的 Linux/Android 隔离运行。
  • 安全存储:提供基于 REE FS 和 RPMB 的安全存储后端,保护敏感数据不被 Normal World 直接读取。
  • 密码学服务:基于 mbedTLS 提供 AES、RSA、ECC、Hash/HMAC 等标准算法,以及 SM2/SM3/SM4 国密算法,配合硬件 Trusted Engine 加速。
  • 安全启动支持:作为 ATF BL32 加载,参与 ARM TrustZone 安全启动链。
  • TA/CA 开发框架:提供完整的 TA Internal API 和 CA Client API,支持用户开发自定义可信应用。

1.1 术语

术语说明
OP-TEE OS运行在 Secure World 的 TEE OS,提供 TA 运行环境、安全存储和加密服务。
REERich Execution Environment,通常指 Linux/Android Normal World。
TATrusted Application,运行在 OP-TEE 中的可信应用。
CAClient Application,运行在 REE 用户态,通过 TEE Client API 访问 TA。
ATFARM Trusted Firmware,负责 EL3 固件和 Secure Monitor 相关功能。
SMCSecure Monitor Call,Normal World 与 Secure World 之间的切换接口。
TETrusted Engine,MTT E300 平台硬件安全引擎,提供硬件加速密码学和真随机数。
xtestOP-TEE 测试程序,用于验证 TEE Client API、TA 加载和安全服务。

2. 软件架构

2.1 系统架构

MTT E300 平台 OP-TEE 的软件架构如下:

+---------------------------------------------------------------+
| Normal World (REE) |
| |
| +----------------+ +----------------+ +-------------------+ |
| | CA Application | | xtest | | tee-supplicant | |
| +-------+--------+ +-------+--------+ +---------+---------+ |
| | | | |
| +-------+-------------------+---------------------+---------+ |
| | TEE Client API (libteec) | |
| +-----------------------------+-----------------------------+ |
| | |
| +-----------------------------+-----------------------------+ |
| | Linux Kernel TEE Driver | |
| +-----------------------------------------------------------+ |
+---------------------------------------------------------------+
| SMC
+---------------------------------------------------------------+
| Secure World (TEE) |
| |
| +-----------------------------------------------------------+ |
| | OP-TEE OS | |
| | | |
| | +--------------+ +--------------+ +-------------------+ | |
| | | TEE Core | | TA Framework | | Crypto Service | | |
| | +--------------+ +--------------+ +---------+---------+ | |
| | +--------------+ +--------------+ | | |
| | | Secure Store | | TA Instance | +---------+---------+ | |
| | | REE/RPMB | | (TA Runtime) | | Trusted Engine | | |
| | +--------------+ +--------------+ | (TE) | | |
| | +--------------+ +--------------+ +-------------------+ | |
| +-----------------------------------------------------------+ |
+---------------------------------------------------------------+
| SMC
+---------------------------------------------------------------+
| ARM Trusted Firmware (ATF) |
| EL3 / Secure Monitor |
+---------------------------------------------------------------+

2.2 组件说明

组件运行环境作用
OP-TEE OSSecure World (EL1S)提供 TEE Core、TA 运行框架、安全存储和加密服务。
ATFEL3 / Secure Monitor负责启动阶段加载 OP-TEE,运行时通过 SMC 完成 Normal World 与 Secure World 切换。
Linux Kernel TEE driverNormal World kernel向 REE 提供 /dev/tee0/dev/teepriv0 设备节点。
tee-supplicantNormal World user space配合 OP-TEE 完成 REE FS 读写、TA 加载等需要 REE 协助的操作。
libteecNormal World user space提供 TEE Client API 供 CA 调用。
CANormal World user space用户开发的 REE 应用,通过 TEE Client API 访问 TA。
TASecure World user space用户开发的可信应用,实现敏感业务逻辑。
xtestNormal World user space执行 OP-TEE 功能和回归测试。

2.3 启动链路

Boot ROM -> Bootloader -> ATF (BL31) -> OP-TEE OS (BL32) -> Linux Kernel (BL33)
  1. Boot ROM 加载并启动 Bootloader。
  2. Bootloader 加载 ATF(BL31)、OP-TEE OS(BL32)和 Linux Kernel(BL33)。
  3. ATF 在启动阶段将 OP-TEE OS 作为 BL32 secure payload 初始化。
  4. ATF 跳转到 Linux Kernel,Linux 进入 Normal World 启动流程。
  5. Linux 启动后,TEE driver 初始化并与 OP-TEE 交换 capability 信息。
  6. tee-supplicant 启动,完成 OP-TEE 用户态服务就绪。

2.4 内存布局

MTT E300 平台 OP-TEE 的安全内存布局:

0x80100000 +----------------------------------+
| TEE Core (TEE_RAM) |
| OP-TEE OS code and data |
+----------------------------------+
| TA RAM |
| TA instance runtime memory |
+----------------------------------+
0x80F00000 +----------------------------------+
| Shared Memory (SHM) |
| REE/TEE shared buffer |
0x81100000 +----------------------------------+

3. TA 开发

3.1 TA 与 CA 的关系

TA(Trusted Application)运行在 OP-TEE Secure World 中,CA(Client Application)运行在 Normal World 中。CA 通过 TEE Client API 向 TA 发起请求,TA 通过 TEE Internal Core API 处理请求并返回结果,整个过程由 OP-TEE OS 和 ATF 保证安全隔离。

+----------------------+ +-------------------+
| CA (Normal World) | | TA (Secure World)|
| | TEEC_OpenSession | |
| TEEC_InitializeCtx |--------------------->| TA_OpenSession |
| TEEC_OpenSession | TEEC_InvokeCommand | |
| TEEC_InvokeCommand |--------------------->| TA_InvokeCommand |
| TEEC_CloseSession | TEEC_CloseSession | |
| TEEC_FinalizeCtx |--------------------->| TA_CloseSession |
+----------------------+ +-------------------+

3.2 TA 开发概述

3.2.1 TA 入口函数

每个 TA 通常需要实现以下 5 个入口函数(OP-TEE 提供弱默认实现,实际项目按需覆盖):

入口函数说明
TA_CreateEntryPointTA 首次加载时调用,用于全局初始化。
TA_DestroyEntryPointTA 卸载时调用,用于释放全局资源。
TA_OpenSessionEntryPointCA 打开 Session 时调用。
TA_CloseSessionEntryPointCA 关闭 Session 时调用。
TA_InvokeCommandEntryPointCA 调用 TA 命令时调用,根据 cmd_id 分发到具体处理函数。

3.2.2 TA 参数类型

CA 与 TA 之间通过 4 个参数(params[0] ~ params[3])传递数据,每个参数的类型由 param_types 指定:

TA 侧类型CA 侧类型说明
TEE_PARAM_TYPE_VALUE_INPUTTEEC_VALUE_INPUT传入两个 32-bit 整数值(value.avalue.b)。
TEE_PARAM_TYPE_VALUE_OUTPUTTEEC_VALUE_OUTPUT返回两个 32-bit 整数值。
TEE_PARAM_TYPE_VALUE_INOUTTEEC_VALUE_INOUT传入并返回两个 32-bit 整数值。
TEE_PARAM_TYPE_MEMREF_INPUTTEEC_MEMREF_TEMP_INPUT传入内存缓冲区。
TEE_PARAM_TYPE_MEMREF_OUTPUTTEEC_MEMREF_TEMP_OUTPUT返回内存缓冲区。
TEE_PARAM_TYPE_MEMREF_INOUTTEEC_MEMREF_TEMP_INOUT传入并返回内存缓冲区。

3.2.3 TA UUID

每个 TA 通过 UUID 唯一标识。CA 使用同一 UUID 打开 TA Session。编译时 UUID 同时作为 .ta 文件名。

3.3 TA Dev Kit

TA 不能直接使用普通用户态的 libc 或系统调用,需要使用 OP-TEE 提供的 TA Dev Kit 完成编译、链接和签名。MTT E300 SDK 随包提供 export-ta_arm64 目录,用户开发 TA 时主要依赖其中的头文件、库文件和构建脚本。

TA Dev Kit 目录通常包含:

export-ta_arm64/
├── include/ # TA API 头文件
├── lib/ # 预编译库 (libutee.a, libutils.a, libmbedtls.a, libdl.a)
├── keys/ # TA 签名密钥
├── mk/ # 构建系统 Makefile (ta_dev_kit.mk 等)
├── scripts/ # 签名脚本 (sign_encrypt.py)
└── src/ # TA 头文件模板 (user_ta_header.c, ta.ld.S)

具体路径以 SDK 发布包目录结构为准。TA 工程的 Makefile 只需要设置 TA UUID、交叉编译器和 TA_DEV_KIT_DIR,再包含 $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk,即可复用 SDK 提供的构建流程。

TA 编译完成后会生成已签名的 .ta 文件。SDK 提供默认签名密钥,用户也可在 TA Makefile 中指定自定义签名密钥:

TA_SIGN_KEY = /path/to/custom_key.pem
注意

量产环境中应使用自定义签名密钥,并妥善保管私钥。所有使用同一密钥签名的 TA 可以互相访问对方的安全存储数据。

3.4 Hello World 示例

以下以 optee-examples/hello_world 为例,展示一个 TA/CA 程序的核心结构和关键源码。

3.4.1 目录结构

hello_world/
├── ta/
│ ├── Makefile
│ ├── hello_world_ta.c # TA 实现
│ └── include/
│ └── hello_world_ta.h # TA 命令和 UUID 定义
├── host/
│ ├── Makefile
│ └── main.c # CA 实现
└── Makefile # 顶层 Makefile

3.4.2 共享头文件

共享头文件只需定义 TA UUID 和命令 ID,供 TA 与 CA 使用:

#define TA_HELLO_WORLD_UUID \
{ 0x8aaaf200, 0x2450, 0x11e4, \
{ 0xab, 0xe2, 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }

#define TA_HELLO_WORLD_CMD_INC_VALUE 0
#define TA_HELLO_WORLD_CMD_DEC_VALUE 1

3.4.3 TA 实现

TA 侧主要实现 Session 生命周期入口和命令分发。TA_InvokeCommandEntryPoint 是 CA 调用 TEEC_InvokeCommand 后进入 TA 的命令处理入口,通常根据 cmd_id 分发到具体命令处理函数,并通过 param_types 校验 params 参数类型。

下面示例展示 INC_VALUEDEC_VALUE 两个命令的核心逻辑:

static TEE_Result inc_value(uint32_t param_types, TEE_Param params[4])
{
if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT,
TEE_PARAM_TYPE_NONE,
TEE_PARAM_TYPE_NONE,
TEE_PARAM_TYPE_NONE))
return TEE_ERROR_BAD_PARAMETERS;

params[0].value.a++;
return TEE_SUCCESS;
}

static TEE_Result dec_value(uint32_t param_types, TEE_Param params[4])
{
if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT,
TEE_PARAM_TYPE_NONE,
TEE_PARAM_TYPE_NONE,
TEE_PARAM_TYPE_NONE))
return TEE_ERROR_BAD_PARAMETERS;

params[0].value.a--;
return TEE_SUCCESS;
}

TEE_Result TA_InvokeCommandEntryPoint(void *session_ctx,
uint32_t cmd_id,
uint32_t param_types,
TEE_Param params[4])
{
(void)session_ctx;

switch (cmd_id) {
case TA_HELLO_WORLD_CMD_INC_VALUE:
return inc_value(param_types, params);
case TA_HELLO_WORLD_CMD_DEC_VALUE:
return dec_value(param_types, params);
default:
return TEE_ERROR_NOT_SUPPORTED;
}
}

TA_CreateEntryPointTA_DestroyEntryPointTA_OpenSessionEntryPointTA_CloseSessionEntryPoint 可根据业务初始化、清理和 Session 管理需求实现。

3.4.4 CA 实现

CA 的核心流程是初始化 Context、打开 Session、调用 TA 命令并释放资源:

TEEC_Context ctx;
TEEC_Session session;
TEEC_Operation op;
TEEC_UUID uuid = TA_HELLO_WORLD_UUID;
uint32_t origin;
TEEC_Result res;

res = TEEC_InitializeContext(NULL, &ctx);
res = TEEC_OpenSession(&ctx, &session, &uuid,
TEEC_LOGIN_PUBLIC, NULL, NULL, &origin);

memset(&op, 0, sizeof(op));
op.params[0].value.a = 42;
op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT,
TEEC_NONE, TEEC_NONE, TEEC_NONE);

res = TEEC_InvokeCommand(&session, TA_HELLO_WORLD_CMD_INC_VALUE, &op, &origin);
printf("42 + 1 = %u\n", op.params[0].value.a);

TEEC_CloseSession(&session);
TEEC_FinalizeContext(&ctx);

实际项目中应检查每个 TEE Client API 的返回值,并根据 origin 判断错误来源。

3.4.5 TA Makefile

ta/Makefile

BINARY = 8aaaf200-2450-11e4-abe2-0002a5d5c51b

CROSS_COMPILE ?= aarch64-linux-gnu-
export CROSS_COMPILE

CFG_TEE_TA_LOG_LEVEL ?= 2
CPPFLAGS += -DCFG_TEE_TA_LOG_LEVEL=$(CFG_TEE_TA_LOG_LEVEL)

-include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk

3.4.6 编译与部署

编译变量说明

编译 TA 和 CA 依赖不同的 SDK 导出目录:

变量用途说明
TA_DEV_KIT_DIRTA 编译指向 TA Dev Kit,用于查找 TA 头文件、libutee、构建脚本和签名脚本。
TEEC_EXPORTCA 编译指向 OP-TEE Client 导出目录,用于查找 tee_client_api.hlibteec
CROSS_COMPILETA/CA 编译指向 AArch64 交叉编译器前缀。

其中,TA_DEV_KIT_DIR 是 TA 编译必需的;TEEC_EXPORT 是 CA 编译必需的。编译完整 optee-examples 示例时,通常需要同时设置这两个变量。

编译

export TA_DEV_KIT_DIR=<SDK路径>/export-ta_arm64 \
TEEC_EXPORT=<SDK路径>/optee-client \
CROSS_COMPILE=aarch64-linux-gnu-

cd optee-examples/hello_world
make

编译成功后在 out/ta/ 下生成 8aaaf200-2450-11e4-abe2-0002a5d5c51b.ta,在 out/ca/ 下生成 CA 可执行文件。

部署

.ta 文件复制到设备 rootfs 中的 TA 搜索路径(通常为 /lib/optee_armtz/,具体以 SDK 发布包为准),确保 tee-supplicant 已启动,然后在设备上运行 CA 程序。

3.5 其他示例程序

SDK 的 optee-examples/ 目录还提供以下示例,覆盖更多 OP-TEE API 场景。MTT E300 rootfs 中已预置对应 CA 程序,可在设备端通过 optee_example_* 命令直接调用:

示例说明核心 TA API
hello_world基本 TA/CA 值参数通信TA_InvokeCommandEntryPoint
aesAES 对称加密/解密(ECB、CBC、CTR 模式)TEE_AllocateOperation, TEE_CipherUpdate
random安全随机数生成TEE_GenerateRandom
secure_storage安全存储读写删除TEE_CreatePersistentObject, TEE_ReadObjectData
acipherRSA 密钥生成与加密TEE_GenerateKey, TEE_AsymmetricEncrypt
hotpHMAC 一次性密码(RFC 4226)TEE_MACInit, TEE_MACComputeFinal
pluginsTA 与 REE 插件通信tee_invoke_supp_plugin

4. 功能验证

4.1 启动检查

设备启动后,在 Linux 用户态检查:

# 检查 TEE 设备节点
ls -l /dev/tee0 /dev/teepriv0

# 检查 tee-supplicant 运行状态
pgrep -a tee-supplicant

# systemd 环境
systemctl status tee-supplicant

正常状态应存在 /dev/tee0/dev/teepriv0 设备节点,且 tee-supplicant 进程在运行。

4.2 示例程序验证

rootfs 中预置了 optee_example_* 示例程序,可用于快速验证 TA 加载、CA/TA 通信和常用 TEE API 功能:

optee_example_hello_world
optee_example_aes
optee_example_random
optee_example_secure_storage
optee_example_acipher
optee_example_hotp
optee_example_plugins

如果示例程序无法运行,请优先检查 /dev/tee0/dev/teepriv0 设备节点、tee-supplicant 状态以及对应 .ta 文件是否已部署到 TA 搜索路径。

4.3 xtest 验证

若 SDK/rootfs 中已包含 xtest,可执行:

# 执行基础用例
xtest 1001

# 执行全部测试
xtest

测试通过时输出中应显示错误数为 0。完整 xtest 用例较多,若测试失败,请记录失败用例编号、TEE return code、串口日志和 tee-supplicant 日志。

5. 常见问题与排障

5.1 启动无 OP-TEE 日志

按启动链路从前到后检查:

  1. 镜像集成:确认 ATF 已集成正确的 OP-TEE OS 镜像。
  2. 固件更新:确认固件已重新打包并烧录,设备当前启动的是新固件。
  3. 串口输出:确认串口号、波特率和日志级别配置正确,避免日志被输出到其他串口或被关闭。
  4. 安全内存配置:确认 ATF、Bootloader、Linux 设备树中的 secure memory 地址和大小配置一致。

5.2 Linux 下没有 /dev/tee0

按 Linux 初始化链路检查:

  1. OP-TEE 初始化:先确认启动日志中 OP-TEE OS 已成功初始化。
  2. SMC 转发:确认 ATF 能正确转发 Normal World 发起的 SMC 调用。
  3. 设备树节点:确认 Linux 设备树中 OP-TEE 节点存在,且 status 为可用状态。
  4. 内核驱动配置:确认 Linux Kernel 已启用 OP-TEE driver,并检查内核日志中 TEE driver 的 probe 信息。
  5. 设备节点创建:确认 /dev/tee0/dev/teepriv0 是否由 devtmpfs 或 udev 正常创建。

5.3 xtest 失败

按从基础环境到具体用例的顺序检查:

  1. 基础设备状态:确认 /dev/tee0/dev/teepriv0 存在。
  2. 用户态服务:确认 tee-supplicant 正在运行。
  3. 测试 TA 部署:确认 rootfs 包含 xtest 依赖的测试 TA,且 TA 文件已部署到正确目录。
  4. 失败用例范围:记录失败用例编号,判断是否集中在安全存储、加密算法、RPMB 或 REE FS 相关用例。
  5. 外部依赖:若失败用例依赖 RPMB 或 REE FS,继续检查 RPMB key、eMMC 状态、REE 文件系统读写权限。
  6. 日志定位:查看串口日志和 tee-supplicant 日志中的 TEE return code 与 origin 信息。

5.4 TA 加载失败

按 TA 查找、读取、校验、运行的顺序检查:

  1. UUID 一致性:确认 CA 使用的 UUID 与 TA UUID 一致。
  2. 文件命名:确认 .ta 文件名为 TA UUID,例如 <uuid>.ta
  3. 部署路径:确认 .ta 文件已部署到 OP-TEE TA 搜索路径。
  4. 文件权限:确认文件权限允许 tee-supplicant 读取。
  5. 签名配置:确认 TA 使用与当前 OP-TEE OS 匹配的签名密钥和签名配置编译。
  6. 工具链兼容性:确认 TA 使用与当前 OP-TEE OS 匹配的 TA Dev Kit 和工具链编译。
  7. 错误码定位:根据 CA 返回的 TEEC_Resultorigin 判断错误来自 CA、TEE driver、tee-supplicant 还是 OP-TEE OS。

5.5 安全存储数据丢失

按存储后端和密钥链路检查:

  1. 确认存储后端:先确认当前配置使用 REE FS 还是 RPMB FS。
  2. REE FS 检查:若使用 REE FS,确认 tee-supplicant 正在运行,且 REE 文件系统可写、未被清空或回滚。
  3. RPMB FS 检查:若使用 RPMB FS,确认 RPMB key 已写入,eMMC 未更换,RPMB 分区可访问。
  4. 密钥链路检查:若更换过固件、HUK 配置、RPMB key 或存储介质,确认旧安全存储数据是否仍可被当前密钥派生链解密。
  5. 恢复策略:若密钥链路不兼容,旧安全存储数据通常无法直接恢复,应按业务策略重新初始化或迁移。

6. 限制与注意事项

  • 本文档基于 MTT E300 平台当前 OP-TEE 配置编写,具体 SDK 发布包可能存在差异。
  • BSP 打包、烧录和量产流程以用户收到的 SDK 发布说明为准。
  • RPMB key、安全存储数据和设备唯一密钥应按用户安全策略管理,避免在调试环境和量产环境之间混用。
  • 更换固件、HUK 配置、RPMB key 或存储介质前,应先评估安全存储数据的兼容性和迁移方案。
  • xtest 通过代表基础 OP-TEE 功能可用,不等同于业务 TA 已完成安全评审。
  • 用户 TA/CA 的权限控制、密钥管理和敏感数据处理应由业务安全设计单独评审。
  • 量产环境中应使用自定义 TA 签名密钥,不使用 SDK 默认密钥。