123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- /*
- * Copyright (C) 2011-2016 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 "aesm_epid_blob.h"
- #include "aesm_xegd_blob.h"
- #include "qe_logic.h"
- #include "pve_logic.h"
- #include "aesm_logic.h"
- #include "PVEClass.h"
- #include "QEClass.h"
- #include "se_sig_rl.h"
- #include "se_quote_internal.h"
- #include "se_wrapper.h"
- #include "prof_fun.h"
- #include "util.h"
- static ae_error_t get_qe_target(sgx_target_info_t *p_qe_target)
- {
- ae_error_t ae_ret = AE_SUCCESS;
- if((ae_ret = CQEClass::instance().load_enclave())!=AE_SUCCESS)
- {
- AESM_DBG_ERROR("Fail to load QE:%d",ae_ret);
- return ae_ret;
- }
- ae_ret = static_cast<ae_error_t>(CQEClass::instance().get_qe_target(p_qe_target));
- if(ae_ret != AE_SUCCESS)
- return ae_ret;
- return AE_SUCCESS;
- }
- //Function to do reprovision if flag updated is false and set it to true if updated successfully
- //The flag updated is used to simpilify logic in caller's code so that provision will not be invoked again
- //if a previous provision has been successfully run
- //After reprovision, the output epid_blob will be copied into output parameter epid_data
- static aesm_error_t try_reprovision_if_not(bool& updated, epid_blob_with_cur_psvn_t& epid_data)
- {
- aesm_error_t aesm_result;
- ae_error_t ae_ret;
- if(updated){
- // We've just got a EPID blob. It's a rare case to reach here.
- // No retry, just return error.
- AESM_DBG_ERROR("try to reprovision again after another provision");
- return AESM_EPIDBLOB_ERROR;
- }
- // The EPID blob is corrupted, and we've not provisioned yet, then
- // we need to start the provision process.
- if((aesm_result = PvEAESMLogic::provision(false, THREAD_TIMEOUT))!=AESM_SUCCESS){
-
- AESM_DBG_ERROR("pve provision failed:%d", aesm_result);
- return aesm_result;
- }
- updated = true;
- // Update the epid blob after a successful provisioning.
- if((ae_ret = EPIDBlob::instance().read(epid_data))!=AE_SUCCESS){
- AESM_DBG_ERROR("read epid blob failed:%d", ae_ret);
- return AESM_EPIDBLOB_ERROR;
- }
- return AESM_SUCCESS;
- }
- //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 pce_isv_svn,
- 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));
- uint32_t xegd_xeid = AESMLogic::get_active_extended_epid_group_id();
- AESM_DBG_TRACE("start read and verify old epid blob");
- uint32_t epid_xeid = 0;
- //EPID BLOB not exist
- 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;
- }
- }
- //ExtEPIDGroupID not match
- else if ((ae_ret = epid_blob.get_extended_epid_group_id(&epid_xeid)) == AE_SUCCESS &&
- xegd_xeid != epid_xeid)
- {
- (void)epid_blob.remove();
- 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);
- if(ae_ret == AESM_AE_OUT_OF_EPC)
- aesm_result = AESM_OUT_OF_EPC;
- else
- aesm_result = AESM_UNEXPECTED_ERROR;
- goto ret_point;
- }
- se_static_assert(SGX_TRUSTED_EPID_BLOB_SIZE_SDK>=SGX_TRUSTED_EPID_BLOB_SIZE_SIK);
- ae_ret = static_cast<ae_error_t>(CQEClass::instance().verify_blob(epid_data.trusted_epid_blob,
- SGX_TRUSTED_EPID_BLOB_SIZE_SDK,
- &resealed));
- if(ae_ret == QE_EPIDBLOB_ERROR){
- (void)epid_blob.remove();
- if(AESM_SUCCESS!=(aesm_result = try_reprovision_if_not(updated, epid_data))){
- goto ret_point;
- }
- }
- else if(ae_ret == AESM_AE_OUT_OF_EPC)
- {
- aesm_result = AESM_OUT_OF_EPC;
- 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);
- ae_ret = get_qe_target(target);
- if(ae_ret!=AE_SUCCESS){
- AESM_DBG_ERROR("get qe target failed");
- if(ae_ret==AESM_AE_OUT_OF_EPC)
- aesm_result = AESM_OUT_OF_EPC;
- else
- 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 after all Quoting Enclave works
- AESM_DBG_TRACE("qe_isv_svn %d, epid_isv_svn %d",qe_isv_svn, epid_data.cur_pi.pve_svn);
- if((qe_isv_svn > epid_data.cur_pi.pve_svn)
- || (pce_isv_svn > epid_data.cur_pi.pce_svn)
- || (0!=memcmp(&qe_cpu_svn, &epid_data.cur_pi.cpu_svn,
- sizeof(sgx_cpu_svn_t))))
- {
-
- 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;
- }
- /* 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, uint16_t pce_isv_svn)
- {
- 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((ae_ret = CQEClass::instance().load_enclave())!=AE_SUCCESS)
- {
- AESM_DBG_ERROR("load QE failed");
- if(ae_ret == AESM_AE_OUT_OF_EPC)
- aesm_result = AESM_OUT_OF_EPC;
- else
- 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_SDK,
- 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, pce_isv_svn);
- 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;
- }
|