Exemple #1
0
ae_error_t Helper::LoadCertificateChain( /*out*/ std::list<upse::Buffer>& certChain)
{
    ae_error_t status = AESM_PSE_PR_CERT_LOAD_ERROR;

    char* szParseString = NULL;

    do
    {
        // Read the delimited file of certificate names
        upse::Buffer certChainListBuffer;
        if (AE_SUCCESS != upsePersistentStorage::Read(PSE_PR_CERTIFICATE_CHAIN_FID, certChainListBuffer))
            break;

        szParseString = (char*)calloc(1, certChainListBuffer.getSize() + 1);
        if (NULL == szParseString)
            break;

        memcpy_s(szParseString,  certChainListBuffer.getSize(), certChainListBuffer.getData(), certChainListBuffer.getSize());
        szParseString[certChainListBuffer.getSize()] = '\0';

        char* nextToken = NULL;
        char* szCertificateNamePostfix = get_next_token(szParseString, TOKEN_SEPARATOR, &nextToken); 

        // For each certificate name, read the certificate and save in list
        aesm_data_id_t fileid = PSE_PR_CERTIFICATE_FID;
        while (NULL != szCertificateNamePostfix)
        {
            upse::Buffer cert;
            if (AE_SUCCESS != upsePersistentStorage::Read(fileid++, cert))
            {
                break;
            }
            if (PSE_PR_CERTIFICATE_FID_MAX == fileid)
            {
                break;
            }

            certChain.push_back(cert);

            szCertificateNamePostfix = get_next_token(NULL, TOKEN_SEPARATOR, &nextToken);
        }

        if (NULL != szCertificateNamePostfix)
        {
            break;
        }

        status = AE_SUCCESS;

    } while (0);

    if (NULL != szParseString)
    {
        free(szParseString);
    }

    SGX_DBGPRINT_PRINT_FUNCTION_AND_RETURNVAL(__FUNCTION__, status);

    return status;
}
//*********************************************************************
// Main engine routine for Certificate Chain Provisioning
//*********************************************************************
ae_error_t certificate_chain_provisioning(const endpoint_selection_infos_t& es_info, platform_info_blob_wrapper_t* pib_wrapper)
{
    ae_error_t status = AE_FAILURE;
    AESM_DBG_TRACE("enter fun");

    try
    {
        do
        {

            status = do_certificate_chain_provisioning(es_info, pib_wrapper);

            if (status == PSE_PR_ENCLAVE_LOST_ERROR)
            {
                //
                // went to sleep while in enclave
                // in this case (beginning of flow), we should just retry, after first destroying and then reloading
                // note that this code gets significantly more complicated if the PSE-pr ever becomes multi-threaded
                //
                for (unsigned rcount = 0; rcount < PSEPR_LOST_ENCLAVE_RETRY_COUNT; rcount++)
                {
                    CPSEPRClass::instance().unload_enclave();
                    if (0 != CPSEPRClass::instance().load_enclave())
                    {
                        status = AE_FAILURE;
                        break;
                    }
                    SaveEnclaveID(CPSEPRClass::instance().GetEID());

                    status = do_certificate_chain_provisioning(es_info, pib_wrapper);
                    if (status != PSE_PR_ENCLAVE_LOST_ERROR)
                        break;
                }
            }

            BREAK_IF_FAILED(status);

            status = AE_SUCCESS;

        } while (0);
    }
    catch (...)
    {
        status = AESM_PSE_PR_EXCEPTION;
    }

    SGX_DBGPRINT_PRINT_FUNCTION_AND_RETURNVAL(__FUNCTION__, status);
    SGX_DBGPRINT_PRINT_ANSI_STRING("End Certificate Chain Provisioning");
    return status;
}
//*********************************************************************
// Call quoting enclave to convert report to name-based quote
//*********************************************************************
static ae_error_t do_get_quote
    (
    /*in */ upse::Buffer& reportBuffer,
    /*in */ upse::Buffer& sigRLBuffer,
    /*out*/ upse::Buffer& quoteBuffer
    )
{
    // Call QE to convert REPORT to a name-based QUOTE
    ae_error_t status = AE_FAILURE;
    ae_error_t tmp_status = AE_SUCCESS;

    do
    {
#ifndef FAKE_QUOTE
        uint32_t nQuote;                                 // in     - Quote buffer size

        sgx_report_t enclaveReport;                      // in
        sgx_quote_sign_type_t quote_type;                // in
        sgx_spid_t spid = {{0}};                           // in
        uint8_t* pSigRL = NULL;                          // in
        uint32_t nSigRL = 0;                               // in     - Sig RL buffer size

        memset(&enclaveReport, 0, sizeof(enclaveReport));

        nSigRL = sigRLBuffer.getSize();

        if (0 != nSigRL)
            pSigRL = const_cast<uint8_t*>(sigRLBuffer.getData());

        if (SGX_SUCCESS != sgx_calc_quote_size(pSigRL, nSigRL, &nQuote))
            break;

        tmp_status = quoteBuffer.Alloc(nQuote);
        if (AE_FAILED(tmp_status))
            break;
        upse::BufferWriter bwQuote(quoteBuffer);
        uint8_t* pQuote;
        tmp_status = bwQuote.reserve(nQuote, &pQuote);      // out
        if (AE_FAILED(tmp_status))
            break;

        quote_type = SGX_UNLINKABLE_SIGNATURE; // or SGX_LINKABLE_SIGNATURE

        // LSB16(SHA256("SGX PSE PROVISIONING SERVER"))
        // const char* SPID_VALUE = "SGX PSE PROVISIONING SERVER";
        // sgx_sha256_hash_t spid_hash;
        // sgx_sha256_msg((const uint8_t*)SPID_VALUE, strlen(SPID_VALUE), &spid_hash);
        // memcpy_s(spid.id, sizeof(spid.id), &spid_hash[0], 16);
        static uint8_t spid_hash[] = { 0x32, 0x81, 0xE5, 0x9E, 0xB1, 0x23, 0xFA, 0xCD,
            0x56, 0xDB, 0x62, 0x1E, 0x3B, 0x37, 0xFB, 0xE2 };
        memcpy_s(spid.id, sizeof(spid.id), spid_hash, sizeof(spid_hash));

        if (reportBuffer.getSize() != sizeof(enclaveReport))
            break;

        memcpy_s(&enclaveReport, reportBuffer.getSize(), reportBuffer.getData(), reportBuffer.getSize());
        aesm_error_t result;
        result = AESMLogic::get_quote(
            (uint8_t*)&enclaveReport, sizeof(enclaveReport),
            quote_type,
            (uint8_t*)&spid, sizeof(spid),
            NULL, 0,
            pSigRL, nSigRL,
            NULL, 0,
            (uint8_t*)pQuote, nQuote);
        if (result == AESM_BUSY)
        {
            //EPID_PROVISION triggered, make sure previous EPID provision has finished
            ae_error_t temp_ret = wait_pve_thread();
            BREAK_IF_TRUE(AE_SUCCESS != temp_ret , status, PSE_PR_PCH_EPID_UNKNOWN_ERROR);
            //redo get_quote
            result = AESMLogic::get_quote(
                (uint8_t*)&enclaveReport, sizeof(enclaveReport),
                quote_type,
                (uint8_t*)&spid, sizeof(spid),
                NULL, 0,
                pSigRL, nSigRL,
                NULL, 0,
                (uint8_t*)pQuote, nQuote);
        }
        BREAK_IF_TRUE(AESM_OUT_OF_EPC == result, status, AESM_AE_OUT_OF_EPC);
        BREAK_IF_TRUE(AESM_SUCCESS != result, status, AESM_PSE_PR_GET_QUOTE_ERROR);
#else
        const uint16_t SIGNATURE_LENGTH = 32;

        tmp_status = quoteBuffer.Alloc(sizeof(sgx_quote_t) + SIGNATURE_LENGTH);
        if (AE_FAILED(tmp_status))
            break;

        sgx_quote_t* pQuote;
        tmp_status = upse::BufferWriter(quoteBuffer).reserve(quoteBuffer.getSize(), (uint8_t**)&pQuote);
        if (AE_FAILED(tmp_status))
            break;

        uint16_t CPUSVN = 1;
        pQuote->version = 1;
        memcpy_s(pQuote->epid_group_id, sizeof(pQuote->epid_group_id), &GID_TO_USE, sizeof(GID_TO_USE));
        pQuote->report_body.isv_prod_id = 0x0002; //0x8086;
        pQuote->report_body.isv_svn = 1;
        memcpy_s(pQuote->report_body.cpu_svn, sizeof(pQuote->report_body.cpu_svn), &CPUSVN, sizeof(CPUSVN));

        const sgx_report_t* pReport = (sgx_report_t*)reportBuffer.getData();

        memcpy_s(pQuote->report_body.report_data, sizeof(pQuote->report_body.report_data), pReport->body.report_data, sizeof(pQuote->report_body.report_data));

        pQuote->signature_len = SIGNATURE_LENGTH;

        //NOTE: The signature is not valid when doing a FAKE_QUOTE
#endif

        status = AE_SUCCESS;

    } while (0);

    if ((AE_FAILURE == status) && AE_FAILED(tmp_status))
        status = tmp_status;

    SGX_DBGPRINT_PRINT_FUNCTION_AND_RETURNVAL(__FUNCTION__, status);

    return status;
}
//*********************************************************************
// Call quoting enclave to get target info
//*********************************************************************
static ae_error_t do_quote_initialization
    (
    /*out */ upse::Buffer& targetInfo,
    /*out */ GroupId* pGID
    )
{
    ae_error_t status = AE_FAILURE;


    do
    {
        BREAK_IF_TRUE( (NULL == pGID), status, PSE_PR_BAD_POINTER_ERROR);

#ifndef FAKE_QUOTE
        if (AE_FAILED(targetInfo.Alloc(sizeof(sgx_target_info_t))))
            break;
        upse::BufferWriter bwTargetInfo(targetInfo);
        uint8_t* p;
        status = bwTargetInfo.reserve(sizeof(sgx_target_info_t), &p);
        if (AE_FAILED(status))
            break;
        sgx_target_info_t* pTargetInfo = (sgx_target_info_t*)p;

        aesm_error_t result;
        SGX_DBGPRINT_PRINT_ANSI_STRING("aesmLogic.init_quote?");

        result = AESMLogic::init_quote(
            (uint8_t*)pTargetInfo, sizeof(sgx_target_info_t),
            (uint8_t*)pGID, sizeof(*pGID));
        if (result == AESM_BUSY)
        {
            //EPID_PROVISION triggered, make sure previous EPID provision has finished
            ae_error_t temp_ret = wait_pve_thread();
            BREAK_IF_TRUE(AE_SUCCESS != temp_ret , status, PSE_PR_PCH_EPID_UNKNOWN_ERROR);
            //redo init_quote
            result = AESMLogic::init_quote(
                (uint8_t*)pTargetInfo, sizeof(sgx_target_info_t),
                (uint8_t*)pGID, sizeof(*pGID));
        }
        BREAK_IF_TRUE(AESM_UPDATE_AVAILABLE == result, status, PSW_UPDATE_REQUIRED);
        BREAK_IF_TRUE(AESM_OUT_OF_EPC == result, status, AESM_AE_OUT_OF_EPC);
        BREAK_IF_TRUE(AESM_SUCCESS != result, status, AESM_PSE_PR_INIT_QUOTE_ERROR);
#else

        //NRG: m_tmpGID = 0;
        upse::Buffer m_tmpGID;
        if (AE_FAILED(m_tmpGID.Alloc(GID_TO_USE, sizeof(GID_TO_USE))))
            break;

        //      m_tmpGID = 1244;
        //      upse::BufferWriter(m_tmpGID).writeRaw(GID_TO_USE, sizeof(GID_TO_USE));
        SigmaData::SetGID(m_tmpGID);
        memcpy_s(pGID, sizeof(GroupId), m_tmpGID.getData(), sizeof(GroupId));
        if (AE_FAILED(targetInfo.Alloc(sizeof(sgx_target_info_t))))
            break;
#endif

        SGX_DBGPRINT_PRINT_ANSI_STRING("aesmLogic.init_quote success");
        status = AE_SUCCESS;

    } while (0);

    SGX_DBGPRINT_PRINT_FUNCTION_AND_RETURNVAL(__FUNCTION__, status);

    return status;
}
Exemple #5
0
ae_error_t Helper::PrepareCertificateChainVLR( /*in*/ std::list<upse::Buffer>& certChain, /*out*/ upse::Buffer& certChainVLR)
{
    ae_error_t status = AESM_PSE_PR_LOAD_VERIFIER_CERT_ERROR;

    try
    {
        do
        {
            int nPaddedBytes = 0;
            int nCertChain = 0;

#if !defined(LEAFTOROOT)
#error LEAFTOROOT not #defined
#endif

            //
            // spec'd behavior is to receive certs in leaft to root order
            // then, it only makes sense to store them leaf to root
            // but sigma wants them root to leaf
            // we'll leave the #if here since, cumulatively, it shows how to traverse
            // in both directions
            //
#if !LEAFTOROOT
            SGX_DBGPRINT_PRINT_STRING_LTP("leaf cert to root cert direction, padding");

            std::list<upse::Buffer>::reverse_iterator it;
            for (it = certChain.rbegin(); it != certChain.rend(); ++it)
            {
                int nSize = (*it).getSize();
                nPaddedBytes += REQUIRED_PADDING_DWORD_ALIGNMENT(nSize);
                nCertChain += nSize;
            }
#else
            SGX_DBGPRINT_PRINT_STRING_LTP("root cert to leaf cert direction, padding");
            std::list<upse::Buffer>::iterator it;
            for (it = certChain.begin(); it != certChain.end(); ++it)
            {
                int nSize = (*it).getSize();
                nPaddedBytes += REQUIRED_PADDING_DWORD_ALIGNMENT(nSize);
                nCertChain += nSize;
            }
#endif

            SGX_DBGPRINT_PRINT_STRING_LTP("less cert padding");
            //NRG: This doesn't work, but should. It should replace the previous
            nPaddedBytes = REQUIRED_PADDING_DWORD_ALIGNMENT(nCertChain);

            if(UINT16_MAX - ((int)sizeof(SIGMA_VLR_HEADER) + nPaddedBytes) < nCertChain){
                break;
            }
            int nLength = static_cast<int>(sizeof(SIGMA_VLR_HEADER)) + nPaddedBytes + nCertChain;

            certChainVLR.Alloc(nLength);

            upse::BufferWriter bw(certChainVLR);
            VERIFIER_CERT_CHAIN_VLR* pVLR;
            uint8_t* p;
            if (AE_FAILED(bw.reserve(nLength, &p)))
                break;
            pVLR = (VERIFIER_CERT_CHAIN_VLR*)p;

            pVLR->VlrHeader.ID = VERIFIER_CERTIFICATE_CHAIN_VLR_ID;
            pVLR->VlrHeader.PaddedBytes = (UINT8)nPaddedBytes;
            pVLR->VlrHeader.Length = (UINT16)nLength;

            memset(pVLR->VerifierCertificateChain, 0, nPaddedBytes + nCertChain);
            int ndx = 0;

            //
            // see above 
            //
#if (!LEAFTOROOT)
            SGX_DBGPRINT_PRINT_STRING_LTP("leaf cert to root cert direction");
            for (it = certChain.rbegin(); it != certChain.rend(); ++it)
            {
                memcpy_s(pVLR->VerifierCertificateChain + ndx, (*it).getSize(), (*it).getData(), (*it).getSize());
                ndx += (*it).getSize();
            }
#else
            SGX_DBGPRINT_PRINT_STRING_LTP("root cert to leaf cert direction");
            for (it = certChain.begin(); it != certChain.end(); ++it)
            {
                memcpy_s(pVLR->VerifierCertificateChain + ndx, (*it).getSize(), (*it).getData(), (*it).getSize());
                ndx += (*it).getSize();
            }
#endif

            status = AE_SUCCESS;

        } while (0);
    } catch(...)
    {
    }

    SGX_DBGPRINT_PRINT_FUNCTION_AND_RETURNVAL(__FUNCTION__, status);
    return status;
}
Exemple #6
0
ae_error_t Helper::SaveCertificateChain( /*in */ std::list<upse::Buffer>& certChain)
{
    ae_error_t status = AESM_PSE_PR_CERT_SAVE_ERROR;

    char* szParseString = NULL; 
    int nLen, pos=0;

    do
    {
        RemoveCertificateChain();

        // Allocate enough space for the list of names and separator character
        if(((size_t)(INT32_MAX-1))/sizeof(CERT_FILENAME_POSTFIX_FORMAT) < certChain.size() )
            break;
        int nBytes = static_cast<int>(certChain.size() * sizeof(CERT_FILENAME_POSTFIX_FORMAT)) + 1;
        szParseString = (char*)calloc(1, nBytes);
        if (NULL == szParseString)
        {
            break;
        }

        char* szNextCertNamePostfix = szParseString;

        int fileNo = 0;
        char szFilenamePostfix[80];
        std::list<upse::Buffer>::iterator it = certChain.begin();
        aesm_data_id_t fileid = PSE_PR_CERTIFICATE_FID;
        while (it != certChain.end())
        {
            nLen = sprintf_s(szFilenamePostfix, sizeof(szFilenamePostfix), CERT_FILENAME_POSTFIX_FORMAT, ++fileNo);
            if (AE_SUCCESS != upsePersistentStorage::Write(fileid++, *it))
            {
                break;
            }
            if (PSE_PR_CERTIFICATE_FID_MAX == fileid)
            {
                break;
            }

            strcpy_s(szNextCertNamePostfix, nBytes-pos, szFilenamePostfix);
            pos += nLen;
            szNextCertNamePostfix += nLen;

            ++it;
            if (it != certChain.end())
            {
                if (pos >= nBytes)
                {
                    break;
                }
                *szNextCertNamePostfix = ';';
                pos++;
                ++szNextCertNamePostfix;
            }
        }

        if ((szNextCertNamePostfix - szParseString) > nBytes)
        {
            break;
        }
        nBytes = static_cast<int>(szNextCertNamePostfix - szParseString);
        upse::Buffer nameListBuffer;
        if (AE_FAILED(nameListBuffer.Alloc(nBytes)))
            break;
        upse::BufferWriter bw(nameListBuffer);
        bw.writeRaw((uint8_t*)szParseString, nBytes);
        if (AE_SUCCESS != upsePersistentStorage::Write(PSE_PR_CERTIFICATE_CHAIN_FID, nameListBuffer))
        {
            break;
        }

        status = AE_SUCCESS;

    } while (0);

    if (NULL != szParseString)
    {
        free(szParseString);
    }

    SGX_DBGPRINT_PRINT_FUNCTION_AND_RETURNVAL(__FUNCTION__, status);

    return status;
}
Exemple #7
0
ae_error_t Helper::RemoveCertificateChain()
{
    ae_error_t status = AESM_PSE_PR_CERT_DELETE_ERROR;

    char* szParseString = NULL;
    int nError = 0;

    do
    {
        // Read the delimited file of certificate names
        upse::Buffer certChainListBuffer;
        if (AE_SUCCESS != upsePersistentStorage::Read(PSE_PR_CERTIFICATE_CHAIN_FID, certChainListBuffer))
        {
            break;
        }

        szParseString = (char*) calloc(1, certChainListBuffer.getSize() + 1);
        if (NULL == szParseString)
        {
            break;
        }

        memcpy_s(szParseString, certChainListBuffer.getSize(), certChainListBuffer.getData(), certChainListBuffer.getSize());
        szParseString[certChainListBuffer.getSize()] = '\0';

        char* nextToken = NULL;
        char* szCertificateNamePostfix = get_next_token(szParseString, TOKEN_SEPARATOR, &nextToken); 

        aesm_data_id_t fileid = PSE_PR_CERTIFICATE_FID;
        // For each certificate name, delete the file
        while (NULL != szCertificateNamePostfix)
        {
            if (AE_SUCCESS != upsePersistentStorage::Delete(fileid++))
            {
                ++nError;
            }
            if (PSE_PR_CERTIFICATE_FID_MAX == fileid)
            {
                break;
            }
            szCertificateNamePostfix = get_next_token(NULL, TOKEN_SEPARATOR, &nextToken);
        }

        if (PSE_PR_CERTIFICATE_FID_MAX == fileid)
        {
            break;
        }
        if (AE_SUCCESS != upsePersistentStorage::Delete(PSE_PR_CERTIFICATE_CHAIN_FID))
        {
            ++nError;
        }

        if (0 != nError)
        {
            break;
        }

        status = AE_SUCCESS;
    } while (0);

    if (NULL != szParseString)
    {
        free(szParseString);
    }

    SGX_DBGPRINT_PRINT_FUNCTION_AND_RETURNVAL(__FUNCTION__, status);

    return status;
}
Exemple #8
0
ae_error_t SigmaHelper::GetOcspResponseFromServer
    (
    /*in */ const std::list<upse::Buffer>& certChain,
    /*in */ const OCSP_REQ& ocspReq,
    /*out*/ upse::Buffer& ocspResp
    )
{
    ae_error_t status = AE_FAILURE;

    int nPaddedBytes = 0;
    int nTotalOcspBytes = 0;

    do
    {
        if (ocspReq.ReqType == NO_OCSP)
        {
            status = AE_SUCCESS;
            break;
        }

        const char *url  = EndpointSelectionInfo::instance().get_server_url( PSE_OCSP);
        if (url == NULL){
            return OAL_CONFIG_FILE_ERROR;
        }

        // Load the root certificate into a local buffer
        upse::Buffer rootCert;
        SigmaHelper::GetRootCA(rootCert);

        std::list<upse::Buffer> ocspResponseList;

        // loop through chain and get an OCSP Response for each certificate/issuer pair
        bool fDone = false;
        //
        // certs were added leaf to root direction (assuming server functions according to spec)
        //
        std::list<upse::Buffer>::const_iterator itCertificate = certChain.begin();
        do
        {
            if (itCertificate == certChain.end())
            {
                status = AE_FAILURE;
                break;
            }

            upse::Buffer ocspResponse;
            const upse::Buffer& verifierCertificate = *itCertificate;

            ++itCertificate;

            int busy_loop = 0;
            do
            {
                if (itCertificate != certChain.end())
                {
                    const upse::Buffer& issuerCertificate = *itCertificate;
                    status = Get_OCSPResponse(url, &ocspReq.OcspNonce, verifierCertificate, issuerCertificate, ocspResponse);
                }
                else
                {
                    fDone = true;
                    const upse::Buffer& issuerCertificate = rootCert;
                    status = Get_OCSPResponse(url, &ocspReq.OcspNonce, verifierCertificate, issuerCertificate, ocspResponse);
                }

                if (AESM_PSE_PR_OCSP_RESPONSE_STATUS_TRYLATER != status)
                    break;

                se_sleep(OCSP_BUSY_RETRY_SLEEP_MILLISECONDS);

            } while (busy_loop++ < MAX_OCSP_BUSY_RETRIES);

            if (AE_FAILED(status))
                break;

            nPaddedBytes += REQUIRED_PADDING_DWORD_ALIGNMENT(ocspResponse.getSize());
            nTotalOcspBytes += ocspResponse.getSize();

            ocspResponseList.push_back(ocspResponse);

        } while (!fDone);

        if (AE_FAILED(status))
            break;

        if (0 == ocspResponseList.size())
        {
            status = AE_FAILURE;
            break;
        }


        nPaddedBytes = REQUIRED_PADDING_DWORD_ALIGNMENT(nTotalOcspBytes);
        if(UINT16_MAX-((int)sizeof(SIGMA_VLR_HEADER) + nPaddedBytes) < nTotalOcspBytes){
            status = AE_FAILURE;
            break;
        }
        int nLength = static_cast<int>(sizeof(SIGMA_VLR_HEADER)) + nPaddedBytes + nTotalOcspBytes;

        ocspResp.Alloc(nLength);

        upse::BufferWriter bw(ocspResp);
        uint8_t* p;
        status = bw.reserve(nLength, &p);
        if (AE_FAILED(status))
            break;
        OCSP_RESPONSE_VLR* pVLR = (OCSP_RESPONSE_VLR*)p;

        pVLR->VlrHeader.ID = OCSP_RESPONSE_VLR_ID;
        pVLR->VlrHeader.PaddedBytes = (UINT8)nPaddedBytes;
        pVLR->VlrHeader.Length = (UINT16)nLength;

        memset(pVLR->OcspResponse, 0, nPaddedBytes + nTotalOcspBytes);

        int nNext = 0;

        //
        // order above doesn't really matter since it's between verifier/host and ocsp responder
        // and each request/response is independent
        // spec basically says what's correct here
        // but we'll leave condition to show how to traverse in either order
        //
#if !defined(LEAFTOROOT)
#error LEAFTOROOT not defined
#endif

#if !LEAFTOROOT
        //
        // this clause adds responses from root to leaf
        //
        SGX_DBGPRINT_PRINT_STRING_LTP("root ocsp to leaf ocsp direction");
        std::list<upse::Buffer>::reverse_iterator itRespList = ocspResponseList.rbegin();
        for ( ; itRespList != ocspResponseList.rend(); ++itRespList)
        {
            const upse::Buffer& item = *itRespList;
            memcpy_s(pVLR->OcspResponse + nNext, item.getSize(), item.getData(), item.getSize());
            nNext += item.getSize();
        }
#else
        SGX_DBGPRINT_PRINT_STRING_LTP("leaf ocsp to root ocsp direction");

        //
        // this clause adds responses from leaf to root
        //
        std::list<upse::Buffer>::iterator itRespList = ocspResponseList.begin();
        for ( ; itRespList != ocspResponseList.end(); ++itRespList)
        {
            const upse::Buffer& item = *itRespList;
            memcpy_s(pVLR->OcspResponse + nNext, item.getSize(), item.getData(), item.getSize());
            nNext += item.getSize();
        }
#endif

        Helper::write_ocsp_response_vlr(ocspResp);

        status = AE_SUCCESS;

    } while (0);

    if (status == OAL_NETWORK_UNAVAILABLE_ERROR)
    {
        if (ocspReq.ReqType == CACHED && AE_SUCCEEDED(Helper::read_ocsp_response_vlr(ocspResp)))
        {
            status = AE_SUCCESS;
        }
    }

    SGX_DBGPRINT_PRINT_FUNCTION_AND_RETURNVAL(__FUNCTION__, status);

    return status;
}