Introduction
I�ve recently needed to make a Secure Sockets Layer (SSL) connection to Visa server and send our signed client certificate in order to make our MPI application authorized. I searched many articles but could find just a few ones about the subject. I collected parts of the solution from different articles and MSDN, and implemented a simple class that performs this operation programmatically.
There�s InternetErrorDlg
API for some purposes including sending client certificate modeling a selection dialog to the user. But in many cases, the programmer may require authentication without user interface (i.e. user interface requires an OK clicker J.. This might be useless for us if we want our program to do things automatically). This is done here by InternetSetOption()
with INTERNET_OPTION_CLIENT_CERT_CONTEXT
flag. Don�t forget that this option only works with Internet Explorer 5.01 or later (as MSDN writes).
INTERNET_OPTION_CLIENT_CERT_CONTEXT
flag is not included in VC6.0 default headers. If you�ve platform SDK installed, that�s no problem, include the wininet header in sdk/include directory, else you may define it manually;
#define INTERNET_OPTION_CLIENT_CERT_CONTEXT 84
That should be ok if you don�t have old wininet.dll versions.
For readers who are not familiar with wininet, SSL or certificates:
I am not gonna tell what wininet functions do & how they are used nor about the certificates. These are generic subjects and much information can be gathered from so many resources such as MSDN. I will try to answer the questions if you send an email to me.
Well, the flow is simple. First we connect to the HTTPS server and send a HTTPS request. If the server asks for a signed client certificate, we open and dig through the system store(s) for the certificate context we need. Then resend our request but after attaching the certificate context. If the server is satisfied, we are authenticated.
ConnectToHttpsServer()
summarizes the flow of the connection. This is the initial place.
SendHttpsRequest()
sends a request. After that, if the server requires client certificate, we search it in the system store. If we find it, InternetSetOption()
attaches the context to the connection. Then we try the SendHttpsRequest()
again.
A sample usage of the class can be like this:
CSslConnection inetSec;
string sAgentName("My Firm");
string sServerName("207.219.70.31");
string sUserName("");
string sPass("");
string sObjectName("/xxx.asp");
string sOrganizationUnitName("3-D Secure Compliance TestFacility");
string strVerb = "POST";
inetSec.SetAgentName(sAgentName);
inetSec.SetCertStoreType(certStoreMY);
inetSec.SetObjectName(sObjectName);
inetSec.SetOrganizationName(sOrganizationUnitName);
inetSec.SetPort(9660);
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;
The �organization name� notated functions and variables are completely sample. I chose using �O value of the issuer field� in the certificate, that�s my search criteria. You may wish to perform store search by different fields. Because, there are many fields in a certificate and a context search can be performed by any of these.
You may possibly add your own functions instead of using FindCertWithOUNITName()
function. If you do that, just change the code calling this function (only in 1 place) and provide some variables and accessors which are suitable for your certificate search criteria.