👹
Carlos's Tech Blog
  • 🧔ECUs
    • ZYNQ_Documents
      • [ZYNQ] 构建ZYNQ的BSP工程
      • [ZYNQ] 启动流程
      • [ZYNQ] Secure Boot Flow
      • [ZYNQ] Provisioning Guideline
      • [ZYNQ] Decrypting Partition by the Decrypt Agent Using PUF key
      • [ZYNQ] enabling the cryptsetup on ramdisk
      • [ZYNQ] Encrypt external files based on file system using PUF key
      • [ZYNQ] Loading an Encrypted Linux kernel at U-Boot with a KUP Key
      • [ZYNQ] cross-compile the cryptsetup on Xilinx ZYNQ aarch64 platform
      • [ZYNQ] Linux Linaro系统镜像制作SD卡启动
    • S32G_Documents
      • [S32G] Going through the s32g hard/soft platform
      • [S32G] S32g247's Secure Boot using HSE firmware
        • S32g2 HSE key config
        • How S32g verify secure boot image
        • S32g secure boot signature generation
        • How to download and build S32g Secure boot image
        • [S32G] OTA with Secure Boot
    • RT117x_Documents
      • [RT-117x]IMX RT1170 Provisioning Guideline
      • [RT-117x] Going through the MX-RT1170 hard/soft platform
      • [RT-117x] i.MX-RT1170's Secure Boot
        • [RT-117x]Signing image with the HSM (SignServer)
    • LS104x_Documents
      • [LS104x] bsp project
      • [LS104x] boot flow
      • [LS104x] secure boot
      • [LS104x] Application Note, Using the PKCS#11 in TCU platform
      • [LS104x] 使用ostree更新rootfs
      • [LS104x] ostree的移植
      • [LS104x] Starting with Yocto
      • [LS104x] 使用FIT的kernel格式和initramfs
    • IMX6/8_Documents
      • [IMX6] Defining A U-Boot Command
      • NXP IMX6 嵌入式板子一些笔记
      • NXP-imx6 initialization
    • Vehicle_Apps
      • [SecOC] Tree
        • [SecOC] SecOC Freshness and MAC Truncation
  • 😾TECH
    • Rust Arm OS
      • ARMv7m_Using_The_RUST_Cross_Compiler
    • ARM
      • ARM-v7-M
        • 01_ARMv7-M_处理器架构技术综述
        • 02_ARMv7-M_编程模型与模式
        • 03_ARMv7-M_存储系统结构
        • 04_ARMv7-M_异常处理及中断处理
      • ARM-v8-A
        • 02_ARMv8_基本概念
        • 03_ARMv8_指令集介绍_加载指令集和存储指令集
        • 04_ARMv8_指令集_运算指令集
        • 05_ARMv8_指令集_跳转_比较与返回指令
        • 06_ARMv8_指令集_一些重要的指令
        • 0X_ARMv8_指令集_基于汇编的UART驱动
        • 07_ARMv8_汇编器Using as
        • 08_ARMv8_链接器和链接脚本
        • 09_ARMv8_内嵌汇编(内联汇编)Inline assembly
        • 10_ARMv8_异常处理(一) - 入口与返回、栈选择、异常向量表
        • 11_ARMv8_异常处理(二)- Legacy 中断处理
        • 12_ARMv8_异常处理(三)- GICv1/v2中断处理
        • 13_ARMv8_内存管理(一)-内存管理要素
        • 14_ARMv8_内存管理(二)-ARM的MMU设计
        • 15_ARMv8_内存管理(三)-MMU恒等映射及Linux实现
        • 16_ARMv8_高速缓存(一)cache要素
        • 17_ARMv8_高速缓存(二)ARM cache设计
        • 18_ARMv8_高速缓存(三)多核与一致性要素
        • 19_ARMv8_TLB管理(Translation Lookaside buffer)
        • 20_ARMv8_barrier(一)流水线和一致性模型
        • 21_ARMv8_barrier(二)内存屏障案例
      • ARM Boot Flow
        • 01_Embedded_ARMv7/v8 non-secure Boot Flow
        • 02_Embedded_ARMv8 ATF Secure Boot Flow (BL1/BL2/BL31)
        • 03_Embedded_ARMv8 BL33 Uboot Booting Flow
      • ARM Compiler
        • Compiler optimization and the volatile keyword
      • ARM Development
        • 在MACBOOK上搭建ARMv8架构的ARM开发环境
        • Starting with JLink debugger or QEMU
    • Linux
      • Kernel
        • 0x01_LinuxKernel_内核的启动(一)之启动前准备
        • 0x02_LinuxKernel_内核的启动(二)SMP多核处理器启动过程分析
        • 0x21_LinuxKernel_内核活动(一)之系统调用
        • 0x22_LinuxKernel_内核活动(二)中断体系结构(中断上文)
        • 0x23_LinuxKernel_内核活动(三)中断体系结构(中断下文)
        • 0x24_LinuxKernel_进程(一)进程的管理(生命周期、进程表示)
        • 0x25_LinuxKernel_进程(二)进程的调度器的实现
        • 0x26_LinuxKernel_设备驱动(一)综述与文件系统关联
        • 0x27_LinuxKernel_设备驱动(二)字符设备操作
        • 0x28_LinuxKernel_设备驱动(三)块设备操作
        • 0x29_LinuxKernel_设备驱动(四)资源与总线系统
        • 0x30_LinuxKernel_设备驱动(五)模块
        • 0x31_LinuxKernel_内存管理(一)物理页面、伙伴系统和slab分配器
        • 0x32_LinuxKernel_内存管理(二)虚拟内存管理、缺页与调试工具
        • 0x33_LinuxKernel_同步管理_原子操作_内存屏障_锁机制等
        • 01_LinuxDebug_调试理论和基础综述
      • Userspace
        • Linux-用户空间-多线程与同步
        • Linux进程之间的通信-管道(上)
        • Linux进程之间的通信-管道(下)
        • Linux进程之间的通信-信号量(System V)
        • Linux进程之间的通信-内存共享(System V)
        • Linux进程之间的通信-消息队列(System V)
        • Linux应用调试(一)方法、技巧和工具 - 综述
        • Linux应用调试(二)工具之coredump
        • Linux应用调试(三)工具之Valgrind
        • Linux机制之内存池
        • Linux机制之对象管理和引用计数(kobject/ktype/kset)
        • Linux机制copy_{to, from}_user
        • Linux设备树 - DTS语法、节点、设备树解析等
        • Linux System : Managing Linux Services - inittab & init.d
        • Linux System : Managing Linux Services - initramfs
      • Kernel Examples
        • Linux Driver - GPIO键盘驱动开发记录_OMAPL138
        • 基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(一)之miscdevice和ioctl
        • 基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(二)之cdev与read、write
        • 基于OMAPL138的字符驱动_GPIO驱动AD9833(三)之中断申请IRQ
        • Linux内核调用SPI驱动_实现OLED显示功能
        • Linux内核调用I2C驱动_驱动嵌套驱动方法MPU6050
    • OPTEE
      • 01_OPTEE-OS_基础之(一)功能综述、简要介绍
      • 02_OPTEE-OS_基础之(二)TrustZone和ATF功能综述、简要介绍
      • 03_OPTEE-OS_系统集成之(一)编译、实例、在QEMU上执行
      • 05_OPTEE-OS_系统集成之(三)ATF启动过程
      • 06_OPTEE-OS_系统集成之(四)OPTEE镜像启动过程
      • 07_OPTEE-OS_系统集成之(五)REE侧上层软件
      • 08_OPTEE-OS_系统集成之(六)TEE的驱动
      • 09_OPTEE-OS_内核之(一)ARM核安全态和非安全态的切换
      • 10_OPTEE-OS_内核之(二)对安全监控模式的调用的处理
      • 11_OPTEE-OS_内核之(三)中断与异常的处理
      • 12_OPTEE-OS_内核之(四)对TA请求的处理
      • 13_OPTEE-OS_内核之(五)内存和cache管理
      • 14_OPTEE-OS_内核之(六)线程管理与并发
      • 15_OPTEE-OS_内核之(七)系统调用及IPC机制
      • 16_OPTEE-OS_应用之(一)TA镜像的签名和加载
      • 17_OPTEE-OS_应用之(二)密码学算法和安全存储
      • 18_OPTEE-OS_应用之(三)可信应用的开发
      • 19_OPTEE-OS_应用之(四)安全驱动开发
      • 20_OPTEE-OS_应用之(五)终端密钥在线下发系统
    • Binary
      • 01_ELF文件_目标文件格式
      • 02_ELF文件结构_浅析内部文件结构
      • 03_ELF文件_静态链接
      • 04_ELF文件_加载进程虚拟地址空间
      • 05_ELF文件_动态链接
      • 06_Linux的动态共享库
      • 07_ELF文件_堆和栈调用惯例以ARMv8为例
      • 08_ELF文件_运行库(入口、库、多线程)
      • 09_ELF文件_基于ARMv7的Linux系统调用原理
      • 10_ELF文件_ARM的镜像文件(.bin/.hex/.s19)
    • Build
      • 01_Script_makefile_summary
    • Rust
      • 02_SYS_RUST_文件IO
    • Security
      • Crypto
        • 1.0_Security_计算机安全概述及安全需求
        • 2.0_Security_随机数(伪随机数)
        • 3.0_Security_对称密钥算法加解密
        • 3.1_Security_对称密钥算法之AES
        • 3.2_Security_对称密钥算法之MAC(CMAC/HMAC)
        • 3.3_Security_对称密钥算法之AEAD
        • 8.0_Security_pkcs7(CMS)_embedded
        • 9.0_Security_pkcs11(HSM)_embedded
      • Tools
        • Openssl EVP to implement RSA and SM2 en/dec sign/verify
        • 基于Mac Silicon M1 的OpenSSL 编译
        • How to compile mbedtls library on Linux/Mac/Windows
    • Embedded
      • eMMC启动介质
  • 😃Design
    • Secure Boot
      • JY Secure Boot Desgin
    • FOTA
      • [FOTA] Module of ECUs' FOTA unit design
        • [FOTA] Tech key point: OSTree Deployment
        • [FOTA] Tech key point: repositories role for onboard
        • [FOTA] Tech key point: metadata management
        • [FOTA] Tech key point: ECU verifying and Decrpting
        • [FOTA] Tech key point: time server
      • [FOTA] Local-OTA for Embedded Linux System
    • Provisioning
      • [X-Shield] Module of the Embedded Boards initialization
    • Report
