TEE软件框架

TEE 系统软件从整体上包含 REE 和 TEE 两部分,各自对应的基础组件如下图所示。

  • REE 部分 Client Applications(CA) 一般是指指纹录入,支付应用等上层应用,其通过调用 TEE Client API 接口来与 TEE 环境的 Trusted OS 进行交互,这里的 TEE Client API 包括 TEE 厂商自定义的一些接口或 GlobalPlatform(GP) 全球组织定义的通用 API,其目的是制定一套标准的编程接口,方便开发者在不同软硬件平台下使用同一套代码实现其功能。
  • TEE Client API 通过 ioctl 系统调用对 TEE Driver 进行操作,TEE Driver 是沟通 REE 和 TEE 的桥梁,其通过 SMC 指令,实现将上层的 OpenSession,InvokeCommand,CloseSession 等标准调用的请求转发到 TEE 环境,同时其也会处理来自 TEE 的请求,将请求转发到 TEE Helper Daemon 让其处理。
  • TEE Helper Daemon 是一个辅助进程,用于 TEE 请求 REE 的资源。 一般来说,TEE 需要获得存储在 EMMC 的数据文件(例如安全加密文件,TA 可执行镜像文件等),而读写 EMMC 操作需要复杂的内核驱动的支持,显然如果把读写 EMMC 的驱动放到 TEE 侧运行会使软件复杂度会变得很高,因此 REE 需要一个可以访问这些资源的辅助进程支持,这就是 TEE Helper Daemon 的基本功能。TEE Helper Daemon 在软件逻辑实现上比较简单,以 OP-TEE 的 tee-supplicant 辅助进程为例,整体上是一个循环流程: 其首先通过 ioctl 接口查询是否有来自 TEE 的请求,如果没有,则进入睡眠等待状态,等待 TEE Driver 的唤醒信号,当 TEE Driver 收到来自 TEE 的请求后,会唤醒 tee-supplicant 辅助进程,然后根据请求号进行相应处理(读写数据文件,读写 EMMC 设备分区等),最后返回结果到 TEE Driver,完成一次循环,具体实现可参照《OP-TEE 中 tee-supplicant 执行流程》

  • TEE 侧的 Secure Monitor 的主要作用是实现 REE 和 TEE 环境的切换,转发请求到 Trusted OS。当 Secure Monitor 收到 TEE Driver 的 SMC 请求后,会将 CPU 切换到 Secure 状态,然后转发请求到 Trusted OS 来处理,Trusted OS 会找到请求对应的 Trusted App(TA) 去处理请求,具体逻辑流程会在下一节中详细说明。 另外 Secure Monitor 还用于开机时候 Trusted OS 的引导工作,此内容不在本文的叙述范围,读者可以参看: 《Secure-EL1 Payloads and Dispatchers》
  • Trusted OS 是运行在 TEE 侧的小型操作系统,简单来说,其作用是:
    • 构建满足 TA 运行的安全运行环境
    • 提供安全外设(SPI,I2C,Timer 等)的驱动程序
    • 根据 REE 的请求,调度相应 TA 处理请求
    • 提供 TA 运行所需要的加解密,随机数生成,证书生成校验等通用函数库
  • 上文提到 GlobalPlatform(GP) 全球组织定义的通用 API,TEE Client API 供 REE 侧的 CA 使用,TEE Internal API 则是供 TA 调用 Trusted OS 资源的标准 API,同样是用于方便 TA 开发者在不同软硬件平台进行开发。

TEE 软件交互流程

上文对 REE 调用 TEE 软件交互所需要的基础组件及其基本作用进行了介绍,下面将对各个组件的交互流程进行介绍。

在 GP 标准中,CA 要与 TA 进行通信,需要建立如图2所示的软件逻辑流程:

  1. 首先 CA 需要与 Trusted OS 之间建立一个 Context(InitializeContext),以后此 CA 与 TEE 环境的所有通信均基于此 Context。
  2. 然后 CA 会向 Trusted OS 申请与请求的 TA 建立一个 Session(OpenSession)。
  3. CA 与 TA 之间的 Session 建立完成后,CA 就可以向 TA 发送 Command(InvokeCommand)。
  4. Command 及其参数会通过共享内存的方式传递,TA 从共享内存中获取到 CA 的请求以及请求参数。
  5. TA 在 TEE 环境下执行处理,得到的处理结果重新填充到共享内存中,CA 通过共享内存就可以获取到处理结果。
  6. 获得处理结果后,如不需要进一步请求,则由 CA 发起关闭 Session 的请求(CloseSession),Trusted OS 回收 TA 相关资源,最后 CA 发起销毁 Context 的请求(FinalizeContext),完成一次完整交互。

