secGear跨架构机密计算开发套件介绍

top_tony
发布于 2022-8-17 18:11
浏览
0收藏

机密计算简介
随着网络与计算业务的快速发展,越来越多的关键性服务和高价值数据被迁移到了云端,使得相应的安全保护也变得更加困难。当前的成熟保护方法通常作用于静态存储或网络传输状态的数据,但是难以有效保护正在被使用中的数据,这也是安全保护中最具挑战性的技术难题。此外,根据包括欧盟 GDPR 和我国个人信息保护法等要求来看,数据隐私监管保护的范围愈加扩大、力度日益增强。因此,对关键数据和业务进行安全保护,不仅是技术挑战,也是满足合规遵从要求的必要条件。

secGear跨架构机密计算开发套件介绍-鸿蒙开发者社区

图 1  机密计算基本原理示意图

机密计算是一种利用硬件可信执行环境(Trusted Execution Environment, TEE)来保护被处理的数据的技术 [1]。这些安全的、隔离的TEE环境可防止对使用中的应用程序和数据进行未经授权的访问或篡改,从而提升相关组织在管理敏感数据和受监管数据方面的安全级别。2019年8月,Linux基金会宣布成立“机密计算联盟”(Confidential Computing Consortium),其成员包括了国内的华为、阿里、百度、字节跳动,以及国外的ARM、AMD、Intel、IBM、红帽、英伟达、微软、谷歌等科技巨头,标志着机密计算产业的进一步发展和壮大。

Intel酷睿处理器放弃SGX特性

近日,Intel第11、12代酷睿芯片Datasheet中声明停止支持SGX,影响使用第11、12代酷睿芯片的笔记本、台式机、工作站(不涉及服务器,服务器主要是Xeon系列处理器),引起机密计算业界的广泛关注。

secGear跨架构机密计算开发套件介绍-鸿蒙开发者社区

图 2  第12代酷睿手册宣布放弃SGX特性

虽然Intel在酷睿处理器上放弃了SGX,但这并不代表机密计算即将走向“末路”。细究之下,反而昭示着机密计算新的发展方向。TrustZone、SGX代表了业界早期对TEE技术的探索,而随着云计算、serverless等场景的发展演进,机密计算对TEE的需求也不断变化,催生了如AMD SEV、Intel TDX、ARM CCA等新的架构设计,能够更好地满足安全应用的便捷开发和灵活部署的要求。而且,SGX本身仍然在不断发展完善中,当前第三代可扩展Intel Xeon服务器处理器也支持最新的SGX特性。

openEuler secGear机密计算统一编程框架
机密计算是基于硬件可信执行环境保护使用中数据的解决方案,面对硬件的突然停止支持,机密计算应用开发者该如何最大限度地降低不利影响呢?

secGear跨架构机密计算开发套件介绍-鸿蒙开发者社区

