37

I installed a new SSL certificate into IIS7, removed the old certificate and setup the bindings for the new certificate - so https is now bound to the new certificate only.

I restarted IIS7 (and the Windows 2008 Server itself) and checked the certificate using the commands:

netsh http show sslcert

This showed the new certificate only, as I expected

certutil -store MY

This also only showed the new certificate and not the old one, as I expected

I also opened mmc and checked the certificates there and I only see the new one and not the old one.

I'm also using an account with Administrator privileges.

However — when I open a browser (from any computer) and go to the https site it is still using the old certificate. Even when I remove the old certificate from the browser it still gets sent the old one and not the new one.

Can anyone help me work out where I'm going wrong? How can I exorcize the old phantom certificate?

7 Answers 7

40

First a couple points that are probably the same for you

  • I was trying to update a certificate because it has expired.
  • I have multiple domains bound to the same IP. They happen to be a SAN certificate but that's probably irrelevant.
  • I was trying to use the centralized certificate store. Again I think this is irrelevant to most of my answer.
  • I had already attempted to update the certificate but it wasn't showing the new date.
  • You're probably in a panic right now if your old certificate already expired. Take a deep breath...

First I'd recommend strongly going to https://www.digicert.com/help/ and downloading their DigiCert tool. You can also use it online.

Enter in your website https://example.com and it will show you the expiration date and thumbprint (what MS calls the certificate hash). It does a realtime lookup so you don't have to worry whether or not your browser (or intermediate server) is caching something.

If you're using the centralized certificate store you'll want to be 100% sure the .pfx file is the latest version so go to your store directory and run this command:

C:\WEBSITES\SSL> certutil -dump www.example.com.pfx

This will show you the expiration date and hash/thumbprint. Obviously if this expiration date is wrong you probaly just exported the wrong certifcate to the filesystem so go and fix that first.

If you are using the CCS then assuming this certutil command gives you the expected expiration date (of your updated certificate) you can proceed.

Run the command:

netsh http show sslcert > c:\temp\certlog.txt
notepad c:\temp\certlog.txt

You likely have a lot of stuff in here so it's easier to open it up in a text editor.

You'll want to search this file for the WRONG hash that you got from digicert.com (or the thumbprint you got fromChrome).

For me this yielded the following. You'll see it is bound to an IP and not my expected domain name. This is the problem. It seems that this (for whatever reason I'm not sure) takes precedence over the binding set in IIS that I just updated for example.com.

IP:port                      : 10.0.0.1:443
Certificate Hash             : d4a17e3b57e48c1166f18394a819edf770459ac8
Application ID               : {4dc3e181-e14b-4a21-b022-59fc669b0914}
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

I don't even know where this binding came from - I don't even have any SSL bindings on my default site but this server is a few years old and I think something just got corrupted and stuck.

So you'll want to delete it.

To be on the safe side you'll want to run the following comand first to be sure you're only deleting this one item:

C:\Windows\system32>netsh http show sslcert ipport=10.0.0.1:443

SSL Certificate bindings:
-------------------------

IP:port                      : 10.0.0.1:443
Certificate Hash             : d4a17e3b57e48c1166f18394a819edf770459ac8
Application ID               : {4dc3e181-e14b-4a21-b022-59fc669b0914}
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

Now we've verified this is the 'bad' thumbprint, and expected single record we can delete it with this command:

C:\Windows\system32>netsh http delete sslcert ipport=10.0.0.1:443

SSL Certificate successfully deleted

Hopefully if you now go back to Digicert and re-run the command it will give you the expected certificate thumbprint. You should check all SAN names if you have any just to be sure.

Probably want to IISRESET here to be sure no surprises later.

Final note: If you're using the centralized certificate store and you're seeing erratic behavior trying to even determine if it is picking up your certificate from there or not don't worry - it's not your fault. It seems to sometimes pick up new files immediately, but cache old ones. Opening and resaving the SSL binding after making any kind of change seems to reset it but not 100% of the time.

Good luck :-)

6
  • 4
    You are a Simon among Simons. In our case, it turned out that our server had 'cached' the expired cert under [::1]:443 whereas updating the cert in IIS only updated the record for 0.0.0.0:443. Thank you!
    – tuespetre
    Aug 16, 2016 at 16:33
  • 1
    This resolved my issue with multiple domains on the same IP; not using centralised cert store. Jun 15, 2017 at 16:23
  • 1
    I've had to use this a few times. The PLESK web hosting management software occasionally messes up the certificate bindings and I end up needing the above netsh commands to remove the offending binding. Not sure which versions are all affected, but I'm using current version of PLESK Onyx on Windows Server 2016.
    – BenSwayne
    Feb 2, 2018 at 17:13
  • In my case it was by hostname and port. So, to filter and delete by hostname, the commands would be: "netsh http show sslcert hostnameport=www.example.com:443" and "netsh http delete sslcert hostnameport=www.example.com:443" Dec 15, 2018 at 1:59
  • i also had an issue
    – Max
    Feb 10, 2022 at 8:05
15

Check the certificate that is bound to the site in IIS. You can right-click on the site and choose edit bindings. In there, you should see a binding for port 443 that is associated with an SSL cert. That may still be pointing at the old one.

