Introduction
When we try to access a Web Service hosted on HTTPS and is secured over SSL, Host Verification and/or Peer Verification are to be handled in our application.
Background
Android supports the java.net
and org.apache
packages to access Web Services. I use Apache packages as I find them more useful and easier than using Java packages.
System Requirements
To Start
Host and Peer Verification are shown here. Each Android application has its own trusted store called KeyStore
. In the KeyStore
, we can store our self-signed SSL certificates that will be used for the verification purposes of our Web Service. Android trusts a couple of Trust Certificates, but if our signed certificate is not signed among those, then we need to add our certificate to the trusted store of the application.
Assuming you already have a self-signed certificate (if not, kindly use the key tool of Java to create one), let's add the certificate to a keystore using Bouncy Castle that we can access in our application. Like keytool is used in Java to create certificates, Bouncy Castle is the only way to add certificates to the Android keystore.
1. Creating the KeyStore
Download and unzip Bouncy Castle in a proper location and add the .jar file to the class path. Open cmd, go to the application folder, and type the following command:
keytool -import -v -trustcacerts -alias 0 -file mycertificate.crt
-keystore res/raw/mystore.bks -storetype BKS -provider
org.bouncycastle.jce.provider.BouncyCastleProvider -storepass mypassword
- file parameter points to your certificate file that you want to add
- keystore => gives the store name that you want to give
- storepass => password to access the keystore
On successful execution of the command, the mystore.bks file will be generated successfully.
2. Create a Class to Use Our Store for HTTPS Connections
To use the store that we created above, we have to create a custom Apache DefaultHttpClient
that knows to use the store for HTTPS requests.
public class MyHttpClient extends DefaultHttpClient {
final Context context;
public MyHttpClient(Context context) {
this.context = context;
}
@Override
protected ClientConnectionManager createClientConnectionManager {
SchemeRegistry registry = new SchemeRegistry();
registry.register("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
KeyStore trusted = KeyStore.getInstance("BKS");
InputStream in = context.getResources().openRawResource(R.raw.mystore);
try {
trusted.load(in, "mypassword".toCharArray());
}
finally {
in.close();
}
SSLSocketFactory mySslFact = new SslFactory(trusted);
return mySslFact;
} catch(Exception e) {
throw new AssertionError(e);
}
}
}
This code helps us to accept a server certificate and sets the certificate for verification. You can see how we are using our -storename
parameter "BKS
" to get the instance of the KeyStore
, loading the certificate file mystore
from R.raw
, and setting its password that was used while adding it to the store.
3. Copy mystore File
Import the generated mystore.bks file to the res/raw folder. So our above class can access it from there.
With this, SSL Peer Verification is taken care of. We just have to create an instance of MyHttpClient
in place of DefaultHttpClient
and Peer Verification will be handled by itself.
4. Process for Host Verification
Android supports only the host/domain via which the web service is being called - if any other host is tried to connect it throws exception. For example, if our application connects to a host, and then tries to connect another host for any reason, Android won't allow to do that. For this to be allowed, we got to set the hostnames that we want to allow the application to access.
public class MyHostVerifier extends org.apache.http.conn.ssl.AbstractVerifier {
String[] allowHost = {"my.ultra.com", "your.ultra.com", "ours.ultra.com"};
@Override
public void verify(String host, String[] cns,
String[] subjectAlts) throws SSLException {
for (int i=0; i < allowHost.length; i++) {
if (host == allowHost[i])
return;
}
throw SSLException;
}
}
Uncomment setHostVerifier
in the MyHttpClient
class and our class is ready to handle SSL Host Verification as well.
That's it. Thanks.
History
- 2011.04.25: Initial submission