Chain validation issues with YE/YR under Linux distributions

Issue description

Couple of days ago, I noticed some issues at my automated curl requests. The issues appear after a renewal of some LE certificates. I was able to trace back the problems to an incomplete validation of my LE TLS certifications chain. A missing ISRG Root YR cert in my local CA trust store or within the provided cert chain causes the problem. This topic was also referenced in a post YE/YR are not in ca-certificates! by 532910.

I opened this new topic, because I think many people could come across this issue, because many(?) major linux distributions do not provide the ISRG Root YE/YR within ins ca-certificates packages. It's also possible to reproduce this situation with the test websites of the ISRG Root YE/YR certificates, provide by Let's Encrypt > Chains of Trust

  • ISRG Root YE
    [...]
    • Test websites: valid, revoked, expired
  • ISRG Root YR
    [...]
    • Test websites: valid, revoked, expired

(see also: The difficulty of making sure your website is broken - Let's Encrypt)

If these test websites are opened with a browser like firefox, everything is fine. A complete TLS chain validation is able.
(I am not complete sure, why e.g. firefox has no issues validating the chain, because ISRG Root YE/YR is neither inside the ff certificate store (or I missed it searching for it). FF may downloads the missing Root certificate on demand... I do not know ).

A incomplete validation behaivor can be seen using curl under different Linux distributions, because even the testing websites do not provide the complete certificate chain:

# openssl s_client -connect valid.yr.test-certs.letsencrypt.org:443 -showcerts </dev/null 2>/dev/null | grep -E "( s| i):" 
 0 s:
   i:C=US, O=Let's Encrypt, CN=YR1
 1 s:C=US, O=Let's Encrypt, CN=YR1
   i:C=US, O=ISRG, CN=Root YR

Debian 13.5 (trixie)

root@e26f2be3e817:/# cat /etc/os-release 
PRETTY_NAME="Debian GNU/Linux 13 (trixie)"
[...]
DEBIAN_VERSION_FULL=13.5
[...]

root@e26f2be3e817:/# dpkg -l | grep ca-certificates
ii  ca-certificates           20250419                       all          Common CA certificates

root@e26f2be3e817:/# dpkg -L ca-certificates | grep ISRG
/usr/share/ca-certificates/mozilla/ISRG_Root_X1.crt
/usr/share/ca-certificates/mozilla/ISRG_Root_X2.crt

root@e26f2be3e817:/# dpkg -L ca-certificates | grep YR  
root@e26f2be3e817:/# dpkg -L ca-certificates | grep YE
# ^_ YE/YR are not in ca-certificates trust store

Broken (insecure) TLS request:

root@e26f2be3e817:/# curl https://valid.yr.test-certs.letsencrypt.org/
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the webpage mentioned above.

root@e26f2be3e817:/# curl -v https://valid.yr.test-certs.letsencrypt.org/ 2>&1 | grep CAfile
*  CAfile: /etc/ssl/certs/ca-certificates.crt

Ubuntu (26.04 LTS)

root@e46e8254f45e:/# cat /etc/os-release 
PRETTY_NAME="Ubuntu 26.04 LTS"
[...]

root@e46e8254f45e:/# dpkg -l | grep ca-certificates
ii  ca-certificates                20260223                         all          Common CA certificates

root@e46e8254f45e:/# dpkg -L ca-certificates | grep ISRG
/usr/share/ca-certificates/mozilla/ISRG_Root_X1.crt
/usr/share/ca-certificates/mozilla/ISRG_Root_X2.crt

root@e46e8254f45e:/# dpkg -L ca-certificates | grep YR
root@e46e8254f45e:/# dpkg -L ca-certificates | grep YE
# ^_ YE/YR are not in ca-certificates trust store

root@e46e8254f45e:/# find /usr/share/ca-certificates -iname "*isrg*"
/usr/share/ca-certificates/mozilla/ISRG_Root_X1.crt
/usr/share/ca-certificates/mozilla/ISRG_Root_X2.crt

Broken (insecure) TLS request:

root@e46e8254f45e:/# curl https://valid.yr.test-certs.letsencrypt.org/
curl: (60) SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the webpage mentioned above.

Fedora (44)

[root@8fa12baac27c /]# cat /etc/os-release 
[...]
PRETTY_NAME="Fedora Linux 44 (Container Image)"
[...]

[root@8fa12baac27c /]# dnf list installed ca-certificates
Updating and loading repositories:
Repositories loaded.
Installed packages (available for reinstall, available for upgrade)
ca-certificates.noarch 2025.2.80_v9.0.304-7.fc44 9f717d77be324992a27b71f74a042c00

[root@8fa12baac27c /]# dnf repoquery -l ca-certificates | grep ISRG
Updating and loading repositories:
 [...]
Repositories loaded.
/etc/pki/ca-trust/extracted/pem/directory-hash/ISRG_Root_X1.pem
/etc/pki/ca-trust/extracted/pem/directory-hash/ISRG_Root_X2.pem

[root@8fa12baac27c /]# dnf repoquery -l ca-certificates | grep YR
Updating and loading repositories:
Repositories loaded.
[root@8fa12baac27c /]# dnf repoquery -l ca-certificates | grep YE
Updating and loading repositories:
Repositories loaded.

# ^_ YE/YR are not in ca-certificates trust store

Broken (insecure) TLS request:

[root@8fa12baac27c /]# curl https://valid.yr.test-certs.letsencrypt.org/
curl: (60) SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the webpage mentioned above.

[root@8fa12baac27c /]# curl -v https://valid.yr.test-certs.letsencrypt.org/ 2>&1 | grep CAfile
*   CAfile: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
[root@8fa12baac27c /]# grep ISRG /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
# ISRG Root X1
# ISRG Root X2

Conclusion

I my opinion the ISRG Root YE/YR should be provided by the distribution ca-certificates packages as mentioned in YE/YR are not in ca-certificates! by 532910.

Providing two intermediates (e.g. YR1+Root YR) certificates for the fullchain valiadition is a "solution" until then.

it'd be normal to see it there:
things like https://valid.x1.test-certs.letsencrypt.org/ already using Y tier signed certificate at its leaf, just including cross-sign certificate from YE/YR to X2/X1.

That's entirely normal, since the new YE and YR Root Certificates haven't been submitted to any root programs yet, including Mozilla's Root Program, where the ca-certificates trust store is sourced from.

The "current" trust anchors are still X1 and X2, and all chains served by Let's Encrypt chain up to one or both of these roots:

For ECC certificates: EE <= YEn <= YE <= X2 <= X1 (the last cross-cert being optional)
For RSA certificates: EE <= YRn <= YR <= X1

This is not true, we are getting new certificates signed by YR2 and things are broken as Root YR is not trusted anywhere.

The Root YR does not have to be in the trust anchor store, because the TLS server supposed to send it (actually a cross-signed version) to the TLS client. Then, this certificate chains up to a trusted root certificate X2, or definitely to X1 as the client searches for a valid trust chain.

Can you point me to any LE documentation saying this? Thanks.

Note that LE is NOT sending Root YR in default chain.

Here it is: Chains of Trust - Let's Encrypt

That's why you have the YR <= X1 cross-cert in the chain.

YR is not a trust anchor (yet), X1 is. But soon there will be disjoint sets of clients trusting either YR or X1 (not both). That's why you must have both in the chain.

Even valid LE YR has broken Chain of trust - https://valid.yr.test-certs.letsencrypt.org/

 Start 2026-06-10 17:34:53        -->> 52.34.89.55:443 (valid.yr.test-certs.letsencrypt.org) <<--

 Further IP addresses:   52.24.183.97 54.189.78.235 
 rDNS (52.34.89.55):     ec2-52-34-89-55.us-west-2.compute.amazonaws.com.
 Service detected:       HTTP

 Testing server defaults (Server Hello) 

 TLS extensions               "server name/#0" "EC point formats/#11" "application layer protocol negotiation/#16" "extended master secret/#23" "session ticket/#35" "supported versions/#43" "key share/#51" "renegotiation info/#65281"
 Session Ticket RFC 5077 hint no -- no lifetime advertised
 SSL Session ID support       yes
 Session Resumption           tickets no, ID: no
 TLS 1.3 early data support   no early data offered
 TLS clock skew               Random values, no fingerprinting possible 
 Certificate Compression      none
 Client Authentication        none
 Signature Algorithm          SHA256 with RSA
 Server key size              RSA 2048 bits (exponent is 65537)
 Server key usage             Digital Signature
 Server extended key usage    TLS Web Server Authentication
 Serial                       066E6C15537C8E643B848C926920DB749CA4 (OK: length 18)
 Fingerprints                 SHA1 A9915FD595E43EFBF751E53BD96E9B758097013B
                              SHA256 0426B433D69AD8C6293B96A91D2F0C4FEBD64E94D93F7D51E28287F45629AEBA
 Common Name (CN)             (no CN field in subject) (request w/o SNI didn't succeed)
 subjectAltName (SAN)         valid.yr.test-certs.letsencrypt.org 
 Trust (hostname)             Ok via SAN (SNI mandatory)
 Chain of trust               NOT ok (chain incomplete)
 EV cert (experimental)       no 
 Certificate Validity (UTC)   expires < 15 days (6) (2026-06-10 03:25 --> 2026-06-16 19:25)
 ETS/"eTLS", visibility info  not present
 Certificate Revocation List  http://yr2.c.lencr.org/37.crl
 OCSP URI                     --
 OCSP stapling                not offered
 OCSP must staple extension   --
 DNS CAA RR (experimental)    available - please check for match with "Issuer" below
                              issue=amazon.com, issue=letsencrypt.org, issue=pki.goog, issue=sectigo.com, issue=ssl.com, issuewild=amazon.com, issuewild=letsencrypt.org, issuewild=pki.goog, issuewild=sectigo.com, issuewild=ssl.com,
                              issuewild=www.digicert.com, issue=www.digicert.com
 Certificate Transparency     yes (certificate extension)
 Certificates provided        2
 Issuer                       YR2 (Let's Encrypt from US)
 Intermediate cert validity   #1: ok > 40 days (2028-09-02 23:59). YR2 <-- Root YR
 Intermediate Bad OCSP (exp.) Ok



 Done 2026-06-10 17:35:16 [  25s] -->> 52.34.89.55:443 (valid.yr.test-certs.letsencrypt.org) <<--

Yes, the valid.yr.test-certs.letsencrypt.org site is intended for systems that are testing having Root YE & YR in their trust stores. But they aren't in any major trust stores yet, and so no server intended to be used by the general public would be set up the same way as that testing site; they'd be set up to serve the cross sign like valid.x1.test-certs.letsencrypt.org does.