Administrators usually first run into SSL certificate cross-signing during an outage, when a chain that worked for years starts failing on a subset of clients overnight. Cross-signing lets a new certificate authority piggyback on the trust an older one has already built, and it is one of the least understood mechanisms in the TLS ecosystem. This article explains how cross-signed certificates work, why they break, and how to configure and monitor your certificate chain so legacy clients don’t surprise you.
The short version: a cross-signed certificate gives a client two possible paths to a trusted root. Which path the client picks depends on its software, its root store and its age, and you don’t control any of those.
How Cross-Signing Actually Works
A new root CA has a problem. Before it is trusted, it has to be included in root stores from Mozilla, Apple, Microsoft, Google and Oracle (for Java), plus thousands of embedded devices that never get updates. That process takes years, and older devices never get the new root at all.
Cross-signing solves this. An established CA signs a certificate that carries the same subject name and the same public key as the new root. A client that trusts the new root builds a path straight to it. A client that only knows the old root follows the cross-signed certificate up to the established CA, and the signature still validates because the key is identical.
The best-known example is Let’s Encrypt. ISRG Root X1 launched in 2015 but wasn’t widely trusted for years, so IdenTrust’s DST Root CA X3 cross-signed it. For most of Let’s Encrypt’s early history, nearly every client validated its certificates through IdenTrust, not through ISRG’s own root.
Where Cross-Signed Chains Break
Problems start when one of the two paths expires. DST Root CA X3 expired on September 30, 2021. Modern clients with ISRG Root X1 in their store didn’t notice. Clients running OpenSSL 1.0.2, which builds one path and gives up if it fails, did notice. They followed the chain the server sent, hit the expired root, and rejected the connection even though a valid path existed.
The same pattern played out on May 30, 2020, when Sectigo’s AddTrust External CA Root expired. Servers still sending the old cross-signed intermediate broke API integrations, payment callbacks and monitoring agents running on older Linux distributions, curl builds and GnuTLS versions. Browsers were mostly fine. Machine-to-machine traffic was not.
Root store behavior adds another twist. Android up to 7.1.1 doesn’t check expiry on root certificates in its store, which is why Let’s Encrypt could keep serving a long chain through the expired DST root to support old phones. That workaround ended when the cross-sign itself expired on September 30, 2024, and Let’s Encrypt stopped serving the long chain by default on February 8, 2024. More background on why these events cascade is in the article on why root certificate expiration causes widespread outages.
Busting the Myth: “Clients Will Find the Valid Path”
A common belief is that if any valid path to a trusted root exists, every client will find it. It isn’t true. Path building differs widely between implementations.
Chrome, Firefox and Safari do sophisticated path building, and Chrome and Edge also fetch missing intermediates through the AIA extension. OpenSSL 1.1.0 and later default to trusted-first verification, which handles most cross-signing cases. Older OpenSSL, some Java 7 and 8 builds, embedded TLS stacks like older mbedTLS, and many IoT firmware images just follow the chain the server presents. If that chain leads to an expired root, they fail.
The chain your server sends is therefore not a hint. For a meaningful share of clients it is the only path they will ever try.
Configuring Your Chain with Cross-Signing in Mind
An experienced platform engineer starts by deciding who the clients are before touching the chain file. A public marketing site needs a different chain than an API consumed by payment terminals running firmware from 2016.
A practical sequence looks like this:
- Inspect what you serve: run openssl s_client -connect example.com:443 -servername example.com -showcerts and read the issuer and subject of each certificate in order.
- Map both paths: note where each intermediate chains to, and check the expiry date of every certificate in both directions, not just the leaf.
- Choose the chain deliberately: with Certbot, use –preferred-chain “ISRG Root X1” to request a specific path rather than taking whatever the CA defaults to.
- Test with the oldest real client: run curl against your endpoint from a container built on the oldest OS image your consumers actually run.
- Recheck on every renewal: CAs change default chains, and an automated renewal can quietly swap your path.
Don’t include the root certificate in the chain you serve. Clients already have it, or they don’t, and sending it adds bytes to every handshake without helping validation. The cross-signed certificate is different. It looks like a root but acts as an intermediate, so it does belong in the chain when you serve it on purpose. The guide to intermediate SSL certificates and chains covers chain ordering in more detail.
Common Mistakes Administrators Make
The first mistake is testing only in a browser. A browser will often repair an incomplete or outdated chain using cached intermediates or AIA fetching, so the site looks perfect. Meanwhile a Python requests client, a Go service or a webhook sender rejects the same chain. Always test with a strict, non-browser client.
The second is hardcoded chain bundles on load balancers and appliances. Teams upload a leaf plus a chain file to an F5, a Citrix ADC or an AWS ELB listener, and the chain file gets copied from an old wiki page. Two renewals later the leaf is fresh but the intermediate points at a cross-sign that expired months ago. The fix is to treat the chain file as part of the certificate, generated together and deployed together.
The third is assuming root store updates reach everything. Desktop and mobile browsers update their stores within weeks. Smart TVs, payment terminals, industrial controllers and Java runtimes with bundled cacerts files may never update. If your clients include air-gapped or embedded systems, plan for their root store as it was when the firmware shipped, not as it is today. Read more on how browser root store updates affect your SSL certs.
Monitoring Cross-Signed Chains Over Time
Expiry monitoring that only checks the leaf certificate misses the whole failure mode described above. A useful check validates every certificate in the served chain, flags any intermediate or cross-sign expiring within 90 days, and alerts when the issuer path changes after a renewal.
Watch for other signals too. Certificate Transparency logs show which chain your CA issued against. OCSP responses tell you whether an intermediate has been revoked. A sudden drop in your SSL grade after a renewal often points to a chain problem rather than a cipher or HSTS problem.
Time matters as well. With leaf validity shrinking toward 47 days by 2029, certificate renewal happens often enough that a chain change can land on a Friday evening with nobody watching. Automated chain checks after every deployment cost little and catch the issue before your customers do.
FAQ
Is a cross-signed certificate less secure than a directly issued one?
No. The cryptographic strength depends on the key and signature algorithm, not on how many paths exist. The risk is operational: an extra path means an extra expiry date to track.
Should I still serve the Let’s Encrypt long chain for old Android devices?
No, you can’t any more. The DST Root CA X3 cross-sign expired on September 30, 2024, so the long chain no longer helps any client. Android 7.1.1 and older devices that lack ISRG Root X1 can’t validate current Let’s Encrypt certificates, and the only fix is a CA whose root they already trust.
How do I know which path a specific client is using?
Reproduce it with that client’s TLS library. For OpenSSL-based clients, openssl verify -show_chain with the matching CA bundle shows the path that was built. For Java, enable -Djavax.net.debug=certpath.
Key Takeaways for Administrators
Cross-signing is a bridge between old and new trust, and every bridge has an end date. Know which paths your chain offers, know the expiry date of every certificate on both of them, and test against the oldest client that really connects to you. Re-verify the served chain after every renewal, because that’s usually when the path changes and nobody notices.
