Android 4.4 Volley connection error to nginx

0

I'm having trouble letting android devices with an API < 21 connect to my nginx server. All results here are from an API 19 emulated device.

I tried using the VolleyToolboxExtension and NoSSLv3Factory as suggested elsewhere but still got hard errors like below, except then instead of sslv3 it was tlsv1.

My current approach is to let old android versions connect via SSLv3.But this still produces errors like down below.

Note: I'm aware that SSLv3 is broken but I'm using a different certificate and I'm not sending anything security relevant. The whole idea is to make a survey so I can decide whether I want to drop support for older android SDK versions.

error during request: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb8a45890: Failure in SSL library, usually a protocol error
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0x8d959990:0x00000000)

I'm using the following code for connecting:

final String url;
if ( Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ){
    url = "https://abc.badssl.example.com";
} else {
    url = "https://abc.example.com";
}
final JSONObject jsonBody;
try {
    jsonBody = new JSONObject("{\"api\":" + Build.VERSION.SDK_INT + "}");
    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, url,
            jsonBody,
            response -> {
                try {
                    Log.d(TAG, "Response is: " + response.getInt("api"));
                } catch (JSONException e) {
                    Log.wtf(TAG, e);
                }
                wasRunning = true;
                loading.postValue(false);
            }, e -> {
        Log.e(TAG, "error during request: " + e.getMessage());
        error.postValue(true);
    });
    jsonObjectRequest.setShouldCache(false);
    jsonObjectRequest.setRetryPolicy(new DefaultRetryPolicy(DefaultRetryPolicy.DEFAULT_TIMEOUT_MS, 5, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
    queue.getCache().clear();

    queue.add(jsonObjectRequest);
} catch (JSONException e) {
    Log.wtf(TAG, e);
}

And this is my nginx configuration for abc.badssl.example.com, using a different certificate:

listen  443 ssl;
server_name abc.badssl.example.com;

ssl on;
ssl_protocols SSLv3;
ssl_dhparam /etc/nginx/ssl/dhparams.pem;

#worker shared ssl cache
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 5m;
ssl_ciphers 'ECDHE-ECDSA-AES256-SHA:EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:!DHE-RSA-AES256-GCM-SHA384:!DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:!DHE-RSA-AES256-SHA256:!DHE-RSA-AES128-SHA256:!DHE-RSA-AES256-SHA:!DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4:!DHE-RSA-DES-CBC-SHA:!DHE-RSA-CAMELLIA256-SHA:!DHE-RSA-CAMELLIA128-SHA:!DHE-DSS-CBC-SHA:!DHE-RSA-DES-CBC3-SHA';

fastcgi_param HTTPS on;

I think I got the nginx params wrong but I can't seem to find much as 99% is either about disabling SSLv3 or nothing regarding the current version of volley (dead links in SO).

android
nginx
https
android-volley
asked on Stack Overflow Feb 19, 2019 by proc • edited Feb 19, 2019 by proc

1 Answer

0

Ok so the solution turns out to be a bit different.

First of all: SSLv3 is disabled on debian & ubuntu in current versions of OpenSSL for obvious reasons. Interestingly this does not throw any errors or such, the nginx configuraton protocols are simply ignored ?! I can still connect via TLS1.X to the server, even with only SSLv3 in the configuration. nmap reports the same.

On Android < 21 (as told in other Answers) TLS is existent, but SSLv3 preferred or even forced.

The easiest solution to get a working HTTPsUrlConnection on older devices is to use NetCipher.

build.gradle:

implementation "info.guardianproject.netcipher:netcipher:2.0.0-alpha1"

And then use Netcipher for creation of the HTTPs connection.
You can also use this together with volley, by using a custom HttpStack. Please note that StrongBuilders from Netcipher aren't for making simple https connections! They're only for making connections through the Tor network. So don't get fooled thinking you can just use these to avoid HttpStack.

The request handler without volley, using the raw HttpsUrlConnection, stripped down:

final String url = "https://asd.example.com";
runner = new Thread(() -> {

    final JSONObject jsonBody;
    try {
        HttpsURLConnection con = NetCipher.getHttpsURLConnection(new URL(url));
        con.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
        con.setRequestProperty("Accept", "application/json");
        con.setDoOutput(true);
        con.setDoInput(true);

        jsonBody = new JSONObject("{\"api\":" + Build.VERSION.SDK_INT + "}");

        OutputStream wr = con.getOutputStream();
        wr.write(jsonBody.toString().getBytes("UTF-8"));
        wr.flush();
        wr.close();

        InputStream in = new BufferedInputStream(con.getInputStream());
        ByteArrayOutputStream result = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int length;
        while ((length = in.read(buffer)) != -1) {
            result.write(buffer, 0, length);
        }

        JSONObject jsonObject = new JSONObject(result.toString("UTF-8"));
        in.close();


        con.disconnect();
        Log.d(TAG,"received json: "+jsonObject.toString());
        loading.postValue(false);
    } catch (
            Exception e) {
        Log.wtf(TAG, e);
    }
});
runner.start();
answered on Stack Overflow Feb 20, 2019 by proc • edited Feb 20, 2019 by proc

User contributions licensed under CC BY-SA 3.0