Summary
- SSL handshake failures occur on Android 13 and below when the backend API’s certificate chain includes the DigiCert TLS RSA4096 Root G5 root.
- The issue is triggered after the server was updated to send the full chain, which Flutter’s
HttpClient validates against the platform trust store on older Android versions.
Root Cause
- The Flutter
HttpClient does not honor Android Network Security Configuration by default.
- Older Android (≤ 13) does not ship the DigiCert TLS RSA4096 Root G5 as a trusted root, so the chain fails verification.
- The fallback to a custom
SecurityContext was necessary because the system trust store lacked the required root.
Why This Happens in Real Systems
- Platform discrepancies: Android 14+ includes the root; Android 13 and below do not.
- Flutter isolation: networking is performed in Dart, bypassing native
HttpURLConnection/OkHttp.
- Certificate chain length: including the root in the chain triggers an error on systems that already have that root in the store, causing duplication and failure if the root is missing.
Real-World Impact
- End‑users on older devices receive
CERTIFICATE_VERIFY_FAILED errors and cannot access protected APIs.
- Increased support tickets and loss of revenue due to non‑functional features on legacy devices.
- Potential confusion for QA and dev teams about HTTPS configuration correctness.
Example or Code (if necessary and relevant)
final certData = await rootBundle.load(
'assets/certs/DigiCert_TLS_RSA4096_Root_G5.pem',
);
final context = SecurityContext(withTrustedRoots: true);
context.setTrustedCertificatesBytes(certData.buffer.asUint8List());
final client = HttpClient(context: context);
How Senior Engineers Fix It
- Add the missing root cert to the trust store using a custom
SecurityContext as shown above.
- Verify the certificate chain on a staging environment that mimics all targeted Android versions.
- Pin the certificate if the API is static, or rely on the system store when the root is available.
- Document the workaround clearly in the codebase and CI/CD pipelines to avoid accidental removal.
- Monitor app crashes via Play‑Console or crash‑reporting tools to catch regressions.
Why Juniors Miss It
- Assume that Android’s Network Security Configuration automatically applies to all HTTP traffic, including Flutter.
- Overlook platform differences between Android 13 and newer releases.
- Focus on the error message without exploring the underlying certificate chain and trust store.
- Fail to consider that
HttpClient requires an explicit SecurityContext for custom roots on legacy devices.