How to survive to Volley + Let’s Encrypt + Android

Alberto Bonacina
AndroidPub
Published in
4 min readApr 27, 2017

What is Let’s Encrypt ?

Let’s Encrypt is a free, automated, and open certificate authority (CA), run for the public’s benefit. It is a service provided by the Internet Security Research Group (ISRG).

The key principles behind Let’s Encrypt are:

  • Free: Anyone who owns a domain name can use Let’s Encrypt to obtain a trusted certificate at zero cost.
  • Automatic: Software running on a web server can interact with Let’s Encrypt to painlessly obtain a certificate, securely configure it for use, and automatically take care of renewal.
  • Secure: Let’s Encrypt will serve as a platform for advancing TLS security best practices, both on the CA side and by helping site operators properly secure their servers.
  • Transparent: All certificates issued or revoked will be publicly recorded and available for anyone to inspect.
  • Open: The automatic issuance and renewal protocol will be published as an open standard that others can adopt.
  • Cooperative: Much like the underlying Internet protocols themselves, Let’s Encrypt is a joint effort to benefit the community, beyond the control of any one organization.
Credits: Luca Bravo (https://unsplash.com/search/code?photo=XJXWbfSo2f0)

What is Volley?

Volley is an HTTP library that makes networking for Android apps easier and most importantly, faster. Volley is available on GitHub and offers the following benefits

  • Automatic scheduling of network requests
  • Multiple concurrent network connections
  • Transparent disk and memory response caching with standard HTTP cache coherence
  • Support for request prioritization
  • Cancellation request API. You can cancel a single request, or you can set blocks or scopes of requests to cancel
  • Ease of customization, for example, for retry and backoff
  • Strong ordering that makes it easy to correctly populate your UI with data fetched asynchronously from the network
  • Debugging and tracing tools

It integrates easily with any protocol and comes out of the box with support for raw strings, images, and JSON.

Set up Let’s Encrypt on server

In my case I have a VPS running Centos 7.2 and Node.js (v5.2.0) provides my APIs so I follow the Node.js part of this guide: Let’s Encrypt setup for Apache, NGINX & Node.js. I login in my VPS with ssh and launch all the commands to download all the Let’s Encrypt files.

git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
./letsencrypt-auto certonly --manual --email admin@mywebsite.com -d mywebsite.com

In the process you’ll be asked to put a custom string in a file and this file has to be accessible via browser (so you have to put it on a public http dir of your webserver that provides mywebsite.com). After that I have to setup Node.js to use Let’s Encrypt certificate with something like that

var https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync('/etc/letsencrypt/live/mywebsite.com/privkey.pem'),
cert: fs.readFileSync('/etc/letsencrypt/live/mywebsite.com/cert.pem'),
ca: fs.readFileSync('/etc/letsencrypt/live/mywebsite.com/chain.pem')
};
https.createServer(options, function (req, res) {
res.writeHead(200);
res.end("hello world\n");
}).listen(8000);

This part could be different based on your Node.js app, for me was very different.

Set up Volley on Android and make it works with Let’s Encrypt

To use Volley you have to add the following dependency to your app’s build.gradle file:

dependencies {
...
compile 'com.android.volley:volley:1.0.0'
}

In all of my project I follow this directory setup to use Volley using a single class to call my APIs: MyRequest.java

app/src/main/java/{packagename}/AppController.java
app/src/main/java/{packagename}/Utils/LruBitmapCache.java
app/src/main/java/{packagename}/types/HttpsTrustManager.java
app/src/main/java/{packagename}/types/MyRequest.java
app/src/main/java/{packagename}/types/VolleyCallback.java

All the classes can be found in this gist. I have also to download the chain.pem file, made by Let’s Encrypt, from my server and put it in the res/raw directory of my project:

app/src/main/res/raw/chain.pem

Now all the magic is done by the allowMySSL() function in HttpsTrustManager.java that use the chain.pem file as a trusted Certificate Authority

public static void allowMySSL(){   try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");

InputStream caInput = AppController.getInstance().getResources().openRawResource(R.raw.chain);
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
HttpsURLConnection.setDefaultSSLSocketFactory(context
.getSocketFactory());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
}
}

In the sendRequest() function of MyRequest.java class all I have to do is to call the HttpsTrustManager.allowMySSL() function to set up request in the right way.

Finally I can call my API made with Node.js in this way and the request made by Volley uses a secure https connection to the server:

MyRequest req = new MyRequest(getContext());
//Params
JSONObject params = new JSONObject();
//Call
req.sendRequest("/api/function/", params, new VolleyCallback() {
@Override
public void onSuccess(JSONObject resp) {
try {
JSONObject response = resp.getJSONObject("response");
String status = response.getString("status");
if(status.equals("OK")) {
Object dataObject = resp.get("data");
//Do something with dataObject
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public void onError() {
//Do something with Error
}
});

Conclusion

Now you’re able to use https in your APIs with Let’s Encrypt Certificate and all of your Android App’s requests is secure and protected.

Useful links

--

--