diff --git a/android-system-certificate-injection.js b/android-system-certificate-injection.js new file mode 100644 index 0000000..fa15d3e --- /dev/null +++ b/android-system-certificate-injection.js @@ -0,0 +1,59 @@ +const CERT_PEM = `-----BEGIN CERTIFICATE----- +MIIDTzCCAjegAwIBAgIRClDpdJeylUmDvNyq5qq+plcwDQYJKoZIhvcNAQELBQAw +QTEYMBYGA1UEAxMPSFRUUCBUb29sa2l0IENBMQswCQYDVQQGEwJYWDEYMBYGA1UE +ChMPSFRUUCBUb29sa2l0IENBMB4XDTIyMTIyNTE5MDQ1MFoXDTIzMTIyNjE5MDQ1 +MFowQTEYMBYGA1UEAxMPSFRUUCBUb29sa2l0IENBMQswCQYDVQQGEwJYWDEYMBYG +A1UEChMPSFRUUCBUb29sa2l0IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAz4pwm0pLDvf8qVmAiOi2cvu8xDgboetoLWBoONOY2wvoEFRylLUGaieP +UG5Yuofcj798uYPEqPLoF2ugnw8J/lhYhkMqTEbuqoyZT7DooBiqtSbm4b++T/Zt +F6YnpkYeWIkv88UJaRvLG8OHytVbiC71JQ/DFCEjzNzATCKT7UFqyF4ZsT3cnGJe +3x1iiSzWxJsnDkNZmiQ+IDYSM/dx7RJYwrXO5oWbAHC7otdC66O9eB1uBYq9I8gU +4FcVKHbWAH1BYbsoF/pQJLz2mAXD7E92/Vvho7FgTKYOUq0b58LF9UHt+gDRUGUC +L4HtuMeb/Ckiwyoej50jqI//ER1XswIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/ +MA4GA1UdDwEB/wQEAwIBxjAdBgNVHQ4EFgQUfsk69D2mzcAFjDX0GV53o3gySMMw +DQYJKoZIhvcNAQELBQADggEBAH08sPexRXFxzuIVWD1aUoarYq8FwNBP+xusgZcg +DmRKr0FpEyUjBxgVIsmd44WSX/TWdXokdd7aLPVnjwQbq2mhYtXAn4aIRn3QBNaj +TvFQovVy+LCSRwZjvlpr/KJnXlVMrqLIxP++I6FqLO5G5zJ+qDF39C7RUkkMpvmU +tiS70/zpt2LSfLUNtnS287P9s4wXEwbrkOOY6oNgKDz7jtNua0ZiPq2uGdqrkyZ2 +VPgirbNnuoC1uZmuy0Mvih4+8xrvJWHb9QO7JOH3cXA+ZiZ945V+viMEnV0YkQB6 +FL11l3fE9xzkPv357Z3e7QULnC8vDRgFAossuh8WBhNjjmo= +-----END CERTIFICATE-----`; + +Java.perform(() => { + // First, we build a JVM representation of our certificate: + const String = Java.use("java.lang.String"); + const ByteArrayInputStream = Java.use('java.io.ByteArrayInputStream'); + const CertFactory = Java.use('java.security.cert.CertificateFactory'); + + const certFactory = CertFactory.getInstance("X.509"); + const certBytes = String.$new(CERT_PEM).getBytes(); + const cert = certFactory.generateCertificate(ByteArrayInputStream.$new(certBytes)); + + // Then we hook TrustedCertificateIndex. This is used for caching known trusted certs within Conscrypt - + // by prepopulating all instances, we ensure that all TrustManagerImpls (and potentially other + // things) automatically trust our certificate specifically (without disabling validation entirely). + // This should apply to Android v7+ - previous versions used SSLContext & X509TrustManager. + const TrustedCertificateIndex = Java.use('com.android.org.conscrypt.TrustedCertificateIndex'); + TrustedCertificateIndex.$init.overloads.forEach((overload) => { + overload.implementation = function () { + this.$init(...arguments); + // Index our cert as already trusted, right from the start: + this.index(cert); + } + }); + + TrustedCertificateIndex.reset.overloads.forEach((overload) => { + overload.implementation = function () { + const result = this.reset(...arguments); + // Index our cert in here again, since the reset removes it: + this.index(cert); + return result; + }; + }); + + // This effectively adds us to the system certs, and also defeats quite a bit of basic certificate + // pinning too! It auto-trusts us in any implementation that uses TrustManagerImpl (Conscrypt) as + // the underlying cert checking component. + + console.log('Inject system certificate trust'); +}); \ No newline at end of file