前言
上一期我们对ISEE-M的整体设计架构,核心模块以及系统优势进行了介绍,尤其系统的安全能力,是为物联设备终端提供提供强大的安全保障的关键。而今天我们要介绍ISEE-M的开发工具环境以及开发示例。上一期还没看过的同学,欢迎进入点击链接了解详情~
提到SDK,相信大家最关心的就是部署是否简单快速?是否便于开发?文档是否通俗易懂?嗯,当然Yes~
ISEE-M SDK基于MCUXpresso SDK设计开发,支持GP TEE Client API,可扩展支持第三方RTOS。ISEE-M内部支持GP TEE Internal API,非常方便用户开发。部署简单,可一键合入MCUXpresso SDK。同时提供开发指南,帮助开发者快速着手开发。
ISEE-M SDK使用说明
- 开发环境
- 基于MCUXpresso SDK开发环境即可,无需额外环境准备
- 支持MCUXpresso SDK 2.6.2及以上
- 支持工具链/IDE: KEIL 5.28
- 目录结构
ISEE-M SDK基于MCUXpresso SDK设计开发,与MCUXpresso SDK低耦合,目录结构参考下图所示:
SDK工程结构分为示例工程和ISEE-M组件库两部分:
- 示例工程分为两个子工程,demo_project_ns是非安全工程(REE侧),对应开发业务中安全不敏感的逻辑,demo_project_s是安全工程(TEE侧),对应开发业务中安全敏感的操作(敏感数据或关键算法)。
- ISEE-M组件库的路径为middleware/iseem/sdk,doc存放ISEE-M相关文档,在include和library中,分别有teec和tee目录,teec由非安全工程使用,tee由安全工程使用。
- 支持API & Module概述
- GP TEE 客户端 API v1.0及以上
- GP TEE 内部 API v1.0及以上
- 支持PUF/HashCrypt/Casper/RNG等关键硬件模块
GP TEE Client API (部分API例举)
TEEC_InitializeContext
TEEC_FinalizeContext
TEEC_RegisterSharedMemory
TEEC_AllocateSharedMemory
TEEC_ReleaseSharedMemory
TEEC_OpenSession
TEEC_CloseSession
TEEC_InvokeCommand
GP TEE Internal API (部分API例举)
加密操作 API
TEE_CipherInit
TEE_CipherUpdate
TEE_CipherDoFinal
TEE_AsymmetricEncrypt
TEE_AsymmetricDecrypt
TEE_AsymmetricSignDigest
TEE_AsymmetricVerifyDigest
TEE_GenerateRandom
TEE_MACInit
TEE_MACUpdate
TEE_MACComputeFinal
TEE_MACCompareFinal TEE_DigestUpdate
TEE_DigestDoFinal
Trusted Storage API
TEE_OpenPersistentObject
TEE_CreatePersistentObject
TEE_CloseAndDeletePersistentObject
TEE_RenamePersistentObject
注:GlobalPlatform(GP)是跨行业的国际标准组织,致力于开发、制定并发布安全芯片的技术标准,以促进多应用产业环境的管理及其安全、可互操作的业务部署。
GlobalPlatform组织发布的GP相关规范可以在官方网站上获取:https://globalplatform.org/specs-library/?filter-committee=tee
《TEE Client API Specification v1.0_GPD_SPE_00》
《TEE_Internal_Core_API_Specification_v1.2.1》
- 开发CA/TA
CA(Client Application)泛指非安全侧(REE侧)的工程,可参考SDK目录中demo_project_ns。
TA(Trusted Application)泛指安全侧(TEE侧)的工程,可参考SDK目录中demo_project_s。
开发者可以基于提供的示例代码和开发指南,开发实现相应功能。
在本示例中,CA将敏感数据存储到TA的安全存储中,并在CA需要时从TA安全存储中读出敏感数据。CA和TA通过GP TEE Client API通信,TA将CA请求的敏感数据加密后存储到非易失存储中,加密及存储通过TEE Internal API实现。密钥存储在TEE侧,REE侧程序无法获得,从而保证了敏感数据的安全。
- CA代码片段如下:
- intcmd_type = CMD_ENCRYPT_AND_STORAGE_WRITE;
- constTEEC_UUID demo_ta_uuid = DEMO_TA_UUID;
- TEEC_Context context;
- TEEC_Session session;
- TEEC_InitializeContext(NULL,&context);
- TEEC_OpenSession(&context,&session,&demo_ta_uuid,0,NULL,NULL,NULL);
- TEEC_Operation operation;
- cmd_type = getchar();
- cmd_type -= 0x30;
- if(cmd_type == CMD_ENCRYPT_AND_STORAGE_WRITE)
- {
- paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,TEEC_NONE,
- TEEC_NONE,TEEC_NONE);
- params[0].tmpref.buffer = send_data;
- params[0].tmpref.size = sizeof(send_data);
- printf(“CA: send write command\n”,cmd_type);
- TEEC_InvokeCommand(&session,CMD_ENCRYPT_AND_STORAGE_WRITE,&operation,NULL);
- }
- elseif(cmd_type == CMD_STORAGE_READ_AND_DECRYPT)
- {
- hexdump8(“CA: prepare data buffer:”,receive_data,128);
- paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_OUTPUT,TEEC_NONE,
- TEEC_NONE,TEEC_NONE);
- params[0].tmpref.buffer = receive_data;
- params[0].tmpref.size = sizeof(receive_data);
- printf(“CA: send read command\n”,cmd_type);
- TEEC_InvokeCommand(&session,CMD_STORAGE_READ_AND_DECRYPT,&operation,NULL);
- hexdump8(“CA: receive data:”,receive_data,128);
- } else{
- printf(“cmd type %d not support\n”,cmd_type);
- }
- TEEC_CloseSession(&session);
- TEEC_FinalizeContext(&context);
- TA代码片段如下:
- TEE_OperationHandle operation = NULL;
- TEE_ObjectHandle keyObj = NULL;
- TEE_ObjectHandle dataObj = NULL;
- TEE_Attribute attr[1] = {0};
- TEE_Result res = TEE_ERROR_GENERIC;
- size_t output_len = 0;
- uint8_t *tmp_data_buf = NULL;
- if((data == NULL) || (len != 128))
- {
- returnTEE_ERROR_BAD_PARAMETERS;
- }
- output_len = len;
- tmp_data_buf = TEE_Malloc(len, 0);
- if(!tmp_data_buf)
- {
- LOG_ERR(“TEE Malloc buffer failed”);
- returnTEE_ERROR_OUT_OF_MEMORY;
- }
- LOG_INFO(“read data from persistent object.”);
- res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, (void*)obj_name,
- sizeof(obj_name), flags | TEE_DATA_FLAG_SHARE_READ |
- TEE_DATA_FLAG_ACCESS_WRITE_META, &dataObj);
- if(res != TEE_SUCCESS)
- {
- LOG_ERR(“TEE_OpenPersistentObject failed”);
- gotoout;
- }
- res = TEE_ReadObjectData(dataObj, tmp_data_buf, len, &output_len);
- if(res != TEE_SUCCESS)
- {
- LOG_ERR(“read object failed”);
- gotoout;
- }
- hexdump8(“TA: data from storage with encrpyt”,tmp_data_buf,output_len);
- LOG_INFO(“read data success.”);
- LOG_INFO(“decrypt data to ree buffer.”);
- res = TEE_AllocateOperation(&operation, TEE_ALG_AES_CBC_NOPAD,
- TEE_MODE_DECRYPT, 256);
- if(res != TEE_SUCCESS)
- {
- LOG_ERR(“allocate operation failed, res %x”, res);
- gotoout;
- }
- res = TEE_AllocateTransientObject(TEE_TYPE_AES, 256, &keyObj);
- if(res != TEE_SUCCESS)
- {
- LOG_ERR(“allocate key failed, res %x”, res);
- gotoout;
- }
- TEE_InitRefAttribute(attr, TEE_ATTR_SECRET_VALUE, key, sizeof(key));
- res = TEE_PopulateTransientObject(keyObj, attr, 1);
- if(res != TEE_SUCCESS)
- {
- LOG_ERR(“populate key failed, res %x”, res);
- gotoout;
- }
- res = TEE_SetOperationKey(operation, keyObj);
- if(res != TEE_SUCCESS)
- {
- LOG_ERR(“set key failed, res %x”, res);
- gotoout;
- }
- TEE_CipherInit(operation, iv, sizeof(iv));
- res = TEE_CipherUpdate(operation, tmp_data_buf, output_len, data,
- (size_t*)&len);
- if(res != TEE_SUCCESS)
- {
- LOG_ERR(“cipher update failed, res %x”, res);
- gotoout;
- }
- res = TEE_CipherDoFinal(operation, NULL, 0, data, (size_t*)&len);
- if(res != TEE_SUCCESS)
- {
- LOG_ERR(“cipher dofinal failed, res %x”, res);
- gotoout;
- }
- LOG_INFO(“decrypt data success.”);
- 工程编译
工程编译操作超简单,打开工程->编译->烧写 三步走即可。
演示工程环境说明:
- 芯片型号:LPC55S69-EVK
- MCUXpresso SDK版本:2.6.2
编译步骤:
- Keil打开示例程序工程/boards/lpcxpresso55s69/iseem_examples/demo/cm33_core0/demo_project_s/mdk/demo_project.uvmpw ,该操作会打开demo_project_s,demo_project_ns两个子工程。
- 依次编译demo_project_s和demo_project_ns工程。
- 设置demo_project_s为活动工程,连接device,烧写。
- 主要功能
在本示例中,CA将敏感信息存储到TA的安全存储中,并在CA需要时从TA安全存储中读出敏感信息。
CA和TA通过GP TEE Client API通信,TA将CA请求的敏感信息加密后存储到非易失存储中,加密及存储通过TEE Internal API实现。密钥存储在TEE侧,REE侧程序无法获得,保证了密钥的安全。
程序可根据终端传入的参数来执行对应的功能。输入参数1,将信息存储到安全存储中;输入参数2,将信息从安全存储中读出。
- API使用代码示例&编译
这部分已经在前面介绍,这里不再赘述。
- 运行演示
运行前,先准备串口环境,用于查看运行结果。串口工具有很多,例如putty。在串口工具中,设置好芯片设备的COM号以及波特率115200运行即可。
示例程序在串口中运行结果演示如下:
我们还将继续推出此系列的后续文章,敬请持续关注豆荚科技公众号。