123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481 |
- /*
- * Copyright (C) 2011-2018 Intel Corporation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Intel Corporation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
- #include "pse_op_logic.h"
- #include "aesm_logic.h"
- #include "PSEClass.h"
- #include "PSEPRClass.h"
- #include "aesm_long_lived_thread.h"
- #include "platform_info_logic.h"
- #include <assert.h>
- static aesm_error_t pse_ret_to_aesm_ret(ae_error_t ret_pse)
- {
- switch(ret_pse)
- {
- case AE_SUCCESS:
- return AESM_SUCCESS;
- case PSE_OP_PARAMETER_ERROR:
- return AESM_PARAMETER_ERROR;
- case PSE_OP_MAX_NUM_SESSION_REACHED:
- return AESM_MAX_NUM_SESSION_REACHED;
- case PSE_OP_SESSION_INVALID:
- return AESM_SESSION_INVALID;
- case PSE_OP_SERVICE_MSG_ERROR:
- return AESM_MSG_ERROR;
- case AESM_PSDA_NOT_AVAILABLE:
- return AESM_PSDA_UNAVAILABLE;
- case PSE_OP_ERROR_KDF_MISMATCH:
- return AESM_KDF_MISMATCH;
- default:
- return AESM_UNEXPECTED_ERROR;
- }
- }
- // Local helper function to log to the admin log based on error code
- // Note: In some cases, PSEOP functions also log PS errors directly
- static void log_admin_ps_ae(ae_error_t ae_error_code)
- {
- switch (ae_error_code)
- {
- case AE_SUCCESS:
- break;
- case PSE_OP_MAX_NUM_SESSION_REACHED:
- AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_RESOURCE_ERROR]);
- break;
- case PSE_OP_PARAMETER_ERROR:
- case PSE_OP_SESSION_INVALID:
- case PSE_OP_SERVICE_MSG_ERROR:
- case AESM_PSDA_NOT_AVAILABLE:
- default:
- AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_ERROR]);
- break;
- }
- }
- aesm_error_t PSEOPAESMLogic::get_ps_cap(
- uint64_t* ps_cap)
- {
- AESM_DBG_INFO("PSEOPAESMLogic::get_ps_cap");
- ae_error_t ret_pse = CPSEClass::instance().get_ps_cap(ps_cap);
- return pse_ret_to_aesm_ret(ret_pse);
- }
- // Get ready for PS service. Establish ephemeral session or long term pairing according to current
- // status. Update status accordingly.
- aesm_error_t PSEOPAESMLogic::prepare_for_ps_request(void)
- {
- AESM_DBG_INFO("PSEOPAESMLogic::prepare_for_ps_request");
- pse_status_t status = CPSEClass::instance().get_status();
- switch(status)
- {
- case PSE_STATUS_INIT:
- AESM_DBG_ERROR("unexpeted status PSE_STATUS_INIT");
- AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_CERT_ERROR]);
- return AESM_UNEXPECTED_ERROR;
- case PSE_STATUS_UNAVAILABLE:
- AESM_DBG_ERROR("status PSE_STATUS_UNAVAILABLE");
- AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_DAL_ERROR]);
- return AESM_PSDA_UNAVAILABLE;
- case PSE_STATUS_CSE_PROVISIONED:
- {
- AESM_DBG_TRACE("status PSE_STATUS_CSE_PROVISIONED");
- aesm_error_t ret = establish_ephemeral_session(false);
- // If PS is still not ready after trying to establish the ephemeral session, log a general
- // error. The PS_INIT_FAIL log will have more details, so we don't have to log them here.
- if (CPSEClass::instance().get_status() != PSE_STATUS_SERVICE_READY)
- AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_ERROR]);
- return ret;
- }
- case PSE_STATUS_SERVICE_READY:
- return AESM_SUCCESS;
- default:
- AESM_DBG_ERROR("unexpeted status %d", (int)status);
- return AESM_UNEXPECTED_ERROR;
- }
- }
- aesm_error_t PSEOPAESMLogic::create_session(
- uint32_t* session_id,
- uint8_t* se_dh_msg1, uint32_t se_dh_msg1_size)
- {
- aesm_error_t result = AESM_UNEXPECTED_ERROR;
- // prepare for service request
- result = prepare_for_ps_request();
- if (result != AESM_SUCCESS)
- return result;
- ae_error_t ret_pse = CPSEClass::instance().create_session(
- session_id,
- se_dh_msg1,
- se_dh_msg1_size);
- if (ret_pse == PSE_OP_EPHEMERAL_SESSION_INVALID)
- {
- AESM_DBG_ERROR("Ephemeral session is broken");
- // Ephemeral session is broken , re-establish ephemeral session and retry create_session.
- if ((result = establish_ephemeral_session(true)) != AESM_SUCCESS) {
- AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_ERROR]);
- return result;
- }
- AESM_DBG_INFO("create session again");
- ret_pse = CPSEClass::instance().create_session(
- session_id,
- se_dh_msg1,
- se_dh_msg1_size);
- }
- log_admin_ps_ae(ret_pse);
- return pse_ret_to_aesm_ret(ret_pse);
- }
- ae_error_t PSEOPAESMLogic::certificate_provisioning_and_long_term_pairing_func(bool& is_new_pairing)
- {
- ae_error_t psStatus = AE_SUCCESS;
- AESM_DBG_INFO("certificate_provisioning_and_long_term_pairing_func()");
- is_new_pairing = false;
- ae_error_t ltpStatus = CPSEPRClass::instance().long_term_pairing(&is_new_pairing);
- SGX_DBGPRINT_ONE_STRING_TWO_INTS_CREATE_SESSION(__FUNCTION__" ltpStatus = ", ltpStatus, __LINE__);
- switch (ltpStatus)
- {
- case AE_SUCCESS:
- case OAL_PROXY_SETTING_ASSIST:
- case AESM_AE_OUT_OF_EPC:
- return ltpStatus;
- // for below errors need to check cert status
- case AESM_NPC_NO_PSE_CERT:
- case AESM_LTP_PSE_CERT_REVOKED:
- case PSE_PAIRING_BLOB_UNSEALING_ERROR:
- case PSE_PAIRING_BLOB_INVALID_ERROR:
- case AESM_PSDA_LT_SESSION_INTEGRITY_ERROR:
- {
- ae_error_t pcphStatus = PlatformInfoLogic::pse_cert_provisioning_helper(NULL);
- switch (pcphStatus)
- {
- case OAL_NETWORK_UNAVAILABLE_ERROR:
- case OAL_PROXY_SETTING_ASSIST:
- case PSW_UPDATE_REQUIRED:
- case AESM_AE_OUT_OF_EPC:
- case AESM_PCP_PSE_CERT_PROVISIONING_ATTESTATION_FAILURE_MIGHT_NEED_EPID_UPDATE:
- case AESM_PCP_SIMPLE_PSE_CERT_PROVISIONING_ERROR:
- case AESM_PCP_SIMPLE_EPID_PROVISION_ERROR:
- case AESM_PCP_PSE_CERT_PROVISIONING_ATTESTATION_FAILURE_NEED_EPID_UPDATE:
- case AESM_PCP_NEED_PSE_UPDATE:
- return pcphStatus;
- case AE_SUCCESS:
- {
- //
- // retry one time
- //
- ltpStatus = CPSEPRClass::instance().long_term_pairing(&is_new_pairing);
- SGX_DBGPRINT_ONE_STRING_TWO_INTS_CREATE_SESSION(__FUNCTION__" ltpStatus = ", ltpStatus, __LINE__);
- switch (ltpStatus)
- {
- case AE_SUCCESS:
- case OAL_PROXY_SETTING_ASSIST:
- case AESM_AE_OUT_OF_EPC:
- case OAL_THREAD_TIMEOUT_ERROR:
- psStatus = ltpStatus;
- break;
- case AESM_NPC_NO_PSE_CERT:
- case AESM_LTP_PSE_CERT_REVOKED:
- {
- AESM_DBG_ERROR("long_term_pairing Return: 0x%X", ltpStatus);
- AESM_LOG_ERROR_UNICODE("%s", g_event_string_table[SGX_EVENT_LTP_FAILURE]);
- psStatus = AESM_LTP_SIMPLE_LTP_ERROR;
- break;
- }
- default:
- {
- psStatus = AESM_LTP_SIMPLE_LTP_ERROR;
- break;
- }
- }
- break;
- }
- default:
- {
- assert(false); break;
- }
- }
- break;
- }
- default:
- {
- psStatus = AESM_LTP_SIMPLE_LTP_ERROR;
- break;
- }
- }
- return psStatus;
- }
- static aesm_error_t redo_long_term_pairing(
- bool* is_new_pairing)
- {
- ae_error_t ae_ret = AE_FAILURE;
- ae_ret = start_long_term_pairing_thread(*is_new_pairing);
- switch (ae_ret)
- {
- case AE_SUCCESS:
- return AESM_SUCCESS;
- case OAL_THREAD_TIMEOUT_ERROR:
- return AESM_BUSY;
- case PVE_PROV_ATTEST_KEY_NOT_FOUND:
- return AESM_UNRECOGNIZED_PLATFORM;
- case OAL_PROXY_SETTING_ASSIST:
- return AESM_PROXY_SETTING_ASSIST;
- case PSW_UPDATE_REQUIRED:
- return AESM_UPDATE_AVAILABLE;
- case AESM_AE_OUT_OF_EPC:
- return AESM_OUT_OF_EPC;
- default:
- return AESM_LONG_TERM_PAIRING_FAILED;
- break;
- }
- }
- aesm_error_t PSEOPAESMLogic::establish_ephemeral_session(bool force_redo)
- {
- AESM_DBG_INFO("PSEOPAESMLogic::establish_ephemeral_session");
- ae_error_t ret = AE_SUCCESS;
- // If session already exists and force_redo is false, session is already ready
- if (force_redo == false && CPSEClass::instance().get_status() == PSE_STATUS_SERVICE_READY)
- return AESM_SUCCESS;
- AESM_LOG_INFO_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_START]);
- // establish ephemeral session
- // Note: Admin Logging of success/failure after this point is owned by create_ephemeral_session_pse_cse()
- ret = CPSEClass::instance().create_ephemeral_session_pse_cse(false, force_redo);
- // Attempt retry/recovery, where appropriate
- switch (ret)
- {
- case PSE_PAIRING_BLOB_UNSEALING_ERROR:
- case PSE_PAIRING_BLOB_INVALID_ERROR:
- case AESM_PSDA_NEED_REPAIRING:
- case PSE_OP_ERROR_EPH_SESSION_ESTABLISHMENT_INTEGRITY_ERROR:
- case PSE_OP_LTPB_SEALING_OUT_OF_DATE:
- {
- // Pairing blob doesn't exist or blob size is wrong
- // or pse-op fails to unseal pairing blob
- // or PSDA reports session integrity error
- // or pse-op reports session integrity error
- bool is_new_pairing = false;//out
- aesm_error_t retValue = AESM_SUCCESS;
- retValue = redo_long_term_pairing(&is_new_pairing);
- if (AESM_SUCCESS == retValue)
- {
- // retry ephemeral session
- ret = CPSEClass::instance().create_ephemeral_session_pse_cse(is_new_pairing, true);
- goto exit; // handle non retry results for both create_ephemeral_session_pse_cse() calls below
- }
- // else log failure, since we're returning here
- switch (retValue)
- {
- case AESM_SUCCESS: // handled above
- case AESM_BUSY: // don't log an error here
- break;
- case AESM_PROXY_SETTING_ASSIST: // don't log an error here
- break;
- case AESM_UPDATE_AVAILABLE:
- AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_FAIL_PSWVER]);
- break;
- case AESM_OUT_OF_EPC:
- AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_FAIL]);
- break;
- case AESM_LONG_TERM_PAIRING_FAILED:
- default:
- AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_FAIL_LTP]);
- break;
- }
- AESM_DBG_ERROR("Ephemeral session failed");
- return retValue;
- }
- default:
- goto exit; // handle non retry cases for both create_ephemeral_session_pse_cse() calls below
- }
- //All error code handled
- exit:
- // Log result of create_ephemeral_session_pse_cse() and map return value
- switch (ret)
- {
- case AE_SUCCESS:
- AESM_LOG_INFO_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_SUCCESS]);
- AESM_DBG_INFO("PSEOPAESMLogic::establish_ephemeral_session success");
- return AESM_SUCCESS;
- case AESM_AE_OUT_OF_EPC:
- AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_FAIL]);
- AESM_DBG_ERROR("Ephemeral session failed");
- return AESM_OUT_OF_EPC;
- case PSE_PAIRING_BLOB_UNSEALING_ERROR:
- case PSE_PAIRING_BLOB_INVALID_ERROR:
- case PSE_OP_ERROR_EPH_SESSION_ESTABLISHMENT_INTEGRITY_ERROR:
- case PSE_OP_LTPB_SEALING_OUT_OF_DATE:
- AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_FAIL_LTP]);
- AESM_DBG_ERROR("Ephemeral session failed");
- return AESM_EPH_SESSION_FAILED;
- case AESM_PSDA_NEED_REPAIRING:
- case AESM_PSDA_INTERNAL_ERROR:
- case AESM_PSDA_SESSION_LOST:
- // This is logged as an ERROR here, since we know the system is expecting PS capability at this point
- AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_FAIL_DAL]);
- AESM_DBG_ERROR("Ephemeral session failed");
- return AESM_EPH_SESSION_FAILED;
- case AE_FAILURE:
- case AE_OUT_OF_MEMORY_ERROR:
- default:
- AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_FAIL]);
- AESM_DBG_ERROR("Ephemeral session failed");
- return AESM_EPH_SESSION_FAILED;
- }
- }
- aesm_error_t PSEOPAESMLogic::exchange_report(
- uint32_t session_id,
- const uint8_t* se_dh_msg2, uint32_t se_dh_msg2_size,
- uint8_t* se_dh_msg3, uint32_t se_dh_msg3_size)
- {
- aesm_error_t ret = AESM_UNEXPECTED_ERROR;
- // prepare for service request
- ret = prepare_for_ps_request();
- if (ret != AESM_SUCCESS)
- return ret;
- ae_error_t ret_pse = CPSEClass::instance().exchange_report(
- session_id,
- const_cast<uint8_t *>(se_dh_msg2),se_dh_msg2_size,
- se_dh_msg3,se_dh_msg3_size);
- if (ret_pse == PSE_OP_EPHEMERAL_SESSION_INVALID)
- {
- AESM_DBG_ERROR("Ephemeral session is broken");
- // Ephemeral session is broken , re-establish ephemeral session and retry exchange_report.
- aesm_error_t result = AESM_UNEXPECTED_ERROR;
- if ((result = establish_ephemeral_session(true)) != AESM_SUCCESS) {
- AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_ERROR]);
- return result;
- }
- AESM_DBG_INFO("Exchange report again");
- // If CPSECLass:exchange_report() returned PSE_OP_EPHMERAL_SESSIOn_INVALID because PSE-Op loss,
- // the retry here will fail too, as the session is also lost when enclave is lost.
- ret_pse = CPSEClass::instance().exchange_report(
- session_id,
- const_cast<uint8_t *>(se_dh_msg2),se_dh_msg2_size,
- se_dh_msg3,se_dh_msg3_size);
- }
- log_admin_ps_ae(ret_pse);
- return pse_ret_to_aesm_ret(ret_pse);
- }
- aesm_error_t PSEOPAESMLogic::invoke_service(
- const uint8_t* pse_message_req, uint32_t pse_message_req_size,
- uint8_t* pse_message_resp, uint32_t pse_message_resp_size)
- {
- aesm_error_t result;
- // prepare for service request
- result = prepare_for_ps_request();
- if (result != AESM_SUCCESS)
- return result;
- ae_error_t ret_pse = CPSEClass::instance().invoke_service(
- const_cast<uint8_t *>(pse_message_req),pse_message_req_size,
- pse_message_resp,pse_message_resp_size);
- if (ret_pse == PSE_OP_EPHEMERAL_SESSION_INVALID || ret_pse == AESM_PSDA_SESSION_LOST)
- {
- AESM_DBG_ERROR("Ephemeral session is broken");
- // Ephemeral session is broken , re-establish ephemeral session and retry invoke_service.
- if ((result = establish_ephemeral_session(true)) != AESM_SUCCESS) {
- AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_ERROR]);
- return result;
- }
- AESM_DBG_INFO("Invoke service again");
- // If CPSECLass:invoke_service() returned PSE_OP_EPHEMERAL_SESSION_INVALID because PSE-Op loss,
- // the retry here will fail too, as the session is also lost when enclave is lost.
- ret_pse = CPSEClass::instance().invoke_service(
- const_cast<uint8_t *>(pse_message_req),pse_message_req_size,
- pse_message_resp,pse_message_resp_size);
- }
- log_admin_ps_ae(ret_pse);
- return pse_ret_to_aesm_ret(ret_pse);
- }
- aesm_error_t PSEOPAESMLogic::close_session(
- uint32_t session_id)
- {
- ae_error_t ret_pse = CPSEClass::instance().close_session(
- session_id);
- if (ret_pse == PSE_OP_EPHEMERAL_SESSION_INVALID)
- {
- AESM_DBG_ERROR("Ephemeral session is broken");
- // Ephemeral session is broken , re-establish ephemeral session
- aesm_error_t result = AESM_UNEXPECTED_ERROR;
- if ((result = establish_ephemeral_session(true)) != AESM_SUCCESS)
- return result;
- // Here PSE_OP_EPHEMERAL_SESSION_INVALID is returned only when power event occurs,
- // and the session is also lost when enclave is lost, so always return SUCCESS
- ret_pse = AE_SUCCESS;
- }
- return pse_ret_to_aesm_ret(ret_pse);
- }
|