Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / IIS

Insecure Transport – Missing Public Key Pinning

5.00/5 (2 votes)
30 May 2018CPOL12 min read 20.5K  
HTTP Public Key Pinning (HPKP)

Table of Contents

Introduction

This article shares with the reader the steps on how to implement HTTP Public Key Pinning (HPKP) security policy/control. This article also includes the steps to create self signed certificate, implement the security control and some tips to validate the control.

Here are some good summary about HPKP from Mozilla and OWASP.

Please note that HPKP is not compatible with all browsers yet but there is no wrong to experiment it. You do not need to have an authentic certificate signed by reputable CA in order to get an idea on how HPKP work.

Hopefully this article will empower someone to implement this security policy in their environment or prepare them for future opportunity.

Create self-signed certificate through IIS

To create SSL self signed server certificate through IIS

  1. Under IIS Manager, click on the server name
  2. On the Features View, click on Server Certificates
  3. Under the Actions, click on Create Self-Signed Certificate
  4. Specify a friendly Name for the certificate, in this example, I’ll name it MyCert1

Figure 1

create SSL self signed server certificate through IIS

Create self-signed certificate using OpenSSL

To create SSL self signed server certificate using OpenSSL, see below

1. Download and install the OpenSSL for windows
2. Open a command prompt and navigate to the OpenSSL bin folder
3. Enter the command in listing 1 to set the environment variable

Listing 1

 set OPENSSL_CONF=C:\OpenSSL-Win32\bin\openssl.cfg
set RANDFILE=C:\OpenSSL-Win32\bin\.rnd

 

Figure 2
openssl variables

 

4. Enter the following command to create a new self-signed certificate with 4096 bits using x509 structure and a key file. The certificate is valid for 365 days

Listing 2

openssl req -newkey rsa:4096 -days 365 -x509 -nodes -out mycerts\myninja.ysa.cer -keyout mycerts\myninja.ysa.key

5. You will be prompted to enter the Country Name, State, etc… Since the URL to my website is myninja.ysa, the Common Name will be myninja.ysa

Figure 3
openssl create SSL

6. Next, we will generate the PKCS#12/PFX using the certificate and key using the command in listing 3. This command will generate a .pfx file with a friendly name "myninja.ysa". We will import the certificate into IIS in later section.

Listing 3

openssl pkcs12 -export -out mycerts\myninja.ysa.pfx -inkey mycerts\myninja.ysa.key -in mycerts\myninja.ysa.cer -name "myninja.ysa"

7. You will be prompted to enter the password to export the certificate. You can leave it blank by hitting enter twice

Figure 4
openssl create PFX

Create certificate chain with OpenSSL

If you are interested to create self signed server certificate chain using OpenSSL, follow the below steps
1. Let assume the Root/CA is myninja.ysa, enter the command in listing 4 to create a Certificate Signing Request (CSR) or certificate request

Listing 4

openssl req -newkey rsa:4096 -nodes -out mycerts\sub.myninja.ysa.csr -key mycerts\myninja.ysa.key

2. You will be prompted to enter the Country Name, State, etc… Let assumed the URL to my website is sub.myninja.ysa, and under the Common Name, I will enter sub.myninja.ysa

Figure 5
openssl create SSL Chain
3. Run the following command in listing 5 to complete the request. You can read more from here to find out the definition for the OpennSSL option/argument

Listing 5

openssl x509 -req -days 365 -in mycerts\sub.myninja.ysa.csr -CA mycerts\myninja.ysa.cer -CAkey mycerts\myninja.ysa.key -set_serial 01 -out mycerts\sub.myninja.ysa.cer

4. Shown in figure 6 is the output and the new certificate will be created under mycerts\sub.myninja.ysa.cer folder

Figure 6
openssl Complete CSR
5. Let generate the PKCS#12/PFX using the command in listing 6 so that we can import it into the IIS Server Certificates

Listing 6

openssl pkcs12 -export -out mycerts\sub.myninja.ysa.pfx -inkey mycerts\myninja.ysa.key -in mycerts\sub.myninja.ysa.cer -name "sub.myninja.ysa"

Next, we will spend a minute to examine the newly created certificate. Navigate to the mycerts folder and double click to open the myninja.ysa.cer and sub.myninja.ysa.cer certificates as shown in figure 7.

Figure 7
Certificate General tab

Click on the certificate Path tab. Under the Certificate status there will be a message "This CA Root certificate is not trusted because it is not in the Trusted Root Certification Authorities store." and "The issuer of this certificate could not be found." In addition, the child certificate path didn't show the myninja.ysa as root. Refer to figure 7 and 8

Figure 8
Certificate Path tab

To remedy this, click on the General tab of the myninja.ysa certificate. Click on the Install Certificate button. Place the certificate in the Trusted Root Certification Authorities. At the end click Finish to complete the process. You will see a Security Warning prompt "You are about to install certificate from a certification authority (CA) claiming to represent myninja.ysa… Do you want to install this certificate", click Yes to continue. After that double click on the certificate and you should observer that the certificate status show "This certificate is OK." And the chain certificate path shows the myninja.ysa as root as shown in figure 9.

Figure 9
Certificate OK

Import certificate into the IIS Server Certificates

In this section we will touch base on the steps to import the certificate into the IIS

  1. Under IIS Manager, click on the server name
  2. On the Features View, click on Server Certificates
  3. Under the Actions, click on Import…
  4. Browse to the MyCerts folder and select myninja.ysa.pfx, enter the password
  5. Repeat step 4 for sub.myninja.ysa.pfx
  6. At the end of the day, you should have three certificates listed under the Server Certificates

Figure 10
IIS Server Certificates

Bind SSL to a Site

To bind a SSL Certificate to a site

  1. Under IIS Manager, expand the server name
  2. Select the site
  3. Click on Bindings… under Action menu
  4. Click on Add, Type, and select https. Enter a different port number if other than 443. Under SSL Certificate, choose myninja.ysa, Click OK and Close to complete the step
  5. You can iterate the above step to try out other certificate

Figure 11
IIS Server SSL binding

Configuring HPKP

Here is the HPKP syntax:
Public-Key-Pins: pin-sha256="base64_Primary_Key"; pin-sha256="base64_Backup_Key"; max-age=Expire_Time; includeSubdomains;

And here is a brief explanation to the parameters:

Pin-sha256 Directive - Base64 encoded Subject Public Key Information (SPKI) fingerprint.
The max-age Directive - the length in seconds the browser should store the pinning details
Optional includeSubDomains directive - include all subdomains

Create Primary Pin

There are several ways to generate the primary key fingerprint. Let say the URL to my site is https://myninja.ysa/, and then I can run the command in listing 7 to generate the certificate fingerprint. In summary, the command connects to the host, read the public key from the certificate and encode it to base64.

Listing 7

openssl s_client -host myninja.ysa -connect myninja.ysa:443 | openssl x509 -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64

Shown In figure 12 is the output from command in listing 7. Press Control + C to return back to the prompt.

Figure 12
Primary pin
Alternately, since I have the certificate, I can also run the below command to generate the fingerprint by supplying the certificate

Listing 8

openssl x509 -in mycerts\myninja.ysa.cer -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64

Shown in figure 13 is the result from command in listing 8.

Figure 13
Primary pin 2
Ultimately, both methods will generate the identical fingerprint (aCJgrjda9Bvvpx791OQ8g6wksucYBFpmV3gX5sTEqyc=).

Create Backup Pin

I found some good reading from Scott Helme website regarding the backup pin. He pointed out that we can create some backup CSRs and includes their fingerprints in the header. To create a CSR, first run the following command.

Listing 9

openssl req -newkey rsa:4096 -nodes -out mycerts\MyBackup1.csr -keyout mycerts\MyBackup1.key

Then run the following command to generate the fingerprint

Listing 10

openssl req -pubkey < mycerts\MyBackup1.csr | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64

Shown in figure 14 is the output from command in listing 10

Figure 14
backup pin
If you put everything together, the header will look something like in listing 11. The max-age was set to 10 seconds initially, you can set it to one year or 6 months once you have verify everything is working correctly.

Listing 11

pin-sha256='aCJgrjda9Bvvpx791OQ8g6wksucYBFpmV3gX5sTEqyc='; pin-sha256='Mq5prDs0m6V/+DEFM/ML3NysUtYTur+Pwoqzk8ZA0w0='; max-age=10; includeSubdomains;

Configure HPKP in IIS

In this section, we will briefly discuss the steps to setup the HPKP on IIS.

  1. Under IIS Manager, expand the server name
  2. Select the site
  3. Under Features View, double click on HTTP Response Headers
  4. Under Actions, click on Add…
  5. Type in the Name: Pubic-Key-Pins and the value from Listing 11

Figure 15
IIS HPKP
Another way to accomplish this is to add the header through the web.config. Refer to listing 12 to get an idea where to insert the headers

Listing 12

 <?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <httpProtocol>
            <customHeaders>
                <clear />
    <add name="Public-Key-Pins" value="pin-sha256='aCJgrjda9Bvvpx791OQ8g6wksucYBFpmV3gX5sTEqyc='; pin-
sha256='Mq5prDs0m6V/+DEFM/ML3NysUtYTur+Pwoqzk8ZA0w0='; max-age=10; includeSubdomains;" />
            </customHeaders>
        </httpProtocol>
    </system.webServer>
</configuration>

How to test it?

First we need to have a valid certificate or certificate that signs by a trusted CA. You will see a similar error message in figure 16 if the certificate not signed by a valid CA. That not an issue, we can manually add the certificate into the client machine trusted store. This section covers the steps to export and install the certificate on client machine.

Figure 16
chrome error

Export the certificate

There are many ways to accomplish this task but for now, we will stick with Google Chrome. Let start by open the Google Chrome browser, navigate to the website. First thing you will see on the page is the "Your Connection is not private" warning. Click on the pad lock icon on the URL, then click on the Certification link under the Connection tab. Click on the Details tab, then click on Copy to file… button, click Next to continue. Under the Export File Format screen, select DER encoded binary X.509 (.CER), click on Next to continue. Pick a location to save the certificate file, click on Next and Finish to complete the certificate export process.

Install the Certificate

Browse to the location of the certificate, double click on it, Click on Install Certificate under the General tab. Leave the default option, click on Next to continue. On the Certificate Store screen, select Place all certificate in the following store, click on Browse and select Trusted Root Certificate Authorities and OK to close the window. Then click on the Next button to continue and Finish button to complete the installation. A warning message wills popup, click on Yes button to continue.

It will be much simpler to achieve the same on Internet Explorer (IE) browser. Here are the steps, right click the IE browser and then click on Run as administrator. Click on the Certificate error on the URL and then click on View certificates. Under the General tab, click on Install Certificate… button and repeat the step above to complete the certificate installation.

Figure 17
ie error

My other suggestion is, copy the certificate (myninja.ysa.cer) to the client machine and install it.

See the security control/policy in action

Now open the Google Chrome browser and navigate to https://myninja.ysa. You should see the difference between figure 16 and 18 where the certificate error no longer an issue.

Figure 18
chrome ok

On the same browser, open a new tab. Type in chrome://net-internals/#hsts on the URL, enter. Go back to previous tab and refresh the page, then click on the second tab (chrome://net-internals/#hsts), type in myninja.ysa in the domain textbox under query domain. Click on the query button and if everything setup correctly you should see something similar to figure 19.

Figure 19
chrome_query

Next, open up the web.config, modify the primary key by adding a random character at the beginning of the key. Save it, restart the IIS to be sure. On the Chrome browser, refresh the first tab (https://myninja.ysa), on the second tab type in myninja.ysa in the domain textbox under query domain. Click on the query button and compare the result in figure 19 and 20. You will notice that the fields in blue dots were empty. In some situation, you will see the message "Not found" if the key is not valid.

Figure 20
invalid key

Go ahead and remove the random character from the key in web.config. On the Chrome browser, refresh the first tab, on the second tab type in myninja.ysa in the domain textbox under query domain. You should see the result similar to figure 19 again.

If your site is public, you can scan the header through https://securityheaders.io/. Make sure to check the checkbox "Hide results" if you want to keep it private.

Remember early on, one of the purposes of certificate pinning is to prevent the adversary from carry on a Man-in-the-middle-attack (MITM) attack. One thing I can think of is using Fiddler as an example. If you don't have Fiddler, download a copy, it's free from http://www.telerik.com/fiddler. Open the fiddler and the refresh the site and you will see the result in figure 21. Click on the advanced link to toggle the details. Close the Fiddler and refresh the page again. You will noticed that the page load normally without the warning message.

Figure 21
Chrome_error_fiddler

Next, open the web.config and tamper the public key pin by adding a random character to the primary key. Clear the browser cache (Ctrl + Shift + Del) and then navigate to the website again. Open the fiddler and the refresh the site and you should see the result in figure 22. Notice the different between the message in figure 21 and figure 22. The latter has a link "Proceed to myninja.ysa (unsafe)" which will allow the user to proceed to the site.

Figure 22
Chrome_error_fiddler hsts
 

Point of Interest

If you pay attention to figure 21, the message said "You cannot visit myninja.ysa right now because the website uses HSTS". I'm not sure why it said HSTS instead of HPKP. HTTP Strict Transport Security (HSTS) is another important security policy which enforces all the communications to send over HTTPS. You can get information on how to implement it from here.

Another thing to keep in mind is that the HPKP configurations need to be updated each time we renew/replace the site SSL certificate. As mentioned in the beginning this security policy is not compatible with all the browsers yet and OWASP ranked it as low risk. Is always good to know how it works for future prosperity.

Conclusion

I hope someone will find this information useful and equip you for future opportunity. If you find any bugs or disagree with the contents or want to help improve this article, please drop me a line and I'll work with you to correct it.

History

03/04/2016 – Initial version

Resources

https://www.sslshopper.com/article-most-common-openssl-commands.html
http://luke.breuer.com/time/item/Generating_an_SSL_certificate_on_Windows_without_IIS/634.aspx
https://slproweb.com/products/Win32OpenSSL.html
https://langui.sh/2009/01/18/openssl-self-signed-ca/
https://scotthelme.co.uk/hardening-your-http-response-headers/
https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning
https://developer.mozilla.org/en-US/docs/Web/Security/Public_Key_Pinning
https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)