WinHTTP中的客户端证书

WinHTTP中的客户端证书

本文介绍了WinHTTP中的客户端证书的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要发送带有Web请求的客户端证书(通过SSL)。此客户端证书只是一个公钥。我正在尝试复制Request.ClientCertificates.Add(Cert);使用C ++ / WinHTTP的.NET方法。我正在成功加载.cer文件并通过WinHttpSetOption / WINHTTP_OPTION_CLIENT_CERT_CONTEXT设置CERT_CONTEXT。此调用成功,但是当我调用WinHttpSendRequest时,它失败并返回ERROR_WINHTTP_CLIENT_CERT_NO_PRIVATE_KEY(12185)。



所以,问题是,我如何发送客户端证书公钥到服务器,如ClientCertificates.Add方法在.NET中做的那样?下面的代码片段示例:





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);
 #endif

  m_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);
 #endif

      if (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_AUTH_SCHEME_BASIC,
                                  wcaUID,
                                  wcaPWD,
                                  NULL))
         {
           m_dwLastError = ::GetLastError();
           return FALSE;
         }
     }

  if (m_dwRequestTimeout)
     {
       if (!WinHttpSetOption(m_hRequest,WINHTTP_OPTION_RECEIVE_TIMEOUT,&m_dwRequestTimeout,sizeof(m_dwRequestTimeout)))
         {
           m_dwLastError = ::GetLastError();
           return FALSE;
         }
     }

  // Set certificate
   if (m_pCertCtxt)
     {

      // disable for now, to get  this working...

      DWORD dwFlags = SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
                       SECURITY_FLAG_IGNORE_CERT_DATE_INVALID |
                       SECURITY_FLAG_IGNORE_UNKNOWN_CA |
                       SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE;

      WinHttpSetOption(m_hRequest,WINHTTP_OPTION_SECURITY_FLAGS,&dwFlags,sizeof(dwFlags));

      if (!WinHttpSetOption(m_hRequest,WINHTTP_OPTION_CLIENT_CERT_CONTEXT,(void *)m_pCertCtxt,sizeof(CERT_CONTEXT)))
         {
           if (m_pCertCtxt)
             m_dwLastError = ::GetLastError();
           else
             m_dwLastError = 50000;

          return FALSE;
         }
     }


  if (m_oCustomHeaders.GetSize() > 0)
     {
       CString cHeader;
       WCHAR wcaHeaderBuf[2048];

      for (int iLup = 0; iLup < m_oCustomHeaders.GetSize(); iLup++)
         {
           cHeader = m_oCustomHeaders.GetAt(iLup);

#ifdef UNICODE
           _tcscpy(wcaHeaderBuf,(LPCTSTR)cHeader);
 #else
           MultiByteToWideChar(CP_UTF8,0,(LPCSTR)cHeader,-1,wcaHeaderBuf,2048);
 #endif

          WinHttpAddRequestHeaders(m_hRequest,wcaHeaderBuf,lstrlenW(wcaHeaderBuf),WINHTTP_ADDREQ_FLAG_ADD);
         }
     }


  DWORD dwContentLength = 0;
   if ((iVerb == HTTPCALL_POST || iVerb == HTTPCALL_PUT) && m_cpPostData)
     {
       if (m_iPostDataLen < 0)
         dwContentLength = (DWORD)strlen(m_cpPostData);
       else
         dwContentLength = (DWORD)m_iPostDataLen;
     }

  if (!WinHttpSendRequest(m_hRequest,WINHTTP_NO_ADDITIONAL_HEADERS,NULL,(LPVOID)(m_cpPostData ? m_cpPostData : ""),dwContentLength,dwContentLength,0))
     {
 >>>>> THIS FAILS HERE WITH ERROR_WINHTTP_CLIENT_CERT_NO_PRIVATE_KEY (12185)
      m_dwLastError = ::GetLastError();
       return FALSE;
     }

  if (!WinHttpReceiveResponse(m_hRequest,NULL))
     {
       m_dwLastError = ::GetLastError();
       return FALSE;
     }

  TCHAR caBuf[81];

  caBuf[0] = 0;
   int iBufSize = sizeof(caBuf)/sizeof(TCHAR);
   if (!GetStandardHeader(WINHTTP_QUERY_STATUS_CODE,caBuf,&iBufSize))
     {
       m_dwLastError = ::GetLastError();
       return FALSE;
     }

  m_dwHTTPStatus = _ttol(caBuf);

  caBuf[0] = 0;
   iBufSize = sizeof(caBuf)/sizeof(TCHAR);
   if (!GetStandardHeader(WINHTTP_QUERY_CONTENT_LENGTH,caBuf,&iBufSize))  // no content-length is ok, I guess, for chunked transfers...
     m_dwContentLength = 0;
   else
     m_dwContentLength = _ttol(caBuf);

  return TRUE;
 }





