使用WinInet进行客户端身份验证(证书+私钥)

3
  • 这是我之前的问题的进化,那个问题与WinHttp有关。
  • 我希望这是正确的方法...

我正在尝试使用WinInet(来自Win32 API)与服务器进行https通信。

这是一个非常简约的代码:

HINTERNET ses = InternetOpen("test",INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0) ;
HINTERNET con = InternetOpenUrl( ses,"https://stackoverflow.com",NULL,0,0,0 ) ;
DWORD read ;
char  str [3000] ;
InternetReadFile( con,reinterpret_cast<void*>( str ),sizeof( str )-1,&read ) ;
str[read] = 0 ;
cout << &str[0] ;
InternetCloseHandle( con ) ;
InternetCloseHandle( ses ) ;

只要与“经典”https服务器通信,比如stackoverflow.com,一切都很顺利。问题是当我尝试与需要客户端认证的服务器通信时。
我有3个.pem文件:客户端的证书和私钥,以及用于验证客户端证书的根证书(即长度为2的证书链)。
值得一提的是,我可以使用以下cURL命令行连接我的服务器:
curl https://my.server --cert Client_cert.pem --key Client_key.pem --cacert Root_cert.pem
这证明了这是可能的!
阅读WinInet文档,我找到了一个名为“Handling Authentication”的页面,但它全部都是关于用户名:密码的,没有关于证书的内容。
我发现我必须使用Crypt32库:我必须使用CertCreateCertificateContext创建证书上下文,然后将其插入证书存储中,然后将该存储用于我的连接... 好吧,我必须承认我很高兴能找到一个好的教程或一些代码示例! 顺便说一下,我不知道如何将我的私钥插入到那个东西中... 提前致谢!
1个回答

0

您需要使用InternetSetOption()通过INTERNET_OPTION_CLIENT_CERT_CONTEXT将您的证书传递给WinInet:

INTERNET_OPTION_CLIENT_CERT_CONTEXT

84

此标志不受InternetQueryOption支持。 lpBuffer参数必须是指向CERT_CONTEXT结构而不是CERT_CONTEXT指针的指针。如果应用程序接收到ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED,则必须调用InternetErrorDlg或使用InternetSetOption提供证书,然后重试请求。然后调用CertDuplicateCertificateContext,以便应用程序可以独立释放传递的证书上下文。

例如:

InternetSetOption(hI,INTERNET_OPTION_CLIENT_CERT_CONTEXT,(void*)cert,sizeof(CERT_CONTEXT));

顺便说一下,curl调用并不是很好的例子,因为curl使用libcurl,而libcurl使用OpenSSL。


谢谢,我已经阅读了那个页面... 麻烦的部分是我必须构建一个包含证书存储句柄的CERT_CONTEXT:我需要先构建它吗?客户端的私钥怎么办?如何检查证书链?我需要自己做吗? - Captain'Flam
这取决于您的证书放在哪里。它是在PFX文件中吗?可以使用https://learn.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-pfximportcertstore - PFXImportStore导入。然后,您可以使用CertEnumCertificatesInStore循环遍历所有证书。当需要私钥时,将自动包括(例如,您可能会收到PIN请求)。另请参见https://dev59.com/vG015IYBdhLWcg3w7wQW - Michael Chourdakis
我的2个证书+1个私钥存储在.pem文件中。我的代码应该静默运行,因此无法请求PIN码... - Captain'Flam
如果您拥有私钥和公钥,则可以使用pvk2pfx工具将其保存在PFX中,然后导入并使用我所说的函数。此外,您需要一个证书。链(如果有)将从服务器而不是您进行验证。如果这不是由您的服务器知道的证书颁发机构签署的密钥,则您提供的链无论如何都是无用的。如果这是您自己的组织,则服务器已经知道根证书。 - Michael Chourdakis
谢谢你,Michael!最终我成功地从我的两个证书和私钥中构建了一个PFX。我使用PFXImportCertStore导入它,但现在我有了一个全新的HCERTSTORE,我不知道如何将它传递给我的https连接... 它没有使用InternetSetOption... 我没有看到任何使用HCERTSTORE作为参数的Internet或Http函数。 - Captain'Flam
证书存储库中保存了您的证书,您可以使用CertEnumCertificatesInStore查找它们。 - Michael Chourdakis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接