当前位置: 首页 > news >正文

OP-TEE 3.6.0实战:从examples测试到自定义TA/CA开发全流程

1. OP-TEE 3.6.0开发环境搭建

搞嵌入式安全开发的朋友们,今天咱们来聊聊OP-TEE 3.6.0这个好东西。作为ARM TrustZone技术的开源实现,它可是构建可信执行环境(TEE)的利器。我最近在QEMU模拟的ARMv8平台上折腾了好一阵子,把环境搭建的坑都踩了个遍,现在就把最实用的经验分享给大家。

首先得准备基础开发环境。我在Ubuntu 20.04 LTS上实测通过,建议你也用这个版本,能省去不少兼容性问题。安装必备工具链这几个命令记好了:

sudo apt-get update sudo apt-get install -y android-tools-adb autoconf automake bc bison build-essential \ ccache cscope curl device-tree-compiler expect flex ftp-upload gdisk iasl libattr1-dev \ libcap-dev libfdt-dev libftdi-dev libglib2.0-dev libhidapi-dev libncurses5-dev \ libpixman-1-dev libssl-dev libtool make mtools netcat python-crypto python-serial \ python-wand unzip uuid-dev xdg-utils xterm xz-utils zlib1g-dev

接下来获取OP-TEE 3.6.0源码。官方推荐使用repo工具管理,这个步骤可能会花点时间,建议喝杯咖啡等着:

mkdir optee-qemu && cd optee-qemu repo init -u https://github.com/OP-TEE/manifest.git -b 3.6.0 repo sync -j4

编译时有个小技巧,先设置好交叉编译工具链路径能避免很多奇怪错误。我在~/.bashrc里加了这几行:

export PATH=$PATH:$(pwd)/toolchains/aarch32/bin export PATH=$PATH:$(pwd)/toolchains/aarch64/bin export PATH=$PATH:$(pwd)/toolchains/make_4.3/bin

2. 运行和调试examples测试用例

环境搞定后,咱们先拿官方examples开刀。这些测试用例就像练武的木人桩,能帮你快速熟悉OP-TEE的开发套路。我建议从hello_world这个最简单的例子入手,它能验证你的环境是否真正可用。

要让examples跑起来,得先打个补丁。这个补丁的作用是把examples集成到构建系统里,官方文档里没细说,但实测必不可少:

cd build wget https://patch-diff.githubusercontent.com/raw/OP-TEE/build/pull/xxx.patch git apply xxx.patch cd ..

编译命令看起来简单,但有几个关键参数要注意:

make -f qemu_v8.mk all

等编译完成后,启动QEMU环境。这里有个实用技巧:开两个终端,一个跑QEMU,另一个通过soc-term连接,这样调试信息看得更清楚:

# 终端1 make -f qemu_v8.mk run-only # 终端2 make -f qemu_v8.mk soc-term

在QEMU环境中,输入optee_example_后按Tab键,就能看到所有可用的测试用例。跑个hello_world试试:

optee_example_hello_world

如果遇到问题,调整日志级别是必须掌握的技能。OP-TEE的日志系统分好几个层次,TA、CA、tee-supplicant各有各的设置方式。我整理了个表格帮你快速定位:

组件配置文件位置修改方式
TA日志optee_os/mk/config.mkCFG_TEE_TA_LOG_LEVEL=4
客户端日志optee_client/config.mkCFG_TEE_CLIENT_LOG_LEVEL=4
supplicant日志optee_client/config.mkCFG_TEE_SUPP_LOG_LEVEL=4

改完记得重新编译对应模块。比如只想重新编译TA部分可以这样:

make -f qemu_v8.mk optee-os-clean optee-os

3. 深入理解TA/CA通信机制

玩转examples后,咱们得搞清楚TA(Trusted Application)和CA(Client Application)是怎么对话的。这就像理解两个人怎么秘密交流,是OP-TEE开发的核心。

TA运行在安全世界,CA运行在普通世界,它们通过GP(GlobalPlatform)定义的接口通信。我画了个简化版的调用流程:

  1. CA通过libteec库调用TEEC_OpenSession打开会话
  2. OP-TEE内核检查TA是否已加载
  3. 如果TA未加载,tee-supplicant从文件系统加载TA镜像
  4. 建立安全通道后,CA通过TEEC_InvokeCommand调用TA功能
  5. TA处理完成后,通过共享内存返回结果

在examples/hello_world里,这个流程体现得很清楚。CA端关键代码片段:

