Thursday, January 10, 2008

Testing SSL and Certificate Authentication using makecert

I wanted to set up a development environment, all on my local PC, that would allow me to do Certificate Authentication in an ASP.NET application.

Tools used:
  • IIS 5.1 / Windows XP
  • Web browser: IE 6.0
  • IIS Resources / WFetch for troubleshooting HTTP issues
The first step is to set up SSL on IIS. You need a server certificate for this, which you usually get from a Certificate Authority, but for development/testing purposes you just use makecert.exe (installed in the Visual Studio directory).

First we create a "Root CA" for our two certificates:
makecert -pe -n "CN=Dev Root Auth" -ss my -sr LocalMachine -a sha1 -sky signature -r "DevRootAuth.cer"
Open MMC. Add the Certificates snap-in for Local Computer.

Copy and paste the above "Dev Root Auth" certificate from the Personal path to the "Trusted Root Certification Authorities" path. Or use certmgr to copy it:
certmgr -add -all -c "DevRootAuth.cer" -s -r LocalMachine Root
Now create the server certificate (to use for SSL), using the first certificate created above as the Issuer:
makecert -pe -n "CN=localhost" -ss my -sr LocalMachine -a sha1 -sky exchange -eku 1.3.6.1.5.5.7.3.1 -in "Dev Root Auth" -is MY -ir LocalMachine -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 localhost.cer
Note the "Extended Key Usage" value of 1.3.6.1.5.5.7.3.1 which indicates that this cert is for Server Authentication.

Now enable SSL: open Inetnet Information Services management console. Right-click Default Web Site and go to Properties -> Directory Security -> Server Certificate -> Assign an existing certificate. Select the "localhost" cert. Finish the wizard.

You should now be able to access pages on your localhost with HTTPS.

For example, create a directory C:\inetpub\wwwroot\SecureTest with a file named Default.aspx containing the following three lines:
Cert present: <%=Page.Request.ClientCertificate.IsPresent%>

Subject: <%=Page.Request.ClientCertificate.Subject%>
Open now open the file in IE as https://localhost/SecureTest/default.aspx. The output will show:
Cert present: False
Subject:
This verifies HTTPS is working. When you click the padlock icon in Internet Explorer you should see the "localhost" certificate is OK. We're done setting up SSL.

The next step is to create the Client Authentication certificate, which IE will pass to IIS to authenticate the user.
makecert -pe -n "CN=Test Client, O=Test company, OU=Testing, E=test@test.com, C=ZA" -ss my -sr CurrentUser -a sha1 -sky exchange -eku 1.3.6.1.5.5.7.3.2 -in "Dev Root Auth" -is Root -ir LocalMachine -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 testclient.cer
Note this time the Extended Key Usage value is 1.3.6.1.5.5.7.3.2 which indicates that this cert is for Client Authentication.

The Subject string (-n parameter) must conform to the X.500 distinguished names standard. See RFC2253 for a description of the possible X.500 attributes. You can also use E to specify an email address. I found that the UID attribute doesn't work with makecert, which is too bad, because it would be nice to be able to assign a custom field to the cert to easily identify the user.

You can now configure the SecureTest application in IIS to require Certificate Authentication. In IIS manager, right-click on the SecureTest directory and to Properties -> Directory Security -> Edit. Click "Require secure channel (SSL)". Click "Require client certificates". Click OK and OK again.

Now open https://localhost/SecureTest/default.aspx in IE again. This time the output should show:
Cert present: True
Subject: C=ZA, E=test@test.com, OU=Testing, O=Test company, CN=Test Client
This verifies the Certificate Authentication works.

To make this more useful, you would use the certificate ("what you have") in your Login screen in addition to (or instead of) a username/password ("what you know") for a two-factor authentication scheme. You could map the client certificate to a Windows user in IIS, or write custom authentication code (e.g. Forms Authentication) using the certificate information to uniquely identify the user... (Although some might argue that using a certificate doesn't mean it's a two-factor scheme).

Remember to use WFetch during the whole process to test everything - it's much easier troubleshooting HTTP issues (e.g. to see the HTTP request and response headers and status codes) than just testing with IE.