图 3 secGear统一机密计算开发框架

    openEuler很早就关注了机密计算。各芯片阵营都推出了机密计算解决方案,如Intel SGX、ARM TrustZone以及RISC-V Penglai等。但由于硬件架构差异,各厂商的机密计算解决方案存在天然不同,导致SDK接口也存在很大差异,给开发者带来较高的学习成本和跨平台部署的难题,让部分应用开发者望而却步。为此,openEuler打造了开源的机密计算统一开发框架secGear(https://gitee.com/openeuler/secGear),基于SGX、TrustZone等的机密计算SDK为开发者提供了统一极简的编程接口,从而实现不同架构共源码、降低安全应用开发维护成本,使得应用开发者、用户能够轻松享受机密计算带来的安全与便利。基于secGear开发的机密计算应用中,也不乏像银联车充无感支付 [2]、GaussDB全密态数据库 [3]等重量级安全解决方案。

如图 3所示,secGear提供的主要特性包括:

多种硬件可信执行环境支持
多种硬件可信执行环境支持:目前secGear已支持包括Intel SGX、ARM TrustZone(安全OS支持iTrustee)以及RSIC-V(蓬莱TEE)平台,对Intel TDX和ARM CCA (Confidential Computing Architecture)的支持正在紧密规划中。

secGear跨架构机密计算开发套件介绍-鸿蒙开发者社区

图 4 secGear对车充无感支付方案开发屏蔽TEE环境差异

为了降低跨平台开发的难度,secGear支持开发者通过指定目标TEE平台来自动生成相应的enclave交互代码,亦称“代理函数”。由于不同平台的enclave加载与ecall调用机制的不同,使得对相同的安全侧函数调用也产生极大的差异,加剧了跨平台开发、部署的难度。因此,secGear通过自动生成ecall调用相关代理函数,使得ecall调用简洁轻松,无需开发者关注SDK调用实现细节,真正实现了底层TEE环境对开发者透明。例如,在车充无感支付方案的开发中,开发者只需实现一套识别车辆的安全函数(如ecall_identify_car),那么开发者就可以在非安全侧以该函数名直接调用,而由secGear自行对接不同平台的SDK编程模型、处理ecall调用细节的差异,从而达到屏蔽底层TEE环境差异、降低开发者的学习成本的目的。

统一的安全应用开发接口
统一的安全应用开发接口:使用secGear提供的统一编程接口,程序可轻松调用secGear提供的机密计算服务、中间件和基础安全能力,使得开发者只需编写一次代码,即可轻松实现对不同可信执行环境的支持。

secGear跨架构机密计算开发套件介绍-鸿蒙开发者社区

图 5  使用secGear简化应用开发维护

以往,由于不同TEE的SDK接口千差万别,开发者编写应用时需要学习不同SDK手册,在开发中更要按照特定TEE平台接口来实习对enclave的访问。以一个简单的helloworld程序ecall调用为例:在SGX平台上可以自定义ecall_helloworld()函数,然后将enclave代码编译为so文件,最后进行必要的签名,才能运行enclave;在TrustZone平台上要使用TEEC_InvokeCommand()并传入itrustee_helloworld()对应的操作码来访问,还要事先将安全侧代码构建为.sec格式的签名文件;而在Penglai TEE中,则要使用PLenclave_run()来运行enclave实例,才能运行事先编译好的Penglai-ELF文件中的penglai_helloworld()程序。这样无疑使得跨平台程序的开发、维护和迁移变得十分棘手。相比之下,使用secGear开发的安全应用只需通过cc_create_enclave()统一接口实现在不同TEE平台上加载enclave二进制文件,然后统一利用ecall_helloworld()来调用ecall,无需关心平台差异。其次,开发者在构建时指定目标TEE类型,则可自动生成对应的ecall调用过程代理函数并构建生成相应平台的encalve二进制文件,实现“不同平台共源码”,极大简化应用开发与维护过程。

下面通过一个简单的demo来展示secGear、SGX、iTrustee开发的差异。在这个示例中,安全应用要借助TEE完成对输入数据的加法操作。为此,开发者需要初始化enclave,调用ecall完成计算,最后销毁enclave实例。在这一过程中,通过展示通过SGX、iTrustee和secGear开发安全应用的代码片段,使读者们更加形象直观地感受到使用secGear开发带来的便利性。

编写这一安全应用的具体步骤如下:

  • Step 1,编写安全侧ecall函数
    /* Intel SGX 原生方式*/
    
    int add(int a, int b)
    
    {
    
    return a + b;
    
    }​
/* iTrustee原生方式*/

TEE_Result cmd_add_inputs(uint32_t paramTypes, TEE_Param params[PARAMS_IDX4])

{

TEE_Result ret;

errno_t rc;

rc = EOK;

/* params type check */

if (!check_param_type(paramTypes,

TEE_PARAM_TYPE_VALUE_INPUT,

TEE_PARAM_TYPE_VALUE_INPUT,

TEE_PARAM_TYPE_VALUE_OUTPUT)) {

SLogError("Bad expected parameter types.");

return TEE_ERROR_BAD_PARAMETERS;

}

int32_t input_a= params[0].value.a;

int32_t input_b= params[1].value.a;

params[2].value.a result = input_a + input_b;

ret = TEE_SUCCESS;

return ret;

}

可以看出,在itrustee上编写ecall时,其参数处理与SGX有明显不同,导致函数的逻辑比较复杂。为了屏蔽这些细节和差异, secGear SDK自身去处理不同TEE平台上的ecall参数处理。故使用secGear开发时,其代码如下:

/* secGear ecall开发*/

int add(int a, int b)

{

return a + b;

}

相应的,这个ecall在SGX和itrustee上生成的代码分别如下。

/* SGX ecall函数代理 */

sgx_status_t SGX_CDECL sgx_add(void* pms)

{

CHECK_REF_POINTER(pms, sizeof(ms_add_t));

sgx_lfence();

ms_add_t* ms = SGX_CAST(ms_add_t*, pms);

sgx_status_t status = SGX_SUCCESS;

ms->ms_retval = add(ms->ms_a, ms->ms_b);

return status;

}
/* iTrustee ecall函数代理 */

cc_enclave_result_t ecall_add (

uint8_t* in_buf,

size_t in_buf_size,

uint8_t* out_buf,

size_t out_buf_size,

size_t* output_bytes_written)

{

cc_enclave_result_t result = CC_FAIL;

size_t in_buf_offset = 0;

size_t out_buf_offset = 0;

/* Prepare parameters point */

uint8_t *retval_p = NULL;

uint8_t *a_p = NULL;

uint8_t *b_p = NULL;

if (in_buf == NULL || out_buf == NULL)

goto done;

add_size_t *args_size = (add_size_t *)in_buf;

in_buf_offset += size_to_aligned_size(sizeof(*args_size));

/* Fill in and in-out parameters */

SET_PARAM_IN_1(a_p, int, a, args_size->a_size);

SET_PARAM_IN_1(b_p, int, b, args_size->b_size);

/* Fill return val, out and in-out parameters */

SET_PARAM_OUT(retval_p, int, retval, args_size->retval_size);

/* Check if the input and output buffers can be visited */

if (!in_buf || !cc_is_within_enclave(in_buf, in_buf_size))

goto done;

if (out_buf && !cc_is_within_enclave(out_buf, out_buf_size))

goto done;

/* Call host function */

* retval = add(a, b);

/* Sucess */

result = CC_SUCCESS;

*output_bytes_written = out_buf_offset;

done:

return result;

}

相比之下,secGear自动处理了不同平台上的数据传输差异。尤其是在iTrustee平台上,生成的ecall代理函数自动对参数个数和类型进行校验,然后调用开发者编写的add()逻辑,使得开发者能更好地聚焦业务。

  • Step 2,在非安全侧初始化enclave实例并调用ecall
    /* SGX. ENCLAVE_FILENAME为SGX enclave文件路径 */
    
    ret = sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, NULL, NULL, &global_eid, NULL);
    
    if (ret != SGX_SUCCESS) {
    
    print_error_message(ret);
    
    return -1;
    
    }
    
    // 调用add
    
    int result = add(global_eid, a, b);
    
    /* iTrustee. 首先初始化g_context,再加载enclave */
    
    TEEC_Result result = TEEC_InitializeContext(NULL, &g_context);
    
    if (result != TEEC_SUCCESS) {
    
    TEEC_Error("teec initial failed");
    
    return result;
    
    }
    
    /* pass TA's FULLPATH to TEE, then OpenSession. */
    
    (void)memset_s(&operation, sizeof(operation), 0x00, sizeof(operation));
    
    operation.started = 1;
    
    operation.paramTypes = TEEC_PARAM_TYPES(
    
    TEEC_NONE,
    
    TEEC_NONE,
    
    TEEC_MEMREF_TEMP_INPUT,
    
    TEEC_MEMREF_TEMP_INPUT);
    
    g_context.ta_path = (uint8_t *)RSA_CRYPTO_DEMO_TA_PATH;
    
    result = TEEC_OpenSession(&g_context, &g_session, &RSA_CRYPTO_uuid, TEEC_LOGIN_IDENTIFY, NULL, &operation, &origin);
    
    if (result != TEEC_SUCCESS) {
    
    TEEC_Error("open session failed: result:%d orgin: %d.", (int)result, origin);
    
    TEEC_FinalizeContext(&g_context);
    
    return result;
    
    }
    
    // 调用cmd_add_inputs
    
    TEEC_Operation operation;
    
    (void)memset_s(&operation, sizeof(operation), 0x00, sizeof(operation));
    
    operation.started = 1;
    
    operation.paramTypes = TEEC_PARAM_TYPES(
    
    TEEC_Value,
    
    TEEC_Value,
    
    TEEC_Value,
    
    TEEC_NONE);
    
    operation.params[0].tmpref.buffer = msgBuf;
    
    operation.params[0].tmpref.size = RSA_MASSAGE_SIZE;
    
    // CMD_ADD_INPUTS 是代表cmd_add_inputs()的操作码
    
    result = TEEC_InvokeCommand(&g_session, CMD_ADD_INPUTS, &operation, &origin);
    
    if (result != TEEC_SUCCESS) {
    
    TEEC_Error("invoke cmd_add_inputs failed, codes=0x%x, origin=0x%x", result, origin);
    
    return result;
    
    }​

