Restricting Who Can Issue Certificates for Your Domain with CAA


Thursday 13th February 2020

Certificate Authority Authorisation (CAA) is a security control that can be used to restrict the Certificate Authorities (CAs) that are permitted to issue certificates for your domain. The purpose of this is to help ensure that only explicitly whitelisted CAs are able to issue certificates, and also to report on any attempted violations of this policy.

CAA policies are set using the CAA DNS resource record type, and it has been mandatory for issuing CAs to check for and comply with CAA policies since 8th September 2017. The CAA specification is defined in RFC8659.

The following sample CAA policy marks Let's Encrypt as the only CA authorised to issue certificates for example.com, while requesting that violations are reported to the caa-violations@example.com mailbox:

example.com IN CAA 0 issue "letsencrypt.org"
example.com IN CAA 0 iodef "mailto:caa-violations@example.com"

This policy will then be checked by CAs when a certificate request is submitted for your domain.

Skip to Section:

Restricting Who Can Issue Certificates for Your Domain with CAA
┣━━ Example CAA Policies
┣━━ DNS Record Format
┣━━ Querying CAA Records
┣━━ CAA Policy Violation Reports
┣━━ Other Considerations
┗━━ Conclusion

Example CAA Policies

Below are examples of a wide variety of different CAA policy configurations, which should help you to get CAA set up in the way that you want.

Note that I have used ca1.example.net and ca2.example.org to represent two different Certificate Authorities. In reality you'll need to use the CAA policy address of your preferred CA. This is usually just their domain name (e.g. for Let's Encrypt the policy address is letsencrypt.org), however you should check their customer documentation to be sure.

Allow two CAs to issue normal and wildcard certificates for your domain:

example.com IN CAA 0 issue "ca1.example.net"
example.com IN CAA 0 issue "ca2.example.org"

Allow ca1 to issue only normal certificates, and ca2 to issue only wildcard certificates:

example.com IN CAA 0 issue "ca1.example.net"
example.com IN CAA 0 issuewild "ca2.example.org"

Allow ca1 to issue only normal certificates, and ca2 to issue both normal and wildcard certificates:

example.com IN CAA 0 issue "ca1.example.net"
example.com IN CAA 0 issue "ca2.example.org"
example.com IN CAA 0 issuewild "ca2.example.org"

Allow ca1 to issue certificates, except for subdomain.example.com where only ca2 is allowed:

example.com IN CAA 0 issue "ca1.example.net"
subdomain.example.com IN CAA 0 issue "ca2.example.org"

Deny all wildcard certificates, except for subdomain.example.com where they are allowed from ca1:

example.com IN CAA 0 issuewild ";"
subdomain.example.com IN CAA 0 issuewild "ca1.example.net"

Allow normal certificates from ca1, but deny all wildcard certificates:

example.com IN CAA 0 issue "ca1.example.net"
example.com IN CAA 0 issuewild ";"

Deny normal certificates but allow wildcard certificates from ca1:

example.com IN CAA 0 issue ";"
example.com IN CAA 0 issuewild "ca1.example.net"

Deny all wildcard certificates:

example.com IN CAA 0 issuewild ";"

Deny all certificate requests:

example.com IN CAA 0 issue ";"

Request that policy violations are reported via email and via HTTP POST to an API:

example.com IN CAA 0 iodef "mailto:caa-violations@example.com"
example.com IN CAA 0 iodef "https://api.example.com/report/caa/"

DNS Record Format

The format of DNS CAA records consists of the following:

example.com IN CAA <flags> <property tag> <property value>

Property Tag

The property tag is used to specify which specific CAA policy setting a particular CAA record is referring to. Currently there are 3 different property tags defined in the specification:

Property Value

The property value is the actual setting value that is associated with the property tag. In the case of issue and issuewild, the property value will be the name of a certificate authority, and possibly other metadata such as an account ID (though the latter is not widely supported/implemented). In the case of iodef, the property value will be either an email address prefixed with mailto:, or a HTTP endpoint starting with http:// or https://.

Flags

Flags are designed to allow for extending the CAA specification in the future. They are defined using a single unsigned integer (0 to 255, or 00000000 to 11111111 when represented in binary). Currently there is only one supported flag, which is the Issuer Critical Flag (represented by bit 0). At the time of writing, the flag value is almost always 0.

The Issuer Critical Flag is used to indicate to CAs that they must only issue certificates if all of the critical flagged property tags contained with the CAA policy for a domain are understood.

