How to disable SSLv3 in android for HttpsUrlConnection?

We wrote a client application in android that connects to https servers using the HttpsUrlConnection apis. Due to the Poodle vulnerability, we need to disable SSLv3 from the list of allowed protocols when invoking any request.

We followed the recommendations written by oracle as http://www.oracle.com/technetwork/java/javase/documentation/cve-2014-3566-2342133.html

and added the following line before calling the url connection

java.lang.System.setProperty("https.protocols", "TLSv1"); 

This solution works great with regular Java program. We got an SSLHandShakeException when we tried to connect to a server that runs only on SSLv3 protocol.

But problem : the same fix does not work for android. Am I missing something or should I try a different approach for Android? Please suggest.

+17
java android client poodle-attack
Oct 30 '14 at 9:33
source share
8 answers

I found a solution for this by analyzing data packets using wirehark. I found that when creating a secure connection, the android returned to SSLv3 from TLSv1 . This is a bug in android versions 4.4 and can be resolved by removing SSLv3 from the Enabled Protocols list. I created my own socketFactory class called NoSSLv3SocketFactory.java. Use this to make socketfactory.

 /*Copyright 2015 Bhavit Singh Sengar Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.*/ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; 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.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; public class NoSSLv3SocketFactory extends SSLSocketFactory{ private final SSLSocketFactory delegate; public NoSSLv3SocketFactory() { this.delegate = HttpsURLConnection.getDefaultSSLSocketFactory(); } public NoSSLv3SocketFactory(SSLSocketFactory delegate) { this.delegate = delegate; } @Override public String[] getDefaultCipherSuites() { return delegate.getDefaultCipherSuites(); } @Override public String[] getSupportedCipherSuites() { return delegate.getSupportedCipherSuites(); } private 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)); } private class NoSSLv3SSLSocket extends DelegateSSLSocket { private NoSSLv3SSLSocket(SSLSocket delegate) { super(delegate); } @Override public void setEnabledProtocols(String[] protocols) { if (protocols != null && protocols.length == 1 && "SSLv3".equals(protocols[0])) { List<String> enabledProtocols = new ArrayList<String>(Arrays.asList(delegate.getEnabledProtocols())); if (enabledProtocols.size() > 1) { enabledProtocols.remove("SSLv3"); System.out.println("Removed SSLv3 from enabled protocols"); } else { System.out.println("SSL stuck with protocol available for " + String.valueOf(enabledProtocols)); } protocols = enabledProtocols.toArray(new String[enabledProtocols.size()]); } super.setEnabledProtocols(protocols); } } public 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 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); } } } 

Use this class as when connecting:

 SSLContext sslcontext = SSLContext.getInstance("TLSv1"); sslcontext.init(null, null, null); SSLSocketFactory NoSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory()); HttpsURLConnection.setDefaultSSLSocketFactory(NoSSLv3Factory); l_connection = (HttpsURLConnection) l_url.openConnection(); l_connection.connect(); 
+42
Apr 29 '15 at 14:22
source

Inspired by Bhavit S. Sengar's answer , he associated this technique with a dead simple method call. You can use the NetCipher library to get a modern TLS configuration when using Android HttpsURLConnection . NetCipher configures the HttpsURLConnection instance to use the best supported version of TLS, removes SSLv3 support, and configures the best cipher suite for this version of TLS. First add it to your build.gradle:

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

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

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

Call:

 HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl); 
+15
Sep 08 '15 at 20:23
source

At first I tried to answer Bhavit S. Sengar, and it worked in most cases. But sometimes there are problems there, even when SSLv3 was removed from Enabled Protocols on an Android 4.4.4 device. Therefore, the Hans-Christoph Steiner NetCipher library is ideal for solving this problem as far as I can test it.

We use jsoup to create a bunch of web clips on different servers, so we cannot set HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl); . I assume the same problem if you use OkHttp.

