Merge pull request #2392 from poljar/poljar/user-certs
Add the user certificates as additional certificates to the ClientBuilder
This commit is contained in:
1
changelog.d/2992.feature
Normal file
1
changelog.d/2992.feature
Normal file
@@ -0,0 +1 @@
|
||||
Allow user-installed certificates to be used by the HTTP client
|
||||
@@ -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<ByteArray> {
|
||||
val certs = mutableListOf<ByteArray>()
|
||||
|
||||
// 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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user