As you correctly point out, there are two issues: a) the certificate isn’t trusted, and b) the name on the certificate doesn’t match the hostname.
WARNING: for anybody else arriving at this answer, this is a dirty, horrible hack and you must not use it for anything that matters. SSL/TLS without authentication is worse than no encryption at all – reading and modifying your “encrypted” data is trivial for an attacker and you wouldn’t even know it was happening.
Still with me? I feared so…
a) is solved by creating a custom SSLContext whose TrustManager accepts anything:
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, new TrustManager[] {
new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; }
}
}, null);
HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory());
and b) by creating a HostnameVerifier which allows the connection to proceed even though the cert doesn’t match the hostname:
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
Both must happen right at the beginning of your code, before you start messing around with HttpsURLConnections and so on. This works both in Android and the regular JRE. Enjoy.