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
@@ -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);
+ }
+
}
@@ -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());
}
@@ -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()