I wanted to get client certificate authentication working on a development environment. The environment in this case is a Windows 8.1 laptop so that implies IIS 8.5. It involves a significant number of steps so this will be a long post.

Configure IIS

First of all, you need to configure IIS to allow client certificate mapping authentication. As you can see in the screenshot below, there are two types of these. We need the IIS Client Certificate Mapping Authentication feature. The Client Certificate Mapping Authentication feature is used for client certificate authentication using Active Directory.

Windows Features

Generate certificates

Next step is to generate certificates. Client certificate authentication requires that your website has an HTTPS binding so we first need a certificate for the server. To obtain this, we use a self-signed certificate that we add to the trusted root certificates store of the local computer and we derive both the client and the server certificate from this root certificate.

Self-signed root certificate

To generate the root certificate, use the following command line:

makecert -r -pe -n "CN=WebSSLTestRoot"
         -b 12/22/2013 -e 12/23/2014
         -ss root -sr localmachine -len 2048

The makecert command has a lot of options, some of which we use here:

-r Generate a self-signed certificate.
-pe Allow the private key to be included in the certificate. We need this because we want to use the certificate to issue other certificates that are signed by this private key.
-n "name" Certificate subject name.
-b Validity start date.
-e Validity end date.
-ss Name of the certificate store that stores the certificate. Since we want to automatically trust this certificate, we store it with the trusted root certificates. You can find some more info on store locations here.
-sr Certificate store location where the certificate will be stored (either currentuser or localmachine).
-len Key length.

The result is a trusted root certificate as you can see in the screenshot below.

Self-signed root certificate

Server certificate

We derive the IIS server certificate from the root certificate we just generated with the following command:

makecert -pe -n "CN=www.sslclientauth.local" -b 12/22/2013 -e 12/23/2014
         -eku 1.3.6.1.5.5.7.3.1 -is root -ir localmachine -in WebSSLTestRoot
         -len 2048 -ss WebHosting -sr localmachine

This is no longer a self-signed certificate since we derive it from our own root certificate so the -r option is gone. Note that we use the subject name www.sslclientauth.local. This will become the url for the web site. Besides, we now store the certificate in a LocalMachine store called WebHosting. The new options we’re using are to describe the purpose of this certificate and to locate the issuing (root) certificate we generated before:

-eku Describes the purpose of this certificate, which is to authenticate a server. Check here for more information on certificate OID’s.
-is The name of the certificate store where our issuing certificate resides.
-ir The certificate store location of our issuing certificate.
-in The subject name of our issuing certificate.

The result is a certificate that can be used to verify the authenticity of a server, in this case a server named www.sslclientauth.local. The certificate is trusted because it is signed by a trusted (root) certificate as you can see in the following screenshot.

Server certificate

Client certificate

The last certificate we need is the client certificate. Since we already have a root certificate, let’s derive the client certificate from it as well:

makecert -pe -n "CN=SSLClientAuthClient"
         -eku 1.3.6.1.5.5.7.3.2 -is root -ir localmachine -in WebSSLTestRoot
         -ss my -sr currentuser -len 2048

No new makecert are introduced here. The key purpose this time is client authentication and we store the certificate in the CurrentUser personal store.

Client certificate

Configure a test web application

I generated an empty ASP.NET 4.5.1 web project and added a basic ‘hello world’ page. Next step is to configure IIS. We add a new website and configure an https binding as shown in the following screenshot. The physical path points to the website I just created.

Add IIS website

Most important are the https binding, the host name and the certificate. Make sure that host name and certificate match. The certificate that’s selected in the screenshot is the one we created earlier. It can only be selected from the LocalMachine Personal or WebHosting stores, which is why I added the certificate to the latter.

The checkbox Require Server Name Indication (SNI) requires clients (browsers) to use the SNI extension to the TLS protocol.

Last step is to update your hosts file (in %systemroot%\System32\drivers\etc) to include the following line: 127.0.0.1 www.sslclientauth.local. This maps the address www.sslclientauth.local to localhost.

If all went well, you now have a website running with HTTPS. You can easily check this by visiting https://www.sslclientauth.local in a browser. Now for the client authentication part.

