Upgrade to rustls-platform-verifier:0.2.0 (#7791)

* Upgrade to `rustls-platform-verifier:0.2.0`.

This re-enables certificate revocation checks, but v0.2.0 contains a list of CRL servers that can be accessed using clear text requests to check the validity of certain certificates, which should fix the issue that prevented us from using certificate revocation and at the same time strengthening the security of the client app.

Since we already had some network configuration in Element X, and `network_security_config.xml` files can't be merged, what we can do is manually download and merge the XML contents using `tools/dependencies/update_rustls_platform_verifier.py` like this:

```sh
./update_rustls_platform_verifier.py 0.2.0
```

It will automatically bump the Gradle dependency and merge the security config entries.

* Bump SDK bindings to `v26.09.28`, containing the rustls bump on the SDK side

* Fix unused resources caused by `app/src/main/res/xml/network_security_config_element.xml`
This commit is contained in:
Jorge Martin Espinosa
2026-09-28 17:35:33 +02:00
committed by GitHub
parent 0f98c5c0e0
commit 03fd288c47
16 changed files with 595 additions and 441 deletions
+3
View File
@@ -342,6 +342,9 @@ licensee {
ignoreDependencies("com.github.matrix-org", "matrix-analytics-events") ignoreDependencies("com.github.matrix-org", "matrix-analytics-events")
// Ignore dependency that are not third-party licenses to us. // Ignore dependency that are not third-party licenses to us.
ignoreDependencies(groupId = "io.element.android") ignoreDependencies(groupId = "io.element.android")
// The rustls-platform-verifier dependency does not provide a license file in their maven repo, but there are MIT and Apache licenses in
// the source code repo: see https://github.com/rustls/rustls-platform-verifier
ignoreDependencies(groupId = "org.rustls", artifactId = "rustls-platform-verifier")
} }
fun Project.configureLicensesTasks(reportingExtension: ReportingExtension) { fun Project.configureLicensesTasks(reportingExtension: ReportingExtension) {
@@ -13,6 +13,7 @@ import android.system.Os
import androidx.startup.Initializer import androidx.startup.Initializer
import io.element.android.features.rageshake.api.logs.createWriteToFilesConfiguration import io.element.android.features.rageshake.api.logs.createWriteToFilesConfiguration
import io.element.android.libraries.architecture.bindings import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.core.extensions.runCatchingExceptions
import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.matrix.api.tracing.TracingConfiguration import io.element.android.libraries.matrix.api.tracing.TracingConfiguration
import io.element.android.x.di.AppBindings import io.element.android.x.di.AppBindings
@@ -41,9 +42,18 @@ class PlatformInitializer : Initializer<Unit> {
sdkSentryDsn = appBindings.sentrySdkDsn()?.value?.takeIf { it.isNotBlank() }, sdkSentryDsn = appBindings.sentrySdkDsn()?.value?.takeIf { it.isNotBlank() },
) )
bugReporter.setCurrentTracingLogLevel(logLevel.name) bugReporter.setCurrentTracingLogLevel(logLevel.name)
// Init the tracing service with the configuration so we have logging enabled as soon as possible
platformService.init(tracingConfiguration) platformService.init(tracingConfiguration)
// Also set env variable for rust back trace // Also set env variable for rust back trace
Os.setenv("RUST_BACKTRACE", "1", true) Os.setenv("RUST_BACKTRACE", "1", true)
// Init the SDK with the Android Context, so it can be used with rustls and other Android specific features
runCatchingExceptions {
org.matrix.rustsdk.Android.init(context)
}.onFailure {
Timber.e(it, "Failed to init the SDK with an Android Context. The app probably won't work properly.")
}
} }
override fun dependencies(): List<Class<out Initializer<*>>> = mutableListOf() override fun dependencies(): List<Class<out Initializer<*>>> = mutableListOf()
@@ -30,5 +30,384 @@
<domain includeSubdomains="true">home</domain> <domain includeSubdomains="true">home</domain>
<domain includeSubdomains="true">lan</domain> <domain includeSubdomains="true">lan</domain>
<domain includeSubdomains="true">localdomain</domain> <domain includeSubdomains="true">localdomain</domain>
<!-- Domains below are imported from rustls-platform-verifier 0.2.0 by tools/dependencies/update_rustls_platform_verifier.py -->
<!-- They are needed to fetch the certificate revocation lists over cleartext -->
<domain includeSubdomains="true">abitabdv.crl.certum.pl</domain>
<domain includeSubdomains="true">abitabev.crl.certum.pl</domain>
<domain includeSubdomains="true">abitabov.crl.certum.pl</domain>
<domain includeSubdomains="true">alpiro.crl.sectigo.com</domain>
<domain includeSubdomains="true">anticdv.crl.certum.pl</domain>
<domain includeSubdomains="true">antrustovsslg2r30ca.crl.certum.pl</domain>
<domain includeSubdomains="true">autontrustprodvtlsg2r31ca.crl.certum.pl</domain>
<domain includeSubdomains="true">bitcert.crl.sectigo.com</domain>
<domain includeSubdomains="true">btdvtlsr35g2ca.crl.certum.pl</domain>
<domain includeSubdomains="true">c.cf-b.ssl.com</domain>
<domain includeSubdomains="true">c.cf-i.ssl.com</domain>
<domain includeSubdomains="true">c.pki.goog</domain>
<domain includeSubdomains="true">ca1.agid.gov.it</domain>
<domain includeSubdomains="true">cdn.d-trust-cloudcrl.net</domain>
<domain includeSubdomains="true">cdp.disig.sk</domain>
<domain includeSubdomains="true">cdp.elektronicznypodpis.pl</domain>
<domain includeSubdomains="true">cdp.geotrust.com</domain>
<domain includeSubdomains="true">cdp.rapidssl.com</domain>
<domain includeSubdomains="true">cdp.thawte.com</domain>
<domain includeSubdomains="true">cdp1.disig.sk</domain>
<domain includeSubdomains="true">cdp1.pca.dfn.de</domain>
<domain includeSubdomains="true">cdpa.digitalcertvalidation.com</domain>
<domain includeSubdomains="true">cdpb.digitalcertvalidation.com</domain>
<domain includeSubdomains="true">cdpc.digitalcertvalidation.com</domain>
<domain includeSubdomains="true">cdpd.digitalcertvalidation.com</domain>
<domain includeSubdomains="true">cdpe.digitalcertvalidation.com</domain>
<domain includeSubdomains="true">cdpf.digitalcertvalidation.com</domain>
<domain includeSubdomains="true">cdpg.digitalcertvalidation.com</domain>
<domain includeSubdomains="true">cdph.digitalcertvalidation.com</domain>
<domain includeSubdomains="true">cdpi.digitalcertvalidation.com</domain>
<domain includeSubdomains="true">certcloud.crl.trust-provider.com</domain>
<domain includeSubdomains="true">certdata.crl.sectigo.com</domain>
<domain includeSubdomains="true">certera.crl.sectigo.com</domain>
<domain includeSubdomains="true">certificates.godaddy.com</domain>
<domain includeSubdomains="true">certum-crl.wt.trustasia.com</domain>
<domain includeSubdomains="true">certum.crl.sheca.com</domain>
<domain includeSubdomains="true">certumdvtlsg2e39ca.crl.certum.pl</domain>
<domain includeSubdomains="true">certumdvtlsg2r39ca.crl.certum.pl</domain>
<domain includeSubdomains="true">certumevtlsg2e39ca.crl.certum.pl</domain>
<domain includeSubdomains="true">certumevtlsg2r39ca.crl.certum.pl</domain>
<domain includeSubdomains="true">certumovtlsg2e39ca.crl.certum.pl</domain>
<domain includeSubdomains="true">certumovtlsg2r39ca.crl.certum.pl</domain>
<domain includeSubdomains="true">cfcadveccca.crl.certum.pl</domain>
<domain includeSubdomains="true">cfcadvrsaca.crl.certum.pl</domain>
<domain includeSubdomains="true">cfcaeveccca.crl.certum.pl</domain>
<domain includeSubdomains="true">cfcaevrsaca.crl.certum.pl</domain>
<domain includeSubdomains="true">cfcaoveccca.crl.certum.pl</domain>
<domain includeSubdomains="true">cfcaovrsaca.crl.certum.pl</domain>
<domain includeSubdomains="true">cnssldvtlsg2r36ca.crl.certum.pl</domain>
<domain includeSubdomains="true">cnsslovtlsg2r36ca.crl.certum.pl</domain>
<domain includeSubdomains="true">crl-01.r1.ica.amazontrust.com</domain>
<domain includeSubdomains="true">crl-01.r1.ica.amznts.eu</domain>
<domain includeSubdomains="true">crl-c.emsign.com</domain>
<domain includeSubdomains="true">crl-pro.litessl.com</domain>
<domain includeSubdomains="true">crl.anf.es</domain>
<domain includeSubdomains="true">crl.apple.com</domain>
<domain includeSubdomains="true">crl.businessid.telesec.de</domain>
<domain includeSubdomains="true">crl.buypass.no</domain>
<domain includeSubdomains="true">crl.catrust.oemssl.cn</domain>
<domain includeSubdomains="true">crl.certigna.fr</domain>
<domain includeSubdomains="true">crl.certsign.ro</domain>
<domain includeSubdomains="true">crl.certum.pl</domain>
<domain includeSubdomains="true">crl.cfca.com.cn</domain>
<domain includeSubdomains="true">crl.cntrus.oemssl.cn</domain>
<domain includeSubdomains="true">crl.cnwebtrust.oemssl.cn</domain>
<domain includeSubdomains="true">crl.comodoca.com</domain>
<domain includeSubdomains="true">crl.crlocsp.cn</domain>
<domain includeSubdomains="true">crl.cybertrust.ne.jp</domain>
<domain includeSubdomains="true">crl.d-trust.net</domain>
<domain includeSubdomains="true">crl.dhimyotis.com</domain>
<domain includeSubdomains="true">crl.digicert.cn</domain>
<domain includeSubdomains="true">crl.digicert.eu</domain>
<domain includeSubdomains="true">crl.e-szigno.hu</domain>
<domain includeSubdomains="true">crl.e2m01.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e2m01.eu.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e2m02.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e2m03.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e2m04.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e2s14.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e2s15.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e2s16.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e2s17.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e2s18.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e2s19.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e2s20.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e2s21.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e3m01.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e3m01.eu.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e3m02.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e3m03.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e3m04.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e3s22.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e3s23.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e3s24.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e3s25.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e3s26.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e3s27.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e3s28.amazontrust.com</domain>
<domain includeSubdomains="true">crl.e3s29.amazontrust.com</domain>
<domain includeSubdomains="true">crl.emsign.com</domain>
<domain includeSubdomains="true">crl.ensuredca.com</domain>
<domain includeSubdomains="true">crl.firmaprofesional.com</domain>
<domain includeSubdomains="true">crl.gdca.com.cn</domain>
<domain includeSubdomains="true">crl.global.sheca.com</domain>
<domain includeSubdomains="true">crl.globalsign.com</domain>
<domain includeSubdomains="true">crl.globalsign.net</domain>
<domain includeSubdomains="true">crl.godaddy.com</domain>
<domain includeSubdomains="true">crl.harica.gr</domain>
<domain includeSubdomains="true">crl.izenpe.com</domain>
<domain includeSubdomains="true">crl.litessl.com</domain>
<domain includeSubdomains="true">crl.netsolssl.com</domain>
<domain includeSubdomains="true">crl.oem.trustca.net</domain>
<domain includeSubdomains="true">crl.pcsp.telesec.de</domain>
<domain includeSubdomains="true">crl.pki.goog</domain>
<domain includeSubdomains="true">crl.quovadisglobal.com</domain>
<domain includeSubdomains="true">crl.r1001.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r2001.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r2m01.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r2m01.eu.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r2m02.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r2m03.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r2m04.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r2s18.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r2s19.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r2s20.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r2s21.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r2s22.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r2s23.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r2s24.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r2s25.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r3001.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r4001.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r4m01.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r4m02.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r4m03.amazontrust.com</domain>
<domain includeSubdomains="true">crl.r4m04.amazontrust.com</domain>
<domain includeSubdomains="true">crl.root-e1.certainly.com</domain>
<domain includeSubdomains="true">crl.root-r1.certainly.com</domain>
<domain includeSubdomains="true">crl.rootca1.amazontrust.com</domain>
<domain includeSubdomains="true">crl.rootca2.amazontrust.com</domain>
<domain includeSubdomains="true">crl.rootca3.amazontrust.com</domain>
<domain includeSubdomains="true">crl.rootca4.amazontrust.com</domain>
<domain includeSubdomains="true">crl.rztrust.oemssl.cn</domain>
<domain includeSubdomains="true">crl.sbca.telesec.de</domain>
<domain includeSubdomains="true">crl.sectigo.com</domain>
<domain includeSubdomains="true">crl.sectigochina.com</domain>
<domain includeSubdomains="true">crl.serverid.telesec.de</domain>
<domain includeSubdomains="true">crl.starfieldtech.com</domain>
<domain includeSubdomains="true">crl.swisssign.ch</domain>
<domain includeSubdomains="true">crl.trust-provider.cn</domain>
<domain includeSubdomains="true">crl.trust-provider.com</domain>
<domain includeSubdomains="true">crl.tuntrust.tn</domain>
<domain includeSubdomains="true">crl.usertrust.com</domain>
<domain includeSubdomains="true">crl.wt.trustasia.com</domain>
<domain includeSubdomains="true">crl.xinchacha.oemssl.cn</domain>
<domain includeSubdomains="true">crl.zw.oemssl.cn</domain>
<domain includeSubdomains="true">crl05.actalis.it</domain>
<domain includeSubdomains="true">crl06.actalis.it</domain>
<domain includeSubdomains="true">crl09.actalis.it</domain>
<domain includeSubdomains="true">crl1.ecert.gov.hk</domain>
<domain includeSubdomains="true">crl13.actalis.it</domain>
<domain includeSubdomains="true">crl14.actalis.it</domain>
<domain includeSubdomains="true">crl15.actalis.it</domain>
<domain includeSubdomains="true">crl2.microsoft.com</domain>
<domain includeSubdomains="true">crl3.digicert.com</domain>
<domain includeSubdomains="true">crl4.digicert.com</domain>
<domain includeSubdomains="true">crls.certainly.com</domain>
<domain includeSubdomains="true">crls.ssl.com</domain>
<domain includeSubdomains="true">cyberfolks2.crl.certum.pl</domain>
<domain includeSubdomains="true">depo.kamusm.gov.tr</domain>
<domain includeSubdomains="true">digitaltrust.crl.sectigo.com</domain>
<domain includeSubdomains="true">dnencrypt.crl.sectigo.com</domain>
<domain includeSubdomains="true">dvtlsca2025-crl.e-szigno.hu</domain>
<domain includeSubdomains="true">dvtlsca2026-crl.e-szigno.hu</domain>
<domain includeSubdomains="true">e5.c.lencr.org</domain>
<domain includeSubdomains="true">e6.c.lencr.org</domain>
<domain includeSubdomains="true">e7.c.lencr.org</domain>
<domain includeSubdomains="true">e8.c.lencr.org</domain>
<domain includeSubdomains="true">ec2ca2017-crl1.e-szigno.hu</domain>
<domain includeSubdomains="true">ec2ca2017-crl2.e-szigno.hu</domain>
<domain includeSubdomains="true">ec2ca2017-crl3.e-szigno.hu</domain>
<domain includeSubdomains="true">ec2sslca2017-crl1.e-szigno.hu</domain>
<domain includeSubdomains="true">ec2sslca2017-crl2.e-szigno.hu</domain>
<domain includeSubdomains="true">ec2sslca2017-crl3.e-szigno.hu</domain>
<domain includeSubdomains="true">ec3ca2017-crl1.e-szigno.hu</domain>
<domain includeSubdomains="true">ec3ca2017-crl2.e-szigno.hu</domain>
<domain includeSubdomains="true">ec3ca2017-crl3.e-szigno.hu</domain>
<domain includeSubdomains="true">ec3sslca2017-crl1.e-szigno.hu</domain>
<domain includeSubdomains="true">ec3sslca2017-crl2.e-szigno.hu</domain>
<domain includeSubdomains="true">ec3sslca2017-crl3.e-szigno.hu</domain>
<domain includeSubdomains="true">eca.hinet.net</domain>
<domain includeSubdomains="true">edvtlsca2023-crl.e-szigno.hu</domain>
<domain includeSubdomains="true">edvtlsca2025-crl.e-szigno.hu</domain>
<domain includeSubdomains="true">edvtlsca2026-crl.e-szigno.hu</domain>
<domain includeSubdomains="true">emudhra.crl.sectigo.com</domain>
<domain includeSubdomains="true">eosslca2017-crl1.e-szigno.hu</domain>
<domain includeSubdomains="true">eosslca2017-crl2.e-szigno.hu</domain>
<domain includeSubdomains="true">eosslca2017-crl3.e-szigno.hu</domain>
<domain includeSubdomains="true">eovtlsca2023-crl.e-szigno.hu</domain>
<domain includeSubdomains="true">eovtlsca2025-crl.e-szigno.hu</domain>
<domain includeSubdomains="true">eovtlsca2026-crl.e-szigno.hu</domain>
<domain includeSubdomains="true">eqca2017-crl1.e-szigno.hu</domain>
<domain includeSubdomains="true">eqca2017-crl2.e-szigno.hu</domain>
<domain includeSubdomains="true">eqca2017-crl3.e-szigno.hu</domain>
<domain includeSubdomains="true">eqcpca2017-crl1.e-szigno.hu</domain>
<domain includeSubdomains="true">eqcpca2017-crl2.e-szigno.hu</domain>
<domain includeSubdomains="true">eqcpca2017-crl3.e-szigno.hu</domain>
<domain includeSubdomains="true">eqoca2017-crl1.e-szigno.hu</domain>
<domain includeSubdomains="true">eqoca2017-crl2.e-szigno.hu</domain>
<domain includeSubdomains="true">eqoca2017-crl3.e-szigno.hu</domain>
<domain includeSubdomains="true">eqtlsca2018-crl1.e-szigno.hu</domain>
<domain includeSubdomains="true">eqtlsca2018-crl2.e-szigno.hu</domain>
<domain includeSubdomains="true">eqtlsca2018-crl3.e-szigno.hu</domain>
<domain includeSubdomains="true">eqtlsca2023-crl.e-szigno.hu</domain>
<domain includeSubdomains="true">eqtlsca2025-crl.e-szigno.hu</domain>
<domain includeSubdomains="true">eqtlsca2026-crl.e-szigno.hu</domain>
<domain includeSubdomains="true">esafer.crl.sectigo.com</domain>
<domain includeSubdomains="true">eue2m1.crl.root.amznts.eu</domain>
<domain includeSubdomains="true">eue3m1.crl.root.amznts.eu</domain>
<domain includeSubdomains="true">eur2m1.crl.root.amznts.eu</domain>
<domain includeSubdomains="true">eveccca.crl.certum.pl</domain>
<domain includeSubdomains="true">evrsaca.crl.certum.pl</domain>
<domain includeSubdomains="true">gdcadv.crl.certum.pl</domain>
<domain includeSubdomains="true">gdcaev.crl.certum.pl</domain>
<domain includeSubdomains="true">gdcaov.crl.certum.pl</domain>
<domain includeSubdomains="true">gdcatrustauthdvtlsg3r31ca.crl.certum.pl</domain>
<domain includeSubdomains="true">gdcatrustauthevtlsg3r31ca.crl.certum.pl</domain>
<domain includeSubdomains="true">gdcatrustauthovtlsg3r31ca.crl.certum.pl</domain>
<domain includeSubdomains="true">geant.crl.sectigo.com</domain>
<domain includeSubdomains="true">genious.crl.sectigo.com</domain>
<domain includeSubdomains="true">geossldvtlsr34g2ca.crl.certum.pl</domain>
<domain includeSubdomains="true">geosslevtlsr34g2ca.crl.certum.pl</domain>
<domain includeSubdomains="true">geosslovtlsr34g2ca.crl.certum.pl</domain>
<domain includeSubdomains="true">globaltrust.crl.sectigo.com</domain>
<domain includeSubdomains="true">globessl.crl.sectigo.com</domain>
<domain includeSubdomains="true">gogetssldv.crl.certum.pl</domain>
<domain includeSubdomains="true">gogetsslev.crl.certum.pl</domain>
<domain includeSubdomains="true">gogetsslov.crl.certum.pl</domain>
<domain includeSubdomains="true">homepldvtlsg2r35ca.crl.certum.pl</domain>
<domain includeSubdomains="true">homepldvtlsg2r36ca.crl.certum.pl</domain>
<domain includeSubdomains="true">homeplovtlsg2r35ca.crl.certum.pl</domain>
<domain includeSubdomains="true">homeplovtlsg2r36ca.crl.certum.pl</domain>
<domain includeSubdomains="true">httpcrl.trust.telia.com</domain>
<domain includeSubdomains="true">ica.navercloudtrust.com</domain>
<domain includeSubdomains="true">ica.navercorp.com</domain>
<domain includeSubdomains="true">issauth.crl.sectigo.com</domain>
<domain includeSubdomains="true">itrusdv2.crl.certum.pl</domain>
<domain includeSubdomains="true">itrusdvtlsr35g2ca.crl.certum.pl</domain>
<domain includeSubdomains="true">itrusov2.crl.certum.pl</domain>
<domain includeSubdomains="true">itrusovtlsr35g2ca.crl.certum.pl</domain>
<domain includeSubdomains="true">itso.crl.sectigo.com</domain>
<domain includeSubdomains="true">joyssldvtlsg2r33ca.crl.certum.pl</domain>
<domain includeSubdomains="true">joysslovtlsg2r33ca.crl.certum.pl</domain>
<domain includeSubdomains="true">kingnettechdv.crl.certum.pl</domain>
<domain includeSubdomains="true">kingnettechev.crl.certum.pl</domain>
<domain includeSubdomains="true">kingnettechov.crl.certum.pl</domain>
<domain includeSubdomains="true">kr.crl.digicert.com</domain>
<domain includeSubdomains="true">lh2.crl.certum.pl</domain>
<domain includeSubdomains="true">namecheap.crl.sectigo.com</domain>
<domain includeSubdomains="true">nazwassldvtlsg2e29ca.crl.certum.pl</domain>
<domain includeSubdomains="true">nazwassldvtlsg2r29ca.crl.certum.pl</domain>
<domain includeSubdomains="true">netartcadv2.crl.certum.pl</domain>
<domain includeSubdomains="true">netartssldvtlsg2e31ca.crl.certum.pl</domain>
<domain includeSubdomains="true">nijimo.crl.sectigo.com</domain>
<domain includeSubdomains="true">nyalabscadv.crl.certum.pl</domain>
<domain includeSubdomains="true">nyatworkdv.crl.certum.pl</domain>
<domain includeSubdomains="true">omitsecurity.crl.sectigo.com</domain>
<domain includeSubdomains="true">onesign.crl.sectigo.com</domain>
<domain includeSubdomains="true">osslca2016-crl1.e-szigno.hu</domain>
<domain includeSubdomains="true">osslca2016-crl2.e-szigno.hu</domain>
<domain includeSubdomains="true">osslca2016-crl3.e-szigno.hu</domain>
<domain includeSubdomains="true">ovtlsca2025-crl.e-szigno.hu</domain>
<domain includeSubdomains="true">ovtlsca2026-crl.e-szigno.hu</domain>
<domain includeSubdomains="true">pki-crl.atos.net</domain>
<domain includeSubdomains="true">pki.telesec.de</domain>
<domain includeSubdomains="true">pkipro.certsign.ro</domain>
<domain includeSubdomains="true">positiwise.crl.sectigo.com</domain>
<domain includeSubdomains="true">psw.crl.sectigo.com</domain>
<domain includeSubdomains="true">public.wisekey.com</domain>
<domain includeSubdomains="true">qiduodv.crl.certum.pl</domain>
<domain includeSubdomains="true">qtlsca2018-crl1.e-szigno.hu</domain>
<domain includeSubdomains="true">qtlsca2018-crl2.e-szigno.hu</domain>
<domain includeSubdomains="true">qtlsca2018-crl3.e-szigno.hu</domain>
<domain includeSubdomains="true">qtlsca2026-crl.e-szigno.hu</domain>
<domain includeSubdomains="true">r10.c.lencr.org</domain>
<domain includeSubdomains="true">r11.c.lencr.org</domain>
<domain includeSubdomains="true">r12.c.lencr.org</domain>
<domain includeSubdomains="true">r13.c.lencr.org</domain>
<domain includeSubdomains="true">rca.navercloudtrust.com</domain>
<domain includeSubdomains="true">rca.navercorp.com</domain>
<domain includeSubdomains="true">repo.pubcert.jprs.jp</domain>
<domain includeSubdomains="true">repo1.secomtrust.net</domain>
<domain includeSubdomains="true">repository.secomtrust.net</domain>
<domain includeSubdomains="true">repository.tls.hinet.net</domain>
<domain includeSubdomains="true">rootca.twca.com.tw</domain>
<domain includeSubdomains="true">rootglobaldv.crl.certum.pl</domain>
<domain includeSubdomains="true">rootnetworksdv2.crl.certum.pl</domain>
<domain includeSubdomains="true">shenzhendv.crl.certum.pl</domain>
<domain includeSubdomains="true">shenzhenev.crl.certum.pl</domain>
<domain includeSubdomains="true">shenzhenov.crl.certum.pl</domain>
<domain includeSubdomains="true">shoperdvtlsg2r34ca.crl.certum.pl</domain>
<domain includeSubdomains="true">shuididv.crl.certum.pl</domain>
<domain includeSubdomains="true">shuidiev.crl.certum.pl</domain>
<domain includeSubdomains="true">shuidiov.crl.certum.pl</domain>
<domain includeSubdomains="true">soomadv.crl.certum.pl</domain>
<domain includeSubdomains="true">ssl2ca2016-crl1.e-szigno.hu</domain>
<domain includeSubdomains="true">ssl2ca2016-crl2.e-szigno.hu</domain>
<domain includeSubdomains="true">ssl2ca2016-crl3.e-szigno.hu</domain>
<domain includeSubdomains="true">sslca2014-crl1.e-szigno.hu</domain>
<domain includeSubdomains="true">sslca2014-crl2.e-szigno.hu</domain>
<domain includeSubdomains="true">sslca2014-crl3.e-szigno.hu</domain>
<domain includeSubdomains="true">sslcom.crl.certum.pl</domain>
<domain includeSubdomains="true">ssllimiteddv.crl.certum.pl</domain>
<domain includeSubdomains="true">sslserver.twca.com.tw</domain>
<domain includeSubdomains="true">subca.crl.certum.pl</domain>
<domain includeSubdomains="true">titrust.crl.sectigo.com</domain>
<domain includeSubdomains="true">tlcdvtlsr34g2ca.crl.certum.pl</domain>
<domain includeSubdomains="true">tlcevtlsr34g2ca.crl.certum.pl</domain>
<domain includeSubdomains="true">tlcovtlsr34g2ca.crl.certum.pl</domain>
<domain includeSubdomains="true">tlsrootca2025-crl.e-szigno.hu</domain>
<domain includeSubdomains="true">trustasia.crl.certum.pl</domain>
<domain includeSubdomains="true">trustasiadv.crl.certum.pl</domain>
<domain includeSubdomains="true">trustasiadvtlsr35g2ca.crl.certum.pl</domain>
<domain includeSubdomains="true">trustasiaev.crl.certum.pl</domain>
<domain includeSubdomains="true">trustasiaevtlse35g2ca.crl.certum.pl</domain>
<domain includeSubdomains="true">trustasiaevtlsr35g2ca.crl.certum.pl</domain>
<domain includeSubdomains="true">trustasiaov.crl.certum.pl</domain>
<domain includeSubdomains="true">trustasiaovtlse35g2ca.crl.certum.pl</domain>
<domain includeSubdomains="true">trustasiaovtlsr35g2ca.crl.certum.pl</domain>
<domain includeSubdomains="true">trustocean.crl.certum.pl</domain>
<domain includeSubdomains="true">tstlser20.crl.telesec.de</domain>
<domain includeSubdomains="true">tstlsrr23.crl.telesec.de</domain>
<domain includeSubdomains="true">unitedtrustov.crl.certum.pl</domain>
<domain includeSubdomains="true">validation.identrust.com</domain>
<domain includeSubdomains="true">verokey.crl.sectigo.com</domain>
<domain includeSubdomains="true">vtrusdvtlsg3r31ca.crl.certum.pl</domain>
<domain includeSubdomains="true">vtrusovtlsg3r31ca.crl.certum.pl</domain>
<domain includeSubdomains="true">webnic.crl.sectigo.com</domain>
<domain includeSubdomains="true">whitessldvtlsg2e36ca.crl.certum.pl</domain>
<domain includeSubdomains="true">wosign.crl.certum.pl</domain>
<domain includeSubdomains="true">wotrus-dvca.crl.certum.pl</domain>
<domain includeSubdomains="true">wotrus-evca.crl.certum.pl</domain>
<domain includeSubdomains="true">wotrus-ovca.crl.certum.pl</domain>
<domain includeSubdomains="true">wotrus.crl.sectigo.com</domain>
<domain includeSubdomains="true">wtca-cafiles.itrus.com.cn</domain>
<domain includeSubdomains="true">wtca-crl.itrus.com.cn</domain>
<domain includeSubdomains="true">www.accv.es</domain>
<domain includeSubdomains="true">www.cert.fnmt.es</domain>
<domain includeSubdomains="true">www.d-trust.net</domain>
<domain includeSubdomains="true">www.microsoft.com</domain>
<domain includeSubdomains="true">x1.c.lencr.org</domain>
<domain includeSubdomains="true">x2.c.lencr.org</domain>
<domain includeSubdomains="true">xcctrustdvtlsg3r31ca.crl.certum.pl</domain>
<domain includeSubdomains="true">xcctrustevtlsg3r31ca.crl.certum.pl</domain>
<domain includeSubdomains="true">xcctrustovtlsg3r31ca.crl.certum.pl</domain>
<domain includeSubdomains="true">xinchacha2dv.crl.certum.pl</domain>
<domain includeSubdomains="true">xinchacha2ov.crl.certum.pl</domain>
<domain includeSubdomains="true">xinchachatrustdvtlsg2r34ca.crl.certum.pl</domain>
<domain includeSubdomains="true">xinchachatrustevtlsg2r34ca.crl.certum.pl</domain>
<domain includeSubdomains="true">xinchachatrustovtlsg2r34ca.crl.certum.pl</domain>
<domain includeSubdomains="true">xinnetdvtlsr34g2ca.crl.certum.pl</domain>
<domain includeSubdomains="true">xinnetevtlsr34g2ca.crl.certum.pl</domain>
<domain includeSubdomains="true">xinnetovtlsr34g2ca.crl.certum.pl</domain>
<domain includeSubdomains="true">ye.c.lencr.org</domain>
<domain includeSubdomains="true">ye1.c.lencr.org</domain>
<domain includeSubdomains="true">ye2.c.lencr.org</domain>
<domain includeSubdomains="true">yektadv.crl.certum.pl</domain>
<domain includeSubdomains="true">yektaov.crl.certum.pl</domain>
<domain includeSubdomains="true">yr.c.lencr.org</domain>
<domain includeSubdomains="true">yr1.c.lencr.org</domain>
<domain includeSubdomains="true">yr2.c.lencr.org</domain>
<domain includeSubdomains="true">zerossl.crl.sectigo.com</domain>
<domain includeSubdomains="true">ziwit.crl.sectigo.com</domain>
<domain includeSubdomains="true">zycatrustdvtlsg3r31ca.crl.certum.pl</domain>
<domain includeSubdomains="true">zycatrustevtlsg3r31ca.crl.certum.pl</domain>
<domain includeSubdomains="true">zycatrustovtlsg3r31ca.crl.certum.pl</domain>
</domain-config> </domain-config>
</network-security-config> </network-security-config>
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config xmlns:tools="http://schemas.android.com/tools">
<!-- Ref: https://developer.android.com/training/articles/security-config.html -->
<!-- By default, do not allow clearText traffic -->
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="system" />
<certificates
src="user"
tools:ignore="AcceptsUserCertificates" />
</trust-anchors>
</base-config>
<!-- Allow clearText traffic on some specified host -->
<domain-config cleartextTrafficPermitted="true">
<!-- Localhost -->
<domain includeSubdomains="true">localhost</domain>
<domain includeSubdomains="true">127.0.0.1</domain>
<!-- Localhost for Android emulator -->
<domain includeSubdomains="true">10.0.2.2</domain>
<!-- Onion services -->
<domain includeSubdomains="true">onion</domain>
<!-- Domains that are used for LANs -->
<!-- These are IANA recognized special use domain names, see https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml -->
<domain includeSubdomains="true">home.arpa</domain>
<domain includeSubdomains="true">local</domain> <!-- Note this has been reserved for use with mDNS -->
<domain includeSubdomains="true">test</domain>
<!-- These are observed in the wild either by convention or RFCs that have not been accepted, and are not currently TLDs -->
<domain includeSubdomains="true">home</domain>
<domain includeSubdomains="true">lan</domain>
<domain includeSubdomains="true">localdomain</domain>
</domain-config>
</network-security-config>
+2 -1
View File
@@ -182,7 +182,8 @@ test_detekt_test = { module = "io.gitlab.arturbosch.detekt:detekt-test", version
# https://github.com/matrix-org/matrix-rust-components-kotlin/commits/main/sdk/sdk-android/src/main/kotlin/org/matrix/rustcomponents/sdk/matrix_sdk_ffi.kt # https://github.com/matrix-org/matrix-rust-components-kotlin/commits/main/sdk/sdk-android/src/main/kotlin/org/matrix/rustcomponents/sdk/matrix_sdk_ffi.kt
# All new features should not be implemented in the pull request that upgrades the version, developers should # All new features should not be implemented in the pull request that upgrades the version, developers should
# only fix API breaks and may add some TODOs. # only fix API breaks and may add some TODOs.
matrix_sdk = "org.matrix.rustcomponents:sdk-android:26.09.26" matrix_sdk = "org.matrix.rustcomponents:sdk-android:26.09.28"
rustls_platform_verifier = "org.rustls:rustls-platform-verifier:0.2.0"
# Others # Others
coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" } coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" }
+1 -1
View File
@@ -28,7 +28,7 @@ dependencies {
} else { } else {
debugImplementation(libs.matrix.sdk) debugImplementation(libs.matrix.sdk)
} }
implementation(projects.libraries.rustlsTls) implementation(variantOf(libs.rustls.platform.verifier) { artifactType("aar") })
implementation(projects.appconfig) implementation(projects.appconfig)
implementation(projects.features.enterprise.api) implementation(projects.features.enterprise.api)
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package org.matrix.rustsdk
import android.content.Context
/**
* This class is used to initialize the Rust SDK on Android and give it access to an Android [Context].
*/
object Android {
init {
System.loadLibrary("matrix_sdk_ffi")
}
@JvmStatic
external fun init(context: Context)
}
@@ -40,6 +40,8 @@ internal fun aRustEventTimelineItem(
canBeRepliedTo: Boolean = true, canBeRepliedTo: Boolean = true,
reactions: List<Reaction> = emptyList(), reactions: List<Reaction> = emptyList(),
lazyProvider: LazyTimelineItemProvider = FakeFfiLazyTimelineItemProvider(), lazyProvider: LazyTimelineItemProvider = FakeFfiLazyTimelineItemProvider(),
editSendState: EventSendState? = null,
redactionSendState: EventSendState? = null,
) = EventTimelineItem( ) = EventTimelineItem(
isRemote = isRemote, isRemote = isRemote,
eventOrTransactionId = eventOrTransactionId, eventOrTransactionId = eventOrTransactionId,
@@ -59,4 +61,6 @@ internal fun aRustEventTimelineItem(
canBeRepliedTo = canBeRepliedTo, canBeRepliedTo = canBeRepliedTo,
reactions = reactions, reactions = reactions,
lazyProvider = lazyProvider, lazyProvider = lazyProvider,
editSendState = editSendState,
redactionSendState = redactionSendState,
) )
-9
View File
@@ -1,9 +0,0 @@
This module is a wrapper for the Android code distributed in the rustls-platform-verifier-android crate.
To avoid the distribution mess that this library has (download a Rust crate, then search for it using Gradle and use it as local maven repo),
we previously just manually updated the AAR file instead using a script. This won't work for F-Droid because the AAR library is a black box with
no sources attached to it, so we can't use it like that.
Instead, for the time being, we're adding the single `CertificateVerifier.kt` class this AAR had in it as part of our sources.
When this file is updated, the [UPDATED.md](./UPDATED.md) file should be updated too with the commit SHA of the new version.
-7
View File
@@ -1,7 +0,0 @@
Below is the commit SHA in [rustls-platform-verifier](https://github.com/rustls/rustls-platform-verifier) library used to update the code in this module:
```
996b1c903491641b17b3c9afb65d1352f6fc6b76
```
Please update it after making manual changes.
-24
View File
@@ -1,24 +0,0 @@
import extension.buildConfigFieldBoolean
/*
* Copyright (c) 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
plugins {
id("io.element.android-library")
}
android {
namespace = "org.rustls.platformverifier"
buildFeatures {
buildConfig = true
}
defaultConfig {
buildConfigFieldBoolean("TEST", false)
}
}
@@ -1,398 +0,0 @@
@file:SuppressLint("LogNotTimber", "ObsoleteSdkInt")
@file:Suppress("KotlinConstantConditions")
// IMPORTANT: this file comes from rustls-platform-verifier and should not be modified locally.
/*
* Copyright (c) 2022 1Password
*
* SPDX-License-Identifier: MIT
*/
package org.rustls.platformverifier
import android.annotation.SuppressLint
import android.content.Context
import android.net.http.X509TrustManagerExtensions
import android.util.Log
import java.io.ByteArrayInputStream
import java.io.File
import java.security.KeyStore
import java.security.KeyStoreException
import java.security.MessageDigest
import java.security.PublicKey
import java.security.cert.CertificateException
import java.security.cert.CertificateExpiredException
import java.security.cert.CertificateFactory
import java.security.cert.CertificateNotYetValidException
import java.security.cert.CertificateParsingException
import java.security.cert.X509Certificate
import java.util.Date
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
import javax.security.auth.x500.X500Principal
// If this is updated, update the Rust definition too.
// Marked private as this is not meant to be used in Android code.
private enum class StatusCode(val value: Int) {
Ok(0),
Unavailable(1),
Expired(2),
UnknownCert(3),
Revoked(4),
InvalidEncoding(5),
InvalidExtension(6),
}
// Marked private as this is not meant to be used in Android code.
private class VerificationResult(
status: StatusCode,
@Suppress("unused") val message: String? = null
) {
@Suppress("unused")
private val code: Int = status.value
}
// NOTE: All TrustManager and certificate validation methods are not thread safe. These
// are all guarded by Kotlin's `Synchronized` accessors to prevent undefined behavior.
// Only JNI and test code calls this, so unused code warnings are suppressed.
// Internal for test code - no other Kotlin code should use this object directly.
@Suppress("unused")
// We want to show a difference between Kotlin-side logs and those in Rust code
@SuppressLint("LongLogTag")
internal object CertificateVerifier {
private const val TAG = "rustls-platform-verifier-android"
private fun createTrustManager(keystore: KeyStore?): X509TrustManagerExtensions? {
// This can never throw since the default algorithm is used.
val factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
factory.init(keystore)
val availableTrustManagers = try {
factory.trustManagers
} catch (e: RuntimeException) {
Log.w(TAG, "exception thrown creating a TrustManager: $e")
return null
}
for (manager in availableTrustManagers) {
if (manager is X509TrustManager) {
// Kotlin ensures this can't throw at runtime since it knows that
// it must be the correct type by now.
return X509TrustManagerExtensions(manager)
}
}
Log.e(TAG, "failed to find a usable trust manager")
return null
}
private fun makeLazyTrustManager(keystore: KeyStore?): Lazy<X509TrustManagerExtensions?> {
// Ensure the keystore is loaded. Since all of the trust managers are initialized in a
// `Lazy`, this will only run once.
keystore?.load(null)
return lazy { createTrustManager(keystore) }
}
// -- Test only --
// Ideally, all of this will be optimized out at compile time due to not being accessed
// in release builds.
@get:Synchronized
private val mockKeystore: KeyStore = KeyStore.getInstance(KeyStore.getDefaultType())
@get:Synchronized
private var mockTrustManager: Lazy<X509TrustManagerExtensions?> =
makeLazyTrustManager(mockKeystore)
@JvmStatic
private fun addMockRoot(root: ByteArray) {
if (!BuildConfig.TEST) {
throw Exception("attempted to add a mock root outside a test!")
}
val alias = "root_${mockKeystore.size()}"
// Throwing here is fine since test roots should always be well-formed
val cert = certFactory.generateCertificate(ByteArrayInputStream(root))
mockKeystore.setCertificateEntry(alias, cert)
reloadMockData()
}
@JvmStatic
private fun clearMockRoots() {
// Reload to get a completely fresh internal state
mockKeystore.load(null)
reloadMockData()
}
@JvmStatic
private fun reloadMockData() {
if (mockTrustManager.isInitialized()) {
mockTrustManager = makeLazyTrustManager(mockKeystore)
}
}
// Get a list of the system's root CAs.
// Function is public for testing only.
@JvmStatic
fun getSystemRootCAs(): List<X509Certificate> {
val rootCAs = mutableListOf<X509Certificate>()
val factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
factory.init(systemKeystore)
val availableTrustManagers = try {
factory.trustManagers
} catch (e: RuntimeException) {
Log.w(TAG, "exception thrown creating a TrustManager: $e")
return rootCAs
}
availableTrustManagers.forEach { trustManager ->
if (trustManager is X509TrustManager) {
rootCAs.addAll(trustManager.acceptedIssuers)
}
}
return rootCAs
}
// -- End testing requirements --
private val certFactory: CertificateFactory = CertificateFactory.getInstance("X.509")
private var systemTrustAnchorCache = hashSetOf<Pair<X500Principal, PublicKey>>()
@get:Synchronized
private var systemCertificateDirectory: File? = System.getenv("ANDROID_ROOT")?.let { rootPath ->
File("$rootPath/etc/security/cacerts")
}
@get:Synchronized
private val systemKeystore: KeyStore? = try {
KeyStore.getInstance("AndroidCAStore")
} catch (_: KeyStoreException) {
null
}
@get:Synchronized
private val systemTrustManager: Lazy<X509TrustManagerExtensions?> =
makeLazyTrustManager(systemKeystore)
@JvmStatic
private fun verifyCertificateChain(
@Suppress("UNUSED_PARAMETER") context: Context,
serverName: String,
authMethod: String,
allowedEkus: Array<String>,
ocspResponse: ByteArray?,
time: Long,
certChain: Array<ByteArray>
): VerificationResult {
// Convert the array of (supposedly) DER bytes into certificates.
val certificateChain = mutableListOf<X509Certificate>()
certChain.forEach { certBytes ->
val certificate = try {
certFactory.generateCertificate(ByteArrayInputStream(certBytes))
} catch (e: CertificateException) {
return VerificationResult(StatusCode.InvalidEncoding)
}
certificateChain.add(certificate as X509Certificate)
}
// Will never throw `ArrayIndexOutOfBoundsException` because `rustls`'s `ServerCertVerifier` trait
// has a mandatory `end_entity` parameter in `verify_server_cert`.
val endEntity = certificateChain[0]
// Check that the certificate is valid at the point of time provided by `rustls`.
try {
endEntity.checkValidity(Date(time))
} catch (e: CertificateExpiredException) {
return VerificationResult(StatusCode.Expired)
} catch (e: CertificateNotYetValidException) {
return VerificationResult(StatusCode.Expired)
}
// Check that this certificate can be used in a TLS server.
if (!verifyCertUsage(endEntity, allowedEkus)) {
return VerificationResult(StatusCode.InvalidExtension)
}
// Select the trust manager to use.
//
// We select them as follows:
// - If built for release, only use the system trust manager. This should let all test-related
// code be optimized out.
// - If built for tests:
// - If the mock CA store has any values, use the mock trust manager.
// - Otherwise, use the system trust manager.
val (trustManager, keystore) = if (!BuildConfig.TEST) {
val trustManager =
systemTrustManager.value ?: return VerificationResult(StatusCode.Unavailable)
Pair(trustManager, systemKeystore)
} else {
if (mockKeystore.size() != 0) {
val trustManager = mockTrustManager.value!!
Pair(trustManager, mockKeystore)
} else {
val trustManager =
systemTrustManager.value ?: return VerificationResult(StatusCode.Unavailable)
Pair(trustManager, systemKeystore)
}
}
// Verify that the certificate chain is valid and correct, and nothing more.
//
// NOTE: This does not validate `serverName` is valid for the end-entity certificate.
// That is handled in Rust as Android/Java do not currently provide a RFC 6125 compliant
// hostname verifier. Additionally, even the RFC 2818 verifier is not available until API 24.
//
// `serverName` is only used for pinning/CT requirements.
//
// Returns the "the properly ordered chain used for verification as a list of X509Certificates.",
// meaning a list from end-entity certificate to trust-anchor.
val validChain = try {
trustManager.checkServerTrusted(certificateChain.toTypedArray(), authMethod, serverName)
} catch (e: CertificateException) {
// In test configurations we may see `checkServerTrusted` fail once vendored test
// certificates pass their expiry date. We try to avoid that by using a fixed
// verification time when calling `endEntity.checkValidity` above, however we can't
// fix the time for the `checkServerTrusted` call.
//
// To make diagnosing CI test failures easier we try to find the root cause of
// checkServerTrusted failing, returning a different `StatusCode` as appropriate.
if (BuildConfig.TEST) {
var rootCause: Throwable? = e
while (rootCause?.cause != null && rootCause.cause != rootCause) {
rootCause = rootCause.cause
}
return when (rootCause) {
is CertificateExpiredException, is CertificateNotYetValidException -> VerificationResult(
StatusCode.Expired,
rootCause.toString()
)
else -> VerificationResult(StatusCode.UnknownCert, rootCause.toString())
}
}
// In non-test configurations we should have caught expiry errors earlier and
// can simply return an unknown cert error without digging through the exception
// cause chain.
return VerificationResult(StatusCode.UnknownCert, e.toString())
}
// TEST ONLY: Mock test suite cannot attempt to check revocation status if no OSCP data has been stapled,
// because Android requires certificates to an specify OCSP responder for network fetch in this case.
// If in testing w/o OCSP stapled, short-circuit here - only prior checks apply.
if (BuildConfig.TEST && (mockKeystore.size() != 0) && (ocspResponse == null)) {
return VerificationResult(StatusCode.Ok)
}
// =================================================================================================
// IMPORTANT! DIFF WITH THE ORIGINAL SOURCES HERE:
//
// We removed the cert revocation checks because Android won't do them by default
// and supporting them would be quite difficult given CRLs won't work out of the box.
//
// See https://github.com/rustls/rustls-platform-verifier/issues/221 for more info.
// =================================================================================================
return VerificationResult(StatusCode.Ok)
}
private fun verifyCertUsage(certificate: X509Certificate, allowedEkus: Array<String>): Boolean {
val ekus = try {
certificate.extendedKeyUsage
}
// This should be unreachable, but could happen.
catch (_: CertificateParsingException) {
return false
} catch (_: NullPointerException) {
// According to Chromium's implementation, this can crash when the EKU data is malformed.
Log.w(TAG, "exception handling certificate EKU")
return false
} ?: return true // If the list is empty, we have nothing to do.
return ekus.any { allowedEkus.contains(it) }
}
// Android hashes a principal using the first four bytes of its MD5 digest, encoded in
// lowercase hex and reversed.
//
// Ref: https://source.chromium.org/chromium/chromium/src/+/main:net/android/java/src/org/chromium/net/X509Util.java;l=339
private fun hashPrincipal(principal: X500Principal): String {
val hexDigits = "0123456789abcdef".toCharArray()
val digest = MessageDigest.getInstance("MD5").digest(principal.encoded)
val hexChars = CharArray(8)
for (i in 0..3) {
// Kotlin doesn't support bitwise operators for bytes, only Int and Long.
val digestByte = digest[3 - i].toInt()
hexChars[2 * i] = hexDigits[(digestByte shr 4) and 0xf]
hexChars[2 * i + 1] = hexDigits[digestByte and 0xf]
}
return String(hexChars)
}
// Check if CA root is known or not.
// Known means installed in root CA store, either a preset public CA or a custom one installed by an enterprise/user.
//
// Ref: https://source.chromium.org/chromium/chromium/src/+/main:net/android/java/src/org/chromium/net/X509Util.java;l=351
fun isKnownRoot(root: X509Certificate): Boolean {
// System keystore and cert directory must be non-null to perform checking
systemKeystore?.let { loadedSystemKeystore ->
systemCertificateDirectory?.let { loadedSystemCertificateDirectory ->
// Check the in-memory cache first
val key = Pair(root.subjectX500Principal, root.publicKey)
if (systemTrustAnchorCache.contains(key)) {
return true
}
// System trust anchors are stored under a hash of the principal.
// In case of collisions, append number.
val hash = hashPrincipal(root.subjectX500Principal)
var i = 0
while (true) {
val alias = "$hash.$i"
if (!File(loadedSystemCertificateDirectory, alias).exists()) {
break
}
val anchor = loadedSystemKeystore.getCertificate("system:$alias")
// It's possible for `anchor` to be `null` if the user deleted a trust anchor.
// Continue iterating as there may be further collisions after the deleted anchor.
if (anchor == null) {
continue
// This should never happen
} else if (anchor !is X509Certificate) {
// SAFETY: This logs a unique identifier (hash value) only in cases where a file within the
// system's root trust store is not a valid X509 certificate (extremely unlikely error).
// The hash doesn't tell us any sensitive information about the invalid cert or reveal any of
// its contents - it just lets us ID the bad file if a user is having TLS failure issues.
Log.e(TAG, "anchor is not a certificate, alias: $alias")
continue
// If subject and public key match, it's a system root.
} else {
if ((root.subjectX500Principal == anchor.subjectX500Principal) && (root.publicKey == anchor.publicKey)) {
systemTrustAnchorCache.add(key)
return true
}
}
i += 1
}
}
}
// Not found in cache or store: non-public
return false
}
}
@@ -43,7 +43,6 @@ val excludedKoverSubProjects = listOf(
":libraries:core", ":libraries:core",
":libraries:coroutines", ":libraries:coroutines",
":libraries:di", ":libraries:di",
":libraries:rustls-tls",
":tests:detekt-rules", ":tests:detekt-rules",
":tests:konsist", ":tests:konsist",
":tests:testutils", ":tests:testutils",
+10
View File
@@ -17,6 +17,16 @@ pluginManagement {
dependencyResolutionManagement { dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories { repositories {
exclusiveContent {
forRepository {
maven {
url = uri("https://github.com/rustls/rustls-platform-verifier/raw/maven-archive/android-release-support/maven/")
}
}
filter {
includeModule("org.rustls", "rustls-platform-verifier")
}
}
maven { maven {
url = uri("https://www.jitpack.io") url = uri("https://www.jitpack.io")
content { content {
+128
View File
@@ -0,0 +1,128 @@
#!/usr/bin/env python3
# Copyright (c) 2026 Element Creations Ltd.
#
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
# Please see LICENSE files in the repository root for full details.
"""
Update the rustls-platform-verifier dependency to the given version and regenerate
app/src/main/res/xml/network_security_config.xml.
The rustls-platform-verifier AAR ships a network_security_config.xml allowing cleartext traffic
to the domains used by certificate authorities to publish their CRLs. Since the app has its own
network security config, those domains are merged into a copy of network_security_config_element.xml.
Usage: ./tools/dependencies/update_rustls_platform_verifier.py <version>
"""
import io
import os
import re
import sys
import urllib.request
import xml.etree.ElementTree as ET
import zipfile
ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
LIBS_VERSIONS_TOML = os.path.join(ROOT_DIR, "gradle", "libs.versions.toml")
XML_DIR = os.path.join(ROOT_DIR, "app", "src", "main", "res", "xml")
SOURCE_CONFIG = os.path.join(XML_DIR, "network_security_config_element.xml")
TARGET_CONFIG = os.path.join(XML_DIR, "network_security_config.xml")
AAR_URL = (
"https://raw.githubusercontent.com/rustls/rustls-platform-verifier/maven-archive/android-release-support/"
"maven/org/rustls/rustls-platform-verifier/{version}/rustls-platform-verifier-{version}.aar"
)
AAR_CONFIG_PATH = "res/xml/network_security_config.xml"
CLEARTEXT_DOMAIN_CONFIG_REGEX = re.compile(
r'(<domain-config\s+cleartextTrafficPermitted="true"\s*>.*?)(\n?[ \t]*</domain-config>)',
re.DOTALL,
)
def update_libs_versions(version):
with open(LIBS_VERSIONS_TOML, "r") as f:
content = f.read()
new_content, count = re.subn(
r'^(rustls_platform_verifier\s*=\s*"org\.rustls:rustls-platform-verifier:)[^"]+(")',
rf"\g<1>{version}\g<2>",
content,
flags=re.MULTILINE,
)
if count != 1:
sys.exit(f"Error: could not find the rustls_platform_verifier dependency in {LIBS_VERSIONS_TOML}")
with open(LIBS_VERSIONS_TOML, "w") as f:
f.write(new_content)
print(f"Updated rustls_platform_verifier to {version} in {os.path.relpath(LIBS_VERSIONS_TOML, ROOT_DIR)}")
def download_aar(version):
url = AAR_URL.format(version=version)
print(f"Downloading {url}")
try:
with urllib.request.urlopen(url) as response:
return response.read()
except urllib.error.HTTPError as e:
sys.exit(f"Error: could not download the AAR for version {version} ({e.code} {e.reason})")
def extract_cleartext_domains(aar_bytes):
with zipfile.ZipFile(io.BytesIO(aar_bytes)) as aar:
try:
config = aar.read(AAR_CONFIG_PATH)
except KeyError:
sys.exit(f"Error: {AAR_CONFIG_PATH} not found in the AAR")
root = ET.fromstring(config)
domains = []
for domain_config in root.iter("domain-config"):
if domain_config.get("cleartextTrafficPermitted") != "true":
continue
for domain in domain_config.findall("domain"):
domains.append((domain.get("includeSubdomains"), domain.text.strip()))
if not domains:
sys.exit("Error: no cleartext domains found in the AAR network_security_config.xml")
return domains
def write_network_security_config(domains, version):
with open(SOURCE_CONFIG, "r") as f:
content = f.read()
lines = [
"",
"",
f" <!-- Domains below are imported from rustls-platform-verifier {version} by tools/dependencies/update_rustls_platform_verifier.py -->",
" <!-- They are needed to fetch the certificate revocation lists over cleartext -->",
]
for include_subdomains, name in domains:
attributes = f' includeSubdomains="{include_subdomains}"' if include_subdomains is not None else ""
lines.append(f" <domain{attributes}>{name}</domain>")
extra = "\n".join(lines)
new_content, count = CLEARTEXT_DOMAIN_CONFIG_REGEX.subn(lambda m: m.group(1) + extra + m.group(2), content, count=1)
if count != 1:
sys.exit(f'Error: could not find <domain-config cleartextTrafficPermitted="true"> in {SOURCE_CONFIG}')
with open(TARGET_CONFIG, "w") as f:
f.write(new_content)
print(f"Wrote {os.path.relpath(TARGET_CONFIG, ROOT_DIR)} with {len(domains)} extra domains")
def main():
if len(sys.argv) != 2:
sys.exit(f"Usage: {sys.argv[0]} <version>")
version = sys.argv[1].strip()
if not re.fullmatch(r"[0-9A-Za-z.\-]+", version):
sys.exit(f"Error: invalid version '{version}'")
# Download first, so nothing is modified if the version does not exist
aar_bytes = download_aar(version)
domains = extract_cleartext_domains(aar_bytes)
update_libs_versions(version)
write_network_security_config(domains, version)
if __name__ == "__main__":
main()
+2
View File
@@ -42,6 +42,8 @@
<ignore path="**/src/debug/**" /> <ignore path="**/src/debug/**" />
<!-- Ignore unused resources in designsystem since they're imported elsewhere through aliases and can't be properly detected --> <!-- Ignore unused resources in designsystem since they're imported elsewhere through aliases and can't be properly detected -->
<ignore path="**/libraries/designsystem/src/main/res/**" /> <ignore path="**/libraries/designsystem/src/main/res/**" />
<!-- Ignore the network security config template: this will be merged with rustls's security config -->
<ignore path="**/src/main/res/xml/network_security_config_element.xml" />
</issue> </issue>
<!-- UX --> <!-- UX -->