How to Disable Sslv3 in Android for Httpsurlconnection

Disable SSL as a protocol in HttpsURLConnection

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.

How to disable SSLv3 in Jsoup android? (javax.net.ssl.SSLHandshakeException)

Found out how to make this work using NetCipher library.
Answer from another question answered by Hans-Christoph Steiner: https://stackoverflow.com/a/32466614/6723008

In the build.gradle (app module) file include the NetCipher compile dependency, latest version is 1.2:

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

(Or you can download the netcipher-1.2.jar and include it directly in your app.)

Usage:

HttpsURLConnection netCipherconnection = NetCipher.getHttpsURLConnection(url);
netCipherconnection.connect();

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(netCipherconnection.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();
String stringHTML;
while ((stringHTML = bufferedReader.readLine()) != null)
stringBuilder.append(stringHTML);
bufferedReader.close();
Document resultDocument = Jsoup.parse(String.valueOf(stringBuilder));


Related Topics



Leave a reply



Submit