int sl_fcall_mngr_clone(struct sl_fcall_mngr* mngr, struct sl_fcall_mngr* untrusted) { PANIC_ON(!sgx_is_outside_enclave(untrusted, sizeof(*untrusted))); sgx_lfence(); BUG_ON(mngr == NULL); BUG_ON(untrusted == NULL); sl_fcall_type_t type_u = untrusted->fmn_type; PANIC_ON((type_u != SL_FCALL_TYPE_ECALL) && (type_u != SL_FCALL_TYPE_OCALL)); mngr->fmn_type = type_u; int ret = sl_siglines_clone(&mngr->fmn_siglns, &untrusted->fmn_siglns, can_type_process(type_u) ? process_fcall : NULL); if (ret) return ret; //check that we have right call managers. //i.e ecall manager on untrusted or ocall manager on trusted side PANIC_ON(fcall_type2direction(type_u) != sl_siglines_get_direction(&mngr->fmn_siglns)); uint32_t num_lines = sl_siglines_size(&mngr->fmn_siglns); BUG_ON(untrusted->fmn_bufs == NULL); struct sl_fcall_buf** bufs_u = untrusted->fmn_bufs; PANIC_ON(!sgx_is_outside_enclave(bufs_u, sizeof(bufs_u[0]) * num_lines)); sgx_lfence(); mngr->fmn_bufs = bufs_u; mngr->fmn_call_table = NULL; return 0; }
/* * External function used to verify EPID Blob and check whether QE has * been updated. * * @param p_blob[in, out] Pointer to EPID Blob. * @param blob_size[in] The size of EPID Blob, in bytes. * @param p_is_resealed[out] Whether the EPID Blob is resealed within this function call. * @param p_cpusvn[out] Return the raw CPUSVN. * @return uint32_t AE_SUCCESS or other error cases. */ uint32_t verify_blob( uint8_t *p_blob, uint32_t blob_size, uint8_t *p_is_resealed, sgx_cpu_svn_t *p_cpusvn) { se_plaintext_epid_data_sdk_t plain_text; /* Actually, some cases here will be checked with code generated by edger8r. Here we just want to defend in depth. */ if(NULL == p_blob || NULL == p_is_resealed || NULL == p_cpusvn) return QE_PARAMETER_ERROR; if(SGX_TRUSTED_EPID_BLOB_SIZE_SDK != blob_size) return QE_PARAMETER_ERROR; // // if we mispredict here and blob_size is too // small, we might overflow // sgx_lfence(); if(!sgx_is_within_enclave(p_blob, blob_size)) return QE_PARAMETER_ERROR; return random_stack_advance(verify_blob_internal, p_blob, blob_size, p_is_resealed, FALSE, plain_text, (MemberCtx**) NULL, p_cpusvn); }
int sl_siglines_clone(struct sl_siglines* sglns, struct sl_siglines* untrusted, sl_sighandler_t handler) { PANIC_ON(!sgx_is_outside_enclave(untrusted, sizeof(*untrusted))); sgx_lfence(); sl_siglines_dir_t dir = untrusted->dir; PANIC_ON((dir != SL_SIGLINES_DIR_T2U) && (dir != SL_SIGLINES_DIR_U2T)); BUG_ON(sglns == NULL); sglns->dir = dir; BUG_ON(is_direction_sender(dir) && (handler != NULL)); uint32_t num_lines = untrusted->num_lines; if ((num_lines <= 0) || ((num_lines % NBITS_PER_UINT64) != 0)) return -EINVAL; sglns->num_lines = num_lines; uint32_t nlong = num_lines / NBITS_PER_UINT64; BUG_ON(untrusted->event_lines == NULL); uint64_t* event_lines_u = untrusted->event_lines; PANIC_ON(!sgx_is_outside_enclave(event_lines_u, sizeof(uint64_t) * nlong)); sgx_lfence(); sglns->event_lines = event_lines_u; uint64_t* free_lines = NULL; if (is_direction_sender(dir)) { free_lines = malloc(sizeof(uint64_t) * nlong); if (free_lines == NULL) return -ENOMEM; for (uint32_t i = 0; i < nlong; i++) free_lines[i] = (uint64_t)(-1);// 1's -> free } sglns->free_lines = free_lines; sglns->handler = handler; return 0; }
/* Override the weak symbol defined in tRTS */ sgx_status_t do_init_switchless(struct sl_uswitchless* handle) { PANIC_ON(!sgx_is_outside_enclave(handle, sizeof(*handle))); sgx_lfence(); if (lock_cmpxchg64((uint64_t*)&sl_uswitchless_handle, (uint64_t)NULL, (uint64_t)handle) != (uint64_t)NULL) { return SGX_ERROR_UNEXPECTED; } return SGX_SUCCESS; }
//get the item pointer in the vector //return 0 if success, return 1 if index is out of range or data pointer is invalid. errno_t vector_get(const simple_vector* v, uint32_t index, void** data) { if (!v || index >= v->size || !data) return 1; //fence after boundary check sgx_lfence(); *data = v->data[index]; return 0; }
static sgx_status_t make_target_info( const PS& ps, const sgx_report_t& rpt, sgx_target_info_t& ti) { if (!ps.is_valid()) return SGX_ERROR_INVALID_PARAMETER; memset_s(&ti, sizeof(ti), 0, sizeof(sgx_target_info_t)); auto *d = reinterpret_cast<uint8_t*>(&ti); // Spectre sgx_lfence(); for (int i = 1, to = 0; i <= ps.ts_count(); ++i) { int size = 1 << (ps.target_spec[i] & 0xf); to += size - 1; to &= -size; if (to + size > int(sizeof(ti))) return SGX_ERROR_UNEXPECTED; int from = int16_t(ps.target_spec[i]) >> 4; if (from >= 0) { if (from + size > int(sizeof(rpt))) return SGX_ERROR_UNEXPECTED; memcpy(d + to, reinterpret_cast<const uint8_t*>(&rpt) + from, size); } else switch (from) { case -1: break; default: return SGX_ERROR_UNEXPECTED; } to += size; } return SGX_SUCCESS; }
/* 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; }
/* * External function used to get quote. Prefix "emp_" means it is a pointer * points memory outside enclave. * * @param p_blob[in, out] Pointer to the EPID Blob. * @param blob_size[in] The size of EPID Blob, in bytes. * @param p_enclave_report[in] The application enclave's report. * @param quote_type[in] The type of quote, random based or name based. * @param p_spid[in] Pointer to SPID. * @param p_nonce[in] Pointer to nonce. * @param emp_sig_rl[in] Pointer to SIG-RL. * @param sig_rl_size[in] The size of SIG-RL, in bytes. * @param p_qe_report[out] Pointer to QE report, which reportdata is * sha256(nonce || quote) * @param emp_quote[out] Pointer to the output buffer for quote. * @param quote_size[in] The size of emp_quote, in bytes. * @param pce_isvsvn[in] The ISVSVN of PCE. * @return ae_error_t AE_SUCCESS for success, otherwise for errors. */ uint32_t get_quote( uint8_t *p_blob, uint32_t blob_size, const sgx_report_t *p_enclave_report, sgx_quote_sign_type_t quote_type, const sgx_spid_t *p_spid, const sgx_quote_nonce_t *p_nonce, const uint8_t *emp_sig_rl, uint32_t sig_rl_size, sgx_report_t *p_qe_report, uint8_t *emp_quote, uint32_t quote_size, sgx_isv_svn_t pce_isvsvn) { ae_error_t ret = AE_SUCCESS; EpidStatus epid_ret = kEpidNoErr; MemberCtx *p_epid_context = NULL; sgx_quote_t quote_body; uint8_t is_resealed = 0; sgx_basename_t basename = {{0}}; uint64_t sign_size = 0; sgx_status_t se_ret = SGX_SUCCESS; sgx_report_t qe_report; uint64_t required_buffer_size = 0; se_sig_rl_t sig_rl_header; se_plaintext_epid_data_sdk_t plaintext; sgx_ec256_signature_t ec_signature; sgx_cpu_svn_t cpusvn; memset("e_body, 0, sizeof(quote_body)); memset(&sig_rl_header, 0, sizeof(sig_rl_header)); memset(&plaintext, 0, sizeof(plaintext)); memset(&ec_signature, 0, sizeof(ec_signature)); memset(&cpusvn, 0, sizeof(cpusvn)); /* Actually, some cases here will be checked with code generated by edger8r. Here we just want to defend in depth. */ if((NULL == p_blob) || (NULL == p_enclave_report) || (NULL == p_spid) || (NULL == emp_quote) || (!quote_size) || ((NULL != emp_sig_rl) && (sig_rl_size < sizeof(se_sig_rl_t) + 2 * SE_ECDSA_SIGN_SIZE)) // // this size check could mispredict and cause us to // overflow, but we have an lfence below // that's safe to use for this case // || ((NULL == emp_sig_rl) && (sig_rl_size != 0))) return QE_PARAMETER_ERROR; if(SGX_TRUSTED_EPID_BLOB_SIZE_SDK != blob_size) return QE_PARAMETER_ERROR; // // this could mispredict and cause us to // overflow, but we have an lfence below // that's safe to use for this case // if(SGX_LINKABLE_SIGNATURE != quote_type && SGX_UNLINKABLE_SIGNATURE != quote_type) return QE_PARAMETER_ERROR; if(!p_nonce && p_qe_report) return QE_PARAMETER_ERROR; if(p_nonce && !p_qe_report) return QE_PARAMETER_ERROR; /* To reduce the memory footprint of QE, we should leave sig_rl and quote buffer outside enclave. */ if(!sgx_is_outside_enclave(emp_sig_rl, sig_rl_size)) return QE_PARAMETER_ERROR; // // for user_check SigRL input // based on quote_size input parameter // sgx_lfence(); if(!sgx_is_outside_enclave(emp_quote, quote_size)) return QE_PARAMETER_ERROR; /* Check whether p_blob is copied into EPC. If we want to reduce the memory usage, maybe we can leave the p_blob outside EPC. */ if(!sgx_is_within_enclave(p_blob, blob_size)) return QE_PARAMETER_ERROR; if(!sgx_is_within_enclave(p_enclave_report, sizeof(*p_enclave_report))) return QE_PARAMETER_ERROR; if(!sgx_is_within_enclave(p_spid, sizeof(*p_spid))) return QE_PARAMETER_ERROR; /* If the code reach here, if p_nonce is NULL, then p_qe_report will be NULL also. So we only check p_nonce here.*/ if(p_nonce) { /* Actually Edger8r will alloc the buffer within EPC, this is just kind of defense in depth. */ if(!sgx_is_within_enclave(p_nonce, sizeof(*p_nonce))) return QE_PARAMETER_ERROR; if(!sgx_is_within_enclave(p_qe_report, sizeof(*p_qe_report))) return QE_PARAMETER_ERROR; } /* Verify the input report. */ if(SGX_SUCCESS != sgx_verify_report(p_enclave_report)) return QE_PARAMETER_ERROR; /* Verify EPID p_blob and create the context */ ret = random_stack_advance(verify_blob_internal, p_blob, blob_size, &is_resealed, TRUE, plaintext, &p_epid_context, &cpusvn); if(AE_SUCCESS != ret) goto CLEANUP; /* If SIG-RL is provided, we should check its size. */ if(emp_sig_rl) { uint64_t temp_size = 0; uint64_t n2 = 0; memcpy(&sig_rl_header, emp_sig_rl, sizeof(sig_rl_header)); if(sig_rl_header.protocol_version != SE_EPID_SIG_RL_VERSION) { ret = QE_PARAMETER_ERROR; goto CLEANUP; } if(sig_rl_header.epid_identifier != SE_EPID_SIG_RL_ID) { ret = QE_PARAMETER_ERROR; goto CLEANUP; } if(memcmp(&sig_rl_header.sig_rl.gid, &plaintext.epid_group_cert.gid, sizeof(sig_rl_header.sig_rl.gid))) { ret = QE_PARAMETER_ERROR; goto CLEANUP; } temp_size = se_get_sig_rl_size(&sig_rl_header); if(temp_size != sig_rl_size) { ret = QE_PARAMETER_ERROR; goto CLEANUP; } se_static_assert(sizeof(ec_signature.x) == SE_ECDSA_SIGN_SIZE); se_static_assert(sizeof(ec_signature.y) == SE_ECDSA_SIGN_SIZE); memcpy(ec_signature.x, emp_sig_rl + sig_rl_size - (SE_ECDSA_SIGN_SIZE * 2), sizeof(ec_signature.x)); SWAP_ENDIAN_32B(ec_signature.x); memcpy(ec_signature.y, emp_sig_rl + sig_rl_size - (SE_ECDSA_SIGN_SIZE * 1), sizeof(ec_signature.y)); SWAP_ENDIAN_32B(ec_signature.y); n2 = SWAP_4BYTES(sig_rl_header.sig_rl.n2); temp_size = sizeof(EpidSignature) - sizeof(NrProof) + n2 * sizeof(NrProof); if(temp_size > UINT32_MAX) { ret = QE_PARAMETER_ERROR; goto CLEANUP; } sign_size = temp_size; } else { sign_size = sizeof(BasicSignature) + sizeof(uint32_t) // rl_ver + sizeof(uint32_t); // rl_num } /* Verify sizeof basename is large enough and it should always be true*/ se_static_assert(sizeof(basename) > sizeof(*p_spid)); /* Because basename has already been zeroed, so we don't need to concatenating with 0s.*/ memcpy(&basename, p_spid, sizeof(*p_spid)); if(SGX_UNLINKABLE_SIGNATURE == quote_type) { uint8_t *p = (uint8_t *)&basename + sizeof(*p_spid); se_ret = sgx_read_rand(p, sizeof(basename) - sizeof(*p_spid)); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } } epid_ret = EpidRegisterBasename(p_epid_context, (uint8_t *)&basename, sizeof(basename)); if(kEpidNoErr != epid_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } required_buffer_size = SE_QUOTE_LENGTH_WITHOUT_SIG + sign_size; /* We should make sure the buffer size is big enough. */ if(quote_size < required_buffer_size) { ret = QE_PARAMETER_ERROR; goto CLEANUP; } // // for user_check SigRL input // based on n2 field in SigRL // sgx_lfence(); /* Copy the data in the report into quote body. */ memset(emp_quote, 0, quote_size); quote_body.version = QE_QUOTE_VERSION; quote_body.sign_type = (uint16_t)quote_type; quote_body.pce_svn = pce_isvsvn; // Both are little endian quote_body.xeid = plaintext.xeid; // Both are little endian se_static_assert(sizeof(plaintext.epid_group_cert.gid) == sizeof(OctStr32)); se_static_assert(sizeof(quote_body.epid_group_id) == sizeof(uint32_t)); ((uint8_t *)("e_body.epid_group_id))[0] = plaintext.epid_group_cert.gid.data[3]; ((uint8_t *)("e_body.epid_group_id))[1] = plaintext.epid_group_cert.gid.data[2]; ((uint8_t *)("e_body.epid_group_id))[2] = plaintext.epid_group_cert.gid.data[1]; ((uint8_t *)("e_body.epid_group_id))[3] = plaintext.epid_group_cert.gid.data[0]; memcpy("e_body.basename, &basename, sizeof(quote_body.basename)); // Get the QE's report. se_ret = sgx_create_report(NULL, NULL, &qe_report); if(SGX_SUCCESS != se_ret) { ret = QE_PARAMETER_ERROR; goto CLEANUP; } // Copy QE's security version in to Quote body. quote_body.qe_svn = qe_report.body.isv_svn; // Copy the incoming report into Quote body. memcpy("e_body.report_body, &(p_enclave_report->body), sizeof(quote_body.report_body)); /* Because required_buffer_size is larger than signature_len, so if we get here, then no integer overflow will ocur. */ quote_body.signature_len = (uint32_t)(sizeof(se_wrap_key_t) + QUOTE_IV_SIZE + sizeof(uint32_t) + sign_size + sizeof(sgx_mac_t)); /* Make the signature. */ ret = qe_epid_sign(p_epid_context, plaintext, &basename, emp_sig_rl ? ((const se_sig_rl_t *)emp_sig_rl)->sig_rl.bk : NULL, &sig_rl_header, &ec_signature, p_enclave_report, p_nonce, p_qe_report, emp_quote, "e_body, (uint32_t)sign_size); if(AE_SUCCESS != ret) { // Only need to clean the buffer after the fixed length part. memset_s(emp_quote + sizeof(sgx_quote_t), quote_size - sizeof(sgx_quote_t), 0, quote_size - sizeof(sgx_quote_t)); goto CLEANUP; } memcpy(emp_quote, "e_body, sizeof(sgx_quote_t)); CLEANUP: if(p_epid_context) epid_member_delete(&p_epid_context); return ret; }
/******************************************************************* ** Function name: invoke_service_wrapper ** Descrption: ** This function is used to invoke a service call ** Parameters: ** tick - the number of milliseconds that have elapsed since the system was started, ** used to detect which session is idle for the longest time. ** req_msg - service request message ** req_msg_size - size of request message ** resp_msg - service response message ** resp_msg_size - size of response message ** Returns: ae_error_t *******************************************************************/ ae_error_t invoke_service_wrapper ( /* IN */ uint64_t tick, /* IN */ uint8_t* req_msg, /* IN */ uint32_t req_msg_size, /* OUT */ uint8_t* resp_msg, /* IN */ uint32_t resp_msg_size) { // check parameter ae_error_t ae_ret = AE_SUCCESS; pse_message_t* pse_req_msg = (pse_message_t*)req_msg; pse_message_t* pse_resp_msg = (pse_message_t*)resp_msg; pse_op_error_t op_ret; if (!req_msg || !resp_msg) { return PSE_OP_PARAMETER_ERROR; } // // make sure the header is inside enclave // if (req_msg_size < sizeof(pse_message_t)) { return PSE_OP_PARAMETER_ERROR; } // // if this mispredicts, we might overflow below // sgx_lfence(); if (pse_req_msg->payload_size > UINT32_MAX - sizeof(pse_message_t) // check potential overflow || req_msg_size != sizeof(pse_message_t) + pse_req_msg->payload_size) { return PSE_OP_PARAMETER_ERROR; } if (resp_msg_size < sizeof(pse_message_t) // make sure the header is inside enclave || pse_req_msg->exp_resp_size > UINT32_MAX - sizeof(pse_message_t) // check potential overflow || resp_msg_size < sizeof(pse_message_t) + pse_req_msg->exp_resp_size) { return PSE_OP_PARAMETER_ERROR; } // // put LFENCE here mostly for pse_req_msg->payload_size // check above. I don't think we use // pse_req_msg->exp_resp_size to calculate // any pointers. // sgx_lfence(); pse_session_t* session = sid2session(pse_req_msg->session_id); // ephemeral session must have been established if(!is_eph_session_active()) { // the ephemeral session is not active return PSE_OP_EPHEMERAL_SESSION_INVALID; } //if session is invalid (session not exists or established, or sequence num overflow) if (!is_isv_session_valid(session)) { return PSE_OP_SESSION_INVALID; } // update session tick update_session_tick_count(session, tick); //clear response message memset(resp_msg, 0, resp_msg_size); uint8_t* req = (uint8_t*)malloc(pse_req_msg->payload_size); uint8_t* resp= NULL; uint32_t session_seq_num = get_session_seq_num(session); do { BREAK_ON_MALLOC_FAIL(req, ae_ret) // decrypt service request message using session key if(false == decrypt_msg(pse_req_msg, req, (sgx_key_128bit_t*)session->active.AEK)) { ae_ret = PSE_OP_SERVICE_MSG_ERROR; break; } pse_req_hdr_t* req_hdr = (pse_req_hdr_t*)req; // check session sequence number if(req_hdr->seq_num != session_seq_num) { ae_ret = PSE_OP_SESSION_INVALID; //close session free_session(session); break; } // Dispatch the service request to the proper handler int i; int service_count = static_cast<int>(sizeof(service_handler) / sizeof(service_handler_t)); for (i = 0; i < service_count; i++) { // // might mispredict the end of the loop // sgx_lfence(); if (req_hdr->service_id == service_handler[i].service_id && req_hdr->service_cmd == service_handler[i].service_cmd) { if (pse_req_msg->payload_size != service_handler[i].req_size || pse_req_msg->exp_resp_size < service_handler[i].resp_size) // response message buffer must be large enough to hold response data { ae_ret = PSE_OP_SERVICE_MSG_ERROR; goto clean_up; } resp = (uint8_t*)malloc(service_handler[i].resp_size); if (resp == NULL) { ae_ret = PSE_OP_INTERNAL_ERROR; goto clean_up; } // // in case payload_size, req_size comparisons // mispredict // sgx_lfence(); // serve the request op_ret = service_handler[i].srv_pfn(session->isv_attributes, req, resp); if(op_ret != OP_SUCCESS) { ae_ret = error_reinterpret(op_ret); goto clean_up; } // set payload size for valid requests pse_resp_msg->payload_size = service_handler[i].resp_size; break; } } if (i == service_count) { // service_id or service_cmd mismatch resp = (uint8_t*)malloc(sizeof(pse_resp_hdr_t)); BREAK_ON_MALLOC_FAIL(resp, ae_ret) // for unknown requests, payload data only includes response header pse_resp_msg->payload_size = sizeof(pse_resp_hdr_t); // set error status ((pse_resp_hdr_t*)resp)->status = PSE_ERROR_UNKNOWN_REQ; } // prepare the response message pse_resp_hdr_t* resp_hdr = (pse_resp_hdr_t*)resp; pse_resp_msg->exp_resp_size = 0; pse_resp_msg->session_id = pse_req_msg->session_id; //set response header, status code is already set in service functions resp_hdr->seq_num = session_seq_num + 1; // addition overflow already checked in is_isv_session_valid() resp_hdr->service_id = req_hdr->service_id; resp_hdr->service_cmd = req_hdr->service_cmd; // update sequence number for current session set_session_seq_num(session, resp_hdr->seq_num + 1); // encrypt the response message if(false == encrypt_msg((pse_message_t*)pse_resp_msg, (uint8_t*)resp, (sgx_key_128bit_t*)session->active.AEK)) { ae_ret = PSE_OP_INTERNAL_ERROR; break; } } while (0); clean_up: SAFE_FREE(req); SAFE_FREE(resp); return ae_ret; }