// 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; }
ae_error_t CertificateProvisioningProtocol::sendReceive(const upse::Buffer& sendSerialized, upse::Buffer& recvSerialized) { ae_error_t status = AE_FAILURE; uint8_t* recv = NULL; uint32_t recv_size = 0; do { AESM_DBG_INFO("start send msg"); status = AESMNetworkEncoding::aesm_send_recv_msg_encoding(m_url.c_str(), const_cast<uint8_t *>(sendSerialized.getData()), sendSerialized.getSize(), recv, recv_size); if (AE_FAILED(status)) break; AESM_DBG_INFO("msg received with size %u", recv_size); status = recvSerialized.Alloc(recv_size); if (AE_FAILED(status)) break; AESM_DBG_INFO("buffer alloced"); status = upse::BufferWriter(recvSerialized).writeRaw(recv, recv_size); if (AE_FAILED(status)) break; AESM_DBG_INFO("buffer written"); status = AE_SUCCESS; } while (0); if (NULL != recv) AESMNetworkEncoding::aesm_free_response_msg(recv); return status; }
aesm_error_t AESMLogic::get_quote(const uint8_t *report, uint32_t report_size, uint32_t quote_type, const uint8_t *spid, uint32_t spid_size, const uint8_t *nonce, uint32_t nonce_size, const uint8_t *sigrl, uint32_t sigrl_size, uint8_t *qe_report, uint32_t qe_report_size, uint8_t *quote, uint32_t buf_size) { AESM_DBG_INFO("get_quote"); if(sizeof(sgx_report_t) != report_size || sizeof(sgx_spid_t) != spid_size) { return AESM_PARAMETER_ERROR; } if((nonce && sizeof(sgx_quote_nonce_t) != nonce_size) || (qe_report && sizeof(sgx_report_t) != qe_report_size)) { return AESM_PARAMETER_ERROR; } AESMLogicLock lock(_qe_pve_mutex); CHECK_EPID_PROVISIONG_STATUS; return QEAESMLogic::get_quote(report, quote_type, spid, nonce, sigrl, sigrl_size, qe_report, quote, buf_size); }
aesm_error_t AESMLogic::init_quote( uint8_t *target_info, uint32_t target_info_size, uint8_t *gid, uint32_t gid_size) { ae_error_t ret = AE_SUCCESS; uint16_t qe_isv_svn = 0xFFFF; sgx_cpu_svn_t qe_cpu_svn; memset(&qe_cpu_svn, 0, sizeof(qe_cpu_svn)); AESM_DBG_INFO("init_quote"); if(sizeof(sgx_target_info_t) != target_info_size || sizeof(sgx_epid_group_id_t) != gid_size) { return AESM_PARAMETER_ERROR; } AESMLogicLock lock(_qe_pve_mutex); CHECK_EPID_PROVISIONG_STATUS; ret = get_qe_cpu_svn(qe_cpu_svn); if(AE_SUCCESS != ret) { return AESM_UNEXPECTED_ERROR; } ret = get_qe_isv_svn(qe_isv_svn); if(AE_SUCCESS != ret) { return AESM_UNEXPECTED_ERROR; } return QEAESMLogic::init_quote( reinterpret_cast<sgx_target_info_t *>(target_info), gid, gid_size, qe_isv_svn, qe_cpu_svn); }
/* This function will be called outside aesm(from urts_internal) */ extern "C" sgx_status_t get_launch_token(const enclave_css_t* signature, const sgx_attributes_t* attribute, sgx_launch_token_t* launch_token) { AESM_DBG_INFO("enter function"); return AESMLogic::get_launch_token(signature, attribute, launch_token); }
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; } }
aesm_error_t AESMLogic::report_attestation_status( uint8_t* platform_info, uint32_t platform_info_size, uint32_t attestation_status, uint8_t* update_info, uint32_t update_info_size) { AESM_DBG_INFO("report_attestation_status"); AESMLogicLock lock(_pse_mutex); return PlatformInfoLogic::report_attestation_status(platform_info, platform_info_size, attestation_status, update_info, update_info_size); }
// // 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; }
void AESMLogic::service_stop() { CPVEClass::instance().unload_enclave(); CQEClass::instance().unload_enclave(); CLEClass::instance().unload_enclave(); stop_all_long_lived_threads(); AESM_DBG_INFO("aesm service down"); AESM_LOG_FINI(); AESM_PROFILE_OUTPUT; }
//Function to read urls from configure files ae_error_t EndpointSelectionInfo::get_url_info() { ae_error_t ae_err=AE_SUCCESS; uint32_t server_urls_size = sizeof(_server_urls); ae_err = aesm_read_data(FT_PERSISTENT_STORAGE, AESM_SERVER_URL_FID, reinterpret_cast<uint8_t *>(&_server_urls), &server_urls_size, AESMLogic::get_active_extended_epid_group_id()); if(AE_SUCCESS != ae_err || server_urls_size != sizeof(_server_urls)|| !is_valid_server_url_infos(_server_urls)){ //If fail to read or data format error, use default value _is_server_url_valid = false; if(AE_SUCCESS == ae_err){//File available but format error, report ERROR LOG AESM_LOG_WARN("Server URL Blob file format error"); AESM_DBG_INFO("fail to read server url info from persistent storage, error code (%d), size %d, expected size %d", ae_err, server_urls_size, sizeof(_server_urls)); ae_err = OAL_CONFIG_FILE_ERROR; }else{ AESM_DBG_INFO("server url blob file not available in persistent storage"); } if (AESMLogic::get_active_extended_epid_group_id() == DEFAULT_EGID){ if (strcpy_s(_server_urls.endpoint_url, MAX_PATH, DEFAULT_URL) != 0) return AE_FAILURE; if (strcpy_s(_server_urls.pse_rl_url, MAX_PATH, DEFAULT_PSE_RL_URL) != 0) return AE_FAILURE; if (strcpy_s(_server_urls.pse_ocsp_url, MAX_PATH, DEFAULT_PSE_OCSP_URL) != 0) return AE_FAILURE; _is_server_url_valid = true; return AE_SUCCESS; } else{ return ae_err; } } _is_server_url_valid = true; return AE_SUCCESS; }
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; } }
ae_error_t EndpointSelectionInfo::read_pek(endpoint_selection_infos_t& es_info) { ae_error_t ae_err=AE_SUCCESS; uint32_t es_info_size = sizeof(es_info); ae_err = aesm_read_data(FT_PERSISTENT_STORAGE, PROVISION_PEK_BLOB_FID, reinterpret_cast<uint8_t *>(&es_info), &es_info_size); if(AE_SUCCESS == ae_err && (es_info_size != sizeof(es_info)||!is_valid_endpoint_selection_info(es_info))){ AESM_DBG_ERROR("Invalid ES result in persistent storage:size %d, expected size %d", es_info_size, sizeof(es_info)); ae_err = OAL_FILE_ACCESS_ERROR; } if(AE_SUCCESS == ae_err){ AESM_DBG_INFO("Read ES result from persistent storage successfully"); }else{ AESM_DBG_WARN("ES result in persistent storage failed to load:%d", ae_err); } return ae_err; }
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; }
//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; }
//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; }