void CertificateProvisioningProtocol::free_intel_rsa_pub_key(void* rsa_pub_key) { if (NULL == rsa_pub_key) return; sgx_free_rsa_key(rsa_pub_key, SGX_RSA_PUBLIC_KEY, sizeof(m_publicKey.n), sizeof(m_publicKey.e)); }
/* * 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; }
//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; }
uint32_t CPVEClass::gen_prov_msg1( pve_data_t &pve_data, uint8_t *msg1, uint32_t msg1_size) { uint32_t ret = AE_SUCCESS; uint16_t pce_id = 0; uint16_t pce_isv_svn = 0; sgx_report_t pek_report; uint8_t *field2 = NULL; uint8_t field2_iv[IV_SIZE]; uint8_t field2_mac[MAC_SIZE]; uint8_t encrypted_ppid[RSA_3072_KEY_BYTES]; //msg1 header will be in the beginning part of the output msg provision_request_header_t *msg1_header = reinterpret_cast<provision_request_header_t *>(msg1); memset(&pek_report, 0, sizeof(pek_report)); sgx_target_info_t pce_target_info; sgx_status_t sgx_status; //Load PCE Enclave required ret = CPCEClass::instance().load_enclave(); if(ret != AE_SUCCESS){ AESM_DBG_ERROR("Fail to load PCE enclave:( ae%d)\n",ret); return ret; } ret = CPCEClass::instance().get_pce_target(&pce_target_info); if(ret != AE_SUCCESS){ AESM_DBG_ERROR("Fail to get PCE target info:( ae %d)\n",ret); return ret; } //Load PvE enclave now ret = CPVEClass::instance().load_enclave(); if( ret != AE_SUCCESS){ AESM_DBG_ERROR("Fail to load PvE enclave:(ae%d)\n",ret); return ret; } //The code will generate a report on PEK by PvE ret = gen_prov_msg1_data(&pve_data.pek, &pce_target_info, &pek_report); if(AE_SUCCESS != ret ){ AESM_DBG_ERROR("Gen ProvMsg1 in trusted code failed:( ae %d)",ret); return ret; } se_static_assert(sizeof(encrypted_ppid)==PEK_MOD_SIZE); //Load PCE Enclave required ret = CPCEClass::instance().load_enclave(); if(ret != AE_SUCCESS){ AESM_DBG_ERROR("Fail to load PCE enclave:( ae %d)\n",ret); return ret; } ret = CPCEClass::instance().get_pce_info(pek_report, pve_data.pek, pce_id, pce_isv_svn, encrypted_ppid); if(AE_SUCCESS != ret){ AESM_DBG_ERROR("Fail to generate pc_info:(ae%d)",ret); return ret; } //randomly generate XID ret = aesm_read_rand(pve_data.xid, XID_SIZE); if(AE_SUCCESS != ret ){ AESM_DBG_ERROR("Fail to generate random XID (ae%d)",ret); return ret; } //randomly generate SK ret = aesm_read_rand(pve_data.sk, SK_SIZE); if(AE_SUCCESS != ret ){ AESM_DBG_ERROR("Fail to generate random SK (ae%d)",ret); return ret; } CPCEClass::instance().unload_enclave(); ret = prov_msg1_gen_header(msg1_header, pve_data.is_performance_rekey, pve_data.xid, msg1_size); if(AE_SUCCESS != ret){ AESM_DBG_ERROR("fail to generate ProvMsg1 Header:(ae %d)",ret); return ret; } { TLVsMsg tlvs_msg1_sub; tlv_status_t tlv_status; sgx_sha256_hash_t psid; tlv_status = tlvs_msg1_sub.add_block_cipher_info(pve_data.sk); ret = tlv_error_2_pve_error(tlv_status); if(AE_SUCCESS!=ret){ AESM_DBG_ERROR("Fail to generate SK TLV of ProvMsg1 (ae %d)",ret); return ret; } sgx_status = sgx_sha256_msg(reinterpret_cast<const uint8_t *>(&pve_data.pek.n), static_cast<uint32_t>(sizeof(pve_data.pek.n) + sizeof(pve_data.pek.e)), &psid); if(SGX_SUCCESS != sgx_status){ AESM_DBG_ERROR("Fail to generate PSID, (sgx0x%x)",sgx_status); return AE_FAILURE; } se_static_assert(sizeof(sgx_sha256_hash_t)==sizeof(psid_t)); tlv_status = tlvs_msg1_sub.add_psid(reinterpret_cast<const psid_t *>(&psid)); ret = tlv_error_2_pve_error(tlv_status); if(SGX_SUCCESS != ret){ AESM_DBG_ERROR("Fail to add PSID TLV ae(%d)",ret); return ret; } //transform rsa format PEK public key of Provision Server void *rsa_pub_key = NULL; signed_pek_t le_pek{}; // Change the endian for the PEK public key for(uint32_t i = 0; i< sizeof(le_pek.n); i++) { le_pek.n[i] = pve_data.pek.n[sizeof(le_pek.n) - i - 1]; } for(uint32_t i= 0; i < sizeof(le_pek.e); i++) { le_pek.e[i] = pve_data.pek.e[sizeof(le_pek.e) - i - 1]; } sgx_status = get_provision_server_rsa_pub_key(le_pek, &rsa_pub_key); if( SGX_SUCCESS != sgx_status){ AESM_DBG_ERROR("Fail to decode PEK:%d",sgx_status); return AE_FAILURE; } uint8_t field0[RSA_3072_KEY_BYTES]; ret = aesm_rsa_oaep_encrypt(tlvs_msg1_sub.get_tlv_msg(), tlvs_msg1_sub.get_tlv_msg_size(), rsa_pub_key, field0); sgx_free_rsa_key(rsa_pub_key, SGX_RSA_PUBLIC_KEY, RSA_3072_KEY_BYTES, sizeof(le_pek.e)); if(AE_SUCCESS!=ret){ AESM_DBG_ERROR("Fail to in RSA_OAEP for ProvMsg1:(ae%d)",ret); return ret; } TLVsMsg tlvs_msg1; tlv_status= tlvs_msg1.add_cipher_text(field0, RSA_3072_KEY_BYTES, PEK_3072_PUB); ret = tlv_error_2_pve_error(tlv_status); if(AE_SUCCESS!=ret){ AESM_DBG_ERROR("Fail to generate field0 TLV of ProvMsg1( ae%d)",ret); return ret; } TLVsMsg tlvs_msg2_sub; tlv_status = tlvs_msg2_sub.add_cipher_text(encrypted_ppid, RSA_3072_KEY_BYTES, PEK_3072_PUB); ret = tlv_error_2_pve_error(tlv_status); if(AE_SUCCESS!=ret){ return ret; } if(!pve_data.is_backup_retrieval){ if(0!=memcpy_s(&pve_data.bpi.cpu_svn, sizeof(pve_data.bpi.cpu_svn), &pek_report.body.cpu_svn, sizeof(pek_report.body.cpu_svn))){ AESM_DBG_FATAL("fail in memcpy_s"); return PVE_UNEXPECTED_ERROR; } if(0!=memcpy_s(&pve_data.bpi.pve_svn, sizeof(pve_data.bpi.pve_svn), &pek_report.body.isv_svn, sizeof(pek_report.body.isv_svn))){ AESM_DBG_FATAL("fail in memcpy_s"); return PVE_UNEXPECTED_ERROR; } if(0!=memcpy_s(&pve_data.bpi.pce_svn, sizeof(pve_data.bpi.pce_svn), &pce_isv_svn, sizeof(pce_isv_svn))){ AESM_DBG_FATAL("fail in memcpy_s"); return PVE_UNEXPECTED_ERROR; } } //always use pce_id from PCE enclave pve_data.bpi.pce_id = pce_id; memset(&pve_data.bpi.fmsp, 0, sizeof(pve_data.bpi.fmsp)); tlv_status = tlvs_msg2_sub.add_platform_info(pve_data.bpi); ret = tlv_error_2_pve_error(tlv_status); if(AE_SUCCESS != ret){ AESM_DBG_ERROR("Fail to generate Platform Info TLV of ProvMsg1 (ae%d)",ret); return ret; } if(pve_data.is_performance_rekey){ flags_t flags; memset(&flags,0,sizeof(flags)); //set performance rekey flags flags.flags[FLAGS_SIZE-1]=1; tlv_status = tlvs_msg2_sub.add_flags(&flags); ret = tlv_error_2_pve_error(tlv_status); if(AE_SUCCESS != ret){ AESM_DBG_ERROR("Fail to generate FLAGS TLV of ProvMsg1, (ae %d)",ret); return ret; } } ret = aesm_read_rand(field2_iv, IV_SIZE); if(AE_SUCCESS != ret){ AESM_DBG_ERROR("Fail to read rand:(ae%d)",ret); return ret; } sgx_cmac_128bit_tag_t ek1; se_static_assert(SK_SIZE==sizeof(sgx_cmac_128bit_key_t)); if((sgx_status = sgx_rijndael128_cmac_msg(reinterpret_cast<const sgx_cmac_128bit_key_t *>(pve_data.sk), pve_data.xid, XID_SIZE, &ek1))!=SGX_SUCCESS){ AESM_DBG_ERROR("Fail to generate ek1:(sgx%d)",sgx_status); return AE_FAILURE; } field2 = (uint8_t *)malloc(tlvs_msg2_sub.get_tlv_msg_size()); if(NULL == field2){ AESM_DBG_ERROR("Out of memory"); return AE_OUT_OF_MEMORY_ERROR; } sgx_status = sgx_rijndael128GCM_encrypt(&ek1, tlvs_msg2_sub.get_tlv_msg(), tlvs_msg2_sub.get_tlv_msg_size(), field2,field2_iv, IV_SIZE, (const uint8_t *)msg1_header, sizeof(provision_request_header_t), (sgx_aes_gcm_128bit_tag_t *)field2_mac); if(SGX_SUCCESS != sgx_status){ ret = sgx_error_to_ae_error(sgx_status); AESM_DBG_ERROR("Fail to do AES encrypt (sgx %d)", sgx_status); free(field2); return ret; } tlv_status = tlvs_msg1.add_block_cipher_text(field2_iv, field2, tlvs_msg2_sub.get_tlv_msg_size()); ret = tlv_error_2_pve_error(tlv_status); if(AE_SUCCESS!=ret){ free(field2); AESM_DBG_ERROR("Fail to generate field1 TLV of ProvMsg1(ae%d)",ret); return ret; } free(field2); tlv_status = tlvs_msg1.add_mac(field2_mac); ret = tlv_error_2_pve_error(tlv_status); if(AE_SUCCESS!=ret){ AESM_DBG_ERROR("Fail to create field2 TLV of ProvMsg1:(ae %d)",ret); return ret; } uint32_t size = tlvs_msg1.get_tlv_msg_size(); if(memcpy_s(msg1+PROVISION_REQUEST_HEADER_SIZE, msg1_size - PROVISION_REQUEST_HEADER_SIZE, tlvs_msg1.get_tlv_msg(), size)!=0){ //The size overflow has been checked in header generation AESM_DBG_FATAL("fail in memcpy_s"); return PVE_UNEXPECTED_ERROR; } } return AE_SUCCESS; }