Connecting with https to a url using a self signed certificate
Something good to know when for instance you have to connect to a QA backend that doesn't have a valid certificate. Here's how to proceed:
1st step: download bouncycastle
Android uses Bouncycastle to handle ssl certificates. It uses version 1.46 Keystores generated with later versions won't work for Android and will cause exceptions like java.io.IOException: Wrong version of key store on runtime
2nd step: get the certificate of the site
There are different ways to achieve this. Using openssl in command line for instance or opening the url in a browser, checking the certificate details and saving the certificate to a file (*.cer)
3rd step: generate a keystore
This can be done using the keytool program found in your JDK. Use the following command:
keytool -import -v -trustcacerts -alias 0 -file [full certificate name] -keystore [keystore file name].bks -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerPath [path to Jar file]/bcprov-jdk15on-146.jar -storepass [password]
A bks file should be created after this step
4th step: copy the keystore to your Android project
The file should be copied to resources/raw
5th step: add the following class to your project
public class MyHttpsClient extends DefaultHttpClient {
final Context context;
public MyHttpsClient(Context context) {
this.context = context;
}
@Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Register for port 443 our SSLSocketFactory with our keystore
// to the ConnectionManager
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with
// your trusted certificates (root and any intermediate certs)
InputStream in = context.getResources().openRawResource(R.raw.keystore);
try {
// Initialize the keystore with the provided trusted certificates
// Also provide the password of the keystore
trusted.load(in, "password".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible
// for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
Remember to update the password and change the resource name if necessary.
6th step: Call your new Https client from your code
defaultHttpClient client = new MyHttpClient(getApplicationContext());
Post inspired by:
http://blog.antoine.li/2010/10/22/android-trusting-ssl-certificates/
http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html
http://stackoverflow.com/questions/11963852/wrong-version-of-key-store-error-how-can-i-create-a-version-1-keystore-certif