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

前端 未结 5 860
失恋的感觉
失恋的感觉 2020-11-29 05:21

Iam having this strange issue in which the retrofit keeps throwing me

\"SSL handshake aborted: ssl=0x618d9c18: I/O error during system call, Connec

5条回答
  •  心在旅途
    2020-11-29 06:12

    In addition to Navneet Krishna I had to do the next in my App's class:

    ProviderInstaller.installIfNeededAsync
    

    According to https://developer.android.com/training/articles/security-gms-provider, and this because I needed to update the security provider to protect against SSL exploits.

    My App Class:

    public class AppClass extends MultiDexApplication {
    
    private static final String TAG = AppClass.class.getName();
    
    private static Context context;
    private static AuthAPI authAPI;
    private static RestAPI buyersAPI;
    
    @Override
    public void onCreate() {
        super.onCreate();
        /* enable SSL compatibility in pre-lollipop devices */
        upgradeSecurityProvider();
    
        createAuthAPI();
        createRestAPI();
    }
    
    private void upgradeSecurityProvider() {
        try{
            ProviderInstaller.installIfNeededAsync(this, new ProviderInstaller.ProviderInstallListener() {
                @Override
                public void onProviderInstalled() {
                    Log.e(TAG, "New security provider installed.");
                }
    
                @Override
                public void onProviderInstallFailed(int errorCode, Intent recoveryIntent) {
                    GooglePlayServicesUtil.showErrorNotification(errorCode, BuyersApp.this);
                    Log.e(TAG, "New security provider install failed.");
                }
            });
        }catch (Exception ex){
            Log.e(TAG, "Unknown issue trying to install a new security provider", ex);
        }
    
    }
    
    private void createAuthAPI() {
        OkHttpClient.Builder authAPIHttpClientBuilder = new OkHttpClient.Builder();
    
        Retrofit retrofit = new Retrofit.Builder()
                .client(enableTls12OnPreLollipop(authAPIHttpClientBuilder).build())
                .baseUrl(DomainLoader.getInstance(context).getAuthDomain())
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        authAPI = retrofit.create(AuthAPI.class);
    }
    
    private static OkHttpClient.Builder enableTls12OnPreLollipop(OkHttpClient.Builder client) {
        if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 22) {
            try {
                SSLContext sc = SSLContext.getInstance("TLSv1.2");
                sc.init(null, null, null);
    
                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));
                }
                X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
    
                client.sslSocketFactory(new Tls12SocketFactory(sc.getSocketFactory()), trustManager);
    
                ConnectionSpec cs = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
                        .tlsVersions(TlsVersion.TLS_1_2)
                        .build();
    
                List specs = new ArrayList<>();
                specs.add(cs);
                specs.add(ConnectionSpec.COMPATIBLE_TLS);
                specs.add(ConnectionSpec.CLEARTEXT);
    
                client.connectionSpecs(specs);
            } catch (Exception exc) {
                Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc);
            }
        }
    
        return client;
    }
    
    private void createRestAPI() {
        OkHttpClient.Builder restAPIHttpClientBuilder = new OkHttpClient.Builder();
        buyersAPIHttpClientBuilder.readTimeout(60, TimeUnit.SECONDS);
        buyersAPIHttpClientBuilder.connectTimeout(60, TimeUnit.SECONDS);
        buyersAPIHttpClientBuilder.writeTimeout(600, TimeUnit.SECONDS);
        buyersAPIHttpClientBuilder.addInterceptor(new NetworkErrorInterceptor());
        buyersAPIHttpClientBuilder.addInterceptor(new TokenVerificationInterceptor());
    
        Retrofit retrofit = new Retrofit.Builder()
                .client(enableTls12OnPreLollipop(restAPIHttpClientBuilder).build())
                .baseUrl(DomainLoader.getInstance(context).getDomain())
                .addConverterFactory(GsonConverterFactory.create(new GsonBuilder().setLenient().create()))
                .addConverterFactory(ScalarsConverterFactory.create())
                .build();
    
        buyersAPI = retrofit.create(RestAPI.class);
    }
    }
    

    And My Tls12SocketFactory class:

    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 it's working like a charm in all devices with KitKat and above.

提交回复
热议问题