From 73ba371a3ee5d8f0ba05b627984be538ab58400e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Wed, 14 Feb 2024 10:16:01 +0100 Subject: [PATCH 1/5] Add the user certificates as additional certificates to the ClientBuilder Now, this is a story all about how Certificates work in Android town And I'd like to take a minute Enter, close the door I'll tell you how I've figured out the inner workings of the Keystore Well it all boils down the fact that Google got scared It said, "You're certs are movin' to a place you won't find". So the directory, user certificates are stored, is hard to find, and possibly not readable by your application[1]. Instead, we need to use the Keystore[2] API, specifically we'll need to open the `AndroidCAStore` Keystore type. The various Keystore types are supposedly documented[3], but I'm failing to find a logical path that would lead you to conclude that: a) System certificates can or should be accessed using the Keystore, specifically the AndroidCAStore type b) User certificates can be found in the same Keystore type as the system certificates So this was mostly found using random googling, swearing, and a couple of educated guesses. [1]: https://android-developers.googleblog.com/2016/07/changes-to-trusted-certificate.html [2]: https://developer.android.com/reference/java/security/KeyStore [3]: https://docs.oracle.com/en/java/javase/17/docs/specs/security/standard-names.html#keystore-types --- .../matrix/impl/RustMatrixClientFactory.kt | 54 +++++++++++++++++++ .../auth/RustMatrixAuthenticationService.kt | 4 +- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt index 0f1c47445b..3d428afc0b 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt @@ -27,7 +27,9 @@ import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.ClientBuilder import org.matrix.rustcomponents.sdk.Session import org.matrix.rustcomponents.sdk.use +import timber.log.Timber import java.io.File +import java.security.KeyStore import javax.inject.Inject class RustMatrixClientFactory @Inject constructor( @@ -46,6 +48,7 @@ class RustMatrixClientFactory @Inject constructor( .username(sessionData.userId) .passphrase(sessionData.passphrase) .userAgent(userAgentProvider.provide()) + .addRootCertificates(getAdditionalCertificates()) // FIXME Quick and dirty fix for stopping version requests on startup https://github.com/matrix-org/matrix-rust-sdk/pull/1376 .serverVersions(listOf("v1.0", "v1.1", "v1.2", "v1.3", "v1.4", "v1.5")) .use { it.build() } @@ -68,6 +71,57 @@ class RustMatrixClientFactory @Inject constructor( } } +/** +* Get additional user-installed certificates from the `AndroidCAStore` `Keystore`. +* +* The Rust HTTP client doesn't include user-installed certificates in its internal certificate +* store. This means that whatever the user installs will be ignored. +* +* While most users don't need user-installed certificates some special deployments or debugging +* setups using a proxy might want to use them. +* +* @return A list of byte arrays where each byte array is a single user-installed certificate +* in encoded form. +*/ +fun getAdditionalCertificates(): List { + val certs = mutableListOf() + + // At least for API 34 the `AndroidCAStore` `Keystore` type contained user certificates as well. + // I have not found this to be documented anywhere. + val keyStore: KeyStore = KeyStore.getInstance("AndroidCAStore").apply { + load(null) + } + + val aliases = keyStore.aliases() + + while (aliases.hasMoreElements()) { + val alias = aliases.nextElement() + val entry = keyStore.getEntry(alias, null) + + if (entry is KeyStore.TrustedCertificateEntry) { + // The certificate alias always contains the prefix `system` or + // `user` and the MD5 subject hash separated by a colon. + // + // The subject hash can be calculated using openssl as such: + // openssl x509 -subject_hash_old -noout -in mycert.cer + // + // Again, I have not found this to be documented somewhere. + if (alias.startsWith("user")) { + certs.add(entry.trustedCertificate.encoded) + } + } + } + + // Let's at least log the number of user-installed certificates we found, + // since the alias isn't particularly useful nor does the issuer seem to + // be easily available. + val certCount = certs.count() + + Timber.i("Found $certCount additional user-provided certificates.") + + return certs +} + private fun SessionData.toSession() = Session( accessToken = accessToken, refreshToken = refreshToken, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt index c27ace88f6..e24993417a 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt @@ -30,6 +30,7 @@ import io.element.android.libraries.matrix.api.auth.OidcDetails import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.impl.RustMatrixClientFactory import io.element.android.libraries.matrix.impl.exception.mapClientException +import io.element.android.libraries.matrix.impl.getAdditionalCertificates import io.element.android.libraries.matrix.impl.keys.PassphraseGenerator import io.element.android.libraries.matrix.impl.mapper.toSessionData import io.element.android.libraries.network.useragent.UserAgentProvider @@ -61,11 +62,12 @@ class RustMatrixAuthenticationService @Inject constructor( // Passphrase which will be used for new sessions. Existing sessions will use the passphrase // stored in the SessionData. private val pendingPassphrase = getDatabasePassphrase() + private val additionalCertificates = getAdditionalCertificates() private val authService: RustAuthenticationService = RustAuthenticationService( basePath = baseDirectory.absolutePath, passphrase = pendingPassphrase, userAgent = userAgentProvider.provide(), - additionalRootCertificates = emptyList(), + additionalRootCertificates = additionalCertificates, oidcConfiguration = oidcConfiguration, customSlidingSyncProxy = null, sessionDelegate = null, From e9d3bfda45b9be12393d5e9b5293cbf94491c4e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Wed, 14 Feb 2024 14:40:40 +0100 Subject: [PATCH 2/5] Add a changelog fragment for the user-installed certs feature --- changelog.d/2992.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/2992.feature diff --git a/changelog.d/2992.feature b/changelog.d/2992.feature new file mode 100644 index 0000000000..622f6fdc69 --- /dev/null +++ b/changelog.d/2992.feature @@ -0,0 +1 @@ +Allow user-installed certificates to be used by the HTTP client From fd555b1070f4f5a561db89b662583959d5c3db7f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Feb 2024 11:02:26 +0100 Subject: [PATCH 3/5] Move getAdditionalCertificates function to a dedicated class (no change in the implementation). --- .../matrix/impl/RustMatrixClientFactory.kt | 57 +------------- .../auth/RustMatrixAuthenticationService.kt | 6 +- .../DefaultUserCertificatesProvider.kt | 77 +++++++++++++++++++ .../certificates/UserCertificatesProvider.kt | 21 +++++ .../android/samples/minimal/MainActivity.kt | 3 + .../minimal/NoOpUserCertificatesProvider.kt | 23 ++++++ 6 files changed, 130 insertions(+), 57 deletions(-) create mode 100644 libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/DefaultUserCertificatesProvider.kt create mode 100644 libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/UserCertificatesProvider.kt create mode 100644 samples/minimal/src/main/kotlin/io/element/android/samples/minimal/NoOpUserCertificatesProvider.kt diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt index 3d428afc0b..96670d2a2d 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt @@ -18,6 +18,7 @@ package io.element.android.libraries.matrix.impl import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.di.CacheDirectory +import io.element.android.libraries.matrix.impl.certificates.UserCertificatesProvider import io.element.android.libraries.network.useragent.UserAgentProvider import io.element.android.libraries.sessionstorage.api.SessionData import io.element.android.libraries.sessionstorage.api.SessionStore @@ -27,9 +28,7 @@ import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.ClientBuilder import org.matrix.rustcomponents.sdk.Session import org.matrix.rustcomponents.sdk.use -import timber.log.Timber import java.io.File -import java.security.KeyStore import javax.inject.Inject class RustMatrixClientFactory @Inject constructor( @@ -39,6 +38,7 @@ class RustMatrixClientFactory @Inject constructor( private val coroutineDispatchers: CoroutineDispatchers, private val sessionStore: SessionStore, private val userAgentProvider: UserAgentProvider, + private val userCertificatesProvider: UserCertificatesProvider, private val clock: SystemClock, ) { suspend fun create(sessionData: SessionData): RustMatrixClient = withContext(coroutineDispatchers.io) { @@ -48,7 +48,7 @@ class RustMatrixClientFactory @Inject constructor( .username(sessionData.userId) .passphrase(sessionData.passphrase) .userAgent(userAgentProvider.provide()) - .addRootCertificates(getAdditionalCertificates()) + .addRootCertificates(userCertificatesProvider.provides()) // FIXME Quick and dirty fix for stopping version requests on startup https://github.com/matrix-org/matrix-rust-sdk/pull/1376 .serverVersions(listOf("v1.0", "v1.1", "v1.2", "v1.3", "v1.4", "v1.5")) .use { it.build() } @@ -71,57 +71,6 @@ class RustMatrixClientFactory @Inject constructor( } } -/** -* Get additional user-installed certificates from the `AndroidCAStore` `Keystore`. -* -* The Rust HTTP client doesn't include user-installed certificates in its internal certificate -* store. This means that whatever the user installs will be ignored. -* -* While most users don't need user-installed certificates some special deployments or debugging -* setups using a proxy might want to use them. -* -* @return A list of byte arrays where each byte array is a single user-installed certificate -* in encoded form. -*/ -fun getAdditionalCertificates(): List { - val certs = mutableListOf() - - // At least for API 34 the `AndroidCAStore` `Keystore` type contained user certificates as well. - // I have not found this to be documented anywhere. - val keyStore: KeyStore = KeyStore.getInstance("AndroidCAStore").apply { - load(null) - } - - val aliases = keyStore.aliases() - - while (aliases.hasMoreElements()) { - val alias = aliases.nextElement() - val entry = keyStore.getEntry(alias, null) - - if (entry is KeyStore.TrustedCertificateEntry) { - // The certificate alias always contains the prefix `system` or - // `user` and the MD5 subject hash separated by a colon. - // - // The subject hash can be calculated using openssl as such: - // openssl x509 -subject_hash_old -noout -in mycert.cer - // - // Again, I have not found this to be documented somewhere. - if (alias.startsWith("user")) { - certs.add(entry.trustedCertificate.encoded) - } - } - } - - // Let's at least log the number of user-installed certificates we found, - // since the alias isn't particularly useful nor does the issuer seem to - // be easily available. - val certCount = certs.count() - - Timber.i("Found $certCount additional user-provided certificates.") - - return certs -} - private fun SessionData.toSession() = Session( accessToken = accessToken, refreshToken = refreshToken, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt index e24993417a..afedc889da 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt @@ -29,8 +29,8 @@ import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails import io.element.android.libraries.matrix.api.auth.OidcDetails import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.impl.RustMatrixClientFactory +import io.element.android.libraries.matrix.impl.certificates.UserCertificatesProvider import io.element.android.libraries.matrix.impl.exception.mapClientException -import io.element.android.libraries.matrix.impl.getAdditionalCertificates import io.element.android.libraries.matrix.impl.keys.PassphraseGenerator import io.element.android.libraries.matrix.impl.mapper.toSessionData import io.element.android.libraries.network.useragent.UserAgentProvider @@ -57,17 +57,17 @@ class RustMatrixAuthenticationService @Inject constructor( userAgentProvider: UserAgentProvider, private val rustMatrixClientFactory: RustMatrixClientFactory, private val passphraseGenerator: PassphraseGenerator, + userCertificatesProvider: UserCertificatesProvider, private val buildMeta: BuildMeta, ) : MatrixAuthenticationService { // Passphrase which will be used for new sessions. Existing sessions will use the passphrase // stored in the SessionData. private val pendingPassphrase = getDatabasePassphrase() - private val additionalCertificates = getAdditionalCertificates() private val authService: RustAuthenticationService = RustAuthenticationService( basePath = baseDirectory.absolutePath, passphrase = pendingPassphrase, userAgent = userAgentProvider.provide(), - additionalRootCertificates = additionalCertificates, + additionalRootCertificates = userCertificatesProvider.provides(), oidcConfiguration = oidcConfiguration, customSlidingSyncProxy = null, sessionDelegate = null, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/DefaultUserCertificatesProvider.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/DefaultUserCertificatesProvider.kt new file mode 100644 index 0000000000..fdccde1cd0 --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/DefaultUserCertificatesProvider.kt @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.matrix.impl.certificates + +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.di.AppScope +import timber.log.Timber +import java.security.KeyStore +import javax.inject.Inject + +@ContributesBinding(AppScope::class) +class DefaultUserCertificatesProvider @Inject constructor() : UserCertificatesProvider { + /** + * Get additional user-installed certificates from the `AndroidCAStore` `Keystore`. + * + * The Rust HTTP client doesn't include user-installed certificates in its internal certificate + * store. This means that whatever the user installs will be ignored. + * + * While most users don't need user-installed certificates some special deployments or debugging + * setups using a proxy might want to use them. + * + * @return A list of byte arrays where each byte array is a single user-installed certificate + * in encoded form. + */ + override fun provides(): List { + val certs = mutableListOf() + + // At least for API 34 the `AndroidCAStore` `Keystore` type contained user certificates as well. + // I have not found this to be documented anywhere. + val keyStore: KeyStore = KeyStore.getInstance("AndroidCAStore").apply { + load(null) + } + + val aliases = keyStore.aliases() + + while (aliases.hasMoreElements()) { + val alias = aliases.nextElement() + val entry = keyStore.getEntry(alias, null) + + if (entry is KeyStore.TrustedCertificateEntry) { + // The certificate alias always contains the prefix `system` or + // `user` and the MD5 subject hash separated by a colon. + // + // The subject hash can be calculated using openssl as such: + // openssl x509 -subject_hash_old -noout -in mycert.cer + // + // Again, I have not found this to be documented somewhere. + if (alias.startsWith("user")) { + certs.add(entry.trustedCertificate.encoded) + } + } + } + + // Let's at least log the number of user-installed certificates we found, + // since the alias isn't particularly useful nor does the issuer seem to + // be easily available. + val certCount = certs.count() + + Timber.i("Found $certCount additional user-provided certificates.") + + return certs + } +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/UserCertificatesProvider.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/UserCertificatesProvider.kt new file mode 100644 index 0000000000..330e29ee47 --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/UserCertificatesProvider.kt @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.matrix.impl.certificates + +interface UserCertificatesProvider { + fun provides(): List +} diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt index 30f5d2afe9..e87e0057d0 100644 --- a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt +++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt @@ -42,6 +42,7 @@ class MainActivity : ComponentActivity() { val baseDirectory = File(applicationContext.filesDir, "sessions") val userAgentProvider = SimpleUserAgentProvider("MinimalSample") val sessionStore = InMemorySessionStore() + val userCertificatesProvider = NoOpUserCertificatesProvider() RustMatrixAuthenticationService( baseDirectory = baseDirectory, coroutineDispatchers = Singleton.coroutineDispatchers, @@ -54,10 +55,12 @@ class MainActivity : ComponentActivity() { coroutineDispatchers = Singleton.coroutineDispatchers, sessionStore = sessionStore, userAgentProvider = userAgentProvider, + userCertificatesProvider = userCertificatesProvider, clock = DefaultSystemClock(), ), passphraseGenerator = NullPassphraseGenerator(), buildMeta = Singleton.buildMeta, + userCertificatesProvider = userCertificatesProvider, ) } diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/NoOpUserCertificatesProvider.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/NoOpUserCertificatesProvider.kt new file mode 100644 index 0000000000..a34fb4dbe0 --- /dev/null +++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/NoOpUserCertificatesProvider.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.samples.minimal + +import io.element.android.libraries.matrix.impl.certificates.UserCertificatesProvider + +class NoOpUserCertificatesProvider : UserCertificatesProvider { + override fun provides(): List = emptyList() +} From a3f7d55a64a1f5fd2d96e749f4b1653cb89c6460 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Feb 2024 12:06:42 +0100 Subject: [PATCH 4/5] Safer code, add some try catch blocks. Filter out system alias before reading the keyStore entry. use `size` instead of `count()` Kotlin style. --- .../DefaultUserCertificatesProvider.kt | 62 ++++++++++++------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/DefaultUserCertificatesProvider.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/DefaultUserCertificatesProvider.kt index fdccde1cd0..826e09489b 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/DefaultUserCertificatesProvider.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/DefaultUserCertificatesProvider.kt @@ -20,6 +20,7 @@ import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.di.AppScope import timber.log.Timber import java.security.KeyStore +import java.security.KeyStoreException import javax.inject.Inject @ContributesBinding(AppScope::class) @@ -37,21 +38,28 @@ class DefaultUserCertificatesProvider @Inject constructor() : UserCertificatesPr * in encoded form. */ override fun provides(): List { - val certs = mutableListOf() - // At least for API 34 the `AndroidCAStore` `Keystore` type contained user certificates as well. // I have not found this to be documented anywhere. - val keyStore: KeyStore = KeyStore.getInstance("AndroidCAStore").apply { - load(null) + val keyStore: KeyStore = try { + KeyStore.getInstance("AndroidCAStore") + } catch (e: KeyStoreException) { + Timber.w(e, "Failed to get AndroidCAStore keystore") + return emptyList() } - - val aliases = keyStore.aliases() - - while (aliases.hasMoreElements()) { - val alias = aliases.nextElement() - val entry = keyStore.getEntry(alias, null) - - if (entry is KeyStore.TrustedCertificateEntry) { + try { + keyStore.load(null) + } catch (e: Exception) { + Timber.w(e, "Failed to load AndroidCAStore keystore") + return emptyList() + } + val aliases = try { + keyStore.aliases() + } catch (e: Exception) { + Timber.w(e, "Failed to get aliases from AndroidCAStore keystore") + return emptyList() + } + return aliases.toList() + .filter { alias -> // The certificate alias always contains the prefix `system` or // `user` and the MD5 subject hash separated by a colon. // @@ -59,19 +67,25 @@ class DefaultUserCertificatesProvider @Inject constructor() : UserCertificatesPr // openssl x509 -subject_hash_old -noout -in mycert.cer // // Again, I have not found this to be documented somewhere. - if (alias.startsWith("user")) { - certs.add(entry.trustedCertificate.encoded) + alias.startsWith("user") + } + .mapNotNull { alias -> + try { + keyStore.getEntry(alias, null) + } catch (e: Exception) { + Timber.w(e, "Failed to get entry for alias $alias") + null } } - } - - // Let's at least log the number of user-installed certificates we found, - // since the alias isn't particularly useful nor does the issuer seem to - // be easily available. - val certCount = certs.count() - - Timber.i("Found $certCount additional user-provided certificates.") - - return certs + .filterIsInstance() + .map { trustedCertificateEntry -> + trustedCertificateEntry.trustedCertificate.encoded + } + .also { + // Let's at least log the number of user-installed certificates we found, + // since the alias isn't particularly useful nor does the issuer seem to + // be easily available. + Timber.i("Found ${it.size} additional user-provided certificates.") + } } } From 9fed8689682dacd9382030ce766f210ff479e608 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Feb 2024 16:06:01 +0100 Subject: [PATCH 5/5] Merge try blocks. --- .../impl/certificates/DefaultUserCertificatesProvider.kt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/DefaultUserCertificatesProvider.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/DefaultUserCertificatesProvider.kt index 826e09489b..5919952a9a 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/DefaultUserCertificatesProvider.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/DefaultUserCertificatesProvider.kt @@ -46,16 +46,11 @@ class DefaultUserCertificatesProvider @Inject constructor() : UserCertificatesPr Timber.w(e, "Failed to get AndroidCAStore keystore") return emptyList() } - try { - keyStore.load(null) - } catch (e: Exception) { - Timber.w(e, "Failed to load AndroidCAStore keystore") - return emptyList() - } val aliases = try { + keyStore.load(null) keyStore.aliases() } catch (e: Exception) { - Timber.w(e, "Failed to get aliases from AndroidCAStore keystore") + Timber.w(e, "Failed to load and get aliases AndroidCAStore keystore") return emptyList() } return aliases.toList()