从以上流程可以看到,整个交互流程主要涉及 InitializeContext,OpenSession,InvokeCommand,CloseSession 和 FinalizeContext 5个操作。 InitializeContext 用于 Trusted OS 分配 TA 运行需要的安全内存,FinalizeContext 则是销毁相应内存,具体流程分别与 OpenSession 和 CloseSession 类似,本文将不对这两个操作赘述。 下面看看 OpenSession,InvokeCommand 和 CloseSession 这几个操作下,各个基础组件的交互时序。

OpenSession 时序如图3所示,操作步骤如下:

  1. CA 经过 TEE Client API 向 TEE Driver 发送 OpenSession 请求。
  2. TEE Driver 发送 OpenSession SMC 请求到 Trusted OS,此请求中包含要请求 TA 的唯一标识号(UUID)。
  3. Trusted OS 会根据 TA 的 UUID 查找 TA 是否已经加载了,如果已经加载了,则执行步骤6,否则执行步骤4。
  4. 若请求的 TA 未加载,则 Trusted OS 会向 TEE Helper Daemon 进程发送 Load TA 命令请求,TEE Helper Daemon 收到请求后,会根据要加载的 TA 的 UUID,从文件系统指定路径下找到 TA 镜像文件,并将其加载到预先分配的共享内存中,最后将共享内存的地址回传给 Trusted OS(这次地址回传实际需要经过 TEE Driver 进行虚拟地址与物理地址转换)。
  5. Trusted OS 从回传的共享地址拷贝 TA 镜像到安全内存中,然后对安全内存中的 TA 镜像的 ELF 格式头,签名信息进行校验,校验通过则加载成功,否则返回错误信息给 CA。
  6. TA 加载成功后,Trusted OS 分配一个 Session 操作句柄,并定位到已加载镜像的 TA_OpenSessionEntryPoint 函数入口执行。
  7. 最后,Trusted OS 将分配的 Session 句柄逐级返回,最终 CA 拿到 Session 句柄,以后的 InvokeCommand 将需要依赖此句柄进行调用。

InvokeCommand 和 CloseSession 的流程与 OpenSession 流程相似,差别在于少了 load TA 的流程,时序图如图4和图5所示。

TEE Example

参考https://github.com/linaro-swg/optee_examples

TEE应用举例

指纹软件框架

如下图是Android上的指纹软件框架,REE环境下主要分为APP,Framework,HAL和linux kernel。APP主要负责指纹录入解锁调用逻辑,Framework主要负责回调HAL层相关函数,HAl层负责和硬件以及指纹TA交互。而TEE主要是指纹TA,指纹TA负责控制指纹sensor和执行指纹算法相关函数。

  • Fingerprint TA:主要进行基本操作,比如控制finger sensor采图,特征提取,指纹算法处理等操作。
  • finger CA:负责与Fingerprint TA进行通信,发送指令,向Fingerprint HAL提供REE与TEE的通信接口。
  • Secure SPI driver:TEE与指纹sensor通信的SPI安全驱动
  • finger lib:指纹算法库,主要是对指纹图像特征提取比对等算法实现
  • Fingerprint HAL:指纹hal,调用CA的接口向TA下发指令,同时通过Fingerprint Device Driver实现对GPIO,Power,INT等管脚和功能控制。
  • Fingerprint service:指纹framework,回调hal层相关函数,控制指纹录入解锁等流程
  • App:指纹最上层的代码,主要是负责指纹录入解锁调用逻辑

指纹录入流程

Hal中指纹的录入流程为:指纹sensor初始化(begin enroll)->采图(do capture)->录入(do enroll)->结束录入(do enroll)->指纹模板存储(store template)。对应TA的录入流程为:指纹sensor init(begin enroll)->采图(capture image)->将采集的指纹数据传输回TA->录入(do enroll)->结束录入(end enroll)->模板加密存储到secure memory(encrypt)。

HAL中主要进行的是与TA交互,给TA发送指令,同时还会对指纹硬件进行操作,比如指纹sensor上下电等。TA收到CA的command,则需要处理敏感数据和一些安全性要求高的动作,如TA通过secure spi控制指纹sensor采图,图像传输,图像处理,图像比对,模板存储等。这些都是在TEE环境下进行操作的,所以指纹解锁是一种相对比较安全的解锁方式。

QA

optee是否是多线程的?

optee支持多核SMP,optee里的线程数是通过静态定义的(一个数组,数组大小决定了线程数量),但是如果cpu是单核那么就只支持单线程,optee的线程不支持时间片轮转,一个cpu核不能通过时间片轮转处理多个TA应用。但是如果是多核cpu,例如4核cpu那么optee最多可以4核同时处理4个TA应用。由于TA里涉及很多加解密操作可能会很耗时导致Linux端出现性能问题(optee在运行的时候,该cpu核无法运行Linux程序)。optee运行期间只有中断可以打断其运行。

参考文献

https://kernel.meizu.com/2017/12/27//tee.html
https://deepinout.com/android-system-analysis/android-security-related/easy-to-understand-tee.html
https://blog.csdn.net/shuaifengyun/article/details/72912238