OpenSSL编程(4):VC客户端访问HTTPS服务器
2010-04-11 04:01
453 查看
本文主要介绍如何在VC客户端应用程序访问HTTPS服务器,同时需要提供客户端证书进行认证。最近需要在VC应用程序中发送客户端证书到HTTPS服务器,建立SSL连接进行身份认证。这方面的资料MSDN上和网上也比较少,这里实现了一个简单的类编程实现上述的SSL连接。
(1)实现流程
首先我们连接HTTPS服务器,并向服务器发送HTTPS请求;
如果服务器要求客户端证书,我们就打开证书存储区域的证书或者用户指定的证书,然后附加上这个证书内容结构重新发送HTTPS请求;
如果服务器响应客户端证书正确,那么客户端用户也就认证成功了,整个SSL连接也就建立了。
(2)参考代码
(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
(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
相关文章推荐
- ftp客户端源代码,使用VC+SOCKET编程,在SERV-U6.0服务器上测试通过,能断点续传
- 【socket编程】使用socket访问https客户端
- 客户端以https访问服务器的流程
- 使用SVN管理VC项目(解决无法访问https://code.google.com/hosting/settings)(服务器为Code Google)(转http://blog.csdn.net/xiadasong007/archive/2010/07/
- 利用openssl生成的https的ca来访问web服务器
- VC++访问HTTPS服务器(不受限制)
- GeoServer不同服务器安装配置、数据发布及客户端访问
- Linux 网络编程基础---------------客户端/服务器的简单实现
- linux 网络编程:客户端与服务器通过TCP协议相互通信 + UDP
- Mobile移动客户端程序访问Oracle服务器对象的方法
- 强制https访问(tomcat服务器下)
- 阿里云服务器Tomcat无法通过客户端http访问
- 解决路由问题造成客户端无法访问服务器的方法之瞒天过海
- linux客户端服务器回射程序-编程记录
- Socket 编程,一个服务器,多个客户端,互相通信
- C++ Socket编程 基础四:类FTP 文件下载服务器 客户端
- JavaSE的有关网络编程的服务器与客户端的通信代码
- 客户端跟服务器效对编程
- 【项目管理】使用SVN客户端搭建可以在局域网中访问的SVN本地库,类似局域网的SVN服务器
- 深入研究socket编程(3)——使用select函数编写客户端和服务器