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



Comments

  • Can you get a realm when doing certificate authentication?

    Posted by sshields on 12/04/2007 10:23pm

    When the httpsendrequest fails with ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED, is there a way to get the realm? Or does that not apply with certificates? I want to use the realm to associate it with the certificate for future connections.

    Reply
  • Very nice

    Posted by GuOddian on 12/05/2005 01:14am

    Exactly the information I was looking for.

    Reply
  • Proxy Authentication Required

    Posted by Legacy on 01/21/2004 12:00am

    Originally posted by: Shan

    Not able to succesfully connect to the server through SSL. Basically I am using your code as it is. The HttpSendRequest() succeeds, but it's handle response is as below.
    ---------------------handle response-----------------------
    "+ response {0x00841951 "
    Proxy Authentication Required
    Unable to complete request:
    Access denied due to authentication failure.
    ---------------------------------------------------------
    Could you plese tell me as to what I could be doing wrong?

    Reply
  • Excellent Information

    Posted by Legacy on 10/21/2003 12:00am

    Originally posted by: Cecilia

    Thank you so much.
    They are very useful information and samples. Information that you won't find in the MSDN. It certainly saves my day.
    Thanks

    Reply
  • THANK YOU

    Posted by Legacy on 04/16/2003 12:00am

    Originally posted by: Sunglim Lee

    You have indeed saved bunch of my hair!

    Thank you very much for sharing your precious information.

    Reply
  • Code doesn't work when implemented as DLL

    Posted by Legacy on 01/30/2003 12:00am

    Originally posted by: Juaritos

    I included this code in a VC++ desktop app and works perfect, however, when I migrated this code to an ATL component so it can be called from an ASP page, fails when executing HttpSendRequest and never returns, so I cannot even call GetLastError() to get the error code.

    I tried the same using VB6 but got the same results, ...works well as a dektop app, but HttpSendRequest never returns when the code is included in an ActiveX dll.

    I also tried to do the same using c# in a web service, but .net does not have access to the private key using X509Certificate.

    Any clues on why this code doesn't work when implemented as a component.

    Reply
  • But how do you register a cert w/WinInet?

    Posted by Legacy on 11/14/2001 12:00am

    Originally posted by: Ken Overton


    That seems, to me, to be the crux of the issue. If we want to install a trusted root and use it, how do we do that?

    -- kov

    Reply
  • HTTP With SSL

    Posted by Legacy on 09/20/2001 12:00am

    Originally posted by: Venkata Reddy

    Here is the Solution I got working when I use SSL with HTTP.

    In InternetConnect() call use the HTTPS port instead of HTTP default Port

    InternetOpen(..);
    InternetConnect(..,
    m_szDestination,
    m_bUseSSL?ITERNET_DEFAULT_HTTPS_PORT:m_uPort, ..,
    ..,
    INTERNET_SERVICE_HTTP,
    m_bUseSSL ? INTERNET_FLAG_SECURE : 0,
    0);

    Then in
    HttpOpenRequest(.., dwFlags) use
    dwFlags = INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID;
    flags..

    This would work, and when HttpSendRequest() request returns error and GetLAstError() returns ERROR_INTERNET_INVALID_CA because of the invalid certificate, show up the WinInet message box for selection.

    Caution: If the ITERNET_DEFAULT_HTTPS_PORT is not used then you get ERROR_INTERNET_SECURITY_CHANNEL_ERROR.

    Reply
  • I am unable to connect to a server through HTTPS

    Posted by Legacy on 09/15/2000 12:00am

    Originally posted by: Jaganathan Rajagopalan

    Hope you can help. I am unable to succesfully connect to the server through SSL. Basically I am using your code as is. The HttpSendRequest() method fails, with the error code ERROR_INTERNET_SECURITY_CHANNEL_ERROR . Could you plese tell me as to what I could be doing wrong?

    Reply
  • public/private key pair

    Posted by Legacy on 01/25/2000 12:00am

    Originally posted by: G. Vinod Kumar

    How SSL is used with public and private keys pair.
    i.e I want to generate public and private key pair on the server and distribute public key to the clients for encryption. Decryption is done at the server using private key. can you please give me the solution for this.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • With JRebel, developers get to see their code changes immediately, fine-tune their code with incremental changes, debug, explore and deploy their code with ease (both locally and remotely), and ultimately spend more time coding instead of waiting for the dreaded application redeploy to finish. Every time a developer tests a code change it takes minutes to build and deploy the application. JRebel keeps the app server running at all times, so testing is instantaneous and interactive.

  • Live Event Date: May 6, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT While you likely have very good reasons for remaining on WinXP after end of support -- an estimated 20-30% of worldwide devices still are -- the bottom line is your security risk is now significant. In the absence of security patches, attackers will certainly turn their attention to this new opportunity. Join Lumension Vice President Paul Zimski in this one-hour webcast to discuss risk and, more importantly, 5 pragmatic risk mitigation techniques …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds