使用 Wininet 通过 SSL 连接到 HTTPS 服务器,发送客户端证书并读取响应






4.71/5 (30投票s)
2003 年 4 月 3 日
2分钟阅读

510535

8684
一个示例类,演示如何连接到 HTTPS 服务器,该类发送所需的客户端证书并验证用户。
引言
最近我需要与 Visa 服务器建立安全套接字层 (SSL) 连接,并发送我们签名的客户端证书,以便授权我们的 MPI 应用程序。 我搜索了许多文章,但只找到了一些关于该主题的文章。 我从不同的文章和 MSDN 中收集了部分解决方案,并实现了一个简单的类,该类以编程方式执行此操作。
InternetErrorDlg
API 适用于某些目的,包括发送客户端证书,模拟向用户显示的选择对话框。 但在许多情况下,程序员可能需要在没有用户界面的情况下进行身份验证(即,用户界面需要单击确定 J.. 如果我们希望我们的程序自动执行某些操作,这对我们来说可能没有用)。 这可以通过 InternetSetOption()
和 INTERNET_OPTION_CLIENT_CERT_CONTEXT
标志来完成。 不要忘记,此选项仅适用于 Internet Explorer 5.01 或更高版本(如 MSDN 所写)。
INTERNET_OPTION_CLIENT_CERT_CONTEXT
标志未包含在 VC6.0 默认标头中。 如果您已安装平台 SDK,则没有问题,请在 sdk/include 目录中包含 wininet 标头,否则您可以手动定义它;
#define INTERNET_OPTION_CLIENT_CERT_CONTEXT 84
如果您没有旧的 wininet.dll 版本,这应该可以。
对于不熟悉 wininet、SSL 或证书的读者
我不会告诉你 wininet 函数的作用以及它们是如何使用的,也不会告诉你关于证书的信息。 这些都是通用主题,可以从许多资源(例如 MSDN)中收集大量信息。 如果您给我发送电子邮件,我会尝试回答这些问题。
嗯,流程很简单。 首先,我们连接到 HTTPS 服务器并发送 HTTPS 请求。 如果服务器要求提供签名的客户端证书,我们会打开并搜索系统存储以查找我们需要的证书上下文。 然后重新发送我们的请求,但在附加证书上下文之后。 如果服务器满意,我们就通过了身份验证。
ConnectToHttpsServer()
总结了连接的流程。 这是初始位置。SendHttpsRequest()
发送请求。 之后,如果服务器需要客户端证书,我们会在系统存储中搜索它。 如果我们找到了它,InternetSetOption()
会将上下文附加到连接。 然后我们再次尝试SendHttpsRequest()
。
该类的一个示例用法可以是这样的
CSslConnection inetSec; string sAgentName("My Firm"); string sServerName("207.219.70.31");//Can be any https server address string sUserName("");//if required string sPass("");//if required string sObjectName("/xxx.asp");//there should be an object to send a verb string sOrganizationUnitName("3-D Secure Compliance TestFacility"); string strVerb = "POST";//I chose POST verb. That’s usually done inetSec.SetAgentName(sAgentName); inetSec.SetCertStoreType(certStoreMY); //The stores provided by the system // are: MY, ROOT, SPC and CA inetSec.SetObjectName(sObjectName); inetSec.SetOrganizationName(sOrganizationUnitName); inetSec.SetPort(9660);//443 is the default HTTPS port inetSec.SetServerName(sServerName); inetSec.SetRequestID(0); if (!inetSec.ConnectToHttpsServer(strVerb)) { cout << inetSec.GetLastErrorString() << " Code: " << inetSec.GetLastErrorCode(); << endl; return 0; } if (!inetSec.SendHttpsRequest()) { cout << inetSec.GetLastErrorString() << " Code: " << inetSec.GetLastErrorCode(); << endl return 0; } string response = inetSec.GetRequestResult(); cout << response.c_str() << endl;
带“组织名称”注释的函数和变量完全是示例。 我选择使用证书中“颁发者字段的 O 值”,这是我的搜索条件。 您可能希望通过不同的字段执行存储搜索。 因为证书中有很多字段,并且可以通过这些字段中的任何一个执行上下文搜索。
您可能会添加自己的函数而不是使用 FindCertWithOUNITName()
函数。 如果你这样做,只需更改调用此函数的代码(仅在一个地方),并提供一些适合您的证书搜索条件的变量和访问器。