Disable SSL as a protocol in HttpsURLConnection
Asked Answered
U

6

16

Due to the POODLE vulnerability, my server, hosted in Amazon AWS does no longer support SSLv3.

As a result, the first HTTPS connection my Android app does against the server results in an error when the connection was being established.

Error reading server response: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x77d8ab68: Failure in SSL library, usually a protocol error
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0x7339ad74:0x00000000)
       [....]
Caused by: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x77d8ab68: Failure in SSL library, usually a protocol error
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0x7339ad74:0x00000000)
       at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:448)
       at com.android.okhttp.Connection.upgradeToTls(Connection.java:146)
       at com.android.okhttp.Connection.connect(Connection.java:107)
       at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:294)
       at com.android.okhttp.internal.http.HttpEngine.sendSocketRequest(HttpEngine.java:255)
       at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:206)

The error happens only in the first request. Subsequent requests work for some time.

To fix this I'm trying to remove SSL from the list of protocols accepted by the Android client, and ensure I'm going only with TLS. To do this, I set a custom SSLSocketFactory which removes SSL from the list of enabled protocols and supported cypher suites.

/**
 * SSLSocketFactory that wraps one existing SSLSocketFactory and delegetes into it adding
 * a new cipher suite
 */
public class TLSOnlySocketFactory extends SSLSocketFactory {

    private final SSLSocketFactory delegate;

    public TLSOnlySocketFactory(SSLSocketFactory delegate) {
        this.delegate = delegate;
    }

    @Override
    public String[] getDefaultCipherSuites() {

        return getPreferredDefaultCipherSuites(this.delegate);
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return getPreferredSupportedCipherSuites(this.delegate);
    }



    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        final Socket socket = this.delegate.createSocket(s, host, port, autoClose);

        ((SSLSocket)socket).setEnabledCipherSuites(getPreferredDefaultCipherSuites(delegate));
        ((SSLSocket)socket).setEnabledProtocols(getEnabledProtocols((SSLSocket)socket));

        return socket;
    }



   [.....]

        ((SSLSocket)socket).setEnabledCipherSuites(getPreferredDefaultCipherSuites(delegate));
        ((SSLSocket) socket).setEnabledProtocols(getEnabledProtocols((SSLSocket)socket));

        return socket;
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        final Socket socket = this.delegate.createSocket(host, port);

        ((SSLSocket)socket).setEnabledCipherSuites(getPreferredDefaultCipherSuites(delegate));
        ((SSLSocket) socket).setEnabledProtocols(getEnabledProtocols((SSLSocket)socket));

        return socket;
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        final Socket socket = this.delegate.createSocket(address, port, localAddress, localPort);

        ((SSLSocket)socket).setEnabledCipherSuites(getPreferredDefaultCipherSuites(delegate));
        ((SSLSocket) socket).setEnabledProtocols(getEnabledProtocols((SSLSocket)socket));

        return socket;
    }

    private String[] getPreferredDefaultCipherSuites(SSLSocketFactory sslSocketFactory) {
        return getCipherSuites(sslSocketFactory.getDefaultCipherSuites());
    }

    private String[] getPreferredSupportedCipherSuites(SSLSocketFactory sslSocketFactory) {
        return getCipherSuites(sslSocketFactory.getSupportedCipherSuites());
    }

    private String[] getCipherSuites(String[] cipherSuites) {
        final ArrayList<String> suitesList = new ArrayList<String>(Arrays.asList(cipherSuites));
        final Iterator<String> iterator = suitesList.iterator();
        while (iterator.hasNext()) {
            final String cipherSuite = iterator.next();
            if (cipherSuite.contains("SSL")) {
                iterator.remove();
            }
        }
        return suitesList.toArray(new String[suitesList.size()]);
    }

    private String[] getEnabledProtocols(SSLSocket socket) {
        final ArrayList<String> protocolList = new ArrayList<String>(Arrays.asList(socket.getSupportedProtocols()));
        final Iterator<String> iterator = protocolList.iterator();
        while (iterator.hasNext()) {
            final String protocl = iterator.next();
            if (protocl.contains("SSL")) {
                iterator.remove();
            }
        }
        return protocolList.toArray(new String[protocolList.size()]);
     }

}

