示例#1
0
pve_status_t get_ppid(ppid_t* ppid)
{
    sgx_key_128bit_t key_tmp;
    sgx_status_t sgx_status = SGX_SUCCESS;
    memset(&key_tmp, 0, sizeof(key_tmp));

    //get Provisioning Key with both CPUSVN and ISVSVN set to 0
    pve_status_t status = get_provision_key(&key_tmp, NULL);

    if(status != PVEC_SUCCESS){
        (void)memset_s(&key_tmp,sizeof(key_tmp), 0, sizeof(key_tmp));
        return status;
    }

    uint8_t content[16];
    memset(&content, 0, sizeof(content));
    

    //generate the mac as PPID
    se_static_assert(sizeof(sgx_cmac_128bit_key_t) == sizeof(sgx_key_128bit_t)); /*size of sgx_cmac_128bit_key_t and sgx_key_128bit_t should be same*/
    se_static_assert(sizeof(sgx_cmac_128bit_tag_t) == sizeof(ppid_t)); /*size of sgx_cmac_128bit_tag_t and ppit_t should be same*/
    if((sgx_status=sgx_rijndael128_cmac_msg(reinterpret_cast<const sgx_cmac_128bit_key_t *>(&key_tmp),  
        content, sizeof(content), reinterpret_cast<sgx_cmac_128bit_tag_t *>(ppid)))!=SGX_SUCCESS){
            status = sgx_error_to_pve_error(sgx_status);
    }else{
        status = PVEC_SUCCESS;
    }
    (void)memset_s(&key_tmp,sizeof(key_tmp), 0, sizeof(key_tmp));//clear provisioning key in stack
    return status;
}
示例#2
0
//Function to generate Provisioning Sealing Key given the psvn
//The key is used to seal the private parameter f before sending to backend server
pve_status_t get_pve_psk(
    const psvn_t* psvn,
    sgx_key_128bit_t* seal_key)
{

    sgx_status_t se_ret = SGX_SUCCESS;
    sgx_key_request_t seal_key_req;

    if(psvn == NULL)
        return PVEC_PARAMETER_ERROR;

    memset(&seal_key_req, 0, sizeof(sgx_key_request_t));
    memcpy(&seal_key_req.cpu_svn, &psvn->cpu_svn, SGX_CPUSVN_SIZE);
    memcpy(&seal_key_req.isv_svn, &psvn->isv_svn, sizeof(psvn->isv_svn));
    seal_key_req.key_name = SGX_KEYSELECT_PROVISION_SEAL; //provisioning sealling key

    seal_key_req.attribute_mask.xfrm = 0;
    seal_key_req.attribute_mask.flags = ~SGX_FLAGS_MODE64BIT;

    se_ret = sgx_get_key(&seal_key_req, seal_key);
    if(SGX_SUCCESS != se_ret)
    {
        return sgx_error_to_pve_error(se_ret);
    }

    return PVEC_SUCCESS;
}
示例#3
0
//Function to get provisioning key using the provided PSVN
//If the psvn is NULL, both CPUSVN and ISVSVN is set to 0 (used for PPID generation only)
//Input: psvn, the psvn used to generate provisioning key
//Output: key, the provisioning key to return
//        return PVEC_SUCCESS on success
static pve_status_t get_provision_key(sgx_key_128bit_t *key, const psvn_t *psvn)
{
    sgx_status_t se_ret = SGX_SUCCESS;
    sgx_key_request_t wrap_key_req;

    //memset here will also set cpusvn isvsvn to 0 for the case when psvn==NULL
    memset(&wrap_key_req, 0, sizeof(sgx_key_request_t));
    if(psvn==NULL){
        //keeping isv_svn and cpu_svn all 0 according to spec (this is for calcuation of PPID)
    }else{
        memcpy(&wrap_key_req.cpu_svn, &psvn->cpu_svn, sizeof(wrap_key_req.cpu_svn));
        memcpy(&wrap_key_req.isv_svn, &psvn->isv_svn, sizeof(wrap_key_req.isv_svn));
    }
    wrap_key_req.key_name = SGX_KEYSELECT_PROVISION; //provisioning key
    wrap_key_req.attribute_mask.xfrm = 0;
    wrap_key_req.misc_mask = 0xFFFFFFFF;
    wrap_key_req.attribute_mask.flags = ~SGX_FLAGS_MODE64BIT; //set all bits except the SGX_FLAGS_MODE64BIT

    se_ret = sgx_get_key(&wrap_key_req, key);
    if(SGX_SUCCESS != se_ret)
    {
        return sgx_error_to_pve_error(se_ret);
    }
    return PVEC_SUCCESS;
}
示例#4
0
//The function will try to do some preparation for piece meal encryption of field1 in ProvMsg3
//  It prepares the encryption state in msg3
//@parm: structure to provide some input data to generate ProvMsg3 and also some states for piece meal processing
//@return PVEC_SUCCESS on success and error code if failed
static pve_status_t proc_msg3_state_init(prov_msg3_parm_t *parm, const sgx_key_128bit_t *pwk2)
{
    pve_status_t ret = PVEC_SUCCESS;
    sgx_status_t se_ret = SGX_SUCCESS;

    if((se_ret=sgx_read_rand(parm->iv, IV_SIZE))!=SGX_SUCCESS){//randomly generate the IV
        ret = se_read_rand_error_to_pve_error(se_ret);
        goto ret_point;
    }
    se_static_assert(SK_SIZE==sizeof(sgx_cmac_128bit_tag_t)); /*size of sgx_cmac_128bit_tag_t should same as value of SK_SIZE*/

    //initialize state for piece-meal encryption of field of ProvMsg3
    ret = sgx_error_to_pve_error(sgx_aes_gcm128_enc_init((const uint8_t *)pwk2,  parm->iv, IV_SIZE,//pwk2 as the key 
        NULL, 0,//no AAD used for the encryption of EpidSignature
        (sgx_aes_state_handle_t*)&parm->p_msg3_state));
ret_point:
    return ret;
}
示例#5
0
//Get Provisioning Wrap2 Key with respect to the PSVN
pve_status_t get_pwk2(
    const psvn_t* psvn,
    const uint8_t  n2[NONCE_2_SIZE],
    sgx_key_128bit_t* wrap_key)
{

    if( psvn == NULL)
        return PVEC_PARAMETER_ERROR;
    uint8_t content[32];
    sgx_status_t sgx_status = SGX_SUCCESS;
    sgx_key_128bit_t key_tmp;
    pve_status_t status = PVEC_SUCCESS;

    memset(&key_tmp, 0, sizeof(key_tmp));
    status = get_provision_key(&key_tmp, psvn); //Generate Provisioning Key with respect to the psvn
    if(status != PVEC_SUCCESS)
        goto ret_point;

    memset(&content, 0, sizeof(content));
    content[0] = 0x01;    
    memcpy(&content[START_OFF_PROV_WRAP_2], PROV_WRAP_2, PROV_WRAP_2_LEN); // byte 1-11 : "PROV_WRAP_2" (ascii encoded)
    memcpy(&content[START_OFF_NONCE_2], n2, NONCE_2_SIZE);
    content[OFF_BYTE_ZERO] = 0x00; //fill zero in byte offset 30
    content[OFF_BYTE_0X80] = 0x80; //fill 0x80 in byte offset 31

    //get the cmac of provision key as PWK2
    se_static_assert(sizeof(sgx_cmac_128bit_key_t)==sizeof(key_tmp)); /*size of sgx_cmac_128bit_key_t should be same as sgx_key_128bit_t*/
    se_static_assert(sizeof(sgx_cmac_128bit_tag_t)==sizeof(sgx_key_128bit_t)); /*size of sgx_cmac_128bit_tag_t should be same as sgx_key_128bit_t*/
    if((sgx_status = sgx_rijndael128_cmac_msg(reinterpret_cast<const sgx_cmac_128bit_key_t *>(&key_tmp), 
        reinterpret_cast<const uint8_t *>(content), sizeof(content),
        reinterpret_cast<sgx_cmac_128bit_tag_t *>(wrap_key)))!=SGX_SUCCESS){
            status = sgx_error_to_pve_error(sgx_status);
    }else{
        status = PVEC_SUCCESS;
    }
ret_point:
    (void)memset_s(&key_tmp,sizeof(key_tmp), 0 ,sizeof(key_tmp)); //clear provisioninig key in stack
    return status;
}
示例#6
0
//Function to create data for ProvMsg3 generation 
// The sigrl of ProvMsg2 will processed in this function in piece-meal method
//@msg2_blob_input: structure to hold decoded data of ProvMsg2
//@performance_rekey_used[in]: 1 if performance rekey used or 0 if not
//@msg3_parm: structure to hold most information to generate ProvMsg3
//@msg3_output: structure to hold output data to create ProvMsg3
//@emp_epid_sig: output buffer to external memory for variable length EpidSignature
//@epid_sig_buffer_size: size in bytes of buffer emp_epid_sig
//@return PVEC_SUCCESS on success and error code if failed
pve_status_t gen_prov_msg3_data(const proc_prov_msg2_blob_input_t *msg2_blob_input,
                                prov_msg3_parm_t& msg3_parm,
                                uint8_t performance_rekey_used,
                                gen_prov_msg3_output_t *msg3_output,
                                external_memory_byte_t *emp_epid_sig, 
                                uint32_t epid_sig_buffer_size)
{
    pve_status_t ret = PVEC_SUCCESS;
    sgx_status_t sgx_status = SGX_ERROR_UNEXPECTED;
    uint8_t temp_buf[JOIN_PROOF_TLV_TOTAL_SIZE];
    uint8_t *data_to_encrypt = NULL;
    uint8_t  size_to_encrypt = 0;
    uint8_t  pwk2_tlv_buffer[PWK2_TLV_TOTAL_SIZE];
    sgx_key_128bit_t *pwk2=reinterpret_cast<sgx_key_128bit_t *>(pwk2_tlv_buffer+PWK2_TLV_HEADER_SIZE);
    uint8_t report_data_payload[MAC_SIZE + HARD_CODED_JOIN_PROOF_WITH_ESCROW_TLV_SIZE + NONCE_2_SIZE + PEK_MOD_SIZE];
    uint8_t* pdata = &report_data_payload[0];
    sgx_report_data_t report_data = { 0 };
    uint8_t aad[sizeof(GroupId)+sizeof(device_id_t)+CHALLENGE_NONCE_SIZE];
    void *pub_key = NULL;
    const signed_pek_t& pek = msg2_blob_input->pek;
    uint32_t le_e;
    int i;
    size_t output_len = 0;
    uint8_t le_n[sizeof(pek.n)];
    static_assert(sizeof(pek.n)==384, "pek.n should be 384 bytes");
    device_id_t *device_id_in_aad= (device_id_t *)(aad+sizeof(GroupId));
    join_proof_with_escrow_t* join_proof_with_escrow=reinterpret_cast<join_proof_with_escrow_t *>(temp_buf+JOIN_PROOF_TLV_HEADER_SIZE);
    se_static_assert(sizeof(join_proof_with_escrow_t)+JOIN_PROOF_TLV_HEADER_SIZE==JOIN_PROOF_TLV_TOTAL_SIZE); /*unmatched hardcoded size*/
    se_static_assert(sizeof(sgx_key_128bit_t)==PWK2_TLV_TOTAL_SIZE-PWK2_TLV_HEADER_SIZE); /*unmatched PWK2 size*/
    memset(temp_buf, 0 ,sizeof(temp_buf));
    memset(aad, 0, sizeof(aad));
    memset(pwk2, 0, sizeof(sgx_key_128bit_t));
    memcpy(pwk2_tlv_buffer, PWK2_TLV_HEADER, PWK2_TLV_HEADER_SIZE);
    msg3_output->is_join_proof_generated=false;
    msg3_output->is_epid_sig_generated=false;

    if ((msg2_blob_input->pce_target_info.attributes.flags & SGX_FLAGS_PROVISION_KEY) != SGX_FLAGS_PROVISION_KEY ||
        (msg2_blob_input->pce_target_info.attributes.flags & SGX_FLAGS_DEBUG) != 0){
        //PCE must have access to provisioning key
        //Can't be debug PCE
        ret = PVEC_PARAMETER_ERROR;
        goto ret_point;
    }

    if(!performance_rekey_used){
        //the temp_buf used for join_proof_with_escrow tlv
        memcpy(temp_buf, JOIN_PROOF_TLV_HEADER, JOIN_PROOF_TLV_HEADER_SIZE);//first copy in tlv header
        ret = random_stack_advance(gen_msg3_join_proof_escrow_data, msg2_blob_input, *join_proof_with_escrow);//generate the tlv payload
        if( PVEC_SUCCESS != ret )
            goto ret_point;
        msg3_output->is_join_proof_generated = true;
        data_to_encrypt = temp_buf;
        size_to_encrypt = JOIN_PROOF_TLV_TOTAL_SIZE;
    }
    //now encrypt field1
    ret = se_read_rand_error_to_pve_error(sgx_read_rand(msg3_output->field1_iv, IV_SIZE));//randomly generate IV
    if( PVEC_SUCCESS != ret)
        goto ret_point;
    memcpy(aad, &msg2_blob_input->group_cert.key.gid,sizeof(GroupId));//start to prepare AAD
    memcpy(&device_id_in_aad->fmsp, &msg2_blob_input->equiv_pi.fmsp, sizeof(fmsp_t));
    memcpy(&device_id_in_aad->psvn.cpu_svn, &msg2_blob_input->equiv_pi.cpu_svn, sizeof(sgx_cpu_svn_t));
    memcpy(&device_id_in_aad->psvn.isv_svn, &msg2_blob_input->equiv_pi.pve_svn, sizeof(sgx_isv_svn_t));
    memset(&device_id_in_aad->ppid, 0, sizeof(device_id_in_aad->ppid));
    ret = pve_rng_generate(NONCE_2_SIZE*8, msg3_output->n2);
    if(PVEC_SUCCESS !=ret){
        goto ret_point;
    }
    ret = random_stack_advance(get_pwk2, &device_id_in_aad->psvn, msg3_output->n2, pwk2);
    if( PVEC_SUCCESS != ret )
        goto ret_point;

    memcpy(aad+sizeof(GroupId)+sizeof(device_id_t), msg2_blob_input->challenge_nonce, CHALLENGE_NONCE_SIZE);
    se_static_assert(sizeof(sgx_aes_gcm_128bit_key_t)==SK_SIZE); /*sizeof sgx_aes_gcm_128bit_key_t should be same as TCB size*/
    se_static_assert(sizeof(sgx_aes_gcm_128bit_tag_t)==MAC_SIZE); /*sizeof sgx_aes_gcm_128bit_tag_t should be same as MAC_SIZE*/
    sgx_status = sgx_rijndael128GCM_encrypt(reinterpret_cast<const sgx_aes_gcm_128bit_key_t *>(pwk2),
        data_to_encrypt, size_to_encrypt, msg3_output->field1_data,
        msg3_output->field1_iv, IV_SIZE, aad, static_cast<uint32_t>(sizeof(GroupId)+sizeof(device_id_t)+CHALLENGE_NONCE_SIZE),
        reinterpret_cast<sgx_aes_gcm_128bit_tag_t *>(msg3_output->field1_mac));//encrypt field1
    if(SGX_SUCCESS != sgx_status){
        ret = sgx_error_to_pve_error(sgx_status);
        goto ret_point;
    }
    if( msg2_blob_input->is_previous_pi_provided ){
        //preparing the encryption state of ProvMsg3 and encrypt inplace of msg3_inside enclave (field1_0 and field1_1)
        //The function will randomly set the iv value too
        ret = proc_msg3_state_init(&msg3_parm, pwk2);
        if( PVEC_SUCCESS!=ret )
            goto ret_point; 
        //Now start piece-meal generation of EPIDsign 
        ret = gen_msg3_signature(msg2_blob_input, &msg3_parm, emp_epid_sig, epid_sig_buffer_size);
        if( PVEC_SUCCESS!=ret )
            goto ret_point;
        msg3_output->is_epid_sig_generated = true;
        msg3_output->epid_sig_output_size = epid_sig_buffer_size;
        memcpy(msg3_output->epid_sig_iv, msg3_parm.iv, IV_SIZE);
        //generate MAC in EPC
        ret = sgx_error_to_pve_error(sgx_aes_gcm128_enc_get_mac(msg3_output->epid_sig_mac, (sgx_aes_state_handle_t*)msg3_parm.p_msg3_state));
        if (PVEC_SUCCESS != ret)
            goto ret_point;
    }

    le_e = lv_ntohl(pek.e);
    se_static_assert(sizeof(pek.n)==sizeof(le_n));  /*unmatched size of pek.n*/
    //endian swap
    for(i=0;i<(int)(sizeof(pek.n)/sizeof(pek.n[0]));i++){
        le_n[i]=pek.n[sizeof(pek.n)/sizeof(pek.n[0])-i-1];
    }

    sgx_status = sgx_create_rsa_pub_key(sizeof(pek.n), sizeof(pek.e),
        reinterpret_cast<const unsigned char *>(le_n), reinterpret_cast<const unsigned char *>(&le_e), &pub_key);
    if (SGX_SUCCESS != sgx_status) {
        ret = sgx_error_to_pve_error(sgx_status);
        goto ret_point;
    }

    sgx_status = sgx_rsa_pub_encrypt_sha256(pub_key, NULL, &output_len, reinterpret_cast<const unsigned char*>(pwk2_tlv_buffer),
        PWK2_TLV_TOTAL_SIZE);
    if (SGX_SUCCESS != sgx_status) {
        ret = sgx_error_to_pve_error(sgx_status);
        goto ret_point;
    }
    sgx_status = sgx_rsa_pub_encrypt_sha256(pub_key, msg3_output->encrypted_pwk2, &output_len, reinterpret_cast<const unsigned char*>(pwk2_tlv_buffer),
        PWK2_TLV_TOTAL_SIZE);
    if (SGX_SUCCESS != sgx_status) {
        ret = sgx_error_to_pve_error(sgx_status);
        goto ret_point;
    }

    // X = (NT)MAC_PWK2(... (NT)E_PWK2((T)(JoinP, f)) ...) | (NT)E_PWK2((T)(JoinP, f)) | (NT)PWK2N | (NT)E_PEK((T)PWK2)
    // REPORT.ReportData == SHA256[X] 
    memcpy(pdata, msg3_output->field1_mac, MAC_SIZE);
    pdata += MAC_SIZE;
    if (!performance_rekey_used){
        memcpy(pdata, msg3_output->field1_data, HARD_CODED_JOIN_PROOF_WITH_ESCROW_TLV_SIZE);
        pdata += HARD_CODED_JOIN_PROOF_WITH_ESCROW_TLV_SIZE;
    }
    memcpy(pdata, msg3_output->n2, NONCE_2_SIZE);
    pdata += NONCE_2_SIZE;
    memcpy(pdata, msg3_output->encrypted_pwk2, PEK_MOD_SIZE);
    pdata += PEK_MOD_SIZE;
    se_static_assert(sizeof(report_data) >= sizeof(sgx_sha256_hash_t)); /*report data is no large enough*/
    sgx_status = sgx_sha256_msg(report_data_payload, (uint32_t)(pdata - &report_data_payload[0]), reinterpret_cast<sgx_sha256_hash_t *>(&report_data));
    if (SGX_SUCCESS != sgx_status){
        ret = sgx_error_to_pve_error(sgx_status);
        goto ret_point;
    }
    sgx_status = sgx_create_report(&msg2_blob_input->pce_target_info, &report_data, &msg3_output->pwk2_report);
    if (SGX_SUCCESS != sgx_status){
        ret = sgx_error_to_pve_error(sgx_status);
        goto ret_point;
    }

ret_point:
    (void)memset_s(aad, sizeof(aad), 0, sizeof(aad));
    (void)memset_s(temp_buf, sizeof(temp_buf), 0, sizeof(temp_buf));
    (void)memset_s(pwk2_tlv_buffer, sizeof(pwk2_tlv_buffer),0,sizeof(pwk2_tlv_buffer));
    if(pub_key){
        sgx_free_rsa_key(pub_key, SGX_RSA_PUBLIC_KEY, sizeof(pek.n), sizeof(pek.e));
    }

    return ret;
}
示例#7
0
//Function to generate Field1_0 of ProvMsg3
//@msg2_blob_input, input decoded ProvMsg2 info
//@join_proof, output the join proof and the escrow data which is encrypted f of Private Key
//@return PVEC_SUCCESS on success and error code on failure
//The function assume all required inputs have been prepared in msg2_blob_input
static pve_status_t gen_msg3_join_proof_escrow_data(const proc_prov_msg2_blob_input_t *msg2_blob_input,
                                                    join_proof_with_escrow_t& join_proof)
{
    pve_status_t ret = PVEC_SUCCESS;
    BitSupplier epid_prng = (BitSupplier) epid_random_func;
    FpElemStr temp_f;
    //first generate private key f randomly before sealing it by PSK
    FpElemStr *f = &temp_f;
    sgx_status_t sgx_status = SGX_SUCCESS;
    JoinRequest *join_r = &join_proof.jr;
    EpidStatus epid_ret  = kEpidNoErr;
    psvn_t psvn;
    MemberCtx* ctx = NULL;
    memset(&temp_f, 0, sizeof(temp_f));

    //randomly generate the private EPID key f, host to network transformation not required since server will not decode it
    ret=sgx_error_to_pve_error(sgx_gen_epid_priv_f((void*)f));
	if(PVEC_SUCCESS != ret){
        goto ret_point;
    }

    //generate JoinP using f before encryption by calling EPID library
    memset(join_r, 0, sizeof(JoinRequest));//first clear to 0
    //generate JoinP to fill it in field1_0_0 by EPID library

    epid_ret = epid_member_create(epid_prng, NULL, f, &ctx);
    if(kEpidNoErr!=epid_ret){
        ret = epid_error_to_pve_error(epid_ret);
        goto ret_point;
    }
    
    epid_ret = EpidCreateJoinRequest(ctx, 
        &msg2_blob_input->group_cert.key, //EPID Group Cert from ProvMsgs2 used
        reinterpret_cast<const IssuerNonce *>(msg2_blob_input->challenge_nonce),
        join_r);
    if(kEpidNoErr != epid_ret){
        ret = epid_error_to_pve_error(epid_ret);
        goto ret_point;
    }

    //get PSK
    sgx_key_128bit_t psk;
    memcpy(&psvn.cpu_svn, &msg2_blob_input->equiv_pi.cpu_svn, sizeof(psvn.cpu_svn));
    memcpy(&psvn.isv_svn, &msg2_blob_input->equiv_pi.pve_svn, sizeof(psvn.isv_svn));
    ret = get_pve_psk(&psvn, &psk);
    if(PVEC_SUCCESS != ret){
        goto ret_point;
    }

    join_proof.escrow.version = 0;//version 0 used for escrow data
    //now we could seal f by PSK
    ret = se_read_rand_error_to_pve_error(sgx_read_rand(join_proof.escrow.iv, IV_SIZE));
    if(PVEC_SUCCESS != ret){
        goto ret_point;
    }

    se_static_assert(sizeof(psk)==sizeof(sgx_aes_gcm_128bit_key_t)); /*sizeof sgx_aes_gcm_128bit_key_t tshould be same as size of psk*/
    se_static_assert(sizeof(sgx_aes_gcm_128bit_tag_t)==sizeof(join_proof.escrow.mac)); /*sizeof sgx_aes_gcm_128bit_tag_t should be same as MAC_SIZE*/
    sgx_status = sgx_rijndael128GCM_encrypt(reinterpret_cast<const sgx_aes_gcm_128bit_key_t *>(&psk),
        reinterpret_cast<uint8_t *>(f), sizeof(*f), reinterpret_cast<uint8_t *>(&join_proof.escrow.f),
        join_proof.escrow.iv, IV_SIZE, NULL, 0, 
        reinterpret_cast<sgx_aes_gcm_128bit_tag_t *>(join_proof.escrow.mac));
    if(SGX_SUCCESS != sgx_status){
        ret = sgx_error_to_pve_error(sgx_status);
    }
ret_point:
    (void)memset_s(&psk, sizeof(psk), 0, sizeof(psk));//clear the key
    (void)memset_s(&temp_f, sizeof(temp_f), 0, sizeof(temp_f));//clear temp f in stack
    if(PVEC_SUCCESS != ret){
        (void)memset_s(&join_proof, sizeof(join_proof), 0, sizeof(join_proof));
    }
    epid_member_delete(&ctx);
    return ret;
}
示例#8
0
//This function will first generate EPIDSig Header according to sigrl_header
//After that, piece meal algorithm is used to
//   decode SigRl Entry in msg2 and update hash value 
//   generate EPIDSigEntry in msg3 and encrypt it
// The memory of msg2 for SigRl and  msg3 for EPIDSigEntry are all outside enclave
//     So that we need first copy each SigRl Entry into EPC memory, generate EPIDSigEntry inside EPC memory 
//            and copy it out after it is generated
//   The function assumes the size of SigRl has been verfied and it is not checked again here. 
// Finally it checks whether the hash value is valid according to ECDSA Sign in the end of SigRl to verify data is not modified
// A TLV Header for the EpidSignature should have been prepared in EPC memory signature_tlv_header
//It is assumed that the parm->sigrl_count>0 when the function is called and the size of sigrl has been checked
//EpidSignature TLV format: TLVHeader:EpidSignatureHeader:NrProof1:NrProof2:...:NrProofn
static pve_status_t gen_msg3_signature(const proc_prov_msg2_blob_input_t *msg2_blob_input,
                                       prov_msg3_parm_t *parm, 
                                       external_memory_byte_t *emp_signature,//pointer to external memory to write the EPID Signature
                                       uint32_t& signature_size) 
{
    pve_status_t ret = PVEC_SUCCESS;
    uint32_t cur_size = static_cast<uint32_t>(EPID_SIGNATURE_TLV_HEADER_SIZE+sizeof(EpidSignature)-sizeof(NrProof));
    //emp_proof_entry is pointer to external memory to each entry of the epid signature body in external memory
    external_memory_byte_t *emp_proof_entry = emp_signature + cur_size; 
    //emp_sigrl_entry is pointer to external memory to each entry of the sigrl_body in external memory
    const external_memory_byte_t *emp_sigrl_entry = parm->emp_sigrl_sig_entries;
    uint32_t i,entry_count = parm->sigrl_count;
    bool revoked = false;
    uint8_t sigrl_sign[2*ECDSA_SIGN_SIZE];//temp buffer in EPC to hold ECDSA signature
    //declare a buffer to hold encrypted data of TLV Header and EpidSignature Header
    uint8_t signature_header_to_encrypt[EPID_SIGNATURE_TLV_HEADER_SIZE + sizeof(EpidSignature)-sizeof(NrProof)];
    SigRlEntry temp1;
    NrProof temp3;
    uint32_t tlv_payload_size = 0;
    const SigRl *sigrl_header = NULL;
    BigNumStr rnd_bsn = { 0 };
    sgx_status_t sgx_status = SGX_SUCCESS;

    memset(sigrl_sign, 0, sizeof(sigrl_sign));
    memset(&temp1, 0, sizeof(temp1));
    memset(&temp3, 0, sizeof(temp3));
    memset(signature_header_to_encrypt, 0, sizeof(signature_header_to_encrypt));

    if(entry_count>0){
        sigrl_header = &parm->sigrl_header.sig_rl;//use the sigrl_header only when sigrl is available
        if(signature_size <  cur_size){//size of output buffer at least to hold currently generated data
            ret = PVEC_INSUFFICIENT_MEMORY_ERROR;
            goto ret_point;
        }
        if((signature_size-cur_size)/entry_count<sizeof(NrProof)){//safe way to check buffer overflow of output buffer to avoid integer overflow
            ret = PVEC_INSUFFICIENT_MEMORY_ERROR;
            goto ret_point;
        }
        tlv_payload_size = static_cast<uint32_t>(sizeof(EpidSignature)-sizeof(NrProof) + entry_count * sizeof(NrProof));
    }else{
        tlv_payload_size = static_cast<uint32_t>(sizeof(EpidSignature)-sizeof(NrProof)); //payload size for 0 entry, only basic signature with n2 and rl_ver to be 0
        if(signature_size <  cur_size){//size of output buffer at least to hold currently generated data
            ret = PVEC_INSUFFICIENT_MEMORY_ERROR;
            goto ret_point;
        }
    }

    memcpy(signature_header_to_encrypt, EPID_SIGNATURE_TLV_HEADER, EPID_SIGNATURE_TLV_HEADER_SIZE); //copy in the hard coded EPID Signature TLV Header
    tlv_payload_size = pve_htonl(tlv_payload_size);
    //overwritten the bigendian size in TLV Header. It is assumed that the size in TLV Header is always 4 bytes//Long format
    memcpy(signature_header_to_encrypt+EPID_SIGNATURE_TLV_SIZE_OFFSET, &tlv_payload_size, sizeof(tlv_payload_size));

    ret = gen_epid_signature_header(sigrl_header, parm->epid_member, msg2_blob_input->challenge_nonce, &parm->signature_header, &rnd_bsn);//Now generate EpidSignatureHeader 
    if( PVEC_SUCCESS != ret )
        goto ret_point;
    //Now encrypt the TLV Header and signature header including basic signature while the parm->signature_header is kept since piece-meal processing will use it
    memcpy(signature_header_to_encrypt+EPID_SIGNATURE_TLV_HEADER_SIZE, &parm->signature_header, cur_size-EPID_SIGNATURE_TLV_HEADER_SIZE);
    ret = sgx_error_to_pve_error(sgx_aes_gcm128_enc_inplace_update((sgx_aes_state_handle_t*)parm->p_msg3_state, signature_header_to_encrypt, cur_size));
    if( PVEC_SUCCESS != ret )
        goto ret_point;

    pve_memcpy_out(emp_signature, signature_header_to_encrypt, cur_size);//copy out tlv header, basic signature and other epid signature header info if required

    if(NULL==parm->emp_sigrl_sig_entries){//finish if no sigrl avaiable
        signature_size = cur_size;
        goto ret_point;
    }

    //copy the ECDSA Signature of the SigRl in ProvMsg2 into EPC memory in advance to defense in depth
    pve_memcpy_in(sigrl_sign, emp_sigrl_entry + entry_count *sizeof(SigRlEntry), 2*ECDSA_SIGN_SIZE);

    //piece-meal processing
    //The pointer calculation will never overflow as soon as size of sigrl and epid signature have been checked in advance
    //TO BE CLARIFY:We assume that the ecdsa signature follows entry array of SigRl directly 
    //  If later we change the format of sigrl to include extra data which should be ecdsa signed too,
    //       we need do the modification here: change the sigrl_sign and do more sha update
    signature_size = static_cast<uint32_t>(cur_size+entry_count *sizeof(NrProof));//recalculate output buffer
    //Start piece meal processing for each entry
    for(i=0;i<entry_count; i++){
        pve_memcpy_in(&temp1, emp_sigrl_entry, sizeof(temp1));//copy the data into trusted memory
        //update hash for the SigRl Entry
        sgx_status = sgx_sha256_update(reinterpret_cast<uint8_t *>(&temp1), sizeof(SigRlEntry), parm->sha_state);
        if(sgx_status != SGX_SUCCESS){
            ret = sgx_error_to_pve_error(sgx_status);
            goto ret_point;
        }
        //generate NrProof for the SigRl Entry in trusted memory
        EpidStatus epid_ret = EpidNrProve(parm->epid_member,
            const_cast<uint8_t *>(msg2_blob_input->challenge_nonce),//msg to sign
            CHALLENGE_NONCE_SIZE,
            &rnd_bsn,
            sizeof(rnd_bsn),
            &parm->signature_header.sigma0, //B and K in BasicSignature
            &temp1,  //B and K in sigrl entry
            &temp3); //output one NrProof
        if(kEpidNoErr != epid_ret){
            if(kEpidSigRevokedInSigRl == epid_ret){
                revoked = true;//if revoked, we could not return revoked status immediately until integrity checking passed
            }else{
                ret = epid_error_to_pve_error(epid_ret);
                goto ret_point;
            }
        }
        //encrypt the NrProof in EPC
        ret = sgx_error_to_pve_error(sgx_aes_gcm128_enc_inplace_update((sgx_aes_state_handle_t*)parm->p_msg3_state, reinterpret_cast<uint8_t *>(&temp3), sizeof(temp3)));
        if(ret != PVEC_SUCCESS){
            goto ret_point;
        }
        pve_memcpy_out(emp_proof_entry, &temp3, sizeof(temp3));//copy encrypted NrProof out of enclave
        emp_sigrl_entry += sizeof(SigRlEntry);//pointer to next SigRlEntry in external memory
        emp_proof_entry += sizeof(NrProof);//pointer to next NrProof in external memory
    }

    se_ae_ecdsa_hash_t out;
    //generate SHA256 hash value of the whole SigRl
    if((sgx_status=sgx_sha256_get_hash(parm->sha_state,
        reinterpret_cast<sgx_sha256_hash_t *>(&out))) !=
        SGX_SUCCESS){
            ret = sgx_error_to_pve_error(sgx_status);
            goto ret_point;
    }
    //Verify the signature is signed by EPIDSK 
    ret = verify_epid_ecdsa_signature(sigrl_sign, parm->local_xegb, &out);
    if(ret == PVEC_MSG_ERROR){
        ret = PVEC_SIGRL_INTEGRITY_CHECK_ERROR;//If sigrl signature checking failed, someone must has modified the message
    }

ret_point:
    //clear unsealed NrProof to defense in depth for potential attack to match attacker created sigrl entry with key 
    //While we need not clear BasicSignature
    (void)memset_s(&temp3, sizeof(temp3), 0, sizeof(temp3));
    if(ret == PVEC_SUCCESS &&revoked){
        ret = PVEC_REVOKED_ERROR;
    }
    return ret;
}