Making a HTTPS request using Android Volley

AndroidHttpsAndroid Volley

Android Problem Overview


I am trying to make a https request using this code:

RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
request = new Request<String>(Request.Method.GET,"https://devblahblahblah.com/service/etc",errListener);

but I am getting this error:

> com.android.volley.NoConnectionError: > javax.net.ssl.SSLHandshakeException: > java.security.cert.CertPathValidatorException: Trust anchor for > certification path not found.

Two points to be noted:

  1. The HTTPS cert is valid. Easily opens without any warning on browser.
  2. The above code works fine with HTTP links.

I actually need to know if there are any switches/options in the Android Volley framework by using which I'll successfully hit a HTTPS URL?

Android Solutions


Solution 1 - Android

Warning: The following code should not be used in production because it is vulnerable to SSL attacks

Probably these codes below will be helpful for you:

1.Create a HttpsTrustManager class that implements X509TrustManager:

public class HttpsTrustManager implements X509TrustManager {

    private static TrustManager[] trustManagers;
    private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{};

    @Override
    public void checkClientTrusted(
            java.security.cert.X509Certificate[] x509Certificates, String s)
            throws java.security.cert.CertificateException {

    }

    @Override
    public void checkServerTrusted(
            java.security.cert.X509Certificate[] x509Certificates, String s)
            throws java.security.cert.CertificateException {

    }

    public boolean isClientTrusted(X509Certificate[] chain) {
        return true;
    }

    public boolean isServerTrusted(X509Certificate[] chain) {
        return true;
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return _AcceptedIssuers;
    }

    public static void allowAllSSL() {
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {

            @Override
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }

        });

        SSLContext context = null;
        if (trustManagers == null) {
            trustManagers = new TrustManager[]{new HttpsTrustManager()};
        }

        try {
            context = SSLContext.getInstance("TLS");
            context.init(null, trustManagers, new SecureRandom());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }

        HttpsURLConnection.setDefaultSSLSocketFactory(context
                .getSocketFactory());
    }

}

2.Add HttpsTrustManager.allowAllSSL() before you make a https request:

HttpsTrustManager.allowAllSSL();
String  tag_string_req = "string_req";
StringRequest strReq = new StringRequest(Request.Method.POST,
		your_https_url, new Response.Listener<String>() {
	@Override
	public void onResponse(String response) {
		Log.d(TAG, "response :"+response);
	}
}, new Response.ErrorListener() {
	@Override
	public void onErrorResponse(VolleyError error) {
		VolleyLog.d(TAG, "Error: " + error.getMessage());
	}
}){
	@Override
	protected Map<String, String> getParams() {
		Map<String, String> params = new HashMap<String, String>();
		params.put("username", "max");
		params.put("password", "123456");
		return params;
	}
};
AppController.getInstance().addToRequestQueue(strReq, tag_string_req);

Solution 2 - Android

you can [add this class][1] and execut it from onCreate method

new NukeSSLCerts().nuke();

it will make volley to Trust all SSL certificates. [1]: https://newfivefour.com/android-trust-all-ssl-certificates.html

Solution 3 - Android

If you are using volley and want to HTTPS request or SSL Certified service then you can choose this easiest way : -->

Step --> 1. keep .cer file into res/raw/ folder.

Step --> 2. Use this method and replace .cer file name with your .cer file and replace your host name also.

private SSLSocketFactory getSocketFactory() {

    CertificateFactory cf = null;
    try {

        cf = CertificateFactory.getInstance("X.509");
        InputStream caInput = getResources().openRawResource(R.raw.cert_name);
        Certificate ca;
        try {

            ca = cf.generateCertificate(caInput);
            Log.e("CERT", "ca=" + ((X509Certificate) ca).getSubjectDN());
        } finally {
            caInput.close();
        }


        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);


        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);


        HostnameVerifier hostnameVerifier = new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {

                Log.e("CipherUsed", session.getCipherSuite());
                return hostname.compareTo("10.199.89.68")==0; //The Hostname of your server.

            }
        };


        HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
        SSLContext context = null;
        context = SSLContext.getInstance("TLS");

        context.init(null, tmf.getTrustManagers(), null);
        HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());

        SSLSocketFactory sf = context.getSocketFactory();


        return sf;

    } catch (CertificateException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (KeyManagementException e) {
        e.printStackTrace();
    }

    return  null;
}

