天天看點

代碼角度了解SGX的認證機制(一):本地認證

一、基本概念

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用對稱算法傳輸加密消息了。

繼續閱讀