From 2b490dd4f36525d2850a0fda6c6913db904601d6 Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Mon, 4 Mar 2019 19:25:51 +0100 Subject: [PATCH] upgrade OkHttp, add Conscrypt (#1083) * upgrade OkHttp, add Conscrypt * fix tests --- app/build.gradle | 5 +- .../keylesspalace/tusky/TuskyApplication.java | 10 +++ .../keylesspalace/tusky/util/OkHttpUtils.java | 89 +------------------ .../tusky/FakeTuskyApplication.kt | 4 + 4 files changed, 21 insertions(+), 87 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index a91db177..8d1b9ceb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -94,8 +94,9 @@ dependencies { implementation 'com.squareup.retrofit2:converter-gson:2.5.0' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0' implementation 'com.squareup.picasso:picasso:2.5.2' - implementation 'com.squareup.okhttp3:okhttp:3.12.0' - implementation 'com.squareup.okhttp3:logging-interceptor:3.12.0' + implementation 'com.squareup.okhttp3:okhttp:3.13.1' + implementation 'com.squareup.okhttp3:logging-interceptor:3.13.1' + implementation "org.conscrypt:conscrypt-android:2.0.0" implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0' implementation 'com.github.connyduck:sparkbutton:2.0.0' implementation 'com.github.chrisbanes:PhotoView:2.3.0' diff --git a/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java b/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java index a7302101..ce3dde8d 100644 --- a/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java +++ b/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java @@ -32,6 +32,10 @@ import com.keylesspalace.tusky.util.EmojiCompatFont; import com.keylesspalace.tusky.util.NotificationPullJobCreator; import com.squareup.picasso.Picasso; +import org.conscrypt.Conscrypt; + +import java.security.Security; + import javax.inject.Inject; import dagger.android.AndroidInjector; @@ -62,6 +66,8 @@ public class TuskyApplication extends Application implements HasActivityInjector public void onCreate() { super.onCreate(); + initSecurityProvider(); + appDatabase = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "tuskyDB") .allowMainThreadQueries() .addMigrations(AppDatabase.MIGRATION_2_3, AppDatabase.MIGRATION_3_4, AppDatabase.MIGRATION_4_5, @@ -93,6 +99,10 @@ public class TuskyApplication extends Application implements HasActivityInjector } + protected void initSecurityProvider() { + Security.insertProviderAt(Conscrypt.newProvider(), 1); + } + /** * This method will load the EmojiCompat font which has been selected. * If this font does not work or if the user hasn't selected one (yet), it will use a diff --git a/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java index e9c34254..7647c2c8 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java +++ b/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java @@ -19,49 +19,21 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.Build; import android.preference.PreferenceManager; -import androidx.annotation.NonNull; -import android.util.Log; import com.keylesspalace.tusky.BuildConfig; import java.net.InetSocketAddress; import java.net.Proxy; -import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import java.util.concurrent.TimeUnit; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - +import androidx.annotation.NonNull; import okhttp3.Cache; -import okhttp3.ConnectionSpec; import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; public class OkHttpUtils { - private static final String TAG = "OkHttpUtils"; // logging tag - /** - * Makes a Builder with the maximum range of TLS versions and cipher suites enabled. - *

- * It first tries the "approved" list of cipher suites given in OkHttp (the default in - * ConnectionSpec.MODERN_TLS) and if that doesn't work falls back to the set of ALL enabled, - * then falls back to plain http. - *

- * API level 24 has a regression in elliptic curves where it only supports secp256r1, so this - * first tries a fallback without elliptic curves at all, and then tries them after. - *

- * TLS 1.1 and 1.2 have to be manually enabled on API levels 16-20. - */ @NonNull public static OkHttpClient.Builder getCompatibleClientBuilder(@NonNull Context context) { @@ -77,25 +49,13 @@ public class OkHttpUtils { httpPort = -1; } - ConnectionSpec fallback = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) - .allEnabledCipherSuites() - .supportsTlsExtensions(true) - .build(); - - List specList = new ArrayList<>(); - specList.add(ConnectionSpec.MODERN_TLS); - addNougatFixConnectionSpec(specList); - specList.add(fallback); - specList.add(ConnectionSpec.CLEARTEXT); - int cacheSize = 25*1024*1024; // 25 MiB OkHttpClient.Builder builder = new OkHttpClient.Builder() .addInterceptor(getUserAgentInterceptor()) .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) - .cache(new Cache(context.getCacheDir(), cacheSize)) - .connectionSpecs(specList); + .cache(new Cache(context.getCacheDir(), cacheSize)); if (httpProxyEnabled && !httpServer.isEmpty() && (httpPort > 0) && (httpPort < 65535)) { InetSocketAddress address = InetSocketAddress.createUnresolved(httpServer, httpPort); @@ -121,47 +81,6 @@ public class OkHttpUtils { }; } - /** - * Android version Nougat has a regression where elliptic curve cipher suites are supported, but - * only the curve secp256r1 is allowed. So, first it's best to just disable all elliptic - * ciphers, try the connection, and fall back to the all cipher suites enabled list after. - */ - private static void addNougatFixConnectionSpec(List specList) { - if (Build.VERSION.SDK_INT != Build.VERSION_CODES.N) { - return; - } - SSLSocketFactory socketFactory; - try { - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( - TrustManagerFactory.getDefaultAlgorithm()); - trustManagerFactory.init((KeyStore) null); - TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); - if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) { - throw new IllegalStateException("Unexpected default trust managers:" - + Arrays.toString(trustManagers)); - } - - X509TrustManager trustManager = (X509TrustManager) trustManagers[0]; - - SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, new TrustManager[] { trustManager }, null); - socketFactory = sslContext.getSocketFactory(); - } catch (NoSuchAlgorithmException|KeyStoreException|KeyManagementException e) { - Log.e(TAG, "Failed obtaining the SSL socket factory."); - return; - } - String[] cipherSuites = socketFactory.getDefaultCipherSuites(); - ArrayList allowedList = new ArrayList<>(); - for (String suite : cipherSuites) { - if (!suite.contains("ECDH")) { - allowedList.add(suite); - } - } - ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) - .cipherSuites(allowedList.toArray(new String[0])) - .supportsTlsExtensions(true) - .build(); - specList.add(spec); - } - } + + diff --git a/app/src/test/java/com/keylesspalace/tusky/FakeTuskyApplication.kt b/app/src/test/java/com/keylesspalace/tusky/FakeTuskyApplication.kt index 217a1520..6337228a 100644 --- a/app/src/test/java/com/keylesspalace/tusky/FakeTuskyApplication.kt +++ b/app/src/test/java/com/keylesspalace/tusky/FakeTuskyApplication.kt @@ -8,6 +8,10 @@ class FakeTuskyApplication : TuskyApplication() { lateinit var locator: ServiceLocator + override fun initSecurityProvider() { + // No-op + } + override fun initAppInjector() { // No-op }