Baris is right! The SSL certificate configured on an IP:PORT binding (example: 100.74.156.187:443) always takes precedence in http.sys! So the solution is as follows:
Do not configure an IP:443 binding for your wildcard-fallback-certificate but configure a *:443 binding (* means "All Unassigned") for it.
If you have configured your wildcard certificate on the Azure Cloud Service SSL endpoint (as i have) you have to change the SSL binding created by the Azure Cloud Service Runtime (IISconfigurator.exe) from IP:PORT to *:PORT. I am calling the following method in OnStart of my web role:
public static void UnbindDefaultSslBindingFromIp()
{
Trace.TraceInformation(">> IISTenantManager: Unbind default SSL binding from IP");
using (var serverManager = new Microsoft.Web.Administration.ServerManager())
{
try
{
var websiteName = string.Format("{0}_Web", Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.CurrentRoleInstance.Id);
var site = serverManager.Sites[websiteName];
var defaultSslBinding = site.Bindings.Single(b => b.IsIPPortHostBinding && b.Protocol == "https");
defaultSslBinding.BindingInformation = string.Format("*:{0}:", defaultSslBinding.EndPoint.Port);
serverManager.CommitChanges();
}
catch (Exception ex)
{
Trace.TraceError(ex.ToString());
}
}
}
The following screenshot shows a working configuration of our cloud service. Please don't be confused about the non-standard ports. The screenshot is from the emulated cloud service.
One further thing to mention: Do not change all bindings to * because the HTTP (port 80) binding only works with IP:PORT binding in the deployed cloud service. Something else is bind to IP:80 so *:80 does not work because * stands for "all unassigned" and the IP is already assigned somewhere else in http.sys.
The context of the answer is that IIS 7 doesn't actually care about the certificate binding. IIS 7 only ties websites to one or more sockets. Each socket being a combination of IP + port. Source: IIS7 add certificate to site from command line
So, what we want to do is do certificate re-binding on the OS layer. The OS layer takes control of the SSL part, so you use netsh
to associate a certificate with a particular socket. This is done through netsh
using netsh http add sslcert
.
When we bind a (new) certificate to a socket (ip + port), all sites using that socket will use the new certificate.
The command to bind a certificate to a socket is:
netsh http add sslcert ipport=10.100.0.12:443 certhash=1234567890123456789012345678901234567890 appid={12345678-1234-1234-1234-999999999999}
How to
This part explains how to proceed step-by-step. It assumes you have some websites (aaa.my-domain.com, bbb.my-domain.com) running a *.my-domain.com certificate that is about to expire. You already have a new certificate that you already installed on the server but not yet applied to the websites on IIS.
First, we need to find out 2 things. The certhash of your new certificate and the appid.
certhash
Specifies the SHA hash of the certificate. This hash is 20 bytes long and specified as a hexadecimal string.
appid
Specifies the GUID to identify the owning application, which is IIS itself.
Find the certhash
Execute the certutil
command to get all certificates on the machine:
certutil -store My
I need not all information so I do:
certutil -store My | findstr /R "sha1 my-domain.com ===="
Among the output you should find your new certificate ready on your server:
================ Certificate 5 ================
Subject: CN=*.my-domain.com, OU=PositiveSSL Wildcard, OU=Domain Control Validated
Cert Hash(sha1): 12 34 56 78 90 12 34 56 78 90 12 34 56 78 90 12 34 56 78 90
1234567890123456789012345678901234567890
is the certhash
we were looking for. it's the Cert Hash(sha1) without the spaces.
Find the appid
Let's start of by looking at all certificate-socket bindings:
netsh http show sslcert
Or one socket in particular
netsh http show sslcert ipport=10.100.0.12:443
Output:
SSL Certificate bindings:
----------------------
IP:port : 10.100.0.12:443
Certificate Hash : 1111111111111111111111111111111111111111
Application ID : {12345678-1234-1234-1234-123456789012}
Certificate Store Name : MY
Verify Client Certificate Revocation : Enabled
Verify Revocation Using Cached Client Certificate Only : Disabled
Usage Check : Enabled
Revocation Freshness Time : 0
URL Retrieval Timeout : 0
Ctl Identifier : (null)
Ctl Store Name : (null)
DS Mapper Usage : Disabled
Negotiate Client Certificate : Disabled
{12345678-1234-1234-1234-123456789012}
is the appid
we were looking for. It's the Application ID of IIS itself. Here you see the socket 10.100.0.12:443
is currently still bound to the old certificate (Hash 111111111...)
bind a (new) certificate to a socket
Open a command prompt and run it as a administrator. If you don't run it as administrator, you'll get an error like: "The requested operation requires elevation (Run as administrator)."
First remove the current certificate-socket binding using this command
netsh http delete sslcert ipport=10.100.0.12:443
You should get:
SSL Certificate successfully deleted
Then use this command (found here) to add the new certificate-socket binding with the appid and the certhash (without spaces) that you found earlier using this command
netsh http add sslcert ipport=10.100.0.12:443 certhash=1234567890123456789012345678901234567890 appid={12345678-1234-1234-1234-123456789012}
You should get:
SSL Certificate successfully added
DONE. You just replaced the certificate of all websites that are binded to this IP + port (socket).
Best Answer
From here: http://www.orcsweb.com/blog/terri/making-ssl-administration-easy-iis8-centralized-certificates-store/
But wait there's more!
From here: http://blogs.msdn.com/b/kaushal/archive/2012/10/11/central-certificate-store-ccs-with-iis-8-windows-server-2012.aspx
So the moral of the story is: Underscores.