The best solution we have come is to set info.guardianproject.netcipher.client.TlsOnlySocketFactory from NetCipher as DefaultSSLSocketFactory in a static block. Thus, it is configured for the entire runtime of our application:

 SSLContext sslcontext = SSLContext.getInstance("TLSv1"); sslcontext.init(null, null, null); SSLSocketFactory noSSLv3Factory = new TlsOnlySocketFactory(sc.getSocketFactory()); HttpsURLConnection.setDefaultSSLSocketFactory(noSSLv3Factory); 

If you want to see the full details (using trustAllCertificates ), you can do it here .

+6
Jan 20 '16 at 16:01
source

use this piece of code if the SSLv3 server is turned on, then it will not be acknowledged.

  SocketFactory sf = SSLSocketFactory.getDefault(); SSLSocket socket = (SSLSocket) sf.createSocket("host-name", 443); socket.setEnabledProtocols(new String[] { "TLSv1"}); socket.startHandshake(); 
+4
Oct 30 '14 at 12:27
source

It connects to the https server, we need a certificate in handshaking mode from the client side. 1 year ago, I solved a similar problem using a self-determination certificate as follows:

 import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.cert.X509Certificate; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; public class HttpsTrustManager implements X509TrustManager { private static TrustManager[] trustManagers; private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{}; @Override public void checkClientTrusted( java.security.cert.X509Certificate[] x509Certificates, String s) throws java.security.cert.CertificateException { } @Override public void checkServerTrusted( java.security.cert.X509Certificate[] x509Certificates, String s) throws java.security.cert.CertificateException { } public boolean isClientTrusted(X509Certificate[] chain) { return true; } public boolean isServerTrusted(X509Certificate[] chain) { return true; } @Override public X509Certificate[] getAcceptedIssuers() { return _AcceptedIssuers; } public static void allowAllSSL() { HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String arg0, SSLSession arg1) { return true; } }); SSLContext context = null; if (trustManagers == null) { trustManagers = new TrustManager[]{new HttpsTrustManager()}; } try { context = SSLContext.getInstance("TLS"); context.init(null, trustManagers, new SecureRandom()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyManagementException e) { e.printStackTrace(); } HttpsURLConnection.setDefaultSSLSocketFactory(context .getSocketFactory()); } } 

Client Side Usage Before HttpsUrlConnection

 HttpsTrustManager.allowAllSSL(); 

hope it works :)

+1
Nov 30 '16 at 11:07
source
  SSLContext sslContext = SSLContext.getInstance("TLSv1"); sslContext.init(null, null, null); SSLSocketFactory socketFactory = sslContext.getSocketFactory(); httpURLConnection.setSSLSocketFactory(socketFactory); 

HttpsURLConnection using TSL creates a security failure, Android implementation will revert to SSLV3 to the connection.

Please refer to http://code.google.com/p/android/issues/detail?id=78431

0
Apr 16 '15 at 10:31
source

Using the PlayService publisher client libraries running on Android, I encountered the same problem when running sample .

This is fixed with awnser @ bhavit-s-sengar. I also had to change AndroidPublisherHelper.newTrustedTransport() to the following:

 SSLContext sslcontext = SSLContext.getInstance("TLSv1"); sslcontext.init(null, null, null); // NoSSLv3SocketFactory is @bhavit-s-sengar http://stackoverflow.com/a/29946540/8524 SSLSocketFactory noSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory()); NetHttpTransport.Builder netTransportBuilder = new NetHttpTransport.Builder(); netTransportBuilder.setSslSocketFactory(noSSLv3Factory); HTTP_TRANSPORT = netTransportBuilder.build(); 
0
Sep 03 '15 at 9:31 on
source

In fact, we do not need to disable SSLV3 or TLSV1.0, we just need to enable TLSV1.1 or TLSv1.2 in android <5 devices.

The problem is that TLSv1.1 and TLSv1.2 are not enabled by default on Android <5 and to connect using this latest secure protocol, which should be enabled on Android devices <5.

This solution fixed my problem: stack overflow

0
Aug 24 '17 at 7:19
source



All Articles