static ae_error_t http_network_init(CURL **curl, const char *url, bool is_ocsp) { CURLcode cc = CURLE_OK; UNUSED(is_ocsp); AESM_DBG_TRACE("http init for url %s",url); if(!is_curl_initialized_succ()){ AESM_DBG_ERROR("libcurl not initialized"); return AE_FAILURE;//fatal error that libcurl could not be initialized } std::string url_path = url; uint32_t proxy_type; char proxy_url[MAX_PATH]; EndpointSelectionInfo::instance().get_proxy(proxy_type, proxy_url); *curl = curl_easy_init(); if(!*curl){ AESM_DBG_ERROR("fail to init curl handle"); return AE_FAILURE; } if((cc=curl_easy_setopt(*curl, CURLOPT_URL, url_path.c_str()))!=CURLE_OK){ AESM_DBG_ERROR("fail error code %d in set url %s",(int)cc, url_path.c_str()); curl_easy_cleanup(*curl); return AE_FAILURE; } (void)curl_easy_setopt(*curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); //setting proxy now if(proxy_type == AESM_PROXY_TYPE_DIRECT_ACCESS){ AESM_DBG_TRACE("use no proxy"); (void)curl_easy_setopt(*curl, CURLOPT_NOPROXY , "*"); }else if(proxy_type == AESM_PROXY_TYPE_MANUAL_PROXY){ AESM_DBG_TRACE("use manual proxy %s",proxy_url); (void)curl_easy_setopt(*curl, CURLOPT_PROXY, proxy_url); } return AE_SUCCESS; }
ae_error_t CertificateProvisioningProtocol::SendM3_ReceiveM4 ( /*in */ const upse::Buffer& csrBuffer, /*in */ const upse::Buffer& quoteBuffer, /*out*/ std::list< upse::Buffer >& certificateChainList, /*out*/ platform_info_blob_wrapper_t& piBlobWrapper ) { ae_error_t status = AE_FAILURE; upse::Buffer serializedMsg3; upse::Buffer serializedMsg4; AESM_DBG_TRACE("start to send M3"); do { BREAK_IF_FALSE((m_is_initialized), status, AESM_PSE_PR_BACKEND_NOT_INITIALIZED); BREAK_IF_FALSE( (msg_next_state_M3 == m_nextState), status, AESM_PSE_PR_CALL_ORDER_ERROR); status = msg3_generate(csrBuffer, quoteBuffer, serializedMsg3); BREAK_IF_FAILED_ERR(status, AESM_PSE_PR_BACKEND_MSG3_GENERATE); // BREAK_IF_FAILED(status); AESM_DBG_TRACE("M3 generated"); status = sendReceive(serializedMsg3, serializedMsg4); BREAK_IF_FAILED(status); AESM_DBG_TRACE("start to process M4"); status = msg4_process(serializedMsg4, certificateChainList, piBlobWrapper); BREAK_IF_FAILED(status); AESM_DBG_TRACE("finished M4"); } while (0); m_nextState = msg_next_state_init; return status; }
aesm_error_t AESMLogic::get_launch_token( const uint8_t * mrenclave, uint32_t mrenclave_size, const uint8_t *public_key, uint32_t public_key_size, const uint8_t *se_attributes, uint32_t se_attributes_size, uint8_t * lictoken, uint32_t lictoken_size) { AESM_DBG_INFO("enter function"); CHECK_SERVICE_STATUS; AESMLogicLock lock(_le_mutex); CHECK_SERVICE_STATUS; ae_error_t ret_le = AE_SUCCESS; if (NULL == mrenclave || NULL == public_key || NULL == se_attributes || NULL == lictoken) { //sizes are checked in CLEClass::get_launch_token() AESM_DBG_TRACE("Invalid parameter"); return AESM_PARAMETER_ERROR; } ae_error_t ae_ret = CLEClass::instance().load_enclave(); if(ae_ret == AE_SERVER_NOT_AVAILABLE) { AESM_LOG_ERROR("%s", g_event_string_table[SGX_EVENT_SERVICE_UNAVAILABLE]); AESM_DBG_FATAL("LE not loaded due to AE_SERVER_NOT_AVAILABLE, possible SGX Env Not Ready"); return AESM_NO_DEVICE_ERROR; } else if(AE_FAILED(ae_ret)) { AESM_DBG_ERROR("LE not loaded:%d", ae_ret); return AESM_UNEXPECTED_ERROR; } ret_le = static_cast<ae_error_t>(CLEClass::instance().get_launch_token( const_cast<uint8_t *>(mrenclave), mrenclave_size, const_cast<uint8_t *>(public_key), public_key_size, const_cast<uint8_t *>(se_attributes), se_attributes_size, lictoken, lictoken_size)); switch (ret_le) { case AE_SUCCESS: return AESM_SUCCESS; case LE_INVALID_PARAMETER: AESM_DBG_TRACE("Invalid parameter"); return AESM_PARAMETER_ERROR; case LE_INVALID_ATTRIBUTE: case LE_INVALID_PRIVILEGE_ERROR: AESM_DBG_TRACE("Launch token error"); return AESM_GET_LICENSETOKEN_ERROR; case LE_WHITELIST_UNINITIALIZED_ERROR: AESM_DBG_TRACE("LE whitelist uninitialized error"); return AESM_UNEXPECTED_ERROR; default: AESM_DBG_WARN("unexpeted error %d", ret_le); return AESM_UNEXPECTED_ERROR; } }
// Must be called when AESM starts ae_error_t AESMLogic::service_start() { AESM_PROFILE_INIT; ae_error_t ae_ret = AE_SUCCESS; AESM_LOG_INIT(); //ippInit();//no ippInit available for c version ipp AESM_DBG_INFO("aesm service is starting"); ae_ret = CLEClass::instance().load_enclave(); if(AE_SUCCESS != ae_ret) { AESM_DBG_INFO("fail to load LE: %d", ae_ret); AESM_LOG_FATAL("%s", g_event_string_table[SGX_EVENT_SERVICE_UNAVAILABLE]); return ae_ret; } aesm_thread_t qe_thread=NULL; ae_error_t aesm_ret1 = aesm_create_thread(thread_to_load_qe, 0,&qe_thread); if(AE_SUCCESS != aesm_ret1 ){ AESM_DBG_WARN("Fail to create thread to preload QE:%d",aesm_ret1); }else{ (void)aesm_free_thread(qe_thread);//release thread handle to free memory } AESM_DBG_TRACE("aesm service is started"); return AE_SUCCESS; }
// // return values // NEED_PSE_UPDATE: pse out of date, cert matches pse // SUCCESS: have new cert // PSE_CERT_PROVISIONING_ATTESTATION_FAILURE_NEED_EPID_UPDATE: // PSE_CERT_PROVISIONING_ATTESTATION_FAILURE_MIGHT_NEED_EPID_UPDATE: // SIMPLE_PSE_CERT_PROVISIONING_ERROR: internal error during cert provisioning // SIMPLE_EPID_PROVISION_ERROR: internal error during epid provisioning during cert provisioning // ae_error_t PlatformInfoLogic::pse_cert_provisioning_helper(const platform_info_blob_wrapper_t* p_platform_info_blob) { AESM_DBG_TRACE("enter fun"); ae_error_t status = AESM_NPC_DONT_NEED_PSEP; ae_error_t npcStatus = need_pse_cert_provisioning(); switch (npcStatus) { default: { assert(false); break; } case AESM_NPC_DONT_NEED_PSEP: { status = AESM_PCP_NEED_PSE_UPDATE; break; } case AESM_NPC_NO_PSE_CERT: { platform_info_blob_wrapper_t new_platform_info_blob; new_platform_info_blob.valid_info_blob = 0; AESM_DBG_INFO("helper; redo certificate provisioning"); ae_error_t cpStatus = CPSEPRClass::instance().certificate_provisioning(&new_platform_info_blob); SGX_DBGPRINT_ONE_STRING_TWO_INTS_CREATE_SESSION("cpStatus = ", cpStatus, cpStatus); switch (cpStatus) { case AE_SUCCESS: case OAL_PROXY_SETTING_ASSIST: case PSW_UPDATE_REQUIRED: case AESM_AE_OUT_OF_EPC: case OAL_NETWORK_UNAVAILABLE_ERROR: { status = cpStatus; break; } case AESM_CP_ATTESTATION_FAILURE: { status = attestation_failure_in_pse_cert_provisioning(p_platform_info_blob); break; } default: { status = AESM_PCP_SIMPLE_PSE_CERT_PROVISIONING_ERROR; break; } } break; } } SGX_DBGPRINT_ONE_STRING_TWO_INTS_CREATE_SESSION(__FUNCTION__" returning ", status, status); return status; }
aesm_error_t AESMLogic::white_list_register( const uint8_t *white_list_cert, uint32_t white_list_cert_size) { AESM_DBG_INFO("enter function"); CHECK_SERVICE_STATUS; AESMLogicLock lock(_le_mutex); CHECK_SERVICE_STATUS; ae_error_t ret_le = AE_SUCCESS; if (NULL == white_list_cert||0==white_list_cert_size){ AESM_DBG_TRACE("Invalid parameter"); return AESM_PARAMETER_ERROR; } ae_error_t ae_ret = CLEClass::instance().load_enclave(); if(ae_ret == AE_SERVER_NOT_AVAILABLE) { AESM_DBG_WARN("LE not loaded due to AE_SERVER_NOT_AVAILABLE, possible SGX Env Not Ready"); ret_le = save_unverified_white_list(white_list_cert, white_list_cert_size); } else if(AE_FAILED(ae_ret)) { AESM_DBG_ERROR("LE not loaded:%d", ae_ret); return AESM_UNEXPECTED_ERROR; }else{ ret_le = static_cast<ae_error_t>(CLEClass::instance().white_list_register( white_list_cert, white_list_cert_size)); } switch (ret_le) { case AE_SUCCESS: return AESM_SUCCESS; case LE_INVALID_PARAMETER: AESM_DBG_TRACE("Invalid parameter"); return AESM_PARAMETER_ERROR; case LE_INVALID_ATTRIBUTE: AESM_DBG_TRACE("Launch token error"); return AESM_GET_LICENSETOKEN_ERROR; default: AESM_DBG_WARN("unexpeted error %d", ret_le); return AESM_UNEXPECTED_ERROR; } }
//function to decode proxy type from string to integer value static uint32_t read_aesm_proxy_type(const char *string, uint32_t len) { uint32_t i; for(i=0;i<NUM_PROXY_TYPE;++i){ if(strncasecmp(proxy_type_name[i],string,len)==0){ return i; } } AESM_DBG_TRACE("Invalid proxy type %.*s",len,string); return (uint32_t)NUM_PROXY_TYPE; }
ae_error_t AESMLogic::set_psvn(uint16_t prod_id, uint16_t isv_svn, sgx_cpu_svn_t cpu_svn) { if(prod_id == QE_PROD_ID){ if(_is_qe_psvn_set){ if(0!=memcmp(&_qe_psvn.isv_svn, &isv_svn, sizeof(isv_svn))|| 0!=memcmp(&_qe_psvn.cpu_svn, &cpu_svn, sizeof(sgx_cpu_svn_t))){ AESM_DBG_ERROR("PSVN unmatched for QE/PVE"); return AE_PSVN_UNMATCHED_ERROR; } }else{ if(0!=memcpy_s(&_qe_psvn.isv_svn, sizeof(_qe_psvn.isv_svn), &isv_svn, sizeof(isv_svn))|| 0!=memcpy_s(&_qe_psvn.cpu_svn, sizeof(_qe_psvn.cpu_svn), &cpu_svn, sizeof(sgx_cpu_svn_t))){ AESM_DBG_ERROR("memcpy failed"); return AE_FAILURE; } AESM_DBG_TRACE("get QE or PvE isv_svn=%d",(int)isv_svn); _is_qe_psvn_set = true; return AE_SUCCESS; } }else if(prod_id == PSE_PROD_ID){ if(_is_pse_psvn_set){ if(0!=memcmp(&_pse_psvn.isv_svn, &isv_svn, sizeof(isv_svn))|| 0!=memcmp(&_pse_psvn.cpu_svn, &cpu_svn, sizeof(sgx_cpu_svn_t))){ AESM_DBG_ERROR("PSVN unmatched for PSE"); return AE_PSVN_UNMATCHED_ERROR; } }else{ if(0!=memcpy_s(&_pse_psvn.isv_svn, sizeof(_pse_psvn.isv_svn), &isv_svn, sizeof(isv_svn))|| 0!=memcpy_s(&_pse_psvn.cpu_svn, sizeof(_pse_psvn.cpu_svn), &cpu_svn, sizeof(sgx_cpu_svn_t))){ AESM_DBG_ERROR("memcpy failed"); return AE_FAILURE; } AESM_DBG_TRACE("get PSE isv_svn=%d", (int)isv_svn); _is_pse_psvn_set = true; return AE_SUCCESS; } } return AE_SUCCESS; }
static ae_error_t thread_to_load_qe(aesm_thread_arg_type_t arg) { epid_blob_with_cur_psvn_t epid_data; ae_error_t ae_ret = AE_FAILURE; UNUSED(arg); AESM_DBG_TRACE("start to load qe"); memset(&epid_data, 0, sizeof(epid_data)); AESMLogicLock lock(AESMLogic::_qe_pve_mutex); if((ae_ret = EPIDBlob::instance().read(epid_data)) == AE_SUCCESS) { AESM_DBG_TRACE("EPID blob is read successfully, loading QE ..."); ae_ret = CQEClass::instance().load_enclave(); if(AE_SUCCESS != ae_ret) { AESM_DBG_WARN("fail to load QE: %d", ae_ret); }else{ AESM_DBG_TRACE("QE loaded successfully"); } } AESM_DBG_TRACE("QE Thread finished succ"); return AE_SUCCESS; }
//********************************************************************* // Main engine routine for Certificate Chain Provisioning //********************************************************************* ae_error_t certificate_chain_provisioning(const endpoint_selection_infos_t& es_info, platform_info_blob_wrapper_t* pib_wrapper) { ae_error_t status = AE_FAILURE; AESM_DBG_TRACE("enter fun"); try { do { status = do_certificate_chain_provisioning(es_info, pib_wrapper); if (status == PSE_PR_ENCLAVE_LOST_ERROR) { // // went to sleep while in enclave // in this case (beginning of flow), we should just retry, after first destroying and then reloading // note that this code gets significantly more complicated if the PSE-pr ever becomes multi-threaded // for (unsigned rcount = 0; rcount < PSEPR_LOST_ENCLAVE_RETRY_COUNT; rcount++) { CPSEPRClass::instance().unload_enclave(); if (0 != CPSEPRClass::instance().load_enclave()) { status = AE_FAILURE; break; } SaveEnclaveID(CPSEPRClass::instance().GetEID()); status = do_certificate_chain_provisioning(es_info, pib_wrapper); if (status != PSE_PR_ENCLAVE_LOST_ERROR) break; } } BREAK_IF_FAILED(status); status = AE_SUCCESS; } while (0); } catch (...) { status = AESM_PSE_PR_EXCEPTION; } SGX_DBGPRINT_PRINT_FUNCTION_AND_RETURNVAL(__FUNCTION__, status); SGX_DBGPRINT_PRINT_ANSI_STRING("End Certificate Chain Provisioning"); return status; }
// // return values // AESM_NPC_DONT_NEED_PSEP: cert present, ltp blob present and current pse version at least matches // pse version in cert - may also be latest; default // AESM_NPC_NO_PSE_CERT: no cert or no ltp blob ae_error_t PlatformInfoLogic::need_pse_cert_provisioning() { AESM_DBG_TRACE("enter fun"); ae_error_t status = AESM_NPC_DONT_NEED_PSEP; if (Helper::noPseCert() || Helper::noLtpBlob()) // long-term pairing blob holds verifier/pse private key { status = AESM_NPC_NO_PSE_CERT; // break this up in order to distinguish between no cert and no ltp blob? } SGX_DBGPRINT_ONE_STRING_TWO_INTS_CREATE_SESSION(__FUNCTION__" returning ", status, status); return status; }
ae_error_t upse_long_term_pairing(sgx_enclave_id_t enclave_id, bool* new_pairing) { ae_error_t status = AE_SUCCESS; AESM_DBG_TRACE("enter fun"); SaveEnclaveID(enclave_id); // Save the enclave ID for use in ECALLs do { status = create_sigma_long_term_pairing(new_pairing); BREAK_IF_FAILED(status); } while (0); return status; }
ae_error_t CPSEPRClass::long_term_pairing(bool* p_new_pairing) { ae_error_t status = AE_FAILURE; AESM_DBG_TRACE("enter fun"); do { if ((status = CPSEPRClass::instance().load_enclave()) != AE_SUCCESS) break; status = upse_long_term_pairing(m_enclave_id, p_new_pairing); } while (0); CPSEPRClass::instance().unload_enclave(); return status; }
ae_error_t CPSEPRClass::certificate_provisioning(platform_info_blob_wrapper_t* pib_wrapper) { ae_error_t status = AE_FAILURE; AESM_DBG_TRACE("enter fun"); do { if ((status = CPSEPRClass::instance().load_enclave()) != AE_SUCCESS) break; status = upse_certificate_provisioning(m_enclave_id, pib_wrapper); } while (0); CPSEPRClass::instance().unload_enclave(); return status; }
ae_error_t upse_certificate_provisioning(sgx_enclave_id_t enclave_id, platform_info_blob_wrapper_t* pib_wrapper) { ae_error_t status = AE_SUCCESS; AESM_DBG_TRACE("enter fun"); SaveEnclaveID(enclave_id); // Save the enclave ID for use in ECALLs do { endpoint_selection_infos_t es_info; if(AE_SUCCESS == (status = (ae_error_t)AESMLogic::endpoint_selection(es_info)) ) { status = certificate_chain_provisioning(es_info, pib_wrapper); } BREAK_IF_FAILED(status); } while (0); return status; }
// // get_sgx_gid // // get sgx gid from epid blob, specifically from stored group cert in epid blob // // inputs // // pgid: pointer to gid // // outputs // // *pgid: gid // status // ae_error_t EPIDBlob::get_sgx_gid(uint32_t* pgid) { ae_error_t aesm_result = AE_SUCCESS; epid_blob_with_cur_psvn_t epid_blob; sgx_sealed_data_t *sealed_epid = reinterpret_cast<sgx_sealed_data_t *>(epid_blob.trusted_epid_blob); if (NULL != pgid) { // // get the epid blob // aesm_result = this->read(epid_blob); if (AE_SUCCESS == aesm_result) { // // get the gid // uint32_t plain_text_offset = sealed_epid->plain_text_offset; se_plaintext_epid_data_t* plain_text = reinterpret_cast<se_plaintext_epid_data_t *>(epid_blob.trusted_epid_blob + sizeof(sgx_sealed_data_t) + plain_text_offset); if(memcpy_s(pgid, sizeof(*pgid), &plain_text->epid_group_cert.gid, sizeof(plain_text->epid_group_cert.gid))) //read gid from EPID Data blob { AESM_DBG_ERROR("memcpy_s failed"); aesm_result = AE_FAILURE; } // // return little-endian // *pgid = _htonl(*pgid); AESM_DBG_TRACE(": get gid %d from epid blob", *pgid); } } else { aesm_result = AE_INVALID_PARAMETER; } return aesm_result; }
tlv_status_t TLVsMsg::init_from_tlv_msg(const tlv_msg_t& tlv_msg) { clear(); msg.msg_size = tlv_msg.msg_size; msg.msg_buf = (uint8_t *)malloc(msg.msg_size); if(msg.msg_buf == NULL){ msg.msg_size = 0; AESM_DBG_ERROR("malloc failed"); return TLV_OUT_OF_MEMORY_ERROR; } if(memcpy_s(msg.msg_buf, msg.msg_size, tlv_msg.msg_buf, tlv_msg.msg_size)!=0){ AESM_DBG_ERROR("memcpy failed"); return TLV_UNKNOWN_ERROR; } tlv_msg_t tlv_tmp = msg; tlv_info_t one_info; tlv_info_t *new_info = NULL; while(tlv_tmp.msg_size>0){ if(decode_one_tlv(tlv_tmp, &one_info)){ tlv_status_t ret = create_new_info(new_info); if(ret != TLV_SUCCESS) return ret; if(memcpy_s(new_info, sizeof(*new_info), &one_info, sizeof(one_info))!=0){ AESM_DBG_ERROR("memcpy failed"); return TLV_UNKNOWN_ERROR; } #ifdef DBG_LOG char dbg_str[256]; aesm_dbg_format_hex(new_info->payload, new_info->size, dbg_str, 256); AESM_DBG_TRACE("Decode One TLV: type (tlv %d), size %u, version %d, payload:%s",new_info->type, new_info->size, (int)new_info->version,dbg_str); #endif }else{ return TLV_INVALID_MSG_ERROR; } } return TLV_SUCCESS; }
/* Assuming buffer size is checked before calling this function, and get_quote in QE will also check size. */ aesm_error_t QEAESMLogic::get_quote(const uint8_t *report, uint32_t quote_type, const uint8_t *spid, const uint8_t *nonce, const uint8_t *sigrl, uint32_t sigrl_size, uint8_t *qe_report, uint8_t *quote, uint32_t buf_size) { epid_blob_with_cur_psvn_t epid_data; uint32_t ae_ret = AE_SUCCESS; aesm_error_t aesm_result = AESM_UNEXPECTED_ERROR; EPIDBlob& epid_blob = EPIDBlob::instance(); AESM_PROFILE_FUN; memset(&epid_data, 0, sizeof(epid_data)); AESM_DBG_TRACE("start to read and verify epid blob"); if((ae_ret = epid_blob.read(epid_data))!=AE_SUCCESS){ if((aesm_result = PvEAESMLogic::provision(false, THREAD_TIMEOUT))!=AESM_SUCCESS){ AESM_DBG_ERROR("pve provision failed:%d", aesm_result); goto CLEANUP; } } if(CQEClass::instance().load_enclave()) { AESM_DBG_ERROR("load QE failed"); aesm_result = AESM_UNEXPECTED_ERROR; goto CLEANUP; } AESM_DBG_TRACE("start to get quote"); ae_ret = CQEClass::instance().get_quote(epid_data.trusted_epid_blob, SGX_TRUSTED_EPID_BLOB_SIZE, reinterpret_cast<const sgx_report_t *>(report), static_cast<sgx_quote_sign_type_t>(quote_type), reinterpret_cast<const sgx_spid_t *>(spid), reinterpret_cast<const sgx_quote_nonce_t *>(nonce), sigrl, sigrl_size, reinterpret_cast<sgx_report_t *>(qe_report), quote, buf_size); if(ae_ret != AE_SUCCESS) { AESM_DBG_TRACE("get_quote failed:%d",ae_ret); if(ae_ret == QE_EPIDBLOB_ERROR) aesm_result = AESM_EPIDBLOB_ERROR; else if(ae_ret == QE_PARAMETER_ERROR) aesm_result = AESM_PARAMETER_ERROR; else if(ae_ret == QE_REVOKED_ERROR) aesm_result = AESM_EPID_REVOKED_ERROR; else aesm_result = AESM_UNEXPECTED_ERROR; goto CLEANUP; } AESM_DBG_TRACE("get quote succ"); aesm_result = AESM_SUCCESS; CLEANUP: return aesm_result; }
//Function to decode ProvMsg4 and generate epid data blob uint32_t CPVEClass::proc_prov_msg4( bool use_ek2_in_input, const uint8_t ek2[SK_SIZE], const uint8_t* msg4, uint32_t msg4_size, uint8_t* data_blob, uint32_t blob_size) { ae_error_t ret = AE_SUCCESS; uint8_t local_ek2[SK_SIZE]; uint8_t *decoded_msg4 = NULL; const provision_response_header_t *msg4_header = reinterpret_cast<const provision_response_header_t *>(msg4); if(msg4_size < PROVISION_RESPONSE_HEADER_SIZE){ AESM_DBG_ERROR("invalid msg4 size"); return PVE_MSG_ERROR; } if(blob_size != HARD_CODED_EPID_BLOB_SIZE){ AESM_DBG_FATAL("invalid input epid blob size"); return PVE_PARAMETER_ERROR; } ret = check_prov_msg4_header(msg4_header, msg4_size); if( AE_SUCCESS != ret){ AESM_DBG_ERROR("Invalid ProvMsg4 Header:%d",ret); return ret; } ret = check_epid_pve_pg_status_before_mac_verification(msg4_header); if( AE_SUCCESS != ret){ AESM_DBG_ERROR("Backend return failure in ProvMsg4 Header:%d",ret); return ret; } do{ TLVsMsg tlvs_msg4; tlv_status_t tlv_status; tlv_status = tlvs_msg4.init_from_buffer(msg4+static_cast<uint32_t>(PROVISION_RESPONSE_HEADER_SIZE), msg4_size - static_cast<uint32_t>(PROVISION_RESPONSE_HEADER_SIZE)); ret = tlv_error_2_pve_error(tlv_status); if(AE_SUCCESS!=ret){ AESM_DBG_ERROR("fail to decode ProvMsg4:%d",tlv_status); break; } ret = msg4_integrity_checking(tlvs_msg4); if(AE_SUCCESS != ret){ AESM_DBG_ERROR("ProvMsg4 integrity checking error:%d",ret); break; } AESM_DBG_TRACE("ProvMsg4 decoded"); if(!use_ek2_in_input){ //we need generate ek2 prov_get_ek2_input_t ek2_input; if(memcpy_s(ek2_input.nonce, NONCE_SIZE, MSG4_TOP_FIELD_NONCE.payload, NONCE_SIZE)!=0){ AESM_DBG_ERROR("fail in memcpy"); ret = PVE_UNEXPECTED_ERROR; break; } if(memcpy_s(ek2_input.xid, XID_SIZE, msg4_header->xid, XID_SIZE)!=0){ AESM_DBG_ERROR("fail in memcpy"); ret = PVE_UNEXPECTED_ERROR; break; } //call PvE to get EK2 se_static_assert(SK_SIZE == sizeof(prov_get_ek2_output_t)); ret = (ae_error_t)get_ek2(&ek2_input, reinterpret_cast<prov_get_ek2_output_t *>(local_ek2)); if(AE_SUCCESS != ret){ AESM_DBG_ERROR("fail to get EK2:%d",ret); break; } }else{//reuse ek2 generated in processing ProvMsg2 if(0!=memcpy_s(local_ek2, sizeof(local_ek2), ek2, SK_SIZE)){ AESM_DBG_ERROR("fail in memcpy"); ret = PVE_UNEXPECTED_ERROR; break; } } se_static_assert(SK_SIZE==sizeof(sgx_aes_gcm_128bit_key_t)); tlv_msg_t field1 = block_cipher_tlv_get_encrypted_text(MSG4_TOP_FIELD_DATA); decoded_msg4 = reinterpret_cast<uint8_t *>(malloc(field1.msg_size)); if(NULL == decoded_msg4){ AESM_DBG_ERROR("malloc error"); ret = AE_OUT_OF_MEMORY_ERROR; break; } sgx_status_t sgx_status = sgx_rijndael128GCM_decrypt(reinterpret_cast<const sgx_aes_gcm_128bit_key_t *>(local_ek2), field1.msg_buf, field1.msg_size, decoded_msg4, reinterpret_cast<uint8_t *>(block_cipher_tlv_get_iv(MSG4_TOP_FIELD_DATA)), IV_SIZE, reinterpret_cast<const uint8_t *>(msg4_header), PROVISION_RESPONSE_HEADER_SIZE, reinterpret_cast<const sgx_aes_gcm_128bit_tag_t *>(MSG4_TOP_FIELD_MAC.payload)); if(SGX_ERROR_MAC_MISMATCH == sgx_status){ AESM_DBG_ERROR("fail to decrypt ProvMsg4 by EK2"); ret = PVE_INTEGRITY_CHECK_ERROR; break; } if( AE_SUCCESS != (ret = sgx_error_to_ae_error(sgx_status))){ AESM_DBG_ERROR("error in decrypting ProvMsg4:%d",sgx_status); break; } AESM_DBG_TRACE("ProvMsg4 decrypted by EK2 successfully"); ret = check_epid_pve_pg_status_after_mac_verification(msg4_header); if(AE_SUCCESS != ret){ AESM_DBG_ERROR("Backend reported error passed MAC verification:%d",ret); break; } TLVsMsg tlvs_field1; tlv_status = tlvs_field1.init_from_buffer(decoded_msg4, field1.msg_size); ret = tlv_error_2_pve_error(tlv_status); if(AE_SUCCESS != ret){ AESM_DBG_ERROR("ProvMsg4 Field2.1 decoding failed:%d",tlv_status); break; } ret = msg4_field1_msg_checking(tlvs_field1); if( AE_SUCCESS != ret){ AESM_DBG_ERROR("ProvMsg4 Field2.1 invalid:%d",ret); break; } proc_prov_msg4_input_t msg4_input; if(sizeof(proc_prov_msg4_output_t)!=SGX_TRUSTED_EPID_BLOB_SIZE){ AESM_DBG_FATAL("Trusted ProvMsg4 output buffer size error"); ret = PVE_UNEXPECTED_ERROR; break; } tlv_msg_t tcb_data = block_cipher_tlv_get_encrypted_text(MSG4_FIELD1_ENC_TCB); tlv_msg_t Axf_data = block_cipher_tlv_get_encrypted_text(MSG4_FIELD1_ENC_Axf); if(0!=memcpy_s(&msg4_input.group_cert, sizeof(msg4_input.group_cert), MSG4_FIELD1_GROUP_CERT.payload, MSG4_FIELD1_GROUP_CERT.size)|| 0!=memcpy_s(&msg4_input.equivalent_psvn, sizeof(psvn_t), device_id_tlv_get_psvn(MSG4_FIELD1_DEVICE_ID), sizeof(psvn_t))|| 0!=memcpy_s(&msg4_input.fmsp, sizeof(fmsp_t), device_id_tlv_get_fmsp(MSG4_FIELD1_DEVICE_ID), sizeof(fmsp_t))|| 0!=memcpy_s(&msg4_input.tcb_iv, IV_SIZE, block_cipher_tlv_get_iv(MSG4_FIELD1_ENC_TCB), IV_SIZE)|| 0!=memcpy_s(&msg4_input.encrypted_tcb, SK_SIZE, tcb_data.msg_buf, tcb_data.msg_size)|| 0!=memcpy_s(&msg4_input.tcb_mac, MAC_SIZE, MSG4_FIELD1_MAC_TCB.payload, MSG4_FIELD1_MAC_TCB.size)|| 0!=memcpy_s(&msg4_input.member_credential_iv, IV_SIZE, block_cipher_tlv_get_iv(MSG4_FIELD1_ENC_Axf), IV_SIZE)|| 0!=memcpy_s(&msg4_input.encrypted_member_credential, HARD_CODED_EPID_MEMBER_WITH_ESCROW_TLV_SIZE, Axf_data.msg_buf, Axf_data.msg_size)|| 0!=memcpy_s(&msg4_input.member_credential_mac, MAC_SIZE, MSG4_FIELD1_MAC_Axf.payload, MSG4_FIELD1_MAC_Axf.size)){ AESM_DBG_ERROR("memcpy error"); ret = PVE_UNEXPECTED_ERROR; break; } ret = (ae_error_t)proc_prov_msg4_data(&msg4_input, reinterpret_cast<proc_prov_msg4_output_t *>(data_blob)); AESM_DBG_TRACE("PvE return %d in Process ProvMsg4",ret); }while(0); if(decoded_msg4)free(decoded_msg4); return ret; }
//Function to decode ProvMsg4 and generate epid data blob uint32_t CPVEClass::proc_prov_msg4( const pve_data_t &data, const uint8_t *msg4, uint32_t msg4_size, uint8_t *data_blob, uint32_t blob_size) { ae_error_t ret = AE_SUCCESS; uint8_t local_ek2[SK_SIZE]; uint8_t *decoded_msg4 = NULL; uint8_t temp[XID_SIZE+NONCE_SIZE]; sgx_status_t sgx_status; const provision_response_header_t *msg4_header = reinterpret_cast<const provision_response_header_t *>(msg4); if(msg4_size < PROVISION_RESPONSE_HEADER_SIZE) { AESM_DBG_ERROR("invalid msg4 size"); return PVE_MSG_ERROR; } if (blob_size != SGX_TRUSTED_EPID_BLOB_SIZE_PAK) { AESM_DBG_FATAL("invalid input epid blob size"); return PVE_PARAMETER_ERROR; } ret = check_prov_msg4_header(msg4_header, msg4_size); if( AE_SUCCESS != ret) { AESM_DBG_ERROR("Invalid ProvMsg4 Header:(ae%d)",ret); return ret; } if(0!=memcmp(msg4_header->xid, data.xid, XID_SIZE)) { AESM_DBG_ERROR("Invalid XID in msg4 header"); return PVE_MSG_ERROR; } ret = check_epid_pve_pg_status_before_mac_verification(msg4_header); if( AE_SUCCESS != ret) { AESM_DBG_ERROR("Backend return failure in ProvMsg4 Header:(ae%d)",ret); return ret; } do { TLVsMsg tlvs_msg4; uint8_t aad[PROVISION_RESPONSE_HEADER_SIZE+NONCE_SIZE]; tlv_status_t tlv_status; tlv_status = tlvs_msg4.init_from_buffer(msg4+static_cast<uint32_t>(PROVISION_RESPONSE_HEADER_SIZE), msg4_size - static_cast<uint32_t>(PROVISION_RESPONSE_HEADER_SIZE)); ret = tlv_error_2_pve_error(tlv_status); if(AE_SUCCESS!=ret) { AESM_DBG_ERROR("fail to decode ProvMsg4:(ae%d)",ret); break; } ret = msg4_integrity_checking(tlvs_msg4); if(AE_SUCCESS != ret) { AESM_DBG_ERROR("ProvMsg4 integrity checking error:(ae%d)",ret); break; } AESM_DBG_TRACE("ProvMsg4 decoded"); se_static_assert(sizeof(sgx_cmac_128bit_key_t)==SK_SIZE); if(0!=memcpy_s(temp,sizeof(temp), data.xid, XID_SIZE)|| 0!=memcpy_s(temp+XID_SIZE, sizeof(temp)-XID_SIZE, MSG4_TOP_FIELD_NONCE.payload, NONCE_SIZE)) { AESM_DBG_ERROR("Fail in memcpy"); ret = AE_FAILURE; break; } if((sgx_status=sgx_rijndael128_cmac_msg(reinterpret_cast<const sgx_cmac_128bit_key_t *>(data.sk), temp, XID_SIZE+NONCE_SIZE, reinterpret_cast<sgx_cmac_128bit_tag_t *>(local_ek2)))!=SGX_SUCCESS) { AESM_DBG_ERROR("Fail to generate ek2:(sgx0x%x)",sgx_status); ret = AE_FAILURE; break; } se_static_assert(SK_SIZE==sizeof(sgx_aes_gcm_128bit_key_t)); tlv_msg_t field1 = block_cipher_tlv_get_encrypted_text(MSG4_TOP_FIELD_DATA); decoded_msg4 = reinterpret_cast<uint8_t *>(malloc(field1.msg_size)); if(NULL == decoded_msg4) { AESM_DBG_ERROR("malloc error"); ret = AE_OUT_OF_MEMORY_ERROR; break; } if (memcpy_s(aad, sizeof(aad), msg4_header, PROVISION_RESPONSE_HEADER_SIZE) != 0 || memcpy_s(aad + PROVISION_RESPONSE_HEADER_SIZE, sizeof(aad)-PROVISION_RESPONSE_HEADER_SIZE, MSG4_TOP_FIELD_NONCE.payload, MSG4_TOP_FIELD_NONCE.size) != 0) { AESM_DBG_ERROR("memcpy failure"); ret = AE_FAILURE; break; } sgx_status_t sgx_status = sgx_rijndael128GCM_decrypt(reinterpret_cast<const sgx_aes_gcm_128bit_key_t *>(local_ek2), field1.msg_buf, field1.msg_size, decoded_msg4, reinterpret_cast<uint8_t *>(block_cipher_tlv_get_iv(MSG4_TOP_FIELD_DATA)), IV_SIZE, aad, sizeof(aad), reinterpret_cast<const sgx_aes_gcm_128bit_tag_t *>(MSG4_TOP_FIELD_MAC.payload)); if(SGX_ERROR_MAC_MISMATCH == sgx_status) { AESM_DBG_ERROR("fail to decrypt ProvMsg4 by EK2 (sgx0x%x)",sgx_status); ret = PVE_INTEGRITY_CHECK_ERROR; break; } if( AE_SUCCESS != (ret = sgx_error_to_ae_error(sgx_status))) { AESM_DBG_ERROR("error in decrypting ProvMsg4:(sgx0x%x)",sgx_status); break; } AESM_DBG_TRACE("ProvMsg4 decrypted by EK2 successfully"); ret = check_epid_pve_pg_status_after_mac_verification(msg4_header); if(AE_SUCCESS != ret) { AESM_DBG_ERROR("Backend reported error passed MAC verification:(ae%d)",ret); break; } TLVsMsg tlvs_field1; tlv_status = tlvs_field1.init_from_buffer(decoded_msg4, field1.msg_size); ret = tlv_error_2_pve_error(tlv_status); if(AE_SUCCESS != ret) { AESM_DBG_ERROR("ProvMsg4 Field2.1 decoding failed:(ae%d)",ret); break; } ret = msg4_field1_msg_checking(tlvs_field1); if( AE_SUCCESS != ret) { AESM_DBG_ERROR("ProvMsg4 Field2.1 invalid:(ae%d)",ret); break; } proc_prov_msg4_input_t msg4_input; tlv_msg_t Axf_data = block_cipher_tlv_get_encrypted_text(MSG4_FIELD1_ENC_Axf); if(0!=memcpy_s(&msg4_input.group_cert, sizeof(msg4_input.group_cert), MSG4_FIELD1_GROUP_CERT.payload, MSG4_FIELD1_GROUP_CERT.size)|| 0!=memcpy_s(&msg4_input.n2, NONCE_2_SIZE, MSG4_FIELD1_Nonce2.payload, MSG4_FIELD1_Nonce2.size) || 0!=memcpy_s(&msg4_input.equivalent_psvn, sizeof(psvn_t), platform_info_tlv_get_psvn(MSG4_FIELD1_PLATFORM_INFO), sizeof(psvn_t))|| 0!=memcpy_s(&msg4_input.fmsp, sizeof(fmsp_t), platform_info_tlv_get_fmsp(MSG4_FIELD1_PLATFORM_INFO), sizeof(fmsp_t))|| 0!=memcpy_s(&msg4_input.member_credential_iv, IV_SIZE, block_cipher_tlv_get_iv(MSG4_FIELD1_ENC_Axf), IV_SIZE)|| 0!=memcpy_s(&msg4_input.encrypted_member_credential, HARD_CODED_EPID_MEMBER_WITH_ESCROW_TLV_SIZE, Axf_data.msg_buf, Axf_data.msg_size)|| 0!=memcpy_s(&msg4_input.member_credential_mac, MAC_SIZE, MSG4_FIELD1_MAC_Axf.payload, MSG4_FIELD1_MAC_Axf.size)) { AESM_DBG_ERROR("memcpy error"); ret = PVE_UNEXPECTED_ERROR; break; } if (AE_SUCCESS != (ret =XEGDBlob::instance().read(msg4_input.xegb))) { AESM_DBG_ERROR("Fail to read extend epid blob info (ae%d)",ret); return ret; } ret = CPVEClass::instance().load_enclave();//Load PvE enclave now if( ret != AE_SUCCESS) { AESM_DBG_ERROR("Fail to load PvE enclave:(ae%d)\n",ret); break; } ret = (ae_error_t)proc_prov_msg4_data(&msg4_input, reinterpret_cast<proc_prov_msg4_output_t *>(data_blob)); AESM_DBG_TRACE("PvE return (ae%d) in Process ProvMsg4",ret); } while(0); if(decoded_msg4)free(decoded_msg4); return ret; }
//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; }
//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; }
static ae_error_t http_network_send_data(CURL *curl, const char *req_msg, uint32_t msg_size, char **resp_msg, uint32_t& resp_size, http_methods_t method, bool is_ocsp) { AESM_DBG_TRACE("send data method=%d",method); struct curl_slist *headers=NULL; struct curl_slist *tmp=NULL; ae_error_t ae_ret = AE_SUCCESS; CURLcode cc=CURLE_OK; int num_bytes = 0; if(is_ocsp){ tmp = curl_slist_append(headers, "Accept: application/ocsp-response"); if(tmp==NULL){ AESM_DBG_ERROR("fail in add accept ocsp-response header"); ae_ret = AE_FAILURE; goto fini; } headers = tmp; tmp = curl_slist_append(headers, "Content-Type: application/ocsp-request"); if(tmp == NULL){ AESM_DBG_ERROR("fail in add content type ocsp-request"); ae_ret = AE_FAILURE; goto fini; } headers=tmp; AESM_DBG_TRACE("ocsp request"); } char buf[50]; num_bytes = snprintf(buf,sizeof(buf), "Content-Length: %u", (unsigned int)msg_size); if(num_bytes<0 || num_bytes>=sizeof(buf)){ AESM_DBG_ERROR("fail to prepare string Content-Length"); ae_ret = AE_FAILURE; goto fini; } tmp = curl_slist_append(headers, buf); if(tmp == NULL){ AESM_DBG_ERROR("fail to add content-length header"); ae_ret = AE_FAILURE; goto fini; } headers=tmp; if((cc=curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers))!=CURLE_OK){ AESM_DBG_ERROR("fail to set http header:%d",(int)cc); ae_ret = AE_FAILURE; goto fini; } if(method == POST){ if((cc=curl_easy_setopt(curl, CURLOPT_POSTFIELDS, req_msg))!=CURLE_OK){ AESM_DBG_ERROR("fail to set POST fields:%d",(int)cc); ae_ret = AE_FAILURE; goto fini; } if((cc=curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, msg_size))!=CURLE_OK){ AESM_DBG_ERROR("fail to set POST fields size:%d",(int)cc); ae_ret = AE_FAILURE; goto fini; } } if((cc=curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback))!=CURLE_OK){ AESM_DBG_ERROR("Fail to set callback function:%d",(int)cc); ae_ret = AE_FAILURE; goto fini; } network_malloc_info_t malloc_info; malloc_info.base=NULL; malloc_info.size = 0; if((cc=curl_easy_setopt(curl, CURLOPT_WRITEDATA, reinterpret_cast<void *>(&malloc_info)))!=CURLE_OK){ AESM_DBG_ERROR("fail to set write back function parameter:%d",(int)cc); ae_ret = AE_FAILURE; goto fini; } if((cc=curl_easy_perform(curl))!=CURLE_OK){ if(malloc_info.base){ free(malloc_info.base); } AESM_DBG_ERROR("fail in connect:%d",(int)cc); ae_ret = OAL_NETWORK_UNAVAILABLE_ERROR; goto fini; } *resp_msg = malloc_info.base; resp_size = malloc_info.size; AESM_DBG_TRACE("get response size=%d",resp_size); ae_ret = AE_SUCCESS; fini: if(headers!=NULL){ curl_slist_free_all(headers); } return ae_ret; }
// // return values // SUCCESS: // NO_LONGTERM_PAIRING_BLOB: // DONT_NEED_UPDATE_PAIR_LTP: psda svn now up to date // MAY_NEED_UPDATE_LTP: psda updated, but may not be up to date // OLD_EPID11_RLS: // ae_error_t PlatformInfoLogic::need_long_term_pairing(const platform_info_blob_wrapper_t* platformInfoBlobWrapper) { AESM_DBG_TRACE("enter fun"); ae_error_t status = AE_SUCCESS; pairing_blob_t pairing_blob; if (AE_FAILED(Helper::read_ltp_blob(pairing_blob))) { status = AESM_NLTP_NO_LTP_BLOB; } else if (Helper::noPseCert()) { status = AESM_NPC_NO_PSE_CERT; } else { uint32_t current_psda_svn = PSDAService::instance().psda_svn; pse_pr_interface_psda* pPSDA = NULL; pPSDA = new(std::nothrow) pse_pr_interface_psda(); if (pPSDA == NULL) { return AE_OUT_OF_MEMORY_ERROR; } EPID_GID meGid; if (NULL != platformInfoBlobWrapper) { // // psda svn was bad, cse gid was good and now psda svn is good // fact that we may not be able to get current PSDA SVN doesn't matter // here as long as expression involving it evaluates to false // uint32_t pib_psda_svn; pib_psda_svn = latest_psda_svn(platformInfoBlobWrapper); //pairing_blob_t pairing_blob; //Helper::read_ltp_blob(pairing_blob); // // psda svn was bad, cse gid was good and now psda svn is good // fact that we may not be able to get current PSDA SVN doesn't matter // here as long as expression involving it evaluates to false // if (((psda_svn_out_of_date(platformInfoBlobWrapper)) && (current_psda_svn == pib_psda_svn)) || 0) //(!psda_svn_out_of_date(platformInfoBlobWrapper) && cse_gid_out_of_date(platformInfoBlobWrapper))) { status = AESM_NLTP_DONT_NEED_UPDATE_PAIR_LTP; // don't need update, but need pairing } else if (cse_gid_out_of_date(platformInfoBlobWrapper)) { if (AE_SUCCESS == pPSDA->get_csme_gid(&meGid)) { if (Helper::ltpBlobCseGid(pairing_blob) != meGid) { status = AESM_NLTP_DONT_NEED_UPDATE_PAIR_LTP; } } else { status = AESM_NLTP_DONT_NEED_UPDATE_PAIR_LTP; } } // // we need to handle cases where current psda svn or psda svn in ltp // blob is unavailable // no ltp blob is handled above // not being able to get current psda svn is handled elsewhere // we just need to make sure we don't return something misleading // else if (newer_psda_svn(current_psda_svn, Helper::ltpBlobPsdaSvn(pairing_blob))) //(currentCse_gid() != ltpBlobCse_gid())) // assume no rollback { status = AESM_NLTP_MAY_NEED_UPDATE_LTP; // may need update and need pairing } else if (old_epid11_rls(platformInfoBlobWrapper)) { status = AESM_NLTP_OLD_EPID11_RLS; } } else { if ((AE_SUCCESS == pPSDA->get_csme_gid(&meGid)) && (Helper::ltpBlobCseGid(pairing_blob) != meGid)) { status = AESM_NLTP_DONT_NEED_UPDATE_PAIR_LTP; } // // see comment above about what happens when no ltp blob // or we can't get current psda svn // else if (newer_psda_svn(current_psda_svn, Helper::ltpBlobPsdaSvn(pairing_blob))) //(currentCse_gid() != ltpBlobCse_gid())) { status = AESM_NLTP_MAY_NEED_UPDATE_LTP; } } delete pPSDA; pPSDA = NULL; } SGX_DBGPRINT_ONE_STRING_TWO_INTS_CREATE_SESSION(__FUNCTION__" returning ", status, status); return status; }
sgx_status_t AESMLogic::get_launch_token(const enclave_css_t* signature, const sgx_attributes_t* attribute, sgx_launch_token_t* launch_token) { AESM_DBG_INFO("enter function"); AESMLogicLock lock(_le_mutex); ae_error_t ret_le = AE_SUCCESS; // load LE to get launch token if((ret_le=CLEClass::instance().load_enclave()) != AE_SUCCESS) { if(ret_le == AE_SERVER_NOT_AVAILABLE) { AESM_DBG_FATAL("LE not loaded due to AE_SERVER_NOT_AVAILABLE, possible SGX Env Not Ready"); return SGX_ERROR_NO_DEVICE; } AESM_DBG_FATAL("fail to load LE:%d",ret_le); return SGX_ERROR_UNEXPECTED; } ret_le = static_cast<ae_error_t>(CLEClass::instance().get_launch_token( const_cast<uint8_t*>(reinterpret_cast<const uint8_t *>(&signature->body.enclave_hash)), sizeof(sgx_measurement_t), const_cast<uint8_t*>(reinterpret_cast<const uint8_t *>(&signature->key.modulus)), sizeof(signature->key.modulus), const_cast<uint8_t*>(reinterpret_cast<const uint8_t *>(attribute)), sizeof(sgx_attributes_t), reinterpret_cast<uint8_t*>(launch_token), sizeof(token_t))); switch (ret_le) { case AE_SUCCESS: break; case LE_INVALID_PARAMETER: AESM_DBG_TRACE("Invalid parameter"); return SGX_ERROR_INVALID_PARAMETER; case LE_INVALID_ATTRIBUTE: case LE_INVALID_PRIVILEGE_ERROR: AESM_DBG_TRACE("Launch token error"); return SGX_ERROR_SERVICE_INVALID_PRIVILEGE; case LE_WHITELIST_UNINITIALIZED_ERROR: AESM_DBG_TRACE("LE whitelist uninitialized error"); return SGX_ERROR_UNEXPECTED; default: AESM_DBG_WARN("unexpeted error %d", ret_le); return SGX_ERROR_UNEXPECTED; } token_t *lt = reinterpret_cast<token_t *>(launch_token); ret_le = set_psvn(signature->body.isv_prod_id, signature->body.isv_svn, lt->cpu_svn_le); if(AE_PSVN_UNMATCHED_ERROR == ret_le) { //QE or PSE has been changed, but AESM doesn't restart. Will not provide service. return SGX_ERROR_SERVICE_UNAVAILABLE; }else if(AE_SUCCESS != ret_le) { AESM_DBG_ERROR("fail to save psvn:%d", ret_le); return SGX_ERROR_UNEXPECTED; } return SGX_SUCCESS; }
//The function is to verify the PEK ECDSA Signature and RSA Signature for ES Msg2 // When PvE uses PEK, it will re-check the ECDSA Signature //The function will only be called after ES protocol is completed. But it will not be called when reading data back from persitent storage //@param provision_ttl: The TTL field from ES Msg2 in little endian format //@param rsa_signature: The RSA Signature in ES Msg2, it is RSA Signature to XID:TTL:provision_url //@param xid: The transaction id (XID) of the ES Protocol //@return AE_SUCCESS if signature verification success and passed //@return PVE_MSG_ERROR if signature verification failed or message error //other kinds of error code could be returned too due to corresponding error situation ae_error_t EndpointSelectionInfo::verify_signature(const endpoint_selection_infos_t& es_info, uint8_t xid[XID_SIZE], uint8_t rsa_signature[RSA_3072_KEY_BYTES], uint16_t provision_ttl) { //Do signature verification here ae_error_t ae_err = AE_SUCCESS; IppsRSAPublicKeyState *rsa_pub_key = NULL; Ipp8u *buffer = NULL; int public_key_buffer_size = 0; int vr = 0; uint16_t ttl=_htons(provision_ttl); IppStatus ipp_status = ippStsNoErr; uint8_t msg_buf[XID_SIZE + sizeof(ttl) + MAX_PATH]; uint32_t buf_size = 0; extended_epid_group_blob_t xegb; memset(&xegb, 0, sizeof(xegb)); if (AE_SUCCESS != (ae_err=XEGDBlob::instance().read(xegb))){ return ae_err; } ae_err = aesm_check_pek_signature(es_info.pek, xegb); if(AE_SUCCESS != ae_err){ AESM_DBG_ERROR("PEK Signature verifcation not passed:%d",ae_err); goto ret_point; } AESM_DBG_INFO("PEK signature verified successfully"); buf_size = XID_SIZE +static_cast<uint32_t>(sizeof(ttl) + strnlen(es_info.provision_url, MAX_PATH)); if(0!=memcpy_s(msg_buf,sizeof(msg_buf), xid, XID_SIZE)|| 0!=memcpy_s(msg_buf+XID_SIZE, sizeof(ttl) + MAX_PATH, &ttl, sizeof(ttl))|| 0!=memcpy_s(msg_buf+XID_SIZE+sizeof(ttl), MAX_PATH, es_info.provision_url, buf_size-XID_SIZE-sizeof(ttl))){ ae_err = AE_FAILURE; AESM_DBG_ERROR("memcpy error"); goto ret_point; } ipp_status = get_provision_server_rsa_pub_key_in_ipp_format(es_info.pek, &rsa_pub_key); if(ippStsNoErr != ipp_status){ AESM_DBG_ERROR("Fail to load rsa public key from PEK:%d", ipp_status); ae_err = ipp_error_to_ae_error(ipp_status); goto ret_point; } ipp_status = ippsRSA_GetBufferSizePublicKey(&public_key_buffer_size, rsa_pub_key); if(ippStsNoErr != ipp_status){ AESM_DBG_ERROR("Fail to get rsa public key size:%s", ipp_status); ae_err = ipp_error_to_ae_error(ipp_status); goto ret_point; } buffer = (Ipp8u *)malloc(public_key_buffer_size); if(NULL == buffer){ AESM_DBG_ERROR("malloc error"); ae_err = AE_OUT_OF_MEMORY_ERROR; goto ret_point; } ipp_status = ippsRSAVerify_PKCS1v15(msg_buf, buf_size, rsa_signature, &vr, rsa_pub_key, ippHashAlg_SHA256, buffer); if(ippStsNoErr != ipp_status){ AESM_DBG_ERROR("Fail to verify rsa signature:%d", ipp_status); ae_err = ipp_error_to_ae_error(ipp_status); goto ret_point; } if(vr == 0){ AESM_DBG_TRACE("rsa signature verification failed"); ae_err = PVE_MSG_ERROR; goto ret_point; }else{ AESM_DBG_TRACE("rsa signature verification passed"); ae_err = AE_SUCCESS; } ret_point: if(NULL != rsa_pub_key){ secure_free_rsa_pub_key(RSA_3072_KEY_BYTES, sizeof(uint32_t), rsa_pub_key); } if(NULL != buffer){ free(buffer); } return ae_err; }