From 9f296996abb465fd223ae089230d64c5369420a2 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Thu, 26 Dec 2019 03:39:17 +0100 Subject: [PATCH] Fix #672 --- .../talk/newarch/di/module/NetworkModule.kt | 29 ++- .../talk/utils/ssl/SSLSocketFactoryCompat.kt | 181 ------------------ 2 files changed, 20 insertions(+), 190 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/talk/utils/ssl/SSLSocketFactoryCompat.kt diff --git a/app/src/main/java/com/nextcloud/talk/newarch/di/module/NetworkModule.kt b/app/src/main/java/com/nextcloud/talk/newarch/di/module/NetworkModule.kt index 0f76f1687..557c98a47 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/di/module/NetworkModule.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/di/module/NetworkModule.kt @@ -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( diff --git a/app/src/main/java/com/nextcloud/talk/utils/ssl/SSLSocketFactoryCompat.kt b/app/src/main/java/com/nextcloud/talk/utils/ssl/SSLSocketFactoryCompat.kt deleted file mode 100644 index 2f4875145..000000000 --- a/app/src/main/java/com/nextcloud/talk/utils/ssl/SSLSocketFactoryCompat.kt +++ /dev/null @@ -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? = null - var cipherSuites: Array? = 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() - for (protocol in socket.supportedProtocols.filterNot { it.contains("SSL", true) }) - _protocols += protocol - protocols = _protocols.toTypedArray() - - /* set up reasonable cipher suites */ - val knownCiphers = arrayOf( - // 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() - _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? = cipherSuites - ?: delegate.defaultCipherSuites - - override fun getSupportedCipherSuites(): Array? = 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 } - } - -}