由 GitBook 提供支持
在本页
  • 16_OPTEE-OS_应用之(一)TA镜像的签名和加载
  • 1. TA文件的编译和签名
  • 1.1 TA镜像文件编译
  • 1.2 对TA镜像文件的签名
  • 2. TA镜像加载
  • 2.1 REE获取TA文件
  • 2.2 加载TA镜像的RPC请求
  • 2.3 RPC请求发送
  • 2.4 读取TA内容到共享内存
  • 3. TA合法性验证
  • 3.1 RSA公钥产生和获取
  • 3.2 合法性检查
  • 4. 加载TA到OP-TEE用户空间
  • 5. TA运行上下文的初始化
  • 6. 总结
  1. TECH
  2. OPTEE

16_OPTEE-OS_应用之(一)TA镜像的签名和加载

https://github.com/carloscn/blog/issues/106

16_OPTEE-OS_应用之(一)TA镜像的签名和加载

使用OP-TEE实现特定功能需求则需要开发一个特定的TA,TA调用GP规范定义的接口实现该功能需求。TA镜像文件会被保存在REE侧的文件系统中并以动态TA的方式运行于OP-TEE中,当用户需要调用该TA的功能时,通过在CA中调用libteec库中的接口,完成创建会话的操作,将REE侧文件系统中的TA镜像文件加载到OP-TEE的用户空间运行。为防止该TA镜像文件被篡改或被破坏,在加载TA镜像文件的过程中会对该TA镜像文件的合法性进行检查,只有校验通过的TA镜像文件才允许运行于OP-TEE的用户空间。编译TA镜像文件过程中会对TA镜像文件做电子签名操作。本章将详细介绍TA镜像文件的编译、签名,以及加载过程。