5
  • I checked and the certificate in the bindings for port 443 is the new certificate, not the old one. Thanks for your suggestion.
    – joechip
    Oct 11, 2011 at 16:17
  • 1
    Weird, I've never had this happen. Although I never remove the old certificates. How are you sure you're still getting the old cert? Is it showing that it's expired?
    – Tatas
    Oct 11, 2011 at 17:25
  • Yes, in the browser you can check the certificate's details (expiration date, etc) and its the old one that IIS7 is serving.
    – joechip
    Oct 11, 2011 at 17:27
  • 2
    I have seen this with - Chrome. Chrome caching the old certificate and showing that to the user.
    – TomTom
    Jun 17, 2014 at 15:10
  • I never thought to check this - It seemed like it was just binding ips to protocols. Now I know, and I thank you for time saved! Nov 9, 2021 at 1:15
4

I had the same issue and checked the bindings also. I had 2 apps installed in IIS, one was using the new certificate, one using the old.

To fix, I had to remove the certificate from the server completely (then possibly a reboot).

From IIS Manager -> (IIS tree root) -> Server Certificates icon, select the old certificate and click Remove in the Actions pane.

2
  • 2
    Likewise we actually had an additional STOPPED site which referenced the old certificate, and once we updated that site to use the new one, the actual live site started showing the new certificate!
    – Action Dan
    Jul 1, 2018 at 21:22
  • Same here, i had to remove the old one before the new one worked, thanks! Sep 25, 2020 at 3:44
3

I just worked it out. The server was actually sitting behind an ISA server so we also had to install the new SSL certificate to the ISA server.

1

I experienced this during an IPv6 upgrade. I had IIS providing a redirect in case someone tried to access a service via HTTP that wasn't actually a web server based service. I updated the actual service (a voice server) to be IPv6, however I had failed to update the bindings for the redirect to include the IPv6 addresses.

This resulted in the resolutions failing over to a globally bound catch all site which had the outdated certificate on it. Since the catch all simply 404's, it appeared that the site wasn't working, when in reality it was hitting the wrong site.

1

Simon's answer has got me on the right track.

In my case, I've been trying to "renew" an existing certificate on a long running Windows 2012 R2 with IIS 8.5.

The first thing to note is that apparently it is a good idea to import the PFX certs using the MMC (pointer to a HOWTO at Digicert), rather than just use the icon "Server Certificates" in the IIS Management util. Why: becase after messing with the old bindings from command line (netsh http delete sslcert), and after deleting and re-importing the cert VIA IIS manager's "Server Certificates", I kept getting a funny error saying A specified logon session does not exist. It may already have been terminated. (Exception from HRESULT: 0x80070520) (another link to Digicert) when trying to re-bind the new certificate. And that kept happening despite me trying again and "allowing export", as suggested in the Digicert KB article. I needed to import the new cert via MMC, and then the bindings started to work again.

Also: this whole affair has taught me a few lessons about the logic of certificate bindings combined with "virtual host resolution logic". The command netsh http show sslcert shows you in all its nude beauty, what bindings you have configured using that single certificate. It may not be something the IIS Management has devised - it may be your own creation from two years ago :-) In your IIS, you may have something like:

+ Your IIS instance
  + Your default virtual host (responding to 0.0.0.0:443)
    + also responding to a particular IP address (say 1.2.3.4:443)
    + also responding to a name-based alias (www.yourname.com:443 - SNI)
    + and another name-based alias (www.someothername.net:443 - SNI)

In that case, the web server (understandably and correctly) follows some simple "resolution rules". If you match a particular "name" and you have Server Name Indication (SNI) enabled in its HTTPS binding, you get the cert that's bound to that particular name. If you don't have an SNI-based binding to that name, you get a cert based on the destination IP address that you've used to contact the server (even if you used a particular DNS name at the command line or browser address row) - that underlying IP address, combined with the binding configured in your IIS. Third, if even the IP address does not have a binding in your IIS, the "default" binding applies.

So the server-side bindings get listed neatly together in the output of netsh http show sslcert - but you have to figure out the resolution hierarchy on your own. Originally I thought that IIS was caching something, and that this command-line curse showed me the "cached entries". And I was probably wrong - I just wasn't aware of the several manual bindings established, and I kept hitting some other rule than the one I thought I'd just reconfigured :-) Just imagine how many times I restarted the IIS.

Another note: I kept using the "openssl" command-line utility in Linux to query the server to check the certificate. I kept using:

openssl s_client -connect www.mywebsite.com:443 -showcerts | openssl x509 -text -noout

Initially I wasn't aware that www.mywebsite.com in that command just gets translated into an IP address, and does not get asked for via SNI ! Even when, in despair, I deleted the name-based cert binding in IIS. Thus, I was getting some IP-based or global binding on part of the IIS = I got what I deserved ;-) After a bit of pulling my hair, it dawned on me that I needed some arg to openssl, that would make it ask for a particular HTTPS name-based virtual host via SNI. The argument for that is called -servername:

openssl s_client -connect www.mywebsite.com:443 -servername www.mywebsite.com -showcerts | openssl x509 -text -noout

Which means, that you can actually (ab)use this for things like

openssl s_client -connect 192.168.30.41:443 -servername www.my-test-website.com -showcerts | openssl x509 -text -noout

or

openssl s_client -connect www.mymachine.net:443 -servername www.not-yet-in-dns.com -showcerts | openssl x509 -text -noout

Thanks for bringing up this topic. I hope my scribbling helps someone...

0

In case someone still stumble onto this issue. Mine was solved by going to

C:\inetpub\wwwroot

Then you will find a web.config file, open it using notepad and remove the line with

<httpRedirect enabled="true" destination="http://foo.company.org" />

Save and try again to access the localhost or root site of your IIS server.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .