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
netsh http show sslcert
This command will show the IP:Port binding but also some other SSL settings.