Skip to content

Conversation

dhalbert
Copy link
Contributor

Let's Encrypt has two alternative certificate chains, to accommodate some older devices whose root certificate lists cannot be updated. See https://community.letsencrypt.org/t/production-chain-changes/150739, and also read what it links to.

  • Default chain: End-entity certificate <- Let's Encrypt R3 intermediate cert <- ISRG Root X1 (special cross-signed version) <- DST Root CA X3
  • Alternate chain: End-entity certificate <- Let's Encrypt R3 intermediate cert <- ISRG Root X1 (special cross-signed version)

Note that DST Root CA X3 expired in September 2021, but the default chain above still works, as explained below.

The End-entity cert, the R3 cert, and the ISRG Root X1 cert are all supplied by the server that is using Let's Encrypt. The ISRG Root X1 cert has two versions:

  • ISRG Root X1, self-signed to be a root cert. This is the "regular" version found in cert lists used by Mozilla, etc, such as https://curl.se/docs/caextract.html. It is not what is supplied by the server. It was already in data/roots.pem in this repo. This version is listed as https://crt.sh/?id=9314791.
  • ISRG Root X1, signed by DST Root CA X3. This version is not in roots.pem. Instead it is supplied as the last server-supplied certificate in the chains listed above. This version is listed as https://crt.sh/?id=3958242236.

For most SSL/TLS implementations, the chain verifier gets to the ISRG Root X1, and decides that ISRG Root X1 represents a "trust anchor" that verifies the chain is OK. This is because the self-signed version of ISRG Root X1 is in the chain verifier's local list of trusted root certs. The verifier does not bother to look for DST Root CA X3 because it already has a trust anchor. The two ISRG Root X1 certs do not have to match exactly.

For mbedTLS, as used in ESP-IDF, this "trust anchor" mechanism does not seem to work, or at least as we are using it. Instead the actual DST Root CA X3 has to be available. I'm not sure if this is a deficiency of mbedTLS, or it is because mbedTLS doesn't know the date and time it is, or some other reason. I looked at the mbedTLS compilation flags, but found none that seem related.

In any case, adding the DST Root CA X3 fixes the problem, and that is what this PR does. I found a few other references to this problem and doing the same solutionwhile websearching, but never found a fully complete explanation.

In addition, this PR improves the tooling:

  • Allow multiple sources of root certificates.
  • Renames issuer to filter, because it's more correct.
  • Removes the filter_certs.py --comment option. The roots.pem produced is now always commented, because in general, in .pem files, anything that is outside the certificate delimiter lines is ignored.

@dhalbert dhalbert merged commit cbb33c1 into main Sep 11, 2023
@dhalbert dhalbert deleted the dst-root-ca-x3 branch September 11, 2023 15:00
@dhalbert
Copy link
Contributor Author

Useful debugging commands. Note that these aren't testing mbedTLS, so they mostly are helpful for determining what should be happening.

openssl s_client -showcerts -connect site.api.espn.com:443 < /dev/null

openssl s_client --CAfile roots.pem -no-CApath -showcerts -connect site.api.espn.com:443 < /dev/null

certtool -i < roots.pem

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant