代码角度理解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用对称算法传输加密消息了。

  • 9
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值