androidretrofittls1.2sslexception

Getting SSLException using Retrofit 2


I'm creating authorization app, where I'm using Retrofit 2. When I'm doing call, that goes to onFailure method and gets exception

"javax.net.ssl.SSLException: Connection closed by peer"

But the problem is, that yesterday this worked great. Today it gives exception. I find in internet some SSLException - Connection closed by peer on Android 4.x versions, or this How to add TLS v 1.0 and TLS v.1.1 with Retrofit, but this not helped me. Any ideas how to fix it. In backend TLS1.2 is enable.

public class RegistrationFragment extends BaseFragment {
View mainView;

ApiClient apiClient = ApiClient.getInstance();

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    mainView = inflater.inflate
            (R.layout.registration_fragment, container, false);

            //Calling the authorization method
            registerCall();
        }
    });

    return mainView;
}

//User authorization method

public void registerCall() {

    Call<ResponseBody> call = apiClient.registration(supportopObj);
    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
            if (response.isSuccessful()) {

                //Calling the clientCall method for getting the user clientID and clientSecret
                Toast.makeText(getActivity(), "Registration Successful ",
                        Toast.LENGTH_SHORT).show();;

            } else {
                //if the response not successful
                Toast.makeText(getActivity(), "Could not register the user maybe already registered ",
                        Toast.LENGTH_SHORT).show();
            }
        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {
            Toast.makeText(getActivity(), "An error occurred", Toast.LENGTH_SHORT).show();
        }
    });
}
}

Solution

  • I used something like this in my OkHttp initialize class, but is it safe to use here?

    I'm created a new class Tls12SocketFactory.class

    Here is it.

    public class Tls12SocketFactory extends SSLSocketFactory {
    private static final String[] TLS_V12_ONLY = {"TLSv1.2"};
    
    final SSLSocketFactory delegate;
    
    public Tls12SocketFactory(SSLSocketFactory base) {
        this.delegate = base;
    }
    
    @Override
    public String[] getDefaultCipherSuites() {
        return delegate.getDefaultCipherSuites();
    }
    
    @Override
    public String[] getSupportedCipherSuites() {
        return delegate.getSupportedCipherSuites();
    }
    
    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        return patch(delegate.createSocket(s, host, port, autoClose));
    }
    
    @Override
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        return patch(delegate.createSocket(host, port));
    }
    
    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
        return patch(delegate.createSocket(host, port, localHost, localPort));
    }
    
    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return patch(delegate.createSocket(host, port));
    }
    
    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        return patch(delegate.createSocket(address, port, localAddress, localPort));
    }
    
    private Socket patch(Socket s) {
        if (s instanceof SSLSocket) {
            ((SSLSocket) s).setEnabledProtocols(TLS_V12_ONLY);
        }
        return s;
    }
    }
    

    And I done something like this in OkHttp initialize class.

    X509TrustManager trustManager = null;
    
        try {
            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));
            }
             trustManager = (X509TrustManager) trustManagers[0];
        } catch (KeyStoreException | NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    
        OkHttpClient.Builder client = new OkHttpClient.Builder()
                .readTimeout(10, TimeUnit.SECONDS)
                .connectTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS);
    
        try {
            SSLContext sc = SSLContext.getInstance("TLSv1.2");
            sc.init(null, new TrustManager[] { trustManager }, null);
            client.sslSocketFactory(new Tls12SocketFactory(sc.getSocketFactory()), trustManager);
            ConnectionSpec cs = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
                    .tlsVersions(TlsVersion.TLS_1_2)
                    .build();
            client.connectionSpecs(Collections.singletonList(cs));
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            e.printStackTrace();
        }
    
     name = new Retrofit.Builder()
                .baseUrl(endpoint)
                .client(client.build())
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    

    So is it safe to use this code in Android studio. And шill there be any problems in the future from this code? Thank you. I think my answer can help anyone else too.