Configure client authentication

We already have a client certificate so all we need to do is tell the server that only clients using this particular certificate may enter and configure a client to use the certificate.

To configure the server part, first we must export the public key part of the certificate in base64 format. To do this, right-click your certificate in the MMC Certificate Snap-in and select All Tasks → Export…. Do not export the private key, select the base-64 format and a place to store the certificate. Open the certificate with a text editor, remove the BEGIN and END CERTIFICATE lines and make sure the certificate itself is on one line.

Now that we have the certificate, configure the server to actually use it for authentication. First configure your website to require client certificates:

SSL Settings

Next, open up the Configuration Editor for the website..

Configuration Editor

..and enter the following into the Section: text box: system.webServer/security/authentication/iisClientCertificateMappingAuthentication. Change enabled to True and click on the ellipsis on the right of oneToOneMappings. Click on the Add on the right of the dialog and paste your client certificate value to the right place (make sure it’s really one line of text). Next, enter a valid username and password for your local environment.

One to one mapping config

Exit the dialog and apply the changes. These changes will be applied not to your Web.config file but to your applicationHost.config file (in %systemroot%\System32\inetsrv\config).

Testing

We should now have a valid setup that you can test so we open up a browser and go to https://www.sslclientauth.local. The browser should ask for a certificate:

Browser requests certificate

And we finally have access to our website!

Things that can go wrong

Incorrect username or password

When you do not enter a username and password or you enter incorrect values, the error you receive is a 401.1 – Unauthorized. This may suggest that there is something wrong with your certificate but that doesn’t have to be the case. If you’ve entered incorrect credentials, you’ll see error code 0x8007052e, as in the following screenshot.

Invalid mapped credentials

Base64 client certificate incorrect

You have had to export the client certificate to base64 and then open the file in a text editor, remove the begin and end lines and remove all CRLF’s. Something may have gone wrong in the process so you end up with an incorrect or invalid base64 string. You’ll get a 401.1 – Unauthorized again. However, this time you see either error code 0x80093102 or 0x8009310b.

And finally…

Keep in mind that all we have done is to configure authentication, not authorization! If I present another client certificate that has a valid trust chain, I can gain access to the site as well. In one of the last screenshots you see a certificate named SSLClientAuthClient2. If I select that one, I also see my hello world page. The difference between both access attempts is that with a valid certificate I enter my website with an authenticated principal while with the invalid certificate I’m not authenticated. You’ll have to specify authorization rules for your website or part of your website to actually deny users access.

Ronald Wildenberg

Author Ronald Wildenberg

Coming from an Artificial Intelligence background, turned developer after graduating. Interested in the tiny programming language details that make your life simpler but also in high-level designs that solve business problems in the most efficient way. And everything in between of course.

More posts by Ronald Wildenberg
7 January 2014

