Selecting a client certificate

Environment: VC6 NT4 IE 4,5

This article covers the basics of selecting a client certificate for use within WinInet. I have put this text together, in the hope it may prevent others suffering the hair loss I have during the last week.

First of all I am assuming you know the basics of setting up a HTTPS connection, bellow is a brief outline to refresh your memory. The INTERNET_FLAG_SECURE flag can be set within the InternetConnect command to force the use of SSL.


// Initialize wininet.
hOpen = InternetOpen (…)

// connect to remote server
hConnect = InternetConnect ( hOpen, strServerName , ….)

// Open a HTTP request
hReq = HttpOpenRequest (hConnect, “GET”, strObject, ….)

// Send request
HttpSendRequest (hReq, ….)

// read results
InternetReadFile (hReq, bBuf, cbBuf, &cbRead)

// use the returned HTML page
printf(bBuf);

If the server that we are making the request to requires a client certificate then the HttpSendRequest function will fail with the error ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED. At this point we must select a certificate.

There are basically 2 ways of selecting a certificate. First (the easiest, and the way IE does it), is to ask the user. See Dialog bellow.

This can be done programmatically using the following code:-



while ( !HttpSendRequest( hReq, NULL, 0, NULL, 0 ) )
{
dwError = GetLastError();
if ( dwError == ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED )
{
// Return ERROR_SUCCESS regardless of clicking on OK or Cancel
if( InternetErrorDlg( GetDesktopWindow(),
hReq,
ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED,
FLAGS_ERROR_UI_FILTER_FOR_ERRORS |
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA |
FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS,
NULL) != ERROR_SUCCESS )
{
return ;
}
}
}

See Q224282 for more details.

However if you dont want the user to see the dialog, then you will need to actually select the certificate programmatically. This sounds simple but, due to the extreme lack of documentation becomes something of a nightmare.


Anyhow it can basically be accomplished using InternetSetOptions INTERNET_OPTION_SECURITY_SELECT_CLIENT_CERT flag. This, you may notice has no documentation. The sample code for using this flag is included. But the guts of it are here:-


if (!HttpSendRequest (hReq, NULL, 0, NULL, 0) )
{
dwError = GetLastError () ;
if ( dwError == ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED)
{
//This works but there is no way to iterate through the client certs
DWORD dwCert = 0;
InternetSetOption(hReq, INTERNET_OPTION_SECURITY_SELECT_CLIENT_CERT,
&dwCert, sizeof(dwCert));

goto again;
}
}


This will select the first client certificate registered with WinInet. The bad news is if there are more than one Cert on the machine then you dont know which one you got!


As the most common reason for wanting to avoid the selection dialog is because the application is running as a service, I will provide a link to an MS article that describes how to set the registry up to cope with finding the certs when running as system. Q190542.


I will also include some code I picked up from a news group posting with regards to enumerating the client certificates installed. Although this is inrelated to the article directly, it may prove useful. 


I would also like to thank Scott Davis. For his Dev Studio HTML Plugin.

Downloads

Download source – 2KB

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read