相应的,使用secGear调用ecall时,其代码大致如下:

/* secGear. PATH为enclave文件路径 */

res = cc_enclave_create(PATH, AUTO_ENCLAVE_TYPE, 0, SECGEAR_DEBUG_FLAG, NULL, 0, &context);

if (res != CC_SUCCESS) {

printf("Create enclave error\n");

return -1;

}

/* add in enclave */

int num1 = 1, num2 = 2, sum = 0;

res = add(&context, &sum, num1, num2);

if (res != CC_SUCCESS) {

printf("Ecall in enclave error:%d\n", res);

(void)cc_enclave_destroy(&context);

return -1;

}

相应的,cc_enclave_create()为secGear根据不同TEE类型创建enclave实例的接口,而调用ecall的代码在不同平台上生成的代理函数如下:

/* SGX ecall调用代理函数 */

cc_enclave_result_t add(cc_enclave_t *enclave, int* retval, int a, int b)

{

cc_enclave_result_t result;

ms_add_t ms;

ms.ms_a = a;

ms.ms_b = b;

if(!enclave)

return CC_ERROR_BAD_PARAMETERS;

if (pthread_rwlock_rdlock(&enclave->rwlock))

return CC_ERROR_BUSY;

if (!enclave->list_ops_node || !enclave->list_ops_node->ops_desc ||

!enclave->list_ops_node->ops_desc->ops ||

!enclave->list_ops_node->ops_desc->ops->cc_ecall_enclave)

return CC_ERROR_BAD_PARAMETERS;

result = enclave->list_ops_node->ops_desc->ops->cc_ecall_enclave(enclave,

0, NULL, 0, NULL, 0, &ms, &ocall_table_helloworld);

pthread_rwlock_unlock(&enclave->rwlock);

if (result == CC_SUCCESS && retval) *retval = ms.ms_retval;

return result;

}