1. TA文件的编译和签名

TA镜像文件在OP-TEE工程编译过程中生成,也可通过单独调用TA目录下的脚本来进行编译,但前提是OP-TEE工程被完整编译过。编译过程会先生成原始的TA镜像文件,然后使用签名脚本对该文件进行电子签名,并最终生成.ta文件,即最终会被加载到OP-TEE中的TA镜像文件。

1.1 TA镜像文件编译

对某个TA源代码目录中的Makefile文件执行make指令可触发编译生成TA镜像文件的操作,该Makefile文件将会包含optee_os/ta/mk/ta_dev_kit.mk文件,该文件中会定义各种目标依赖关系和Object,编译完目标和object后,编译器将会按照optee_os/ta/arch/arm/link.mk文件中的依赖关系将目标和object链接成xxx.ta文件,其中xxx是该TA UUID的值。link.mk中的链接依赖关系如下:

link-script$(sm) = $(ta-dev-kit-dir$(sm))/src/ta.ld.S
link-script-pp$(sm) = $(link-out-dir$(sm))/ta.lds
link-script-dep$(sm) = $(link-out-dir$(sm))/.ta.ld.d

SIGN_ENC ?= $(PYTHON3) $(ta-dev-kit-dir$(sm))/scripts/sign_encrypt.py
TA_SIGN_KEY ?= $(ta-dev-kit-dir$(sm))/keys/default_ta.pem

