forked from GitHub-Mirror/riotX-android
266 lines
10 KiB
Kotlin
266 lines
10 KiB
Kotlin
/*
|
|
* Copyright 2019 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 im.vector.matrix.android.api.auth.data
|
|
|
|
import android.net.Uri
|
|
import com.squareup.moshi.JsonClass
|
|
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig.Builder
|
|
import im.vector.matrix.android.internal.network.ssl.Fingerprint
|
|
import okhttp3.CipherSuite
|
|
import okhttp3.TlsVersion
|
|
|
|
/**
|
|
* This data class holds how to connect to a specific Homeserver.
|
|
* It's used with [im.vector.matrix.android.api.auth.Authenticator] class.
|
|
* You should use the [Builder] to create one.
|
|
*/
|
|
@JsonClass(generateAdapter = true)
|
|
data class HomeServerConnectionConfig(
|
|
val homeServerUri: Uri,
|
|
val identityServerUri: Uri,
|
|
val antiVirusServerUri: Uri? = null,
|
|
val allowedFingerprints: MutableList<Fingerprint> = ArrayList(),
|
|
val shouldPin: Boolean = false,
|
|
val tlsVersions: MutableList<TlsVersion>? = null,
|
|
val tlsCipherSuites: MutableList<CipherSuite>? = null,
|
|
val shouldAcceptTlsExtensions: Boolean = true,
|
|
val allowHttpExtension: Boolean = false,
|
|
val forceUsageTlsVersions: Boolean = false
|
|
) {
|
|
|
|
/**
|
|
* This builder should be use to create a [HomeServerConnectionConfig] instance.
|
|
*/
|
|
class Builder {
|
|
|
|
private lateinit var homeServerUri: Uri
|
|
private lateinit var identityServerUri: Uri
|
|
private var antiVirusServerUri: Uri? = null
|
|
private val allowedFingerprints: MutableList<Fingerprint> = ArrayList()
|
|
private var shouldPin: Boolean = false
|
|
private val tlsVersions: MutableList<TlsVersion> = ArrayList()
|
|
private val tlsCipherSuites: MutableList<CipherSuite> = ArrayList()
|
|
private var shouldAcceptTlsExtensions: Boolean = true
|
|
private var allowHttpExtension: Boolean = false
|
|
private var forceUsageTlsVersions: Boolean = false
|
|
|
|
fun withHomeServerUri(hsUriString: String): Builder {
|
|
return withHomeServerUri(Uri.parse(hsUriString))
|
|
}
|
|
|
|
/**
|
|
* @param hsUri The URI to use to connect to the homeserver.
|
|
* @return this builder
|
|
*/
|
|
fun withHomeServerUri(hsUri: Uri): Builder {
|
|
if (hsUri.scheme != "http" && hsUri.scheme != "https") {
|
|
throw RuntimeException("Invalid home server URI: " + hsUri)
|
|
}
|
|
// ensure trailing /
|
|
homeServerUri = if (!hsUri.toString().endsWith("/")) {
|
|
try {
|
|
val url = hsUri.toString()
|
|
Uri.parse("$url/")
|
|
} catch (e: Exception) {
|
|
throw RuntimeException("Invalid home server URI: $hsUri")
|
|
}
|
|
} else {
|
|
hsUri
|
|
}
|
|
return this
|
|
}
|
|
|
|
fun withIdentityServerUri(identityServerUriString: String): Builder {
|
|
return withIdentityServerUri(Uri.parse(identityServerUriString))
|
|
}
|
|
|
|
/**
|
|
* @param identityServerUri The URI to use to manage identity.
|
|
* @return this builder
|
|
*/
|
|
fun withIdentityServerUri(identityServerUri: Uri): Builder {
|
|
if (identityServerUri.scheme != "http" && identityServerUri.scheme != "https") {
|
|
throw RuntimeException("Invalid identity server URI: $identityServerUri")
|
|
}
|
|
// ensure trailing /
|
|
if (!identityServerUri.toString().endsWith("/")) {
|
|
try {
|
|
val url = identityServerUri.toString()
|
|
this.identityServerUri = Uri.parse("$url/")
|
|
} catch (e: Exception) {
|
|
throw RuntimeException("Invalid identity server URI: $identityServerUri")
|
|
}
|
|
} else {
|
|
this.identityServerUri = identityServerUri
|
|
}
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* @param allowedFingerprints If using SSL, allow server certs that match these fingerprints.
|
|
* @return this builder
|
|
*/
|
|
fun withAllowedFingerPrints(allowedFingerprints: List<Fingerprint>?): Builder {
|
|
if (allowedFingerprints != null) {
|
|
this.allowedFingerprints.addAll(allowedFingerprints)
|
|
}
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* @param pin If true only allow certs matching given fingerprints, otherwise fallback to
|
|
* standard X509 checks.
|
|
* @return this builder
|
|
*/
|
|
fun withPin(pin: Boolean): Builder {
|
|
this.shouldPin = pin
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* @param shouldAcceptTlsExtension
|
|
* @return this builder
|
|
*/
|
|
fun withShouldAcceptTlsExtensions(shouldAcceptTlsExtension: Boolean): Builder {
|
|
this.shouldAcceptTlsExtensions = shouldAcceptTlsExtension
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* Add an accepted TLS version for TLS connections with the home server.
|
|
*
|
|
* @param tlsVersion the tls version to add to the set of TLS versions accepted.
|
|
* @return this builder
|
|
*/
|
|
fun addAcceptedTlsVersion(tlsVersion: TlsVersion): Builder {
|
|
this.tlsVersions.add(tlsVersion)
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* Force the usage of TlsVersion. This can be usefull for device on Android version < 20
|
|
*
|
|
* @param forceUsageOfTlsVersions set to true to force the usage of specified TlsVersions (with [.addAcceptedTlsVersion]
|
|
* @return this builder
|
|
*/
|
|
fun forceUsageOfTlsVersions(forceUsageOfTlsVersions: Boolean): Builder {
|
|
this.forceUsageTlsVersions = forceUsageOfTlsVersions
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* Add a TLS cipher suite to the list of accepted TLS connections with the home server.
|
|
*
|
|
* @param tlsCipherSuite the tls cipher suite to add.
|
|
* @return this builder
|
|
*/
|
|
fun addAcceptedTlsCipherSuite(tlsCipherSuite: CipherSuite): Builder {
|
|
this.tlsCipherSuites.add(tlsCipherSuite)
|
|
return this
|
|
}
|
|
|
|
fun withAntiVirusServerUri(antivirusServerUriString: String?): Builder {
|
|
return withAntiVirusServerUri(antivirusServerUriString?.let { Uri.parse(it) })
|
|
}
|
|
|
|
/**
|
|
* Update the anti-virus server URI.
|
|
*
|
|
* @param antivirusServerUri the new anti-virus uri. Can be null
|
|
* @return this builder
|
|
*/
|
|
fun withAntiVirusServerUri(antivirusServerUri: Uri?): Builder {
|
|
if (null != antivirusServerUri && "http" != antivirusServerUri.scheme && "https" != antivirusServerUri.scheme) {
|
|
throw RuntimeException("Invalid antivirus server URI: $antivirusServerUri")
|
|
}
|
|
this.antiVirusServerUri = antivirusServerUri
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* Convenient method to limit the TLS versions and cipher suites for this Builder
|
|
* Ref:
|
|
* - https://www.ssi.gouv.fr/uploads/2017/02/security-recommendations-for-tls_v1.1.pdf
|
|
* - https://developer.android.com/reference/javax/net/ssl/SSLEngine
|
|
*
|
|
* @param tlsLimitations true to use Tls limitations
|
|
* @param enableCompatibilityMode set to true for Android < 20
|
|
* @return this builder
|
|
*/
|
|
fun withTlsLimitations(tlsLimitations: Boolean, enableCompatibilityMode: Boolean): Builder {
|
|
if (tlsLimitations) {
|
|
withShouldAcceptTlsExtensions(false)
|
|
|
|
// Tls versions
|
|
addAcceptedTlsVersion(TlsVersion.TLS_1_2)
|
|
addAcceptedTlsVersion(TlsVersion.TLS_1_3)
|
|
|
|
forceUsageOfTlsVersions(enableCompatibilityMode)
|
|
|
|
// Cipher suites
|
|
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
|
|
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256)
|
|
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
|
|
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256)
|
|
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
|
|
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384)
|
|
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256)
|
|
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256)
|
|
|
|
if (enableCompatibilityMode) {
|
|
// Adopt some preceding cipher suites for Android < 20 to be able to negotiate
|
|
// a TLS session.
|
|
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
|
|
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA)
|
|
}
|
|
}
|
|
return this
|
|
}
|
|
|
|
fun withAllowHttpConnection(allowHttpExtension: Boolean): Builder {
|
|
this.allowHttpExtension = allowHttpExtension
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* @return the [HomeServerConnectionConfig]
|
|
*/
|
|
fun build(): HomeServerConnectionConfig {
|
|
return HomeServerConnectionConfig(
|
|
homeServerUri,
|
|
identityServerUri,
|
|
antiVirusServerUri,
|
|
allowedFingerprints,
|
|
shouldPin,
|
|
tlsVersions,
|
|
tlsCipherSuites,
|
|
shouldAcceptTlsExtensions,
|
|
allowHttpExtension,
|
|
forceUsageTlsVersions
|
|
)
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|