MagiskTrustUserCerts icon indicating copy to clipboard operation
MagiskTrustUserCerts copied to clipboard

Use PEM format for Flutter trust store

Open aeri opened this issue 4 months ago • 0 comments

Dart/Flutter runtime loads the trust store directly with BoringSSL from /system/etc/security/cacerts:

// On Android, we don't compile in the trusted root certificates. Instead,
// we use the directory of trusted certificates already present on the
// device. This saves ~240KB from the size of the binary. This has the
// drawback that SSL_do_handshake will synchronously hit the filesystem
// looking for root certs during its trust evaluation. We call
// SSL_do_handshake directly from the Dart thread so that Dart code can be
// invoked from the "bad certificate" callback called by SSL_do_handshake.
const char* android_cacerts = "/system/etc/security/cacerts";
LoadRootCertCache(android_cacerts);

This invokes SSL_CTX_load_verify_locations that requires that CA certificates will be in PEM format.

In the case of this module, as the format appears to be DER, Flutter is unable to verify the certificate correctly and considers it invalid.

This does not happen with native Kotlin/Java applications because uses Android native trusted certificate store through Java Platform CertificateFactory("X509"), which also accepts X.509 binary DER.

Related: https://github.com/NVISOsecurity/AlwaysTrustUserCerts/issues/1

aeri avatar Aug 09 '25 18:08 aeri