您的位置:首页 > 理论基础 > 计算机网络

OpenSSL编程(4):VC客户端访问HTTPS服务器

2010-04-11 04:01 453 查看
本文主要介绍如何在VC客户端应用程序访问HTTPS服务器,同时需要提供客户端证书进行认证。最近需要在VC应用程序中发送客户端证书到HTTPS服务器,建立SSL连接进行身份认证。这方面的资料MSDN上和网上也比较少,这里实现了一个简单的类编程实现上述的SSL连接。

(1)实现流程

首先我们连接HTTPS服务器,并向服务器发送HTTPS请求;

如果服务器要求客户端证书,我们就打开证书存储区域的证书或者用户指定的证书,然后附加上这个证书内容结构重新发送HTTPS请求;

如果服务器响应客户端证书正确,那么客户端用户也就认证成功了,整个SSL连接也就建立了。

(2)参考代码

bool CSslConnection::ConnectToHttpsServer(string &strVerb)
{
try {
m_hInternet = InternetOpen(m_strAgentName.c_str(), INTERNET_OPEN_TYPE_PRECONFIG ,
NULL, NULL, 0);
if (!m_hInternet) {
m_strLastError = "Cannot open internet";
m_lastErrorCode = GetLastError();
return false;
}

m_hSession = InternetConnect(m_hInternet,
m_strServerName.c_str(),
m_wPort,
m_strUserName.c_str(),
m_strPassword.c_str(),
INTERNET_SERVICE_HTTP,
0,
0);
if (!m_hSession) {
m_strLastError = "Cannot connect to internet";
m_lastErrorCode = GetLastError();
ClearHandles();
return false;
}
m_hRequest = HttpOpenRequest(m_hSession,
strVerb.c_str(),
m_strObjectName.c_str(),
NULL,
"",
NULL,
m_secureFlags,
m_ReqID);
if (!m_hRequest) {
m_strLastError = "Cannot perform http request";
m_lastErrorCode = GetLastError();
ClearHandles();
return false;
}

m_ReqID++;
}
catch(...) {
m_strLastError = "Memory Exception occured";
m_lastErrorCode = GetLastError();
return false;
}
return true;
}
bool CSslConnection::SendHttpsRequest()
{
try {
for (int tries = 0; tries < 20; ++tries) {
int result =  HttpSendRequest(m_hRequest, NULL, 0, NULL, 0);
if (result)
return true;
int lastErr = GetLastError();
if (lastErr == ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) {
if (!SetClientCert()) {
m_strLastError = "Cannot perform http request, client authentication needed but couldnt detect required client certificate";
m_lastErrorCode = GetLastError();
return false;
}
}
else if (lastErr == ERROR_INTERNET_INVALID_CA) {
m_strLastError = "Cannot perform http request, client authentication needed, invalid client certificate is used";
m_lastErrorCode = GetLastError();
return false;
}
else {
m_strLastError = "Cannot perform http request";
m_lastErrorCode = GetLastError();
return false;
}
}
}
catch(...) {
m_strLastError = "Memory Exception occured";
m_lastErrorCode = GetLastError();
return false;
}
return false;
}
void CSslConnection::ClearHandles()
{
if (m_hInternet) {
InternetCloseHandle(m_hInternet);
m_hInternet = NULL;
}

if (m_hSession) {
InternetCloseHandle(m_hSession);
m_hSession = NULL;
}

if (m_pContext) {
CertFreeCertificateContext(m_pContext);
m_pContext = NULL;
}
if (m_hStore) {
CertCloseStore(m_hStore, CERT_CLOSE_STORE_FORCE_FLAG);
m_hStore = NULL;
}
}
bool CSslConnection::SetClientCert()
{
char *lpszStoreName;
switch (m_certStoreType) {
case certStoreMY:
lpszStoreName = "MY";
break;
case certStoreCA:
lpszStoreName = "CA";
break;
case certStoreROOT:
lpszStoreName = "ROOT";
break;
case certStoreSPC:
lpszStoreName = "SPC";
break;
}
m_hStore = CertOpenSystemStore(NULL, lpszStoreName);
if (!m_hStore) {
m_strLastError = "Cannot open system store ";
m_strLastError += lpszStoreName;
m_lastErrorCode = GetLastError();
ClearHandles();
return false;
}

m_pContext = FindCertWithOUNITName();
if (!m_pContext) {
m_strLastError = "Cannot find the required certificate";
m_lastErrorCode = GetLastError();
ClearHandles();
return false;
}

// INTERNET_OPTION_CLIENT_CERT_CONTEXT is 84
int res = InternetSetOption(m_hRequest,
INTERNET_OPTION_CLIENT_CERT_CONTEXT,
(void *) m_pContext, sizeof(CERT_CONTEXT));
if (!res) {
m_strLastError = "Cannot set certificate context";
m_lastErrorCode = GetLastError();
ClearHandles();
return false;
}

return true;
}
PCCERT_CONTEXT CSslConnection::FindCertWithOUNITName()
{
//This function performs a certificate contex search
//by the organizational unit name of the issuer
//Take this function as a sample for your possible different search functions
PCCERT_CONTEXT pCertContext = NULL;
CERT_RDN certRDN;
certRDN.cRDNAttr = 1;
certRDN.rgRDNAttr = new CERT_RDN_ATTR;
certRDN.rgRDNAttr->pszObjId = szOID_ORGANIZATIONAL_UNIT_NAME;
certRDN.rgRDNAttr->dwValueType = CERT_RDN_ANY_TYPE;
certRDN.rgRDNAttr->Value.pbData = (BYTE *) m_strOName.c_str();
certRDN.rgRDNAttr->Value.cbData = strlen(m_strOName.c_str());
pCertContext = CertFindCertificateInStore(m_hStore,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0, CERT_FIND_ISSUER_ATTR, &certRDN, NULL);

delete certRDN.rgRDNAttr;
return pCertContext;
}
string CSslConnection::GetRequestResult()
{
DWORD dwNumberOfBytesRead;
char sz[1024];
string strResult;
int result;
m_lastErrorCode = GetLastError();
do {
result = InternetReadFile(m_hRequest, sz, 1023, &dwNumberOfBytesRead);
sz[dwNumberOfBytesRead] = '/0';
int x = strlen(sz);
strResult += sz;
memset(sz, 0, 1024);

} while(result && dwNumberOfBytesRead != 0);
m_lastErrorCode = GetLastError();
return strResult;
}






(3)参考资料;

(1)Connecting to a HTTPS server with SSL using Wininet, sending client certificate and reading response

http://www.codeproject.com/KB/IP/wininet_ssl___certificate.aspx
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: