void WinHttpConnection::callback_status_request_error()

in Source/HTTP/WinHttp/winhttp_connection.cpp [599:683]


void WinHttpConnection::callback_status_request_error(
    _In_ HINTERNET hRequestHandle,
    _In_ WinHttpConnection* pRequestContext,
    _In_ void* statusInfo)
{
    WINHTTP_ASYNC_RESULT *error_result = reinterpret_cast<WINHTTP_ASYNC_RESULT *>(statusInfo);
    if (error_result == nullptr)
        return;

    DWORD errorCode = error_result->dwError;
    HC_TRACE_ERROR(HTTPCLIENT, "HCHttpCallPerform [ID %llu] [TID %ul] WINHTTP_CALLBACK_STATUS_REQUEST_ERROR dwResult=%d dwError=%d", TO_ULL(HCHttpCallGetId(pRequestContext->m_call)), GetCurrentThreadId(), error_result->dwResult, error_result->dwError);

    bool reissueSend{ false };

    if (error_result->dwError == ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED)
    {
        SecPkgContext_IssuerListInfoEx* pIssuerList{ nullptr };
        DWORD dwBufferSize{ sizeof(void*) };

        if (WinHttpQueryOption(
            hRequestHandle,
            WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST,
            &pIssuerList,
            &dwBufferSize
        ))
        {
            PCERT_CONTEXT pClientCert{ nullptr };
            PCCERT_CHAIN_CONTEXT pClientCertChain{ nullptr };

            CERT_CHAIN_FIND_BY_ISSUER_PARA searchCriteria{};
            searchCriteria.cbSize = sizeof(CERT_CHAIN_FIND_BY_ISSUER_PARA);
            searchCriteria.cIssuer = pIssuerList->cIssuers;
            searchCriteria.rgIssuer = pIssuerList->aIssuers;

            HCERTSTORE hCertStore = CertOpenSystemStore(0, L"MY");
            if (hCertStore)
            {
                pClientCertChain = CertFindChainInStore(
                    hCertStore,
                    X509_ASN_ENCODING,
                    CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_URL_FLAG | CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_FLAG,
                    CERT_CHAIN_FIND_BY_ISSUER,
                    &searchCriteria,
                    nullptr
                );

                if (pClientCertChain)
                {
                    pClientCert = (PCERT_CONTEXT)pClientCertChain->rgpChain[0]->rgpElement[0]->pCertContext;

                    // "!!" to cast from BOOL to bool
                    reissueSend = !!WinHttpSetOption(
                        hRequestHandle,
                        WINHTTP_OPTION_CLIENT_CERT_CONTEXT,
                        (LPVOID)pClientCert,
                        sizeof(CERT_CONTEXT)
                    );

                    CertFreeCertificateChain(pClientCertChain);
                }
                CertCloseStore(hCertStore, 0);
            }
            GlobalFree(pIssuerList);
        }
        else
        {
            auto certError = GetLastError();
            HC_TRACE_ERROR(HTTPCLIENT, "WinHttp returned ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED but unable to get cert issuer list, dwError=%d", certError);
        }
    }

    if (reissueSend)
    {
        HRESULT hr = pRequestContext->SendRequest();
        if (FAILED(hr))
        {
            HC_TRACE_ERROR(HTTPCLIENT, "WinHttpConnection Failure to send HTTP request 0x%0.8x", hr);
            pRequestContext->complete_task(E_FAIL, hr);
        }
    }
    else
    {
        pRequestContext->complete_task(E_FAIL, HRESULT_FROM_WIN32(errorCode));
    }
}