Loading app/src/main/java/net/fabiszewski/ulogger/TlsSocketFactory.java 0 → 100644 +113 −0 Original line number Diff line number Diff line /* * Copyright (c) 2020 Bartek Fabiszewski * http://www.fabiszewski.net * * This file is part of μlogger-android. * Licensed under GPL, either version 3, or any later. * See <http://www.gnu.org/licenses/> */ package net.fabiszewski.ulogger; import android.annotation.TargetApi; import android.os.Build; import android.util.Log; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; /** * This custom ssl socket factory will be used only with APIs 16-22 * to ensure only TLSv1, TLSv1.1, TLSv1.2 are enabled, which is default for later APIs * * Protocol Supported (API Levels) Enabled by default (API Levels) * SSLv3 1–25 1–22 * TLSv1 1+ 1+ * TLSv1.1 16+ 20+ * TLSv1.2 16+ 20+ */ @SuppressWarnings("RedundantThrows") @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1) class TlsSocketFactory extends SSLSocketFactory { private static final String TAG = TlsSocketFactory.class.getSimpleName(); private static SSLSocketFactory factory; TlsSocketFactory() throws NoSuchAlgorithmException, KeyManagementException { SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(null, null, null); factory = sslContext.getSocketFactory(); } @Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { socket = factory.createSocket(socket, host, port, autoClose); if (socket instanceof SSLSocket) { if (Logger.DEBUG) { Log.d(TAG, "[Preparing TLS socket]"); } SSLSocket sslSocket = (SSLSocket) socket; // set default protocols of APIs 22+ sslSocket.setEnabledProtocols(new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" }); if (host != null && !host.isEmpty()) { // set hostname for SNI if (Logger.DEBUG) { Log.d(TAG, "[Setting SNI for host " + host + "]"); } try { sslSocket.getClass().getMethod("setHostname", String.class).invoke(socket, host); } catch (Throwable e) { if (Logger.DEBUG) { Log.d(TAG, "[Setting hostname failed: " + e + "]"); } } } SSLSession session = sslSocket.getSession(); if (!session.isValid()) { if (Logger.DEBUG) { Log.d(TAG, "[Handshake failure]"); } throw new SSLHandshakeException("Handshake failure"); } if (Logger.DEBUG) { Log.d(TAG, "[Connected to " + session.getPeerHost() + " using " + session.getProtocol() + " (" + session.getCipherSuite() + ")]"); } } return socket; } @Override public String[] getDefaultCipherSuites() { throw new UnsupportedOperationException("Not implemented"); } @Override public String[] getSupportedCipherSuites() { throw new UnsupportedOperationException("Not implemented"); } @Override public Socket createSocket(String host, int port) throws IOException { throw new UnsupportedOperationException("Not implemented"); } @Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { throw new UnsupportedOperationException("Not implemented"); } @Override public Socket createSocket(InetAddress host, int port) throws IOException { throw new UnsupportedOperationException("Not implemented"); } @Override public Socket createSocket(InetAddress host, int port, InetAddress localHost, int localPort) throws IOException { throw new UnsupportedOperationException("Not implemented"); } } No newline at end of file app/src/main/java/net/fabiszewski/ulogger/WebHelper.java +16 −1 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.SharedPreferences; import android.net.Uri; import android.os.Build; import android.util.Base64; import android.util.Log; Loading Loading @@ -43,6 +44,8 @@ import java.util.HashMap; import java.util.Map; import java.util.Random; import javax.net.ssl.HttpsURLConnection; import static android.util.Base64.NO_PADDING; import static android.util.Base64.NO_WRAP; import static android.util.Base64.URL_SAFE; Loading Loading @@ -97,8 +100,9 @@ class WebHelper { private final String userAgent; private final Context context; private static boolean tlsSocketInitialized = false; // Socket timeout in milliseconds private static final int SOCKET_TIMEOUT = 30 * 1000; static final int SOCKET_TIMEOUT = 30 * 1000; private static final Random random = new Random(); static boolean isAuthorized = false; Loading @@ -119,6 +123,17 @@ class WebHelper { cookieManager = new CookieManager(); CookieHandler.setDefault(cookieManager); } // On APIs < 20 enable TLSv1.1 and TLSv1.2 protocols, on APIs <= 22 disable SSLv3 if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1 && !tlsSocketInitialized) { try { if (Logger.DEBUG) { Log.d(TAG, "[init TLS socket factory]"); } HttpsURLConnection.setDefaultSSLSocketFactory(new TlsSocketFactory()); tlsSocketInitialized = true; } catch (Exception e) { if (Logger.DEBUG) { Log.d(TAG, "[TLS socket setup error (ignored): " + e.getMessage() + "]"); } } } } /** Loading Loading
app/src/main/java/net/fabiszewski/ulogger/TlsSocketFactory.java 0 → 100644 +113 −0 Original line number Diff line number Diff line /* * Copyright (c) 2020 Bartek Fabiszewski * http://www.fabiszewski.net * * This file is part of μlogger-android. * Licensed under GPL, either version 3, or any later. * See <http://www.gnu.org/licenses/> */ package net.fabiszewski.ulogger; import android.annotation.TargetApi; import android.os.Build; import android.util.Log; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; /** * This custom ssl socket factory will be used only with APIs 16-22 * to ensure only TLSv1, TLSv1.1, TLSv1.2 are enabled, which is default for later APIs * * Protocol Supported (API Levels) Enabled by default (API Levels) * SSLv3 1–25 1–22 * TLSv1 1+ 1+ * TLSv1.1 16+ 20+ * TLSv1.2 16+ 20+ */ @SuppressWarnings("RedundantThrows") @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1) class TlsSocketFactory extends SSLSocketFactory { private static final String TAG = TlsSocketFactory.class.getSimpleName(); private static SSLSocketFactory factory; TlsSocketFactory() throws NoSuchAlgorithmException, KeyManagementException { SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(null, null, null); factory = sslContext.getSocketFactory(); } @Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { socket = factory.createSocket(socket, host, port, autoClose); if (socket instanceof SSLSocket) { if (Logger.DEBUG) { Log.d(TAG, "[Preparing TLS socket]"); } SSLSocket sslSocket = (SSLSocket) socket; // set default protocols of APIs 22+ sslSocket.setEnabledProtocols(new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" }); if (host != null && !host.isEmpty()) { // set hostname for SNI if (Logger.DEBUG) { Log.d(TAG, "[Setting SNI for host " + host + "]"); } try { sslSocket.getClass().getMethod("setHostname", String.class).invoke(socket, host); } catch (Throwable e) { if (Logger.DEBUG) { Log.d(TAG, "[Setting hostname failed: " + e + "]"); } } } SSLSession session = sslSocket.getSession(); if (!session.isValid()) { if (Logger.DEBUG) { Log.d(TAG, "[Handshake failure]"); } throw new SSLHandshakeException("Handshake failure"); } if (Logger.DEBUG) { Log.d(TAG, "[Connected to " + session.getPeerHost() + " using " + session.getProtocol() + " (" + session.getCipherSuite() + ")]"); } } return socket; } @Override public String[] getDefaultCipherSuites() { throw new UnsupportedOperationException("Not implemented"); } @Override public String[] getSupportedCipherSuites() { throw new UnsupportedOperationException("Not implemented"); } @Override public Socket createSocket(String host, int port) throws IOException { throw new UnsupportedOperationException("Not implemented"); } @Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { throw new UnsupportedOperationException("Not implemented"); } @Override public Socket createSocket(InetAddress host, int port) throws IOException { throw new UnsupportedOperationException("Not implemented"); } @Override public Socket createSocket(InetAddress host, int port, InetAddress localHost, int localPort) throws IOException { throw new UnsupportedOperationException("Not implemented"); } } No newline at end of file
app/src/main/java/net/fabiszewski/ulogger/WebHelper.java +16 −1 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.SharedPreferences; import android.net.Uri; import android.os.Build; import android.util.Base64; import android.util.Log; Loading Loading @@ -43,6 +44,8 @@ import java.util.HashMap; import java.util.Map; import java.util.Random; import javax.net.ssl.HttpsURLConnection; import static android.util.Base64.NO_PADDING; import static android.util.Base64.NO_WRAP; import static android.util.Base64.URL_SAFE; Loading Loading @@ -97,8 +100,9 @@ class WebHelper { private final String userAgent; private final Context context; private static boolean tlsSocketInitialized = false; // Socket timeout in milliseconds private static final int SOCKET_TIMEOUT = 30 * 1000; static final int SOCKET_TIMEOUT = 30 * 1000; private static final Random random = new Random(); static boolean isAuthorized = false; Loading @@ -119,6 +123,17 @@ class WebHelper { cookieManager = new CookieManager(); CookieHandler.setDefault(cookieManager); } // On APIs < 20 enable TLSv1.1 and TLSv1.2 protocols, on APIs <= 22 disable SSLv3 if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1 && !tlsSocketInitialized) { try { if (Logger.DEBUG) { Log.d(TAG, "[init TLS socket factory]"); } HttpsURLConnection.setDefaultSSLSocketFactory(new TlsSocketFactory()); tlsSocketInitialized = true; } catch (Exception e) { if (Logger.DEBUG) { Log.d(TAG, "[TLS socket setup error (ignored): " + e.getMessage() + "]"); } } } } /** Loading