TEEC_Result res; TEEC_Context ctx; TEEC_Session sess; TEEC_Operation op; res = TEEC_InitializeContext(NULL, &ctx); res = TEEC_OpenSession(&ctx, &sess, &uuid, TEEC_LOGIN_PUBLIC, NULL, NULL, NULL); memset(&op, 0, sizeof(op)); op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); op.params[0].value.a = 42; res = TEEC_InvokeCommand(&sess, TA_HELLO_WORLD_CMD_INC_VALUE, &op, NULL); printf("TA returned %d\n", op.params[0].value.a); TEEC_CloseSession(&sess); TEEC_FinalizeContext(&ctx);

对应的TA端处理逻辑:

TEE_Result TA_InvokeCommandEntryPoint(void *sess_ctx, uint32_t cmd_id, uint32_t param_types, TEE_Param params[4]) { switch (cmd_id) { case TA_HELLO_WORLD_CMD_INC_VALUE: params[0].value.a++; return TEE_SUCCESS; default: return TEE_ERROR_BAD_PARAMETERS; } }

调试这种跨世界调用时,我习惯在TA入口处加个打印:

DMSG("TA got command %d from CA", cmd_id);

然后在CA端用strace跟踪系统调用,这样两边信息对照着看,问题定位更快:

strace -o trace.log optee_example_hello_world

4. 开发自定义TA/CA实战

终于到了重头戏 - 开发自己的TA/CA!咱们以hello_world为模板,创建一个计算哈希值的示例。这个例子很实用,因为密码学操作正是TEE的典型应用场景。

首先复制hello_world目录并重命名:

cp -r optee_examples/hello_world optee_examples/hash_calculator cd optee_examples/hash_calculator find . -type f -exec sed -i 's/hello_world/hash_calculator/g' {} + find . -type f -exec sed -i 's/HELLO_WORLD/HASH_CALCULATOR/g' {} +

修改CA端代码,增加哈希计算请求:

// hash_calculator/host/main.c struct hash_data { uint8_t *input; size_t input_len; uint8_t output[32]; }; TEEC_Result calculate_hash(TEEC_Session *sess, const char *str, uint8_t out[32]) { TEEC_Operation op; uint32_t ret; size_t len = strlen(str); memset(&op, 0, sizeof(op)); op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE, TEEC_NONE); op.params[0].tmpref.buffer = (void *)str; op.params[0].tmpref.size = len; op.params[1].tmpref.buffer = out; op.params[1].tmpref.size = 32; ret = TEEC_InvokeCommand(sess, TA_HASH_CMD_CALCULATE, &op, NULL); if (ret != TEEC_SUCCESS) printf("TEEC_InvokeCommand failed with code 0x%x\n", ret); return ret; }

对应的TA端实现要使用TEE内部加密API:

// hash_calculator/ta/hash_calculator.c TEE_Result TA_InvokeCommandEntryPoint(void *sess_ctx, uint32_t cmd_id, uint32_t param_types, TEE_Param params[4]) { TEE_Result res; TEE_OperationHandle op_handle; uint32_t hash_size = 32; if (cmd_id == TA_HASH_CMD_CALCULATE) { if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, TEE_PARAM_TYPE_MEMREF_OUTPUT, TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE)) { return TEE_ERROR_BAD_PARAMETERS; } res = TEE_AllocateOperation(&op_handle, TEE_ALG_SHA256, TEE_MODE_DIGEST, 0); if (res != TEE_SUCCESS) return res; res = TEE_DigestDoFinal(op_handle, params[0].memref.buffer, params[0].memref.size, params[1].memref.buffer, &hash_size); TEE_FreeOperation(op_handle); return res; } return TEE_ERROR_BAD_PARAMETERS; }

编译测试时,建议先用独立脚本验证:

cd optee_examples/hash_calculator ./build_ta_hash_calculator.sh

确认没问题后再集成到完整系统:

make -f qemu_v8.mk all

部署后你会在这些路径找到生成的文件:

  • CA程序:out-br/target/usr/bin/optee_example_hash_calculator
  • TA镜像:out-br/target/lib/optee_armtz/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.ta

测试时可以直接传入字符串计算哈希:

optee_example_hash_calculator "hello TEE"

5. 高级调试技巧与性能优化

开发过程中肯定会遇到各种妖魔鬼怪,分享几个我压箱底的调试技巧。首先是内存问题排查,TEE环境下的内存错误更难调试,可以在TA入口处加内存检查:

TEE_AddMemoryAllocator(0x00000000, 0xFFFFFFFF, my_malloc, my_free, my_calloc, my_realloc);

对于性能敏感的应用,要特别注意TA和CA之间的数据传递开销。大块数据应该用共享内存传递,而不是多次调用。我做过测试,传递1MB数据:

