Client Certificates in WinHTTP
-
I need to send a client certificate with a web request (via SSL). This client cert is just a public key. I am trying to replicate the Request.ClientCertificates.Add(Cert); .NET method using C++/WinHTTP. I am loading the .cer file successfully and setting the CERT_CONTEXT via WinHttpSetOption/WINHTTP_OPTION_CLIENT_CERT_CONTEXT. This call succeeds, but when I call WinHttpSendRequest, it fails with ERROR_WINHTTP_CLIENT_CERT_NO_PRIVATE_KEY (12185). So, the question is, how do I send a client cert public key to the server, as the ClientCertificates.Add method does in .NET? Code snippet sample below:
BOOL HTTPCallEx::SendHTTPRequest(int iVerb /*=HTTPCALL_GET*/, LPCTSTR cpUID /*=NULL*/, LPCTSTR cpPWD /*=NULL*/)
{
WCHAR wcaVerb[16];
WCHAR wcaResource[1024];m_dwLastError = 0;
switch (iVerb)
{
case HTTPCALL_POST:
lstrcpyW(wcaVerb,L"POST");
break;case HTTPCALL\_HEAD: lstrcpyW(wcaVerb,L"HEAD"); break; case HTTPCALL\_PUT: lstrcpyW(wcaVerb,L"PUT"); break; case HTTPCALL\_DELETE: lstrcpyW(wcaVerb,L"DELETE"); break; case HTTPCALL\_OPTIONS: lstrcpyW(wcaVerb,L"OPTIONS"); break; case HTTPCALL\_TRACE: lstrcpyW(wcaVerb,L"TRACE"); break; case HTTPCALL\_CONNECT: lstrcpyW(wcaVerb,L"CONNECT"); break; case HTTPCALL\_GET: default: lstrcpyW(wcaVerb,L"GET"); break; }
#ifdef UNICODE
_tcscpy(wcaResource,m_caResource);
#else
MultiByteToWideChar(CP_UTF8,0,m_caResource,-1,wcaResource,1024);
#endifm_hRequest = WinHttpOpenRequest(m_hConnect,wcaVerb,wcaResource,NULL,WINHTTP_NO_REFERER,WINHTTP_DEFAULT_ACCEPT_TYPES,(m_bSSL ? WINHTTP_FLAG_SECURE : 0));
if (!m_hRequest)
{
m_dwLastError = ::GetLastError();
return FALSE;
}if (cpUID && *cpUID)
{
WCHAR wcaUID[512];
WCHAR wcaPWD[512];#ifdef UNICODE
_tcscpy(wcaUID,cpUID);
#else
MultiByteToWideChar(CP_UTF8,0,cpUID,-1,wcaUID,512);
#endifif (cpPWD && \*cpPWD)
#ifdef UNICODE
_tcscpy(wcaPWD,cpPWD);
#else
MultiByteToWideChar(CP_UTF8,0,cpPWD,-1,wcaPWD,512);
#endif
else
wcaPWD[0] = 0;if (!WinHttpSetCredentials(m\_hRequest, WINHTTP\_AUTH\_TARGET\_SERVER, WINHTTP