Step --> 3. Replace this line "RequestQueue queue = Volley.newRequestQueue(this);" with "RequestQueue queue = Volley.newRequestQueue(this, new HurlStack(null, getSocketFactory()));" in request of volley.

Solution 4 - Android

So far the only answer talk about adding an untrusted certificate as the solution, but since your browser doesn't complain it usually means Volley can't find the intermediate certificate that does complete the full trusted chain.

It happened to me with LetsEncrypt certificates. Most browsers already have that intermediate certs so on browser everything looks fine, but Volley was apparently missing something.

The solution
Add the intermediate certificate to your webserver config. For Apache you can follow this reference:
https://access.redhat.com/solutions/43575

For LetsEncrypt it specifically is this file: /etc/letsencrypt/live/your.website.com/chain.pem So besides your CertificateFile and KeyFile you should already have working you now have this third line:

SSLCertificateChainFile /etc/letsencrypt/live/your.website.com/chain.pem

Just adding that line, restarting apache and Volley doesn't complain anymore and you didn't introduce any security vulnerabilities!

Solution 5 - Android

I couldn't open the link provided by @Ogre_BGR,but while browsing the net I found the actual implementation done in following smanikandan14 Github.Look upon his SSl-connection explanation to understand more about it.

Solution 6 - Android

This can happen for several reasons, including:

  • The CA that issued the server certificate was unknown
  • The server certificate wasn't signed by a CA, but was self signed
  • The server configuration is missing an intermediate CA

Official doc from android

Solution: you can provide a certificate file within the request

Solution 7 - Android

For anyone who will come up against a problem like this and you use Letsencrypt for your SSL and node.js for webserver, try this. Assuming you have something like this. I fixed this by adding the line const chain = fs... Hope this helps

...
const app = express();
const privateKey  = fs.readFileSync('ssl/privkey.pem', 'utf8');
const certificate = fs.readFileSync('ssl/cert.pem', 'utf8');
const chain = fs.readFileSync('ssl/chain.pem', 'utf8');
const credentials = {key: privateKey, cert: certificate, ca: chain};
...
var httpsServer = https.createServer(credentials, app);

Solution 8 - Android

I got the same problem when I add ssl to the domain, After 2 days gone, I found the solution the URL is getting wrong . I was using https://example.com but when I add ssl into domain the url will be change

> https://www.example.com

And POST is working fine

Solution 9 - Android

got this error when i turned off proxy from cloudflare check image here the best solution for this problem is you can turn on proxy back and also add a full secure access on ssl certificate.

Solution 10 - Android

If anyone is using nginx and SSL certificates from letsencrypt, the solution is to simply use the certificate from file fullchain.pem instead of cert.pem:

ssl_certificate     /.../fullchain.pem;

This file includes the concatenation of your certificate and the CA's.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAbdullah ShoaibView Question on Stackoverflow
Solution 1 - AndroidMaxMxxView Answer on Stackoverflow
Solution 2 - AndroidSamrat DasView Answer on Stackoverflow
Solution 3 - AndroidChinki SaiView Answer on Stackoverflow
Solution 4 - AndroidPaulView Answer on Stackoverflow
Solution 5 - AndroidlaaptuView Answer on Stackoverflow
Solution 6 - AndroidMilonView Answer on Stackoverflow
Solution 7 - AndroidnadaView Answer on Stackoverflow
Solution 8 - AndroidshubombView Answer on Stackoverflow
Solution 9 - Androidanfaas1618View Answer on Stackoverflow
Solution 10 - AndroidnoeView Answer on Stackoverflow