Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android HttpClient - hostname in certificate didn't match <example.com> != <*.example.com>

I'm using HttpClient on Android to connect to https://someUrl.com/somePath. The problem is that the site's certificate is for *.someUrl.com, not someUrl.com, so I get an SSLException. Lame on the part of the site, yes, but unless I can get it fixed, I'm stuck. Is there a way I can get HttpClient to relax and accept the certificate?

like image 286
noah Avatar asked Jun 28 '10 19:06

noah


2 Answers

This is my (edited) solution:

class MyVerifier extends AbstractVerifier {

    private final X509HostnameVerifier delegate;

    public MyVerifier(final X509HostnameVerifier delegate) {
        this.delegate = delegate;
    }

    @Override
    public void verify(String host, String[] cns, String[] subjectAlts)
                throws SSLException {
        boolean ok = false;
        try {
            delegate.verify(host, cns, subjectAlts);
        } catch (SSLException e) {
            for (String cn : cns) {
                if (cn.startsWith("*.")) {
                    try {
                          delegate.verify(host, new String[] { 
                                cn.substring(2) }, subjectAlts);
                          ok = true;
                    } catch (Exception e1) { }
                }
            }
            if(!ok) throw e;
        }
    }
}


public DefaultHttpClient getTolerantClient() {
    DefaultHttpClient client = new DefaultHttpClient();
    SSLSocketFactory sslSocketFactory = (SSLSocketFactory) client
            .getConnectionManager().getSchemeRegistry().getScheme("https")
            .getSocketFactory();
    final X509HostnameVerifier delegate = sslSocketFactory.getHostnameVerifier();
    if(!(delegate instanceof MyVerifier)) {
        sslSocketFactory.setHostnameVerifier(new MyVerifier(delegate));
    }
    return client;
}

It has the advantage of not changing the default behavior unless there is a wildcard domain, and in that case it revalidates as though the 2 part domain (e.g., someUrl.com) were part of the certificate, otherwise the original exception is rethrown. That means truly invalid certs will still fail.

like image 138
2 revs Avatar answered Sep 22 '22 03:09

2 revs


The BouncyCastle on Android is too old and it doesn't recognize wildcard certificate.

You can write your own X509TrustManager to check for wildcard.

or you can disable certificate check altogether if you can accept the risk. See this question,

Self-signed SSL acceptance on Android

like image 3
ZZ Coder Avatar answered Sep 23 '22 03:09

ZZ Coder