Have you ever wondered what would happen if you tried to connect to a website that was serving a certificate chain way longer than normal? I know, me too. Often times security research is about thinking outside the box, and this is just one of those times. Plus we might learn a few things along the way.
I’m new here. What is a certificate chain?
When you connect to a secure website, your browser uses a TLS certificate to verify the authenticity of the connection and to help set up the encryption of the connection. The way that you know that the certificate is valid is either because you have seen it before and saved it as a remembered certificate(this is common in a self-signed certificate situation or with SSH), in most cases someone else that you trust “signs” the website’s certificate. Allow me to use Star Trek The Next Generation characters(source) to illustrate how this works. If you meet Ensign Tony at Ten Forward, the next time that you meet him you will know who he is based on what he looks or sounds like. This is how self-signed certificates work.
If you have never met Ensign Tony before you may have trouble believing he is who he says he is. You trust Captain Picard though, and when he tells you who Ensign Tony is you believe him. So your knowledge of who Ensign Tony is is chained to your trust of Captain Picard. Captain Picard is playing the role of a trusted root certificate authority in this scenario. When most people think of how certificates are issued they think of them being issued this way, because that is how it happened 10 or more years ago. The vast majority of certificates aren’t issued this way anymore.
So Captain Picard is a busy guy, far too busy to point out low ranking ensigns to you. If Geordi tells you who Ensign Tony is, you believe him because you trust Picard, he trusts Geordi and therefore you trust Geordi. Captain Picard can not only fire and replace Geordi at any time, he can have many intermediates. This scenario is how the vast majority of certificates are issued today. The fact that there can be many intermediates chained to one root certificate authority spreads the risk of a compromise to the many intermediates certificate authorities and away from the root. They can be replaced easily without much disruption.
So normally there is only one intermediate certificate authority in the chain. In some cases two are involved, think of Geordi having a subordinate that works for him and therefore you would also trust them.
Does It Go To 11?
Often times, it isn’t about what happens 99% of the time that is interesting, but what happens at the edges. If most certificate chains are 2-4 certificates long, then what happens when we use like 100? So I tweaked up an OpenSSL config in order to be able to issue CA certificates, and then wrote a quick bash script to recursively sign a chain of 100 certificates and then cat them all together into a big chain. I won’t bore you with the details of how to do that, maybe save it for a follow-up post. I could have set up an instance of apache or nginx to serve up this certificate but instead decided to use SSLSplit in order to sign leaf certificates for all incoming connections and then arpspoof the client I was testing with to ram everything through SSLSplit. What does that all mean? When I point the browsers of the client I’m on at any https:// website, SSLSplit is going to mint an “Ensign Tony” for that website and send him and about 100 “Geordi’s” and 1 “Captain Picard” down to my browser.
So by default when you connect using chrome, you get a certificate error. This is the expected behaviour, as after all our monster certificate chain is still nothing more than a very fancy chain that starts with a self-signed certificate. On google.com we get an HSTS error, which is interesting. I don’t believe google.com actually sends an HSTS header, but Google does some fancy public key pinning on there own sites. Perhaps the message is returned in both cases? Looking into it a bit more, it looks like Google pre-loads a bunch of sites as HSTS and even has a site where you can submit your own site to be preloaded.
On Wikipedia’s site we get a more familiar certificate error message.
Internet Explorer took one look at my chain and said “NOPE!” not even going to try to connect to that site. Whatever, I guess they figure that there is a limit to how long a certificate chain should be, and this is how they have decided to deal with it.
Last on the list to test was Firefox. I can’t remember in which talk on YouTube I heard it, but I was sure that Mozilla’s Network Security Services(NSS) went as deep as something like 37 chained certificates, which seemed like an odd number. Recalling that obscure and useless piece of information, I was sure that I would achieve similar results to IE. I did… kinda. I tested with several secure sites in Firefox, and they all had the same result. Firefox would take every last piece of CPU from the system and wouldn’t let go until you killed/closed/crashed it. I noticed that it was sucking on my AMD 7850K so hard that it was affecting the stability of other applications. I thought maybe, just maybe, it was using all that extra CPU to check the signatures on my fake chain, so I let it run like that several times for more than half an hour. Nothing.
During my testing I wanted to ensure that I had actually built and signed my certificate chain properly so I installed the root self-signed certificate into the certificates MMC snap-in.
And then did my testing with the browsers again. Firefox doesn’t use Window’s certificate store so I didn’t test it again. IE and Chrome both do use the Windows certificate store. IE did the exact same thing as before I had installed the root certificate, which was nothing. Chrome loaded up all of the sites that I expected it to load up, my banks, Wikipedia etc. It also surprised me as it loaded up Google.com.
Google uses something called Public Key Pinning in Chrome, which I always thought meant that it was impossible to impersonate Google.com, and other Google properties, in Chrome. Well looking into it further it turns out that isn’t quite the case when you install your own self-signed root certificates.
There are a number of cases where HTTPS connections are intercepted by using local, ephemeral certificates. These certificates are signed by a root certificate that has to be manually installed on the client. Corporate MITM proxies may do this, several anti-virus/parental control products do this and debugging tools like Fiddler can also do this. Since we cannot break in these situations, user installed root CAs are given the authority to override pins. -Adam Langley on ImperialViolet
So basically certificate authorities that Google doesn’t like can’t sign certificates for Google.com, but the malware/nannyware that installs its own root CA into your trust store totally can.
Well I am not sure what any of it means. Maybe the Firefox thing is a bug that should be reported, but honestly I can’t imagine anything lower on the list of things in Firefox that “need” to be fixed. I learned that even in the weirdest of setups Chrome has a great TLS implementation. And IE still sucks.
Update: Firefox appears to be attempting to be too accommodating of people who don’t know how to build a certificate chain and is doing weird things with chains where the “Common Name” is the same in multiple certificates. As pointed out by /u/briansmith, this is a known bug in Firefox. Still probably not a bug worth exploring. Thanks briansmith!