SGX软硬件栈(三)——驱动接口、SGX API

驱动接口

驱动接口的主要功能还是向不可信运行时uRTS提供管理Enclave生命周期的功能,会在内核权限硬件指令基础之上完成具体的生命周期管理能力。

SGX API

这里将介绍运行时环境(uRTS由Platform Software提供、tRTS由SDK提供)向开发者提供了哪些API供使用。这是SGX开发者直接接触的部分。

1. 可信运行时库函数

由于Enclave程序会被放在Enclave Page中,与其他内存存在隔离,因此无法链接动态链接库来实现各种丰富的传统开发能有的功能,只能链接静态链接库,也就是将需要用到的静态链接库函数一并放到Enclave内存中。因此静态链接库的丰富程度决定了Enclave程序开发的便利程度。为了满足Enclave程序尽可能能够像传统开发一样便利,因此提供了一系列包括C/C++标准库、可信密码学库等源码用于静态链接。由于静态链接库一旦出现安全性问题会直接影响Enclave程序,因此所能使用的库函数是需要经过安全审计的,所以需要剔除或者重新实现不安全的库函数,此外为了便于开发提供可信的密码学相关操作的库函数。总而言之,可信库函数的提供需要满足安全性及便利性。

a. 可信运行时系统服务

一些起到帮助性质的库函数。

  1. sgx_is_within_enclave、sgx_is_outside_enclave:可以帮助开发人员判断一个地址是否在Enclave内存中。
  2. sgx_read_rand:提供一个真随机函数。Enclave不支持链接C/C++标准库里的rand、srand,因为它们是伪随机函数,从库中被剔除。

b. 自定义异常处理函数

当Enclave中发生了硬件异常,将由异常处理链来逐级处理硬件异常。tRTS提供了函数使得开发者的Enclave程序能通过注册处理函数来具体处理部分硬件异常,然后再将异常交给原来的异常处理链处理,或者说将这个异常处理句柄追加到异常处理链中。

  1. sgx_register_exception_handler:注册一个异常处理句柄,将它追加到异常处理链。
  2. sgx_unregister_exception_handler:注销一个异常处理句柄。

c. 为CPUID准备的自定义异常处理函数

Enclave中不支持直接使用CPUID指令,若想在Enclave中操作CPUID指令,得通过libsgx_tstdc.a中的函数sgx_cpuid、sgx_cpuid_ex或内联函数__cpuid、__cpuidex调用ocall进入uRTS具体实现。由于是uRTS下执行,所以最好检查CPUID指令返回值和Ocall返回值。如果Enclave中用到第三方库用到了CPUID指令,需要开发者做分析检查,处理CPUID异常或者开发者直接给出CPUID结果而不去真正调用CPUID。

d. 可信服务库

可信服务库sgx_tservice主要用于安全的数据操作和保护。第一部分函数是对SGX硬件指令包装。

  1. sgx_get_key:产生一个128位的私钥,是对EGETKEY硬件指令的包装。
  2. sgx_create_report:创建一个目标Enclave的报告,是对EREPORT硬件指令的包装。
  3. sgx_verify_report:对sgx_create_report产生报告提供软件验证。
  4. sgx_self_report:创建自身Enclave的密码学报告。
  5. sgx_self_target:函数sgx_self_target使用Enclave的自身的加密学报告生成自身的“目标信息”(另一种实用的结构,更加丰富地描述Enclave的信息)。可以使用它来获取在Enclave间的认证过程所用到的“目标信息”。

第二部分函数是用于将数据密封到SGX平台的不可信存储中的函数。Enclave被关闭或重启的情况下,Enclave中数据将随Enclave销毁而消失,如果有些数据未来需要被用到,那么就需要加密存储不可信存储中。

  1. sgx_seal_data、sgx_seal_data_ex:sgx_seal_data函数找到一个Enclave独有的用于Seal(封装数据)的密钥,并使用该密钥加密输入数据缓冲区。在销毁enclave之后,可以使用这个函数来保存机密数据。密封的数据块可以在Enclave的未来实例化时打开。sgx_seal_data_ex在sgx_seal_data基础上,可以自定义Seal密钥的导出过程。
  2. sgx_unseal_data:实用Enclave的Seal密钥来解密之间Seal过的数据块。
  3. sgx_mac_aadata、sgx_mac_aadata_ex:对密封数据使用Enclave独有的密钥生成AES-GMAC,用于标识这个密封数据对应于该Enclave。
  4. sgx_unmac_aadata:通过比对密封数据(计算MAC)及其之前生成的AES-GMAC数据判断是否是这个密封数据是否是同个Enclave之前的实例生成的。

