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

  • The explosion in mobile devices and applications has generated a great deal of interest in APIs. Today's businesses are under increased pressure to make it easy to build apps, supply tools to help developers work more quickly, and deploy operational analytics so they can track users, developers, application performance, and more. Apigee Edge provides comprehensive API delivery tools and both operational and business-level analytics in an integrated platform. It is available as on-premise software or through …

  • Not long ago, security was viewed as one of the biggest obstacles to widespread adoption of cloud-based deployments for enterprise software solutions. However, the combination of advancing technology and an increasing variety of threats that companies must guard against is rapidly turning the tide. Cloud vendors typically offer a much higher level of data center and virtual system security than most organizations can or will build out on their own. Read this white paper to learn the five ways that cloud …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds