Android Pre-Lollipop Devices Giving Error "Ssl Handshake Aborted: Ssl=0X618D9C18: I/O Error During System Call, Connection Reset by Peer"

Android pre-lollipop devices giving error SSL handshake aborted: ssl=0x618d9c18: I/O error during system call, Connection reset by peer

Finally found a solution to this issue, its not a complete solution as it is a hack mentioned by Jesse Wilson from okhttp, square here. As i mentioned it was a simple hack where i had to rename my SSLSocketFactory variable to

private SSLSocketFactory delegate;

notice that it would throw error if you give any name other than delegate. Iam posting my complete solution below

This is my TLSSocketFactory class

public class TLSSocketFactory extends SSLSocketFactory {

private SSLSocketFactory delegate;
private TrustManager[] trustManagers;

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

private void generateTrustManagers() throws KeyStoreException, NoSuchAlgorithmException {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();

if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers:"
+ Arrays.toString(trustManagers));
}

this.trustManagers = trustManagers;
}

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

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

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

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

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

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

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

@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return enableTLSOnSocket(delegate.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;
}

@Nullable
public X509TrustManager getTrustManager() {
return (X509TrustManager) trustManagers[0];
}

}

and this is how i used it with okhttp and retrofit

 OkHttpClient client=new OkHttpClient();
try {
TLSSocketFactory tlsSocketFactory=new TLSSocketFactory();
if (tlsSocketFactory.getTrustManager()!=null) {
client = new OkHttpClient.Builder()
.sslSocketFactory(tlsSocketFactory, tlsSocketFactory.getTrustManager())
.build();
}
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
}

Retrofit retrofit = new Retrofit.Builder()
.baseUrl(URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();

EDIT : The method public Builder sslSocketFactory(SSLSocketFactory sslSocketFactory) is now deprecated and we should use public Builder sslSocketFactory(
SSLSocketFactory sslSocketFactory, X509TrustManager trustManager)
as i have updated in the answer. This is because X509TrustManager is a field that OkHttp needs to build a clean certificate chain, which was not paased in the deprecated method.

You may also check this for more info

SSLHandshakeException: SSL handshake aborted: ssl=0xbe6af938: I/O error during system call, Connection reset by peer

I'm not sure there's enough info here for me to accurately diagnose your problem but the error indicates an SSL handshake error, which would normally, to me, indicate the problem isn't in the code, but in the certs/acceptable encryption algorithms for the communication channel.

Retrofit is a REST framework, so I'm assuming you wrote an API on top of it and retrofit handles your HTTP sessions and SSL stuff. You said the solution suddenly stopped working. Is your retrofit dependency up to date? Maybe bring your dependencies up to date, repackage your application and see if that works?

Retrofit/OkHTTP examples with TLS Context

Admob in flutter app: Error while connecting to ad server: SSL handshake aborted

It does not work even in example app with the same error, a ticket created.

Retrofit ssl=0x717f870208: I/O error during system call, Connection reset by peer

I found the problem was in my ISP which redirects me to their website for displaying a message about internet consumption and stuck in that redirect, when I run the application using data or different WiFi it works fine!

Retrofit request is not working on pre Lollipop devices

I solved my error with this solution.

Everything is the same as I wrote in the question except this changes.

Add this class to your project.

public class TLSSocketFactory extends SSLSocketFactory {

private SSLSocketFactory delegate;

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

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

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

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

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

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

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

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

@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return enableTLSOnSocket(delegate.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;
}
}

And then onCreate method changes to this.

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

OkHttpClient client = new OkHttpClient();
try {
client = new OkHttpClient.Builder()
.sslSocketFactory(new TLSSocketFactory())
.build();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://www.google.com/")
.client(client)
.addConverterFactory(ScalarsConverterFactory.create())
.build();

IGetHtml iGetHtml = retrofit.create(IGetHtml.class);
Call<String> stringCall = iGetHtml.getHtml(url);
stringCall.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
if (response.isSuccessful()) {
Log.e(TAG, "onResponse: " + response.headers());
}
}

@Override
public void onFailure(Call<String> call, Throwable t) {
Log.e(TAG, "onFailure: " + t);
}
});

}


Related Topics



Leave a reply



Submit