第三部分函数用于帮助计算密封数据的大小、加密文本长度和消息验证码(MAC)文本长度。

  • sgx_calc_sealed_data_size、sgx_get_add_mac_txt_len、sgx_get_encrypt_txt_len:帮助密封库函数确定在具体操作时为一些关键结构分配内存的大小

e. 可信平台服务函数

允许开发者使用平台服务(PSE,Paltform Service Enclave)或者获得平台服务安全属性。.

  1. sgx_create_pse_session、sgx_close_pse_session:创建和关闭与PSE之间的会话,会话用于请求平台服务。
  2. sgx_get_ps_sec_prop、sgx_get_ps_sec_prop_ex:用于获得平台服务的安全属性的描述。
  3. sgx_get_trusted_time:从AE获取可信的时间
  4. sgx_create_monotonic_counter_ex、sgx_create_monotonic_counter:用于创建一个处于非易失性内存(Non-volatile Memory)的有安全保障的单调计数器,用于比如密封数据版本号等维护,防止密封数据的回滚攻击等。
  5. sgx_destroy_monotonic_counter:销毁单调性计数器。
  6. sgx_increment_monotonic_counter:对单调性计数器进行加一操作。
  7. sgx_read_monotonic_counter:读取单调性计数器当前的值。

 f. Diffie–Hellman (DH)会话建立函数 

帮助开发者使用ECDH密钥交换协议在两个Enclave间建立安全会话。

  1. sgx_dh_init_session:用于初始化会话建立的请求方和应答方。
  2. sgx_dh_responder_gen_msg1、sgx_dh_initiator_proc_msg1、sgx_dh_responder_proc_msg2、sgx_dh_initiator_proc_msg3:用于具体的ECDH密钥交换过程。

 g. C 标准库 

sgx_tstdc提供了可信标准C库,同时这个库只能在Enclave中使用。目前支持C99子集,代码来自OpenBSD项目。不支持部分函数的原因:

  1. 函数定义用到了受限制的CPU指令。
  2. 函数定义已知是不安全的。
  3. 函数定义太大了或者函数定义严重依赖于不可信世界的数据。
  4. 需要特定编译器

具体的函数支持情况:

  1. Locale函数:地域设置,如中文操作系统下,显示中文、中国人习惯的日期格式等,Localization数据过大,不适合放Enclave。
  2. 随机数生成函数:不安全的为随机函数,提供了一个真随机sgx_read_rand。
  3. 字符串函数:不安全的字符串操作函数,安全的字符串操作函数仍然可用(strncpy等)。
  4. Abort函数:语义有区别,一旦一个Enclave线程发出abort,那么Enclave处于Unusable状态,不再启动新的Enclave线程,当所有Enclave线程都退出后,这个Enclave就被锁定不再被发现。
  5. 线程同步基元:提供互斥量同步、条件变量同步、线程管理但不支持Enclave内部创建线程。
  6. 在Enclave内查询CPUID:sgx_cpuid、sgx_cpuidex。
  7. 安全函数:_s后缀的函数,在mbusafecrt.h中。
  8. GCC 内建函数:为了优化代码,GCC可能将如malloc替换成内建的__bultin_malloc,这样可能使得Enclave中的代码内联了不安全的内建函数。可以通过fno-builtin or -fno-builtin-function编译选项来禁止。
  9. Non-Local Jumps:标准C库提供了setjmp(记录程序状态)、longjmp(恢复在之前记录的程序状态),longjmp可能破坏栈结构,在C程序使用中要保证这些指令被用在未知行为上。

h. C++ 语言支持

C++语言特性支持情况。ISO/IEC 14882:SGX对定义的C++库大部分语言特性完全支持,包括:

  1. 动态内存分配:new/delete
  2. 支持全局的Initializers,通常用于构建全局对象
  3. Run-time Type Identification (RTTI)
  4. Enclave内部C++异常处理函数

× 不支持全局Destructors,因为Enclave销毁时,EPC会被回收。

× Enclave接口定义中不支持C++对象,如果需要外部往Enclave传参,需要另外保存成C结构体。

C++标准库支持情况:支持了一套遵循C++11标准的可信C++标准库(包括STL)。有多个版本的C++标准库可以被链接:

  1. sgx_tcxx.a(默认):从libc++移植,支持大部分C++11特性。
  2. sgx_tstdcxx.a(较老的):源自STLport,支持有限的C++11特性。