Join the discussion 15 Comments

  • Thiago says:

    Good job!

    Could you please, show how to do client certification authentication in a public scenario?
    In others words, if my site has internet access and i want to authenticate clients with digital certificates issued by a specific CA… how can i do? Mapping one-to-one, in this case, isn’t be able.

    • First you’d have to obtain a server certificate for identifying your server. That’s standard SSL. The client certificates can be anything you like as long as they are trusted by the server. This means they have to be derived from a (potentially self-signed) certificate that’s installed in the trusted root store on the server.

      Next it’s up to you. You can distribute the same client cert to all your clients and use one-to-one mapping to map this certificate to a single user (why is one-to-one not available by the way??). You can give each client his own cert (and use one-to-one mapping). Or anything in between.

      You can also use many-to-one where you specify rules that determine how certs maps to a user. In both one-to-one and many-to-one it comes down to mapping a certificate to a local (or domain) user on your server (the ‘mapping’ part).

  • Nice tutorial thanks. Essentially the same as this for linux: http://www.garex.net/apache/

    But how can you make sure only your issued client certificates have acces? On aopache its this:

    SSLRequireSSL
    SSLRequire %{SSL_CLIENT_S_DN_O} eq “garex AG” and
    %{SSL_CLIENT_S_DN_OU} in {“Fun dept.”}

    but where do you do that with IIS?

    • In the described one-to-one mapping scenario, a certificate is mapped to a user. It is the user that you should authorize. Authorization of a user can be done in a web application Web.config file on a url basis (e.g.: /Sensitive.aspx is only available for Administrator). Or it can be done in-application if more advanced authorization scenario’s are required.

      The least you should do when configuring this is to ensure only authenticated users have access to your site. This is easily accomplished in the root Web.config of your website. Check here for more info: http://msdn.microsoft.com/en-us/library/8aeskccd(v=vs.100).aspx (users attribute).

  • Dang says:

    Hi Ronald,

    I am trying to configure my https site to accept client certificates, which works when I use an ECA I purchased. However, I need to be able to authenticate with self-signed certificates, but when I log into my site, I’m only prompted for the ECA. The self-signed client certificate doesn’t display in the prompt. The client and server certificate were issued by a self-signed root certificate, which is installed in the trusted root authorities list of the computer account. Using “Require” is not an option in this app since there is some complex business logic that has to get handled by the application. Is there something that I’m missing?

    • Hi Dang – This can happen when the certificate is not in your personal store on the machine from which you want to access the website, can you verify that? Another reason may be that you did not specify the correct certificate purpose (client authentication). Check out this screenshot from my blog post for details: https://itq.nl/wp-content/uploads/2013/12/04-ClientCert.png.

      Note that if your browser does not present the certificate, this is a problem on the client, not on the server. The browser simply checks your certificate store and presents all certificates eligible for client authentication.

  • Prasad says:

    Hi,

    I have followed all the given steps to create root, server and client certificates. I have hosted sample website with HTML page and did SSL settings, client certificate configuration settings as mentioned.

    Finally, I tried to access the website by selecting the client certificate from the pop-up window. But, I ended with below error:

    HTTP Error 403.16 – Forbidden
    Your client certificate is either not trusted or is invalid.

    Detailed Error Information:
    Module IIS Web Core
    Notification BeginRequest
    Handler ExtensionlessUrlHandler-Integrated-4.0
    Error Code 0x800b0109
    Requested URL https://localhost:443/
    Physical Path E:SampleRoot
    Logon Method Not yet determined
    Logon User Not yet determined

    Could you please let me know what I missed here.

    Regards,
    M. Prasad Reddy.

  • Ryan says:

    Thank you. This is a very well-written and complete guide. Worked like a charm!

  • Bruno Toscano says:

    Excellent tutorial just I need!!!. Keep doing that

  • Sven says:

    Hey,

    do you know, if there is a setting, to only allow one special client certificate (e.g. in your case “WHERE Issuer=’WebSSLTestRoot’” ? I want to suppress the client certificate dialog, because our users choose always the wrong one ^^ It must somehow be possible, because other services of our company do that but not with IIS. Unfortunately it is a big company, so we can’t simply ask them what might be the problem LOL.

    • This is browser behavior that can not be forced by the server. The default behavior for IE in the intranet zone is not to prompt for a certificate when only one ‘suitable certificate’ exists. A ‘suitable certificate’ is one where the key purpose is client authentication. So if there are multiple client authentication certificates, IE will always show a selection dialog. I don’t know the behavior in other browsers.

  • Eric Belair says:

    This is an excellent explanation. Your spot on about authorization! That’s the only piece of the puzzle that I cannot figure out. I have a website configured for Anonymous access throughout, with the exception of one directory, which is configured for IIS Client Certificate Authentication. When I leave the Authorization Rules set to the default (Allow All Users), anyone with a Client Cert from a trusted source can access it. I tried to remove that rule for the directory and add an Allow rule for the user that is mapped to the client cert, but I get a 401.2 every time. Any idea how to resolve this?

  • Tuan says:

    Hi Ronald,

    I followed your guidelines, but always got HTTP Error 403.7 – Forbidden.

    The page you are attempting to access requires your browser to have a Secure Sockets Layer (SSL) client certificate that the Web server recognizes.

    Popup to select certificate is not shown. I’m checking inside the development server only. I checked certificates, they look seem okay. Do you have any ideas?

    Thanks,

    Tuan

Leave a Reply