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 codedefaultHttpClient 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