ifeq ($(CFG_ENCRYPT_TA),y)
# Default TA encryption key is a dummy key derived from default
# hardware unique key (an array of 16 zero bytes) to demonstrate
# usage of REE-FS TAs encryption feature.
#
# Note that a user of this TA encryption feature needs to provide
# encryption key and its handling corresponding to their security
# requirements.
TA_ENC_KEY ?= 'b64d239b1f3c7d3b06506229cd8ff7c8af2bb4db2168621ac62c84948468c4f4'
endif

all: $(link-out-dir$(sm))/$(user-ta-uuid).dmp \
	$(link-out-dir$(sm))/$(user-ta-uuid).stripped.elf \
	$(link-out-dir$(sm))/$(user-ta-uuid).ta
cleanfiles += $(link-out-dir$(sm))/$(user-ta-uuid).elf
cleanfiles += $(link-out-dir$(sm))/$(user-ta-uuid).dmp
cleanfiles += $(link-out-dir$(sm))/$(user-ta-uuid).map
cleanfiles += $(link-out-dir$(sm))/$(user-ta-uuid).stripped.elf
cleanfiles += $(link-out-dir$(sm))/$(user-ta-uuid).ta
cleanfiles += $(link-script-pp$(sm)) $(link-script-dep$(sm))

link-ldflags  = -e__ta_entry -pie
link-ldflags += -T $(link-script-pp$(sm))
link-ldflags += -Map=$(link-out-dir$(sm))/$(user-ta-uuid).map
link-ldflags += --sort-section=alignment
link-ldflags += -z max-page-size=4096 # OP-TEE always uses 4K alignment
ifeq ($(sm)-$(CFG_TA_BTI),ta_arm64-y)
link-ldflags += $(call ld-option,-z force-bti) --fatal-warnings
endif
link-ldflags += --as-needed # Do not add dependency on unused shlib
link-ldflags += $(link-ldflags$(sm))

$(link-out-dir$(sm))/dyn_list:
	@$(cmd-echo-silent) '  GEN     $@'
	$(q)mkdir -p $(dir $@)
	$(q)echo "{" >$@
	$(q)echo "__elf_phdr_info;" >>$@
ifeq ($(CFG_FTRACE_SUPPORT),y)
	$(q)echo "__ftrace_info;" >>$@
endif
	$(q)echo "trace_ext_prefix;" >>$@
	$(q)echo "trace_level;" >>$@
	$(q)echo "};" >>$@
link-ldflags += --dynamic-list $(link-out-dir$(sm))/dyn_list
dynlistdep = $(link-out-dir$(sm))/dyn_list
cleanfiles += $(link-out-dir$(sm))/dyn_list

