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(
as i have updated in the answer. This is because
SSLSocketFactory sslSocketFactory, X509TrustManager trustManager)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
Android: How to Change the Actionbar "Home" Icon to Be Something Other Than the App Icon
How to Avoid Delay in Android Gcm Messages/Change Heartbeat
Save Sensitive Data in React Native
Android Device Chooser -- Device Not Showing Up
How to Change the Track Color of a Switchcompat
Change the Right Margin of a View Programmatically
Android Retrofit - Onprogressupdate for Showing Progress Notification
Cannot Lower Case Button Text in Android Studio
Filter Output in Logcat by Tagname
How to Fix "Failed to Sync Vcpu Reg" Error
Interstitial Admob Ads: "Illegalstateexception: Only Fullscreen Activities Can Request Orientation"
(Deprecated) Fragment Onoptionsitemselected Not Being Called
How to Add Action Bar Options Menu in Android Fragments
How to Create Converter for My Class in Android Retrofit Library