//Function to fetch gid from Epid Data Blob and also return target info //EPID Provisioning will be redone if Epid Data Blob is not existing/invalid or // the qe_isv_svn or cpu_svn don't match that in Epid Data Blob aesm_error_t QEAESMLogic::init_quote( sgx_target_info_t *target, uint8_t *gid, uint32_t gid_size, uint16_t qe_isv_svn, const sgx_cpu_svn_t qe_cpu_svn) { ae_error_t ae_ret = AE_SUCCESS; EPIDBlob& epid_blob = EPIDBlob::instance(); AESM_DBG_DEBUG("enter fun"); aesm_error_t aesm_result = AESM_UNEXPECTED_ERROR; AESM_PROFILE_FUN; epid_blob_with_cur_psvn_t epid_data; bool resealed = false; bool updated = false; memset(&epid_data,0,sizeof(epid_data)); AESM_DBG_TRACE("start read and verify old epid blob"); if((ae_ret = epid_blob.read(epid_data))!=AE_SUCCESS){ if(AESM_SUCCESS!=(aesm_result = try_reprovision_if_not(updated, epid_data))){ goto ret_point; } } if((ae_ret = CQEClass::instance().load_enclave())!=AE_SUCCESS) { AESM_DBG_ERROR("Fail to load QE:%d", ae_ret); aesm_result = AESM_UNEXPECTED_ERROR; goto ret_point; } ae_ret = static_cast<ae_error_t>(CQEClass::instance().verify_blob(epid_data.trusted_epid_blob, SGX_TRUSTED_EPID_BLOB_SIZE, &resealed)); if(ae_ret == QE_EPIDBLOB_ERROR){ if(AESM_SUCCESS!=(aesm_result = try_reprovision_if_not(updated, epid_data))){ goto ret_point; } } else if(ae_ret != AE_SUCCESS) { aesm_result = AESM_UNEXPECTED_ERROR; goto ret_point; } // Assert the size of GID, we have already checked it in upper level. assert(sizeof(uint32_t) == gid_size); UNUSED(gid_size); if (AE_SUCCESS != EPIDBlob::instance().get_sgx_gid((uint32_t*) gid)) { aesm_result = AESM_UNEXPECTED_ERROR; goto ret_point; } AESM_DBG_TRACE("get gid %d from epid blob (little-endian)", *(uint32_t*) gid); if(get_qe_target(target)!=AE_SUCCESS){ AESM_DBG_ERROR("get qe target failed"); aesm_result = AESM_UNEXPECTED_ERROR; goto ret_point; } AESM_DBG_TRACE("get qe_target flags:%llx xfrm:%llx", target->attributes.flags, target->attributes.xfrm); //Any Quoting enclave related code must be before this section to avoid QE/PvE unloading each other //Do the upgrade reprovision if required AESM_DBG_TRACE("qe_isv_svn %d, epid_isv_svn %df",qe_isv_svn, epid_data.cur_psvn.isv_svn); if((qe_isv_svn > epid_data.cur_psvn.isv_svn) || (0!=memcmp(&qe_cpu_svn, &epid_data.cur_psvn.cpu_svn, sizeof(sgx_cpu_svn_t)))) { //We will ignore all provision failure when there is a working EPID blob and leave the decision to attestation server if(AESM_SUCCESS == (aesm_result = try_reprovision_if_not(updated, epid_data))){ resealed = false; }else if(AESM_PROXY_SETTING_ASSIST == aesm_result || AESM_BUSY == aesm_result || AESM_UPDATE_AVAILABLE == aesm_result ){//we should not ignore the three special error goto ret_point; } } //Any Quoting enclave related code must be before this section to avoid QE/PvE unloading each other */ aesm_result = AESM_SUCCESS; ret_point: if(resealed && aesm_result == AESM_SUCCESS){ AESM_DBG_TRACE("Update epid blob"); if((ae_ret=epid_blob.write(epid_data))!=AE_SUCCESS){ AESM_DBG_WARN("Fail to update epid blob:%d",ae_ret); } } return aesm_result; }
//Function to implement the end point selection protocol ae_error_t EndpointSelectionInfo::start_protocol(endpoint_selection_infos_t& es_info) { AESMLogicLock lock(_es_lock); uint32_t msg_size = 0; uint8_t *resp = NULL; uint32_t resp_size = 0; uint16_t provision_ttl = 0; uint8_t *msg = NULL; uint8_t rsa_signature[RSA_3072_KEY_BYTES]; gen_endpoint_selection_output_t enclave_output; ae_error_t ae_ret = AE_SUCCESS; uint32_t enclave_lost_count = 0; AESM_DBG_DEBUG("enter fun"); memset(&es_info, 0, sizeof(es_info)); memset(&enclave_output, 0, sizeof(enclave_output)); if(!_is_server_url_valid){ ae_ret = get_url_info(); if(AE_SUCCESS != ae_ret){//It is not likely happen, only fail when memcpy_s failed AESM_DBG_ERROR("Fail to initialize server URL information"); goto final_point; } } do{ if((ae_ret = CPVEClass::instance().load_enclave())!=AE_SUCCESS){ AESM_DBG_ERROR("Fail to load PVE enclave:%d", ae_ret); goto final_point; } //call PvE to generate the partition and xid ae_ret = static_cast<ae_error_t>(CPVEClass::instance().gen_es_msg1_data(&enclave_output)); if(ae_ret == AE_ENCLAVE_LOST&& (++enclave_lost_count)<=MAX_ENCLAVE_LOST_RETRY_TIME ){ CPVEClass::instance().unload_enclave();//unload and reload PvE when enclave lost encountered continue; }else if(ae_ret == AE_SUCCESS){ break; }else{ AESM_DBG_ERROR("fail to generate parition by PvE"); goto final_point; } }while(1); AESM_DBG_TRACE("use parition %d from PvE", (int)enclave_output.selector_id); AESM_DBG_INFO("Connect to server url \"%s\" for endpoint selection", _server_urls.endpoint_url); msg_size = estimate_es_msg1_size(); assert(msg_size>0); msg = static_cast<uint8_t *>(malloc(msg_size)); if(msg == NULL){ AESM_DBG_ERROR("malloc error"); ae_ret = AE_OUT_OF_MEMORY_ERROR; goto final_point; } memset(msg, 0, msg_size); ae_ret = static_cast<ae_error_t>(CPVEClass::instance().gen_es_msg1(msg, msg_size, enclave_output));//Generate EndPoint Selection Msg1 if(ae_ret != AE_SUCCESS){ AESM_DBG_ERROR("ES msg1 generation failed:%d",ae_ret); goto final_point; } AESM_DBG_TRACE("ES msg1 generated"); ae_ret = AESMNetworkEncoding::aesm_send_recv_msg_encoding(_server_urls.endpoint_url, msg, msg_size, resp, resp_size);//Encoding/send/receive/Decoding if(ae_ret != AE_SUCCESS){ AESM_DBG_ERROR("fail to send ES msg1 to backend server:%d",ae_ret); if(OAL_PROXY_SETTING_ASSIST == ae_ret){//when proxy setting assistant required, return directly goto final_point; } if(read_pek(es_info)==AE_SUCCESS){ ae_ret = AE_SUCCESS;//use es_info inside persistent storage and ignore network error } goto final_point; } assert(resp != NULL); AESM_DBG_TRACE("start to process ES msg2"); ae_ret = static_cast<ae_error_t>(CPVEClass::instance().proc_es_msg2(resp, resp_size, es_info.provision_url, provision_ttl, enclave_output.xid, rsa_signature , es_info.pek)); if(AE_SUCCESS != ae_ret){ AESM_DBG_WARN("Fail to process ES msg2 from backend server:%d",ae_ret); goto final_point; } AESM_DBG_TRACE("ES Msg2 decoded successfully, ttl %ds",provision_ttl); ae_ret = verify_signature(es_info, enclave_output.xid, rsa_signature, provision_ttl); if(AE_SUCCESS != ae_ret){ AESM_DBG_WARN("Signature verification in ES Msg2 failed"); goto final_point; } AESM_DBG_TRACE("Signature in ES Msg2 verified"); es_info.aesm_data_type = AESM_DATA_ENDPOINT_SELECTION_INFOS; es_info.aesm_data_version = AESM_DATA_ENDPOINT_SELECTION_VERSION; (void)write_pek(es_info);//ignore file writing error AESM_DBG_TRACE("end point selection succ, provisioning url: %s",es_info.provision_url); final_point: if(msg!=NULL)free(msg); if(resp!=NULL){ AESMNetworkEncoding::aesm_free_response_msg(resp); } return ae_ret; }