传递方式耗时(ms)
多次小调用1200
单次共享内存85

设置共享内存的正确姿势:

TEEC_SharedMemory shm; shm.size = buf_size; shm.flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT; res = TEEC_AllocateSharedMemory(&ctx, &shm); // 使用后记得释放 TEEC_ReleaseSharedMemory(&shm);

TA端访问共享内存要检查边界:

TEE_CheckMemoryAccessRights(TEE_MEMORY_ACCESS_READ | TEE_MEMORY_ACCESS_ANY_OWNER, params[0].memref.buffer, params[0].memref.size);

遇到TA崩溃时,可以通过QEMU监控命令获取更多信息。先按Ctrl+A然后C进入QEMU控制台,输入:

info registers x/20i $pc

对于密码学操作,OP-TEE提供了硬件加速支持。比如使用AES加速:

TEE_OperationHandle op_handle; TEE_AllocateOperation(&op_handle, TEE_ALG_AES_CBC_NOPAD, TEE_MODE_ENCRYPT, 256); TEE_SetOperationKey(op_handle, key_handle); TEE_CipherInit(op_handle, iv, sizeof(iv)); TEE_CipherUpdate(op_handle, src, src_len, dst, &dst_len); TEE_FreeOperation(op_handle);

最后提醒一个容易忽略的点:TA的版本控制。在TA的makefile里定义版本号:

CFG_TA_VERSION ?= 0x01000000

这样在CA端可以检查TA版本是否兼容:

TEEC_Operation op; memset(&op, 0, sizeof(op)); op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); res = TEEC_InvokeCommand(&sess, TA_CMD_GET_VERSION, &op, NULL); if (res == TEEC_SUCCESS && op.params[0].value.a >= MIN_SUPPORTED_VERSION) { // 版本兼容 }
http://www.jsqmd.com/news/788857/

相关文章:

  • 用DAIN算法修复老视频,实测4K补帧效果与常见问题避坑(附Python代码)
  • 思源宋体如何让你的中文设计瞬间专业?7种粗细免费商用字体完全指南
  • 零基础AI翻唱制作:5分钟学会用AICoverGen创建专业级歌曲
  • 基于区块链的AI资产溯源:构建可信机器学习工作流
  • BooruDatasetTagManager:AI训练数据标注的终极指南,10倍效率提升的秘密
  • 从算法流程到硬件实现:深入剖析不恢复余数法与基2-SRT除法
  • 如何突破AMD Ryzen处理器性能瓶颈?深入解析SMU调试工具的技术革命
  • 教你如何回收天猫超市卡,轻松变现! - 团团收购物卡回收
  • Unity实战:用Mesh和Color.Lerp手搓一个可交互的3D热力图(附完整C#源码)
  • LibreDWG:打破CAD格式壁垒的跨平台开源解决方案
  • 将HermesAgent智能体工具接入Taotoken实现自定义模型供应商支持
  • QKeyMapper:5个技巧让你在Windows上实现零重启的按键映射
  • 基于大语言模型的文本因果推断:GPI方法原理与工程实践
  • 从数字孪生到空间原生,镜像视界引领港口全要素智能化
  • Nuendo实战排障——从无声到有声的驱动与连接设置指南
  • 终极指南:用AI算法轻松突破2048高分极限
  • 别再踩坑了!手把手教你用CCS9.0和普中开发板点亮TMS320F28335的第一盏灯
  • 易语言多线程下如何安全调用大漠插件?免注册方案与资源管理避坑指南
  • 天猫超市卡换现金,这个方法太简单了! - 团团收购物卡回收
  • 三步搞定抖音无水印下载:从零开始到批量收藏的完整指南
  • 别再手动调了!GraphPad Prism 高效批量处理Grouped数据的3个隐藏技巧
  • 别再只用柱状图了!用Origin 2020b的径向堆积条形图,让你的疫情数据报告更出彩
  • 保姆级教程:用Python解析STIM300的原始十六进制数据流(含陀螺仪、加速度计单位换算)
  • 永磁同步电机无速度传感器控制(二)——滑模观测器(五)【参数整定与鲁棒性验证】
  • Ubuntu 20.04 解锁Root桌面登录:从安全限制到图形化访问
  • snscrape协议级社交数据采集原理与工程实践
  • cann/hccl:通信算子重执行对整网性能说明
  • 视频播放效率革命:如何用Video Speed Controller每天节省2小时
  • 【ETL实战】StreamSets零代码构建实时数据管道
  • 【LlamaIndex 】源码剖析:RAG-First 的设计哲学——为什么“数据即基础设施“才是 Agent 时代的正解