一、基本概念
1、认证(attestation): 是指一个enlave中的程序向其他enclave证明其完整性和真实性的过程。intel SGX认证即是一个在SGX平台上运行的ISV enclave(证明者)希望来向远程enclave(验证者)证明其身份(MRENCLAVE)、和确实是在真实的SGX处理器上正确的隔离执行。
1)本地认证:同一个平台上的两个不同enclave之间认证
2)远程认证:enclave所属平台外的软件验证其真实性
2、MRENCLAVE 和 MRSIGNER:intel SGX为每一个enclave提供的两个度量值,分别为MRENCLAVE 和 MRSIGNER;
1)MRENCLAVE :Enclave Identity
其值为sha256的摘要结果;
sha256的内容包括:从enclave构建开始到初始化完成(EINIT指令执行后)之间的活动记录日志。
日志包含如下信息:
the code, data, and stack placed inside the enclave
the order and position in which the enclave’s pages were placed
the security properties of each page.
以上内容的任一更改都会导致hash结果不同,即MRENCLAVE不同,不同的enclave,该值不同
可以使用如下命令获取到mrenclave:
sgx_sign dump -enclave enclave.signed.so -dumpfile out.log
例如:本地证明demo中,sgx_sign dump -enclave libenclave_initiator.signed.so -dumpfile out.log
在out.log文件中的 metadata->enclave_css.body.enclave_hash.m字段就是MRENCLAVE值。
2)MRSIGNER:- Sealing Identity
enclave构建时使用的RSA签名的公钥的hash结果。签名的rsa密钥对相同,该值即相同。
同样在out.log中搜索mrsigner->value可以看到MRSIGNER。
3、TCB :Trusted computing base
4、EREPORT: 调用enclave时,创建的一个带有cmac签名的结构。包含enclave的两个标识符,enclave相关属性(boby中的attributes字段),硬件TCB的可信度等,及这些消息的MAC结果.(密钥由EGETKEY导出:)
5、EGETKEY:该指令根据调用enclave的属性和请求的密钥类型来产生用于不同目的的五种对称密钥。其中两种用于所有区域的sealing 和report keys。剩下三个仅限于SGX体系结构使用。
可参考此篇论文详细了解EGETKEY:
https://www.idc.ac.il/en/schools/cs/research/Documents/jackson-msc-thesis.pdf
6、Report Key:只有负责验证的enclave可以通过EREPORT 指令恢复Report Key。验证对端的report中的MAC值是否正确。双方只要在driver key的时候设置的参数一致,即可生成相同的mac key。
二、认证关键过程
本端用对端的target info,双方DH公钥的hash值及一些系统信息,生成report,该report带有一个MAC值。对端拿到这个report之后,通过EGETKEY指令获取Report Key,来验证MAC值是否和对端发送的一致。
首先,report.body的组成如下(可查看SIM代码):
typedef struct _report_body_t
{
sgx_cpu_svn_t cpu_svn; /* ( 0) Security Version of the CPU */
sgx_misc_select_t misc_select; /* ( 16) Which fields defined in SSA.MISC */
uint8_t reserved1[SGX_REPORT_BODY_RESERVED1_BYTES]; /* ( 20) */
sgx_isvext_prod_id_t isv_ext_prod_id;/* ( 32) ISV assigned Extended Product ID */
sgx_attributes_t attributes; /* ( 48) Any special Capabilities the Enclave possess */
sgx_measurement_t mr_enclave; /* ( 64) The value of the enclave's ENCLAVE measurement */
uint8_t reserved2[SGX_REPORT_BODY_RESERVED2_BYTES]; /* ( 96) */
sgx_measurement_t mr_signer; /* (128) The value of the enclave's SIGNER measurement */
uint8_t reserved3[SGX_REPORT_BODY_RESERVED3_BYTES]; /* (160) */
sgx_config_id_t config_id; /* (192) CONFIGID */
sgx_prod_id_t isv_prod_id; /* (256) Product ID of the Enclave */
sgx_isv_svn_t isv_svn; /* (258) Security Version of the Enclave */
sgx_config_svn_t config_svn; /* (260) CONFIGSVN */
uint8_t reserved4[SGX_REPORT_BODY_RESERVED4_BYTES]; /* (262) */
sgx_isvfamily_id_t isv_family_id; /* (304) ISV assigned Family ID */
sgx_report_data_t report_data; /* (320) Data provided by the user */
} sgx_report_body_t;
// assemble REPORT Data
memset(&tmp_report, 0, sizeof(tmp_report));
memcpy(&tmp_report.body.cpu_svn,&(g_global_data_sim.cpusvn_sim),sizeof(sgx_cpu_svn_t));
tmp_report.body.isv_prod_id = cur_secs->isv_prod_id;
tmp_report.body.isv_svn = cur_secs->isv_svn;
memcpy(&tmp_report.body.attributes, &cur_secs->attributes, sizeof(sgx_attributes_t));
memcpy(&tmp_report.body.report_data, rd, sizeof(sgx_report_data_t));
memcpy(&tmp_report.body.mr_enclave, &cur_secs->mr_enclave, sizeof(sgx_measurement_t));
memcpy(&tmp_report.body.mr_signer, &cur_secs->mr_signer, sizeof(sgx_measurement_t));
memcpy(&tmp_report.key_id, get_base_key(SGX_KEYSELECT_REPORT), sizeof(sgx_key_id_t)/2);
MAC生成的关键是对称密钥report key的导出:
需要素材如下:
/* Derive data for report key */
typedef struct {
uint16_t key_name; /* should always be 'SGX_KEYSELECT_REPORT' */
sgx_attributes_t attributes; /* attributes from SECS */
se_owner_epoch_t csr_owner_epoch;
sgx_measurement_t mrenclave;
sgx_cpu_svn_t cpu_svn; /* CPUSVN from CPUSVN register */
sgx_key_id_t key_id; /* KEYID from KEYREQUEST */
} dd_report_key_t;
// derive the report key
derivation_data_t dd;
memset(&dd, 0, sizeof(dd));
dd.size = sizeof(dd_report_key_t);
dd.key_name = SGX_KEYSELECT_REPORT;
memcpy(&dd.ddrk.mrenclave, &ti->mr_enclave, sizeof(sgx_measurement_t));
memcpy(&dd.ddrk.attributes, &ti->attributes, sizeof(sgx_attributes_t));
memcpy(dd.ddrk.csr_owner_epoch, SIMU_OWNER_EPOCH_MSR, sizeof(se_owner_epoch_t));
memcpy(&dd.ddrk.cpu_svn,&(g_global_data_sim.cpusvn_sim),sizeof(sgx_cpu_svn_t));
memcpy(&dd.ddrk.key_id, &tmp_report.key_id, sizeof(sgx_key_id_t));
ti 为target info,可以看出,用到了对端的mrenclave和attribute。
derive key函数如下:
// Compute the CMAC of derivation data with corresponding base key
// and save it to `okey'.
void derive_key(const derivation_data_t* dd, sgx_key_128bit_t okey)
{
sgx_rijndael128_cmac_msg((const sgx_cmac_128bit_key_t*)(get_base_key(dd->key_name)),
dd->ddbuf, dd->size, (sgx_cmac_128bit_tag_t*)okey);
}
get_base_key 函数是由系统生成,此处为SIM代码,所以为固定值:
const uint8_t* get_base_key(uint16_t key_name)
{
switch (key_name) {
case SGX_KEYSELECT_SEAL:
return BASE_SEAL_KEY;
case SGX_KEYSELECT_REPORT:
return BASE_REPORT_KEY;
case SGX_KEYSELECT_EINITTOKEN:
return BASE_EINITTOKEN_KEY;
case SGX_KEYSELECT_PROVISION:
return BASE_PROVISION_KEY;
case SGX_KEYSELECT_PROVISION_SEAL:
return BASE_PROV_SEAL_KEY;
}
// Should not come here - error should have been reported
// when the key name is not supported in the caller.
return (uint8_t*)0;
}
mac存储在report结构中。
typedef struct _report_t /* 432 bytes */
{
sgx_report_body_t body;
sgx_key_id_t key_id; /* (384) KeyID used for diversifying the key tree */
sgx_mac_t mac; /* (416) The Message Authentication Code over this structure. */
} sgx_report_t;
双方DH公钥的hash值存储在boby结构体的 sgx_report_data_t report_data字段;
对端拿到report之后,即可利用相同的参数生成一样的mac key。其中SGX保证了BASE_REPORT_KEY的一致性,即同一平台上获取的BASE_REPORT_KEY是一样的。
三、本地认证详细流程
注:以enclave1 表示认证发起端,enclave2 表示验证端。
本地认证有两种形式,其一,两个enclave同属于一个app,消息流程通过api调用即可完成;另一种,两个enclave分别属于各自的app,但在同一平台上,消息可通过socket等方式同步。以下说明不做区分。
以下流程说明标号和图示有所区别,会对消息信息加以详细说明;
1、双方分别调用sgx_create_enclave创建各自的enclave。
2、双方分别调用sgx_dh_init_session初始化各自的dh session。发起端设置自己角色为SGX_DH_SESSION_INITIATOR,状态为SGX_DH_SESSION_INITIATOR_WAIT_M1;验证端设置角色为SGX_DH_SESSION_RESPONDER,状态为SGX_DH_SESSION_STATE_RESET。
3.enclave1向enclave2请求msg1和session ID。
4.msg1包含enclave2的target info, ecdh算法的公钥。enclave2调用dh_generate_message1生成msg1,返回给enclave1,msg1明文传输;
target info包含信息如下:
$4 = {
mr_enclave = {
m = {0x19, 0x35, 0x1a, 0xed, 0xef, 0xc8, 0xe9, 0x87, 0xa6, 0xda, 0x91, 0xe6, 0x10,
0x8, 0xb3, 0x77, 0xc4, 0xa8, 0xbb, 0x1, 0xef, 0x53, 0x26, 0x70, 0xd1, 0xc6, 0xd2,
0x4e, 0x8d, 0x4c, 0x5f, 0x28}
},
attributes = {
flags = 0x7,
xfrm = 0x7
},
reserved1 = {0x0, 0x0},
config_svn = 0x0,
misc_select = 0x0,
reserved2 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
config_id = {0x0 <repeats 64 times>},
reserved3 = {0x0 <repeats 384 times>}
}
5.enclave1调用sgx_dh_initiator_proc_msg1处理msg1,生成msg2,真实处理函数为dh_generate_message2,gdb调用栈如下:
#0 dh_generate_message2 (msg1=0x7ffff63f9430, g_b=0x7ffff63f8dc0, dh_smk=0x7ffff63f8e00,
msg2=0x7ffff63f9230) at ec_dh.cpp:239
#1 0x00007ffff6033986 in dh_initiator_proc_msg1<dh_generate_message2> (
msg1=0x7ffff63f9430, msg2=0x7ffff63f9230, sgx_dh_session=0x7ffff63f8e80)
at ec_dh.cpp:653
#2 0x00007ffff60336fe in sgx_LAv1_initiator_proc_msg1 (msg1=0x7ffff63f9430,
msg2=0x7ffff63f9230, sgx_dh_session=0x7ffff63f8e80) at ec_dh.cpp:699
处理流程:
1)enclave1生成自己的ecdh密钥对,并用enclave2的传送的公钥计算一个sgx_ecc256_compute_shared_dhkey shared key;然后调用derive_key生成msg2的对称密钥dh_smk;
2)enclave1计算自己的公钥和enclave2公钥的hash值;存入report_data
3)report_data第32字节存储kdf算法的id;
4)调用sgx_create_report获取report,输入参数:enclave2的target info,report_data;
会调到do_ereport函数,为汇编实现,汇编的核心为ENCLU指令。
此处处理逻辑看第二章列出的SIM代码;
5)将report拷贝到msg2,并计算report的MAC值,密钥为dh_smk,存储在msg2的mac字段中;
6.发送msg2到enclave2,
7.enclave2调用sgx_dh_responder_proc_msg2处理msg2,生成msg3;
1)首先用enclave1的公钥,计算shared key,导出对称密钥dh_smk;
2)验证msg2的mac值,验证msg2->report.body.report_data是否是双方公钥的sha256结果。
3)调用sgx_verify_report验证msg2->report,包括一些校验及report的MAX值,其中用do_egetkey生成MAC算法的key,即调用EGETKEY指令并导出report key;SIM关键代码如下:
switch (kr->key_name) {
case SGX_KEYSELECT_REPORT:
// assemble derivation data
dd.size = sizeof(dd_report_key_t);
memcpy(&dd.ddrk.attributes, &cur_secs->attributes, sizeof(sgx_attributes_t));
memcpy(dd.ddrk.csr_owner_epoch, SIMU_OWNER_EPOCH_MSR, sizeof(se_owner_epoch_t));
memcpy(&dd.ddrk.cpu_svn,&(g_global_data_sim.cpusvn_sim),sizeof(sgx_cpu_svn_t));
memcpy(&dd.ddrk.mrenclave, &cur_secs->mr_enclave, sizeof(sgx_measurement_t));
memcpy(&dd.ddrk.key_id, &kr->key_id, sizeof(sgx_key_id_t));
break;
其中kr->key_id为对端enclave1传过来的keyid,导出函数为derive_key(&dd, okey);同样会调用get_base_key。
4)msg2处理完成后,生成msg3,msg3和msg2包含信息基本一致。
5)计算对称密钥aek,用于后续消息的加密传输;
6)enclave2可以额外验证一些msg2的信息,通过sgx_dh_session_enclave_identity_t结构体收集:
typedef struct _sgx_dh_session_enclave_identity_t
{
sgx_cpu_svn_t cpu_svn;
sgx_misc_select_t misc_select;
uint8_t reserved_1[28];
sgx_attributes_t attributes;
sgx_measurement_t mr_enclave;
uint8_t reserved_2[32];
sgx_measurement_t mr_signer;
uint8_t reserved_3[96];
sgx_prod_id_t isv_prod_id;
sgx_isv_svn_t isv_svn;
} sgx_dh_session_enclave_identity_t;
8.调用sgx_dh_initiator_proc_msg3处理msg3,流程 和处理msg2一致,同样也会生成对称加密的aek用于后续数据加密传输。enclave1也可以做一些额外校验。
9.至此整个本地认证流程结束。就可以调用sgx_rijndael128GCM_encrypt和sgx_rijndael128GCM_decrypt用对称算法传输加密消息了。