/* iTrustee ecall调用代理函数 */

cc_enclave_result_t add(

cc_enclave_t *enclave,

int* retval,

int a,

int b)

{

cc_enclave_result_t ret = CC_FAIL;

/* Init buffer and size  */

size_t in_buf_size = 0;

size_t out_buf_size = 0;

uint8_t* in_buf = NULL;

uint8_t* out_buf = NULL;

uint32_t ms = TEE_SECE_AGENT_ID;

add_size_t args_size;

/* Init pointer */

size_t retval_p;

size_t a_p;

size_t b_p;

memset(&args_size, 0, sizeof(args_size));

/* Fill argments size */

args_size.retval_size = size_to_aligned_size(sizeof(int));

args_size.a_size = size_to_aligned_size(sizeof(int));

args_size.b_size = size_to_aligned_size(sizeof(int));

in_buf_size += size_to_aligned_size(sizeof(add_size_t));

/* Fill data in */

SIZE_ADD_POINT_IN(a_p, args_size.a_size);

SIZE_ADD_POINT_IN(b_p, args_size.b_size);

/* Fill data out */

SIZE_ADD_POINT_OUT(retval_p, size_to_aligned_size(sizeof(int)));

/* Allocate in_buf and out_buf */

in_buf = (uint8_t*)malloc(in_buf_size);

out_buf = (uint8_t*)malloc(out_buf_size);

if (in_buf == NULL || out_buf == NULL) {

ret = CC_ERROR_OUT_OF_MEMORY;

goto exit;

}

/* Copy in_params to in_buf*/

memcpy(in_buf, &args_size, sizeof(add_size_t));

memcpy(in_buf + a_p, (uint8_t *)&a, sizeof(int));

memcpy(in_buf + b_p, (uint8_t *)&b, sizeof(int));

/* Call the cc_enclave function */

if (!enclave) {

ret = CC_ERROR_BAD_PARAMETERS;

goto exit;

}

if (pthread_rwlock_rdlock(&enclave->rwlock)) {

ret = CC_ERROR_BUSY;

goto exit;

}

if (!enclave->list_ops_node || !enclave->list_ops_node->ops_desc ||

!enclave->list_ops_node->ops_desc->ops ||

!enclave->list_ops_node->ops_desc->ops->cc_ecall_enclave) {

ret = CC_ERROR_BAD_PARAMETERS;

goto exit;

}

if ((ret = enclave->list_ops_node->ops_desc->ops->cc_ecall_enclave( enclave, fid_add,

in_buf, in_buf_size, out_buf, out_buf_size, &ms, &ocall_table)) != CC_SUCCESS) {

pthread_rwlock_unlock(&enclave->rwlock);

goto exit;

}

if (pthread_rwlock_unlock(&enclave->rwlock)) {

ret = CC_ERROR_BUSY;

goto exit;

}

/* Copy out_buf to out_params */

memcpy(retval, out_buf + retval_p, sizeof(int));

ret = CC_SUCCESS;

exit:

if (in_buf)

free(in_buf);

if (out_buf)

free(out_buf);

return ret;

}