As you see, my SSLSocketFactory delegates into another SSLSocketFactory and what it does is simply removing SSL from the list of enabled protocols.

I establish this factory as

final TLSOnlySocketFactory tlsOnlySocketFactory = new TLSOnlySocketFactory(HttpsURLConnection.getDefaultSSLSocketFactory());
HttpsURLConnection.setDefaultSSLSocketFactory(tlsOnlySocketFactory);

This does NOT fix the issue. From time to time, I still see the error when the connection was established. Oddly enough, this does not fix it, but it clearly minimises the occurrences of the issue.

How could I force the HttpsUrlConnection in my Android client to use only TLS?

Thank you.

Umberto answered 29/10, 2014 at 14:44 Comment(6)
You're solving the wrong problem. You don't have to do this. Your problem lies elsewhere.Shetrit
If this is not the right way, how should I make sure my HttpsUrlConnection uses TLS only?Umberto
Hi, I'm stuck in this problem too. Did you find a way to solve this? I need to solve it globally too, because I'm using some jars that are afected tooBarring
@EJP Do you have an idea of how to solve the problem? If so, give us some hints :DBarring
I have not managed to fix it. I'm quite stuck. The work arounds I've found so far are: 1. Use Apache Http Client instead of HttpURLConnection (which sucks). 2. Use HttpURLConnection, and when I catch the IOException that has SSLHandshakeException as cause, retry the request silently (which also sucks).Umberto
Any update on this from anyone? I'm still doing the retry hack, and I'd like to really solve it...Umberto
U
18

