This commit is contained in:
Mario Danic 2019-12-26 03:39:17 +01:00
parent aaecb294f5
commit 9f296996ab
No known key found for this signature in database
GPG Key ID: CDE0BBD2738C4CC0
2 changed files with 20 additions and 190 deletions

View File

@ -22,6 +22,7 @@ package com.nextcloud.talk.newarch.di.module
import android.app.Application
import android.content.Context
import android.os.Build
import android.text.TextUtils
import android.util.Log
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.ssl.MagicKeyManager
import com.nextcloud.talk.utils.ssl.MagicTrustManager
import com.nextcloud.talk.utils.ssl.SSLSocketFactoryCompat
import io.reactivex.schedulers.Schedulers
import okhttp3.*
import okhttp3.internal.tls.OkHostnameVerifier
@ -59,13 +59,13 @@ import java.io.IOException
import java.net.CookieManager
import java.net.CookiePolicy.ACCEPT_ALL
import java.net.Proxy
import java.security.KeyStore
import java.security.KeyStoreException
import java.security.NoSuchAlgorithmException
import java.security.UnrecoverableKeyException
import java.security.*
import java.security.cert.CertificateException
import java.util.*
import java.util.concurrent.TimeUnit
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.X509KeyManager
val NetworkModule = module {
@ -97,7 +97,7 @@ fun createOkHttpClient(
proxy: Proxy,
appPreferences: AppPreferences,
magicTrustManager: MagicTrustManager,
sslSocketFactoryCompat: SSLSocketFactoryCompat,
sslSocketFactory: SSLSocketFactory,
cache: Cache,
cookieManager: CookieManager,
dispatcher: Dispatcher
@ -113,10 +113,16 @@ fun createOkHttpClient(
httpClient.cache(cache)
// Trust own CA and all self-signed certs
httpClient.sslSocketFactory(sslSocketFactoryCompat, magicTrustManager)
httpClient.sslSocketFactory(sslSocketFactory, magicTrustManager)
httpClient.retryOnConnectionFailure(true)
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)
if (Proxy.NO_PROXY != proxy) {
httpClient.proxy(proxy)
@ -181,8 +187,13 @@ fun createSslSocketFactory(
magicKeyManager: MagicKeyManager,
magicTrustManager:
MagicTrustManager
): SSLSocketFactoryCompat {
return SSLSocketFactoryCompat(magicKeyManager, magicTrustManager)
): SSLSocketFactory {
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(
arrayOf(magicKeyManager),
arrayOf(magicTrustManager),
SecureRandom())
return sslContext.socketFactory
}
fun createKeyManager(

View File

@ -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 }
}
}