通过对比可以看出,在不同平台上处理ecall入/出参数的过程被secGear巧妙地进行了封装。开发者只需使用自己定义的ecall函数名就可以轻松与enclave交互。

-Step 3, 销毁enclave实例

/* SGX 销毁enclave */

sgx_destroy_enclave(global_eid);

/* iTrustee 销毁enclave */

TEEC_CloseSession(&g_session);

TEEC_FinalizeContext(&g_context);

而使用secGear时,销毁enclave只需一行代码:

res = cc_enclave_destroy(&context);

通过上面的开发过程可以看出,基于secGear开发的程序可以便捷地在不同TEE平台上生成对应的封装/代理函数,而安全应用代码无需更改,从而实现“不同架构共源码”。

丰富的安全功能和服务
secGear当前提供一整套完善的TEE交互功能和常见的安全服务。其基本功能包括enclave生命周期管理、seal/unseal、代码生成工具、签名工具等兼容接口和工具,并在安全侧支持POSIX APIs 和标准OpenSSL接口。除此之外,它还提供常见的安全组件、安全函数库及安全服务,如安全通道/TLS、 PAKE等,开发者可以直接调用相关接口或服务,不必从头造轮子。

secGear跨架构机密计算开发套件介绍-鸿蒙开发者社区

图 6  基于secGear开发的密态数据库架构图 [3]

以GaussDB全密态数据库为例,其开发也受益于secGear丰富的安全特性。例如,为了实现安全传输客户端数据加密密钥至服务器TEE环境中,全密态数据库采用了secGear提供的安全通道能力。据此,TEE内的安全应用代码和数据库客户端能通过安全可信的方式协商数据传输的加密密钥,而无需担心被非安全侧恶意窥探或被网络中的攻击者窃取机密信息。此外,基于标准OpenSSL接口,密态数据库开发者能够在TEE中方便地实现可靠的数据加解密逻辑,大大减轻了开发、维护的工作量。

鉴于不同硬件可信执行环境方案的差异,secGear致力于提供最大限度的编程接口兼容性及应用可移植性。但是,secGear是对SDK能力的封装,而不是在硬件层面兼容不同可信执行环境,因此enclave的部署运行仍然受到硬件的制约。例如,Intel 11、12代酷睿芯片不支持SGX了,那么基于secGear开发的应用程序也不能在这些处理器上运行,但是开发者可以零成本改造这些enclave程序并轻松迁移到ARM TrustZone等其他平台上运行。

展望
从发展趋势来看,随着新一代可信执行环境技术的推出,机密计算将更专注服务器平台和云上应用场景。secGear将一如既往地持续关注Intel TDX、ARM CCA等技术的演进,为打造安全易用的机密计算统一开发框架而不懈努力。

 

(文章转载自公众号:架构与思维)

已于2022-8-17 18:11:53修改
收藏
回复
举报
回复
    相关推荐