I think I have solved this. The fundamental idea is the same than in the code in the question (avoid SSLv3 as the only protocol available), but the code performing it is different:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

    /**
     * {@link javax.net.ssl.SSLSocketFactory} that doesn't allow {@code SSLv3} only connections
     * <p>fixes https://github.com/koush/ion/issues/386</p>
     *
     * <p> see https://code.google.com/p/android/issues/detail?id=78187 </p>
     */
    public class NoSSLv3Factory extends SSLSocketFactory {
        private final SSLSocketFactory delegate;

        public NoSSLv3Factory() {
            this.delegate = HttpsURLConnection.getDefaultSSLSocketFactory();
        }

        @Override
        public String[] getDefaultCipherSuites() {
            return delegate.getDefaultCipherSuites();
        }

        @Override
        public String[] getSupportedCipherSuites() {
            return delegate.getSupportedCipherSuites();
        }

        private static Socket makeSocketSafe(Socket socket) {
            if (socket instanceof SSLSocket) {
                socket = new NoSSLv3SSLSocket((SSLSocket) socket);
            }
            return socket;
        }

        @Override
        public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
            return makeSocketSafe(delegate.createSocket(s, host, port, autoClose));
        }

        @Override
        public Socket createSocket(String host, int port) throws IOException {
            return makeSocketSafe(delegate.createSocket(host, port));
        }

        @Override
        public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
            return makeSocketSafe(delegate.createSocket(host, port, localHost, localPort));
        }

        @Override
        public Socket createSocket(InetAddress host, int port) throws IOException {
            return makeSocketSafe(delegate.createSocket(host, port));
        }

        @Override
        public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
            return makeSocketSafe(delegate.createSocket(address, port, localAddress, localPort));
        }

        /**
         * Created by robUx4 on 25/10/2014.
         */
        private static class DelegateSSLSocket extends SSLSocket {

            protected final SSLSocket delegate;

            DelegateSSLSocket(SSLSocket delegate) {
                this.delegate = delegate;
            }

            @Override
            public String[] getSupportedCipherSuites() {
                return delegate.getSupportedCipherSuites();
            }

            @Override
            public String[] getEnabledCipherSuites() {
                return delegate.getEnabledCipherSuites();
            }

            @Override
            public void setEnabledCipherSuites(String[] suites) {
                delegate.setEnabledCipherSuites(suites);
            }

            @Override
            public String[] getSupportedProtocols() {
                return delegate.getSupportedProtocols();
            }

            @Override
            public String[] getEnabledProtocols() {
                return delegate.getEnabledProtocols();
            }

            @Override
            public void setEnabledProtocols(String[] protocols) {
                delegate.setEnabledProtocols(protocols);
            }

            @Override
            public SSLSession getSession() {
                return delegate.getSession();
            }

            @Override
            public void addHandshakeCompletedListener(HandshakeCompletedListener listener) {
                delegate.addHandshakeCompletedListener(listener);
            }

            @Override
            public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) {
                delegate.removeHandshakeCompletedListener(listener);
            }

            @Override
            public void startHandshake() throws IOException {
                delegate.startHandshake();
            }

            @Override
            public void setUseClientMode(boolean mode) {
                delegate.setUseClientMode(mode);
            }

            @Override
            public boolean getUseClientMode() {
                return delegate.getUseClientMode();
            }

            @Override
            public void setNeedClientAuth(boolean need) {
                delegate.setNeedClientAuth(need);
            }

            @Override
            public void setWantClientAuth(boolean want) {
                delegate.setWantClientAuth(want);
            }

            @Override
            public boolean getNeedClientAuth() {
                return delegate.getNeedClientAuth();
            }

            @Override
            public boolean getWantClientAuth() {
                return delegate.getWantClientAuth();
            }

            @Override
            public void setEnableSessionCreation(boolean flag) {
                delegate.setEnableSessionCreation(flag);
            }

            @Override
            public boolean getEnableSessionCreation() {
                return delegate.getEnableSessionCreation();
            }

            @Override
            public void bind(SocketAddress localAddr) throws IOException {
                delegate.bind(localAddr);
            }

            @Override
            public synchronized void close() throws IOException {
                delegate.close();
            }

            @Override
            public void connect(SocketAddress remoteAddr) throws IOException {
                delegate.connect(remoteAddr);
            }

            @Override
            public void connect(SocketAddress remoteAddr, int timeout) throws IOException {
                delegate.connect(remoteAddr, timeout);
            }

            @Override
            public SocketChannel getChannel() {
                return delegate.getChannel();
            }

            @Override
            public InetAddress getInetAddress() {
                return delegate.getInetAddress();
            }

            @Override
            public InputStream getInputStream() throws IOException {
                return delegate.getInputStream();
            }

            @Override
            public boolean getKeepAlive() throws SocketException {
                return delegate.getKeepAlive();
            }

            @Override
            public InetAddress getLocalAddress() {
                return delegate.getLocalAddress();
            }

            @Override
            public int getLocalPort() {
                return delegate.getLocalPort();
            }

            @Override
            public SocketAddress getLocalSocketAddress() {
                return delegate.getLocalSocketAddress();
            }

            @Override
            public boolean getOOBInline() throws SocketException {
                return delegate.getOOBInline();
            }

            @Override
            public OutputStream getOutputStream() throws IOException {
                return delegate.getOutputStream();
            }

            @Override
            public int getPort() {
                return delegate.getPort();
            }

            @Override
            public synchronized int getReceiveBufferSize() throws SocketException {
                return delegate.getReceiveBufferSize();
            }

            @Override
            public SocketAddress getRemoteSocketAddress() {
                return delegate.getRemoteSocketAddress();
            }

            @Override
            public boolean getReuseAddress() throws SocketException {
                return delegate.getReuseAddress();
            }

            @Override
            public synchronized int getSendBufferSize() throws SocketException {
                return delegate.getSendBufferSize();
            }

            @Override
            public int getSoLinger() throws SocketException {
                return delegate.getSoLinger();
            }

            @Override
            public synchronized int getSoTimeout() throws SocketException {
                return delegate.getSoTimeout();
            }

            @Override
            public boolean getTcpNoDelay() throws SocketException {
                return delegate.getTcpNoDelay();
            }

            @Override
            public int getTrafficClass() throws SocketException {
                return delegate.getTrafficClass();
            }

            @Override
            public boolean isBound() {
                return delegate.isBound();
            }

            @Override
            public boolean isClosed() {
                return delegate.isClosed();
            }

            @Override
            public boolean isConnected() {
                return delegate.isConnected();
            }

            @Override
            public boolean isInputShutdown() {
                return delegate.isInputShutdown();
            }

            @Override
            public boolean isOutputShutdown() {
                return delegate.isOutputShutdown();
            }

            @Override
            public void sendUrgentData(int value) throws IOException {
                delegate.sendUrgentData(value);
            }

            @Override
            public void setKeepAlive(boolean keepAlive) throws SocketException {
                delegate.setKeepAlive(keepAlive);
            }

            @Override
            public void setOOBInline(boolean oobinline) throws SocketException {
                delegate.setOOBInline(oobinline);
            }

            @Override
            public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
                delegate.setPerformancePreferences(connectionTime, latency, bandwidth);
            }

            @Override
            public synchronized void setReceiveBufferSize(int size) throws SocketException {
                delegate.setReceiveBufferSize(size);
            }

            @Override
            public void setReuseAddress(boolean reuse) throws SocketException {
                delegate.setReuseAddress(reuse);
            }

            @Override
            public synchronized void setSendBufferSize(int size) throws SocketException {
                delegate.setSendBufferSize(size);
            }

            @Override
            public void setSoLinger(boolean on, int timeout) throws SocketException {
                delegate.setSoLinger(on, timeout);
            }

            @Override
            public synchronized void setSoTimeout(int timeout) throws SocketException {
                delegate.setSoTimeout(timeout);
            }

            @Override
            public void setSSLParameters(SSLParameters p) {
                delegate.setSSLParameters(p);
            }

            @Override
            public void setTcpNoDelay(boolean on) throws SocketException {
                delegate.setTcpNoDelay(on);
            }

            @Override
            public void setTrafficClass(int value) throws SocketException {
                delegate.setTrafficClass(value);
            }

            @Override
            public void shutdownInput() throws IOException {
                delegate.shutdownInput();
            }

            @Override
            public void shutdownOutput() throws IOException {
                delegate.shutdownOutput();
            }

            @Override
            public String toString() {
                return delegate.toString();
            }

            @Override
            public boolean equals(Object o) {
                return delegate.equals(o);
            }
        }

        /**
         * An {@link javax.net.ssl.SSLSocket} that doesn't allow {@code SSLv3} only connections
         * <p>fixes https://github.com/koush/ion/issues/386</p>
         */
        private static class NoSSLv3SSLSocket extends DelegateSSLSocket {

            private NoSSLv3SSLSocket(SSLSocket delegate) {
                super(delegate);

                String canonicalName = delegate.getClass().getCanonicalName();
                if (!canonicalName.equals("org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl")) {
                    // try replicate the code from HttpConnection.setupSecureSocket()
                    try {
                        Method msetUseSessionTickets = delegate.getClass().getMethod("setUseSessionTickets", boolean.class);
                        if (null != msetUseSessionTickets) {
                            msetUseSessionTickets.invoke(delegate, true);
                        }
                    } catch (NoSuchMethodException ignored) {
                    } catch (InvocationTargetException ignored) {
                    } catch (IllegalAccessException ignored) {
                    }
                }
            }

            @Override
            public void setEnabledProtocols(String[] protocols) {
                if (protocols != null && protocols.length == 1 && "SSLv3".equals(protocols[0])) {
                    // no way jose
                    // see issue https://code.google.com/p/android/issues/detail?id=78187
                    List<String> enabledProtocols = new ArrayList<String>(Arrays.asList(delegate.getEnabledProtocols()));
                    if (enabledProtocols.size() > 1) {
                        enabledProtocols.remove("SSLv3");
                    }
                    protocols = enabledProtocols.toArray(new String[enabledProtocols.size()]);
                }
                super.setEnabledProtocols(protocols);
            }
        }

    }

