Javax.Net.Ssl.Sslhandshakeexception: Javax.Net.Ssl.Sslprotocolexception: Ssl Handshake Aborted: Failure in Ssl Library, Usually a Protocol Error

Javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: Failure in SSL library, usually a protocol error

I found the solution for it by analyzing the data packets using wireshark. What I found is that while making a secure connection, android was falling back to SSLv3 from TLSv1 . It is a bug in android versions < 4.4 , and it can be solved by removing the SSLv3 protocol from Enabled Protocols list. I made a custom socketFactory class called NoSSLv3SocketFactory.java. Use this to make a 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 like this while 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();

UPDATE :

Now, correct solution would be to install a newer security provider using Google Play Services:

    ProviderInstaller.installIfNeeded(getApplicationContext());

This effectively gives your app access to a newer version of OpenSSL and Java Security Provider, which includes support for TLSv1.2 in SSLEngine. Once the new provider is installed, you can create an SSLEngine which supports SSLv3, TLSv1, TLSv1.1 and TLSv1.2 the usual way:

    SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, null, null);
SSLEngine engine = sslContext.createSSLEngine();

Or you can restrict the enabled protocols using engine.setEnabledProtocols.

Don't forget to add the following dependency (check the latest version here):

implementation 'com.google.android.gms:play-services-auth:17.0.0'

For more info, checkout this link.

javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted:

I have tried to sort out the error and this has worked for me. What I have understood was that for devices below that of lollipop the protocols TLSv1.1 and TLSv1.2 are not enabled by default. Inorder to enable them for devices such using jellybean or kitkat we will have to use a SSLSocketFactory.

So now I have made the following change to the getRequestQueue() method of Volley singleton:

public RequestQueue getRequestQueue() {


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN
&& Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
Log.d("msg", "HI, I m a kitkat phone");
try {
ProviderInstaller.installIfNeeded(getApplicationContext());
} catch (GooglePlayServicesRepairableException e) {
// Indicates that Google Play services is out of date, disabled, etc.
// Prompt the user to install/update/enable Google Play services.
GooglePlayServicesUtil.showErrorNotification(e.getConnectionStatusCode(), getApplicationContext());
e.printStackTrace();

} catch (GooglePlayServicesNotAvailableException e) {
// Indicates a non-recoverable error; the ProviderInstaller is not able
// to install an up-to-date Provider.

e.printStackTrace();
}

HttpStack stack = null;
try {
stack = new HurlStack(null, new TLSSocketFactory());
} catch (KeyManagementException e) {
e.printStackTrace();
Log.d("Your Wrapper Class", "Could not create new stack for TLS v1.2");
stack = new HurlStack();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
Log.d("Your Wrapper Class", "Could not create new stack for TLS v1.2");
stack = new HurlStack();
}
mRequestQueue = Volley.newRequestQueue(getApplicationContext(), stack);
} else {
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
return mRequestQueue;
}

And create a class named TLSSocketFactory.java and add the following code:

public class TLSSocketFactory extends SSLSocketFactory {

private SSLSocketFactory internalSSLSocketFactory;

public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
internalSSLSocketFactory = context.getSocketFactory();
}

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

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

@Override
public Socket createSocket() throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket());
}

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

@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}

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

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

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

private Socket enableTLSOnSocket(Socket socket) {
if(socket != null && (socket instanceof SSLSocket)) {
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
}
return socket;
}

}

One more step is to add the following implementation in your dependencies of gradle file:

implementation 'com.google.android.gms:play-services-base:11.0.0'

I hope this might help you to resolve this issue.

Android System.err: javax.net.ssl.SSLHandshakeException: Handshake failed

I can't take any credit for this article but this will show you what packages need to be installed to fix the TLS/SSLv3 issue.

The other thing that you may need to do is add

<application
android:usesCleartextTraffic="true"
...
>

to your AndroidManifest.xml, which is something that I needed to do during unit tests.

why do I get SSLProtocolExcepetion: Handshake failed when trying to send http request?

... .execute("https://10.0.2.2:4000/products/add",object.toString());

I'm pretty sure that all you did with replace a working http:// with https:// and hoped that the server will magically be accessible by HTTPS this way. Only this does not work: the server actually has to implement and properly setup HTTPS including certificates etc. If this is not done you'll get something like this:

... routines:OPENSSL_internal:WRONG_VERSION_NUMBER ...

This is because the servers plain HTTP response (likely an error message about an invalid request) is blindly interpreted as a HTTPS response by the client. Given that a HTTPS response contains the TLS version number at a specific byte offset the client blindly interprets these bytes as TLS version and then complains about an unsupported TLS version.

To make sure that your server properly serves HTTPS try with a browser: if it does not work there it will likely not work within your app too.

OkHttp SSLHandshakeException SSL handshake aborted Failure in SSL library, a protocol error

So I solved it by adding the following to my http client object

 ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
.tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_1, TlsVersion.TLS_1_0)
.cipherSuites(
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA)
.build();

httpClient.connectionSpecs(Collections.singletonList(spec))

reference : https://github.com/square/okhttp/issues/3894



Related Topics



Leave a reply



Submit