不支持的函数如下:

  1. I/O相关的函数和类,如<iostream>
  2. 依赖locale库的函数
  3. 需要系统调用的函数

只有C语言函数可以作为Enclave与外部的桥接函数。

i. 密码学库

SDK提供了可信密码学库sgx_tcrypto,这同时会被其他可信库如sgx_tservice用到。可信密码学库基于Intel Integrated Performance Primitives (Intel IPP)或Intel Software Guard Extensions SSL cryptographic library (Intel SGX SSL)。sgx_tcrypto库函数包括(除IPP、SGX SSL外的函数,一类适用于单独的直接对单数据集进行密码学运算,另一类是构建管理句柄对多个数据集进行管理和运算):

  1. sgx_sha256_msg:提供标准的SHA256散列。
  2. sgx_sha256_init、sgx_sha256_update、sgx_sha256_get_hash、sgx_sha256_close:用于多数据集的SHA256的管理及运算。
  3. sgx_rijndael128GCM_encrypt、sgx_rijndael128GCM_decrypt:用于单独的Rijndael AES-GCM的加解密操作。
  4. sgx_aes_gcm128_enc_init、sgx_aes_gcm128_enc_update、sgx_aes_gcm128_enc_get_mac、sgx_aes_gcm_close:用于多数据集的AES-GCM128位的管理和运算。
  5. sgx_rijndael128_cmac_msg:提供独立的标准的CMAC散列计算。
  6. sgx_cmac128_init、sgx_cmac128_update、sgx_cmac128_final、sgx_cmac128_close:用于多数据集之上的CMAC128位散列的管理和运算。
  7. sgx_aes_ctr_encrypt、sgx_aes_ctr_decrypt:提供单独的Rijndael AES-CTR加解密运算。
  8. sgx_ecc256_open_context、sgx_ecc256_close_context、sgx_ecc256_create_key_pair、sgx_ecc256_compute_shared_dhkey、sgx_ecc256_check_point:提供ECC256操作的管理和具体运算。
  9. sgx_ecdsa_sign、sgx_ecdsa_verify、sgx_ecdsa_verify_hash:用于ECDSA签名和验证。
  10. sgx_rsa3072_sign、sgx_rsa3072_verify:用于RSA3072的签名和验证。
  11. sgx_create_rsa_key_pair、sgx_create_rsa_priv2_key、sgx_create_rsa_pub1_key、sgx_free_rsa_key:用于构建和销毁RAS密钥。
  12. sgx_rsa_priv_decrypt_sha256、sgx_rsa_pub_encrypt_sha256:RSA-OAEP加密模式的SHA256算法的加解密。
  13. sgx_calculate_ecdsa_priv_key:利用随机种子产生ECDSA私钥。
  14. sgx_ecc256_calculate_pub_from_priv:利用ECC私钥计算ECC公钥。
  15. sgx_hmac_sha256_msg:提供标准的HMAC散列。
  16. sgx_hmac256_init、sgx_hmac256_update、sgx_hmac256_final、sgx_hmac256_close:提供多数据集上的HMAC256散列的管理和运算。

j. 可信密钥交换函数

  • sgx_ra_init、sgx_ra_init_ex、sgx_ra_get_keys、sgx_ra_close:用于远程验证和交换密钥的管理和操作。

k. Intel受保护文件系统库

提供了常规C语言文件操作API的子集,写过程中,文件被加密存储在不可信磁盘中,读取过程中会验证文件的机密性和完整性,功能上总体接近传统的文件库函数。

  1. sgx_fopen、sgx_fopen_auto_key、sgx_fclose、sgx_fread、sgx_fwrite、sgx_fflush、sgx_ftell、sgx_fseek、sgx_feof、sgx_remove:用于受保护文件的开关、创建、读写、定位、删除等功能。
  2. sgx_ferror、sgx_clearerr:返回或清除文件错误
  3. sgx_fexport_auto_key、sgx_fimport_auto_key:用于导入导出最新的用于文件加解密操作的密钥
  4. sgx_fclear_cache:清除内部的文件缓冲。

l. TCMalloc

  • malloc、free、realloc、calloc、memalign:提供了可信的经过安全审计的TCMalloc库版本(sgx_tcmalloc库,从gperftools-2.5移植)

m. Switchless调用库

不可信世界包含switchless调用的不可信部分,如sgx_create_enclave_ex使用switchless模式创建enclave;可信世界中libsgx_tswitchless.a库提供switchless调用的可信部分,主要是维护可信世界中switchless调用的特性,能够让不可信世界switchless调用能够进入到可信世界正常运作。(见下文“SGX Switch模式及Switchless模式”章节)

n. 受保护代码加载器库

维护不可信世界的“受保护代码加载”

2. 不可信运行时库

a. Enclave创建与销毁

  1. sgx_create_enclave、sgx_create_enclave_ex、sgx_create_enclave_from_buffer_ex、sgx_create_encrypted_enclave:用于创建Enclave,传入参数有所不同。
  2. sgx_destroy_enclave:用于销毁Enclave。

b. 证明函数

向应用程序或Enclave程序证明目标Enclave程序的确运行在SGX环境中。

  1. sgx_init_quote、sgx_calc_quote_size、sgx_get_quote_size、sgx_get_quote、sgx_report_attestation_status、sgx_check_update_status:采用Intel EPID(增强隐私标识)方案的证明的管理和获取。
  2. sgx_select_att_key_id、sgx_init_quote_ex、sgx_get_quote_size_ex、sgx_get_quote_ex:采用Intel EPID及ECDSA方案的证明的管理与获取。

c. 不可信密钥交换函数

用于不可信环境下远端服务器和Enclave程序的秘密交换

  1. sgx_ra_get_msg1、sgx_ra_proc_msg2:不可信环境下采用Intel EPID证明方案的远端服务器和Enclave程序的秘密交换。
  2. sgx_get_extended_epid_group_id:Intel EPID证明方案下,告诉远端服务器用的哪一个Intel EPID组。
  3. sgx_ra_get_msg1_ex、sgx_ra_proc_msg2_ex:不可信环境下采用Intel EPID证明及ECDSA证明方案的远端服务器和Enclave程序的秘密交换。

d. 不可信平台服务函数

sgx_get_ps_cap:说明平台服务PSE支持哪些功能

e. Intel SGX 使能和启动控制函数

  1. sgx_cap_enable_device:让应用程序能够动态开启SGX设备。
  2. sgx_register_wl_cert_chain:如果开发者有一个最新的Enclave签名密钥白名单证书链,则需要先调用此函数才能启动Enclave。
  3. sgx_get_whitelist_size:告诉应用程序白名单证书链的大小
  4. sgx_get_whitelist:告诉应用程序当前AE服务所支持的白名单证书链。

f. Intel SGX 设备能力函数

  1. sgx_is_capable:告诉应用程序SGX设备是否可用。
  2. sgx_cap_get_status:帮助开发者检查客户端平台的SGX状态,既SGX是否能用、是否能被开启。

3. SGX API应用举例——本地DH会话建立

想象这样一个场景,一个应用程序启动了若干不同Enclave实例,我们想让实例间构建起可信的会话通道,既ECDH密钥交换及会话建立(API函数见上文“Diffie–Hellman (DH)会话建立函数”章节)。

下文“桥函数”章节将会具体讲述应用程序如何进出Enclave。这里将简化此细节,直接表述为应用程序从不可信环境切换环境进入Enclave。

如图8所示,这里描述Enclave1、Enclave2(简称E1、E2)之间的会话建立。创建E1、E2实例,线程从APP切换至E1,然后调用sgx_dh_init_session这个API函数进入可信运行时(tRTS,由SDK提供,tRTS和Enclave同处于安全世界,不需要环境切换),将自己标记为会话请求方。E1会继续要求外部应用程序转告E2它想要和E2建立通讯。

切换至E2后,E2调用sgx_dh_init_session进入tRTS将自己初始化为应答方,然后调用sgx_dh_responder_gen_msg1,这样会调用硬件指令EREPOTE产生E2的报告,此外创建E2的公私钥对,把公钥、报告封装成Msg1用于返回给E1。

E1调用sgx_dh_initiator_proc_msg1处理Msg1产生Msg2:E1创建自己的公私钥对,通过指令创建E1报告,用Msg1的E2公钥和E1私钥创建共享密钥,将E1公钥、报告等封装成Msg2交给E2。

E2最终会返回Msg3:E2调用sgx_dh_responder_proc_msg2处理Msg2,既用E1公钥和E2私钥构建共享密钥,并用Msg2中的共享密钥散列值验证之。

E1调用sgx_dh_initiator_proc_msg3处理Msg3。最后验证对方身份完成会话建立。

(可以见博客——SGX本地认证)

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值