link-ldadd  = $(user-ta-ldadd) $(addprefix -L,$(libdirs))
link-ldadd += --start-group
link-ldadd += $(addprefix -l,$(libnames))
ifneq (,$(filter %.cpp,$(srcs)))
link-ldflags += --eh-frame-hdr
link-ldadd += $(libstdc++$(sm)) $(libgcc_eh$(sm))
endif
link-ldadd += --end-group

link-ldadd-after-libgcc += $(addprefix -l,$(libnames-after-libgcc))

ldargs-$(user-ta-uuid).elf := $(link-ldflags) $(objs) $(link-ldadd) \
				$(libgcc$(sm)) $(link-ldadd-after-libgcc)

link-script-cppflags-$(sm) := \
	$(filter-out $(CPPFLAGS_REMOVE) $(cppflags-remove), \
		$(nostdinc$(sm)) $(CPPFLAGS) \
		$(addprefix -I,$(incdirs$(sm)) $(link-out-dir$(sm))) \
		$(cppflags$(sm)))

-include $(link-script-dep$(sm))

link-script-pp-makefiles$(sm) = $(filter-out %.d %.cmd,$(MAKEFILE_LIST))

define gen-link-t
$(link-script-pp$(sm)): $(link-script$(sm)) $(conf-file) $(link-script-pp-makefiles$(sm))
	@$(cmd-echo-silent) '  CPP     $$@'
	$(q)mkdir -p $$(dir $$@)
	$(q)$(CPP$(sm)) -P -MT $$@ -MD -MF $(link-script-dep$(sm)) \
		$(link-script-cppflags-$(sm)) $$< -o $$@

$(link-out-dir$(sm))/$(user-ta-uuid).elf: $(objs) $(libdeps) \
					  $(libdeps-after-libgcc) \
					  $(link-script-pp$(sm)) \
					  $(dynlistdep) \
					  $(additional-link-deps)
	@$(cmd-echo-silent) '  LD      $$@'
	$(q)$(LD$(sm)) $(ldargs-$(user-ta-uuid).elf) -o $$@

$(link-out-dir$(sm))/$(user-ta-uuid).dmp: \
			$(link-out-dir$(sm))/$(user-ta-uuid).elf
	@$(cmd-echo-silent) '  OBJDUMP $$@'
	$(q)$(OBJDUMP$(sm)) -l -x -d $$< > $$@

$(link-out-dir$(sm))/$(user-ta-uuid).stripped.elf: \
			$(link-out-dir$(sm))/$(user-ta-uuid).elf
	@$(cmd-echo-silent) '  OBJCOPY $$@'
	$(q)$(OBJCOPY$(sm)) --strip-unneeded $$< $$@

cmd-echo$(user-ta-uuid) := SIGN   #
ifeq ($(CFG_ENCRYPT_TA),y)
crypt-args$(user-ta-uuid) := --enc-key $(TA_ENC_KEY)
cmd-echo$(user-ta-uuid) := SIGNENC
endif
$(link-out-dir$(sm))/$(user-ta-uuid).ta: \
			$(link-out-dir$(sm))/$(user-ta-uuid).stripped.elf \
			$(TA_SIGN_KEY) \
			$(lastword $(SIGN_ENC))
	@$(cmd-echo-silent) '  $$(cmd-echo$(user-ta-uuid)) $$@'
	$(q)$(SIGN_ENC) --key $(TA_SIGN_KEY) $$(crypt-args$(user-ta-uuid)) \
		--uuid $(user-ta-uuid) --ta-version $(user-ta-version) \
		--in $$< --out $$@
endef

$(eval $(call gen-link-t))

additional-link-deps :=

TA镜像文件中的调试信息。在原始TA镜像文件的头部有一个ta_head段,该段中存放该TA的基本信息以及被调用到的入口地址,该段的内容将会在加载TA镜像到OP-TEE时和调用TA执行特定命令时被使用到。存放在该段中的内容定义在optee_os/ta/arch/arm/user_ta_header.c文件中:

