Exemple #1
0
//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;
}
//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;
}