The symptom
A server gets a new certificate, for example at the yearly renewal. The desktop browser is happy. But on devices with Android 13 or older, apps, embedded web views or mail apps abort the connection. Typical messages:
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found. javax.net.ssl.SSLHandshakeException: … Trust anchor for certification path not found.
Browsers such as Firefox ship their own list of trusted root CAs and therefore sometimes still work. That makes troubleshooting confusing: the error does not appear everywhere, only in apps that use the system certificate store.
The cause: a root CA Android 13 does not know
Certificate authorities increasingly issue under new root CAs. At GlobalSign this is GlobalSign Root R46 (RSA) and E46 (ECC). These roots are only in the system store from Android 14 (October 2023) on. Android 13 and older do not know them. The same applies to other newer roots such as ISRG Root X2, DigiCert TLS RSA4096 Root G5 or the 2021 HARICA roots.
The chain of a server certificate then looks like this:
www.example.com (server certificate)
└─ GlobalSign … CA (intermediate)
└─ GlobalSign Root R46 ← unknown to Android 13
Why sending the root CA along does not help
The obvious idea is to put root R46 into the certificate file. That achieves nothing: a client only trusts a root CA that is in its own store. A root sent by the server is never accepted as a trust anchor, otherwise any server could vouch for itself. Installing the root on the device by hand does not help most apps either: since Android 7, apps by default do not trust user-installed certificates.
The fix: a cross certificate
A cross certificate contains the same CA, with the same name and key as root R46, but is signed by an older root that old devices know as well. For R46 there is, among others, a cross certificate from GlobalSign Root CA – R3. If the server sends this cross certificate, old devices get a valid path:
www.example.com
└─ GlobalSign … CA
└─ GlobalSign Root R46 (cross, signed by R3)
└─ GlobalSign Root CA – R3 ← present on Android 13 too
New devices know R46 itself and stop there. Old devices go one step further to R3. Both trust the connection without any change to the server certificate.
Step by step
- Check: enter the server in the SSL check. The “Older devices” section warns that the chain ends at a root only present from Android 14 on.
- Repair: click “Fix in the converter”. The certificate converter takes over the chain and offers the matching cross certificate from the Mozilla CCADB.
- Export: add the private key and choose the server’s format, e.g. a PEM bundle for nginx or a PFX file for IIS.
- Install: with nginx,
ssl_certificatepoints to the new file in the order server certificate → intermediate → cross certificate. Then reload the service. - Check again: the SSL check should now show “Older devices” in green.
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate /etc/ssl/example/fullchain-cross.pem; # server + intermediate + cross
ssl_certificate_key /etc/ssl/example/server.key;
}
Good to know
- The cross certificate has its own expiry date; the one from R3 runs until March 2029. By then hardly any Android 13 devices should still be in use.
- You have to send the cross certificate again with every renewal. The SSL check shows after the change whether it worked.
- The extra 1.5 KB or so per handshake makes no practical difference.
FAQ
Does this only affect GlobalSign?
No. Any chain ending at a root that is only in the store from Android 14 on is affected, for example ISRG Root X2 or DigiCert TLS RSA4096 Root G5. The SSL check detects this automatically.
Can I install root R46 on the phone?
For your own browser yes, for most apps no: since Android 7 apps only trust the system store, not user-installed certificates. For customers’ devices it is no solution anyway.
Does the cross certificate harm new devices?
No. New devices know R46 and stop the check there; they simply do not need the cross certificate.