21

I have android application that was working fine for most of devices Recently some hackers tried to make DDOS attack on our servers that force us to add some security and some firewalls

not some devices are not working and give me the following exception

javax.net.ssl.SSLException: SSL handshake aborted: ssl=0x63eb8240: I/O error during system call, Connection reset by peer 

can any one please tell me what is the problem now and how can I solve it ?

EDIT

this is the code of my execute method

public static BaseResponse execute(Context context, BaseRequest request) {

    mStartTime = System.nanoTime();

    BaseResponse response = new BaseResponse();
    DataOutputStream outputStream;
    try {
        URL url = new URL(request.getURL());
        HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
        urlConnection.setConnectTimeout(TIMEOUT_DURATION);
        urlConnection.setReadTimeout(TIMEOUT_DURATION);
        urlConnection.setRequestMethod(request.getRequestType().getValue());
        urlConnection.addRequestProperty("Accept", "application/json");
        urlConnection.addRequestProperty("Content-Type","application/json");
        urlConnection.setRequestProperty("Accept-Charset", CHARACTER_SET);
        urlConnection.addRequestProperty("Device-Id", PhoneUtils.getDeviceId(context));
        urlConnection.addRequestProperty("Version-Number", PhoneUtils.getAppVersion(context));


        TLSSocketFactory socketFactory = new TLSSocketFactory();
        urlConnection.setSSLSocketFactory(socketFactory);

        switch (request.getRequestType()) {
            case POST:
            case PUT:
                urlConnection.setDoOutput(true);
                if (request.getStringEntity() != null) {
                    outputStream = new DataOutputStream(urlConnection.getOutputStream());
                    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, CHARACTER_SET));
                    writer.write(request.getStringParam());
                    writer.close();
                    outputStream.flush();
                    outputStream.close();
                }

                break;
            case GET:
                urlConnection.setDoOutput(false);
                break;
        }

        urlConnection.connect();

        try {
            if (urlConnection.getResponseCode() == STATUS_OK) {
                InputStream inputStream = new BufferedInputStream(urlConnection.getInputStream());
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                StringBuilder result = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    result.append(line);
                }

                inputStream.close();
                response.setResponse(convertStringToJSONObject(result.toString()));
            } else {
                response.setResponse(null);
            }
        } catch (Exception ex) {
            response.setAppError(AppError.DATA_ERROR);
        }
    } catch (MalformedURLException e) {
        e.printStackTrace();
        response.setAppError(AppError.PARSING_ERROR);
    } catch (IOException e) {
        e.printStackTrace();
        response.setAppError(AppError.DATA_ERROR);
    } catch (Exception e) {
        e.printStackTrace();
        response.setAppError(AppError.DATA_ERROR);
    }

    return response;
}
Amira Elsayed Ismail
  • 9,216
  • 30
  • 92
  • 175
  • Possible duplicate of [javax.net.ssl.SSLException: Read error: ssl=0x9524b800: I/O error during system call, Connection reset by peer](http://stackoverflow.com/questions/30538640/javax-net-ssl-sslexception-read-error-ssl-0x9524b800-i-o-error-during-system) – halileohalilei Feb 26 '17 at 13:00

2 Answers2

45

Use this in your code before making any network call

/**
 * Initialize SSL
 * @param mContext
 */
public static void initializeSSLContext(Context mContext){
    try {
        SSLContext.getInstance("TLSv1.2");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    try {
        ProviderInstaller.installIfNeeded(mContext.getApplicationContext());
    } catch (GooglePlayServicesRepairableException e) {
        e.printStackTrace();
    } catch (GooglePlayServicesNotAvailableException e) {
        e.printStackTrace();
    }
}

I had the same problem and this piece of code solved my problem. FYI: I was using retrofit library for making network calls

You need to include below line in build.gradle

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

Thanks @Houman for the above input

Arshad
  • 1,262
  • 16
  • 25
  • 11
    @Arshad Can you explain why this solves the problem and what is causing the problem? – baldraider Aug 21 '17 at 06:55
  • 1
    You need `implementation 'com.google.android.gms:play-services-safetynet:17.0.0'` to be added to build.gradle to get ProviderInstaller working. – Houman Oct 25 '20 at 19:28
8

Different Android API levels have different support for SSL/TLS protocols versions, for details see in Android Documention - https://developer.android.com/reference/javax/net/ssl/SSLSocket.html

To enable TLS 1.1 and 1.2 you need to create a custom SSLSocketFactory - https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/

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;
    }
}

And then use it in your connection

HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
TLSSocketFactory socketFactory = new TLSSocketFactory();
conn.setSSLSocketFactory(socketFactory);
conn.connect();
kb0
  • 1,143
  • 1
  • 8
  • 13
  • 1
    there is no method in HttpURLConnection called setSSLSocketFactory, what is the version of android you are targeting ? – Amira Elsayed Ismail Feb 26 '17 at 13:25
  • HttpsURLConnection - https://developer.android.com/reference/javax/net/ssl/HttpsURLConnection.html – kb0 Feb 26 '17 at 13:29
  • You can cast HttpsURLConnection for URL.openConnection for https urls, i.e. - HttpsURLConnection con = (HttpsURLConnection) new URL("https://www.google.com/").openConnection() – kb0 Feb 26 '17 at 13:37
  • I have used the class you add to your answer and use it in my execute method and still have the same problem , please check my edit – Amira Elsayed Ismail Feb 26 '17 at 13:41
  • You can try another version of TLSSocketFactory (SSLSocketFactoryCompat) - https://gitlab.com/bitfireAT/davdroid/blob/93464ccf8c7d98cb1af81e51811c337db43eef92/app/src/main/java/at/bitfire/davdroid/SSLSocketFactoryCompat.java – kb0 Feb 26 '17 at 13:44
  • Also you can try to verify your server using some 3d-party service, like https://www.ssllabs.com/ssltest/. It's provide simulation for different android versions - "Handshake Simulation" section – kb0 Feb 26 '17 at 13:53
  • I have tried the 3d-party service and run it on the browser of my devices and it gives me Grade A – Amira Elsayed Ismail Feb 26 '17 at 14:41
  • Do you try second variant of TLSSocketFactory (SSLSocketFactoryCompat) from https://gitlab.com/bitfireAT/davdroid/blob/93464ccf8c7d98cb1af81e51811c337db43eef92/app/src/main/java/at/bitfire/davdroid/SSLSocketFactoryCompat.java ? – kb0 Feb 26 '17 at 15:13
  • You saved my life :) – Homayoon Ahmadi Feb 19 '19 at 19:30