Channel discovery service / okttp needs bundled letsencrypt too

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/crypto/TrustManagers.java             | 17 
src/main/java/eu/siacs/conversations/services/ChannelDiscoveryService.java | 52 
src/main/java/eu/siacs/conversations/services/MemorizingTrustManager.java  | 13 
3 files changed, 60 insertions(+), 22 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/crypto/TrustManagers.java 🔗

@@ -1,17 +1,23 @@
 package eu.siacs.conversations.crypto;
 
+import android.content.Context;
+
 import androidx.annotation.Nullable;
 
 import com.google.common.collect.Iterables;
 
+import java.io.IOException;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
 import java.util.Arrays;
 
 import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
+import eu.siacs.conversations.R;
+
 public final class TrustManagers {
 
     private TrustManagers() {
@@ -34,5 +40,16 @@ public final class TrustManagers {
         return createTrustManager(null);
     }
 
+    public static X509TrustManager defaultWithBundledLetsEncrypt(final Context context)
+            throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
+        final BundledTrustManager bundleTrustManager =
+                BundledTrustManager.builder()
+                        .loadKeyStore(
+                                context.getResources().openRawResource(R.raw.letsencrypt),
+                                "letsencrypt")
+                        .build();
+        return CombiningTrustManager.combineWithDefault(bundleTrustManager);
+    }
+
 
 }

src/main/java/eu/siacs/conversations/services/ChannelDiscoveryService.java 🔗

@@ -1,5 +1,8 @@
 package eu.siacs.conversations.services;
 
+import static eu.siacs.conversations.utils.Random.SECURE_RANDOM;
+
+import android.os.Build;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
@@ -8,34 +11,45 @@ import com.google.common.base.Strings;
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
 import eu.siacs.conversations.Config;
+import eu.siacs.conversations.crypto.TrustManagers;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.Room;
 import eu.siacs.conversations.http.HttpConnectionManager;
 import eu.siacs.conversations.http.services.MuclumbusService;
 import eu.siacs.conversations.parser.IqParser;
+import eu.siacs.conversations.utils.TLSSocketFactory;
 import eu.siacs.conversations.xmpp.Jid;
 import eu.siacs.conversations.xmpp.OnIqPacketReceived;
 import eu.siacs.conversations.xmpp.XmppConnection;
 import eu.siacs.conversations.xmpp.stanzas.IqPacket;
+
 import okhttp3.OkHttpClient;
 import okhttp3.ResponseBody;
+
 import retrofit2.Call;
 import retrofit2.Callback;
 import retrofit2.Response;
 import retrofit2.Retrofit;
 import retrofit2.converter.gson.GsonConverterFactory;
 
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.X509TrustManager;
+
 public class ChannelDiscoveryService {
 
     private final XmppConnectionService service;
@@ -55,6 +69,24 @@ public class ChannelDiscoveryService {
             return;
         }
         final OkHttpClient.Builder builder = HttpConnectionManager.OK_HTTP_CLIENT.newBuilder();
+        try {
+            final X509TrustManager trustManager;
+            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
+                trustManager = TrustManagers.defaultWithBundledLetsEncrypt(service);
+            } else {
+                trustManager = TrustManagers.createDefaultTrustManager();
+            }
+            final SSLSocketFactory socketFactory =
+                    new TLSSocketFactory(new X509TrustManager[] {trustManager}, SECURE_RANDOM);
+            builder.sslSocketFactory(socketFactory, trustManager);
+        } catch (final IOException
+                | KeyManagementException
+                | NoSuchAlgorithmException
+                | KeyStoreException
+                | CertificateException e) {
+            Log.d(Config.LOGTAG, "not reconfiguring service to work with bundled LetsEncrypt");
+            throw new RuntimeException(e);
+        }
         if (service.useTorToConnect()) {
             builder.proxy(HttpConnectionManager.getProxy());
         }

src/main/java/eu/siacs/conversations/services/MemorizingTrustManager.java 🔗

@@ -176,7 +176,7 @@ public class MemorizingTrustManager {
         this.appTrustManager = getTrustManager(appKeyStore);
         try {
             if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
-                this.defaultTrustManager = defaultWithBundledLetsEncrypt(context);
+                this.defaultTrustManager = TrustManagers.defaultWithBundledLetsEncrypt(context);
             } else {
                 this.defaultTrustManager = TrustManagers.createDefaultTrustManager();
             }
@@ -188,17 +188,6 @@ public class MemorizingTrustManager {
         }
     }
 
-    private static X509TrustManager defaultWithBundledLetsEncrypt(final Context context)
-            throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
-        final BundledTrustManager bundleTrustManager =
-                BundledTrustManager.builder()
-                        .loadKeyStore(
-                                context.getResources().openRawResource(R.raw.letsencrypt),
-                                "letsencrypt")
-                        .build();
-        return CombiningTrustManager.combineWithDefault(bundleTrustManager);
-    }
-
     private static boolean isIp(final String server) {
         return server != null
                 && (PATTERN_IPV4.matcher(server).matches()