像往常一样,这是截止日期,所以非常感谢任何帮助!证书加载如下所示:







As usual, this is on a deadline, so any help is greatly appreciated! Certificate loading is shown below:


BOOL LoadCertificate(ApplicationInstance *pAppInst)
 {
   BOOL bRetval = FALSE;

  int iThreadCount = (int)pAppInst->m_pLightningServer->m_wNumWorkerThreads;
   TCHAR caCertFilePath[256];

  caCertFilePath[0] = 0;
   if (!pAppInst->GetUserTagValue(_T("CertFilePath"),caCertFilePath,sizeof(caCertFilePath)/sizeof(TCHAR)))
     _tcscpy(caCertFilePath,_T("c:\\webapps\\test.cer"));


  theApp.m_hStore = CertOpenStore(CERT_STORE_PROV_FILENAME,
                                   X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                                   NULL,
                                   CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG,
                                   caCertFilePath);
   if (theApp.m_hStore)
     {
       PCCERT_CONTEXT *pCertList = new (PCCERT_CONTEXT[iThreadCount]);
       if (pCertList)
         {
           for (int iCert = 0; iCert < iThreadCount; iCert++)
             pCertList[iCert] = NULL;

          pAppInst->SetUserPtr((void *)pCertList);
 /*
           PCCERT_CONTEXT pCertCtxt = CertFindCertificateInStore(theApp.m_hStore,
                                                                 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                                                                 0,
                                                                 CERT_FIND_ANY,
                                                                 NULL,
                                                                 NULL
                                                                );
 */
  PCCERT_CONTEXT pCertCtxt = CertFindCertificateInStore(theApp.m_hStore,
              X509_ASN_ENCODING,
              0,
              CERT_FIND_SUBJECT_STR,
              (LPVOID)_T("test.myserver.com"), //Subject string in the certificate.
              NULL );

           if (pCertCtxt)
            {
               pCertList[0] = pCertCtxt;
               for (int iLup = 1; iLup < iThreadCount; iLup++)
                 pCertList[iLup] = CertDuplicateCertificateContext(pCertCtxt);

              bRetval = TRUE;
             }
          else
             {
               pAppInst->m_pLightningServer->WriteErrorLog(-3,_T("APPINIT: Error Getting CERT_CONTEXT From Store"),caCertFilePath,NULL,FALSE);
             }
         }
       else
         {
           pAppInst->m_pLightningServer->WriteErrorLog(-2,_T("APPINIT: Error MemAlloc CERT_CONTEXT Array"),NULL,NULL,FALSE);
         }
     }
   else
     {
       DWORD dwError = GetLastError();
       TCHAR caErrBuf[1024];
       _stprintf(caErrBuf,_T("APPINIT: Error Opening Cert Store [%d]..."),dwError);
       ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
                       NULL,
                       dwError,
                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                      caErrBuf+_tcslen(caErrBuf),
                       sizeof(caErrBuf)/sizeof(TCHAR)-40,
                       NULL);

      pAppInst->m_pLightningServer->WriteErrorLog(-1,caErrBuf,caCertFilePath,NULL,FALSE);
     }

  return bRetval;
 }

推荐答案


这篇关于WinHTTP中的客户端证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-06 12:59