One of the frustrating limitations in supporting secure websites has been the inability to share IP addresses among SSL websites. In the day, there were a few ways to solve this limitation. One, you could use multiple IP addresses, binding a SSL certificate to each combination of an IP address and standard SSL port. This has been the best method to date but it is administratively heavy and not necessarily a good use of valuable IP addresses. Another approach was to use additional non-standard ports for SSL. While this saved IP addresses, you would potentially run up against strict firewall or proxy limitations making this method undesirable. Finally, in the IIS 7 and 7.5 worlds you could use host-headers to share a certificate among websites but you were limited to a single certificate that each web site would have to share.

The reason behind these limitations rest in the handshake that takes place between the browser and the web server. When a SSL client request is initiated, the HTTP header data is not available to the web server. Only after successful handshake are the headers encrypted and sent to the web server. Too late to allow for successful redirection to the desired web site.

Solving this limitation required an extension to the Transport Layer Security (TLS) protocol that includes the addition of what hostname a client is connecting to when a handshake is initiated with a web server. The name of the extension is Server Name Indication (SNI). Of course, extending the definition of a protocol is never as easy as updating an RFC. Both client and server compatibility are required to make use of these extensions. On the client side, roughly 95% of browsers support SNI. Specifically those are:

  • Internet Explorer 7 or later
  • Mozilla Firefox 2.0 or later
  • Opera 8 or later
  • Google Chrome 6 or later
  • Safari 3 or later
  • Test Your Browser

In the Microsoft world, support for the SNI extensions to TLS were introduced with Windows Server 2012 and IIS 8.  Through the Internet Information Services (IIS) Manager and a web sites bindings UI, SNI can be specified for a HTTPS site along with a host header:

SNI-SSL-Binding-1

There are many resources on the Internet that deal with setting up and configuring a site using SSL bindings as well as utilizing SNI from within the IIS Manager.  Where I’d like to focus the second part of this blog is in creating SNI web-bindings using PowerShell.  As a driver for implementing SNI is the scalability it provides, this scalability might be for naught if not coupled with the ability to deploy a solution without the use of a GUI.

There are three parts to successfully assigning and associating any SSL binding with a website through PowerShell:

  1. A SSL binding needs to be created for the web site
  2. A certificate needs to exist in the local machine certificate store
  3. A SSL binding relationship needs to be created to associate a certificate with a web site
Creating the Web Site Binding

Creating the web site binding is a straightforward process.  The following PowerShell sequence would be used to create the binding and assign the correct port, host header and specification for use of SNI:

[code language=”powershell” gutter=”true” light=”true”]
# Import IIS Management PowerShell Module
Import-Module WebAdministration

$hostHeader = "test.com"

New-WebBinding -Name "Test Website" -Protocol "https" -Port 443 -HostHeader $hostHeader -SslFlags 1
[/code]

The name specified would be the name of the web site you’d like to add the binding to.  The protocol and port are standard for SSL bindings.  The host header is the URL you’d like the web site to respond to.  Finally, SslFlags with a value of 1 enables SNI for this binding.

Retrieving the Certificate from the Certificate Store

While I won’t cover the process to request a certificate or import the certificate into the local machine store, there are two factors we need to address before using the certificate in the third and final step.

In order to use the certificate in IIS it is critical that the certificate is imported allowing the private key to be exported.  If a certificate is used without an exportable private key, IIS will be unable to bind that certificate.

Creating the SSL association in the third step requires we have some reference to the certificate we’d like to associate with the web site.  There are two values that can be used.  The thumbprint of the certificate or a reference to the certificate object itself.

In order to retrieve the thumbprint of a certificate the following PowerShell command is used:

[code language=”powershell” gutter=”true” light=”true”]
$thumbprint = (Get-ChildItem Cert:\LocalMachine\My | Where-Object {$_.FriendlyName -eq "Test Cert"}).Thumbprint
[/code]

In the above example the friendly name of the certificate is used as the matching context.  One could also use the subject instead.

In order to get a reference to the certificate itself the following syntax can be used:

[code language=”powershell” gutter=”true” light=”true”]
$certificate = Get-ChildItem Cert:\LocalMachine\My | Where-Object {$_.FriendlyName -eq "Test Cert"}
[/code]

After this step you will now either have a direct reference to the certificate or the value for the certificates thumbprint.

Creating the SSL Association

The final step in the puzzle is tying together both the binding and the certificate.  This can be the trickiest part to get right.  PowerShell doesn’t provide a native cmdlet to directly do this. Instead, one needs to use the IIS drive exposed by the WebAdministration module to create a SslBinding object and associate that object with the certificate.

The PowerShell sequence for that task is as follows, if you’re using the certificate object:

[code language=”powershell” gutter=”true” light=”true”]
New-Item -Path "IIS:\SslBindings\!443!test.com" -Value $certificate -SSLFlags 1
[/code]

If you’re using the thumbprint your command would be:

[code language=”powershell” gutter=”true” light=”true”]
New-Item -Path "IIS:\SslBindings\!443!test.com" -Thumbprint $certificate -SSLFlags 1
[/code]

If successful, you should receive confirmation displaying the host name, along with the site the host name is bound to.  To confirm that SNI is in use run the following command from the command line:

SNI-SSL-Binding-2

In the above, notice the SSL binding is using the hostname:port syntax which confirms SNI is in use.

Following the above steps will allow you to take advantage of the new Server Name Indication (SNI) implementation in Windows Server 2012 and IIS 8.

Category:
FIM, SharePoint, Technology
Tags:
, , ,

Join the conversation! 7 Comments

  1. This is a good article however I have a couple of comments:

    This statement is simply untrue:

    “n order to use the certificate in IIS it is critical that the certificate is imported allowing the private key to be exported. If a certificate is used without an exportable private key, IIS will be unable to bind that certificate.”

    The private key does not need to be exportable and in fact setting it to be exportable is not recommended from a security perspective.

    There is no mention of how to bind certificates using the Central Certificate Store feature of IIS which takes quite a different approach from what is described here where it is not not necessary to create an association to the certificate.

  2. Any way to pass a $Port variable instead of hard coding the port number (443 in the article example)?

  3. Great article. Thank you.

    I tried the other way of first creating a SSLBinding in IIS (http.sys) using “netsh http add sslcert” and then created the binding for the website for the same HostHeader as explained in https://baskisumiwordpresscom.wordpress.com/2016/10/04/associating-a-website-with-ssl-certificate-and-using-hostname-port-combination/

Comments are closed.