Let's Encrypt now supports ACME-CAA: closing the DV loophole

Today, Let's Encrypt announced that they are enabling an extension to DNS CAA records known as ACME-CAA (RFC 8657). This came as a surprise to me, but a very pleasant one, since I wrote the ACME-CAA specification back in 2016 with Let's Encrypt in mind, and it was finally published as RFC 8657 back in 2019. To my knowledge, this is the first production deployment of ACME-CAA, so I'd like to take this opportunity to introduce people to ACME-CAA and why they might want to use it.

The purpose of SSL certificates is, ultimately, to mitigate man-in-the-middle attacks on connections between a browser and a website. Thus, when you request a SSL certificate for a website from a CA such as Let's Encrypt, that CA must take steps to ensure you are the legitimate owner of the domain in question.

The CA industry has largely settled on a model of charging money based on the degree of verification performed. The cheapest kind of certificate is a “Domain Validation” (DV) certificate, free in the case of Let's Encrypt. (While there are more expensive certificates such as “Extended Validation” (EV), these are basically pointless because even if you go through the process of paying a lot more money for an EV certificate, browsers will still accept a DV certificate, so a MitM attacker still only needs to successfully obtain a DV certificate to pull off a MitM attack successfully.)

DV. So, how does “Domain Validation” work? In general, it involves the CA generating some kind of random challenge string, and then requiring you to make it available at your domain, for example via HTTP or a DNS TXT record. If you can successfully host the challenge string at your domain, presumably you have control over the domain, and are thus the legitimate operator of the domain.

Except, when this Domain Validation is performed, you don't have a certificate yet. That's why you're going through the process in the first place: to get a certificate. Which means that when the CA verifies that your domain is correctly hosting the challenge, it does so via ordinary, unencrypted HTTP... which can be trivially subject to man-in-the-middle attacks.

So to reiterate, we have an entire process of making websites get certificates from a CA, to ensure they aren't susceptible to man-in-the-middle attacks, where said process involves a CA verifying a website in a way vulnerable to a man-in-the-middle attack. If you're unfamiliar with the CA industry, you may have difficulty seeing the logic here.

CT. While on the face of it this doesn't seem to make that much sense, there are at least a few benefits to this somewhat circular setup. Every certificate issued by a CA is logged in Certificate Transparency (CT) logs, which are cryptographically secured, append-only, publically auditable ledgers. This at least means that if someone was capable of MitM'ing a CA's validation probe to your domain and successfully caused a CA to misissue a certificate, you would find out about it when that certificate that you didn't request appeared in a CT log. For example, there are services which can email you whenever a new certificate for your domain is issued.

This ensures that any attack is “noisy”; if an attacker successfully got a certificate for google.com, the world will at least find out about it after the fact. This actually serves as a significant deterrent to many kinds of attacker. For example, intelligence agencies hate to have their operations detected, especially if it means they lose a valuable capability. If an intelligence agency had the capability to fraudulently obtain a DV certificate (which is fairly plausible), it can't use this capability without the misissued certificate being detected (at least, if it's for a high value domain where someone is watching the CT logs); which would be likely to result in the browser and CA industry taking further action to prevent this sort of thing, resulting in their losing the capability.

The fact that we aren't constantly seeing bad certificates for google.com showing up in CT logs is itself significant. It is proof of absence, which is itself valuable and shows us that, despite the fundamental holes in the Domain Validation model, certificate misissuance appears uncommon. So while the purpose of CAs seems at least on paper to be circular (“we prevent MitMs by validating domains using a process vulnerable to MitM”), CT has changed the game by allowing us to prove that, at least, this kind of MitM doesn't seem to be common.

Multiple vantage points. Nonetheless, while CT is a significant contribution to the security of the CA infrastructure, it remains the fact that the validation process used by CAs to verify domain control is vulnerable to man-in-the-middle attacks. The risk of these attacks is partially mitigated by some CAs by making multiple domain verification probes of a domain from different vantage points around the world; the idea here is that an attacker might be sitting on the path of a CA's verification traffic from, say, Sydney to www.example.com, but hopefully aren't also on the (different) path from San Francisco to www.example.com.

Global MitM. However, this can't mitigate against a so called “global MitM”, in which an attacker can intercept all traffic to a given domain regardless of where it comes from. Where an attacker can perform a global MitM against a target, the CA domain validation model is entirely broken; an attacker can trivially obtain a certificate for your website. At best (if you are paying attention) you will find out about it when the certificate is logged in the Certificate Transparency logs.

While this is called global MitM, it doesn't have to be global at all. For example, a MitM attacker sitting on the network path “just outside your front door”, intercepting all traffic going into your datacentre would qualify. Even the datacentre itself could trivially act as a malicious actor in this way. While it's unlikely that an intelligence agency could develop a global MitM infrastructure prevalent enough around the world to allow a large percentage of websites globally to be impersonated at will, targeted attacks against specific, high-value sites are far more feasible, since one simply has to intercept all of the fibre links connecting a target datacentre to the internet (which is exactly what they keep getting caught doing).

ACME-CAA provides a small but significant augmentation to the CA infrastructure because it can close this Domain Validation hole, preventing adversaries who can successfully MitM a CA's validation probes from obtaining certificates for your domain. This closes the major hole which has existed in the CA validation infrastructure up until this point and, under certain specific conditions, makes the CA domain validation process actually resemble something secure.

