4. OP-TEE安全存储架构

OP-TEE 的安全存储并不是单一模块,而是由标准接口、规范约束、TEE 内部组件和底层文件系统共同构成的分层体系。理解这一架构,关键在于把“应用看到的 API”“规范定义的对象模型”“OP-TEE 内部实现组件”以及“最终落盘的文件结构”四者串起来。只有看清数据从 TA 调用到安全世界落盘的完整路径,才能在开发与排障中准确定位问题。

一、核心原理:三层接口与一条数据通路

从调用者视角看,安全存储的入口是 TEE Internal Core API。TA 通过 TEE_OpenPersistentObject、TEE_ReadObjectData、TEE_WriteObjectData、TEE_CloseAndDeletePersistentObject 等函数访问持久化对象。这些 API 由 GlobalPlatform(GP)定义,属于 TEE 内部核心 API 的一部分,屏蔽了底层存储介质差异。

从规范视角看,GP 安全存储规范定义了持久化对象的抽象模型:对象由 Object ID、Object Type、Data、MetaData 等组成,并规定访问控制、完整性保护、原子性、抗回滚等安全属性。规范还区分了可信存储与普通文件系统,要求数据在离开安全世界前必须加密并做完整性校验。

从实现视角看,OP-TEE 存储组件把上述 API 与规范落地。核心组件包括:tee_ta_manager 负责 TA 上下文管理,tee_obj 管理对象句柄,tee_pobj 表示持久化对象,tee_fs 提供安全文件系统抽象,tee_fs_dirfile 管理目录与文件映射,最终由 tee_fs_rpc 通过 RPC 调用 Normal World 的文件系统完成实际读写。

数据通路可以概括为:TA 调用 TEE Internal Core API → tee_obj/tee_pobj 对象层 → tee_fs 安全文件系统 → tee_fs_dirfile 目录索引 → tee_fs_rpc 跨世界调用 → Normal World 文件系统落盘。每一层都承担不同的安全职责,缺一不可。
OP-TEE 安全存储分层架构与数据通路 TA 应用层 调用 TEE Internal Core API:Open / Read / Write / Close / Delete Persistent Object GP 安全存储规范层 对象模型:Object ID / Type / Data / MetaData;访问控制、完整性、原子性、抗回滚 OP-TEE 存储组件层 tee_obj 对象句柄 tee_pobj 持久对象 tee_fs 安全文件系统 tee_fs_dirfile 目录索引 跨世界 RPC 与落盘层 tee_fs_rpc → Normal World 文件系统 → /data/tee/ 下的 block、dirf.db、对象文件 安全边界:加密与完整性校验在安全世界完成,Normal World 仅看到密文与元数据

二、方法流程:一次安全写操作的完整路径

以 TA 写入一个持久化对象为例,流程可拆解为以下步骤:

  1. 创建对象句柄:TA 调用 TEE_OpenPersistentObject,传入 Object ID、存储类型和访问标志。OP-TEE 在 tee_obj 中分配句柄,并关联 tee_pobj。
  2. 定位文件:tee_fs 根据 Object ID 计算文件名,通过 tee_fs_dirfile 查询目录索引,确定对象对应的 block 编号。
  3. 加密与完整性保护:写入数据前,OP-TEE 使用 TA 的密钥对数据加密,并生成完整性校验值(如 HMAC)。密钥由 TEE 内部密钥管理派生,不暴露给 Normal World。
  4. RPC 落盘:tee_fs_rpc 通过共享内存与 Normal World 通信,请求写入指定 block。Normal World 只负责搬运密文,无法解密或篡改而不被发现。
  5. 更新目录索引:写入完成后,tee_fs_dirfile 更新 dirf.db,记录对象与 block 的映射关系,保证后续可检索。
  6. 关闭与提交:TA 调用 TEE_ClosePersistentObject,OP-TEE 释放句柄并确保数据已持久化。
读操作与写操作路径对称,但多了一步完整性校验:读取 block 后先验证 HMAC,校验失败则返回 TEE_ERROR_CORRUPT_OBJECT,防止被篡改的数据进入 TA。

三、文件结构:安全存储在磁盘上的形态

OP-TEE 安全存储在 Normal World 的文件系统中通常位于 /data/tee/ 目录下。其典型结构如下:

/data/tee/
├── dirf.db              # 目录索引数据库,记录对象与 block 映射
├── 0/                   # 按 TA UUID 或存储类型划分的子目录
│   ├── block0001.bin    # 加密后的数据块
│   ├── block0002.bin
│   └── ...
├── 1/
│   └── ...
└── tee_fs_private/      # 私有数据与元数据

其中 dirf.db 是安全存储的“目录树”,它本身也受完整性保护。每个 blockXXXX.bin 对应一个数据块,块内包含加密后的对象数据和校验信息。对象可能跨多个 block,由目录索引串联。理解这一结构,有助于在排障时判断是索引损坏、block 丢失还是校验失败。

四、案例与场景:TA 安全存储计数器

假设一个 TA 需要维护一个防回滚的计数器。它使用 TEE_OpenPersistentObject 打开对象,读取当前值,加一后写回。若攻击者试图回滚文件,OP-TEE 的完整性校验和版本号机制会检测到不一致,拒绝加载旧数据。这个场景体现了 GP 规范中“抗回滚”属性与 OP-TEE 实现的配合:规范定义安全目标,OP-TEE 通过加密、HMAC 和版本管理落地。

五、常见误区与复盘

误区 正确理解
安全存储就是普通文件加密 除加密外,还包含完整性、原子性、抗回滚和访问控制,是完整的安全对象模型。
Normal World 可以随意修改存储文件 修改会导致 HMAC 校验失败,TA 读取时返回损坏错误,无法静默篡改。
dirf.db 只是普通索引,损坏无所谓 dirf.db 受完整性保护,损坏会导致对象无法定位,需恢复或重建。
API 调用成功就代表数据已落盘 需关注关闭与提交语义,部分场景下要确保 RPC 完成和索引更新。
排障时优先检查三处:dirf.db 是否完整、目标 block 是否存在、HMAC 校验是否通过。多数“对象打不开”问题都源于这三者之一,而非 API 本身。

综上,OP-TEE 安全存储架构是“标准 API + GP 规范 + 内部组件 + 文件结构”的协同结果。TEE Internal Core API 提供统一入口,GP 规范定义安全语义,OP-TEE 组件负责实现,最终以加密 block 和目录索引的形式落盘。掌握这条完整链路,才能在开发与排障中做到心中有数。