Sunday, June 29, 2014

Practical Certificate Knowledge for .NET developers: HttpWebRequest Client Certificate Authentication

HttpWebRequest Client Certificate Authentication

Articles in this series:

Introduction

Finally, some C# code! This post builds upon part four, where we use an HttpWebRequest object to contact our web page. This example can be practically used when invoking REST-style HTTP services that use client certificate authentication. 

Sample Code

Copy and paste more easily from here (dotnet fiddle link).

In a new console app, use the following code, but be sure to update the port to match what you used in Part Four.

Additionally, you will need to import the MyClientCert.pfx file into the local computer's personal certificate store. In order to do this, follow Part Four, Step 3, but rather than selecting your user's certificate store, select the local computer's certificate store. 

Go ahead and run this code, and you should see the contents of your HTML file dumped out to the console. Note however, though, if you remove the association line request.ClientCertificates = collection; and re-execute the program, you'll get a 403 Forbidden error, since you aren't passing in the certificate required for the request. 

The code below is commented to walk through what is actually happening. Do note that when working with X509 certificates in .NET, you'll want to utilize the X509Certificate2 classes (not the X509Certificate classes), as the '2' classes are a newer, more fully featured class to handle X509 certs in code. 

using System.IO;
using System.Net;
using System.Security.Cryptography.X509Certificates;

namespace ClientCertInvocation
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create a web request that points to our SSL-enabled client certificate required web site
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("https://my.local.machine:440/");

            // Use the X509Store class to get a handle to the local certificate stores. "My" is the "Personal" store.
            X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);

            // Open the store to be able to read from it.
            store.Open(OpenFlags.ReadOnly); 

            // Use the X509Certificate2Collection class to get a list of certificates that match our criteria (in this case, we should only pull back one).
            X509Certificate2Collection collection = store.Certificates.Find(X509FindType.FindBySubjectName, "MyClientCert", true);

            // Associate the certificates with the request
            request.ClientCertificates = collection;

            // Make the web request
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            // Output the stream to a file.
            Stream stream = response.GetResponseStream();
            using (var fileStream = File.Create("copy.html"))
            {
                stream.CopyTo(fileStream);
            }
        }
    }
}

No comments:

Post a Comment