Today I got the following question:
"I have two sites (siteV1.mysite.com and sitev2.mysite.com). They listen on the same IP address and port. We generated a certificate for siteV1.mysite.com and SSL is working properly. The problem is that some of our customers use siteV2.mysite.com and they are getting certificate errors. What's the problem?"
Here is the issue:
There are three pieces of data to uniquely identify an IIS site:
- The IP address
- The Port
- The Host name which HTTP 1.1 clients send as an HTTP request header.
This IP:Port:Hostname triplet is called a binding. The binding "192.168.1.192:80:myserver" for example represents a site that listens on IP address 192.168.1.192, port 80, host-header myserver.
The very first things IIS (HTTP.SYS to be more precise) does when a request comes in is to read the site's configuration. Connection limits and timeouts are examples of site configuration. The site binding is used to find the right site configuration. The SSL certificate seems to be another great example of site configuration - the SSL certificate is needed to decrypt the encrypted SSL data coming from the client.
And the IIS User Interface certainly makes it appear as if the SSL certificate would be site configuration, too - doesn't it? In reality however you can't bind a SSL certificate to a site. The IIS UI is fooling you. But why?
It's a chicken and egg problem: The host name is encrypted in the SSL blob that the client sends. Because the host name is part of the binding IIS needs the host name to lookup the right certificate. Without the host name IIS can't lookup the right site because the binding is incomplete. Without the certificate IIS can't decrypt the SSL blob that contains the host name. Game over - we are turning in circles.
What IIS does under the covers is to ignore the host name. IIS binds the certificate to IP:Port and warns you when you try to bind a certificate to the same IP:Port combo with different host names.
But there is a way if you need two different sites on the same IP:Port. You can accomplish this by getting a certificate that contains both common names, i.e. sitev1.mysite.com and sitev2.mysitem.com. Cert Authorities usually allow more than one so called "common names" in a certificate. By binding the certificate to one of the two sites you won't not get certificate errors anymore. The client is happy if one of the names in the certificate matches.
But there is another caveat: you can't use the IIS7 User Interface to add a host header to an SSL site binding. You have to use command-line tools, do it programmatically or edit applicationhost.config directly. Here is an example and a link how you can it via command-line:
appcmd set site /site.name:"MySite V2" /+bindings.[protocol='https',bindingInformation='*:443:sitev2.mysite.com']
And last but not least: with IIS7 you can use the following command to figure out what certificate is bound to a particular IP:Port combination:
netsh http show sslcert
This command will show the IP:Port binding but also some other SSL settings.