一、基本概念
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用對稱算法傳輸加密消息了。