ae_error_t CertificateProvisioningProtocol::SendM3_ReceiveM4
(   /*in */ const upse::Buffer& csrBuffer,
    /*in */ const upse::Buffer& quoteBuffer,
    /*out*/ std::list< upse::Buffer >& certificateChainList,
    /*out*/ platform_info_blob_wrapper_t& piBlobWrapper
)
{
    ae_error_t status = AE_FAILURE;

    upse::Buffer serializedMsg3;
    upse::Buffer serializedMsg4;
    AESM_DBG_TRACE("start to send M3");

    do
    {
        BREAK_IF_FALSE((m_is_initialized), status, AESM_PSE_PR_BACKEND_NOT_INITIALIZED);

        BREAK_IF_FALSE( (msg_next_state_M3 == m_nextState), status, AESM_PSE_PR_CALL_ORDER_ERROR);

        status = msg3_generate(csrBuffer, quoteBuffer, serializedMsg3);
        BREAK_IF_FAILED_ERR(status, AESM_PSE_PR_BACKEND_MSG3_GENERATE);
//        BREAK_IF_FAILED(status);
        AESM_DBG_TRACE("M3 generated");
        status = sendReceive(serializedMsg3, serializedMsg4);
        BREAK_IF_FAILED(status);
        AESM_DBG_TRACE("start to process M4");
        status = msg4_process(serializedMsg4, certificateChainList, piBlobWrapper);
        BREAK_IF_FAILED(status);
        AESM_DBG_TRACE("finished M4");
    } while (0);

    m_nextState = msg_next_state_init;

    return status;
}
ae_error_t CertificateProvisioningProtocol::SendM1_ReceiveM2
(   /*in */ const uint32_t gid,
    /*out*/ upse::Buffer& nonce,
    /*out*/ upse::Buffer& sigRLBuffer
)
{
    ae_error_t status = AE_FAILURE;

    upse::Buffer serializedMsg1;
    upse::Buffer serializedMsg2;

    do
    {
        BREAK_IF_FALSE((m_is_initialized), status, AESM_PSE_PR_BACKEND_NOT_INITIALIZED);

        BREAK_IF_FALSE( (msg_next_state_M1 == m_nextState), status, AESM_PSE_PR_CALL_ORDER_ERROR);

        status = msg1_generate(*(const GroupId*)&gid, serializedMsg1);
        BREAK_IF_FAILED_ERR(status, AESM_PSE_PR_BACKEND_MSG1_GENERATE);
//        BREAK_IF_FAILED(status);

        status = sendReceive(serializedMsg1, serializedMsg2);
        if (AE_FAILED(status))
            break;

        status = msg2_process(serializedMsg2, nonce, sigRLBuffer);
        if (AE_FAILED(status))
            break;

        m_nextState = msg_next_state_M3;
    } while (0);

    return status;
}
//*********************************************************************
// Do the certificate chain provisioning logic
//*********************************************************************
static ae_error_t do_certificate_chain_provisioning
    (
    /*in */ const endpoint_selection_infos_t& es_info,
    /*out*/ platform_info_blob_wrapper_t* pib_wrapper
    )
{
    if (NULL == pib_wrapper)
        return AESM_PSE_PR_BAD_POINTER_ERROR;

    ae_error_t status = AE_FAILURE;
    upse::Buffer target_info;

    uint32_t gid = 0;
    //    GroupId gid = {0};                  // Send to Server in M1

    upse::Buffer nonce;                 // Receive from Server in M2
    upse::Buffer sig_rl;                // Receive from Server in M2
    upse::Buffer csr_pse;               // Send to Server in M3
    upse::Buffer quote;                 // Send to Server in M3
    std::list<upse::Buffer> certChain;  // Receive from Server in M4

    upse::Buffer report;                // Received from PSE_pr
    upse::Buffer pairing_blob;          // Received from PSE_pr
    upse::Buffer ocsp_req;              // Created here from cert chain

    const char *szURL = EndpointSelectionInfo::instance().get_pse_provisioning_url(es_info);

    memset(pib_wrapper, 0, sizeof(platform_info_blob_wrapper_t));   // Receive from Server in M4

    CertificateProvisioningProtocol cpp;

    SGX_DBGPRINT_PRINT_ANSI_STRING("Begin Certificate (PSE) Provisioning");
    do
    {
        Helper::RemoveCertificateChain();
        Helper::delete_ocsp_response_vlr();

#if defined(NO_PROVISIONING_SERVER)

        {
            //*********************************************************************
            // Use hardcoded Cert.
            //*********************************************************************
            SGX_DBGPRINT_PRINT_ANSI_STRING("Using Hard Coded Cert");
            status = tPrepareForCertificateProvisioning_hardcoded_privatekey(pairing_blob);
            BREAK_IF_FAILED(status);

            /* Use the hardcoded "Public" Cert */
            upse::Buffer Cert;
            Cert.Alloc(PUBLIC_PSE_CERT_LEN);
            upse::BufferWriter bwCert(Cert);
            uint8_t* pCert;
            status = bwCert.reserve(PUBLIC_PSE_CERT_LEN, &pCert);
            BREAK_IF_FAILED(status);
            memcpy_s(pCert, PUBLIC_PSE_CERT_LEN, PUBLIC_PSE_CERT, PUBLIC_PSE_CERT_LEN);
            certChain.push_back(Cert);

        }

#else

        {

            status = cpp.init(szURL, es_info.pek);
            BREAK_IF_FAILED(status);

            //=====================================================================
            // Start: CERTIFICATE CHAIN PROVISIONING  (3.6.7.1.1.2.1)
            //=====================================================================

            //*********************************************************************
            // Retrieve GID_SE from the QE
            SGX_DBGPRINT_PRINT_ANSI_STRING("quote init?");
            //*********************************************************************
            status = do_quote_initialization(target_info, (GroupId*)&gid);
            BREAK_IF_FAILED(status);//keep reason for quoting failure including UPDATE required
            SGX_DBGPRINT_PRINT_ANSI_STRING("quote init success");

            //*********************************************************************
            // Retrieve SIG_RL and Nonce from Intel Server.
            //*********************************************************************
            status = cpp.SendM1_ReceiveM2(*(uint32_t*)&gid, nonce, sig_rl);
            BREAK_IF_FAILED(status);
            SGX_DBGPRINT_PRINT_ANSI_STRING("send m1, receive m2 success");

            Helper::read_ltp_blob(pairing_blob);
            // Note: failure during read_ltp_blob is okay, pairing_blob will be empty and get filled in by enclave

            //*********************************************************************
            // Generate ECDSA key pair, CSR_pse, and REPORT in enclave (PSE_Pr).
            //*********************************************************************
            status = tPrepareForCertificateProvisioning(nonce, target_info, csr_pse,
                report, pairing_blob);
            BREAK_IF_FAILED(status);
            SGX_DBGPRINT_PRINT_ANSI_STRING("prepare for cert pv success");

            //*********************************************************************
            // Call QE to convert REPORT to name-based QUOTE using SIG_RL
            //*********************************************************************
            status = do_get_quote(report, sig_rl, quote);
            BREAK_IF_TRUE((AESM_AE_OUT_OF_EPC == status), status, AESM_AE_OUT_OF_EPC);
            BREAK_IF_FAILED_ERR(status, AESM_CP_ATTESTATION_FAILURE);
            SGX_DBGPRINT_PRINT_ANSI_STRING("get quote success");

            //*********************************************************************
            // Retrieve the Certificate Chain from Intel Server.
            //*********************************************************************
            status = cpp.SendM3_ReceiveM4(csr_pse, quote, certChain, *pib_wrapper);
            BREAK_IF_TRUE((PSE_PRS_OK != cpp.GetProtocolResponseStatus()), status, AESM_CP_ATTESTATION_FAILURE);
            BREAK_IF_FAILED(status);
            SGX_DBGPRINT_PRINT_ANSI_STRING("send m3, receive m4 success");
        }

#endif

        //*********************************************************************
        // Save the Certificate Chain to persistent storage.
        //*********************************************************************
        status = Helper::SaveCertificateChain(certChain);
        BREAK_IF_FAILED(status);
        SGX_DBGPRINT_PRINT_ANSI_STRING("save cert success");

        //*********************************************************************
        // Save the sealed pairing blob to persistent storage.
        //*********************************************************************
        status = Helper::write_ltp_blob(pairing_blob);
        BREAK_IF_FAILED(status);
        SGX_DBGPRINT_PRINT_ANSI_STRING("write blob success");

        status = AE_SUCCESS;

        SGX_DBGPRINT_PRINT_ANSI_STRING("End of Certificate (PSE) Provisioning");
    } while (0);

    status = ConvertBackendStatus(cpp, status);
    return status;
}