As mentioned in the previous post I access my Azure-hosted service from Android over HTTPS. This worked just fine on my Android 4.1 phone, but when I tested on a version 2.2 emulator I received an error:

javax.net.ssl.SSLException: Not trusted server certificate
            at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:371) ~[na:0.0]
            at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.getSecureSocket(HttpConnection.java:168) ~[na:0.0]
            ...
     Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: TrustAnchor for CertPath not found.
            at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:168) ~[na:0.0]
            at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:366) ~[na:0.0]
    ... 5 common frames omitted
    Caused by: java.security.cert.CertPathValidatorException: TrustAnchor for CertPath not found.
            at org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi.engineValidate(PKIXCertPathValidatorSpi.java:149) ~[na:0.0]
            at java.security.cert.CertPathValidator.validate(CertPathValidator.java:202) ~[na:0.0]
            at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:164) ~[na:0.0]
    ... 6 common frames omitted

This happens because Android 2.2 (and presumably lower versions too) does not accept the Azure SSL certificate.

The really simple solution is to just ignore 2.2: according to the Android Dashboards 2.2 now accounts for only 0.7% of the install base (and shrinking). However, the rest of the app works fine (mainly due to the Android Support Library) and so I wanted to fix this if possible.

The *bad* solution

We can just trust all certificates and that will fix it, right? Well, yes, but you're opening yourself (well, the user) up to man in the middle attacks - if someone can insert themself between the user and the server, returning a valid (and now trusted) certificate, they can intercept all the encrypted HTTPS traffic.

I'm not even going to post sample code for this.

Don't do it.

The correct solution

What we want to do is just trust our known Azure certificate.

The way we do this is to create a KeyStore containing our certificate, and then use that to create a SSLSocketFactory, which the client then uses when it needs to create the connection to our server.

Rather than reproduce it completely, the approach is described here (as well as a number of questions on StackOverflow, eg. this one).

 

I hope the 0.7% of my users are happy :)