2. TEE与OP-TEE基础
在移动终端、支付终端、车载控制器和物联网网关中,系统往往同时承载两类截然不同的任务:一类是界面、网络、多媒体等开放业务,另一类是密钥运算、生物特征比对、DRM 解密、安全启动校验等敏感操作。若把两者放在同一个执行环境中,任何一处应用漏洞都可能直接威胁密钥与身份凭证。TEE(Trusted Execution Environment,可信执行环境)正是为解决这一矛盾而提出的硬件级隔离方案:它与普通操作系统并存,却拥有独立的执行空间、内存与中断资源,只向普通世界暴露受控的调用接口。
一、TEE 的核心概念与安全目标
TEE 可以理解为处理器内部的一块“安全飞地”。它具备三个基本特征:隔离性——安全世界的代码与数据无法被普通世界直接读写;完整性——安全镜像在加载前需通过签名校验,运行中受硬件访问控制保护;可验证性——普通世界只能通过预先定义的命令入口请求服务,参数需经过检查。TEE 并不追求替代操作系统,而是把“必须可信”的最小功能收敛到安全侧,例如密钥管理、加解密、安全存储、可信 UI 和远程证明。
与之相对,REE(Rich Execution Environment,普通执行环境)运行 Linux、Android 等通用操作系统,负责业务逻辑与用户交互。REE 可以发起对 TEE 的请求,但不能读取 TEE 的内部状态。这种“普通世界请求、安全世界执行、结果受控返回”的模式,构成了后续所有 OP-TEE 通信工程的基础。
二、ARM TrustZone 架构:隔离如何落地
ARM TrustZone 是 TEE 在 ARM 平台上的典型硬件支撑。它并非两套物理 CPU,而是通过 安全状态位(NS bit) 将同一颗处理器的运行状态划分为 Secure World 与 Normal World。CPU 在任意时刻处于其中一种状态,配合总线侧的安全控制器,把内存、外设和中断也划分为安全与非安全属性。
关键机制包括:
- 安全监控模式(Monitor Mode):位于两种世界之间的切换枢纽,通过 SMC(Secure Monitor Call)指令进入,负责保存和恢复上下文。
- 地址空间控制器(TZASC):把 DRAM 划分为安全区与非安全区,阻止普通世界访问安全内存。
- 中断控制器(GIC)与 TZPC:区分安全中断与非安全中断,保护安全外设不被普通世界直接操作。
- MMU 与页表隔离:安全世界拥有独立页表,普通世界的地址映射无法覆盖安全区域。
因此,TrustZone 提供的是“硬件强制”的边界,而不是依赖软件自觉。OP-TEE 正是运行在 Secure World 中的可信操作系统,REE 侧的 Linux 内核与用户态程序则位于 Normal World。
三、OP-TEE 的组成与运行位置
OP-TEE 是开源的可信执行环境实现,通常由三部分协同工作:
| 组件 | 运行位置 | 主要职责 |
|---|---|---|
| OP-TEE OS | Secure World | 安全内核,负责 TA 加载、调度、内存与系统调用 |
| OP-TEE Client(libteec) | Normal World 用户态 | 提供 GP TEE Client API,封装会话与命令调用 |
| OP-TEE Linux 驱动 | Normal World 内核态 | 字符设备接口,完成 SMC 参数编组与共享内存映射 |
| TA(Trusted Application) | Secure World | 具体安全业务逻辑,按 UUID 被加载与调用 |
一次典型调用链为:CA 调用 TEEC_OpenSession 打开会话,再通过 TEEC_InvokeCommand 发起命令;libteec 将请求交给 Linux 驱动,驱动通过 SMC 陷入 Monitor Mode,最终由 OP-TEE OS 调度对应 TA 执行,结果沿原路返回。整个过程对 CA 而言像一次普通函数调用,但实际跨越了硬件隔离边界。
四、GlobalPlatform API 与安全世界/普通世界划分
GlobalPlatform 定义了两套互补接口:普通世界侧使用 TEE Client API,安全世界侧使用 TEE Internal Core API。前者负责上下文初始化、会话建立、命令调用与共享内存注册;后者为 TA 提供密码学、安全存储、时间、属性查询等能力。二者通过 UUID 和命令 ID 对齐,形成标准化的跨世界契约。
TEEC_Context ctx;
TEEC_Session sess;
TEEC_UUID uuid = TA_HELLO_WORLD_UUID;
uint32_t err;
err = TEEC_InitializeContext(NULL, &ctx);
err = TEEC_OpenSession(&ctx, &sess, &uuid,
TEEC_LOGIN_PUBLIC, NULL, NULL, NULL);
TEEC_Operation op = {0};
op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
TEEC_NONE, TEEC_NONE, TEEC_NONE);
op.params[0].value.a = 0x1234;
err = TEEC_InvokeCommand(&sess, CMD_INC_VALUE, &op, NULL);
TEEC_CloseSession(&sess);
TEEC_FinalizeContext(&ctx);
世界划分要点:普通世界负责“发起与展示”,安全世界负责“决策与密钥”。CA 不应假设自己能看到 TA 的内部数据;TA 也不应信任 CA 传入的指针,必须通过共享内存与参数类型做严格校验。
五、典型场景与常见误区
以安全支付为例:支付应用作为 CA 运行在 Android 用户态,它把交易金额、随机数和终端信息通过 TEEC_InvokeCommand 发给支付 TA;TA 在安全世界内完成密钥派生、交易签名,并只返回签名结果。即使 Android 被 root,攻击者也无法直接读取 TA 内存中的主密钥。
常见误区一:把 TEE 当成“更安全的 Linux”。TEE 资源有限,不适合运行复杂业务,TA 应保持小而专。
常见误区二:认为只要用了 OP-TEE 就自动安全。若 CA 与 TA 之间缺少参数校验、共享内存未正确注册,仍可能出现越权或数据泄露。
常见误区三:忽略世界切换开销。频繁 SMC 会带来明显延迟,批量命令与共享内存复用是常见优化手段。
复盘建议:排查 OP-TEE 通信问题时,先确认 /dev/tee0 是否存在、TA 是否已签名并放入 /lib/optee_armtz,再检查 UUID 与命令 ID 是否匹配,最后用 xtest 验证基础环境。多数“调用失败”并非密码学问题,而是会话未建立或参数类型不匹配。
理解 TEE 概念、TrustZone 隔离机制、OP-TEE 三组件分工以及 GlobalPlatform 双 API 契约,是后续编写 CA/TA、设计安全通信协议和进行安全调试的前提。只有先看清安全世界与普通世界的边界在哪里,才能正确决定哪些数据必须留在安全侧、哪些交互必须经过受控接口。