const struct ta_head ta_head __section(".ta_head") = {
	/* UUID, unique to each TA */
	.uuid = TA_UUID,
	/*
	 * According to GP Internal API, TA_FRAMEWORK_STACK_SIZE corresponds to
	 * the stack size used by the TA code itself and does not include stack
	 * space possibly used by the Trusted Core Framework.
	 * Hence, stack_size which is the size of the stack to use,
	 * must be enlarged
	 */
	.stack_size = TA_STACK_SIZE + TA_FRAMEWORK_STACK_SIZE,
	.flags = TA_FLAGS,
	/*
	 * The TA entry doesn't go via this field any longer, to be able to
	 * reliably check that an old TA isn't loaded set this field to a
	 * fixed value.
	 */
	.depr_entry = UINT64_MAX,
};

1.2 对TA镜像文件的签名

生成原始的TA镜像文件后,编译系统会对该镜像文件进行签名生成最终的xxx.ta文件,该文件会被保存在REE侧的文件系统中。对原始TA镜像文件的签名操作是使用optee_os/scripts/sign.py文件来实现,使用的私钥是optee_os/keys目录下的RSA2048密钥(default_ta.pem)。当该TA需要被正式发布时,应该使用OEM厂商自有的私钥替换掉该密钥。sign.py文件的内容如下:

2. TA镜像加载

当CA第一次调用libteec库中的创建会话操作时,如果被调用的TA是动态TA,则会触发OP-TEE加载该动态TA镜像文件的操作。在加载过程中,OP-TEE会发送PRC请求通知tee_supplicant从文件系统中将UUID对应的TA镜像文件传递到OP-TEE,OP-TEE会对接收到的数据进行验证操作,如果验证通过则将相关段中的内容保存到OP-TEE用户空间分配的TA内存中。加载TA镜像的整体流程如图所示。

2.1 REE获取TA文件

OP-TEE通过调用rpc_load函数发送PRC请求,将TA镜像文件的内容从REE侧加载到OP-TEE的共享内存中。该函数会触发两次RPC请求,第一次RPC请求用于获取TA镜像文件的大小,第二次RPC请求是将TA镜像文件加载到OP-TEE的共享内存中。触发第二次RPC请求之前,OP-TEE会在用户空间先分配与TA镜像文件的大小相等的共享内存区域,该区域用于存放TA镜像文件的内容。

对TA镜像文件内容的合法性检查,将TA加载到OP-TEE用户空间TA的内存操作都是在共享内存中完成的。

2.2 加载TA镜像的RPC请求

加载TA过程中,ta_open函数会调用rpc_load函数,该函数会调用thread_rpc_cmd来发送OPTEE_MSG_RPC_CMD_LOAD_TA的RPC请求,rpc_load函数会组合该类请求的相关数据结构变量,然后通过调用thread_rpc函数向REE发送RPC请求。

在整个TA的加载过程中会发送两次RPC请求,第一次是用于获取TA镜像文件的大小,第二次RPC请求是通知tee_supplicant将TA镜像文件的内容加载到OP-TEE提供的共享内存中。

2.3 RPC请求发送

RPC请求的发送是通过触发安全监控模式调用(smc)来实现的,在触发安全监控模式调用(smc)之前会将当前的线程挂起,并保存该线程的运行上下文。

当REE处理完RPC请求后,会发送标准安全监控模式调用(std smc)重新进入到OP-TEE中,OPTEE根据返回的安全监控模式调用(smc)的类型判定当前的安全监控模式调用(smc)是RPC的返回还是普通的安全监控模式调用(smc)。如果该安全监控模式调用(smc)是返回RPC请求的处理结果,则会进入到thread_resume_from_rpc分支恢复之前被挂起的线程。在thread_rpc函数中已经指定了恢复该线程之后程序执行的入口函数—— thread_rpc_return,到此一次完整的RPC请求也就被处理完毕。

2.4 读取TA内容到共享内存

rpc_load函数发起第二次RPC请求时才会将TA镜像文件的内容读取到OP-TEE提供的共享内存中,共享内存的分配是在rpc_load函数中调用thread_rpc_alloc_payload函数来实现的。分配的共享内存的地址将会被保存到ta_handle变量的nw_ta成员中,读取到的TA镜像文件的内容将会被加载到OP-TEE用户空间TA运行的内存中。

3. TA合法性验证

