On today's web, a local Certificate Authority is fairly dangerous

April 12, 2017

In a comment on my entry on generating self-signed TLS certificates today, James suggested:

My go-to tool is OpenVPN's EasyRSA. Admittedly that creates a CA which you can then sign certificates with, but for your internal hosts it would mean you could install said CA into your browser and then trust them all.

Superficially, this is certainly an appealing idea. If you have a fleet of IPMIs or other internal websites that need TLS certificates and that have names where you can't get public certificates, you can avoid everyone having to trust them one by one. Just set up a local CA, sign all the internal website certificates with them, add the local CA certificate to your browser, and you're done.

Unfortunately if you do this, you have just loaded a fairly large security-defeating gun and pointed it straight at your face. It's not just that your local CA can be attacked to sign certificate for any host, not just your internal ones; more importantly, certificates signed by a manually added CA specifically bypass all of the modern TLS protections built into browsers. This isn't just things like HTTP Public Key Pinning headers that your browser may have memorized, it's also even critically important pinned keys hard-coded into browsers themselves. A certificate signed by a manually added CA bypasses all of those checks.

(For all of this we may blame HTTPS interception middleware. Browser vendors have extremely reluctantly bowed to the demands of businesses that want to deploy them and have them intercept absolutely everything, partly because businesses basically hold the cards here if they're willing to go far enough.)

As far as I know there's no way in either Firefox or Chrome to constrain a manually added CA to only have its certificates accepted for certain (sub)domains. This means that no matter what you want, your local CA intended for intranet websites has just as much TLS interception ability as the TLS CA for a mandatory HTTPS middleware box. If an attacker can compromise it, they gain complete HTTPS interception capabilities for web browsing, both internal and external. None of the usual precautions and warnings will protect you in the least.

This means that a local CA that you have people's browsers trust is a very big deal, even (or especially) if only the sysadmins are trusting it. If you're going to have one at all, I think that it should involve some sort of hardware security module, even a simple and cheap one. If you are not willing to strongly protect a local CA, at least to the level of buying basic HSM hardware for it, then you should not even think of having one; it's simply far too dangerous in the event of a serious attacker. Even if you buy HSM hardware for it, I think that the balance of risks versus gains are often not going to be in favour of a local CA.

(To be clear, all of this is specific to local CAs that you will have your browsers trust. There are perfectly sensible and not particularly dangerous uses for a local CA outside of this. The general way to know if you're safe is that every operation that is supposed to use the local CA should have to explicitly trust the local CA's root certificate, whether that's through a command-line option or a specific configuration file setting. You should never add a local CA to your general trust roots, whether those are the browser trust roots or the system's generic trust roots.)

(Years ago I sort of wrote about this here, but I didn't take it anywhere near far enough and in particular I didn't think of what an attacker could do with access to your local or organizational CA. Not that overzealous security people aren't a serious risk in and of themselves, and it's not as if middleware HTTPS interception has a good reputation. Rather the contrary.)


Comments on this page:

As you probably know, the way to restrict this is in the CA by X.509 Name Constraints extension.

https://github.com/OpenVPN/easy-rsa/issues/54

It seems like recent versions of Windows CryptoAPI, Firefox (NSS) and OpenSSL support this. Support in Apple products, however, seems worse.

Of course it would be nice to also be able to restrict e.g. a CA run by a government to only be trusted for domains operated under a national TLD in the RootCert store.

By Miksa at 2017-04-13 10:09:24:

Would an ephemereal CA work as a compromise? When you have a few dozen services needing certificates, build a CA, create the certificates and then destroy the CA. It should then be impossible to create new certificates from that CA. Services added later would have to live with self-signed certificates until there are enough of those for a new round of local CA.

By James (trs80) at 2017-04-13 10:32:28:

Hmm, I wonder if using nss-pem you could mitigate some of this since maybe that would make it appear to be a system cert to NSS. Failing that you could rebuild nssckbi with it included, but that's taking things a bit too far.

Paul beat me to mentioning name constraints, which are used a lot in the wild by many organisations who have name-constrained sub-CAs of browser-trusted CAs.

At work I just have a Digicert wildcard with infinite re-issues. And yes, I know there are risks of spreading a wildcard widely too, but for the riskier hosts you can live chat with them and have a non-wildcard cert made that's only valid for subdomains you want.

By Thyrsus at 2017-04-15 01:32:06:

We have an local CA. However, it's locked away so tight that none of the internal services I use are ever signed - not Nagios, not Enterprise Resource Password Manager, and certainly none of the HP iLO web sites. Eight years ago, I got the Nagios server certificate signed, but twelve months later it expired, and it's been too difficult to renew since then.

Written on 12 April 2017.
« Generating good modern self-signed TLS certificates in today's world
Sometimes laziness doesn't pay off »

Page tools: View Source, View Normal.
Search:
Login: Password:

Last modified: Wed Apr 12 21:35:59 2017
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.