@Intel SGX 读书笔记…
Enclave配置文件是一个XML文件,包含用户定义的Enclave参数,此文件是Enclave项目的一部分。sgx_sign使用这个文件作为输入来创建Enclave的签名和元数据。下面是一个配置文件的例子:
<EnclaveConfiguration>
<ProdID>100</ProdID>
<ISVSVN>1</ISVSVN>
<StackMaxSize>0x50000</StackMaxSize>
<HeapMaxSize>0x100000</HeapMaxSize>
<TCSNum>1</TCSNum>
<TCSPolicy>1</TCSPolicy>
<DisableDebug>0</DisableDebug>
<MiscSelect>0</MiscSelect>
<MiscMask>0xFFFFFFFF</MiscMask>
<EnableKSS>1</EnableKSS>
<ISVEXTPRODID_H>1</ISVEXTPRODID_H>
<ISVEXTPRODID_L>2</ISVEXTPRODID_L>
<ISVFAMILYID_H>3</ISVFAMILYID_H>
<ISVFAMILYID_L>4</ISVFAMILYID_L>
</EnclaveConfiguration>
下表列出了配置文件中定义的元素。它们都是可选的。如果没有配置文件,或者配置文件中没有元素,则使用默认值。
表3 Enclave配置默认值
标签 | 描述 | 默认值 |
---|---|---|
ProdID | ISV分配的Product ID | 0 |
ISVSVN | ISV分配的SVN | 0 |
TCSNum | TCS的数量。必须大于0 | 1 |
TCSPolicy | TCS管理策略。0–TCS被绑定到不可信的线程。 1–没有绑定到不可信的线程。 | 1 |
StackMaxSize | 每个线程的最大栈大小。必须域4KB对其。 | 0X40000 |
HeapMaxSize | 进程的最大堆大小。必须与4KB对其 | 0X1000000 |
DisableDebug | 不能调试Enclave | 0–Enclave可以调试 |
MiscSelect | 所需的扩展SSA框架功能 | 0 |
MiscMask | 要强制执行的MiscSelect掩码位 | 0XFFFFFFFF |
EnableKSS | 启用密钥分离和共享特性 | 0 |
ISVEXTPRODID_H | ISV分配扩展产品ID(高8字节) | 0 |
ISVEXTPRODID_L | ISV分配扩展产品ID(低8字节) | 0 |
ISVFAMILYID_H | ISV分配的Family ID(高8字节) | 0 |
ISVFAMILYID_L | ISV分配的Family ID(低8字节) | 0 |
MiscSelect 和 MiscMask用于将来的功能扩展。当前MiscSelect必须为0.否则,相应的Enclave可能无法成功加载。
将EnableKSS设置为1,以启用enclave的密钥分离和共享(KSS)特性。ISVEXTPRODID_H和ISVEXTPRODID_L用于设置ISV分配的扩展产品ID,它是一个16字节的值。ISVFAMILYID_H和ISVFAMILYID_L用于ISV分配的16字节的Family ID。注意,在设置ISV分配的扩展产品ID和ISV分配的Family ID之前,需要启用KSS。
为了避免浪费宝贵的受保护内存资源,可以使用度量工具sgx_emmt适当地调整StackMaxSize和HeapMaxSize。
用Intel SGX Configuration可以可视化的调整配置文件,前面介绍VS插件的时候有提到。
如果没有足够的堆给enclave,则ECALL返回错误代码SGX_ ERROR_STACK_OVERFLOW。此错误代码向enclave写入器提供了StackMaxSize可能需要进一步调整的信息
根据你的开发阶段,选择下列项目配置之一来构建Enclave:
(有关不同的Enclave签名方法的更多信息,请参见Enclave Signing Tool和Enclave Signer Usage Example)
Enclave源代码是作为动态链接库构建的。要使用Enclave应该通过调用API sgx_create_enclave()或sgx_create_enclave_ex()将enclave.dll加载到受保护的内存中。enclave.dll必须由sgx_sign.exe签名。当第一次加载Enclave时,加载程序获取启动令牌并将其保存回in/out参数token中。你可以将启动令牌保存到文件中,以便第二次加载Enclave时,应用程序可以从文件中获取启动令牌。提供有效的启动令牌可以增强加载性能。要卸载一个Enclave,使用参数sgx_enclave_id_t调用sgx_destroy_enclave()接口。
加载和卸载Enclave的示例代码如下所示。
#include
#include
#include "sgx_urts.h"
#define ENCLAVE_FILE _T("Enclave.signed.dll")
int main(int argc, char* argv[])
{
sgx_enclave_id_t eid;
sgx_status_t ret = SGX_SUCCESS;
sgx_launch_token_t token = {0};
int updated = 0;
// Create the Enclave with above launch token.
ret = sgx_create_enclave(ENCLAVE_FILE, SGX_DEBUG_FLAG, &token, &updated, &eid, NULL);
if (ret != SGX_SUCCESS) {
printf("App: error %#x, failed to create enclave.\n", ret);
return -1;
}
// A bunch of Enclave calls (ECALL) will happen here.
// Destroy the enclave when all Enclave calls finished.
if(SGX_SUCCESS != sgx_destroy_enclave(eid))
return -1;
return 0;
}
存储在启用了Intel SGX的CPU中的受保护内存加密密钥的每次power事件(包括挂起和休眠)时都会被销毁。
因此,当发生power transition时,Enclave内存将被删除,并且在此之后将无法访问所有Enclave数据。因此,当系统恢复时,任何后续的ECALL都将无法返回错误代码SGX_ERROR_ENCLAVE_LOST。这个特定的错误代码表明,Enclave由于power transition而丢失。
Intel SGX应用程序应该能够处理在将Enclave加载到受保护内存中时可能发生的任何电源转换。为了以最小的影像处理power事件并恢复Enclave执行,应用程序必须准备在ECALL失败时接收错误代码SGX_ERROR_ENCLAVE_LOST。发生这种情况时,应用程序中的一个且仅有一个线程必须销毁Enclave,即sgx_destroy_enclave(),然后重新加载它,即sgx_create_enclave()。此外,为了从enclave被销毁时的位置恢复执行,应用程序应该定期地在平台上封存和保存Enclave状态信息, 并在重新加载Enclave后使用这些信息将Enclave恢复到原始状态。
SDK中包含地Power Transition示例代码演示了这个过程。
注意:在Windows 10上,Intel SGX应用程序必须调用sgx_destroy_enclave(),以便操作系统从由于power事件而被删除的Enclave中回收受保护的内存或EPC页面。不销毁一个Enclave将导致EPC内存泄漏,sgx_create_enclave()将返回错误代码SGX_ERROR_OUT_OF_EPC。
每当CPU执行跳进(EENTER)或跳出(EEXIT)一个Enclave时,都会发生Enclave切换;例如,当使用ECALLs/OCALLs时。Enclave切换有一个性能开销。对于具有短时间和频繁调用地工作负载,可以使用无切换调用减少Enclave切换开销。无切换调用引入了一种新的操作模式来执行从/到Intel SGX Enclave的调用,使用Enclave内部和外部的工作线程。
性能提示:无切换调用是一个高级特性。它需要额外的工作线程和配置、性能测试和调优。它应该用于需要进行良好性能调优的工作负载。错误的配置可能会导致未充分利用的工作线程,这将消耗CPU时间,同时不为任何任务提供服务。
使用
要使用无切换调用,应该将EDL属性transition_using_threads附加到需要无切换调用的ECALLs和OCALLs中。一个EDL文件可以包含带有或不带有此属性的ECALLs/OCALLs。
应用程序代码必须使用sgx_create_enclave_ex创建一个Enclave,在扩展的选项向量中设置无切换标志,并提供无切换配置结构。
在创建Enclave时,uRTS根据通过初始化提供的无切换配置创建几个可信的和不可信的工作线程,并为无切换调用分配所需的数据结构。可信的工作线程使用常规的Enclave TCSed。当使用无切换的可信工作线程构建Enclave时,应该相应地更新Enclave XML配置中定义的TCSNum。
注意:不应该使用带有TCS绑定策略的无切换调用,即TCSPolicy 0.使用此策略将禁用E/OCALLs的并发执行。
当开发人员使用TCS绑定策略构建Enclave时,他们希望在调用用一个可信函数时保留可信线程的TLS数据。但是,如果Enclave使用无切换调用有两个主要原因,则无法提供这种行为:
- 工作线程处理不同的无切换ECALLs,尽管由TCS绑定策略。因此,分配给任何工作线程的TLS区域将被工作线程服务的所有ECALL函数重用。
- 当无切换调用请求超时时,它将作为常规ECAALL使用为常规ECALL保留的TCS进行服务。因此,无切换的ECALL将重复使用常规的ECALL的TLS区域。
sgx_create_enclave_ex的使用示例:
sgx_launch_token_t token = {0};
sgx_status_t ret = SGX_ERROR_UNEXPECTED;
int updated = 0;
sgx_uswitchless_config_t us_config = { 0, 1, 1, 100000, 100000, { 0 } };
void* enclave_ex_p[32] = { 0 };
enclave_ex_p[SGX_CREATE_ENCLAVE_EX_SWITCHLESS_
BIT_IDX] = &us_config;
sgx_enclave_id_t eid;
const char* fname = "enclave.signed.so";
ret = sgx_create_enclave_ex ( fname, SGX_DEBUG_FLAG, &token, &updated, &eid, NULL, SGX_CREATE_ENCLAVE_EX_SWITCHLESS, enclave_ex_p );
// global processed/missed calls counters
// 0,1 - untrusted; 2,3 - trusted
uint32_t g_stats[4] = { 0 };
/**
* callback to log switchless calls stats
*/
void exit_callback (
sgx_uswitchless_worker_type_t type,
sgx_uswitchless_worker_event_t event,
const sgx_uswitchless_worker_stats_t* stats )
{
// last thread exiting will update the latest results
g_stats[type*2] = stats->processed;
g_stats[type*2+1] = stats->missed;
}
Intel SGX Protected Code Loader(Intel SGX受保护代码加载器)(Intel SGX PCL)旨在保护Windows OS上运行的Intel SGX Enclave应用程序代码中的知识产权(IP)。
问题:Intel SGX在运行时提供代码的完整性、机密性和数据的完整性。但是,它不提供将离线代码作为磁盘上的二进制文件的机密性。攻击者可以反向工程二进制Enclave DLL。
解决办法: 在构建时加密Enclave DLL,并在Enclave加载时解密它。
Intel SGX PCL结构概述:
运行时:
下图显示了Intel SGX PCL构建流程。
注意:
运行时
ISV封装Enclave
要加载一个IP Enclave,ISV必须先将一个解密AES密钥传输到用户本地机器,将其封装在用户本地机器上,并将其用作Intel SGX PCL的输入。为此,ISV必须设计第二个Enclave,即“Sealing Enclave”。下图显示了这个流程。
ISV密封Enclave执行以下操作:
注意:
ISV IP Enclave
下图为Enclave加载流程:
ISV IP Enclave执行以下操作:
与标准过程的比较
下表总结了使用和不使用Intel SGX PCL的IP Enclave负载流之间的差异。
表4 使用和不使用Intel SGX PCL的流程比较
步骤 | 标准过程(没有Intel SGX PCL) | Intel SGX PCL Flow |
---|---|---|
构建时 | 链接:ISV库和objs链接到Enclave.dll 签名:签名Enclave.dll生成Enclave.signed.dll |
链接:ISV库,objs和sgx_pcl.lib连接到IPEnclave.dll 加密IPEnclave.dll为IPEclave.dll 签名:签名IPEnclave.enc.dll为IPEnclave.signed.dll |
Enclave加载 | 1.Enclave应用程序用sgx_create_enclave加载Enclave 2.sgx_create_enclave执行隐式ECALL 3.隐式ECALL启动一个Enclave运行时初始化流 |
1.Enclave应用程序获取已封装的的解密密钥 2.Enclave使用sgx_create_enclave加载Enclave,并提供已封装的解密密钥 3.sgx_create_enclave_ex执行一个隐式ECALL 4.隐式ECALL调用Intel SGX PCL流 5.Intel SGX PCL解封装已加密的blob以获取解密密钥 6.Intel SGX PCL加密已加密的IP sections并返回它的功能状态的Enclave 7.这个过程在Enclave运行时初始化流中持续使用 |
注意:Intel SGX PCL不支持Simulation模式。
安全注意事项
不加密的区域
ISV必须确保下表中描述的区域不包含ISV IP。加密工具不会加密这些区域。
表5 不加密区域
区域 | 描述 |
---|---|
PE部分以外的内容 | 加密工具不加密section以外的内容 |
Section “.reloc” | Intel SGX PCL使用“.reloc”部分,用于将重新定位应用于其代码和数据 |
Sections “niptx”, “nipdt”, “nipdt1”, “nipdt2” | |
and “pcltbl” | 这些部分包括在Intel SGX PCL流程中使用的代码和数据 |
Sections “.debug”, “sgxmeta”, “sgxdata”, | |
“sgxvers”, “.tls” and “.edata” | 这些部分是Intel SGX SDK签名工具或Intel SGX PSW Enclave加载程序所需的 |
导出目录,导出目录字符串符号,导出目录函数,导出目录名称,导出目录序号,TLS目录,线程数据,调试目录,调试数据 | 这些区域是Intel®SGX SDK签名工具或Intel®SGX PSW enclave加载程序所需要的 |
可写的部分
Intel SGX PCL加密攻击在加密的PE节的节标志中设置可写位。因此,属于此类PE部分的所有页面,包括Enclave代码和只读数据的部分,在Enclave运行时都是可写的。
Intel SGX PCL加密标准
在build时,加密工具使用:
在运行时,Intel SGX PCL使用:
Intel SGX PCL加密代码片段来自OpenSSL
Intel SGX PCL库包含来自OpenSSL1.1.1的代码片段(经过稍微修改后,可以在Intel SGX PCL中运行)。这些片段现在是ISV的IP Enclave的TCB的一部分。如果在将来,OpenSSL1.1.1的一个已识别的漏洞需要修改这些代码片段的来源文件,则ISV必须相应地更新这些代码片段。
集成Intel SGX PCL与现有地Intel SGX 解决方案
将ISV Enclave与Intel SGX PCL集成需要ISV对ISV解决方案进行修改:
对IP Enclave的修改
sgx_enc_ip.exe -k key.bin -i IPEnclave.dll -o IPEnclave.enc.dll
对Enclave应用程序的修改
所需的步骤:
#define SEALED_KEY_FILE_NAME "SealedKey.bin"
#define IP_ENCLAVE_FILE_NAME "IPEnclave.signed.dll"
#define SEALING_ENCLAVE_FILE_NAME "SealingEnclave.signed.dll"
uint8_t* sealed_key;
size_t sealed_key_size;
if(file_exists(SEALED_KEY_FILE_NAME))
{
// Sealed key file exists, read it into buffer:
ReadFromFile(SEALED_KEY_FILE_NAME, sealed_key);
}
else
{
/*
* Sealed key file does not exist. Create it:
* 1. Create the Sealing Enclave
* 2. Use the Sealing Enclave to provision the decryption key onto the platform and seal it.
* 3. Save the sealed key to a file for future uses
*/
// 1. create the sealing enclave
sgx_create_enclave(
SEALING_ENCLAVE_FILE_NAME,
debug,
&token,
&updated,
&seal_enclave_id,
NULL);
/*
* 2. Use the Sealing Enclave to provision the decryption key onto the platform and seal it:
*/
ecall_get_sealed_key_size(seal_enclave_id, &sealed_key_size);
sealed_key = (uint8_t*)malloc(sealed_key_size);
ecall_get_sealed_key(seal_enclave_id, sealed_key, sealed_key_size);
// 3. Save the sealed key to a file for future uses
WriteToFile(SEALED_KEY_FILE_NAME, sealed_key);
}
// Load the encrypted enclave, providing the sealed key:
const void* ex_features[32] = {};
ex_features[SGX_CREATE_ENCLAVE_EX_PCL_BIT_IDX] = sealed_key;
sgx_create_enclave_ex(
IP_ENCLAVE_FILE_NAME,
debug,
&token,
&updated,
ip_enclave_id,
NULL,
ex_features,
SGX_CREATE_ENCLAVE_EX_PCL);
封装Enclave
Intel SGX PCL解密密钥供应
本节描述创建和使用ISV密封Enclave的方法。ISV密封Enclave将解密密钥提供给用户本地机器并对其进行密封。(把解密密钥给我,再对这个密钥密封起来)
要安全地将解密AES密钥传输到用户本地机器,ISV密封Enclave需要向ISV服务器进行验证,生成一个安全会话,并使用它来提供解密密钥。(向ISV获取解密密钥的过程)
将Intel SGX PCL解密密钥从ISV服务器发送到本地平台
本文档中的远程认证示例详细说明和描述了如果使用ISV服务器启动远程认证会话。
远程认证允许服务器和客户端共享密钥。这些密钥可用于在ISV服务器和密封Enclave之间生成安全会话(例如,使用TLS)。然后,可以使用安全会话安全地提供解密密钥。
密封Intel SGX PCL解密密钥
**本文档中地密封样例代码说明了如何封装一个秘密。**默认情况下,IntelSGX SDK使用MRSIGNER来密封这个秘密。
与Enclave应用程序地交互
在上面的为代码中,ISV密封Enclave通过实现Enclave调用ecall_get_sealed_key_size 和ecall_get_sealed_key来为Enclave应用程序提供密封的解密密钥。这不是一个架构需求,ISV可以使用自己的设计。
Intel SGX SDK利用CVE-2020-0551的缓解,即LVI(负载值注入).Intel SGX SDK支持两个缓解级别。一级处理易受LVI攻击的所有指令。这个级别为CVE-2020-0551-Load(简称Load)。第二个缓解级别只处理脆弱的控制流指令,称为CVE-2020-0551-CF(简称CF)。
支持缓解的信任库
Intel SGX SDK包含三组可信库:Unmitigated、Load和CF。
表6
缓解等级 | 路径 |
---|---|
Unmitigated | [Intel SGX SDK Install Path]bin\x64\Release |
Load | [Intel SGX SDK Install Path]bin\x64\CVE-2020-0551-Load-Release |
CF | [Intel SGX SDK Install Path]bin\x64\CVE-2020-0551-CF-Release |
如上所述,Intel SGX SDK利用CVE-2020-0551的缓解。充分利用这一点的Intel SGX开发人员需要以下工具。
所需工具:
Load缓解level | CF缓解level | 无LVI缓解 | |
VS2017及以上版本 | /Qspectre-load | /Qspectre-load-cf | 两者都不 |
Sgx-asm-pp.py | --MITIGATION-CVE-2020-0551=LOAD | --MITIGATION-CVE-2020-0551=CF | --MITIGATIONCVE-2020-0551=NONE o或者直接使用 NASM/MASM |
创建启用可信Enclave的CVE-2020-0551缓解项目
你可以用Intel SGX VS Wizard来创建启用CVE-2020-0551 mitigation的新项目。
参见Microsoft* Visual Studio* Intel®Software Guard Extensions向导创建一个启用CVE-2020-0551缓冲的新项目(前面已经介绍过了)
在新的可信项目创建后,将发现四个新的CVE-2020-0051缓解相关配置。
注意:这四个配置只在x64平台上支持。
缓解配置介绍
CVE-2020-0051缓解包括以下四个相关配置:
CVE-2020-0551-Load-Release:
CVE-2020-0551-Load-Prerelease:
CVE-2020-0551-CF-Release:
CVE-2020-0551-CF-Prerelease:
在每个配置中,每个.asm文件的build命令都会根据它的属性–>常规–>项目类型(没找到啊)类型改变:
python "$(SGXSDKInstallPath)\scripts\sgx-asm-pp.py"
--assembler=ml64 --MITIGATION-CVE-2020-0551=
[LOAD|CF] <ml64 command line options>
python "$(SGXSDKInstallPath)\scripts\sgx-asm-pp.py"
--assembler=nasm --MITIGATION-CVE-2020-0551=
[LOAD|CF] <nasm command line options>
存在问题:
找不到属性–>常规–>项目类型,导致后面的都没有完成,应该是没有构建这个模式吧?
如有误,请指正!感激!