letsencrypt / boulder

An ACME-based certificate authority, written in Go.
Mozilla Public License 2.0
5.09k stars 595 forks source link

accept and enforce CAA parameter must-staple=true #5903

Open dkg opened 2 years ago

dkg commented 2 years ago

boulder should always issue certificates with the "must staple OCSP response" X.509 extension (aka "TLS features, RFC 7633) if a must-staple=true parameter is present for the CAA record corresponding to the controlling CA.

This report coins the must-staple=true CAA parameter, but if folks think there's a better way to specify for boulder, i'm ok with that too. For example, a CA running boulder could run two instances of boulder, each with different names, and one of those names in the zone's CAA record would correspond to a strict policy that always issues must-staple. But using a CAA parameter seems more straightforward and understandable to me.


Background

Currently an ACME client that belongs to a server operator that expects to always staple OCSP responses in the TLS handshake needs to specify "must-staple" during the ACME request/challenge (e.g. certbot --must-staple).

This means that an adversary issuing ACME requests for a given name can simply avoid specifying "must-staple" -- if the rest of the challenge succeeds, then no prompt revocation of the misissued certificate is possible, because clients don't actively query OCSP unless it's stapled.

But boulder checks CAA records: if the CAA record were able to specify that must-staple is always required of the CA, then the adversary's omission wouldn't matter; the cert would include the must-staple extension anyway.


update: edited to change must_staple to must-staple to align with the grammar in RFC 8659 §4.2

jprenken commented 2 years ago

Hi, @dkg,

Once CAA record extensions (RFC 8657) are available in production, allowing a CAA record to restrict issuance to (a) specific ACME registration(s), will that satisfy your use case?

dkg commented 2 years ago

Hi @jprenken -- I agree that CAA extensions are the right mechanism (i linked to RFC 8657 in the original report).

Can the specific account that is registered set an explicit "must always apply must-staple" setting that cannot be overridden by a certificate requestor? If so, how do they do that? Would it be some sort of control-panel setting that they'd need to use that would be custom to the service running boulder?

If it is a boulder-specific, idiosyncratic account setting, then a standard, publicly-documented method like a CAA extension still seems better, because it might encourage other ACME service implementations to adopt the same parameter name/value.

You should be able to combine extensions, i think:

example.com         CAA 0 issue "ca.example.net; account=96323336; must-staple=true"
jsha commented 2 years ago

Hi @dkg ! Thanks for the suggestion. You're right that must-staple in its current form isn't very powerful, because an attacker who can successfully validate a victim hostname on their own account can simply request issuance without must-staple.

However, putting additional policy in CAA doesn't really fix this. If the attacker has, say, a BGP hijack or a registry takeover or a hack of the victim's DNS provider, they can also overwrite any CAA records as part of their attack.

dkg commented 2 years ago

a BGP hijack shouldn't be capable of overriding a DNSSEC-signed CAA, right? is failed DNSSEC validation a "fail open" scenario or a "fail closed" scenario?

I agree that registry takeover and some forms of DNS provider hacking (i.e. where the DNS provider is doing the DNSSEC signing directly) would still leave a user vulnerable, but the point here is to try to close as many gaps as possible up to the DNS.

If the DNS still has gaps, that doesn't mean we shouldn't bother closing the gaps on the approach to the DNS, right? that way leads to security nihilism. why bother with any of it, in that case? 😛

jsha commented 2 years ago

a BGP hijack shouldn't be capable of overriding a DNSSEC-signed CAA, right? is failed DNSSEC validation a "fail open" scenario or a "fail closed" scenario?

That's correct. Our recursive resolvers validate DNSSEC, so a bogus response results in SERVFAIL, which results in failure to validate.

But if you've got your zone DNSSEC-signed, it seems like CAA account binding (which we hope to enable soonish) suffices to ensure that no attacker can validate for your domain and then issue a non-must-staple certificate, right? What additional property does the proposed CAA parameter get in that scenario?

dkg commented 2 years ago

Thanks for talking this through with me, @jsha. I'm glad to hear that a DNSSEC-signed zone will hard-fail on the CAA check, that seems like the right thing to do. :+1:

I also think that the account-binding CAA parameter will be useful, but it might be difficult to use in some contexts (e.g. a zone with different sub-zones that use different account identifiers).

Furthermore, even if the account-binding CAA parameter is in use, an adversary that gets even one-shot access to the account key (e.g. via webserver compromise, if there is poor privilege separation between the ACME client and https webserver) can request a certificate without must-staple.

So a must-staple CAA parameter looks to me like it would be simpler to administer and more secure as well.