and somewhere in your code, before creating the Connection:

    static {
    HttpsURLConnection.setDefaultSSLSocketFactory(new NoSSLv3Factory());
}

This code is taken from https://code.google.com/p/android/issues/detail?id=78187, where you can find a fully explanation on why this is happening in Android 4.X.

I've had this in production from one week and seems to have done the trick.

Umberto answered 13/1, 2015 at 17:51 Comment(8)
hi this fix works for me, but running my app with fixed code once, and the uninstalled and installed the old version -> now the old version works still.... does the android system cache this setting anywhere? can i delete it? reboot didn't help eitherPhosphoric
@Umberto I have used the NoSSLv3Factory client but, It is not working Samsung S3 device. When loading the url in application WebView it is giving the error as "Web page not found". Is this a device specific issue ? If not Please let me know if we need to change settings of webviewAmadis
I have never gone through that issue. Changing the SSL factory targets the case in where you are using HttpUrlConnection to connect to your server - the factory will create HttpUrlConnection objects that will not used the obsolete SSLLv3 protocol. However, I don't know if that will work for a webview. I don't know which HTTP client does the webview use under the hood.Umberto
Any way, if you webview says "Web page not found" I think that has nothing to do with this, that is just a 404, not a connection issue caused by handshake problems due to incompatible cipher suites.Umberto
@Umberto I am trying to load the url in webview instead of connecting to it using HttpUrlConnection. So, how can I remove the SSLV3 protocol from the webview settings while loading the url ??Amadis
I'm still experiencing an SSLHandshakeException. I'm using okHTTP with Retrofit. Using this class like so: okClient.setSslSocketFactory(new NoSSLv3Factory());. Does this work with okHTTP and Retrofit?Margeret
How can we keep code in static block without identifier or type static { HttpsURLConnection.setDefaultSSLSocketFactory(new NoSSLv3Factory()); }Kerrykersey
Using this with retrofit, httpClient.socketFactory(new NoSSLv3Factory()); i am having a new error "SocketException: Unconnected sockets not implemented"Dark
T
7