This is to allow the CAA specification to be extended in the future, without creating a loophole where CAs who don't yet conform to the new specification may still be able to issue certificates for a domain because they don't understand or know how to interpret the potentially more stringent CAA policy requirements.

As a silly example, suppose that the CAA specification was extended to allow for restricting the day of the week that certificates can be issued. E.g.:

example.com IN CAA 0 issue "letsencrypt.org"
example.com IN CAA 0 dayofweek "Monday"

If we assume that Let's Encrypt haven't yet updated their CAA policy parsing implementation, the dayofweek property cannot be parsed/understood. If someone requests a certificate on a Tuesday, Let's Encrypt will issue it, as even though they do not understand the dayofweek property, the critical flag is 0 so the issuance goes ahead anyway. This issuance would be in violation of the CAA policy.

However, if the CAA policy were to be changed to have the Issuer Critical Flag set:

example.com IN CAA 0 issue "letsencrypt.org"
example.com IN CAA 1 dayofweek "Monday"

...all certificate requests would now be denied until Let's Encrypt upgrade their CAA parser. This is compliant with the CAA policy.

Once Let's Encrypt update their CAA parser, certificate requests would then be permitted on Mondays.

Querying CAA Records

CAA records can be easily checked using dig:

$ dig +short example.com CAA
0 issue "letsencrypt.org"
0 issuewild ";"
0 iodef "mailto:caa-violations@example.com"

CAA Policy Violation Reports

When using Let's Encrypt with Certbot, attempting to issue a certificate that is in violation of the CAA policy for a domain will result in an error similar to the following:

Failed authorization procedure. www.jamiescaife.uk (http-01): urn:ietf:params:acme:error:caa :: CAA record for www.jamiescaife.uk prevents issuance

IMPORTANT NOTES:
 - The following errors were reported by the server:

   Domain: www.jamiescaife.uk
   Type:   None
   Detail: CAA record for www.jamiescaife.uk prevents issuance

Each distinct certificate authority has their own CAA error format, however the general message is always the same.

If the targeted domain has a CAA violation reporting endpoint specified via an iodef property, a violation report should also be sent (to be received by the owner of the affected domain).

CAA violation reports use the Incident Object Description Exchange Format (IODEF / RFC7970), which is a standardised mechanism for exchanging security report information.

Unfortunately, support for CAA violation reporting is currently very uncommon. Let's Encrypt don't support it at the time of writing, nor do most of the other large CAs. I was able to identify a smaller CA who claimed in their customer documentation that they send CAA violation reports, however despite deliberately triggering several CAA violations and waiting over 48 hours, I am yet to receive a report from them.

Other Considerations

Keep in mind that CAA does not give blanket permission to whitelisted CAs to issue certificates. It just means that they are allowed to, as long as all other required validation methods are satisfied as well. For example, proving ownership of the domain name/website.

Also note that CAA does not necessarily prevent malicious or compromised CAs from issuing certificates for your domain, nor can it stop a person from socially engineering one of your whitelisted CAs or bypassing their technical validation requirements. These scenarios are not likely to be a concern unless you are a high-profile target, and any CA found to be involved or partaking in such activity would be in clear violation of the Baseline Requirements, and would most likely have their status as a publicly trusted CA removed.

I also recommend implementing Certificate Transparency (CT) monitoring, which will allow you to receive alerts whenever a certificate is issued for your domain. This is because modern browsers require all certificates to be recorded at the point of issuance in a series of public ledgers known as the Certificate Transparency logs, otherwise they will not be considered trusted. You can read more about this in my article Let's Encrypt SCTs in Certificates.

Conclusion

CAA is a valuable extra security control that you can implement for your domain names. Combined with CT log monitoring, it allows you to have control and oversight over the certificates that are issued for your domain.

Now that support for HTTP Public Key Pinning (HPKP) has been removed from most browsers, it is no-longer possible to implement strict certificate fingerprint checking for web-based TLS connections. HPKP was rightly removed due to the availability risks that it brought, however CAA + CT still allows you to achieve 95% of the protection.

If bad actors falsely acquiring certificates is really part of your threat model, then TLS with a trust store full of public CAs is most likely not the best option for you. You may wish to consider using something with native support for strict signature checking instead, such as SSH or GPG, and distributing trusted signatures/fingerprints using a secure out-of-band channel.

This article is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.