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 运行环境、安全存储和加密服务。 |
| REE | Rich Execution Environment ,通常指 Linux/Android Normal World。 |
| TA | Trusted Application,运行在 OP-TEE 中的可信应用。 |
| CA | Client Application,运行在 REE 用户态,通过 TEE Client API 访问 TA。 |
| ATF | ARM Trusted Firmware,负责 EL3 固件和 Secure Monitor 相关功能。 |
| SMC | Secure Monitor Call,Normal World 与 Secure World 之间的切换接口。 |
| TE | Trusted Engine,MTT E300 平台硬件安全引擎,提供硬件加速密码学和真随机数。 |
| xtest | OP-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 OS | Secure World (EL1S) | 提供 TEE Core、TA 运行框架、安全存储和加密服务。 |
| ATF | EL3 / Secure Monitor | 负责启动阶段加载 OP-TEE,运行时通过 SMC 完成 Normal World 与 Secure World 切换。 |
| Linux Kernel TEE driver | Normal World kernel | 向 REE 提供 /dev/tee0、/dev/teepriv0 设备节点。 |
| tee-supplicant | Normal World user space | 配合 OP-TEE 完成 REE FS 读写、TA 加载等需要 REE 协助的操作。 |
| libteec | Normal World user space | 提供 TEE Client API 供 CA 调用。 |
| CA | Normal World user space | 用户开发的 REE 应用,通过 TEE Client API 访问 TA。 |
| TA | Secure World user space | 用户开发的可信应用,实现敏感业务逻辑。 |
| xtest | Normal World user space | 执行 OP-TEE 功能和回归测试。 |
2.3 启动链路
Boot ROM -> Bootloader -> ATF (BL31) -> OP-TEE OS (BL32) -> Linux Kernel (BL33)
- Boot ROM 加载并启动 Bootloader。
- Bootloader 加载 ATF(BL31)、OP-TEE OS(BL32)和 Linux Kernel(BL33)。
- ATF 在启动阶段将 OP-TEE OS 作为 BL32 secure payload 初始化。
- ATF 跳转到 Linux Kernel,Linux 进入 Normal World 启动流程。
- Linux 启动后,TEE driver 初始化并与 OP-TEE 交换 capability 信息。
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_CreateEntryPoint | TA 首次加载时调用,用于全局初始化。 |
TA_DestroyEntryPoint | TA 卸载时调用,用于释放全局资源。 |
TA_OpenSessionEntryPoint | CA 打开 Session 时调用。 |
TA_CloseSessionEntryPoint | CA 关闭 Session 时调用。 |
TA_InvokeCommandEntryPoint | CA 调用 TA 命令时调用,根据 cmd_id 分发到具体处理函数。 |
3.2.2 TA 参数类型
CA 与 TA 之间通过 4 个参数(params[0] ~ params[3])传递数据,每个参数的类型由 param_types 指定:
| TA 侧类型 | CA 侧类型 | 说明 |
|---|---|---|
TEE_PARAM_TYPE_VALUE_INPUT | TEEC_VALUE_INPUT | 传入两个 32-bit 整数值(value.a、value.b)。 |
TEE_PARAM_TYPE_VALUE_OUTPUT | TEEC_VALUE_OUTPUT | 返回两个 32-bit 整数值。 |
TEE_PARAM_TYPE_VALUE_INOUT | TEEC_VALUE_INOUT | 传入并返回两个 32-bit 整数值。 |
TEE_PARAM_TYPE_MEMREF_INPUT | TEEC_MEMREF_TEMP_INPUT | 传入内存缓冲区。 |
TEE_PARAM_TYPE_MEMREF_OUTPUT | TEEC_MEMREF_TEMP_OUTPUT | 返回内存缓冲区。 |
TEE_PARAM_TYPE_MEMREF_INOUT | TEEC_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_VALUE 和 DEC_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_CreateEntryPoint、TA_DestroyEntryPoint、TA_OpenSessionEntryPoint 和 TA_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_DIR | TA 编译 | 指向 TA Dev Kit,用于查找 TA 头文件、libutee、构建脚本和签名脚本。 |
TEEC_EXPORT | CA 编译 | 指向 OP-TEE Client 导出目录,用于查找 tee_client_api.h 和 libteec。 |
CROSS_COMPILE | TA/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 |
| aes | AES 对称加密/解密(ECB、CBC、CTR 模式) | TEE_AllocateOperation, TEE_CipherUpdate |
| random | 安全随机数生成 | TEE_GenerateRandom |
| secure_storage | 安全存储读写删除 | TEE_CreatePersistentObject, TEE_ReadObjectData |
| acipher | RSA 密钥生成与加密 | TEE_GenerateKey, TEE_AsymmetricEncrypt |
| hotp | HMAC 一次性密码(RFC 4226) | TEE_MACInit, TEE_MACComputeFinal |
| plugins | TA 与 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 日志
按启动链路从前到后检查:
- 镜像集成:确认 ATF 已集成正确的 OP-TEE OS 镜像。
- 固件更新:确认固件已重新打包并烧录,设备当前启动的是新固件。
- 串口输出:确认串口号、波特率和日志级别配置正确,避免日志被输出到其他串口或被关闭。
- 安全内存配置:确认 ATF、Bootloader、Linux 设备树中的 secure memory 地址和大小配置一致。
5.2 Linux 下没有 /dev/tee0
按 Linux 初始化链路检查:
- OP-TEE 初始化:先确认启动日志中 OP-TEE OS 已成功初始化。
- SMC 转发:确认 ATF 能正确转发 Normal World 发起的 SMC 调用。
- 设备树节点:确认 Linux 设备树中 OP-TEE 节点存在,且
status为可用状态。 - 内核驱动配置:确认 Linux Kernel 已启用 OP-TEE driver,并检查内核日志中 TEE driver 的 probe 信息。
- 设备节点创建:确认
/dev/tee0、/dev/teepriv0是否由 devtmpfs 或 udev 正常创建。
5.3 xtest 失败
按从基础环境到具体用例的顺序检查:
- 基础设备状态:确认
/dev/tee0、/dev/teepriv0存在。 - 用户态服务:确认
tee-supplicant正在运行。 - 测试 TA 部署:确认 rootfs 包含
xtest依赖的测试 TA,且 TA 文件已部署到正确目录。 - 失败用例范围:记录失败用例编号,判断是否集中在安全存储、加密算法、RPMB 或 REE FS 相关用例。
- 外部依赖:若失败用例依赖 RPMB 或 REE FS,继续检查 RPMB key、eMMC 状态、REE 文件系统读写权限。
- 日志定位:查看串口日志和
tee-supplicant日志中的 TEE return code 与 origin 信息。
5.4 TA 加载失败
按 TA 查找、读取、校验、运行的顺序检查:
- UUID 一致性:确认 CA 使用的 UUID 与 TA UUID 一致。
- 文件命名:确认
.ta文件名为 TA UUID,例如<uuid>.ta。 - 部署路径:确认
.ta文件已部署到 OP-TEE TA 搜索路径。 - 文件权限:确认文件权限允许
tee-supplicant读取。 - 签名配置:确认 TA 使用与当前 OP-TEE OS 匹配的签名密钥和签名配置编 译。
- 工具链兼容性:确认 TA 使用与当前 OP-TEE OS 匹配的 TA Dev Kit 和工具链编译。
- 错误码定位:根据 CA 返回的
TEEC_Result和origin判断错误来自 CA、TEE driver、tee-supplicant 还是 OP-TEE OS。
5.5 安全存储数据丢失
按存储后端和密钥链路检查:
- 确认存储后端:先确认当前配置使用 REE FS 还是 RPMB FS。
- REE FS 检查:若使用 REE FS,确认
tee-supplicant正在运行,且 REE 文件系统可写、未被清空或回滚。 - RPMB FS 检查:若使用 RPMB FS,确认 RPMB key 已写入,eMMC 未更换,RPMB 分区可访问。
- 密钥链路检查:若更换过固件、HUK 配置、RPMB key 或存储介质,确认旧安全存储数据是否仍可被当前密钥派生链解密。
- 恢复策略:若密钥链路不兼容,旧安全存储数据通常无法直接恢复,应按业务策略重新初始化或迁移。
6. 限制与注意事项
- 本文档基于 MTT E300 平台当前 OP-TEE 配置编写,具体 SDK 发布包可能存在差异。
- BSP 打包、烧录和量产流程以用户收到的 SDK 发布说明为准。
- RPMB key、安全存储数据和设备唯一密钥应按用户安全策略管理,避免在调试环境和量产环境之间混用。
- 更换固件、HUK 配置、RPMB key 或存储介质前,应先评估安全存储数据的兼容性和迁移方案。
xtest通过代表基础 OP-TEE 功能可用,不等同于业务 TA 已完成安全评审。- 用户 TA/CA 的权限控制、密钥管理和敏感数据处理应由业务安全设计单独评审。
- 量产环境中应使用自定义 TA 签名密钥,不使用 SDK 默认密钥。