What is CAA? The CAA record has been introduced in the past decade as a way to allow a domain to control which CAs can issue for it. The basic idea is that since most domains will only use one CA to obtain their certificates, it doesn't really make sense for an attacker to be able to go to any CA on Earth to try and get a certificate for the domain; this allows an attacker to pick whichever CA has the weakest or most easily gamed validation process.

The concept behind the CAA record is beautifully simple. It's literally just a DNS record at the root of your domain saying which CAs are allowed to issue for the domain:

;; Only allow Let's Encrypt to issue certificates for this domain
example.com. IN CAA 0 issue "letsencrypt.org"

All CAs are required to check for and enforce CAA records; this is set by the CA/Browser forum, the industry forum which decides the rules which CAs must follow.

I recommend every domain sets a CAA record; it's really a no-brainer. (If you only use Let's Encrypt, the above record will suffice.)

There is a caveat, of course: since this record is served over DNS, it's also subject to forgery, just like a CA's validation probes. However, this can be mitigated by using DNSSEC on your domain. By doing so, a CA can cryptographically authenticate the CAA record (or its absence).

What is ACME-CAA? The concept of ACME-CAA is extremely simple; the CAA record is extended so that rather than naming a CA, it names a specific account at a specific CA:

example.com. IN CAA 0 issue "letsencrypt.org; accounturi=https://some/lets-encrypt/account-id"

When certain conditions are met, this closes the Domain Validation hole. Even if an attacker can successfully perform a global MitM which could persuade a CA — in this case Let's Encrypt — that they are the legitimate controller of a domain, they cannot just sign up for an account at Let's Encrypt and obtain a certificate because the CAA record only allows a specific account to request a certificate. Nor can they go to another CA, because the above CAA record states that only Let's Encrypt is allowed to issue certificates for the domain.

It's worth noting that in the ACME protocol used by Let's Encrypt clients to obtain certificates from Let's Encrypt, an account is essentially a private key used to authenticate requests to the CA. In short, this means that only someone with your ACME account private key can obtain certificates (though note the caveats below).

Caveats. There are a couple of caveats to this:

  • Requires DNSSEC to be effective. In order for this to work, you need to use DNSSEC for your domain so that the contents of your domain's DNS zone can be cryptographically authenticated by the CA.

  • Requires your CA to use DNSSEC. Your CA needs to do all DNS resolutions via a DNSSEC-validating resolver. However, this is taken care of since Let's Encrypt (the only CA to support ACME-CAA so far) does this.

  • Vulnerable to other CAs. While all CAs are now required to process CAA records, it's not clear to me that the CA/Browser Forum rules currently require them to use a DNSSEC-validating resolver to do so. This means that an attacker might be able to trick a third party CA which you don't authorise via CAA into issuing if they can MitM the CA's requests to your nameservers. This also doesn't protect against CAs which themselves are malicious (rather than being fooled) or which misissue by virtue of negligence or incompetence. You will still be able to detect this after the fact using CT, of course. Personally I would hope to see the CA/Browser Forum mandate using a DNSSEC-validating resolver to check CAA records in the future. (This doesn't mean domains will have to use DNSSEC, but does mean domains which do will be immune to forgery of their CAA records.)

  • Registrar vulnerabilities or arbitrary action. Fundamentally, ACME-CAA works to enhance security by relying on DNSSEC. Indeed you could argue that DNSSEC makes CAs redundant, and theoretically it does via technologies like DANE. Interestingly though, DANE doesn't provide a transparency log, whereas the CA infrastructure does. By combining the CA transparency infrastructure and DNSSEC, we can in some ways get the best of both worlds. However, it is worth noting that this inherits any security limitations of DNSSEC. For example, your account with your DNS registrar could get hacked; or your registrar could get hacked in general; or your registrar could be persuaded to hijack your domain, whether by a court, government, or intelligence agency, or so on. (This isn't a particularly idle concern. Amazingly Microsoft once got a court to let it take operational control of the domain no-ip.org — that is, to actually hijack the domain — a dynamic DNS service used by countless people — simply because one user was apparently using it for malware-related purposes.)

Using ACME-CAA. If you want to use ACME-CAA, I'd recommend reading the RFC — it's short and more readable than the average RFC. Most of the RFC is taken up by the security considerations section, which is well worth reading and lists the various caveats that apply to the use of ACME-CAA. These caveats are important and are explained in more detail than can be in this article.

To use ACME-CAA with Let's Encrypt, you'll need to determine your ACME Account URL (your Let's Encrypt client should ideally have a way to obtain this) and place that in DNS like so:

example.com. IN CAA 0 issue "letsencrypt.org; accounturi=ACCOUNT_URI_HERE"

If you use DNS challenges with Let's Encrypt, you also have the option of using the validationmethods parameter instead of the accounturi parameter to restrict CA validation to DNS challenges, rather than binding to a specific account:

example.com. IN CAA 0 issue "letsencrypt.org; validationmethods=dns-01"

Keep in mind that since this will cause issuance to fail if the requirements aren't met, it's strongly recommended to test that your Let's Encrypt client can still obtain certificates after setting this up.

Finally, I'd like to thank Let's Encrypt for taking the time to switch this on. The wait has been a little frustrating as the code to implement this was finished and turned on in the staging environment some years ago; however, since processing CAA records correctly is an audit requirement for a CA, changing how CAA records are processed is obviously not something to be done lightly and probably involved a fair amount of paperwork. I believe by making this happen Let's Encrypt has delivered a valuable security enhancement for those who take the time to adopt it. I don't know if they'll end up publishing statistics on adoption at some point — but they would be interesting to see in the future.