当TA镜像文件被加载到共享内存后,OP-TEE会对获取到的数据进行合法性检查。检查TA镜像文件中的哈希(hash)值、magic值、flag值等是否一致,并对镜像文件中的电子签名部分做验证。

3.1 RSA公钥产生和获取

编译整个工程时会生成一个ta_pub_key.c文件,该文件中存放的是RSA公钥,用于验证TA镜像文件合法性。该文件是在编译gensrcs-y目标中的ta_pub_key成员时生成的,该部分的内容定义在optee_os/core/sub.mk文件中。

编译ta_pub_key目标时会调用recipe-ta_pub_key命令来生成ta_pub_key.c文件,该文件被保存在optee_os/out/arm/core/目录中。recipe-ta_pub_key命令调用pem_to_pub_c.py文件解析optee_os/keys目录中的RSA密钥来获取RSA公钥,并将该公钥保存到ta_pub_key.c文件中。

3.2 合法性检查

对TA镜像文件内容合法性的检查是通过调用check_shdr函数来实现的,该函数除了会对TA镜像文件中的签名信息进行验签操作外,还会校验TA镜像文件的shdr部分。

校验TA镜像签名时使用的RSA公钥是由ta_public_key.c文件中的ta_pub_key_exponent和ta_pub_key_modulus变量的值组成。

4. 加载TA到OP-TEE用户空间

待共享内存中的TA镜像文件校验通过后,OPTEE就会将共享内存中的TA的内容复制到OP-TEE用户空间的TA内存区域,并初始化该TA运行于用户空间时的上下文。这些操作通过调用load_elf函数来实现。整个TA镜像文件加载到OP-TEE用户空间的过程如图所示。

TA镜像文件的TA原始文件是ELF格式,在加载前需要先解析该ELF格式文件,获取该ELF文件中哪些段在运行时是必需的、需要保存在什么位置,从而决定用户空间中该TA运行时需要的内存大小和堆栈空间大小。解析完后再将ELF格式的必要段的内容复制到为该TA分配的OP-TEE用户空间内存中。

5. TA运行上下文的初始化

TA镜像的内容从共享内存复制到OP-TEE用户空间内存区域后会返回到ta_load函数继续执行,执行初始化该TA运行上下文的操作,并将该上下文添加到OP-TEE的TA运行上下文队列中。

static TEE_Result ta_load(struct tee_tadb_ta_read *ta)
{
	struct thread_param params[2] = { };
	TEE_Result res;
	const size_t sz = ta->entry.prop.custom_size + ta->entry.prop.bin_size;

	if (ta->ta_mobj)
		return TEE_SUCCESS;

	ta->ta_mobj = thread_rpc_alloc_payload(sz);
	if (!ta->ta_mobj)
		return TEE_ERROR_OUT_OF_MEMORY;

	ta->ta_buf = mobj_get_va(ta->ta_mobj, 0, sz);
	assert(ta->ta_buf);

	params[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_READ, ta->fd, 0);
	params[1] = THREAD_PARAM_MEMREF(OUT, ta->ta_mobj, 0, sz);

	res = thread_rpc_cmd(OPTEE_RPC_CMD_FS, ARRAY_SIZE(params), params);
	if (res) {
		thread_rpc_free_payload(ta->ta_mobj);
		ta->ta_mobj = NULL;
	}
	return res;
}

待ta_load执行完后,加载TA镜像到OP-TEE的操作也就全部完成。在CA中执行的创建会话操作会得到该TA的会话ID,用于REE侧的CA对该TA执行调用命令的操作。

6. 总结

本章节主要介绍OP-TEE在执行创建会话操作时加载动态TA的全过程,OP-TEE通过发送RPC请求通知REE侧的tee_supplicant将文件系统中的TA镜像文件加载到OP-TEE分配的共享内存中,然后对共享内存中的数据进行合法性检查,并将必要段的内容复制到分配的OP-TEE用户空间。本章节同时也介绍了对TA镜像文件进行合法性检查时使用的密钥的生成以及TA镜像文件的签名和验签过程。

上一页15_OPTEE-OS_内核之(七)系统调用及IPC机制下一页17_OPTEE-OS_应用之(二)密码学算法和安全存储

最后更新于1年前

😾