mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-15 00:35:04 +01:00
Fix #672
This commit is contained in:
parent
aaecb294f5
commit
9f296996ab
@ -22,6 +22,7 @@ package com.nextcloud.talk.newarch.di.module
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
@ -44,7 +45,6 @@ import com.nextcloud.talk.utils.LoggingUtils
|
|||||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||||
import com.nextcloud.talk.utils.ssl.MagicKeyManager
|
import com.nextcloud.talk.utils.ssl.MagicKeyManager
|
||||||
import com.nextcloud.talk.utils.ssl.MagicTrustManager
|
import com.nextcloud.talk.utils.ssl.MagicTrustManager
|
||||||
import com.nextcloud.talk.utils.ssl.SSLSocketFactoryCompat
|
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
import okhttp3.*
|
import okhttp3.*
|
||||||
import okhttp3.internal.tls.OkHostnameVerifier
|
import okhttp3.internal.tls.OkHostnameVerifier
|
||||||
@ -59,13 +59,13 @@ import java.io.IOException
|
|||||||
import java.net.CookieManager
|
import java.net.CookieManager
|
||||||
import java.net.CookiePolicy.ACCEPT_ALL
|
import java.net.CookiePolicy.ACCEPT_ALL
|
||||||
import java.net.Proxy
|
import java.net.Proxy
|
||||||
import java.security.KeyStore
|
import java.security.*
|
||||||
import java.security.KeyStoreException
|
|
||||||
import java.security.NoSuchAlgorithmException
|
|
||||||
import java.security.UnrecoverableKeyException
|
|
||||||
import java.security.cert.CertificateException
|
import java.security.cert.CertificateException
|
||||||
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.net.ssl.KeyManagerFactory
|
import javax.net.ssl.KeyManagerFactory
|
||||||
|
import javax.net.ssl.SSLContext
|
||||||
|
import javax.net.ssl.SSLSocketFactory
|
||||||
import javax.net.ssl.X509KeyManager
|
import javax.net.ssl.X509KeyManager
|
||||||
|
|
||||||
val NetworkModule = module {
|
val NetworkModule = module {
|
||||||
@ -97,7 +97,7 @@ fun createOkHttpClient(
|
|||||||
proxy: Proxy,
|
proxy: Proxy,
|
||||||
appPreferences: AppPreferences,
|
appPreferences: AppPreferences,
|
||||||
magicTrustManager: MagicTrustManager,
|
magicTrustManager: MagicTrustManager,
|
||||||
sslSocketFactoryCompat: SSLSocketFactoryCompat,
|
sslSocketFactory: SSLSocketFactory,
|
||||||
cache: Cache,
|
cache: Cache,
|
||||||
cookieManager: CookieManager,
|
cookieManager: CookieManager,
|
||||||
dispatcher: Dispatcher
|
dispatcher: Dispatcher
|
||||||
@ -113,10 +113,16 @@ fun createOkHttpClient(
|
|||||||
httpClient.cache(cache)
|
httpClient.cache(cache)
|
||||||
|
|
||||||
// Trust own CA and all self-signed certs
|
// Trust own CA and all self-signed certs
|
||||||
httpClient.sslSocketFactory(sslSocketFactoryCompat, magicTrustManager)
|
httpClient.sslSocketFactory(sslSocketFactory, magicTrustManager)
|
||||||
httpClient.retryOnConnectionFailure(true)
|
httpClient.retryOnConnectionFailure(true)
|
||||||
httpClient.hostnameVerifier(magicTrustManager.getHostnameVerifier(OkHostnameVerifier.INSTANCE))
|
httpClient.hostnameVerifier(magicTrustManager.getHostnameVerifier(OkHostnameVerifier.INSTANCE))
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N) {
|
||||||
|
val suites = sslSocketFactory.defaultCipherSuites
|
||||||
|
val tlsSpec = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS).cipherSuites(*suites).build()
|
||||||
|
httpClient.connectionSpecs(listOf(tlsSpec, ConnectionSpec.CLEARTEXT))
|
||||||
|
}
|
||||||
|
|
||||||
httpClient.dispatcher(dispatcher)
|
httpClient.dispatcher(dispatcher)
|
||||||
if (Proxy.NO_PROXY != proxy) {
|
if (Proxy.NO_PROXY != proxy) {
|
||||||
httpClient.proxy(proxy)
|
httpClient.proxy(proxy)
|
||||||
@ -181,8 +187,13 @@ fun createSslSocketFactory(
|
|||||||
magicKeyManager: MagicKeyManager,
|
magicKeyManager: MagicKeyManager,
|
||||||
magicTrustManager:
|
magicTrustManager:
|
||||||
MagicTrustManager
|
MagicTrustManager
|
||||||
): SSLSocketFactoryCompat {
|
): SSLSocketFactory {
|
||||||
return SSLSocketFactoryCompat(magicKeyManager, magicTrustManager)
|
val sslContext = SSLContext.getInstance("TLS")
|
||||||
|
sslContext.init(
|
||||||
|
arrayOf(magicKeyManager),
|
||||||
|
arrayOf(magicTrustManager),
|
||||||
|
SecureRandom())
|
||||||
|
return sslContext.socketFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createKeyManager(
|
fun createKeyManager(
|
||||||
|
@ -1,181 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © Ricki Hirner (bitfire web engineering).
|
|
||||||
* All rights reserved. This program and the accompanying materials
|
|
||||||
* are made available under the terms of the GNU Public License v3.0
|
|
||||||
* which accompanies this distribution, and is available at
|
|
||||||
* http://www.gnu.org/licenses/gpl.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.nextcloud.talk.utils.ssl
|
|
||||||
|
|
||||||
import android.os.Build
|
|
||||||
import java.io.IOException
|
|
||||||
import java.net.InetAddress
|
|
||||||
import java.net.Socket
|
|
||||||
import java.security.GeneralSecurityException
|
|
||||||
import java.util.*
|
|
||||||
import javax.net.ssl.*
|
|
||||||
|
|
||||||
class SSLSocketFactoryCompat(
|
|
||||||
keyManager: KeyManager?,
|
|
||||||
trustManager: X509TrustManager
|
|
||||||
) : SSLSocketFactory() {
|
|
||||||
|
|
||||||
private var delegate: SSLSocketFactory
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
// Android 5.0+ (API level 21) provides reasonable default settings
|
|
||||||
// but it still allows SSLv3
|
|
||||||
// https://developer.android.com/reference/javax/net/ssl/SSLSocket.html
|
|
||||||
var protocols: Array<String>? = null
|
|
||||||
var cipherSuites: Array<String>? = null
|
|
||||||
|
|
||||||
init {
|
|
||||||
if (Build.VERSION.SDK_INT >= 23) {
|
|
||||||
// Since Android 6.0 (API level 23),
|
|
||||||
// - TLSv1.1 and TLSv1.2 is enabled by default
|
|
||||||
// - SSLv3 is disabled by default
|
|
||||||
// - all modern ciphers are activated by default
|
|
||||||
protocols = null
|
|
||||||
cipherSuites = null
|
|
||||||
} else {
|
|
||||||
val socket = SSLSocketFactory.getDefault().createSocket() as SSLSocket?
|
|
||||||
try {
|
|
||||||
socket?.let {
|
|
||||||
/* set reasonable protocol versions */
|
|
||||||
// - enable all supported protocols (enables TLSv1.1 and TLSv1.2 on Android <5.0)
|
|
||||||
// - remove all SSL versions (especially SSLv3) because they're insecure now
|
|
||||||
val _protocols = LinkedList<String>()
|
|
||||||
for (protocol in socket.supportedProtocols.filterNot { it.contains("SSL", true) })
|
|
||||||
_protocols += protocol
|
|
||||||
protocols = _protocols.toTypedArray()
|
|
||||||
|
|
||||||
/* set up reasonable cipher suites */
|
|
||||||
val knownCiphers = arrayOf<String>(
|
|
||||||
// TLS 1.2
|
|
||||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
|
||||||
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
// maximum interoperability
|
|
||||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
|
||||||
"SSL_RSA_WITH_3DES_EDE_CBC_SHA",
|
|
||||||
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
|
||||||
// additionally
|
|
||||||
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
|
||||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"
|
|
||||||
)
|
|
||||||
val availableCiphers = socket.supportedCipherSuites
|
|
||||||
|
|
||||||
/* For maximum security, preferredCiphers should *replace* enabled ciphers (thus
|
|
||||||
* disabling ciphers which are enabled by default, but have become unsecure), but for
|
|
||||||
* the security level of DAVdroid and maximum compatibility, disabling of insecure
|
|
||||||
* ciphers should be a server-side task */
|
|
||||||
|
|
||||||
// for the final set of enabled ciphers, take the ciphers enabled by default, ...
|
|
||||||
val _cipherSuites = LinkedList<String>()
|
|
||||||
_cipherSuites.addAll(socket.enabledCipherSuites)
|
|
||||||
// ... add explicitly allowed ciphers ...
|
|
||||||
_cipherSuites.addAll(knownCiphers)
|
|
||||||
// ... and keep only those which are actually available
|
|
||||||
_cipherSuites.retainAll(availableCiphers)
|
|
||||||
|
|
||||||
cipherSuites = _cipherSuites.toTypedArray()
|
|
||||||
}
|
|
||||||
} catch (e: IOException) {
|
|
||||||
// Exception is to be ignored
|
|
||||||
} finally {
|
|
||||||
socket?.close() // doesn't implement Closeable on all supported Android versions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
try {
|
|
||||||
val sslContext = SSLContext.getInstance("TLS")
|
|
||||||
sslContext.init(
|
|
||||||
if (keyManager != null) arrayOf(keyManager) else null,
|
|
||||||
arrayOf(trustManager),
|
|
||||||
null
|
|
||||||
)
|
|
||||||
delegate = sslContext.socketFactory
|
|
||||||
} catch (e: GeneralSecurityException) {
|
|
||||||
throw IllegalStateException() // system has no TLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getDefaultCipherSuites(): Array<String>? = cipherSuites
|
|
||||||
?: delegate.defaultCipherSuites
|
|
||||||
|
|
||||||
override fun getSupportedCipherSuites(): Array<String>? = cipherSuites
|
|
||||||
?: delegate.supportedCipherSuites
|
|
||||||
|
|
||||||
override fun createSocket(
|
|
||||||
s: Socket,
|
|
||||||
host: String,
|
|
||||||
port: Int,
|
|
||||||
autoClose: Boolean
|
|
||||||
): Socket {
|
|
||||||
val ssl = delegate.createSocket(s, host, port, autoClose)
|
|
||||||
if (ssl is SSLSocket)
|
|
||||||
upgradeTLS(ssl)
|
|
||||||
return ssl
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createSocket(
|
|
||||||
host: String,
|
|
||||||
port: Int
|
|
||||||
): Socket {
|
|
||||||
val ssl = delegate.createSocket(host, port)
|
|
||||||
if (ssl is SSLSocket)
|
|
||||||
upgradeTLS(ssl)
|
|
||||||
return ssl
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createSocket(
|
|
||||||
host: String,
|
|
||||||
port: Int,
|
|
||||||
localHost: InetAddress,
|
|
||||||
localPort: Int
|
|
||||||
): Socket {
|
|
||||||
val ssl = delegate.createSocket(host, port, localHost, localPort)
|
|
||||||
if (ssl is SSLSocket)
|
|
||||||
upgradeTLS(ssl)
|
|
||||||
return ssl
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createSocket(
|
|
||||||
host: InetAddress,
|
|
||||||
port: Int
|
|
||||||
): Socket {
|
|
||||||
val ssl = delegate.createSocket(host, port)
|
|
||||||
if (ssl is SSLSocket)
|
|
||||||
upgradeTLS(ssl)
|
|
||||||
return ssl
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createSocket(
|
|
||||||
address: InetAddress,
|
|
||||||
port: Int,
|
|
||||||
localAddress: InetAddress,
|
|
||||||
localPort: Int
|
|
||||||
): Socket {
|
|
||||||
val ssl = delegate.createSocket(address, port, localAddress, localPort)
|
|
||||||
if (ssl is SSLSocket)
|
|
||||||
upgradeTLS(ssl)
|
|
||||||
return ssl
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun upgradeTLS(ssl: SSLSocket) {
|
|
||||||
protocols?.let { ssl.enabledProtocols = it }
|
|
||||||
cipherSuites?.let { ssl.enabledCipherSuites = it }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user