I took @GaRRaPeTa's answer and bundled it into a dead simple method call. You can use the NetCipher library to get a modern TLS config when using Android's HttpsURLConnection. NetCipher configures the `HttpsURLConnection instance to use the best supported TLS version, removes SSLv3 support, and configures the best suite of ciphers for that TLS version. First, add it to your build.gradle:

compile 'info.guardianproject.netcipher:netcipher:1.2'

Or you can download the netcipher-1.2.jar and include it directly in your app. Then instead of calling:

HttpURLConnection connection = (HttpURLConnection) sourceUrl.openConnection();

Call this:

HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl);
Triserial answered 8/9, 2015 at 20:11 Comment(6)
Tried on Android 4.0 Emulator, received "javax.net.ssl.SSLException: Connection closed by peer"Pancreas
This does enforce good SSL configurations, so if you are connecting to a server that only supports SSLv3 for example, then you'll get an Exception. Or if that server only supports weak ciphers, or has problems with TLSv1.2 enabled.Triserial
Only solution that worked for me. Thank you, @Hans-ChristophSteinerCoady
Getting "SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure" when calling conn.getOutputStream() on Android 2.2 deviceDeterminate
On Investigation it seems that the solution above only works on API 9 and above. Android 2.2 is API 8 :/Determinate
Worked for me with OKHttp, Retrofit.Cucullate
C
3

The above solution(s) didn't work for me, therefore this is what I learned and did to overcome this issue.

For older devices than Android 5.0, the default security provider had those properties:

  1. TSLv1 and TSLv2 protocols were not enable by default
  2. SSLv3 protocol is not disable by default.

A solution that worked for me here is to patch the "Provider" if needed when starting the app, so it will no longer have SSLv3 on it's list of protocols. A straightforward way to patch Android from your app is this: (considering you have access to Google Play Store services.)

private void updateAndroidSecurityProvider(Activity callingActivity) {
    try {
        ProviderInstaller.installIfNeeded(this);
    } catch (GooglePlayServicesRepairableException e) {
        // Thrown when Google Play Services is not installed, up-to-date, or enabled
        // Show dialog to allow users to install, update, or otherwise enable Google Play services.
        GooglePlayServicesUtil.getErrorDialog(e.getConnectionStatusCode(), callingActivity, 0);
    } catch (GooglePlayServicesNotAvailableException e) {
        Log.e("SecurityException", "Google Play Services not available.");
    }
}

Take a look at: https://developer.android.com/training/articles/security-gms-provider.html?#patching for more info.

Consortium answered 3/12, 2016 at 17:26 Comment(0)
F
2

Aside from @GaRRaPeTa's response, please make that the makeSocketsafe method determines if the socket is not yet converted to NoSSLv3SSLSocket to prevent Stackoverflow issues:

    private static Socket makeSocketSafe(Socket socket) {
        if (socket instanceof SSLSocket && !(socket instanceof NoSSLv3SSLSocket)) {
            socket = new NoSSLv3SSLSocket((SSLSocket) socket);
        }
        return socket;
    }

PS. Cannot comment so that it's on a separate post.

Forgat answered 20/2, 2015 at 18:24 Comment(1)
hi i got still stack overflow errors because i called "HttpsURLConnection.setDefaultSSLSocketFactory(new NoSSLv3Factory());" multiple times, and the delegate stack got longer and longer, i fixed this by making a static variable: private static final SSLSocketFactory delegate = HttpsURLConnection.getDefaultSSLSocketFactory();Phosphoric
N
0

I've recently tested this using SSLContext (as I needed access to Trustmanager) instead of implementing my own NoSSLv3Factory and so far I haven't had any problems.

private getSSLContext()
{
    /* Load the keyStore that includes self-signed cert as a "trusted" entry. */
    KeyStore keyStore = ...  //optional
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); //optional
    tmf.init(keyStore); //optional

    //This is the important line, specifying the cipher to use and cipher provider
    SSLContext sslContext = SSLContext.getInstance("TLSv1","AndroidOpenSSL");
    ctx.init(null, tmf.getTrustManagers(), null); //if trustmanager not used pass null as the second parameter    
    return sslContext;
}

You could then use this in your HttpsURLConnection object like so:

...
URL url = new URL("https://yourwebapp.com/");
HttpsURLConnection webConnection = (HttpsURLConnection)url.openConnection();
webConnection.setSSLSocketFactory(getSSLContext())
...    

This does mean that you'll have to stay on top of any TLS vulnerabilities though and modify the specified cipher if any SSL/TLS vulnerabilities are publicly disclosed.

A list of supported ciphers and providers you can use are listed here

The first code block, minor the key change for this scenario, was primarily taken from this SO answer

Nardone answered 12/8, 2015 at 8:46 Comment(0)
M
0

Also you should know that you can force TLS v1.2 for Android 4.0 devices that don't have it enabled by default:

This should be in the first line of your Application:

 try {
            ProviderInstaller.installIfNeeded(getApplicationContext());
            SSLContext sslContext;
            sslContext = SSLContext.getInstance("TLSv1.2");
            sslContext.init(null, null, null);
            sslContext.createSSLEngine();
        } catch (GooglePlayServicesRepairableException | GooglePlayServicesNotAvailableException
                | NoSuchAlgorithmException | KeyManagementException e) {
            e.printStackTrace();
        }
Meath answered 11/7, 2018 at 12:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.