2023-09-03
TLS CA root certificate name constraints for internal CAs
For a long time, one of the pieces of advice for dealing with various TLS certificate problems is that you should establish your own internal Certificate Authority with its own CA root certificate, have your systems trust it, and then issue certificates from your internal CA with whatever names and other qualities you needed. My reaction to this suggestion has traditionally been that it was extremely dangerous. If your internal CA was compromised in some way you had given an attacker the ability to impersonate anything, and generally properly operating a truly secure internal CA is within neither the skills nor the budget of a typical organization or group (it's certainly not within ours). Fortunately, this issue was obvious to a lot of people for a long time, so as part of RFC 5280 we got name constraints, which restricted the names (in most contexts, the DNS names) that the CA could sign certificates for. You could include only some (sub)domains, or exclude some.
(So, for example, you could make an internal CA for for your BMC IPMI web servers that was only valid for '.ipmi.internal.example.com'.)
All of this sounds good. However, in the real world, some things appear to have intervened. To start with, TLS libraries, browsers, and so on didn't immediately add support for these name constraints; as a result, even today you probably want to do some testing to see if your particular environment does (possibly using some resources from BetterTLS). The good news is that according to this 2020 article, browsers now support this, which is probably the most important case. Another issue is that creating TLS CA certificates with name constraints isn't the easiest thing in the world, at least with OpenSSL; other tools may be better, but I haven't looked for any.
(I care about how easy and straightforward it is to add name constraints because if it's tricky, we're going to need to test that we actually did it right. I can imagine unpleasant scenarios where we think we've created a CA root certificate with name constraints but we actually haven't.)
A third issue is that until Chrome 112 in April 2023, Chrome didn't pay any attention to name constraints on CA root certificates, and see also, based on their interpretation of RFC 5280 Certificate Validation. As I understand it, until then Chrome only applied name constraints from intermediate CA certificates; the root CA certificate was unconstrained. This is not exactly useful if you're worried about an attacker managing to compromise your root CA key in some way. Other TLS code and TLS libraries may have similar issues, although if you test them directly you can know for yourself.
(Looking at Go, since it's one of my areas of interest, it appears to support name constraints on CA root certificates and enforces them. See src/crypto/x509/name_constraints_test.go.)
We don't currently have any real internal CAs, although we have one for OpenVPN. If we ever set up one for some reason, I'm going to try to make sure to give it a name constraint, and ideally as narrow a one as possible.