1. TEE 基础概念与架构
各位同学好,我是老周。做 TEE 这行快十年了,踩过的坑比写过的代码还多。今天咱们聊聊最基础的东西——TEE 到底是什么,它跟普通操作系统有啥区别,GlobalPlatform 那套规范怎么组织的,以及 TA、CA、TEE Kernel 这些核心组件各自扮演什么角色。
说实话,我刚入行时也一头雾水。那时候文档少,全靠啃 GlobalPlatform 的 PDF。现在条件好多了,但基础概念不扎实,后面做接口适配一定会出问题。所以这一章,咱们把地基打牢。
1.1 什么是 TEE
TEE,全称 Trusted Execution Environment,中文叫可信执行环境。说白了,它就是在主处理器上隔离出一个安全区域,专门跑敏感代码和数据。
你想想看,手机里存着指纹、支付密钥、人脸数据。这些东西如果直接暴露在 Android 或 Linux 下,风险太大了。TEE 就是给这些敏感数据盖了个「保险箱」。
核心特征:
- 隔离性——与普通操作系统硬件隔离,REE 无法直接访问 TEE 内存
- 可信根——基于硬件安全启动链,从 ROM 代码开始逐级验证
- 安全存储——密钥和敏感数据加密后存储在 TEE 专属区域
- 安全通道——TA 与 CA 之间通过共享内存 + 加密方式通信
我在项目中遇到过最典型的场景:某厂商的支付应用在 REE 侧被注入攻击,黑客拿到了用户输入的密码。后来迁移到 TEE 方案,所有密码输入和加密运算都在 TEE 内完成,REE 侧只看到加密后的数据。问题彻底解决。
1.2 TEE 与 REE 的区别
REE 就是 Rich Execution Environment,咱们平时用的 Android、Linux、iOS 都属于 REE。它功能丰富、生态庞大,但安全性不够。
两者的对比,我习惯用这张表来跟团队讲:
| 维度 | REE(普通环境) | TEE(可信环境) |
|---|---|---|
| 操作系统 | Android / Linux / iOS | Trusty / OP-TEE / QSEE / Kinibi |
| 安全等级 | 低,易被 Root / 注入攻击 | 高,硬件隔离 + 安全启动 |
| 功能丰富度 | 极高,支持所有应用 | 有限,只运行安全关键服务 |
| 内存访问 | 可访问全部内存(除 TEE 保留区) | 只能访问 TEE 专属内存 |
| 外设访问 | 直接访问所有外设 | 需通过安全监控器仲裁 |
| 典型应用 | 社交、游戏、办公 | 支付、DRM、指纹认证、eSIM |
嗯,这里要注意:REE 和 TEE 不是「二选一」的关系,而是「共存」的关系。现代 SoC 上,两者同时运行,通过 ARM TrustZone 或 Intel SGX 这类硬件技术隔离。
我的经验:做接口适配时,最容易出问题的地方就是 REE 和 TEE 之间的共享内存管理。我曾经因为没对齐缓存一致性,导致 TA 读到的数据全是乱码。排查了两天才发现是 REE 侧写了数据但没做 cache flush。
1.3 GlobalPlatform TEE 架构
GlobalPlatform(GP)是制定 TEE 标准的组织。目前主流的 TEE OS——OP-TEE、Trusty、QSEE——都遵循 GP 规范。说白了,GP 定义了 TEE 的「游戏规则」。
GP TEE 架构分为三层:
- REE 侧——客户端应用(CA)运行在这里,通过 TEE Client API 发起安全请求
- 通信层——通过共享内存 + SMC(安全监控调用)实现 REE 与 TEE 的数据交换
- TEE 侧——可信应用(TA)运行在 TEE OS 之上,处理安全逻辑
下面这张图是我自己画的 GP 架构概览,你一看就明白:
这张图我建议你保存下来。每次做接口适配时,对照着看,就知道当前在操作哪一层。
1.4 TEE 核心组件详解
1.4.1 CA(客户端应用)
CA 运行在 REE 侧,是用户直接接触的部分。比如支付宝里的指纹支付模块、视频 App 的 DRM 解密模块,都属于 CA。
CA 通过 TEE Client API 与 TEE 通信。典型的调用流程:
// CA 侧伪代码
TEEC_Context context;
TEEC_Session session;
TEEC_Operation operation;
// 1. 初始化上下文
TEEC_InitializeContext(NULL, &context);
// 2. 打开与 TA 的会话
TEEC_OpenSession(&context, &session, &ta_uuid,
TEEC_LOGIN_PUBLIC, NULL, NULL, NULL);
// 3. 调用 TA 中的命令
operation.paramTypes = TEEC_PARAM_TYPES(
TEEC_MEMREF_TEMP_INPUT, TEEC_MEMREF_TEMP_OUTPUT,
TEEC_NONE, TEEC_NONE);
operation.params[0].tmpref.buffer = input_data;
operation.params[0].tmpref.size = input_size;
operation.params[1].tmpref.buffer = output_data;
operation.params[1].tmpref.size = &output_size;
TEEC_InvokeCommand(&session, CMD_ENCRYPT, &operation, NULL);
// 4. 关闭会话
TEEC_CloseSession(&session);
TEEC_FinalizeContext(&context);
避坑指南:我曾经在项目中遇到 CA 调用 TA 时一直返回 TEEC_ERROR_BAD_PARAMETERS。查了半天,发现是共享内存的物理地址没有对齐到 4KB 边界。GP 规范要求共享内存缓冲区必须页对齐,否则底层 SMC 驱动会直接拒绝。
1.4.2 TA(可信应用)
TA 运行在 TEE 侧,是真正处理敏感数据的程序。TA 使用 TEE Internal API,不能直接调用 Linux 系统调用。
TA 的生命周期管理由 TEE Kernel 负责。一个典型的 TA 入口函数:
// TA 侧入口
TEE_Result TA_CreateEntryPoint(void)
{
// 初始化 TA 内部资源
DMSG("TA CreateEntryPoint called");
return TEE_SUCCESS;
}
TEE_Result TA_OpenSessionEntryPoint(
uint32_t param_types,
TEE_Param params[4],
void **session_ctx)
{
// 验证 CA 身份,分配会话上下文
DMSG("Session opened");
return TEE_SUCCESS;
}
TEE_Result TA_InvokeCommandEntryPoint(
void *session_ctx,
uint32_t cmd_id,
uint32_t param_types,
TEE_Param params[4])
{
// 根据 cmd_id 分发处理
switch (cmd_id) {
case CMD_ENCRYPT:
return handle_encrypt(params, param_types);
case CMD_DECRYPT:
return handle_decrypt(params, param_types);
default:
return TEE_ERROR_BAD_PARAMETERS;
}
}
嗯,这里要注意:TA 不能做 printf 调试。我早期做 TA 开发时,全靠 DMSG 宏打印日志,然后通过 TEE 的日志系统拉出来看。后来习惯了,反而觉得这种受限环境让代码更严谨。
1.4.3 TEE Kernel
TEE Kernel 是 TEE 的操作系统内核。它负责:
- 任务调度——管理多个 TA 的并发执行
- 内存管理——隔离 TA 之间的内存空间
- 中断处理——处理来自 REE 的 SMC 请求
- 安全存储——提供加密文件系统接口
- 密码学服务——硬件加速加解密操作
市面上主流的 TEE Kernel 有:
| TEE OS | 厂商 | 开源 | 典型平台 |
|---|---|---|---|
| OP-TEE | Linaro / 社区 | 是(BSD 许可) | ARM 平台,广泛用于嵌入式 |
| Trusty | 是(Apache 2.0) | Pixel 手机、Android 设备 | |
| QSEE | Qualcomm | 否 | 高通骁龙平台 |
| Kinibi | Trustonic | 否 | 三星、华为部分机型 |
我的建议:学习 TEE 接口适配,首选 OP-TEE。它是开源的,文档齐全,社区活跃。我当年就是从 OP-TEE 入门的,先在 QEMU 上跑起来,再移植到开发板。这条路最稳。
1.5 小结
这一章咱们把 TEE 的基础骨架搭起来了。你记住三句话:
- TEE 是 REE 旁边的「保险箱」,硬件隔离是根本
- GP 规范定义了 CA ↔ TA 的通信标准,所有主流 TEE OS 都遵循
- CA 在 REE 侧发请求,TA 在 TEE 侧处理,TEE Kernel 负责调度和隔离