/******************************************************************* ** Function name: calculate_owner_id ** Descrption: ** Calculate VMC Access Control Information. An ID of the creator of a VMC is defined as: ** MR=[]; ** If (OwnerPolicy.MRSIGNER==1) MR=MR||REPORT(creator).MRSIGNER; ** If (OwnerPolicy.MREnclave==1) MR=MR||REPORT(creator).MRENCLAVE; ** MaskedAttrs = REPORT(creator).ATTRIBUTES & OwnerAttrMask ** OwnerID =SHA256(MR||MaskedAttrs|| REPORT(creator).ProdID)); *******************************************************************/ static sgx_status_t calculate_owner_id( const isv_attributes_t &owner_attributes, // [IN] ISV's attributes info const uint16_t mc_policy, // [IN] user's access control policy const uint8_t* mc_att_mask, // [IN] attribute mask void* owner_id) // [OUT] ID of the creator of VMC { sgx_sha_state_handle_t ctx = NULL; sgx_status_t sgx_ret = SGX_SUCCESS; assert(owner_id != NULL && mc_att_mask != NULL); do { sgx_ret = sgx_sha256_init(&ctx); BREAK_ON_ERROR(sgx_ret); if (mc_policy & MC_POLICY_SIGNER) { sgx_ret = sgx_sha256_update((const uint8_t *)(&owner_attributes.mr_signer), sizeof(owner_attributes.mr_signer), ctx); BREAK_ON_ERROR(sgx_ret); } if (mc_policy & MC_POLICY_ENCLAVE) { sgx_ret = sgx_sha256_update((const uint8_t *)(&owner_attributes.mr_enclave), sizeof(owner_attributes.mr_enclave), ctx); BREAK_ON_ERROR(sgx_ret); } uint64_t masked_att_flags = owner_attributes.attribute.flags & *((const uint64_t*)mc_att_mask); sgx_ret = sgx_sha256_update((const uint8_t *)&masked_att_flags, sizeof(masked_att_flags), ctx); BREAK_ON_ERROR(sgx_ret); uint64_t masked_att_xfrm = owner_attributes.attribute.xfrm & *((const uint64_t*)(mc_att_mask+8)); sgx_ret = sgx_sha256_update((const uint8_t *)&masked_att_xfrm, sizeof(masked_att_xfrm), ctx); BREAK_ON_ERROR(sgx_ret); sgx_ret = sgx_sha256_update((const uint8_t *)(&owner_attributes.isv_prod_id), sizeof(sgx_prod_id_t), ctx); BREAK_ON_ERROR(sgx_ret); sgx_ret = sgx_sha256_get_hash(ctx, (sgx_sha256_hash_t*)owner_id); BREAK_ON_ERROR(sgx_ret); } while (0); if(ctx) { sgx_status_t ret = sgx_sha256_close(ctx); sgx_ret = (sgx_ret != SGX_SUCCESS)? sgx_ret : ret; } return sgx_ret; }
ae_error_t PrepareHashSHA256::Update(const void* pData, size_t numBytes) { ae_error_t ae_status = PSE_PR_HASH_CALC_ERROR; do { if (SGX_SUCCESS != m_sgx_status) { break; } if (NULL == pData || numBytes < 1 || NULL == m_pShaState || numBytes > UINT32_MAX) { m_sgx_status = SGX_ERROR_INVALID_PARAMETER; break; } m_sgx_status = sgx_sha256_update((const uint8_t*)pData, (uint32_t)numBytes, m_pShaState); if (SGX_SUCCESS != m_sgx_status) { break; } ae_status = AE_SUCCESS; } while (0); if (SGX_ERROR_OUT_OF_MEMORY == m_sgx_status) { ae_status = PSE_PR_INSUFFICIENT_MEMORY_ERROR; } return ae_status; }
/* the caller is supposed to fill the quote field in emp_msg3 before calling * this function.*/ extern "C" sgx_status_t sgx_ra_get_msg3_trusted( sgx_ra_context_t context, uint32_t quote_size, sgx_report_t* qe_report, sgx_ra_msg3_t *emp_msg3, //(mac||g_a||ps_sec_prop||quote) uint32_t msg3_size) { if(vector_size(&g_ra_db) <= context ||!quote_size || !qe_report || !emp_msg3) return SGX_ERROR_INVALID_PARAMETER; ra_db_item_t* item = NULL; if(0 != vector_get(&g_ra_db, context, reinterpret_cast<void**>(&item)) || item == NULL ) return SGX_ERROR_INVALID_PARAMETER; //check integer overflow of msg3_size and quote_size if (UINTPTR_MAX - reinterpret_cast<uintptr_t>(emp_msg3) < msg3_size || UINT32_MAX - quote_size < sizeof(sgx_ra_msg3_t) || sizeof(sgx_ra_msg3_t) + quote_size != msg3_size) return SGX_ERROR_INVALID_PARAMETER; if (!sgx_is_outside_enclave(emp_msg3, msg3_size)) return SGX_ERROR_INVALID_PARAMETER; // // fence after boundary check // this also stops speculation in case of // branch associated // with sizeof(sgx_ra_msg3_t) + quote_size != msg3_size // mispredicting // sgx_lfence(); sgx_status_t se_ret = SGX_ERROR_UNEXPECTED; //verify qe report se_ret = sgx_verify_report(qe_report); if(se_ret != SGX_SUCCESS) { if (SGX_ERROR_MAC_MISMATCH != se_ret && SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; return se_ret; } sgx_spin_lock(&item->item_lock); //sgx_ra_proc_msg2_trusted must have been called if (item->state != ra_proc_msg2ed) { sgx_spin_unlock(&item->item_lock); return SGX_ERROR_INVALID_STATE; } //verify qe_report attributes and mr_enclave same as quoting enclave if( memcmp( &qe_report->body.attributes, &item->qe_target.attributes, sizeof(sgx_attributes_t)) || memcmp( &qe_report->body.mr_enclave, &item->qe_target.mr_enclave, sizeof(sgx_measurement_t)) ) { sgx_spin_unlock(&item->item_lock); return SGX_ERROR_INVALID_PARAMETER; } sgx_ra_msg3_t msg3_except_quote_in; sgx_cmac_128bit_key_t smk_key; memcpy(&msg3_except_quote_in.g_a, &item->g_a, sizeof(msg3_except_quote_in.g_a)); memcpy(&msg3_except_quote_in.ps_sec_prop, &item->ps_sec_prop, sizeof(msg3_except_quote_in.ps_sec_prop)); memcpy(&smk_key, &item->smk_key, sizeof(smk_key)); sgx_spin_unlock(&item->item_lock); sgx_sha_state_handle_t sha_handle = NULL; sgx_cmac_state_handle_t cmac_handle = NULL; //SHA256(NONCE || emp_quote) sgx_sha256_hash_t hash = {0}; se_ret = sgx_sha256_init(&sha_handle); if (SGX_SUCCESS != se_ret) { if(SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; return se_ret; } if (NULL == sha_handle) { return SGX_ERROR_UNEXPECTED; } do { se_ret = sgx_sha256_update((uint8_t *)&item->quote_nonce, sizeof(item->quote_nonce), sha_handle); if (SGX_SUCCESS != se_ret) { if(SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; break; } //cmac M := ga || PS_SEC_PROP_DESC(all zero if unused) ||emp_quote sgx_cmac_128bit_tag_t mac; se_ret = sgx_cmac128_init(&smk_key, &cmac_handle); if (SGX_SUCCESS != se_ret) { if(SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; break; } if (NULL == cmac_handle) { se_ret = SGX_ERROR_UNEXPECTED; break; } se_ret = sgx_cmac128_update((uint8_t*)&msg3_except_quote_in.g_a, sizeof(msg3_except_quote_in.g_a), cmac_handle); if (SGX_SUCCESS != se_ret) { if(SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; break; } se_ret = sgx_cmac128_update((uint8_t*)&msg3_except_quote_in.ps_sec_prop, sizeof(msg3_except_quote_in.ps_sec_prop), cmac_handle); if (SGX_SUCCESS != se_ret) { if(SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; break; } // sha256 and cmac quote uint8_t quote_piece[32]; const uint8_t* emp_quote_piecemeal = emp_msg3->quote; uint32_t quote_piece_size = static_cast<uint32_t>(sizeof(quote_piece)); while (emp_quote_piecemeal < emp_msg3->quote + quote_size) { //calculate size of one piece, the size of them are sizeof(quote_piece) except for the last one. if (static_cast<uint32_t>(emp_msg3->quote + quote_size - emp_quote_piecemeal) < quote_piece_size) quote_piece_size = static_cast<uint32_t>(emp_msg3->quote - emp_quote_piecemeal) + quote_size ; memcpy(quote_piece, emp_quote_piecemeal, quote_piece_size); se_ret = sgx_sha256_update(quote_piece, quote_piece_size, sha_handle); if (SGX_SUCCESS != se_ret) { if(SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; break; } se_ret = sgx_cmac128_update(quote_piece, quote_piece_size, cmac_handle); if (SGX_SUCCESS != se_ret) { if(SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; break; } emp_quote_piecemeal += sizeof(quote_piece); } ERROR_BREAK(se_ret); //get sha256 hash value se_ret = sgx_sha256_get_hash(sha_handle, &hash); if (SGX_SUCCESS != se_ret) { if(SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; break; } //get cmac value se_ret = sgx_cmac128_final(cmac_handle, &mac); if (SGX_SUCCESS != se_ret) { if(SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; break; } //verify qe_report->body.report_data == SHA256(NONCE || emp_quote) if(0 != memcmp(&qe_report->body.report_data, &hash, sizeof(hash))) { se_ret = SGX_ERROR_MAC_MISMATCH; break; } memcpy(&msg3_except_quote_in.mac, mac, sizeof(mac)); memcpy(emp_msg3, &msg3_except_quote_in, offsetof(sgx_ra_msg3_t, quote)); se_ret = SGX_SUCCESS; }while(0); memset_s(&smk_key, sizeof(smk_key), 0, sizeof(smk_key)); (void)sgx_sha256_close(sha_handle); if(cmac_handle != NULL) sgx_cmac128_close(cmac_handle); return se_ret; }
// Derive two keys from shared key and key id. bool derive_key( const sgx_ec256_dh_shared_t *p_shared_key, uint8_t key_id, sgx_ec_key_128bit_t *first_derived_key, sgx_ec_key_128bit_t *second_derived_key) { sgx_status_t sgx_ret = SGX_SUCCESS; hash_buffer_t hash_buffer; sgx_sha_state_handle_t sha_context; sgx_sha256_hash_t key_material; memset(&hash_buffer, 0, sizeof(hash_buffer_t)); /* counter in big endian */ hash_buffer.counter[3] = key_id; /*convert from little endian to big endian */ for (size_t i = 0; i < sizeof(sgx_ec256_dh_shared_t); i++) { hash_buffer.shared_secret.s[i] = p_shared_key->s[sizeof(p_shared_key->s)-1 - i]; } sgx_ret = sgx_sha256_init(&sha_context); if (sgx_ret != SGX_SUCCESS) { return false; } sgx_ret = sgx_sha256_update((uint8_t*)&hash_buffer, sizeof(hash_buffer_t), sha_context); if (sgx_ret != SGX_SUCCESS) { sgx_sha256_close(sha_context); return false; } sgx_ret = sgx_sha256_update((uint8_t*)&ID_U, sizeof(ID_U), sha_context); if (sgx_ret != SGX_SUCCESS) { sgx_sha256_close(sha_context); return false; } sgx_ret = sgx_sha256_update((uint8_t*)&ID_V, sizeof(ID_V), sha_context); if (sgx_ret != SGX_SUCCESS) { sgx_sha256_close(sha_context); return false; } sgx_ret = sgx_sha256_get_hash(sha_context, &key_material); if (sgx_ret != SGX_SUCCESS) { sgx_sha256_close(sha_context); return false; } sgx_ret = sgx_sha256_close(sha_context); assert(sizeof(sgx_ec_key_128bit_t)* 2 == sizeof(sgx_sha256_hash_t)); memcpy(first_derived_key, &key_material, sizeof(sgx_ec_key_128bit_t)); memcpy(second_derived_key, (uint8_t*)&key_material + sizeof(sgx_ec_key_128bit_t), sizeof(sgx_ec_key_128bit_t)); // memset here can be optimized away by compiler, so please use memset_s on // windows for production code and similar functions on other OSes. memset(&key_material, 0, sizeof(sgx_sha256_hash_t)); return true; }
/* * An internal function used to sign the EPID signature on the quote body. * Prefix "emp_" means it is a pointer points memory outside enclave. * * For quote with SIG-RL * |--------------------------------------------------------------------| * |sgx_quote_t|wrap_key_t|iv|payload_size|basic_sig|rl_ver|n2|nrp..|mac| * |--------------------------------------------------------------------| * For quote without SIG-RL * |--------------------------------------------------------------| * |sgx_quote_t|wrap_key_t|iv|payload_size|basic_sig|rl_ver|n2|mac| * |--------------------------------------------------------------| * * @param p_epid_context[in] Pointer to the EPID context. * @param plaintext[in] Reference to the plain text part of EPID blob. * @param p_basename[in] The pointer to basename. * @param emp_sig_rl_entries[in] The pointer to SIG-RL entries. * @param p_sig_rl_header[in] The header of SIG-RL, within EPC. * @param p_sig_rl_signature[in] The ecdsa signature of SIG-RL, within EPC. * @param p_enclave_report[in] The input isv report. * @param p_nonce[in] The input nonce. * @param p_qe_report[out] The output buffer for qe_report. * @param emp_quote[out] The output buffer for quote. * @param p_quote_body[in] The quote body in EPC. * @param sign_size[in] size of the signature. * @return ae_error_t AE_SUCCESS for success, otherwise for errors. */ static ae_error_t qe_epid_sign( MemberCtx *p_epid_context, const se_plaintext_epid_data_sdk_t& plaintext, const sgx_basename_t *p_basename, const SigRlEntry *emp_sig_rl_entries, se_sig_rl_t *p_sig_rl_header, sgx_ec256_signature_t *p_sig_rl_signature, const sgx_report_t *p_enclave_report, const sgx_quote_nonce_t *p_nonce, sgx_report_t *p_qe_report, uint8_t *emp_quote, const sgx_quote_t *p_quote_body, uint32_t sign_size) { ae_error_t ret = AE_SUCCESS; sgx_status_t se_ret = SGX_SUCCESS; EpidStatus epid_ret = kEpidNoErr; se_wrap_key_t wrap_key; BasicSignature basic_sig; BasicSignature encrypted_basic_sig; uint8_t aes_iv[QUOTE_IV_SIZE] = {0}; uint8_t aes_key[QE_AES_KEY_SIZE] = {0}; uint8_t aes_tag[SGX_SEAL_TAG_SIZE] = {0}; sgx_report_data_t qe_report_data = {{0}}; sgx_target_info_t report_target; sgx_ec256_public_t ec_pub_key; // little endian se_ae_ecdsa_hash_t sig_rl_hash = {{0}}; uint8_t ecc_result = SGX_EC_INVALID_SIGNATURE; sgx_sha_state_handle_t sha_context = NULL; sgx_sha_state_handle_t sha_quote_context = NULL; sgx_aes_state_handle_t aes_gcm_state = NULL; void *pub_key = NULL; size_t pub_key_size = 0; uint8_t* pub_key_buffer = NULL; sgx_ecc_state_handle_t ecc_handle = NULL; memset(&wrap_key, 0, sizeof(wrap_key)); memset(&basic_sig, 0, sizeof(basic_sig)); memset(&encrypted_basic_sig, 0, sizeof(encrypted_basic_sig)); memset(&report_target, 0, sizeof(report_target)); memset(&ec_pub_key, 0, sizeof(ec_pub_key)); se_encrypted_sign_t *emp_p = (se_encrypted_sign_t *) (((sgx_quote_t *)emp_quote)->signature); uint8_t* emp_nr = NULL; uint32_t match = FALSE; /* Sign the quote body and get the basic signature*/ epid_ret = EpidSignBasic(p_epid_context, (uint8_t *)const_cast<sgx_quote_t *>(p_quote_body), (uint32_t)QE_QUOTE_BODY_SIZE, (uint8_t *)const_cast<sgx_basename_t *>(p_basename), sizeof(*p_basename), &basic_sig, NULL); //Random basename, can be NULL if basename is provided if(kEpidNoErr != epid_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } /* Prepare the context for SHA256 of quote. */ if(p_qe_report) { se_ret = sgx_sha256_init(&sha_quote_context); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } // Update hash for nonce. se_ret = sgx_sha256_update((uint8_t *)const_cast<sgx_quote_nonce_t *>(p_nonce), sizeof(*p_nonce), sha_quote_context); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } // Update hash for the first part of quote. se_ret = sgx_sha256_update((uint8_t *)const_cast<sgx_quote_t *>(p_quote_body), sizeof(*p_quote_body), sha_quote_context); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } } /* Prepare the context for SHA256 and start calculate the hash of header * of SIG-RL. */ if(emp_sig_rl_entries) { se_ret = sgx_sha256_init(&sha_context); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } /* Calculate the hash of SIG-RL header. */ se_ret = sgx_sha256_update((uint8_t *)p_sig_rl_header, (uint32_t)(sizeof(se_sig_rl_t) - sizeof(SigRlEntry)), sha_context); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } } // Start encrypt the signature. /* Get the random wrap key */ se_ret = sgx_read_rand(aes_key, sizeof(aes_key)); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } /* Copy the hash of wrap key into output buffer. */ se_static_assert(sizeof(wrap_key.key_hash) == sizeof(sgx_sha256_hash_t)); se_ret = sgx_sha256_msg(aes_key, sizeof(aes_key), (sgx_sha256_hash_t *)wrap_key.key_hash); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } /* Start encrypt the wrap key by RSA algorithm. */ se_ret = sgx_create_rsa_pub1_key(sizeof(g_qsdk_pub_key_n), sizeof(g_qsdk_pub_key_e), (const unsigned char *)g_qsdk_pub_key_n, (const unsigned char *)g_qsdk_pub_key_e, &pub_key); if(se_ret != SGX_SUCCESS) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } /* Get output buffer size */ se_ret = sgx_rsa_pub_encrypt_sha256(pub_key, NULL, &pub_key_size, aes_key, sizeof(aes_key)); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } se_ret = sgx_rsa_pub_encrypt_sha256(pub_key, wrap_key.encrypted_key, &pub_key_size, aes_key, sizeof(aes_key)); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } /* Create the random AES IV. */ se_ret = sgx_read_rand(aes_iv, sizeof(aes_iv)); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } /* Copy the wrap_key_t into output buffer. */ memcpy(&emp_p->wrap_key, &wrap_key, sizeof(wrap_key)); /* Copy the AES IV into output buffer. */ memcpy(&emp_p->iv, aes_iv, sizeof(aes_iv)); /* Copy the AES Blob payload size into output buffer. */ memcpy(&emp_p->payload_size, &sign_size, sizeof(sign_size)); se_ret = sgx_aes_gcm128_enc_init( aes_key, aes_iv, //input initial vector. randomly generated value and encryption of different msg should use different iv sizeof(aes_iv), //length of initial vector, usually IV_SIZE NULL,//AAD of AES-GCM, it could be NULL 0, //length of bytes of AAD &aes_gcm_state); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } memset_s(aes_key, sizeof(aes_key), 0, sizeof(aes_key)); /* Encrypt the basic signature. */ se_ret = sgx_aes_gcm128_enc_update( (uint8_t *)&basic_sig, //start address to data before/after encryption sizeof(basic_sig), (uint8_t *)&encrypted_basic_sig, //length of data aes_gcm_state); //pointer to a state if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } /* Copy the encrypted basic signature into output buffer. */ memcpy(&emp_p->basic_sign, &encrypted_basic_sig, sizeof(encrypted_basic_sig)); if(p_qe_report) { se_ret = sgx_sha256_update((uint8_t *)&wrap_key, sizeof(wrap_key), sha_quote_context); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } se_ret = sgx_sha256_update(aes_iv, sizeof(aes_iv), sha_quote_context); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } se_ret = sgx_sha256_update((uint8_t *)&sign_size, sizeof(sign_size), sha_quote_context); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } se_ret = sgx_sha256_update((uint8_t *)&encrypted_basic_sig, sizeof(encrypted_basic_sig), sha_quote_context); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } } /* Start process the SIG-RL. */ if(emp_sig_rl_entries) { unsigned int entry_count = 0; unsigned int i = 0; RLver_t encrypted_rl_ver = {{0}}; RLCount encrypted_n2 = {{0}}; entry_count = lv_ntohl(p_sig_rl_header->sig_rl.n2);//entry count for big endian to little endian // Continue encrypt the output se_ret = sgx_aes_gcm128_enc_update( (uint8_t *)&(p_sig_rl_header->sig_rl.version), //start address to data before/after encryption sizeof(p_sig_rl_header->sig_rl.version), (uint8_t *)&encrypted_rl_ver, //length of data aes_gcm_state); //pointer to a state if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } se_ret = sgx_aes_gcm128_enc_update( (uint8_t *)&(p_sig_rl_header->sig_rl.n2), //start address to data before/after encryption sizeof(p_sig_rl_header->sig_rl.n2), (uint8_t *)&encrypted_n2, //length of data aes_gcm_state); //pointer to a state if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } memcpy(&(emp_p->rl_ver), &encrypted_rl_ver, sizeof(encrypted_rl_ver)); memcpy(&(emp_p->rl_num), &encrypted_n2, sizeof(encrypted_n2)); if(p_qe_report) { se_ret = sgx_sha256_update((uint8_t *)&encrypted_rl_ver, sizeof(encrypted_rl_ver), sha_quote_context); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } se_ret = sgx_sha256_update((uint8_t *)&encrypted_n2, sizeof(encrypted_n2), sha_quote_context); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } } /* Start process the SIG-RL entries one by one. */ emp_nr = emp_p->nrp_mac; for (i = 0; i < entry_count; i++, emp_nr += sizeof(NrProof)) { /* Generate non-revoke prove one by one. */ SigRlEntry entry; NrProof temp_nr; NrProof encrypted_temp_nr; memcpy(&entry, emp_sig_rl_entries + i, sizeof(entry)); memset_s(&temp_nr, sizeof(temp_nr), 0, sizeof(temp_nr)); memset_s(&encrypted_temp_nr, sizeof(encrypted_temp_nr), 0, sizeof(encrypted_temp_nr)); epid_ret = EpidNrProve(p_epid_context, (uint8_t *)const_cast<sgx_quote_t *>(p_quote_body), (uint32_t)QE_QUOTE_BODY_SIZE, (uint8_t *)const_cast<sgx_basename_t *>(p_basename), // basename is required, otherwise it will return kEpidBadArgErr sizeof(*p_basename), &basic_sig, // Basic signature with 'b' and 'k' in it &entry, //Single entry in SigRl composed of 'b' and 'k' &temp_nr); // The generated non-revoked proof if(kEpidNoErr != epid_ret) { if(kEpidSigRevokedInSigRl == epid_ret) match = TRUE; else { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } } /* Update the hash of SIG-RL */ se_ret = sgx_sha256_update((uint8_t *)&entry, sizeof(entry), sha_context); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } se_ret = sgx_aes_gcm128_enc_update( (uint8_t *)&temp_nr, //start address to data before/after encryption sizeof(encrypted_temp_nr), (uint8_t *)&encrypted_temp_nr, //length of data aes_gcm_state); //pointer to a state if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } memcpy(emp_nr, &encrypted_temp_nr, sizeof(encrypted_temp_nr)); if(p_qe_report) { se_ret = sgx_sha256_update((uint8_t *)&encrypted_temp_nr, sizeof(encrypted_temp_nr), sha_quote_context); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } } } /* Get the final hash of the whole SIG-RL. */ se_ret = sgx_sha256_get_hash(sha_context, (sgx_sha256_hash_t *)&sig_rl_hash.hash); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } /* Verify the integrity of SIG-RL by check ECDSA signature. */ se_static_assert(sizeof(ec_pub_key) == sizeof(plaintext.epid_sk)); // Both plaintext.epid_sk and ec_pub_key are little endian memcpy(&ec_pub_key, plaintext.epid_sk, sizeof(ec_pub_key)); se_ret = sgx_ecc256_open_context(&ecc_handle); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } // sgx_ecdsa_verify_hash will take ec_pub_key as little endian se_ret = sgx_ecdsa_verify_hash((uint8_t*)&(sig_rl_hash.hash), (const sgx_ec256_public_t *)&ec_pub_key, p_sig_rl_signature, &ecc_result, ecc_handle); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } else if(SGX_EC_VALID != ecc_result) { ret = QE_SIGRL_ERROR; goto CLEANUP; } else if(match) { ret = QE_REVOKED_ERROR; goto CLEANUP; } } else { se_static_assert(sizeof(emp_p->rl_ver) == sizeof(RLver_t)); se_static_assert(sizeof(emp_p->rl_num) == sizeof(RLCount)); uint8_t temp_buf[sizeof(RLver_t) + sizeof(RLCount)] = {0}; uint8_t encrypted_temp_buf[sizeof(temp_buf)] = {0}; se_ret = sgx_aes_gcm128_enc_update( (uint8_t *)&temp_buf, //start address to data before/after encryption sizeof(encrypted_temp_buf), (uint8_t *)&encrypted_temp_buf, //length of data aes_gcm_state); //pointer to a state if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } /* This will copy both encrypted rl_ver and encrypted rl_num into Output buffer. */ memcpy(&emp_p->rl_ver, &encrypted_temp_buf, sizeof(encrypted_temp_buf)); if(p_qe_report) { se_ret = sgx_sha256_update((uint8_t *)&encrypted_temp_buf, sizeof(encrypted_temp_buf), sha_quote_context); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } } } se_ret = sgx_aes_gcm128_enc_get_mac(aes_tag, aes_gcm_state); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } memcpy((uint8_t *)&(emp_p->basic_sign) + sign_size, &aes_tag, sizeof(aes_tag)); if(p_qe_report) { se_ret = sgx_sha256_update(aes_tag, sizeof(aes_tag), sha_quote_context); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } se_ret = sgx_sha256_get_hash(sha_quote_context, (sgx_sha256_hash_t *)&qe_report_data); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } memcpy(&(report_target.attributes), &(((const sgx_report_t *)p_enclave_report)->body.attributes), sizeof(report_target.attributes)); memcpy(&(report_target.mr_enclave), &(((const sgx_report_t *)p_enclave_report)->body.mr_enclave), sizeof(report_target.mr_enclave)); memcpy(&(report_target.misc_select), &(((const sgx_report_t *)p_enclave_report)->body.misc_select), sizeof(report_target.misc_select)); se_ret = sgx_create_report(&report_target, &qe_report_data, p_qe_report); if(SGX_SUCCESS != se_ret) { ret = QE_PARAMETER_ERROR; goto CLEANUP; } } CLEANUP: memset_s(aes_key, sizeof(aes_key), 0, sizeof(aes_key)); sgx_sha256_close(sha_context); sgx_sha256_close(sha_quote_context); if (aes_gcm_state) sgx_aes_gcm_close(aes_gcm_state); if (pub_key) sgx_free_rsa_key(pub_key, SGX_RSA_PUBLIC_KEY, sizeof(plaintext.qsdk_mod), sizeof(plaintext.qsdk_exp)); if (pub_key_buffer) free(pub_key_buffer); if (ecc_handle) sgx_ecc256_close_context(ecc_handle); return ret; }
//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; }